root/drivers/net/wireless/quantenna/qtnfmac/event.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. qtnf_event_handle_sta_assoc
  2. qtnf_event_handle_sta_deauth
  3. qtnf_event_handle_bss_join
  4. qtnf_event_handle_bss_leave
  5. qtnf_event_handle_mgmt_received
  6. qtnf_event_handle_scan_results
  7. qtnf_event_handle_scan_complete
  8. qtnf_event_handle_freq_change
  9. qtnf_event_handle_radar
  10. qtnf_event_handle_external_auth
  11. qtnf_event_parse
  12. qtnf_event_process_skb
  13. qtnf_event_work_handler

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

/* [<][>][^][v][top][bottom][index][help] */