diff options
Diffstat (limited to 'drivers/net/wireless/quantenna/qtnfmac/event.c')
| -rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/event.c | 185 |
1 files changed, 142 insertions, 43 deletions
diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c b/drivers/net/wireless/quantenna/qtnfmac/event.c index 3fd1a9217737..6c1b886339ac 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/event.c +++ b/drivers/net/wireless/quantenna/qtnfmac/event.c | |||
| @@ -150,6 +150,13 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif, | |||
| 150 | struct cfg80211_chan_def chandef; | 150 | struct cfg80211_chan_def chandef; |
| 151 | struct cfg80211_bss *bss = NULL; | 151 | struct cfg80211_bss *bss = NULL; |
| 152 | u8 *ie = 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; | ||
| 153 | 160 | ||
| 154 | if (unlikely(len < sizeof(*join_info))) { | 161 | if (unlikely(len < sizeof(*join_info))) { |
| 155 | pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", | 162 | pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", |
| @@ -167,67 +174,118 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif, | |||
| 167 | pr_debug("VIF%u.%u: BSSID:%pM status:%u\n", | 174 | pr_debug("VIF%u.%u: BSSID:%pM status:%u\n", |
| 168 | vif->mac->macid, vif->vifid, join_info->bssid, status); | 175 | vif->mac->macid, vif->vifid, join_info->bssid, status); |
| 169 | 176 | ||
| 170 | if (status == WLAN_STATUS_SUCCESS) { | 177 | if (status != WLAN_STATUS_SUCCESS) |
| 171 | qlink_chandef_q2cfg(wiphy, &join_info->chan, &chandef); | 178 | goto done; |
| 172 | if (!cfg80211_chandef_valid(&chandef)) { | 179 | |
| 173 | pr_warn("MAC%u.%u: bad channel freq=%u cf1=%u cf2=%u bw=%u\n", | 180 | qlink_chandef_q2cfg(wiphy, &join_info->chan, &chandef); |
| 181 | if (!cfg80211_chandef_valid(&chandef)) { | ||
| 182 | pr_warn("MAC%u.%u: bad channel freq=%u cf1=%u cf2=%u bw=%u\n", | ||
| 183 | vif->mac->macid, vif->vifid, | ||
| 184 | chandef.chan->center_freq, | ||
| 185 | chandef.center_freq1, | ||
| 186 | chandef.center_freq2, | ||
| 187 | chandef.width); | ||
| 188 | status = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
| 189 | goto done; | ||
| 190 | } | ||
| 191 | |||
| 192 | bss = cfg80211_get_bss(wiphy, chandef.chan, join_info->bssid, | ||
| 193 | NULL, 0, IEEE80211_BSS_TYPE_ESS, | ||
| 194 | IEEE80211_PRIVACY_ANY); | ||
| 195 | if (!bss) { | ||
| 196 | pr_warn("VIF%u.%u: add missing BSS:%pM chan:%u\n", | ||
| 197 | vif->mac->macid, vif->vifid, | ||
| 198 | join_info->bssid, chandef.chan->hw_value); | ||
| 199 | |||
| 200 | if (!vif->wdev.ssid_len) { | ||
| 201 | pr_warn("VIF%u.%u: SSID unknown for BSS:%pM\n", | ||
| 174 | vif->mac->macid, vif->vifid, | 202 | vif->mac->macid, vif->vifid, |
| 175 | chandef.chan->center_freq, | 203 | join_info->bssid); |
| 176 | chandef.center_freq1, | ||
| 177 | chandef.center_freq2, | ||
| 178 | chandef.width); | ||
| 179 | status = WLAN_STATUS_UNSPECIFIED_FAILURE; | 204 | status = WLAN_STATUS_UNSPECIFIED_FAILURE; |
| 180 | goto done; | 205 | goto done; |
| 181 | } | 206 | } |
| 182 | 207 | ||
| 183 | bss = cfg80211_get_bss(wiphy, chandef.chan, join_info->bssid, | 208 | ie = kzalloc(2 + vif->wdev.ssid_len, GFP_KERNEL); |
| 184 | NULL, 0, IEEE80211_BSS_TYPE_ESS, | 209 | if (!ie) { |
| 185 | IEEE80211_PRIVACY_ANY); | 210 | pr_warn("VIF%u.%u: IE alloc failed for BSS:%pM\n", |
| 211 | vif->mac->macid, vif->vifid, | ||
| 212 | join_info->bssid); | ||
| 213 | status = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
| 214 | goto done; | ||
| 215 | } | ||
| 216 | |||
| 217 | ie[0] = WLAN_EID_SSID; | ||
| 218 | ie[1] = vif->wdev.ssid_len; | ||
| 219 | memcpy(ie + 2, vif->wdev.ssid, vif->wdev.ssid_len); | ||
| 220 | |||
| 221 | bss = cfg80211_inform_bss(wiphy, chandef.chan, | ||
| 222 | CFG80211_BSS_FTYPE_UNKNOWN, | ||
| 223 | join_info->bssid, 0, | ||
| 224 | WLAN_CAPABILITY_ESS, 100, | ||
| 225 | ie, 2 + vif->wdev.ssid_len, | ||
| 226 | 0, GFP_KERNEL); | ||
| 186 | if (!bss) { | 227 | if (!bss) { |
| 187 | pr_warn("VIF%u.%u: add missing BSS:%pM chan:%u\n", | 228 | pr_warn("VIF%u.%u: can't connect to unknown BSS: %pM\n", |
| 188 | vif->mac->macid, vif->vifid, | 229 | vif->mac->macid, vif->vifid, |
| 189 | join_info->bssid, chandef.chan->hw_value); | 230 | join_info->bssid); |
| 231 | status = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
| 232 | goto done; | ||
| 233 | } | ||
| 234 | } | ||
| 190 | 235 | ||
| 191 | if (!vif->wdev.ssid_len) { | 236 | payload_len = len - sizeof(*join_info); |
| 192 | pr_warn("VIF%u.%u: SSID unknown for BSS:%pM\n", | 237 | tlv = (struct qlink_tlv_hdr *)join_info->ies; |
| 193 | vif->mac->macid, vif->vifid, | 238 | |
| 194 | join_info->bssid); | 239 | while (payload_len >= sizeof(struct qlink_tlv_hdr)) { |
| 195 | status = WLAN_STATUS_UNSPECIFIED_FAILURE; | 240 | tlv_type = le16_to_cpu(tlv->type); |
| 196 | goto done; | 241 | tlv_value_len = le16_to_cpu(tlv->len); |
| 197 | } | 242 | tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); |
| 198 | 243 | ||
| 199 | ie = kzalloc(2 + vif->wdev.ssid_len, GFP_KERNEL); | 244 | if (payload_len < tlv_full_len) { |
| 200 | if (!ie) { | 245 | pr_warn("invalid %u TLV\n", tlv_type); |
| 201 | pr_warn("VIF%u.%u: IE alloc failed for BSS:%pM\n", | 246 | status = WLAN_STATUS_UNSPECIFIED_FAILURE; |
| 202 | vif->mac->macid, vif->vifid, | 247 | goto done; |
| 203 | join_info->bssid); | 248 | } |
| 249 | |||
| 250 | if (tlv_type == QTN_TLV_ID_IE_SET) { | ||
| 251 | const struct qlink_tlv_ie_set *ie_set; | ||
| 252 | unsigned int ie_len; | ||
| 253 | |||
| 254 | if (payload_len < sizeof(*ie_set)) { | ||
| 255 | pr_warn("invalid IE_SET TLV\n"); | ||
| 204 | status = WLAN_STATUS_UNSPECIFIED_FAILURE; | 256 | status = WLAN_STATUS_UNSPECIFIED_FAILURE; |
| 205 | goto done; | 257 | goto done; |
| 206 | } | 258 | } |
| 207 | 259 | ||
| 208 | ie[0] = WLAN_EID_SSID; | 260 | ie_set = (const struct qlink_tlv_ie_set *)tlv; |
| 209 | ie[1] = vif->wdev.ssid_len; | 261 | ie_len = tlv_value_len - |
| 210 | memcpy(ie + 2, vif->wdev.ssid, vif->wdev.ssid_len); | 262 | (sizeof(*ie_set) - sizeof(ie_set->hdr)); |
| 211 | 263 | ||
| 212 | bss = cfg80211_inform_bss(wiphy, chandef.chan, | 264 | switch (ie_set->type) { |
| 213 | CFG80211_BSS_FTYPE_UNKNOWN, | 265 | case QLINK_IE_SET_ASSOC_RESP: |
| 214 | join_info->bssid, 0, | 266 | if (ie_len) { |
| 215 | WLAN_CAPABILITY_ESS, 100, | 267 | rsp_ies = ie_set->ie_data; |
| 216 | ie, 2 + vif->wdev.ssid_len, | 268 | rsp_ies_len = ie_len; |
| 217 | 0, GFP_KERNEL); | 269 | } |
| 218 | if (!bss) { | 270 | break; |
| 219 | pr_warn("VIF%u.%u: can't connect to unknown BSS: %pM\n", | 271 | default: |
| 220 | vif->mac->macid, vif->vifid, | 272 | pr_warn("unexpected IE type: %u\n", |
| 221 | join_info->bssid); | 273 | ie_set->type); |
| 222 | status = WLAN_STATUS_UNSPECIFIED_FAILURE; | 274 | break; |
| 223 | goto done; | ||
| 224 | } | 275 | } |
| 225 | } | 276 | } |
| 277 | |||
| 278 | payload_len -= tlv_full_len; | ||
| 279 | tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); | ||
| 226 | } | 280 | } |
| 227 | 281 | ||
| 282 | if (payload_len) | ||
| 283 | pr_warn("VIF%u.%u: unexpected remaining payload: %zu\n", | ||
| 284 | vif->mac->macid, vif->vifid, payload_len); | ||
| 285 | |||
| 228 | done: | 286 | done: |
| 229 | cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, NULL, | 287 | cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, rsp_ies, |
| 230 | 0, status, GFP_KERNEL); | 288 | rsp_ies_len, status, GFP_KERNEL); |
| 231 | if (bss) { | 289 | if (bss) { |
| 232 | if (!ether_addr_equal(vif->bssid, join_info->bssid)) | 290 | if (!ether_addr_equal(vif->bssid, join_info->bssid)) |
| 233 | ether_addr_copy(vif->bssid, join_info->bssid); | 291 | ether_addr_copy(vif->bssid, join_info->bssid); |
| @@ -516,6 +574,43 @@ static int qtnf_event_handle_radar(struct qtnf_vif *vif, | |||
| 516 | return 0; | 574 | return 0; |
| 517 | } | 575 | } |
| 518 | 576 | ||
| 577 | static int | ||
| 578 | qtnf_event_handle_external_auth(struct qtnf_vif *vif, | ||
| 579 | const struct qlink_event_external_auth *ev, | ||
| 580 | u16 len) | ||
| 581 | { | ||
| 582 | struct cfg80211_external_auth_params auth = {0}; | ||
| 583 | struct wiphy *wiphy = priv_to_wiphy(vif->mac); | ||
| 584 | int ret; | ||
| 585 | |||
| 586 | if (len < sizeof(*ev)) { | ||
| 587 | pr_err("MAC%u: payload is too short\n", vif->mac->macid); | ||
| 588 | return -EINVAL; | ||
| 589 | } | ||
| 590 | |||
| 591 | if (!wiphy->registered || !vif->netdev) | ||
| 592 | return 0; | ||
| 593 | |||
| 594 | if (ev->ssid_len) { | ||
| 595 | memcpy(auth.ssid.ssid, ev->ssid, ev->ssid_len); | ||
| 596 | auth.ssid.ssid_len = ev->ssid_len; | ||
| 597 | } | ||
| 598 | |||
| 599 | auth.key_mgmt_suite = le32_to_cpu(ev->akm_suite); | ||
| 600 | ether_addr_copy(auth.bssid, ev->bssid); | ||
| 601 | auth.action = ev->action; | ||
| 602 | |||
| 603 | pr_info("%s: external auth bss=%pM action=%u akm=%u\n", | ||
| 604 | vif->netdev->name, auth.bssid, auth.action, | ||
| 605 | auth.key_mgmt_suite); | ||
| 606 | |||
| 607 | ret = cfg80211_external_auth_request(vif->netdev, &auth, GFP_KERNEL); | ||
| 608 | if (ret) | ||
| 609 | pr_warn("failed to offload external auth request\n"); | ||
| 610 | |||
| 611 | return ret; | ||
| 612 | } | ||
| 613 | |||
| 519 | static int qtnf_event_parse(struct qtnf_wmac *mac, | 614 | static int qtnf_event_parse(struct qtnf_wmac *mac, |
| 520 | const struct sk_buff *event_skb) | 615 | const struct sk_buff *event_skb) |
| 521 | { | 616 | { |
| @@ -574,6 +669,10 @@ static int qtnf_event_parse(struct qtnf_wmac *mac, | |||
| 574 | ret = qtnf_event_handle_radar(vif, (const void *)event, | 669 | ret = qtnf_event_handle_radar(vif, (const void *)event, |
| 575 | event_len); | 670 | event_len); |
| 576 | break; | 671 | break; |
| 672 | case QLINK_EVENT_EXTERNAL_AUTH: | ||
| 673 | ret = qtnf_event_handle_external_auth(vif, (const void *)event, | ||
| 674 | event_len); | ||
| 675 | break; | ||
| 577 | default: | 676 | default: |
| 578 | pr_warn("unknown event type: %x\n", event_id); | 677 | pr_warn("unknown event type: %x\n", event_id); |
| 579 | break; | 678 | break; |
