void orinoco_add_extscan_result(struct orinoco_private *priv, struct agere_ext_scan_info *bss, size_t len) { struct wiphy *wiphy = priv_to_wiphy(priv); struct ieee80211_channel *channel; struct cfg80211_bss *cbss; const u8 *ie; u64 timestamp; s32 signal; u16 capability; u16 beacon_interval; size_t ie_len; int chan, freq; ie_len = len - sizeof(*bss); ie = cfg80211_find_ie(WLAN_EID_DS_PARAMS, bss->data, ie_len); chan = ie ? ie[2] : 0; freq = ieee80211_dsss_chan_to_freq(chan); channel = ieee80211_get_channel(wiphy, freq); timestamp = le64_to_cpu(bss->timestamp); capability = le16_to_cpu(bss->capabilities); beacon_interval = le16_to_cpu(bss->beacon_interval); ie = bss->data; signal = SIGNAL_TO_MBM(bss->level); cbss = cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp, capability, beacon_interval, ie, ie_len, signal, GFP_KERNEL); cfg80211_put_bss(cbss); }
/* * This function informs the CFG802.11 subsystem of a new IBSS. * * The following information are sent to the CFG802.11 subsystem * to register the new IBSS. If we do not register the new IBSS, * a kernel panic will result. * - SSID * - SSID length * - BSSID * - Channel */ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) { struct ieee80211_channel *chan; struct mwifiex_bss_info bss_info; struct cfg80211_bss *bss; int ie_len; u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)]; enum ieee80211_band band; if (mwifiex_get_bss_info(priv, &bss_info)) return -1; ie_buf[0] = WLAN_EID_SSID; ie_buf[1] = bss_info.ssid.ssid_len; memcpy(&ie_buf[sizeof(struct ieee_types_header)], &bss_info.ssid.ssid, bss_info.ssid.ssid_len); ie_len = ie_buf[1] + sizeof(struct ieee_types_header); band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); chan = __ieee80211_get_channel(priv->wdev->wiphy, ieee80211_channel_to_frequency(bss_info.bss_chan, band)); bss = cfg80211_inform_bss(priv->wdev->wiphy, chan, bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, 0, ie_buf, ie_len, 0, GFP_KERNEL); cfg80211_put_bss(bss); memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); return 0; }
static void orinoco_add_hostscan_result(struct orinoco_private *priv, const union hermes_scan_info *bss) { struct wiphy *wiphy = priv_to_wiphy(priv); struct ieee80211_channel *channel; struct cfg80211_bss *cbss; u8 *ie; u8 ie_buf[46]; u64 timestamp; s32 signal; u16 capability; u16 beacon_interval; int ie_len; int freq; int len; len = le16_to_cpu(bss->a.essid_len); /* Reconstruct SSID and bitrate IEs to pass up */ ie_buf[0] = WLAN_EID_SSID; ie_buf[1] = len; memcpy(&ie_buf[2], bss->a.essid, len); ie = ie_buf + len + 2; ie_len = ie_buf[1] + 2; switch (priv->firmware_type) { case FIRMWARE_TYPE_SYMBOL: ie_len += symbol_build_supp_rates(ie, bss->s.rates); break; case FIRMWARE_TYPE_INTERSIL: ie_len += prism_build_supp_rates(ie, bss->p.rates); break; case FIRMWARE_TYPE_AGERE: default: break; } freq = ieee80211_dsss_chan_to_freq(le16_to_cpu(bss->a.channel)); channel = ieee80211_get_channel(wiphy, freq); if (!channel) { printk(KERN_DEBUG "Invalid channel designation %04X(%04X)", bss->a.channel, freq); return; /* Then ignore it for now */ } timestamp = 0; capability = le16_to_cpu(bss->a.capabilities); beacon_interval = le16_to_cpu(bss->a.beacon_interv); signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level)); cbss = cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp, capability, beacon_interval, ie_buf, ie_len, signal, GFP_KERNEL); cfg80211_put_bss(cbss); }
static void r92su_bss_add_work(struct work_struct *work) { struct r92su *r92su; struct llist_node *node; r92su = container_of(work, struct r92su, add_bss_work); node = llist_del_all(&r92su->add_bss_list); while (node) { const struct h2cc2h_bss *c2h_bss; struct r92su_add_bss *bss_priv; struct cfg80211_bss *bss; int chan_idx; int ie_len; bss_priv = llist_entry(node, struct r92su_add_bss, head); c2h_bss = &bss_priv->fw_bss; chan_idx = le32_to_cpu(c2h_bss->config.frequency) - 1; if (chan_idx < 0 || chan_idx >= r92su->band_2GHZ.n_channels) { R92SU_ERR(r92su, "received survey event on bad channel."); goto next; } ie_len = le32_to_cpu(c2h_bss->ie_length) - 12; if (ie_len < 0) goto next; bss = cfg80211_inform_bss(r92su->wdev.wiphy, &r92su->band_2GHZ.channels[chan_idx], CFG80211_BSS_FTYPE_UNKNOWN, c2h_bss->bssid, le64_to_cpu(c2h_bss->ies.timestamp), le16_to_cpu(c2h_bss->ies.caps), le32_to_cpu(c2h_bss->config.beacon_period), c2h_bss->ies.ie, ie_len, le32_to_cpu(c2h_bss->rssi), GFP_KERNEL); if (bss) { r92su_bss_init(r92su, bss, c2h_bss); cfg80211_put_bss(r92su->wdev.wiphy, bss); } next: node = ACCESS_ONCE(node->next); /* these bss_priv have been generated by "c2h_survey_event" * they are not part of the cfg80211 framework and this is * why we have to managed & destroy them. */ kfree(bss_priv); } }
static int ath6kl_add_bss_if_needed(struct ath6kl *ar, const u8 *bssid, struct ieee80211_channel *chan, const u8 *beacon_ie, size_t beacon_ie_len) { struct cfg80211_bss *bss; u8 *ie; bss = cfg80211_get_bss(ar->wdev->wiphy, chan, bssid, ar->ssid, ar->ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); if (bss == NULL) { /* * Since cfg80211 may not yet know about the BSS, * generate a partial entry until the first BSS info * event becomes available. * * Prepend SSID element since it is not included in the Beacon * IEs from the target. */ ie = kmalloc(2 + ar->ssid_len + beacon_ie_len, GFP_KERNEL); if (ie == NULL) return -ENOMEM; ie[0] = WLAN_EID_SSID; ie[1] = ar->ssid_len; memcpy(ie + 2, ar->ssid, ar->ssid_len); memcpy(ie + 2 + ar->ssid_len, beacon_ie, beacon_ie_len); bss = cfg80211_inform_bss(ar->wdev->wiphy, chan, bssid, 0, WLAN_CAPABILITY_ESS, 100, ie, 2 + ar->ssid_len + beacon_ie_len, 0, GFP_KERNEL); if (bss) ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for " "%pM prior to indicating connect/roamed " "event\n", bssid); kfree(ie); } else ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss " "entry\n"); if (bss == NULL) return -ENOMEM; cfg80211_put_bss(bss); return 0; }
static int r92su_join_ibss(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ibss_params *params) { struct r92su *r92su = wiphy_priv(wiphy); struct cfg80211_bss *bss = NULL; struct r92su_bss_priv *bss_priv = NULL; int err = -EAGAIN; u8 ie_buf[256]; u8 *ie = ie_buf; u32 ie_len_left = sizeof(ie_buf); bool join; err = r92su_internal_scan(r92su, params->ssid, params->ssid_len); if (err) return err; mutex_lock(&r92su->lock); if (!r92su_is_open(r92su)) goto out; bss = cfg80211_get_bss(wiphy, NULL, params->bssid, params->ssid, params->ssid_len, IEEE80211_BSS_TYPE_IBSS, IEEE80211_PRIVACY_ANY); if (!bss) { u8 bssid[ETH_ALEN]; u16 capability; capability = WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_SHORT_PREAMBLE; if (params->privacy) capability |= WLAN_CAPABILITY_PRIVACY; if (!params->bssid) { /* generate random, not broadcast, locally administered * bssid. */ get_random_bytes(&bssid, sizeof(bssid)); bssid[0] &= ~0x01; bssid[0] |= 0x02; } else { memcpy(bssid, params->bssid, ETH_ALEN); } err = r92su_ibss_build_ie(r92su, &ie, &ie_len_left, params); if (err) goto out; bss = cfg80211_inform_bss(r92su->wdev.wiphy, params->chandef.chan, CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0, capability, params->beacon_interval, ie_buf, ie - ie_buf, 0, GFP_KERNEL); if (!bss) goto out; bss_priv = r92su_get_bss_priv(bss); err = r92su_bss_build_fw_bss(r92su, bss, ie_buf, ie - ie_buf); if (err) goto out; join = false; } else { bss_priv = r92su_get_bss_priv(bss); WARN(!r92su_add_ies(r92su, &ie, &ie_len_left, params->ie, params->ie_len), "no space left for cfg80211's ies"); join = true; } err = r92su_internal_connect(r92su, bss, join, ie_buf, ie - ie_buf); out: if (err) { if (bss_priv) kfree(bss_priv->assoc_ie); r92su->want_connect_bss = NULL; if (bss) cfg80211_put_bss(wiphy, bss); } mutex_unlock(&r92su->lock); return err; }
static int prism2_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { struct net_device *dev; struct prism2_wiphy_private *priv = wiphy_priv(wiphy); struct wlandevice *wlandev; struct p80211msg_dot11req_scan msg1; struct p80211msg_dot11req_scan_results msg2; struct cfg80211_bss *bss; struct cfg80211_scan_info info = {}; int result; int err = 0; int numbss = 0; int i = 0; u8 ie_buf[46]; int ie_len; if (!request) return -EINVAL; dev = request->wdev->netdev; wlandev = dev->ml_priv; if (priv->scan_request && priv->scan_request != request) return -EBUSY; if (wlandev->macmode == WLAN_MACMODE_ESS_AP) { netdev_err(dev, "Can't scan in AP mode\n"); return -EOPNOTSUPP; } priv->scan_request = request; memset(&msg1, 0x00, sizeof(msg1)); msg1.msgcode = DIDMSG_DOT11REQ_SCAN; msg1.bsstype.data = P80211ENUM_bsstype_any; memset(&msg1.bssid.data.data, 0xFF, sizeof(msg1.bssid.data.data)); msg1.bssid.data.len = 6; if (request->n_ssids > 0) { msg1.scantype.data = P80211ENUM_scantype_active; msg1.ssid.data.len = request->ssids->ssid_len; memcpy(msg1.ssid.data.data, request->ssids->ssid, request->ssids->ssid_len); } else { msg1.scantype.data = 0; } msg1.probedelay.data = 0; for (i = 0; (i < request->n_channels) && i < ARRAY_SIZE(prism2_channels); i++) msg1.channellist.data.data[i] = ieee80211_frequency_to_channel( request->channels[i]->center_freq); msg1.channellist.data.len = request->n_channels; msg1.maxchanneltime.data = 250; msg1.minchanneltime.data = 200; result = p80211req_dorequest(wlandev, (u8 *)&msg1); if (result) { err = prism2_result2err(msg1.resultcode.data); goto exit; } /* Now retrieve scan results */ numbss = msg1.numbss.data; for (i = 0; i < numbss; i++) { int freq; memset(&msg2, 0, sizeof(msg2)); msg2.msgcode = DIDMSG_DOT11REQ_SCAN_RESULTS; msg2.bssindex.data = i; result = p80211req_dorequest(wlandev, (u8 *)&msg2); if ((result != 0) || (msg2.resultcode.data != P80211ENUM_resultcode_success)) { break; } ie_buf[0] = WLAN_EID_SSID; ie_buf[1] = msg2.ssid.data.len; ie_len = ie_buf[1] + 2; memcpy(&ie_buf[2], &msg2.ssid.data.data, msg2.ssid.data.len); freq = ieee80211_channel_to_frequency(msg2.dschannel.data, NL80211_BAND_2GHZ); bss = cfg80211_inform_bss(wiphy, ieee80211_get_channel(wiphy, freq), CFG80211_BSS_FTYPE_UNKNOWN, (const u8 *)&msg2.bssid.data.data, msg2.timestamp.data, msg2.capinfo.data, msg2.beaconperiod.data, ie_buf, ie_len, (msg2.signal.data - 65536) * 100, /* Conversion to signed type */ GFP_KERNEL ); if (!bss) { err = -ENOMEM; goto exit; } cfg80211_put_bss(wiphy, bss); } if (result) err = prism2_result2err(msg2.resultcode.data); exit: info.aborted = !!(err); cfg80211_scan_done(request, &info); priv->scan_request = NULL; return err; }
int prism2_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) { struct prism2_wiphy_private *priv = wiphy_priv(wiphy); wlandevice_t *wlandev = dev->ml_priv; struct p80211msg_dot11req_scan msg1; struct p80211msg_dot11req_scan_results msg2; int result; int err = 0; int numbss = 0; int i = 0; u8 ie_buf[46]; int ie_len; if (!request) return -EINVAL; if (priv->scan_request && priv->scan_request != request) return -EBUSY; if (wlandev->macmode == WLAN_MACMODE_ESS_AP) { printk(KERN_ERR "Can't scan in AP mode\n"); return -EOPNOTSUPP; } priv->scan_request = request; memset(&msg1, 0x00, sizeof(struct p80211msg_dot11req_scan)); msg1.msgcode = DIDmsg_dot11req_scan; msg1.bsstype.data = P80211ENUM_bsstype_any; memset(&(msg1.bssid.data), 0xFF, sizeof(p80211item_pstr6_t)); msg1.bssid.data.len = 6; if (request->n_ssids > 0) { msg1.scantype.data = P80211ENUM_scantype_active; msg1.ssid.data.len = request->ssids->ssid_len; memcpy(msg1.ssid.data.data, request->ssids->ssid, request->ssids->ssid_len); } else { msg1.scantype.data = 0; } msg1.probedelay.data = 0; for (i = 0; (i < request->n_channels) && i < ARRAY_SIZE(prism2_channels); i++) msg1.channellist.data.data[i] = ieee80211_frequency_to_channel(request->channels[i]->center_freq); msg1.channellist.data.len = request->n_channels; msg1.maxchanneltime.data = 250; msg1.minchanneltime.data = 200; result = p80211req_dorequest(wlandev, (u8 *) &msg1); if (result) { err = prism2_result2err(msg1.resultcode.data); goto exit; } /* Now retrieve scan results */ numbss = msg1.numbss.data; for (i = 0; i < numbss; i++) { memset(&msg2, 0, sizeof(msg2)); msg2.msgcode = DIDmsg_dot11req_scan_results; msg2.bssindex.data = i; result = p80211req_dorequest(wlandev, (u8 *) &msg2); if ((result != 0) || (msg2.resultcode.data != P80211ENUM_resultcode_success)) { break; } ie_buf[0] = WLAN_EID_SSID; ie_buf[1] = msg2.ssid.data.len; ie_len = ie_buf[1] + 2; memcpy(&ie_buf[2], &(msg2.ssid.data.data), msg2.ssid.data.len); cfg80211_inform_bss(wiphy, ieee80211_get_channel(wiphy, ieee80211_dsss_chan_to_freq(msg2.dschannel.data)), (const u8 *) &(msg2.bssid.data.data), msg2.timestamp.data, msg2.capinfo.data, msg2.beaconperiod.data, ie_buf, ie_len, (msg2.signal.data - 65536) * 100, /* Conversion to signed type */ GFP_KERNEL ); } if (result) err = prism2_result2err(msg2.resultcode.data); exit: cfg80211_scan_done(request, err ? 1 : 0); priv->scan_request = NULL; return err; }
/* * This function informs the CFG802.11 subsystem of a new BSS connection. * * The following information are sent to the CFG802.11 subsystem * to register the new BSS connection. If we do not register the new BSS, * a kernel panic will result. * - MAC address * - Capabilities * - Beacon period * - RSSI value * - Channel * - Supported rates IE * - Extended capabilities IE * - DS parameter set IE * - HT Capability IE * - Vendor Specific IE (221) * - WPA IE * - RSN IE */ static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, struct mwifiex_802_11_ssid *ssid) { struct mwifiex_bssdescriptor *scan_table; int i, j; struct ieee80211_channel *chan; u8 *ie, *ie_buf; u32 ie_len; u8 *beacon; int beacon_size; u8 element_id, element_len; #define MAX_IE_BUF 2048 ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL); if (!ie_buf) { dev_err(priv->adapter->dev, "%s: failed to alloc ie_buf\n", __func__); return -ENOMEM; } scan_table = priv->adapter->scan_table; for (i = 0; i < priv->adapter->num_in_scan_table; i++) { if (ssid) { /* Inform specific BSS only */ if (memcmp(ssid->ssid, scan_table[i].ssid.ssid, ssid->ssid_len)) continue; } memset(ie_buf, 0, MAX_IE_BUF); ie_buf[0] = WLAN_EID_SSID; ie_buf[1] = scan_table[i].ssid.ssid_len; memcpy(&ie_buf[sizeof(struct ieee_types_header)], scan_table[i].ssid.ssid, ie_buf[1]); ie = ie_buf + ie_buf[1] + sizeof(struct ieee_types_header); ie_len = ie_buf[1] + sizeof(struct ieee_types_header); ie[0] = WLAN_EID_SUPP_RATES; for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) { if (!scan_table[i].supported_rates[j]) break; else ie[j + sizeof(struct ieee_types_header)] = scan_table[i].supported_rates[j]; } ie[1] = j; ie_len += ie[1] + sizeof(struct ieee_types_header); beacon = scan_table[i].beacon_buf; beacon_size = scan_table[i].beacon_buf_size; /* Skip time stamp, beacon interval and capability */ if (beacon) { beacon += sizeof(scan_table[i].beacon_period) + sizeof(scan_table[i].time_stamp) + +sizeof(scan_table[i].cap_info_bitmap); beacon_size -= sizeof(scan_table[i].beacon_period) + sizeof(scan_table[i].time_stamp) + sizeof(scan_table[i].cap_info_bitmap); } while (beacon_size >= sizeof(struct ieee_types_header)) { ie = ie_buf + ie_len; element_id = *beacon; element_len = *(beacon + 1); if (beacon_size < (int) element_len + sizeof(struct ieee_types_header)) { dev_err(priv->adapter->dev, "%s: in processing" " IE, bytes left < IE length\n", __func__); break; } switch (element_id) { case WLAN_EID_EXT_CAPABILITY: case WLAN_EID_DS_PARAMS: case WLAN_EID_HT_CAPABILITY: case WLAN_EID_VENDOR_SPECIFIC: case WLAN_EID_RSN: case WLAN_EID_BSS_AC_ACCESS_DELAY: ie[0] = element_id; ie[1] = element_len; memcpy(&ie[sizeof(struct ieee_types_header)], (u8 *) beacon + sizeof(struct ieee_types_header), element_len); ie_len += ie[1] + sizeof(struct ieee_types_header); break; default: break; } beacon += element_len + sizeof(struct ieee_types_header); beacon_size -= element_len + sizeof(struct ieee_types_header); } chan = ieee80211_get_channel(priv->wdev->wiphy, scan_table[i].freq); cfg80211_inform_bss(priv->wdev->wiphy, chan, scan_table[i].mac_address, 0, scan_table[i].cap_info_bitmap, scan_table[i].beacon_period, ie_buf, ie_len, scan_table[i].rssi, GFP_KERNEL); } kfree(ie_buf); return 0; }
static int qtnf_event_handle_scan_results(struct qtnf_vif *vif, const struct qlink_event_scan_result *sr, u16 len) { struct cfg80211_bss *bss; struct ieee80211_channel *channel; struct wiphy *wiphy = priv_to_wiphy(vif->mac); enum cfg80211_bss_frame_type frame_type = CFG80211_BSS_FTYPE_UNKNOWN; size_t payload_len; u16 tlv_type; u16 tlv_value_len; size_t tlv_full_len; const struct qlink_tlv_hdr *tlv; const u8 *ies = NULL; size_t ies_len = 0; if (len < sizeof(*sr)) { pr_err("VIF%u.%u: payload is too short\n", vif->mac->macid, vif->vifid); return -EINVAL; } channel = ieee80211_get_channel(wiphy, le16_to_cpu(sr->freq)); if (!channel) { pr_err("VIF%u.%u: channel at %u MHz not found\n", vif->mac->macid, vif->vifid, le16_to_cpu(sr->freq)); return -EINVAL; } payload_len = len - sizeof(*sr); tlv = (struct qlink_tlv_hdr *)sr->payload; while (payload_len >= sizeof(struct qlink_tlv_hdr)) { tlv_type = le16_to_cpu(tlv->type); tlv_value_len = le16_to_cpu(tlv->len); tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); if (tlv_full_len > payload_len) return -EINVAL; if (tlv_type == QTN_TLV_ID_IE_SET) { const struct qlink_tlv_ie_set *ie_set; unsigned int ie_len; if (payload_len < sizeof(*ie_set)) return -EINVAL; ie_set = (const struct qlink_tlv_ie_set *)tlv; ie_len = tlv_value_len - (sizeof(*ie_set) - sizeof(ie_set->hdr)); switch (ie_set->type) { case QLINK_IE_SET_BEACON_IES: frame_type = CFG80211_BSS_FTYPE_BEACON; break; case QLINK_IE_SET_PROBE_RESP_IES: frame_type = CFG80211_BSS_FTYPE_PRESP; break; default: frame_type = CFG80211_BSS_FTYPE_UNKNOWN; } if (ie_len) { ies = ie_set->ie_data; ies_len = ie_len; } } payload_len -= tlv_full_len; tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); } if (payload_len) return -EINVAL; bss = cfg80211_inform_bss(wiphy, channel, frame_type, sr->bssid, get_unaligned_le64(&sr->tsf), le16_to_cpu(sr->capab), le16_to_cpu(sr->bintval), ies, ies_len, DBM_TO_MBM(sr->sig_dbm), GFP_KERNEL); if (!bss) return -ENOMEM; cfg80211_put_bss(wiphy, bss); return 0; }
static int qtnf_event_handle_bss_join(struct qtnf_vif *vif, const struct qlink_event_bss_join *join_info, u16 len) { struct wiphy *wiphy = priv_to_wiphy(vif->mac); enum ieee80211_statuscode status = le16_to_cpu(join_info->status); struct cfg80211_chan_def chandef; struct cfg80211_bss *bss = NULL; u8 *ie = NULL; size_t payload_len; u16 tlv_type; u16 tlv_value_len; size_t tlv_full_len; const struct qlink_tlv_hdr *tlv; const u8 *rsp_ies = NULL; size_t rsp_ies_len = 0; if (unlikely(len < sizeof(*join_info))) { pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", vif->mac->macid, vif->vifid, len, sizeof(struct qlink_event_bss_join)); return -EINVAL; } if (vif->wdev.iftype != NL80211_IFTYPE_STATION) { pr_err("VIF%u.%u: BSS_JOIN event when not in STA mode\n", vif->mac->macid, vif->vifid); return -EPROTO; } pr_debug("VIF%u.%u: BSSID:%pM status:%u\n", vif->mac->macid, vif->vifid, join_info->bssid, status); if (status != WLAN_STATUS_SUCCESS) goto done; qlink_chandef_q2cfg(wiphy, &join_info->chan, &chandef); if (!cfg80211_chandef_valid(&chandef)) { pr_warn("MAC%u.%u: bad channel freq=%u cf1=%u cf2=%u bw=%u\n", vif->mac->macid, vif->vifid, chandef.chan->center_freq, chandef.center_freq1, chandef.center_freq2, chandef.width); status = WLAN_STATUS_UNSPECIFIED_FAILURE; goto done; } bss = cfg80211_get_bss(wiphy, chandef.chan, join_info->bssid, NULL, 0, IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY); if (!bss) { pr_warn("VIF%u.%u: add missing BSS:%pM chan:%u\n", vif->mac->macid, vif->vifid, join_info->bssid, chandef.chan->hw_value); if (!vif->wdev.ssid_len) { pr_warn("VIF%u.%u: SSID unknown for BSS:%pM\n", vif->mac->macid, vif->vifid, join_info->bssid); status = WLAN_STATUS_UNSPECIFIED_FAILURE; goto done; } ie = kzalloc(2 + vif->wdev.ssid_len, GFP_KERNEL); if (!ie) { pr_warn("VIF%u.%u: IE alloc failed for BSS:%pM\n", vif->mac->macid, vif->vifid, join_info->bssid); status = WLAN_STATUS_UNSPECIFIED_FAILURE; goto done; } ie[0] = WLAN_EID_SSID; ie[1] = vif->wdev.ssid_len; memcpy(ie + 2, vif->wdev.ssid, vif->wdev.ssid_len); bss = cfg80211_inform_bss(wiphy, chandef.chan, CFG80211_BSS_FTYPE_UNKNOWN, join_info->bssid, 0, WLAN_CAPABILITY_ESS, 100, ie, 2 + vif->wdev.ssid_len, 0, GFP_KERNEL); if (!bss) { pr_warn("VIF%u.%u: can't connect to unknown BSS: %pM\n", vif->mac->macid, vif->vifid, join_info->bssid); status = WLAN_STATUS_UNSPECIFIED_FAILURE; goto done; } } payload_len = len - sizeof(*join_info); tlv = (struct qlink_tlv_hdr *)join_info->ies; while (payload_len >= sizeof(struct qlink_tlv_hdr)) { tlv_type = le16_to_cpu(tlv->type); tlv_value_len = le16_to_cpu(tlv->len); tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); if (payload_len < tlv_full_len) { pr_warn("invalid %u TLV\n", tlv_type); status = WLAN_STATUS_UNSPECIFIED_FAILURE; goto done; } if (tlv_type == QTN_TLV_ID_IE_SET) { const struct qlink_tlv_ie_set *ie_set; unsigned int ie_len; if (payload_len < sizeof(*ie_set)) { pr_warn("invalid IE_SET TLV\n"); status = WLAN_STATUS_UNSPECIFIED_FAILURE; goto done; } ie_set = (const struct qlink_tlv_ie_set *)tlv; ie_len = tlv_value_len - (sizeof(*ie_set) - sizeof(ie_set->hdr)); switch (ie_set->type) { case QLINK_IE_SET_ASSOC_RESP: if (ie_len) { rsp_ies = ie_set->ie_data; rsp_ies_len = ie_len; } break; default: pr_warn("unexpected IE type: %u\n", ie_set->type); break; } } payload_len -= tlv_full_len; tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); } if (payload_len) pr_warn("VIF%u.%u: unexpected remaining payload: %zu\n", vif->mac->macid, vif->vifid, payload_len); done: cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, rsp_ies, rsp_ies_len, status, GFP_KERNEL); if (bss) { if (!ether_addr_equal(vif->bssid, join_info->bssid)) ether_addr_copy(vif->bssid, join_info->bssid); cfg80211_put_bss(wiphy, bss); } if (status == WLAN_STATUS_SUCCESS) netif_carrier_on(vif->netdev); kfree(ie); return 0; }