xref: /openbmc/linux/drivers/net/wireless/quantenna/qtnfmac/event.c (revision 5ef12cb4a3a78ffb331c03a795a15eea4ae35155)
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_addr);
63 
64 	sinfo.assoc_req_ies = NULL;
65 	sinfo.assoc_req_ies_len = 0;
66 	sinfo.generation = vif->generation;
67 
68 	payload_len = len - sizeof(*sta_assoc);
69 	tlv = (const struct qlink_tlv_hdr *)sta_assoc->ies;
70 
71 	while (payload_len >= sizeof(*tlv)) {
72 		tlv_type = le16_to_cpu(tlv->type);
73 		tlv_value_len = le16_to_cpu(tlv->len);
74 		tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
75 
76 		if (tlv_full_len > payload_len)
77 			return -EINVAL;
78 
79 		if (tlv_type == QTN_TLV_ID_IE_SET) {
80 			const struct qlink_tlv_ie_set *ie_set;
81 			unsigned int ie_len;
82 
83 			if (payload_len < sizeof(*ie_set))
84 				return -EINVAL;
85 
86 			ie_set = (const struct qlink_tlv_ie_set *)tlv;
87 			ie_len = tlv_value_len -
88 				(sizeof(*ie_set) - sizeof(ie_set->hdr));
89 
90 			if (ie_set->type == QLINK_IE_SET_ASSOC_REQ && ie_len) {
91 				sinfo.assoc_req_ies = ie_set->ie_data;
92 				sinfo.assoc_req_ies_len = ie_len;
93 			}
94 		}
95 
96 		payload_len -= tlv_full_len;
97 		tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
98 	}
99 
100 	if (payload_len)
101 		return -EINVAL;
102 
103 	cfg80211_new_sta(vif->netdev, sta_assoc->sta_addr, &sinfo,
104 			 GFP_KERNEL);
105 
106 	return 0;
107 }
108 
109 static int
110 qtnf_event_handle_sta_deauth(struct qtnf_wmac *mac, struct qtnf_vif *vif,
111 			     const struct qlink_event_sta_deauth *sta_deauth,
112 			     u16 len)
113 {
114 	const u8 *sta_addr;
115 	u16 reason;
116 
117 	if (unlikely(len < sizeof(*sta_deauth))) {
118 		pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
119 		       mac->macid, vif->vifid, len,
120 		       sizeof(struct qlink_event_sta_deauth));
121 		return -EINVAL;
122 	}
123 
124 	if (vif->wdev.iftype != NL80211_IFTYPE_AP) {
125 		pr_err("VIF%u.%u: STA_DEAUTH event when not in AP mode\n",
126 		       mac->macid, vif->vifid);
127 		return -EPROTO;
128 	}
129 
130 	sta_addr = sta_deauth->sta_addr;
131 	reason = le16_to_cpu(sta_deauth->reason);
132 
133 	pr_debug("VIF%u.%u: MAC:%pM reason:%x\n", mac->macid, vif->vifid,
134 		 sta_addr, reason);
135 
136 	if (qtnf_sta_list_del(vif, sta_addr))
137 		cfg80211_del_sta(vif->netdev, sta_deauth->sta_addr,
138 				 GFP_KERNEL);
139 
140 	return 0;
141 }
142 
143 static int
144 qtnf_event_handle_bss_join(struct qtnf_vif *vif,
145 			   const struct qlink_event_bss_join *join_info,
146 			   u16 len)
147 {
148 	if (unlikely(len < sizeof(*join_info))) {
149 		pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
150 		       vif->mac->macid, vif->vifid, len,
151 		       sizeof(struct qlink_event_bss_join));
152 		return -EINVAL;
153 	}
154 
155 	if (vif->wdev.iftype != NL80211_IFTYPE_STATION) {
156 		pr_err("VIF%u.%u: BSS_JOIN event when not in STA mode\n",
157 		       vif->mac->macid, vif->vifid);
158 		return -EPROTO;
159 	}
160 
161 	if (vif->sta_state != QTNF_STA_CONNECTING) {
162 		pr_err("VIF%u.%u: BSS_JOIN event when STA is not connecting\n",
163 		       vif->mac->macid, vif->vifid);
164 		return -EPROTO;
165 	}
166 
167 	pr_debug("VIF%u.%u: BSSID:%pM\n", vif->mac->macid, vif->vifid,
168 		 join_info->bssid);
169 
170 	cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, NULL,
171 				0, le16_to_cpu(join_info->status), GFP_KERNEL);
172 
173 	if (le16_to_cpu(join_info->status) == WLAN_STATUS_SUCCESS) {
174 		vif->sta_state = QTNF_STA_CONNECTED;
175 		netif_carrier_on(vif->netdev);
176 	} else {
177 		vif->sta_state = QTNF_STA_DISCONNECTED;
178 	}
179 
180 	return 0;
181 }
182 
183 static int
184 qtnf_event_handle_bss_leave(struct qtnf_vif *vif,
185 			    const struct qlink_event_bss_leave *leave_info,
186 			    u16 len)
187 {
188 	if (unlikely(len < sizeof(*leave_info))) {
189 		pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
190 		       vif->mac->macid, vif->vifid, len,
191 		       sizeof(struct qlink_event_bss_leave));
192 		return -EINVAL;
193 	}
194 
195 	if (vif->wdev.iftype != NL80211_IFTYPE_STATION) {
196 		pr_err("VIF%u.%u: BSS_LEAVE event when not in STA mode\n",
197 		       vif->mac->macid, vif->vifid);
198 		return -EPROTO;
199 	}
200 
201 	if (vif->sta_state != QTNF_STA_CONNECTED) {
202 		pr_err("VIF%u.%u: BSS_LEAVE event when STA is not connected\n",
203 		       vif->mac->macid, vif->vifid);
204 		return -EPROTO;
205 	}
206 
207 	pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid);
208 
209 	cfg80211_disconnected(vif->netdev, le16_to_cpu(leave_info->reason),
210 			      NULL, 0, 0, GFP_KERNEL);
211 
212 	vif->sta_state = QTNF_STA_DISCONNECTED;
213 	netif_carrier_off(vif->netdev);
214 
215 	return 0;
216 }
217 
218 static int
219 qtnf_event_handle_mgmt_received(struct qtnf_vif *vif,
220 				const struct qlink_event_rxmgmt *rxmgmt,
221 				u16 len)
222 {
223 	const size_t min_len = sizeof(*rxmgmt) +
224 			       sizeof(struct ieee80211_hdr_3addr);
225 	const struct ieee80211_hdr_3addr *frame = (void *)rxmgmt->frame_data;
226 	const u16 frame_len = len - sizeof(*rxmgmt);
227 	enum nl80211_rxmgmt_flags flags = 0;
228 
229 	if (unlikely(len < min_len)) {
230 		pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
231 		       vif->mac->macid, vif->vifid, len, min_len);
232 		return -EINVAL;
233 	}
234 
235 	if (le32_to_cpu(rxmgmt->flags) & QLINK_RXMGMT_FLAG_ANSWERED)
236 		flags |= NL80211_RXMGMT_FLAG_ANSWERED;
237 
238 	pr_debug("%s LEN:%u FC:%.4X SA:%pM\n", vif->netdev->name, frame_len,
239 		 le16_to_cpu(frame->frame_control), frame->addr2);
240 
241 	cfg80211_rx_mgmt(&vif->wdev, le32_to_cpu(rxmgmt->freq), rxmgmt->sig_dbm,
242 			 rxmgmt->frame_data, frame_len, flags);
243 
244 	return 0;
245 }
246 
247 static int
248 qtnf_event_handle_scan_results(struct qtnf_vif *vif,
249 			       const struct qlink_event_scan_result *sr,
250 			       u16 len)
251 {
252 	struct cfg80211_bss *bss;
253 	struct ieee80211_channel *channel;
254 	struct wiphy *wiphy = priv_to_wiphy(vif->mac);
255 	enum cfg80211_bss_frame_type frame_type = CFG80211_BSS_FTYPE_UNKNOWN;
256 	size_t payload_len;
257 	u16 tlv_type;
258 	u16 tlv_value_len;
259 	size_t tlv_full_len;
260 	const struct qlink_tlv_hdr *tlv;
261 	const u8 *ies = NULL;
262 	size_t ies_len = 0;
263 
264 	if (len < sizeof(*sr)) {
265 		pr_err("VIF%u.%u: payload is too short\n", vif->mac->macid,
266 		       vif->vifid);
267 		return -EINVAL;
268 	}
269 
270 	channel = ieee80211_get_channel(wiphy, le16_to_cpu(sr->freq));
271 	if (!channel) {
272 		pr_err("VIF%u.%u: channel at %u MHz not found\n",
273 		       vif->mac->macid, vif->vifid, le16_to_cpu(sr->freq));
274 		return -EINVAL;
275 	}
276 
277 	payload_len = len - sizeof(*sr);
278 	tlv = (struct qlink_tlv_hdr *)sr->payload;
279 
280 	while (payload_len >= sizeof(struct qlink_tlv_hdr)) {
281 		tlv_type = le16_to_cpu(tlv->type);
282 		tlv_value_len = le16_to_cpu(tlv->len);
283 		tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
284 
285 		if (tlv_full_len > payload_len)
286 			return -EINVAL;
287 
288 		if (tlv_type == QTN_TLV_ID_IE_SET) {
289 			const struct qlink_tlv_ie_set *ie_set;
290 			unsigned int ie_len;
291 
292 			if (payload_len < sizeof(*ie_set))
293 				return -EINVAL;
294 
295 			ie_set = (const struct qlink_tlv_ie_set *)tlv;
296 			ie_len = tlv_value_len -
297 				(sizeof(*ie_set) - sizeof(ie_set->hdr));
298 
299 			switch (ie_set->type) {
300 			case QLINK_IE_SET_BEACON_IES:
301 				frame_type = CFG80211_BSS_FTYPE_BEACON;
302 				break;
303 			case QLINK_IE_SET_PROBE_RESP_IES:
304 				frame_type = CFG80211_BSS_FTYPE_PRESP;
305 				break;
306 			default:
307 				frame_type = CFG80211_BSS_FTYPE_UNKNOWN;
308 			}
309 
310 			if (ie_len) {
311 				ies = ie_set->ie_data;
312 				ies_len = ie_len;
313 			}
314 		}
315 
316 		payload_len -= tlv_full_len;
317 		tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
318 	}
319 
320 	if (payload_len)
321 		return -EINVAL;
322 
323 	bss = cfg80211_inform_bss(wiphy, channel, frame_type,
324 				  sr->bssid, get_unaligned_le64(&sr->tsf),
325 				  le16_to_cpu(sr->capab),
326 				  le16_to_cpu(sr->bintval), ies, ies_len,
327 				  DBM_TO_MBM(sr->sig_dbm), GFP_KERNEL);
328 	if (!bss)
329 		return -ENOMEM;
330 
331 	cfg80211_put_bss(wiphy, bss);
332 
333 	return 0;
334 }
335 
336 static int
337 qtnf_event_handle_scan_complete(struct qtnf_wmac *mac,
338 				const struct qlink_event_scan_complete *status,
339 				u16 len)
340 {
341 	if (len < sizeof(*status)) {
342 		pr_err("MAC%u: payload is too short\n", mac->macid);
343 		return -EINVAL;
344 	}
345 
346 	qtnf_scan_done(mac, le32_to_cpu(status->flags) & QLINK_SCAN_ABORTED);
347 
348 	return 0;
349 }
350 
351 static int
352 qtnf_event_handle_freq_change(struct qtnf_wmac *mac,
353 			      const struct qlink_event_freq_change *data,
354 			      u16 len)
355 {
356 	struct wiphy *wiphy = priv_to_wiphy(mac);
357 	struct cfg80211_chan_def chandef;
358 	struct qtnf_vif *vif;
359 	int i;
360 
361 	if (len < sizeof(*data)) {
362 		pr_err("MAC%u: payload is too short\n", mac->macid);
363 		return -EINVAL;
364 	}
365 
366 	if (!wiphy->registered)
367 		return 0;
368 
369 	qlink_chandef_q2cfg(wiphy, &data->chan, &chandef);
370 
371 	if (!cfg80211_chandef_valid(&chandef)) {
372 		pr_err("MAC%u: bad channel freq=%u cf1=%u cf2=%u bw=%u\n",
373 		       mac->macid, chandef.chan->center_freq,
374 		       chandef.center_freq1, chandef.center_freq2,
375 		       chandef.width);
376 		return -EINVAL;
377 	}
378 
379 	pr_debug("MAC%d: new channel ieee=%u freq1=%u freq2=%u bw=%u\n",
380 		 mac->macid, chandef.chan->hw_value, chandef.center_freq1,
381 		 chandef.center_freq2, chandef.width);
382 
383 	for (i = 0; i < QTNF_MAX_INTF; i++) {
384 		vif = &mac->iflist[i];
385 		if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)
386 			continue;
387 
388 		if (vif->netdev) {
389 			mutex_lock(&vif->wdev.mtx);
390 			cfg80211_ch_switch_notify(vif->netdev, &chandef);
391 			mutex_unlock(&vif->wdev.mtx);
392 		}
393 	}
394 
395 	return 0;
396 }
397 
398 static int qtnf_event_handle_radar(struct qtnf_vif *vif,
399 				   const struct qlink_event_radar *ev,
400 				   u16 len)
401 {
402 	struct wiphy *wiphy = priv_to_wiphy(vif->mac);
403 	struct cfg80211_chan_def chandef;
404 
405 	if (len < sizeof(*ev)) {
406 		pr_err("MAC%u: payload is too short\n", vif->mac->macid);
407 		return -EINVAL;
408 	}
409 
410 	if (!wiphy->registered || !vif->netdev)
411 		return 0;
412 
413 	qlink_chandef_q2cfg(wiphy, &ev->chan, &chandef);
414 
415 	if (!cfg80211_chandef_valid(&chandef)) {
416 		pr_err("MAC%u: bad channel f1=%u f2=%u bw=%u\n",
417 		       vif->mac->macid,
418 		       chandef.center_freq1, chandef.center_freq2,
419 		       chandef.width);
420 		return -EINVAL;
421 	}
422 
423 	pr_info("%s: radar event=%u f1=%u f2=%u bw=%u\n",
424 		vif->netdev->name, ev->event,
425 		chandef.center_freq1, chandef.center_freq2,
426 		chandef.width);
427 
428 	switch (ev->event) {
429 	case QLINK_RADAR_DETECTED:
430 		cfg80211_radar_event(wiphy, &chandef, GFP_KERNEL);
431 		break;
432 	case QLINK_RADAR_CAC_FINISHED:
433 		if (!vif->wdev.cac_started)
434 			break;
435 
436 		cfg80211_cac_event(vif->netdev, &chandef,
437 				   NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
438 		break;
439 	case QLINK_RADAR_CAC_ABORTED:
440 		if (!vif->wdev.cac_started)
441 			break;
442 
443 		cfg80211_cac_event(vif->netdev, &chandef,
444 				   NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
445 		break;
446 	default:
447 		pr_warn("%s: unhandled radar event %u\n",
448 			vif->netdev->name, ev->event);
449 		break;
450 	}
451 
452 	return 0;
453 }
454 
455 static int qtnf_event_parse(struct qtnf_wmac *mac,
456 			    const struct sk_buff *event_skb)
457 {
458 	const struct qlink_event *event;
459 	struct qtnf_vif *vif = NULL;
460 	int ret = -1;
461 	u16 event_id;
462 	u16 event_len;
463 
464 	event = (const struct qlink_event *)event_skb->data;
465 	event_id = le16_to_cpu(event->event_id);
466 	event_len = le16_to_cpu(event->mhdr.len);
467 
468 	if (likely(event->vifid < QTNF_MAX_INTF)) {
469 		vif = &mac->iflist[event->vifid];
470 	} else {
471 		pr_err("invalid vif(%u)\n", event->vifid);
472 		return -EINVAL;
473 	}
474 
475 	switch (event_id) {
476 	case QLINK_EVENT_STA_ASSOCIATED:
477 		ret = qtnf_event_handle_sta_assoc(mac, vif, (const void *)event,
478 						  event_len);
479 		break;
480 	case QLINK_EVENT_STA_DEAUTH:
481 		ret = qtnf_event_handle_sta_deauth(mac, vif,
482 						   (const void *)event,
483 						   event_len);
484 		break;
485 	case QLINK_EVENT_MGMT_RECEIVED:
486 		ret = qtnf_event_handle_mgmt_received(vif, (const void *)event,
487 						      event_len);
488 		break;
489 	case QLINK_EVENT_SCAN_RESULTS:
490 		ret = qtnf_event_handle_scan_results(vif, (const void *)event,
491 						     event_len);
492 		break;
493 	case QLINK_EVENT_SCAN_COMPLETE:
494 		ret = qtnf_event_handle_scan_complete(mac, (const void *)event,
495 						      event_len);
496 		break;
497 	case QLINK_EVENT_BSS_JOIN:
498 		ret = qtnf_event_handle_bss_join(vif, (const void *)event,
499 						 event_len);
500 		break;
501 	case QLINK_EVENT_BSS_LEAVE:
502 		ret = qtnf_event_handle_bss_leave(vif, (const void *)event,
503 						  event_len);
504 		break;
505 	case QLINK_EVENT_FREQ_CHANGE:
506 		ret = qtnf_event_handle_freq_change(mac, (const void *)event,
507 						    event_len);
508 		break;
509 	case QLINK_EVENT_RADAR:
510 		ret = qtnf_event_handle_radar(vif, (const void *)event,
511 					      event_len);
512 		break;
513 	default:
514 		pr_warn("unknown event type: %x\n", event_id);
515 		break;
516 	}
517 
518 	return ret;
519 }
520 
521 static int qtnf_event_process_skb(struct qtnf_bus *bus,
522 				  const struct sk_buff *skb)
523 {
524 	const struct qlink_event *event;
525 	struct qtnf_wmac *mac;
526 	int res;
527 
528 	if (unlikely(!skb || skb->len < sizeof(*event))) {
529 		pr_err("invalid event buffer\n");
530 		return -EINVAL;
531 	}
532 
533 	event = (struct qlink_event *)skb->data;
534 
535 	mac = qtnf_core_get_mac(bus, event->macid);
536 
537 	pr_debug("new event id:%x len:%u mac:%u vif:%u\n",
538 		 le16_to_cpu(event->event_id), le16_to_cpu(event->mhdr.len),
539 		 event->macid, event->vifid);
540 
541 	if (unlikely(!mac))
542 		return -ENXIO;
543 
544 	rtnl_lock();
545 	res = qtnf_event_parse(mac, skb);
546 	rtnl_unlock();
547 
548 	return res;
549 }
550 
551 void qtnf_event_work_handler(struct work_struct *work)
552 {
553 	struct qtnf_bus *bus = container_of(work, struct qtnf_bus, event_work);
554 	struct sk_buff_head *event_queue = &bus->trans.event_queue;
555 	struct sk_buff *current_event_skb = skb_dequeue(event_queue);
556 
557 	while (current_event_skb) {
558 		qtnf_event_process_skb(bus, current_event_skb);
559 		dev_kfree_skb_any(current_event_skb);
560 		current_event_skb = skb_dequeue(event_queue);
561 	}
562 }
563