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