xref: /openbmc/linux/drivers/net/wireless/quantenna/qtnfmac/event.c (revision 2eb3ed33e55d003d721d4d1a5e72fe323c12b4c0)
1 /*
2  * Copyright (c) 2015-2016 Quantenna Communications, Inc.
3  * All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16 
17 #include <linux/kernel.h>
18 #include <linux/module.h>
19 #include <linux/slab.h>
20 
21 #include "cfg80211.h"
22 #include "core.h"
23 #include "qlink.h"
24 #include "bus.h"
25 #include "trans.h"
26 #include "util.h"
27 #include "event.h"
28 #include "qlink_util.h"
29 
30 static int
31 qtnf_event_handle_sta_assoc(struct qtnf_wmac *mac, struct qtnf_vif *vif,
32 			    const struct qlink_event_sta_assoc *sta_assoc,
33 			    u16 len)
34 {
35 	const u8 *sta_addr;
36 	u16 frame_control;
37 	struct station_info sinfo = { 0 };
38 	size_t payload_len;
39 	u16 tlv_type;
40 	u16 tlv_value_len;
41 	size_t tlv_full_len;
42 	const struct qlink_tlv_hdr *tlv;
43 
44 	if (unlikely(len < sizeof(*sta_assoc))) {
45 		pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
46 		       mac->macid, vif->vifid, len, sizeof(*sta_assoc));
47 		return -EINVAL;
48 	}
49 
50 	if (vif->wdev.iftype != NL80211_IFTYPE_AP) {
51 		pr_err("VIF%u.%u: STA_ASSOC event when not in AP mode\n",
52 		       mac->macid, vif->vifid);
53 		return -EPROTO;
54 	}
55 
56 	sta_addr = sta_assoc->sta_addr;
57 	frame_control = le16_to_cpu(sta_assoc->frame_control);
58 
59 	pr_debug("VIF%u.%u: MAC:%pM FC:%x\n", mac->macid, vif->vifid, sta_addr,
60 		 frame_control);
61 
62 	qtnf_sta_list_add(&vif->sta_list, sta_addr);
63 
64 	sinfo.assoc_req_ies = NULL;
65 	sinfo.assoc_req_ies_len = 0;
66 
67 	payload_len = len - sizeof(*sta_assoc);
68 	tlv = (struct qlink_tlv_hdr *)sta_assoc->ies;
69 
70 	while (payload_len >= sizeof(struct qlink_tlv_hdr)) {
71 		tlv_type = le16_to_cpu(tlv->type);
72 		tlv_value_len = le16_to_cpu(tlv->len);
73 		tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
74 
75 		if (tlv_full_len > payload_len) {
76 			pr_warn("VIF%u.%u: malformed TLV 0x%.2X; LEN: %u\n",
77 				mac->macid, vif->vifid, tlv_type,
78 				tlv_value_len);
79 			return -EINVAL;
80 		}
81 
82 		if (tlv_type == QTN_TLV_ID_IE_SET) {
83 			sinfo.assoc_req_ies = tlv->val;
84 			sinfo.assoc_req_ies_len = tlv_value_len;
85 		}
86 
87 		payload_len -= tlv_full_len;
88 		tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
89 	}
90 
91 	if (payload_len) {
92 		pr_warn("VIF%u.%u: malformed TLV buf; bytes left: %zu\n",
93 			mac->macid, vif->vifid, payload_len);
94 		return -EINVAL;
95 	}
96 
97 	cfg80211_new_sta(vif->netdev, sta_assoc->sta_addr, &sinfo,
98 			 GFP_KERNEL);
99 
100 	return 0;
101 }
102 
103 static int
104 qtnf_event_handle_sta_deauth(struct qtnf_wmac *mac, struct qtnf_vif *vif,
105 			     const struct qlink_event_sta_deauth *sta_deauth,
106 			     u16 len)
107 {
108 	const u8 *sta_addr;
109 	u16 reason;
110 
111 	if (unlikely(len < sizeof(*sta_deauth))) {
112 		pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
113 		       mac->macid, vif->vifid, len,
114 		       sizeof(struct qlink_event_sta_deauth));
115 		return -EINVAL;
116 	}
117 
118 	if (vif->wdev.iftype != NL80211_IFTYPE_AP) {
119 		pr_err("VIF%u.%u: STA_DEAUTH event when not in AP mode\n",
120 		       mac->macid, vif->vifid);
121 		return -EPROTO;
122 	}
123 
124 	sta_addr = sta_deauth->sta_addr;
125 	reason = le16_to_cpu(sta_deauth->reason);
126 
127 	pr_debug("VIF%u.%u: MAC:%pM reason:%x\n", mac->macid, vif->vifid,
128 		 sta_addr, reason);
129 
130 	if (qtnf_sta_list_del(&vif->sta_list, sta_addr))
131 		cfg80211_del_sta(vif->netdev, sta_deauth->sta_addr,
132 				 GFP_KERNEL);
133 
134 	return 0;
135 }
136 
137 static int
138 qtnf_event_handle_bss_join(struct qtnf_vif *vif,
139 			   const struct qlink_event_bss_join *join_info,
140 			   u16 len)
141 {
142 	if (unlikely(len < sizeof(*join_info))) {
143 		pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
144 		       vif->mac->macid, vif->vifid, len,
145 		       sizeof(struct qlink_event_bss_join));
146 		return -EINVAL;
147 	}
148 
149 	if (vif->wdev.iftype != NL80211_IFTYPE_STATION) {
150 		pr_err("VIF%u.%u: BSS_JOIN event when not in STA mode\n",
151 		       vif->mac->macid, vif->vifid);
152 		return -EPROTO;
153 	}
154 
155 	if (vif->sta_state != QTNF_STA_CONNECTING) {
156 		pr_err("VIF%u.%u: BSS_JOIN event when STA is not connecting\n",
157 		       vif->mac->macid, vif->vifid);
158 		return -EPROTO;
159 	}
160 
161 	pr_debug("VIF%u.%u: BSSID:%pM\n", vif->mac->macid, vif->vifid,
162 		 join_info->bssid);
163 
164 	cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, NULL,
165 				0, le16_to_cpu(join_info->status), GFP_KERNEL);
166 
167 	if (le16_to_cpu(join_info->status) == WLAN_STATUS_SUCCESS) {
168 		vif->sta_state = QTNF_STA_CONNECTED;
169 		netif_carrier_on(vif->netdev);
170 	} else {
171 		vif->sta_state = QTNF_STA_DISCONNECTED;
172 	}
173 
174 	return 0;
175 }
176 
177 static int
178 qtnf_event_handle_bss_leave(struct qtnf_vif *vif,
179 			    const struct qlink_event_bss_leave *leave_info,
180 			    u16 len)
181 {
182 	if (unlikely(len < sizeof(*leave_info))) {
183 		pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
184 		       vif->mac->macid, vif->vifid, len,
185 		       sizeof(struct qlink_event_bss_leave));
186 		return -EINVAL;
187 	}
188 
189 	if (vif->wdev.iftype != NL80211_IFTYPE_STATION) {
190 		pr_err("VIF%u.%u: BSS_LEAVE event when not in STA mode\n",
191 		       vif->mac->macid, vif->vifid);
192 		return -EPROTO;
193 	}
194 
195 	if (vif->sta_state != QTNF_STA_CONNECTED) {
196 		pr_err("VIF%u.%u: BSS_LEAVE event when STA is not connected\n",
197 		       vif->mac->macid, vif->vifid);
198 		return -EPROTO;
199 	}
200 
201 	pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid);
202 
203 	cfg80211_disconnected(vif->netdev, le16_to_cpu(leave_info->reason),
204 			      NULL, 0, 0, GFP_KERNEL);
205 
206 	vif->sta_state = QTNF_STA_DISCONNECTED;
207 	netif_carrier_off(vif->netdev);
208 
209 	return 0;
210 }
211 
212 static int
213 qtnf_event_handle_mgmt_received(struct qtnf_vif *vif,
214 				const struct qlink_event_rxmgmt *rxmgmt,
215 				u16 len)
216 {
217 	const size_t min_len = sizeof(*rxmgmt) +
218 			       sizeof(struct ieee80211_hdr_3addr);
219 	const struct ieee80211_hdr_3addr *frame = (void *)rxmgmt->frame_data;
220 	const u16 frame_len = len - sizeof(*rxmgmt);
221 	enum nl80211_rxmgmt_flags flags = 0;
222 
223 	if (unlikely(len < min_len)) {
224 		pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
225 		       vif->mac->macid, vif->vifid, len, min_len);
226 		return -EINVAL;
227 	}
228 
229 	if (le32_to_cpu(rxmgmt->flags) & QLINK_RXMGMT_FLAG_ANSWERED)
230 		flags |= NL80211_RXMGMT_FLAG_ANSWERED;
231 
232 	pr_debug("%s LEN:%u FC:%.4X SA:%pM\n", vif->netdev->name, frame_len,
233 		 le16_to_cpu(frame->frame_control), frame->addr2);
234 
235 	cfg80211_rx_mgmt(&vif->wdev, le32_to_cpu(rxmgmt->freq),
236 			 le32_to_cpu(rxmgmt->sig_dbm), rxmgmt->frame_data,
237 			 frame_len, flags);
238 
239 	return 0;
240 }
241 
242 static int
243 qtnf_event_handle_scan_results(struct qtnf_vif *vif,
244 			       const struct qlink_event_scan_result *sr,
245 			       u16 len)
246 {
247 	struct cfg80211_bss *bss;
248 	struct ieee80211_channel *channel;
249 	struct wiphy *wiphy = priv_to_wiphy(vif->mac);
250 	enum cfg80211_bss_frame_type frame_type;
251 	size_t payload_len;
252 	u16 tlv_type;
253 	u16 tlv_value_len;
254 	size_t tlv_full_len;
255 	const struct qlink_tlv_hdr *tlv;
256 
257 	const u8 *ies = NULL;
258 	size_t ies_len = 0;
259 
260 	if (len < sizeof(*sr)) {
261 		pr_err("VIF%u.%u: payload is too short\n", vif->mac->macid,
262 		       vif->vifid);
263 		return -EINVAL;
264 	}
265 
266 	channel = ieee80211_get_channel(wiphy, le16_to_cpu(sr->freq));
267 	if (!channel) {
268 		pr_err("VIF%u.%u: channel at %u MHz not found\n",
269 		       vif->mac->macid, vif->vifid, le16_to_cpu(sr->freq));
270 		return -EINVAL;
271 	}
272 
273 	switch (sr->frame_type) {
274 	case QLINK_BSS_FTYPE_BEACON:
275 		frame_type = CFG80211_BSS_FTYPE_BEACON;
276 		break;
277 	case QLINK_BSS_FTYPE_PRESP:
278 		frame_type = CFG80211_BSS_FTYPE_PRESP;
279 		break;
280 	default:
281 		frame_type = CFG80211_BSS_FTYPE_UNKNOWN;
282 	}
283 
284 	payload_len = len - sizeof(*sr);
285 	tlv = (struct qlink_tlv_hdr *)sr->payload;
286 
287 	while (payload_len >= sizeof(struct qlink_tlv_hdr)) {
288 		tlv_type = le16_to_cpu(tlv->type);
289 		tlv_value_len = le16_to_cpu(tlv->len);
290 		tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
291 
292 		if (tlv_full_len > payload_len) {
293 			pr_warn("VIF%u.%u: malformed TLV 0x%.2X; LEN: %u\n",
294 				vif->mac->macid, vif->vifid, tlv_type,
295 				tlv_value_len);
296 			return -EINVAL;
297 		}
298 
299 		if (tlv_type == QTN_TLV_ID_IE_SET) {
300 			ies = tlv->val;
301 			ies_len = tlv_value_len;
302 		}
303 
304 		payload_len -= tlv_full_len;
305 		tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
306 	}
307 
308 	if (payload_len) {
309 		pr_warn("VIF%u.%u: malformed TLV buf; bytes left: %zu\n",
310 			vif->mac->macid, vif->vifid, payload_len);
311 		return -EINVAL;
312 	}
313 
314 	bss = cfg80211_inform_bss(wiphy, channel, frame_type,
315 				  sr->bssid, get_unaligned_le64(&sr->tsf),
316 				  le16_to_cpu(sr->capab),
317 				  le16_to_cpu(sr->bintval), ies, ies_len,
318 				  sr->signal, GFP_KERNEL);
319 	if (!bss)
320 		return -ENOMEM;
321 
322 	cfg80211_put_bss(wiphy, bss);
323 
324 	return 0;
325 }
326 
327 static int
328 qtnf_event_handle_scan_complete(struct qtnf_wmac *mac,
329 				const struct qlink_event_scan_complete *status,
330 				u16 len)
331 {
332 	if (len < sizeof(*status)) {
333 		pr_err("MAC%u: payload is too short\n", mac->macid);
334 		return -EINVAL;
335 	}
336 
337 	qtnf_scan_done(mac, le32_to_cpu(status->flags) & QLINK_SCAN_ABORTED);
338 
339 	return 0;
340 }
341 
342 static int
343 qtnf_event_handle_freq_change(struct qtnf_wmac *mac,
344 			      const struct qlink_event_freq_change *data,
345 			      u16 len)
346 {
347 	struct wiphy *wiphy = priv_to_wiphy(mac);
348 	struct cfg80211_chan_def chandef;
349 	struct qtnf_vif *vif;
350 	int i;
351 
352 	if (len < sizeof(*data)) {
353 		pr_err("MAC%u: payload is too short\n", mac->macid);
354 		return -EINVAL;
355 	}
356 
357 	if (!wiphy->registered)
358 		return 0;
359 
360 	qlink_chandef_q2cfg(wiphy, &data->chan, &chandef);
361 
362 	if (!cfg80211_chandef_valid(&chandef)) {
363 		pr_err("MAC%u: bad channel f1=%u f2=%u bw=%u\n", mac->macid,
364 		       chandef.center_freq1, chandef.center_freq2,
365 		       chandef.width);
366 		return -EINVAL;
367 	}
368 
369 	pr_debug("MAC%d: new channel ieee=%u freq1=%u freq2=%u bw=%u\n",
370 		 mac->macid, chandef.chan->hw_value, chandef.center_freq1,
371 		 chandef.center_freq2, chandef.width);
372 
373 	for (i = 0; i < QTNF_MAX_INTF; i++) {
374 		vif = &mac->iflist[i];
375 		if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)
376 			continue;
377 
378 		if (vif->netdev) {
379 			mutex_lock(&vif->wdev.mtx);
380 			cfg80211_ch_switch_notify(vif->netdev, &chandef);
381 			mutex_unlock(&vif->wdev.mtx);
382 		}
383 	}
384 
385 	return 0;
386 }
387 
388 static int qtnf_event_parse(struct qtnf_wmac *mac,
389 			    const struct sk_buff *event_skb)
390 {
391 	const struct qlink_event *event;
392 	struct qtnf_vif *vif = NULL;
393 	int ret = -1;
394 	u16 event_id;
395 	u16 event_len;
396 
397 	event = (const struct qlink_event *)event_skb->data;
398 	event_id = le16_to_cpu(event->event_id);
399 	event_len = le16_to_cpu(event->mhdr.len);
400 
401 	if (likely(event->vifid < QTNF_MAX_INTF)) {
402 		vif = &mac->iflist[event->vifid];
403 	} else {
404 		pr_err("invalid vif(%u)\n", event->vifid);
405 		return -EINVAL;
406 	}
407 
408 	switch (event_id) {
409 	case QLINK_EVENT_STA_ASSOCIATED:
410 		ret = qtnf_event_handle_sta_assoc(mac, vif, (const void *)event,
411 						  event_len);
412 		break;
413 	case QLINK_EVENT_STA_DEAUTH:
414 		ret = qtnf_event_handle_sta_deauth(mac, vif,
415 						   (const void *)event,
416 						   event_len);
417 		break;
418 	case QLINK_EVENT_MGMT_RECEIVED:
419 		ret = qtnf_event_handle_mgmt_received(vif, (const void *)event,
420 						      event_len);
421 		break;
422 	case QLINK_EVENT_SCAN_RESULTS:
423 		ret = qtnf_event_handle_scan_results(vif, (const void *)event,
424 						     event_len);
425 		break;
426 	case QLINK_EVENT_SCAN_COMPLETE:
427 		ret = qtnf_event_handle_scan_complete(mac, (const void *)event,
428 						      event_len);
429 		break;
430 	case QLINK_EVENT_BSS_JOIN:
431 		ret = qtnf_event_handle_bss_join(vif, (const void *)event,
432 						 event_len);
433 		break;
434 	case QLINK_EVENT_BSS_LEAVE:
435 		ret = qtnf_event_handle_bss_leave(vif, (const void *)event,
436 						  event_len);
437 		break;
438 	case QLINK_EVENT_FREQ_CHANGE:
439 		ret = qtnf_event_handle_freq_change(mac, (const void *)event,
440 						    event_len);
441 		break;
442 	default:
443 		pr_warn("unknown event type: %x\n", event_id);
444 		break;
445 	}
446 
447 	return ret;
448 }
449 
450 static int qtnf_event_process_skb(struct qtnf_bus *bus,
451 				  const struct sk_buff *skb)
452 {
453 	const struct qlink_event *event;
454 	struct qtnf_wmac *mac;
455 	int res;
456 
457 	if (unlikely(!skb || skb->len < sizeof(*event))) {
458 		pr_err("invalid event buffer\n");
459 		return -EINVAL;
460 	}
461 
462 	event = (struct qlink_event *)skb->data;
463 
464 	mac = qtnf_core_get_mac(bus, event->macid);
465 
466 	pr_debug("new event id:%x len:%u mac:%u vif:%u\n",
467 		 le16_to_cpu(event->event_id), le16_to_cpu(event->mhdr.len),
468 		 event->macid, event->vifid);
469 
470 	if (unlikely(!mac))
471 		return -ENXIO;
472 
473 	qtnf_bus_lock(bus);
474 	res = qtnf_event_parse(mac, skb);
475 	qtnf_bus_unlock(bus);
476 
477 	return res;
478 }
479 
480 void qtnf_event_work_handler(struct work_struct *work)
481 {
482 	struct qtnf_bus *bus = container_of(work, struct qtnf_bus, event_work);
483 	struct sk_buff_head *event_queue = &bus->trans.event_queue;
484 	struct sk_buff *current_event_skb = skb_dequeue(event_queue);
485 
486 	while (current_event_skb) {
487 		qtnf_event_process_skb(bus, current_event_skb);
488 		dev_kfree_skb_any(current_event_skb);
489 		current_event_skb = skb_dequeue(event_queue);
490 	}
491 }
492