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