1 // SPDX-License-Identifier: GPL-2.0+
2 /* Copyright (c) 2015-2016 Quantenna Communications. All rights reserved. */
3
4 #include <linux/kernel.h>
5 #include <linux/module.h>
6 #include <linux/slab.h>
7
8 #include "cfg80211.h"
9 #include "core.h"
10 #include "qlink.h"
11 #include "bus.h"
12 #include "trans.h"
13 #include "util.h"
14 #include "event.h"
15 #include "qlink_util.h"
16
17 static int
qtnf_event_handle_sta_assoc(struct qtnf_wmac * mac,struct qtnf_vif * vif,const struct qlink_event_sta_assoc * sta_assoc,u16 len)18 qtnf_event_handle_sta_assoc(struct qtnf_wmac *mac, struct qtnf_vif *vif,
19 const struct qlink_event_sta_assoc *sta_assoc,
20 u16 len)
21 {
22 const u8 *sta_addr;
23 u16 frame_control;
24 struct station_info *sinfo;
25 size_t payload_len;
26 u16 tlv_type;
27 u16 tlv_value_len;
28 size_t tlv_full_len;
29 const struct qlink_tlv_hdr *tlv;
30 int ret = 0;
31
32 if (unlikely(len < sizeof(*sta_assoc))) {
33 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
34 mac->macid, vif->vifid, len, sizeof(*sta_assoc));
35 return -EINVAL;
36 }
37
38 if (vif->wdev.iftype != NL80211_IFTYPE_AP) {
39 pr_err("VIF%u.%u: STA_ASSOC event when not in AP mode\n",
40 mac->macid, vif->vifid);
41 return -EPROTO;
42 }
43
44 sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
45 if (!sinfo)
46 return -ENOMEM;
47
48 sta_addr = sta_assoc->sta_addr;
49 frame_control = le16_to_cpu(sta_assoc->frame_control);
50
51 pr_debug("VIF%u.%u: MAC:%pM FC:%x\n", mac->macid, vif->vifid, sta_addr,
52 frame_control);
53
54 qtnf_sta_list_add(vif, sta_addr);
55
56 sinfo->assoc_req_ies = NULL;
57 sinfo->assoc_req_ies_len = 0;
58 sinfo->generation = vif->generation;
59
60 payload_len = len - sizeof(*sta_assoc);
61 tlv = (const struct qlink_tlv_hdr *)sta_assoc->ies;
62
63 while (payload_len >= sizeof(*tlv)) {
64 tlv_type = le16_to_cpu(tlv->type);
65 tlv_value_len = le16_to_cpu(tlv->len);
66 tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
67
68 if (tlv_full_len > payload_len) {
69 ret = -EINVAL;
70 goto out;
71 }
72
73 if (tlv_type == QTN_TLV_ID_IE_SET) {
74 const struct qlink_tlv_ie_set *ie_set;
75 unsigned int ie_len;
76
77 if (payload_len < sizeof(*ie_set)) {
78 ret = -EINVAL;
79 goto out;
80 }
81
82 ie_set = (const struct qlink_tlv_ie_set *)tlv;
83 ie_len = tlv_value_len -
84 (sizeof(*ie_set) - sizeof(ie_set->hdr));
85
86 if (ie_set->type == QLINK_IE_SET_ASSOC_REQ && ie_len) {
87 sinfo->assoc_req_ies = ie_set->ie_data;
88 sinfo->assoc_req_ies_len = ie_len;
89 }
90 }
91
92 payload_len -= tlv_full_len;
93 tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
94 }
95
96 if (payload_len) {
97 ret = -EINVAL;
98 goto out;
99 }
100
101 cfg80211_new_sta(vif->netdev, sta_assoc->sta_addr, sinfo,
102 GFP_KERNEL);
103
104 out:
105 kfree(sinfo);
106 return ret;
107 }
108
109 static int
qtnf_event_handle_sta_deauth(struct qtnf_wmac * mac,struct qtnf_vif * vif,const struct qlink_event_sta_deauth * sta_deauth,u16 len)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
qtnf_event_handle_bss_join(struct qtnf_vif * vif,const struct qlink_event_bss_join * join_info,u16 len)144 qtnf_event_handle_bss_join(struct qtnf_vif *vif,
145 const struct qlink_event_bss_join *join_info,
146 u16 len)
147 {
148 struct wiphy *wiphy = priv_to_wiphy(vif->mac);
149 enum ieee80211_statuscode status = le16_to_cpu(join_info->status);
150 struct cfg80211_chan_def chandef;
151 struct cfg80211_bss *bss = NULL;
152 u8 *ie = NULL;
153 size_t payload_len;
154 u16 tlv_type;
155 u16 tlv_value_len;
156 size_t tlv_full_len;
157 const struct qlink_tlv_hdr *tlv;
158 const u8 *rsp_ies = NULL;
159 size_t rsp_ies_len = 0;
160
161 if (unlikely(len < sizeof(*join_info))) {
162 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
163 vif->mac->macid, vif->vifid, len,
164 sizeof(struct qlink_event_bss_join));
165 return -EINVAL;
166 }
167
168 if (vif->wdev.iftype != NL80211_IFTYPE_STATION) {
169 pr_err("VIF%u.%u: BSS_JOIN event when not in STA mode\n",
170 vif->mac->macid, vif->vifid);
171 return -EPROTO;
172 }
173
174 pr_debug("VIF%u.%u: BSSID:%pM chan:%u status:%u\n",
175 vif->mac->macid, vif->vifid, join_info->bssid,
176 le16_to_cpu(join_info->chan.chan.center_freq), status);
177
178 if (status != WLAN_STATUS_SUCCESS)
179 goto done;
180
181 qlink_chandef_q2cfg(wiphy, &join_info->chan, &chandef);
182 if (!cfg80211_chandef_valid(&chandef)) {
183 pr_warn("MAC%u.%u: bad channel freq=%u cf1=%u cf2=%u bw=%u\n",
184 vif->mac->macid, vif->vifid,
185 chandef.chan ? chandef.chan->center_freq : 0,
186 chandef.center_freq1,
187 chandef.center_freq2,
188 chandef.width);
189 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
190 goto done;
191 }
192
193 bss = cfg80211_get_bss(wiphy, chandef.chan, join_info->bssid,
194 NULL, 0, IEEE80211_BSS_TYPE_ESS,
195 IEEE80211_PRIVACY_ANY);
196 if (!bss) {
197 pr_warn("VIF%u.%u: add missing BSS:%pM chan:%u\n",
198 vif->mac->macid, vif->vifid,
199 join_info->bssid, chandef.chan->hw_value);
200
201 if (!vif->wdev.ssid_len) {
202 pr_warn("VIF%u.%u: SSID unknown for BSS:%pM\n",
203 vif->mac->macid, vif->vifid,
204 join_info->bssid);
205 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
206 goto done;
207 }
208
209 ie = kzalloc(2 + vif->wdev.ssid_len, GFP_KERNEL);
210 if (!ie) {
211 pr_warn("VIF%u.%u: IE alloc failed for BSS:%pM\n",
212 vif->mac->macid, vif->vifid,
213 join_info->bssid);
214 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
215 goto done;
216 }
217
218 ie[0] = WLAN_EID_SSID;
219 ie[1] = vif->wdev.ssid_len;
220 memcpy(ie + 2, vif->wdev.ssid, vif->wdev.ssid_len);
221
222 bss = cfg80211_inform_bss(wiphy, chandef.chan,
223 CFG80211_BSS_FTYPE_UNKNOWN,
224 join_info->bssid, 0,
225 WLAN_CAPABILITY_ESS, 100,
226 ie, 2 + vif->wdev.ssid_len,
227 0, GFP_KERNEL);
228 if (!bss) {
229 pr_warn("VIF%u.%u: can't connect to unknown BSS: %pM\n",
230 vif->mac->macid, vif->vifid,
231 join_info->bssid);
232 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
233 goto done;
234 }
235 }
236
237 payload_len = len - sizeof(*join_info);
238 tlv = (struct qlink_tlv_hdr *)join_info->ies;
239
240 while (payload_len >= sizeof(struct qlink_tlv_hdr)) {
241 tlv_type = le16_to_cpu(tlv->type);
242 tlv_value_len = le16_to_cpu(tlv->len);
243 tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
244
245 if (payload_len < tlv_full_len) {
246 pr_warn("invalid %u TLV\n", tlv_type);
247 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
248 goto done;
249 }
250
251 if (tlv_type == QTN_TLV_ID_IE_SET) {
252 const struct qlink_tlv_ie_set *ie_set;
253 unsigned int ie_len;
254
255 if (payload_len < sizeof(*ie_set)) {
256 pr_warn("invalid IE_SET TLV\n");
257 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
258 goto done;
259 }
260
261 ie_set = (const struct qlink_tlv_ie_set *)tlv;
262 ie_len = tlv_value_len -
263 (sizeof(*ie_set) - sizeof(ie_set->hdr));
264
265 switch (ie_set->type) {
266 case QLINK_IE_SET_ASSOC_RESP:
267 if (ie_len) {
268 rsp_ies = ie_set->ie_data;
269 rsp_ies_len = ie_len;
270 }
271 break;
272 default:
273 pr_warn("unexpected IE type: %u\n",
274 ie_set->type);
275 break;
276 }
277 }
278
279 payload_len -= tlv_full_len;
280 tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
281 }
282
283 if (payload_len)
284 pr_warn("VIF%u.%u: unexpected remaining payload: %zu\n",
285 vif->mac->macid, vif->vifid, payload_len);
286
287 done:
288 cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, rsp_ies,
289 rsp_ies_len, status, GFP_KERNEL);
290 if (bss) {
291 if (!ether_addr_equal(vif->bssid, join_info->bssid))
292 ether_addr_copy(vif->bssid, join_info->bssid);
293 cfg80211_put_bss(wiphy, bss);
294 }
295
296 if (status == WLAN_STATUS_SUCCESS)
297 netif_carrier_on(vif->netdev);
298
299 kfree(ie);
300 return 0;
301 }
302
303 static int
qtnf_event_handle_bss_leave(struct qtnf_vif * vif,const struct qlink_event_bss_leave * leave_info,u16 len)304 qtnf_event_handle_bss_leave(struct qtnf_vif *vif,
305 const struct qlink_event_bss_leave *leave_info,
306 u16 len)
307 {
308 if (unlikely(len < sizeof(*leave_info))) {
309 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
310 vif->mac->macid, vif->vifid, len,
311 sizeof(struct qlink_event_bss_leave));
312 return -EINVAL;
313 }
314
315 if (vif->wdev.iftype != NL80211_IFTYPE_STATION) {
316 pr_err("VIF%u.%u: BSS_LEAVE event when not in STA mode\n",
317 vif->mac->macid, vif->vifid);
318 return -EPROTO;
319 }
320
321 pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid);
322
323 cfg80211_disconnected(vif->netdev, le16_to_cpu(leave_info->reason),
324 NULL, 0, 0, GFP_KERNEL);
325 netif_carrier_off(vif->netdev);
326
327 return 0;
328 }
329
330 static int
qtnf_event_handle_mgmt_received(struct qtnf_vif * vif,const struct qlink_event_rxmgmt * rxmgmt,u16 len)331 qtnf_event_handle_mgmt_received(struct qtnf_vif *vif,
332 const struct qlink_event_rxmgmt *rxmgmt,
333 u16 len)
334 {
335 const size_t min_len = sizeof(*rxmgmt) +
336 sizeof(struct ieee80211_hdr_3addr);
337 const struct ieee80211_hdr_3addr *frame = (void *)rxmgmt->frame_data;
338 const u16 frame_len = len - sizeof(*rxmgmt);
339 enum nl80211_rxmgmt_flags flags = 0;
340
341 if (unlikely(len < min_len)) {
342 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
343 vif->mac->macid, vif->vifid, len, min_len);
344 return -EINVAL;
345 }
346
347 if (le32_to_cpu(rxmgmt->flags) & QLINK_RXMGMT_FLAG_ANSWERED)
348 flags |= NL80211_RXMGMT_FLAG_ANSWERED;
349
350 pr_debug("%s LEN:%u FC:%.4X SA:%pM\n", vif->netdev->name, frame_len,
351 le16_to_cpu(frame->frame_control), frame->addr2);
352
353 cfg80211_rx_mgmt(&vif->wdev, le32_to_cpu(rxmgmt->freq), rxmgmt->sig_dbm,
354 rxmgmt->frame_data, frame_len, flags);
355
356 return 0;
357 }
358
359 static int
qtnf_event_handle_scan_results(struct qtnf_vif * vif,const struct qlink_event_scan_result * sr,u16 len)360 qtnf_event_handle_scan_results(struct qtnf_vif *vif,
361 const struct qlink_event_scan_result *sr,
362 u16 len)
363 {
364 struct cfg80211_bss *bss;
365 struct ieee80211_channel *channel;
366 struct wiphy *wiphy = priv_to_wiphy(vif->mac);
367 enum cfg80211_bss_frame_type frame_type = CFG80211_BSS_FTYPE_UNKNOWN;
368 size_t payload_len;
369 u16 tlv_type;
370 u16 tlv_value_len;
371 size_t tlv_full_len;
372 const struct qlink_tlv_hdr *tlv;
373 const u8 *ies = NULL;
374 size_t ies_len = 0;
375
376 if (len < sizeof(*sr)) {
377 pr_err("VIF%u.%u: payload is too short\n", vif->mac->macid,
378 vif->vifid);
379 return -EINVAL;
380 }
381
382 channel = ieee80211_get_channel(wiphy, le16_to_cpu(sr->freq));
383 if (!channel) {
384 pr_err("VIF%u.%u: channel at %u MHz not found\n",
385 vif->mac->macid, vif->vifid, le16_to_cpu(sr->freq));
386 return -EINVAL;
387 }
388
389 payload_len = len - sizeof(*sr);
390 tlv = (struct qlink_tlv_hdr *)sr->payload;
391
392 while (payload_len >= sizeof(struct qlink_tlv_hdr)) {
393 tlv_type = le16_to_cpu(tlv->type);
394 tlv_value_len = le16_to_cpu(tlv->len);
395 tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
396
397 if (tlv_full_len > payload_len)
398 return -EINVAL;
399
400 if (tlv_type == QTN_TLV_ID_IE_SET) {
401 const struct qlink_tlv_ie_set *ie_set;
402 unsigned int ie_len;
403
404 if (payload_len < sizeof(*ie_set))
405 return -EINVAL;
406
407 ie_set = (const struct qlink_tlv_ie_set *)tlv;
408 ie_len = tlv_value_len -
409 (sizeof(*ie_set) - sizeof(ie_set->hdr));
410
411 switch (ie_set->type) {
412 case QLINK_IE_SET_BEACON_IES:
413 frame_type = CFG80211_BSS_FTYPE_BEACON;
414 break;
415 case QLINK_IE_SET_PROBE_RESP_IES:
416 frame_type = CFG80211_BSS_FTYPE_PRESP;
417 break;
418 default:
419 frame_type = CFG80211_BSS_FTYPE_UNKNOWN;
420 }
421
422 if (ie_len) {
423 ies = ie_set->ie_data;
424 ies_len = ie_len;
425 }
426 }
427
428 payload_len -= tlv_full_len;
429 tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
430 }
431
432 if (payload_len)
433 return -EINVAL;
434
435 bss = cfg80211_inform_bss(wiphy, channel, frame_type,
436 sr->bssid, get_unaligned_le64(&sr->tsf),
437 le16_to_cpu(sr->capab),
438 le16_to_cpu(sr->bintval), ies, ies_len,
439 DBM_TO_MBM(sr->sig_dbm), GFP_KERNEL);
440 if (!bss)
441 return -ENOMEM;
442
443 cfg80211_put_bss(wiphy, bss);
444
445 return 0;
446 }
447
448 static int
qtnf_event_handle_scan_complete(struct qtnf_wmac * mac,const struct qlink_event_scan_complete * status,u16 len)449 qtnf_event_handle_scan_complete(struct qtnf_wmac *mac,
450 const struct qlink_event_scan_complete *status,
451 u16 len)
452 {
453 if (len < sizeof(*status)) {
454 pr_err("MAC%u: payload is too short\n", mac->macid);
455 return -EINVAL;
456 }
457
458 qtnf_scan_done(mac, le32_to_cpu(status->flags) & QLINK_SCAN_ABORTED);
459
460 return 0;
461 }
462
463 static int
qtnf_event_handle_freq_change(struct qtnf_wmac * mac,const struct qlink_event_freq_change * data,u16 len)464 qtnf_event_handle_freq_change(struct qtnf_wmac *mac,
465 const struct qlink_event_freq_change *data,
466 u16 len)
467 {
468 struct wiphy *wiphy = priv_to_wiphy(mac);
469 struct cfg80211_chan_def chandef;
470 struct qtnf_vif *vif;
471 int i;
472
473 if (len < sizeof(*data)) {
474 pr_err("MAC%u: payload is too short\n", mac->macid);
475 return -EINVAL;
476 }
477
478 if (!wiphy->registered)
479 return 0;
480
481 qlink_chandef_q2cfg(wiphy, &data->chan, &chandef);
482
483 if (!cfg80211_chandef_valid(&chandef)) {
484 pr_err("MAC%u: bad channel freq=%u cf1=%u cf2=%u bw=%u\n",
485 mac->macid, chandef.chan->center_freq,
486 chandef.center_freq1, chandef.center_freq2,
487 chandef.width);
488 return -EINVAL;
489 }
490
491 pr_debug("MAC%d: new channel ieee=%u freq1=%u freq2=%u bw=%u\n",
492 mac->macid, chandef.chan->hw_value, chandef.center_freq1,
493 chandef.center_freq2, chandef.width);
494
495 for (i = 0; i < QTNF_MAX_INTF; i++) {
496 vif = &mac->iflist[i];
497
498 if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)
499 continue;
500
501 if (vif->wdev.iftype == NL80211_IFTYPE_STATION &&
502 !vif->wdev.current_bss)
503 continue;
504
505 if (!vif->netdev)
506 continue;
507
508 mutex_lock(&vif->wdev.mtx);
509 cfg80211_ch_switch_notify(vif->netdev, &chandef);
510 mutex_unlock(&vif->wdev.mtx);
511 }
512
513 return 0;
514 }
515
qtnf_event_handle_radar(struct qtnf_vif * vif,const struct qlink_event_radar * ev,u16 len)516 static int qtnf_event_handle_radar(struct qtnf_vif *vif,
517 const struct qlink_event_radar *ev,
518 u16 len)
519 {
520 struct wiphy *wiphy = priv_to_wiphy(vif->mac);
521 struct cfg80211_chan_def chandef;
522
523 if (len < sizeof(*ev)) {
524 pr_err("MAC%u: payload is too short\n", vif->mac->macid);
525 return -EINVAL;
526 }
527
528 if (!wiphy->registered || !vif->netdev)
529 return 0;
530
531 qlink_chandef_q2cfg(wiphy, &ev->chan, &chandef);
532
533 if (!cfg80211_chandef_valid(&chandef)) {
534 pr_err("MAC%u: bad channel f1=%u f2=%u bw=%u\n",
535 vif->mac->macid,
536 chandef.center_freq1, chandef.center_freq2,
537 chandef.width);
538 return -EINVAL;
539 }
540
541 pr_info("%s: radar event=%u f1=%u f2=%u bw=%u\n",
542 vif->netdev->name, ev->event,
543 chandef.center_freq1, chandef.center_freq2,
544 chandef.width);
545
546 switch (ev->event) {
547 case QLINK_RADAR_DETECTED:
548 cfg80211_radar_event(wiphy, &chandef, GFP_KERNEL);
549 break;
550 case QLINK_RADAR_CAC_FINISHED:
551 if (!vif->wdev.cac_started)
552 break;
553
554 cfg80211_cac_event(vif->netdev, &chandef,
555 NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
556 break;
557 case QLINK_RADAR_CAC_ABORTED:
558 if (!vif->wdev.cac_started)
559 break;
560
561 cfg80211_cac_event(vif->netdev, &chandef,
562 NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
563 break;
564 case QLINK_RADAR_CAC_STARTED:
565 if (vif->wdev.cac_started)
566 break;
567
568 if (!wiphy_ext_feature_isset(wiphy,
569 NL80211_EXT_FEATURE_DFS_OFFLOAD))
570 break;
571
572 cfg80211_cac_event(vif->netdev, &chandef,
573 NL80211_RADAR_CAC_STARTED, GFP_KERNEL);
574 break;
575 default:
576 pr_warn("%s: unhandled radar event %u\n",
577 vif->netdev->name, ev->event);
578 break;
579 }
580
581 return 0;
582 }
583
584 static int
qtnf_event_handle_external_auth(struct qtnf_vif * vif,const struct qlink_event_external_auth * ev,u16 len)585 qtnf_event_handle_external_auth(struct qtnf_vif *vif,
586 const struct qlink_event_external_auth *ev,
587 u16 len)
588 {
589 struct cfg80211_external_auth_params auth = {0};
590 struct wiphy *wiphy = priv_to_wiphy(vif->mac);
591 int ret;
592
593 if (len < sizeof(*ev)) {
594 pr_err("MAC%u: payload is too short\n", vif->mac->macid);
595 return -EINVAL;
596 }
597
598 if (!wiphy->registered || !vif->netdev)
599 return 0;
600
601 if (ev->ssid_len) {
602 memcpy(auth.ssid.ssid, ev->ssid, ev->ssid_len);
603 auth.ssid.ssid_len = ev->ssid_len;
604 }
605
606 auth.key_mgmt_suite = le32_to_cpu(ev->akm_suite);
607 ether_addr_copy(auth.bssid, ev->bssid);
608 auth.action = ev->action;
609
610 pr_info("%s: external auth bss=%pM action=%u akm=%u\n",
611 vif->netdev->name, auth.bssid, auth.action,
612 auth.key_mgmt_suite);
613
614 ret = cfg80211_external_auth_request(vif->netdev, &auth, GFP_KERNEL);
615 if (ret)
616 pr_warn("failed to offload external auth request\n");
617
618 return ret;
619 }
620
qtnf_event_parse(struct qtnf_wmac * mac,const struct sk_buff * event_skb)621 static int qtnf_event_parse(struct qtnf_wmac *mac,
622 const struct sk_buff *event_skb)
623 {
624 const struct qlink_event *event;
625 struct qtnf_vif *vif = NULL;
626 int ret = -1;
627 u16 event_id;
628 u16 event_len;
629
630 event = (const struct qlink_event *)event_skb->data;
631 event_id = le16_to_cpu(event->event_id);
632 event_len = le16_to_cpu(event->mhdr.len);
633
634 if (likely(event->vifid < QTNF_MAX_INTF)) {
635 vif = &mac->iflist[event->vifid];
636 } else {
637 pr_err("invalid vif(%u)\n", event->vifid);
638 return -EINVAL;
639 }
640
641 switch (event_id) {
642 case QLINK_EVENT_STA_ASSOCIATED:
643 ret = qtnf_event_handle_sta_assoc(mac, vif, (const void *)event,
644 event_len);
645 break;
646 case QLINK_EVENT_STA_DEAUTH:
647 ret = qtnf_event_handle_sta_deauth(mac, vif,
648 (const void *)event,
649 event_len);
650 break;
651 case QLINK_EVENT_MGMT_RECEIVED:
652 ret = qtnf_event_handle_mgmt_received(vif, (const void *)event,
653 event_len);
654 break;
655 case QLINK_EVENT_SCAN_RESULTS:
656 ret = qtnf_event_handle_scan_results(vif, (const void *)event,
657 event_len);
658 break;
659 case QLINK_EVENT_SCAN_COMPLETE:
660 ret = qtnf_event_handle_scan_complete(mac, (const void *)event,
661 event_len);
662 break;
663 case QLINK_EVENT_BSS_JOIN:
664 ret = qtnf_event_handle_bss_join(vif, (const void *)event,
665 event_len);
666 break;
667 case QLINK_EVENT_BSS_LEAVE:
668 ret = qtnf_event_handle_bss_leave(vif, (const void *)event,
669 event_len);
670 break;
671 case QLINK_EVENT_FREQ_CHANGE:
672 ret = qtnf_event_handle_freq_change(mac, (const void *)event,
673 event_len);
674 break;
675 case QLINK_EVENT_RADAR:
676 ret = qtnf_event_handle_radar(vif, (const void *)event,
677 event_len);
678 break;
679 case QLINK_EVENT_EXTERNAL_AUTH:
680 ret = qtnf_event_handle_external_auth(vif, (const void *)event,
681 event_len);
682 break;
683 default:
684 pr_warn("unknown event type: %x\n", event_id);
685 break;
686 }
687
688 return ret;
689 }
690
qtnf_event_process_skb(struct qtnf_bus * bus,const struct sk_buff * skb)691 static int qtnf_event_process_skb(struct qtnf_bus *bus,
692 const struct sk_buff *skb)
693 {
694 const struct qlink_event *event;
695 struct qtnf_wmac *mac;
696 int res;
697
698 if (unlikely(!skb || skb->len < sizeof(*event))) {
699 pr_err("invalid event buffer\n");
700 return -EINVAL;
701 }
702
703 event = (struct qlink_event *)skb->data;
704
705 mac = qtnf_core_get_mac(bus, event->macid);
706
707 pr_debug("new event id:%x len:%u mac:%u vif:%u\n",
708 le16_to_cpu(event->event_id), le16_to_cpu(event->mhdr.len),
709 event->macid, event->vifid);
710
711 if (unlikely(!mac))
712 return -ENXIO;
713
714 rtnl_lock();
715 res = qtnf_event_parse(mac, skb);
716 rtnl_unlock();
717
718 return res;
719 }
720
qtnf_event_work_handler(struct work_struct * work)721 void qtnf_event_work_handler(struct work_struct *work)
722 {
723 struct qtnf_bus *bus = container_of(work, struct qtnf_bus, event_work);
724 struct sk_buff_head *event_queue = &bus->trans.event_queue;
725 struct sk_buff *current_event_skb = skb_dequeue(event_queue);
726
727 while (current_event_skb) {
728 qtnf_event_process_skb(bus, current_event_skb);
729 dev_kfree_skb_any(current_event_skb);
730 current_event_skb = skb_dequeue(event_queue);
731 }
732 }
733