linux/drivers/net/wireless/quantenna/qtnfmac/event.c
<<
>>
Prefs
   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
  30static int
  31qtnf_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
 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        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
 183static int
 184qtnf_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
 218static int
 219qtnf_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
 247static int
 248qtnf_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
 336static int
 337qtnf_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
 351static int
 352qtnf_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
 398static 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
 455static 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
 521static 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
 551void 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