1 /* 2 * Copyright (c) 2015-2016 Quantenna Communications, Inc. 3 * All rights reserved. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License 7 * as published by the Free Software Foundation; either version 2 8 * of the License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 */ 16 17 #include <linux/kernel.h> 18 #include <linux/module.h> 19 #include <linux/slab.h> 20 21 #include "cfg80211.h" 22 #include "core.h" 23 #include "qlink.h" 24 #include "bus.h" 25 #include "trans.h" 26 #include "util.h" 27 #include "event.h" 28 #include "qlink_util.h" 29 30 static int 31 qtnf_event_handle_sta_assoc(struct qtnf_wmac *mac, struct qtnf_vif *vif, 32 const struct qlink_event_sta_assoc *sta_assoc, 33 u16 len) 34 { 35 const u8 *sta_addr; 36 u16 frame_control; 37 struct station_info sinfo = { 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_list, sta_addr); 63 64 sinfo.assoc_req_ies = NULL; 65 sinfo.assoc_req_ies_len = 0; 66 67 payload_len = len - sizeof(*sta_assoc); 68 tlv = (const struct qlink_tlv_hdr *)sta_assoc->ies; 69 70 while (payload_len >= sizeof(*tlv)) { 71 tlv_type = le16_to_cpu(tlv->type); 72 tlv_value_len = le16_to_cpu(tlv->len); 73 tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); 74 75 if (tlv_full_len > payload_len) 76 return -EINVAL; 77 78 if (tlv_type == QTN_TLV_ID_IE_SET) { 79 const struct qlink_tlv_ie_set *ie_set; 80 unsigned int ie_len; 81 82 if (payload_len < sizeof(*ie_set)) 83 return -EINVAL; 84 85 ie_set = (const struct qlink_tlv_ie_set *)tlv; 86 ie_len = tlv_value_len - 87 (sizeof(*ie_set) - sizeof(ie_set->hdr)); 88 89 if (ie_set->type == QLINK_IE_SET_ASSOC_REQ && ie_len) { 90 sinfo.assoc_req_ies = ie_set->ie_data; 91 sinfo.assoc_req_ies_len = ie_len; 92 } 93 } 94 95 payload_len -= tlv_full_len; 96 tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); 97 } 98 99 if (payload_len) 100 return -EINVAL; 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 sta_addr = sta_deauth->sta_addr; 130 reason = le16_to_cpu(sta_deauth->reason); 131 132 pr_debug("VIF%u.%u: MAC:%pM reason:%x\n", mac->macid, vif->vifid, 133 sta_addr, reason); 134 135 if (qtnf_sta_list_del(&vif->sta_list, sta_addr)) 136 cfg80211_del_sta(vif->netdev, sta_deauth->sta_addr, 137 GFP_KERNEL); 138 139 return 0; 140 } 141 142 static int 143 qtnf_event_handle_bss_join(struct qtnf_vif *vif, 144 const struct qlink_event_bss_join *join_info, 145 u16 len) 146 { 147 if (unlikely(len < sizeof(*join_info))) { 148 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", 149 vif->mac->macid, vif->vifid, len, 150 sizeof(struct qlink_event_bss_join)); 151 return -EINVAL; 152 } 153 154 if (vif->wdev.iftype != NL80211_IFTYPE_STATION) { 155 pr_err("VIF%u.%u: BSS_JOIN event when not in STA mode\n", 156 vif->mac->macid, vif->vifid); 157 return -EPROTO; 158 } 159 160 if (vif->sta_state != QTNF_STA_CONNECTING) { 161 pr_err("VIF%u.%u: BSS_JOIN event when STA is not connecting\n", 162 vif->mac->macid, vif->vifid); 163 return -EPROTO; 164 } 165 166 pr_debug("VIF%u.%u: BSSID:%pM\n", vif->mac->macid, vif->vifid, 167 join_info->bssid); 168 169 cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, NULL, 170 0, le16_to_cpu(join_info->status), GFP_KERNEL); 171 172 if (le16_to_cpu(join_info->status) == WLAN_STATUS_SUCCESS) { 173 vif->sta_state = QTNF_STA_CONNECTED; 174 netif_carrier_on(vif->netdev); 175 } else { 176 vif->sta_state = QTNF_STA_DISCONNECTED; 177 } 178 179 return 0; 180 } 181 182 static int 183 qtnf_event_handle_bss_leave(struct qtnf_vif *vif, 184 const struct qlink_event_bss_leave *leave_info, 185 u16 len) 186 { 187 if (unlikely(len < sizeof(*leave_info))) { 188 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", 189 vif->mac->macid, vif->vifid, len, 190 sizeof(struct qlink_event_bss_leave)); 191 return -EINVAL; 192 } 193 194 if (vif->wdev.iftype != NL80211_IFTYPE_STATION) { 195 pr_err("VIF%u.%u: BSS_LEAVE event when not in STA mode\n", 196 vif->mac->macid, vif->vifid); 197 return -EPROTO; 198 } 199 200 if (vif->sta_state != QTNF_STA_CONNECTED) { 201 pr_err("VIF%u.%u: BSS_LEAVE event when STA is not connected\n", 202 vif->mac->macid, vif->vifid); 203 return -EPROTO; 204 } 205 206 pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid); 207 208 cfg80211_disconnected(vif->netdev, le16_to_cpu(leave_info->reason), 209 NULL, 0, 0, GFP_KERNEL); 210 211 vif->sta_state = QTNF_STA_DISCONNECTED; 212 netif_carrier_off(vif->netdev); 213 214 return 0; 215 } 216 217 static int 218 qtnf_event_handle_mgmt_received(struct qtnf_vif *vif, 219 const struct qlink_event_rxmgmt *rxmgmt, 220 u16 len) 221 { 222 const size_t min_len = sizeof(*rxmgmt) + 223 sizeof(struct ieee80211_hdr_3addr); 224 const struct ieee80211_hdr_3addr *frame = (void *)rxmgmt->frame_data; 225 const u16 frame_len = len - sizeof(*rxmgmt); 226 enum nl80211_rxmgmt_flags flags = 0; 227 228 if (unlikely(len < min_len)) { 229 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", 230 vif->mac->macid, vif->vifid, len, min_len); 231 return -EINVAL; 232 } 233 234 if (le32_to_cpu(rxmgmt->flags) & QLINK_RXMGMT_FLAG_ANSWERED) 235 flags |= NL80211_RXMGMT_FLAG_ANSWERED; 236 237 pr_debug("%s LEN:%u FC:%.4X SA:%pM\n", vif->netdev->name, frame_len, 238 le16_to_cpu(frame->frame_control), frame->addr2); 239 240 cfg80211_rx_mgmt(&vif->wdev, le32_to_cpu(rxmgmt->freq), 241 le32_to_cpu(rxmgmt->sig_dbm), rxmgmt->frame_data, 242 frame_len, flags); 243 244 return 0; 245 } 246 247 static int 248 qtnf_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 sr->signal, GFP_KERNEL); 328 if (!bss) 329 return -ENOMEM; 330 331 cfg80211_put_bss(wiphy, bss); 332 333 return 0; 334 } 335 336 static int 337 qtnf_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 351 static int 352 qtnf_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 f1=%u f2=%u bw=%u\n", mac->macid, 373 chandef.center_freq1, chandef.center_freq2, 374 chandef.width); 375 return -EINVAL; 376 } 377 378 pr_debug("MAC%d: new channel ieee=%u freq1=%u freq2=%u bw=%u\n", 379 mac->macid, chandef.chan->hw_value, chandef.center_freq1, 380 chandef.center_freq2, chandef.width); 381 382 for (i = 0; i < QTNF_MAX_INTF; i++) { 383 vif = &mac->iflist[i]; 384 if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) 385 continue; 386 387 if (vif->netdev) { 388 mutex_lock(&vif->wdev.mtx); 389 cfg80211_ch_switch_notify(vif->netdev, &chandef); 390 mutex_unlock(&vif->wdev.mtx); 391 } 392 } 393 394 return 0; 395 } 396 397 static int qtnf_event_parse(struct qtnf_wmac *mac, 398 const struct sk_buff *event_skb) 399 { 400 const struct qlink_event *event; 401 struct qtnf_vif *vif = NULL; 402 int ret = -1; 403 u16 event_id; 404 u16 event_len; 405 406 event = (const struct qlink_event *)event_skb->data; 407 event_id = le16_to_cpu(event->event_id); 408 event_len = le16_to_cpu(event->mhdr.len); 409 410 if (likely(event->vifid < QTNF_MAX_INTF)) { 411 vif = &mac->iflist[event->vifid]; 412 } else { 413 pr_err("invalid vif(%u)\n", event->vifid); 414 return -EINVAL; 415 } 416 417 switch (event_id) { 418 case QLINK_EVENT_STA_ASSOCIATED: 419 ret = qtnf_event_handle_sta_assoc(mac, vif, (const void *)event, 420 event_len); 421 break; 422 case QLINK_EVENT_STA_DEAUTH: 423 ret = qtnf_event_handle_sta_deauth(mac, vif, 424 (const void *)event, 425 event_len); 426 break; 427 case QLINK_EVENT_MGMT_RECEIVED: 428 ret = qtnf_event_handle_mgmt_received(vif, (const void *)event, 429 event_len); 430 break; 431 case QLINK_EVENT_SCAN_RESULTS: 432 ret = qtnf_event_handle_scan_results(vif, (const void *)event, 433 event_len); 434 break; 435 case QLINK_EVENT_SCAN_COMPLETE: 436 ret = qtnf_event_handle_scan_complete(mac, (const void *)event, 437 event_len); 438 break; 439 case QLINK_EVENT_BSS_JOIN: 440 ret = qtnf_event_handle_bss_join(vif, (const void *)event, 441 event_len); 442 break; 443 case QLINK_EVENT_BSS_LEAVE: 444 ret = qtnf_event_handle_bss_leave(vif, (const void *)event, 445 event_len); 446 break; 447 case QLINK_EVENT_FREQ_CHANGE: 448 ret = qtnf_event_handle_freq_change(mac, (const void *)event, 449 event_len); 450 break; 451 default: 452 pr_warn("unknown event type: %x\n", event_id); 453 break; 454 } 455 456 return ret; 457 } 458 459 static int qtnf_event_process_skb(struct qtnf_bus *bus, 460 const struct sk_buff *skb) 461 { 462 const struct qlink_event *event; 463 struct qtnf_wmac *mac; 464 int res; 465 466 if (unlikely(!skb || skb->len < sizeof(*event))) { 467 pr_err("invalid event buffer\n"); 468 return -EINVAL; 469 } 470 471 event = (struct qlink_event *)skb->data; 472 473 mac = qtnf_core_get_mac(bus, event->macid); 474 475 pr_debug("new event id:%x len:%u mac:%u vif:%u\n", 476 le16_to_cpu(event->event_id), le16_to_cpu(event->mhdr.len), 477 event->macid, event->vifid); 478 479 if (unlikely(!mac)) 480 return -ENXIO; 481 482 qtnf_bus_lock(bus); 483 res = qtnf_event_parse(mac, skb); 484 qtnf_bus_unlock(bus); 485 486 return res; 487 } 488 489 void qtnf_event_work_handler(struct work_struct *work) 490 { 491 struct qtnf_bus *bus = container_of(work, struct qtnf_bus, event_work); 492 struct sk_buff_head *event_queue = &bus->trans.event_queue; 493 struct sk_buff *current_event_skb = skb_dequeue(event_queue); 494 495 while (current_event_skb) { 496 qtnf_event_process_skb(bus, current_event_skb); 497 dev_kfree_skb_any(current_event_skb); 498 current_event_skb = skb_dequeue(event_queue); 499 } 500 } 501