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;
  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
 117out:
 118        kfree(sinfo);
 119        return ret;
 120}
 121
 122static int
 123qtnf_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
 156static int
 157qtnf_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
 196static int
 197qtnf_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
 229static int
 230qtnf_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
 258static int
 259qtnf_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
 347static int
 348qtnf_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
 362static int
 363qtnf_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
 409static 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
 477static 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
 543static 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
 573void 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}
 585