Merge tag 'trace-v4.14-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
[sfrench/cifs-2.6.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
29 static int
30 qtnf_event_handle_sta_assoc(struct qtnf_wmac *mac, struct qtnf_vif *vif,
31                             const struct qlink_event_sta_assoc *sta_assoc,
32                             u16 len)
33 {
34         const u8 *sta_addr;
35         u16 frame_control;
36         struct station_info sinfo = { 0 };
37         size_t payload_len;
38         u16 tlv_type;
39         u16 tlv_value_len;
40         size_t tlv_full_len;
41         const struct qlink_tlv_hdr *tlv;
42
43         if (unlikely(len < sizeof(*sta_assoc))) {
44                 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
45                        mac->macid, vif->vifid, len, sizeof(*sta_assoc));
46                 return -EINVAL;
47         }
48
49         if (vif->wdev.iftype != NL80211_IFTYPE_AP) {
50                 pr_err("VIF%u.%u: STA_ASSOC event when not in AP mode\n",
51                        mac->macid, vif->vifid);
52                 return -EPROTO;
53         }
54
55         if (!(vif->bss_status & QTNF_STATE_AP_START)) {
56                 pr_err("VIF%u.%u: STA_ASSOC event when AP is not started\n",
57                        mac->macid, vif->vifid);
58                 return -EPROTO;
59         }
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_list, sta_addr);
68
69         sinfo.assoc_req_ies = NULL;
70         sinfo.assoc_req_ies_len = 0;
71
72         payload_len = len - sizeof(*sta_assoc);
73         tlv = (struct qlink_tlv_hdr *)sta_assoc->ies;
74
75         while (payload_len >= sizeof(struct qlink_tlv_hdr)) {
76                 tlv_type = le16_to_cpu(tlv->type);
77                 tlv_value_len = le16_to_cpu(tlv->len);
78                 tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
79
80                 if (tlv_full_len > payload_len) {
81                         pr_warn("VIF%u.%u: malformed TLV 0x%.2X; LEN: %u\n",
82                                 mac->macid, vif->vifid, tlv_type,
83                                 tlv_value_len);
84                         return -EINVAL;
85                 }
86
87                 if (tlv_type == QTN_TLV_ID_IE_SET) {
88                         sinfo.assoc_req_ies = tlv->val;
89                         sinfo.assoc_req_ies_len = tlv_value_len;
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                 pr_warn("VIF%u.%u: malformed TLV buf; bytes left: %zu\n",
98                         mac->macid, vif->vifid, payload_len);
99                 return -EINVAL;
100         }
101
102         cfg80211_new_sta(vif->netdev, sta_assoc->sta_addr, &sinfo,
103                          GFP_KERNEL);
104
105         return 0;
106 }
107
108 static int
109 qtnf_event_handle_sta_deauth(struct qtnf_wmac *mac, struct qtnf_vif *vif,
110                              const struct qlink_event_sta_deauth *sta_deauth,
111                              u16 len)
112 {
113         const u8 *sta_addr;
114         u16 reason;
115
116         if (unlikely(len < sizeof(*sta_deauth))) {
117                 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
118                        mac->macid, vif->vifid, len,
119                        sizeof(struct qlink_event_sta_deauth));
120                 return -EINVAL;
121         }
122
123         if (vif->wdev.iftype != NL80211_IFTYPE_AP) {
124                 pr_err("VIF%u.%u: STA_DEAUTH event when not in AP mode\n",
125                        mac->macid, vif->vifid);
126                 return -EPROTO;
127         }
128
129         if (!(vif->bss_status & QTNF_STATE_AP_START)) {
130                 pr_err("VIF%u.%u: STA_DEAUTH event when AP is not started\n",
131                        mac->macid, vif->vifid);
132                 return -EPROTO;
133         }
134
135         sta_addr = sta_deauth->sta_addr;
136         reason = le16_to_cpu(sta_deauth->reason);
137
138         pr_debug("VIF%u.%u: MAC:%pM reason:%x\n", mac->macid, vif->vifid,
139                  sta_addr, reason);
140
141         if (qtnf_sta_list_del(&vif->sta_list, sta_addr))
142                 cfg80211_del_sta(vif->netdev, sta_deauth->sta_addr,
143                                  GFP_KERNEL);
144
145         return 0;
146 }
147
148 static int
149 qtnf_event_handle_bss_join(struct qtnf_vif *vif,
150                            const struct qlink_event_bss_join *join_info,
151                            u16 len)
152 {
153         if (unlikely(len < sizeof(*join_info))) {
154                 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
155                        vif->mac->macid, vif->vifid, len,
156                        sizeof(struct qlink_event_bss_join));
157                 return -EINVAL;
158         }
159
160         if (vif->wdev.iftype != NL80211_IFTYPE_STATION) {
161                 pr_err("VIF%u.%u: BSS_JOIN event when not in STA mode\n",
162                        vif->mac->macid, vif->vifid);
163                 return -EPROTO;
164         }
165
166         if (vif->sta_state != QTNF_STA_CONNECTING) {
167                 pr_err("VIF%u.%u: BSS_JOIN event when STA is not connecting\n",
168                        vif->mac->macid, vif->vifid);
169                 return -EPROTO;
170         }
171
172         pr_debug("VIF%u.%u: BSSID:%pM\n", vif->mac->macid, vif->vifid,
173                  join_info->bssid);
174
175         cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, NULL,
176                                 0, le16_to_cpu(join_info->status), GFP_KERNEL);
177
178         if (le16_to_cpu(join_info->status) == WLAN_STATUS_SUCCESS) {
179                 vif->sta_state = QTNF_STA_CONNECTED;
180                 netif_carrier_on(vif->netdev);
181         } else {
182                 vif->sta_state = QTNF_STA_DISCONNECTED;
183         }
184
185         return 0;
186 }
187
188 static int
189 qtnf_event_handle_bss_leave(struct qtnf_vif *vif,
190                             const struct qlink_event_bss_leave *leave_info,
191                             u16 len)
192 {
193         if (unlikely(len < sizeof(*leave_info))) {
194                 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
195                        vif->mac->macid, vif->vifid, len,
196                        sizeof(struct qlink_event_bss_leave));
197                 return -EINVAL;
198         }
199
200         if (vif->wdev.iftype != NL80211_IFTYPE_STATION) {
201                 pr_err("VIF%u.%u: BSS_LEAVE event when not in STA mode\n",
202                        vif->mac->macid, vif->vifid);
203                 return -EPROTO;
204         }
205
206         if (vif->sta_state != QTNF_STA_CONNECTED) {
207                 pr_err("VIF%u.%u: BSS_LEAVE event when STA is not connected\n",
208                        vif->mac->macid, vif->vifid);
209                 return -EPROTO;
210         }
211
212         pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid);
213
214         cfg80211_disconnected(vif->netdev, le16_to_cpu(leave_info->reason),
215                               NULL, 0, 0, GFP_KERNEL);
216
217         vif->sta_state = QTNF_STA_DISCONNECTED;
218         netif_carrier_off(vif->netdev);
219
220         return 0;
221 }
222
223 static int
224 qtnf_event_handle_mgmt_received(struct qtnf_vif *vif,
225                                 const struct qlink_event_rxmgmt *rxmgmt,
226                                 u16 len)
227 {
228         const size_t min_len = sizeof(*rxmgmt) +
229                                sizeof(struct ieee80211_hdr_3addr);
230         const struct ieee80211_hdr_3addr *frame = (void *)rxmgmt->frame_data;
231         const u16 frame_len = len - sizeof(*rxmgmt);
232         enum nl80211_rxmgmt_flags flags = 0;
233
234         if (unlikely(len < min_len)) {
235                 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
236                        vif->mac->macid, vif->vifid, len, min_len);
237                 return -EINVAL;
238         }
239
240         if (le32_to_cpu(rxmgmt->flags) & QLINK_RXMGMT_FLAG_ANSWERED)
241                 flags |= NL80211_RXMGMT_FLAG_ANSWERED;
242
243         pr_debug("%s LEN:%u FC:%.4X SA:%pM\n", vif->netdev->name, frame_len,
244                  le16_to_cpu(frame->frame_control), frame->addr2);
245
246         cfg80211_rx_mgmt(&vif->wdev, le32_to_cpu(rxmgmt->freq),
247                          le32_to_cpu(rxmgmt->sig_dbm), rxmgmt->frame_data,
248                          frame_len, flags);
249
250         return 0;
251 }
252
253 static int
254 qtnf_event_handle_scan_results(struct qtnf_vif *vif,
255                                const struct qlink_event_scan_result *sr,
256                                u16 len)
257 {
258         struct cfg80211_bss *bss;
259         struct ieee80211_channel *channel;
260         struct wiphy *wiphy = priv_to_wiphy(vif->mac);
261         enum cfg80211_bss_frame_type frame_type;
262         size_t payload_len;
263         u16 tlv_type;
264         u16 tlv_value_len;
265         size_t tlv_full_len;
266         const struct qlink_tlv_hdr *tlv;
267
268         const u8 *ies = NULL;
269         size_t ies_len = 0;
270
271         if (len < sizeof(*sr)) {
272                 pr_err("VIF%u.%u: payload is too short\n", vif->mac->macid,
273                        vif->vifid);
274                 return -EINVAL;
275         }
276
277         channel = ieee80211_get_channel(wiphy, le16_to_cpu(sr->freq));
278         if (!channel) {
279                 pr_err("VIF%u.%u: channel at %u MHz not found\n",
280                        vif->mac->macid, vif->vifid, le16_to_cpu(sr->freq));
281                 return -EINVAL;
282         }
283
284         switch (sr->frame_type) {
285         case QLINK_BSS_FTYPE_BEACON:
286                 frame_type = CFG80211_BSS_FTYPE_BEACON;
287                 break;
288         case QLINK_BSS_FTYPE_PRESP:
289                 frame_type = CFG80211_BSS_FTYPE_PRESP;
290                 break;
291         default:
292                 frame_type = CFG80211_BSS_FTYPE_UNKNOWN;
293         }
294
295         payload_len = len - sizeof(*sr);
296         tlv = (struct qlink_tlv_hdr *)sr->payload;
297
298         while (payload_len >= sizeof(struct qlink_tlv_hdr)) {
299                 tlv_type = le16_to_cpu(tlv->type);
300                 tlv_value_len = le16_to_cpu(tlv->len);
301                 tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
302
303                 if (tlv_full_len > payload_len) {
304                         pr_warn("VIF%u.%u: malformed TLV 0x%.2X; LEN: %u\n",
305                                 vif->mac->macid, vif->vifid, tlv_type,
306                                 tlv_value_len);
307                         return -EINVAL;
308                 }
309
310                 if (tlv_type == QTN_TLV_ID_IE_SET) {
311                         ies = tlv->val;
312                         ies_len = tlv_value_len;
313                 }
314
315                 payload_len -= tlv_full_len;
316                 tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
317         }
318
319         if (payload_len) {
320                 pr_warn("VIF%u.%u: malformed TLV buf; bytes left: %zu\n",
321                         vif->mac->macid, vif->vifid, payload_len);
322                 return -EINVAL;
323         }
324
325         bss = cfg80211_inform_bss(wiphy, channel, frame_type,
326                                   sr->bssid, get_unaligned_le64(&sr->tsf),
327                                   le16_to_cpu(sr->capab),
328                                   le16_to_cpu(sr->bintval), ies, ies_len,
329                                   sr->signal, GFP_KERNEL);
330         if (!bss)
331                 return -ENOMEM;
332
333         cfg80211_put_bss(wiphy, bss);
334
335         return 0;
336 }
337
338 static int
339 qtnf_event_handle_scan_complete(struct qtnf_wmac *mac,
340                                 const struct qlink_event_scan_complete *status,
341                                 u16 len)
342 {
343         if (len < sizeof(*status)) {
344                 pr_err("MAC%u: payload is too short\n", mac->macid);
345                 return -EINVAL;
346         }
347
348         qtnf_scan_done(mac, le32_to_cpu(status->flags) & QLINK_SCAN_ABORTED);
349
350         return 0;
351 }
352
353 static int
354 qtnf_event_handle_freq_change(struct qtnf_wmac *mac,
355                               const struct qlink_event_freq_change *data,
356                               u16 len)
357 {
358         struct wiphy *wiphy = priv_to_wiphy(mac);
359         struct cfg80211_chan_def chandef;
360         struct ieee80211_channel *chan;
361         struct qtnf_vif *vif;
362         int freq;
363         int i;
364
365         if (len < sizeof(*data)) {
366                 pr_err("payload is too short\n");
367                 return -EINVAL;
368         }
369
370         freq = le32_to_cpu(data->freq);
371         chan = ieee80211_get_channel(wiphy, freq);
372         if (!chan) {
373                 pr_err("channel at %d MHz not found\n", freq);
374                 return -EINVAL;
375         }
376
377         pr_debug("MAC%d switch to new channel %u MHz\n", mac->macid, freq);
378
379         if (mac->status & QTNF_MAC_CSA_ACTIVE) {
380                 mac->status &= ~QTNF_MAC_CSA_ACTIVE;
381                 if (chan->hw_value != mac->csa_chandef.chan->hw_value)
382                         pr_warn("unexpected switch to %u during CSA to %u\n",
383                                 chan->hw_value,
384                                 mac->csa_chandef.chan->hw_value);
385         }
386
387         /* FIXME: need to figure out proper nl80211_channel_type value */
388         cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20);
389         /* fall-back to minimal safe chandef description */
390         if (!cfg80211_chandef_valid(&chandef))
391                 cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20);
392
393         memcpy(&mac->chandef, &chandef, sizeof(mac->chandef));
394
395         for (i = 0; i < QTNF_MAX_INTF; i++) {
396                 vif = &mac->iflist[i];
397                 if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)
398                         continue;
399
400                 if (vif->netdev) {
401                         mutex_lock(&vif->wdev.mtx);
402                         cfg80211_ch_switch_notify(vif->netdev, &chandef);
403                         mutex_unlock(&vif->wdev.mtx);
404                 }
405         }
406
407         return 0;
408 }
409
410 static int qtnf_event_parse(struct qtnf_wmac *mac,
411                             const struct sk_buff *event_skb)
412 {
413         const struct qlink_event *event;
414         struct qtnf_vif *vif = NULL;
415         int ret = -1;
416         u16 event_id;
417         u16 event_len;
418
419         event = (const struct qlink_event *)event_skb->data;
420         event_id = le16_to_cpu(event->event_id);
421         event_len = le16_to_cpu(event->mhdr.len);
422
423         if (likely(event->vifid < QTNF_MAX_INTF)) {
424                 vif = &mac->iflist[event->vifid];
425         } else {
426                 pr_err("invalid vif(%u)\n", event->vifid);
427                 return -EINVAL;
428         }
429
430         switch (event_id) {
431         case QLINK_EVENT_STA_ASSOCIATED:
432                 ret = qtnf_event_handle_sta_assoc(mac, vif, (const void *)event,
433                                                   event_len);
434                 break;
435         case QLINK_EVENT_STA_DEAUTH:
436                 ret = qtnf_event_handle_sta_deauth(mac, vif,
437                                                    (const void *)event,
438                                                    event_len);
439                 break;
440         case QLINK_EVENT_MGMT_RECEIVED:
441                 ret = qtnf_event_handle_mgmt_received(vif, (const void *)event,
442                                                       event_len);
443                 break;
444         case QLINK_EVENT_SCAN_RESULTS:
445                 ret = qtnf_event_handle_scan_results(vif, (const void *)event,
446                                                      event_len);
447                 break;
448         case QLINK_EVENT_SCAN_COMPLETE:
449                 ret = qtnf_event_handle_scan_complete(mac, (const void *)event,
450                                                       event_len);
451                 break;
452         case QLINK_EVENT_BSS_JOIN:
453                 ret = qtnf_event_handle_bss_join(vif, (const void *)event,
454                                                  event_len);
455                 break;
456         case QLINK_EVENT_BSS_LEAVE:
457                 ret = qtnf_event_handle_bss_leave(vif, (const void *)event,
458                                                   event_len);
459                 break;
460         case QLINK_EVENT_FREQ_CHANGE:
461                 ret = qtnf_event_handle_freq_change(mac, (const void *)event,
462                                                     event_len);
463                 break;
464         default:
465                 pr_warn("unknown event type: %x\n", event_id);
466                 break;
467         }
468
469         return ret;
470 }
471
472 static int qtnf_event_process_skb(struct qtnf_bus *bus,
473                                   const struct sk_buff *skb)
474 {
475         const struct qlink_event *event;
476         struct qtnf_wmac *mac;
477         int res;
478
479         if (unlikely(!skb || skb->len < sizeof(*event))) {
480                 pr_err("invalid event buffer\n");
481                 return -EINVAL;
482         }
483
484         event = (struct qlink_event *)skb->data;
485
486         mac = qtnf_core_get_mac(bus, event->macid);
487
488         pr_debug("new event id:%x len:%u mac:%u vif:%u\n",
489                  le16_to_cpu(event->event_id), le16_to_cpu(event->mhdr.len),
490                  event->macid, event->vifid);
491
492         if (unlikely(!mac))
493                 return -ENXIO;
494
495         qtnf_bus_lock(bus);
496         res = qtnf_event_parse(mac, skb);
497         qtnf_bus_unlock(bus);
498
499         return res;
500 }
501
502 void qtnf_event_work_handler(struct work_struct *work)
503 {
504         struct qtnf_bus *bus = container_of(work, struct qtnf_bus, event_work);
505         struct sk_buff_head *event_queue = &bus->trans.event_queue;
506         struct sk_buff *current_event_skb = skb_dequeue(event_queue);
507
508         while (current_event_skb) {
509                 qtnf_event_process_skb(bus, current_event_skb);
510                 dev_kfree_skb_any(current_event_skb);
511                 current_event_skb = skb_dequeue(event_queue);
512         }
513 }