/* * 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; }
/* * This function locates the Channel-Frequency-Power triplet based upon * band and channel/frequency parameters. */ struct mwifiex_chan_freq_power * mwifiex_get_cfp(struct mwifiex_private *priv, u8 band, u16 channel, u32 freq) { struct mwifiex_chan_freq_power *cfp = NULL; struct ieee80211_supported_band *sband; struct ieee80211_channel *ch = NULL; int i; if (!channel && !freq) return cfp; if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG) sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; else sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; if (!sband) { dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d\n", __func__, band); return cfp; } for (i = 0; i < sband->n_channels; i++) { ch = &sband->channels[i]; if (ch->flags & IEEE80211_CHAN_DISABLED) continue; if (freq) { if (ch->center_freq == freq) break; } else { /* find by valid channel*/ if (ch->hw_value == channel || channel == FIRST_VALID_CHANNEL) break; } } if (i == sband->n_channels) { dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" " & channel=%d freq=%d\n", __func__, band, channel, freq); } else { if (!ch) return cfp; priv->cfp.channel = ch->hw_value; priv->cfp.freq = ch->center_freq; priv->cfp.max_tx_power = ch->max_power; cfp = &priv->cfp; } return cfp; }
/* This function appends 11h info to a buffer while joining an * infrastructure BSS */ static void mwifiex_11h_process_infra_join(struct mwifiex_private *priv, u8 **buffer, struct mwifiex_bssdescriptor *bss_desc) { struct mwifiex_ie_types_header *ie_header; struct mwifiex_ie_types_pwr_capability *cap; struct mwifiex_ie_types_local_pwr_constraint *constraint; struct ieee80211_supported_band *sband; u8 radio_type; int i; if (!buffer || !(*buffer)) return; radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); sband = priv->wdev.wiphy->bands[radio_type]; cap = (struct mwifiex_ie_types_pwr_capability *)*buffer; cap->header.type = cpu_to_le16(WLAN_EID_PWR_CAPABILITY); cap->header.len = cpu_to_le16(2); cap->min_pwr = 0; cap->max_pwr = 0; *buffer += sizeof(*cap); constraint = (struct mwifiex_ie_types_local_pwr_constraint *)*buffer; constraint->header.type = cpu_to_le16(WLAN_EID_PWR_CONSTRAINT); constraint->header.len = cpu_to_le16(2); constraint->chan = bss_desc->channel; constraint->constraint = bss_desc->local_constraint; *buffer += sizeof(*constraint); ie_header = (struct mwifiex_ie_types_header *)*buffer; ie_header->type = cpu_to_le16(TLV_TYPE_PASSTHROUGH); ie_header->len = cpu_to_le16(2 * sband->n_channels + 2); *buffer += sizeof(*ie_header); *(*buffer)++ = WLAN_EID_SUPPORTED_CHANNELS; *(*buffer)++ = 2 * sband->n_channels; for (i = 0; i < sband->n_channels; i++) { *(*buffer)++ = ieee80211_frequency_to_channel( sband->channels[i].center_freq); *(*buffer)++ = 1; /* one channel in the subband */ } }
/* * This function locates the Channel-Frequency-Power triplet based upon * band and channel parameters. */ struct mwifiex_chan_freq_power * mwifiex_get_cfp_by_band_and_channel_from_cfg80211(struct mwifiex_private *priv, u8 band, u16 channel) { struct mwifiex_chan_freq_power *cfp = NULL; struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; int i; if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG) sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; else sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; if (!sband) { dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" " & channel %d\n", __func__, band, channel); return cfp; } for (i = 0; i < sband->n_channels; i++) { ch = &sband->channels[i]; if (((ch->hw_value == channel) || (channel == FIRST_VALID_CHANNEL)) && !(ch->flags & IEEE80211_CHAN_DISABLED)) { priv->cfp.channel = channel; priv->cfp.freq = ch->center_freq; priv->cfp.max_tx_power = ch->max_power; cfp = &priv->cfp; break; } } if (i == sband->n_channels) dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" " & channel %d\n", __func__, band, channel); return cfp; }
/* * This function prepares command for ad-hoc start. * * Driver will fill up SSID, BSS mode, IBSS parameters, physical * parameters, probe delay, and capability information. Firmware * will fill up beacon period, basic rates and operational rates. * * In addition, the following TLVs are added - * - Channel TLV * - Vendor specific IE * - WPA/WPA2 IE * - HT Capabilities IE * - HT Information IE * * Preparation also includes - * - Setting command ID and proper size * - Ensuring correct endian-ness */ int mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, struct cfg80211_ssid *req_ssid) { int rsn_ie_len = 0; struct mwifiex_adapter *adapter = priv->adapter; struct host_cmd_ds_802_11_ad_hoc_start *adhoc_start = &cmd->params.adhoc_start; struct mwifiex_bssdescriptor *bss_desc; u32 cmd_append_size = 0; u32 i; u16 tmp_cap; struct mwifiex_ie_types_chan_list_param_set *chan_tlv; u8 radio_type; struct mwifiex_ie_types_htcap *ht_cap; struct mwifiex_ie_types_htinfo *ht_info; u8 *pos = (u8 *) adhoc_start + sizeof(struct host_cmd_ds_802_11_ad_hoc_start); if (!adapter) return -1; cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START); bss_desc = &priv->curr_bss_params.bss_descriptor; priv->attempted_bss_desc = bss_desc; /* * Fill in the parameters for 2 data structures: * 1. struct host_cmd_ds_802_11_ad_hoc_start command * 2. bss_desc * Driver will fill up SSID, bss_mode,IBSS param, Physical Param, * probe delay, and Cap info. * Firmware will fill up beacon period, Basic rates * and operational rates. */ memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN); memcpy(adhoc_start->ssid, req_ssid->ssid, req_ssid->ssid_len); dev_dbg(adapter->dev, "info: ADHOC_S_CMD: SSID = %s\n", adhoc_start->ssid); memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN); memcpy(bss_desc->ssid.ssid, req_ssid->ssid, req_ssid->ssid_len); bss_desc->ssid.ssid_len = req_ssid->ssid_len; /* Set the BSS mode */ adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS; bss_desc->bss_mode = NL80211_IFTYPE_ADHOC; adhoc_start->beacon_period = cpu_to_le16(priv->beacon_period); bss_desc->beacon_period = priv->beacon_period; /* Set Physical param set */ /* Parameter IE Id */ #define DS_PARA_IE_ID 3 /* Parameter IE length */ #define DS_PARA_IE_LEN 1 adhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID; adhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN; if (!mwifiex_get_cfp(priv, adapter->adhoc_start_band, (u16) priv->adhoc_channel, 0)) { struct mwifiex_chan_freq_power *cfp; cfp = mwifiex_get_cfp(priv, adapter->adhoc_start_band, FIRST_VALID_CHANNEL, 0); if (cfp) priv->adhoc_channel = (u8) cfp->channel; } if (!priv->adhoc_channel) { dev_err(adapter->dev, "ADHOC_S_CMD: adhoc_channel cannot be 0\n"); return -1; } dev_dbg(adapter->dev, "info: ADHOC_S_CMD: creating ADHOC on channel %d\n", priv->adhoc_channel); priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel; priv->curr_bss_params.band = adapter->adhoc_start_band; bss_desc->channel = priv->adhoc_channel; adhoc_start->phy_param_set.ds_param_set.current_chan = priv->adhoc_channel; memcpy(&bss_desc->phy_param_set, &adhoc_start->phy_param_set, sizeof(union ieee_types_phy_param_set)); /* Set IBSS param set */ /* IBSS parameter IE Id */ #define IBSS_PARA_IE_ID 6 /* IBSS parameter IE length */ #define IBSS_PARA_IE_LEN 2 adhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID; adhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN; adhoc_start->ss_param_set.ibss_param_set.atim_window = cpu_to_le16(priv->atim_window); memcpy(&bss_desc->ss_param_set, &adhoc_start->ss_param_set, sizeof(union ieee_types_ss_param_set)); /* Set Capability info */ bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS; tmp_cap = le16_to_cpu(adhoc_start->cap_info_bitmap); tmp_cap &= ~WLAN_CAPABILITY_ESS; tmp_cap |= WLAN_CAPABILITY_IBSS; /* Set up privacy in bss_desc */ if (priv->sec_info.encryption_mode) { /* Ad-Hoc capability privacy on */ dev_dbg(adapter->dev, "info: ADHOC_S_CMD: wep_status set privacy to WEP\n"); bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; tmp_cap |= WLAN_CAPABILITY_PRIVACY; } else { dev_dbg(adapter->dev, "info: ADHOC_S_CMD: wep_status NOT set," " setting privacy to ACCEPT ALL\n"); bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; } memset(adhoc_start->data_rate, 0, sizeof(adhoc_start->data_rate)); mwifiex_get_active_data_rates(priv, adhoc_start->data_rate); if ((adapter->adhoc_start_band & BAND_G) && (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) { if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, HostCmd_ACT_GEN_SET, 0, &priv->curr_pkt_filter)) { dev_err(adapter->dev, "ADHOC_S_CMD: G Protection config failed\n"); return -1; } } /* Find the last non zero */ for (i = 0; i < sizeof(adhoc_start->data_rate); i++) if (!adhoc_start->data_rate[i]) break; priv->curr_bss_params.num_of_rates = i; /* Copy the ad-hoc creating rates into Current BSS rate structure */ memcpy(&priv->curr_bss_params.data_rates, &adhoc_start->data_rate, priv->curr_bss_params.num_of_rates); dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%4ph\n", adhoc_start->data_rate); dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n"); if (IS_SUPPORT_MULTI_BANDS(adapter)) { /* Append a channel TLV */ chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); chan_tlv->header.len = cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); memset(chan_tlv->chan_scan_param, 0x00, sizeof(struct mwifiex_chan_scan_param_set)); chan_tlv->chan_scan_param[0].chan_number = (u8) priv->curr_bss_params.bss_descriptor.channel; dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Chan = %d\n", chan_tlv->chan_scan_param[0].chan_number); chan_tlv->chan_scan_param[0].radio_type = mwifiex_band_to_radio_type(priv->curr_bss_params.band); if (adapter->adhoc_start_band & BAND_GN || adapter->adhoc_start_band & BAND_AN) { if (adapter->sec_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) chan_tlv->chan_scan_param[0].radio_type |= (IEEE80211_HT_PARAM_CHA_SEC_ABOVE << 4); else if (adapter->sec_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) chan_tlv->chan_scan_param[0].radio_type |= (IEEE80211_HT_PARAM_CHA_SEC_BELOW << 4); } dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Band = %d\n", chan_tlv->chan_scan_param[0].radio_type); pos += sizeof(chan_tlv->header) + sizeof(struct mwifiex_chan_scan_param_set); cmd_append_size += sizeof(chan_tlv->header) + sizeof(struct mwifiex_chan_scan_param_set); } /* Append vendor specific IE TLV */ cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ADHOC, &pos); if (priv->sec_info.wpa_enabled) { rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); if (rsn_ie_len == -1) return -1; cmd_append_size += rsn_ie_len; } if (adapter->adhoc_11n_enabled) { /* Fill HT CAPABILITY */ ht_cap = (struct mwifiex_ie_types_htcap *) pos; memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); ht_cap->header.len = cpu_to_le16(sizeof(struct ieee80211_ht_cap)); radio_type = mwifiex_band_to_radio_type( priv->adapter->config_bands); mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap); if (adapter->sec_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) { u16 tmp_ht_cap; tmp_ht_cap = le16_to_cpu(ht_cap->ht_cap.cap_info); tmp_ht_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; tmp_ht_cap &= ~IEEE80211_HT_CAP_SGI_40; ht_cap->ht_cap.cap_info = cpu_to_le16(tmp_ht_cap); } pos += sizeof(struct mwifiex_ie_types_htcap); cmd_append_size += sizeof(struct mwifiex_ie_types_htcap); /* Fill HT INFORMATION */ ht_info = (struct mwifiex_ie_types_htinfo *) pos; memset(ht_info, 0, sizeof(struct mwifiex_ie_types_htinfo)); ht_info->header.type = cpu_to_le16(WLAN_EID_HT_OPERATION); ht_info->header.len = cpu_to_le16(sizeof(struct ieee80211_ht_operation)); ht_info->ht_oper.primary_chan = (u8) priv->curr_bss_params.bss_descriptor.channel; if (adapter->sec_chan_offset) { ht_info->ht_oper.ht_param = adapter->sec_chan_offset; ht_info->ht_oper.ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; } ht_info->ht_oper.operation_mode = cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); ht_info->ht_oper.basic_set[0] = 0xff; pos += sizeof(struct mwifiex_ie_types_htinfo); cmd_append_size += sizeof(struct mwifiex_ie_types_htinfo); } cmd->size = cpu_to_le16((u16)(sizeof(struct host_cmd_ds_802_11_ad_hoc_start) + S_DS_GEN + cmd_append_size)); if (adapter->adhoc_start_band == BAND_B) tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; else tmp_cap |= WLAN_CAPABILITY_SHORT_SLOT_TIME; adhoc_start->cap_info_bitmap = cpu_to_le16(tmp_cap); return 0; }
/* * This function prepares command for association. * * This sets the following parameters - * - Peer MAC address * - Listen interval * - Beacon interval * - Capability information * * ...and the following TLVs, as required - * - SSID TLV * - PHY TLV * - SS TLV * - Rates TLV * - Authentication TLV * - Channel TLV * - WPA/WPA2 IE * - 11n TLV * - Vendor specific TLV * - WMM TLV * - WAPI IE * - Generic IE * - TSF TLV * * Preparation also includes - * - Setting command ID and proper size * - Ensuring correct endian-ness */ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, struct mwifiex_bssdescriptor *bss_desc) { struct host_cmd_ds_802_11_associate *assoc = &cmd->params.associate; struct mwifiex_ie_types_ssid_param_set *ssid_tlv; struct mwifiex_ie_types_phy_param_set *phy_tlv; struct mwifiex_ie_types_ss_param_set *ss_tlv; struct mwifiex_ie_types_rates_param_set *rates_tlv; struct mwifiex_ie_types_auth_type *auth_tlv; struct mwifiex_ie_types_chan_list_param_set *chan_tlv; u8 rates[MWIFIEX_SUPPORTED_RATES]; u32 rates_size; u16 tmp_cap; u8 *pos; int rsn_ie_len = 0; pos = (u8 *) assoc; cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE); /* Save so we know which BSS Desc to use in the response handler */ priv->attempted_bss_desc = bss_desc; memcpy(assoc->peer_sta_addr, bss_desc->mac_address, sizeof(assoc->peer_sta_addr)); pos += sizeof(assoc->peer_sta_addr); /* Set the listen interval */ assoc->listen_interval = cpu_to_le16(priv->listen_interval); /* Set the beacon period */ assoc->beacon_period = cpu_to_le16(bss_desc->beacon_period); pos += sizeof(assoc->cap_info_bitmap); pos += sizeof(assoc->listen_interval); pos += sizeof(assoc->beacon_period); pos += sizeof(assoc->dtim_period); ssid_tlv = (struct mwifiex_ie_types_ssid_param_set *) pos; ssid_tlv->header.type = cpu_to_le16(WLAN_EID_SSID); ssid_tlv->header.len = cpu_to_le16((u16) bss_desc->ssid.ssid_len); memcpy(ssid_tlv->ssid, bss_desc->ssid.ssid, le16_to_cpu(ssid_tlv->header.len)); pos += sizeof(ssid_tlv->header) + le16_to_cpu(ssid_tlv->header.len); phy_tlv = (struct mwifiex_ie_types_phy_param_set *) pos; phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS); phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set)); memcpy(&phy_tlv->fh_ds.ds_param_set, &bss_desc->phy_param_set.ds_param_set.current_chan, sizeof(phy_tlv->fh_ds.ds_param_set)); pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len); ss_tlv = (struct mwifiex_ie_types_ss_param_set *) pos; ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS); ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set)); pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len); /* Get the common rates supported between the driver and the BSS Desc */ if (mwifiex_setup_rates_from_bssdesc (priv, bss_desc, rates, &rates_size)) return -1; /* Save the data rates into Current BSS state structure */ priv->curr_bss_params.num_of_rates = rates_size; memcpy(&priv->curr_bss_params.data_rates, rates, rates_size); /* Setup the Rates TLV in the association command */ rates_tlv = (struct mwifiex_ie_types_rates_param_set *) pos; rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); rates_tlv->header.len = cpu_to_le16((u16) rates_size); memcpy(rates_tlv->rates, rates, rates_size); pos += sizeof(rates_tlv->header) + rates_size; dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: rates size = %d\n", rates_size); /* Add the Authentication type to be used for Auth frames */ auth_tlv = (struct mwifiex_ie_types_auth_type *) pos; auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type)); if (priv->sec_info.wep_enabled) auth_tlv->auth_type = cpu_to_le16( (u16) priv->sec_info.authentication_mode); else auth_tlv->auth_type = cpu_to_le16(NL80211_AUTHTYPE_OPEN_SYSTEM); pos += sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len); if (IS_SUPPORT_MULTI_BANDS(priv->adapter) && !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info) && (!bss_desc->disable_11n) && (priv->adapter->config_bands & BAND_GN || priv->adapter->config_bands & BAND_AN) && (bss_desc->bcn_ht_cap) ) ) { /* Append a channel TLV for the channel the attempted AP was found on */ chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); chan_tlv->header.len = cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); memset(chan_tlv->chan_scan_param, 0x00, sizeof(struct mwifiex_chan_scan_param_set)); chan_tlv->chan_scan_param[0].chan_number = (bss_desc->phy_param_set.ds_param_set.current_chan); dev_dbg(priv->adapter->dev, "info: Assoc: TLV Chan = %d\n", chan_tlv->chan_scan_param[0].chan_number); chan_tlv->chan_scan_param[0].radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); dev_dbg(priv->adapter->dev, "info: Assoc: TLV Band = %d\n", chan_tlv->chan_scan_param[0].radio_type); pos += sizeof(chan_tlv->header) + sizeof(struct mwifiex_chan_scan_param_set); } if (!priv->wps.session_enable) { if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); if (rsn_ie_len == -1) return -1; } if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) && (!bss_desc->disable_11n) && (priv->adapter->config_bands & BAND_GN || priv->adapter->config_bands & BAND_AN)) mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos); if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) && !bss_desc->disable_11n && !bss_desc->disable_11ac && priv->adapter->config_bands & BAND_AAC) mwifiex_cmd_append_11ac_tlv(priv, bss_desc, &pos); /* Append vendor specific IE TLV */ mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos); mwifiex_wmm_process_association_req(priv, &pos, &bss_desc->wmm_ie, bss_desc->bcn_ht_cap); if (priv->sec_info.wapi_enabled && priv->wapi_ie_len) mwifiex_cmd_append_wapi_ie(priv, &pos); if (priv->wps.session_enable && priv->wps_ie_len) mwifiex_cmd_append_wps_ie(priv, &pos); mwifiex_cmd_append_generic_ie(priv, &pos); mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc); mwifiex_11h_process_join(priv, &pos, bss_desc); cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN); /* Set the Capability info at last */ tmp_cap = bss_desc->cap_info_bitmap; if (priv->adapter->config_bands == BAND_B) tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; tmp_cap &= CAPINFO_MASK; dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", tmp_cap, CAPINFO_MASK); assoc->cap_info_bitmap = cpu_to_le16(tmp_cap); return 0; }
/* * This function prepares command for ad-hoc join. * * Most of the parameters are set up by copying from the target BSS descriptor * from the scan response. * * In addition, the following TLVs are added - * - Channel TLV * - Vendor specific IE * - WPA/WPA2 IE * - 11n IE * * Preparation also includes - * - Setting command ID and proper size * - Ensuring correct endian-ness */ int mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, struct mwifiex_bssdescriptor *bss_desc) { int rsn_ie_len = 0; struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join = &cmd->params.adhoc_join; struct mwifiex_ie_types_chan_list_param_set *chan_tlv; u32 cmd_append_size = 0; u16 tmp_cap; u32 i, rates_size = 0; u16 curr_pkt_filter; u8 *pos = (u8 *) adhoc_join + sizeof(struct host_cmd_ds_802_11_ad_hoc_join); /* Use G protection */ #define USE_G_PROTECTION 0x02 if (bss_desc->erp_flags & USE_G_PROTECTION) { curr_pkt_filter = priv-> curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON; if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, HostCmd_ACT_GEN_SET, 0, &curr_pkt_filter)) { dev_err(priv->adapter->dev, "ADHOC_J_CMD: G Protection config failed\n"); return -1; } } priv->attempted_bss_desc = bss_desc; cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN); adhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS; adhoc_join->bss_descriptor.beacon_period = cpu_to_le16(bss_desc->beacon_period); memcpy(&adhoc_join->bss_descriptor.bssid, &bss_desc->mac_address, ETH_ALEN); memcpy(&adhoc_join->bss_descriptor.ssid, &bss_desc->ssid.ssid, bss_desc->ssid.ssid_len); memcpy(&adhoc_join->bss_descriptor.phy_param_set, &bss_desc->phy_param_set, sizeof(union ieee_types_phy_param_set)); memcpy(&adhoc_join->bss_descriptor.ss_param_set, &bss_desc->ss_param_set, sizeof(union ieee_types_ss_param_set)); tmp_cap = bss_desc->cap_info_bitmap; tmp_cap &= CAPINFO_MASK; dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", tmp_cap, CAPINFO_MASK); /* Information on BSSID descriptor passed to FW */ dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: BSSID=%pM, SSID='%s'\n", adhoc_join->bss_descriptor.bssid, adhoc_join->bss_descriptor.ssid); for (i = 0; i < MWIFIEX_SUPPORTED_RATES && bss_desc->supported_rates[i]; i++) ; rates_size = i; /* Copy Data Rates from the Rates recorded in scan response */ memset(adhoc_join->bss_descriptor.data_rates, 0, sizeof(adhoc_join->bss_descriptor.data_rates)); memcpy(adhoc_join->bss_descriptor.data_rates, bss_desc->supported_rates, rates_size); /* Copy the adhoc join rates into Current BSS state structure */ priv->curr_bss_params.num_of_rates = rates_size; memcpy(&priv->curr_bss_params.data_rates, bss_desc->supported_rates, rates_size); /* Copy the channel information */ priv->curr_bss_params.bss_descriptor.channel = bss_desc->channel; priv->curr_bss_params.band = (u8) bss_desc->bss_band; if (priv->sec_info.wep_enabled || priv->sec_info.wpa_enabled) tmp_cap |= WLAN_CAPABILITY_PRIVACY; if (IS_SUPPORT_MULTI_BANDS(priv->adapter)) { /* Append a channel TLV */ chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); chan_tlv->header.len = cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); memset(chan_tlv->chan_scan_param, 0x00, sizeof(struct mwifiex_chan_scan_param_set)); chan_tlv->chan_scan_param[0].chan_number = (bss_desc->phy_param_set.ds_param_set.current_chan); dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Chan=%d\n", chan_tlv->chan_scan_param[0].chan_number); chan_tlv->chan_scan_param[0].radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Band=%d\n", chan_tlv->chan_scan_param[0].radio_type); pos += sizeof(chan_tlv->header) + sizeof(struct mwifiex_chan_scan_param_set); cmd_append_size += sizeof(chan_tlv->header) + sizeof(struct mwifiex_chan_scan_param_set); } if (priv->sec_info.wpa_enabled) rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); if (rsn_ie_len == -1) return -1; cmd_append_size += rsn_ie_len; if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)) cmd_append_size += mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos); /* Append vendor specific IE TLV */ cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ADHOC, &pos); cmd->size = cpu_to_le16 ((u16) (sizeof(struct host_cmd_ds_802_11_ad_hoc_join) + S_DS_GEN + cmd_append_size)); adhoc_join->bss_descriptor.cap_info_bitmap = cpu_to_le16(tmp_cap); return 0; }
/* * This function sends domain information to the firmware. * * The following information are passed to the firmware - * - Country codes * - Sub bands (first channel, number of channels, maximum Tx power) */ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) { u8 no_of_triplet = 0; struct ieee80211_country_ie_triplet *t; u8 no_of_parsed_chan = 0; u8 first_chan = 0, next_chan = 0, max_pwr = 0; u8 i, flag = 0; enum ieee80211_band band; struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_private *priv; struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg; /* Set country code */ domain_info->country_code[0] = adapter->country_code[0]; domain_info->country_code[1] = adapter->country_code[1]; domain_info->country_code[2] = ' '; band = mwifiex_band_to_radio_type(adapter->config_bands); if (!wiphy->bands[band]) { wiphy_err(wiphy, "11D: setting domain info in FW\n"); return -1; } sband = wiphy->bands[band]; for (i = 0; i < sband->n_channels ; i++) { ch = &sband->channels[i]; if (ch->flags & IEEE80211_CHAN_DISABLED) continue; if (!flag) { flag = 1; first_chan = (u32) ch->hw_value; next_chan = first_chan; max_pwr = ch->max_power; no_of_parsed_chan = 1; continue; } if (ch->hw_value == next_chan + 1 && ch->max_power == max_pwr) { next_chan++; no_of_parsed_chan++; } else { t = &domain_info->triplet[no_of_triplet]; t->chans.first_channel = first_chan; t->chans.num_channels = no_of_parsed_chan; t->chans.max_power = max_pwr; no_of_triplet++; first_chan = (u32) ch->hw_value; next_chan = first_chan; max_pwr = ch->max_power; no_of_parsed_chan = 1; } } if (flag) { t = &domain_info->triplet[no_of_triplet]; t->chans.first_channel = first_chan; t->chans.num_channels = no_of_parsed_chan; t->chans.max_power = max_pwr; no_of_triplet++; } domain_info->no_of_triplet = no_of_triplet; priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, HostCmd_ACT_GEN_SET, 0, NULL)) { wiphy_err(wiphy, "11D: setting domain info in FW\n"); return -1; } return 0; }
/* * In Ad-Hoc mode, the IBSS is created if not found in scan list. * In both Ad-Hoc and infra mode, an deauthentication is performed * first. */ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, struct cfg80211_ssid *req_ssid) { int ret; struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_bssdescriptor *bss_desc = NULL; priv->scan_block = false; if (bss) { mwifiex_process_country_ie(priv, bss); /* Allocate and fill new bss descriptor */ bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), GFP_KERNEL); if (!bss_desc) return -ENOMEM; ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc); if (ret) goto done; } if (priv->bss_mode == NL80211_IFTYPE_STATION || priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) { u8 config_bands; ret = mwifiex_deauthenticate(priv, NULL); if (ret) goto done; if (!bss_desc) return -1; if (mwifiex_band_to_radio_type(bss_desc->bss_band) == HostCmd_SCAN_RADIO_TYPE_BG) config_bands = BAND_B | BAND_G | BAND_GN; else config_bands = BAND_A | BAND_AN | BAND_AAC; if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands)) adapter->config_bands = config_bands; ret = mwifiex_check_network_compatibility(priv, bss_desc); if (ret) goto done; if (mwifiex_11h_get_csa_closed_channel(priv) == (u8)bss_desc->channel) { dev_err(adapter->dev, "Attempt to reconnect on csa closed chan(%d)\n", bss_desc->channel); goto done; } dev_dbg(adapter->dev, "info: SSID found in scan list ... " "associating...\n"); mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); /* Clear any past association response stored for * application retrieval */ priv->assoc_rsp_size = 0; ret = mwifiex_associate(priv, bss_desc); /* If auth type is auto and association fails using open mode, * try to connect using shared mode */ if (ret == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG && priv->sec_info.is_authtype_auto && priv->sec_info.wep_enabled) { priv->sec_info.authentication_mode = NL80211_AUTHTYPE_SHARED_KEY; ret = mwifiex_associate(priv, bss_desc); } if (bss) cfg80211_put_bss(priv->adapter->wiphy, bss); } else { /* Adhoc mode */ /* If the requested SSID matches current SSID, return */ if (bss_desc && bss_desc->ssid.ssid_len && (!mwifiex_ssid_cmp(&priv->curr_bss_params.bss_descriptor. ssid, &bss_desc->ssid))) { ret = 0; goto done; } /* Exit Adhoc mode first */ dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n"); ret = mwifiex_deauthenticate(priv, NULL); if (ret) goto done; priv->adhoc_is_link_sensed = false; ret = mwifiex_check_network_compatibility(priv, bss_desc); mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); if (!ret) { dev_dbg(adapter->dev, "info: network found in scan" " list. Joining...\n"); ret = mwifiex_adhoc_join(priv, bss_desc); if (bss) cfg80211_put_bss(priv->adapter->wiphy, bss); } else { dev_dbg(adapter->dev, "info: Network not found in " "the list, creating adhoc with ssid = %s\n", req_ssid->ssid); ret = mwifiex_adhoc_start(priv, req_ssid); } } done: /* beacon_ie buffer was allocated in function * mwifiex_fill_new_bss_desc(). Free it now. */ if (bss_desc) kfree(bss_desc->beacon_buf); kfree(bss_desc); return ret; }
int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, u16 channel) { int ret; struct mwifiex_bss_info bss_info; struct mwifiex_ssid_bssid ssid_bssid; u16 curr_chan = 0; struct cfg80211_bss *bss = NULL; struct ieee80211_channel *chan; enum ieee80211_band band; memset(&bss_info, 0, sizeof(bss_info)); if (mwifiex_get_bss_info(priv, &bss_info)) return -1; ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_GET, &curr_chan); if (curr_chan == channel) { ret = 0; goto done; } dev_dbg(priv->adapter->dev, "cmd: updating channel from %d to %d\n", curr_chan, channel); if (!bss_info.media_connected) { ret = 0; goto done; } memset(&ssid_bssid, 0, ETH_ALEN); ret = mwifiex_deauthenticate(priv, ssid_bssid.bssid); ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_SET, &channel); if (mwifiex_request_scan(priv, &bss_info.ssid)) { ret = -1; goto done; } band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); chan = __ieee80211_get_channel(priv->wdev->wiphy, ieee80211_channel_to_frequency(channel, band)); bss = cfg80211_get_bss(priv->wdev->wiphy, chan, bss_info.bssid, bss_info.ssid.ssid, bss_info.ssid.ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); if (!bss) wiphy_warn(priv->wdev->wiphy, "assoc: bss %pM not in scan results\n", bss_info.bssid); ret = mwifiex_bss_start(priv, bss, &bss_info.ssid); done: return ret; }
/* * This function fills bss descriptor structure using provided * information. * beacon_ie buffer is allocated in this function. It is caller's * responsibility to free the memory. */ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, struct cfg80211_bss *bss, struct mwifiex_bssdescriptor *bss_desc) { u8 *beacon_ie; size_t beacon_ie_len; struct mwifiex_bss_priv *bss_priv = (void *)bss->priv; const struct cfg80211_bss_ies *ies; int ret; rcu_read_lock(); ies = rcu_dereference(bss->ies); beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC); beacon_ie_len = ies->len; bss_desc->timestamp = ies->tsf; rcu_read_unlock(); if (!beacon_ie) { mwifiex_dbg(priv->adapter, ERROR, " failed to alloc beacon_ie\n"); return -ENOMEM; } memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN); bss_desc->rssi = bss->signal; /* The caller of this function will free beacon_ie */ bss_desc->beacon_buf = beacon_ie; bss_desc->beacon_buf_size = beacon_ie_len; bss_desc->beacon_period = bss->beacon_interval; bss_desc->cap_info_bitmap = bss->capability; bss_desc->bss_band = bss_priv->band; bss_desc->fw_tsf = bss_priv->fw_tsf; if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { mwifiex_dbg(priv->adapter, INFO, "info: InterpretIE: AP WEP enabled\n"); bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; } else { bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; } if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_IBSS) bss_desc->bss_mode = NL80211_IFTYPE_ADHOC; else bss_desc->bss_mode = NL80211_IFTYPE_STATION; /* Disable 11ac by default. Enable it only where there * exist VHT_CAP IE in AP beacon */ bss_desc->disable_11ac = true; if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_SPECTRUM_MGMT) bss_desc->sensed_11h = true; ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc); if (ret) return ret; /* Update HT40 capability based on current channel information */ if (bss_desc->bcn_ht_oper && bss_desc->bcn_ht_cap) { u8 ht_param = bss_desc->bcn_ht_oper->ht_param; u8 radio = mwifiex_band_to_radio_type(bss_desc->bss_band); struct ieee80211_supported_band *sband = priv->wdev.wiphy->bands[radio]; int freq = ieee80211_channel_to_frequency(bss_desc->channel, radio); struct ieee80211_channel *chan = ieee80211_get_channel(priv->adapter->wiphy, freq); switch (ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) { sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; } else { sband->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_SGI_40; } break; case IEEE80211_HT_PARAM_CHA_SEC_BELOW: if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) { sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; } else { sband->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_SGI_40; } break; } } return 0; }
int mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, struct cfg80211_ssid *req_ssid) { int rsn_ie_len = 0; struct mwifiex_adapter *adapter = priv->adapter; struct host_cmd_ds_802_11_ad_hoc_start *adhoc_start = &cmd->params.adhoc_start; struct mwifiex_bssdescriptor *bss_desc; u32 cmd_append_size = 0; u32 i; u16 tmp_cap; struct mwifiex_ie_types_chan_list_param_set *chan_tlv; u8 radio_type; struct mwifiex_ie_types_htcap *ht_cap; struct mwifiex_ie_types_htinfo *ht_info; u8 *pos = (u8 *) adhoc_start + sizeof(struct host_cmd_ds_802_11_ad_hoc_start); if (!adapter) return -1; cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START); bss_desc = &priv->curr_bss_params.bss_descriptor; priv->attempted_bss_desc = bss_desc; memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN); memcpy(adhoc_start->ssid, req_ssid->ssid, req_ssid->ssid_len); dev_dbg(adapter->dev, "info: ADHOC_S_CMD: SSID = %s\n", adhoc_start->ssid); memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN); memcpy(bss_desc->ssid.ssid, req_ssid->ssid, req_ssid->ssid_len); bss_desc->ssid.ssid_len = req_ssid->ssid_len; adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS; bss_desc->bss_mode = NL80211_IFTYPE_ADHOC; adhoc_start->beacon_period = cpu_to_le16(priv->beacon_period); bss_desc->beacon_period = priv->beacon_period; #define DS_PARA_IE_ID 3 #define DS_PARA_IE_LEN 1 adhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID; adhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN; if (!mwifiex_get_cfp(priv, adapter->adhoc_start_band, (u16) priv->adhoc_channel, 0)) { struct mwifiex_chan_freq_power *cfp; cfp = mwifiex_get_cfp(priv, adapter->adhoc_start_band, FIRST_VALID_CHANNEL, 0); if (cfp) priv->adhoc_channel = (u8) cfp->channel; } if (!priv->adhoc_channel) { dev_err(adapter->dev, "ADHOC_S_CMD: adhoc_channel cannot be 0\n"); return -1; } dev_dbg(adapter->dev, "info: ADHOC_S_CMD: creating ADHOC on channel %d\n", priv->adhoc_channel); priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel; priv->curr_bss_params.band = adapter->adhoc_start_band; bss_desc->channel = priv->adhoc_channel; adhoc_start->phy_param_set.ds_param_set.current_chan = priv->adhoc_channel; memcpy(&bss_desc->phy_param_set, &adhoc_start->phy_param_set, sizeof(union ieee_types_phy_param_set)); #define IBSS_PARA_IE_ID 6 #define IBSS_PARA_IE_LEN 2 adhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID; adhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN; adhoc_start->ss_param_set.ibss_param_set.atim_window = cpu_to_le16(priv->atim_window); memcpy(&bss_desc->ss_param_set, &adhoc_start->ss_param_set, sizeof(union ieee_types_ss_param_set)); bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS; tmp_cap = le16_to_cpu(adhoc_start->cap_info_bitmap); tmp_cap &= ~WLAN_CAPABILITY_ESS; tmp_cap |= WLAN_CAPABILITY_IBSS; if (priv->sec_info.encryption_mode) { dev_dbg(adapter->dev, "info: ADHOC_S_CMD: wep_status set privacy to WEP\n"); bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; tmp_cap |= WLAN_CAPABILITY_PRIVACY; } else { dev_dbg(adapter->dev, "info: ADHOC_S_CMD: wep_status NOT set," " setting privacy to ACCEPT ALL\n"); bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; } memset(adhoc_start->data_rate, 0, sizeof(adhoc_start->data_rate)); mwifiex_get_active_data_rates(priv, adhoc_start->data_rate); if ((adapter->adhoc_start_band & BAND_G) && (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) { if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, HostCmd_ACT_GEN_SET, 0, &priv->curr_pkt_filter)) { dev_err(adapter->dev, "ADHOC_S_CMD: G Protection config failed\n"); return -1; } } for (i = 0; i < sizeof(adhoc_start->data_rate); i++) if (!adhoc_start->data_rate[i]) break; priv->curr_bss_params.num_of_rates = i; memcpy(&priv->curr_bss_params.data_rates, &adhoc_start->data_rate, priv->curr_bss_params.num_of_rates); dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%02x %02x %02x %02x\n", adhoc_start->data_rate[0], adhoc_start->data_rate[1], adhoc_start->data_rate[2], adhoc_start->data_rate[3]); dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n"); if (IS_SUPPORT_MULTI_BANDS(adapter)) { chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); chan_tlv->header.len = cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); memset(chan_tlv->chan_scan_param, 0x00, sizeof(struct mwifiex_chan_scan_param_set)); chan_tlv->chan_scan_param[0].chan_number = (u8) priv->curr_bss_params.bss_descriptor.channel; dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Chan = %d\n", chan_tlv->chan_scan_param[0].chan_number); chan_tlv->chan_scan_param[0].radio_type = mwifiex_band_to_radio_type(priv->curr_bss_params.band); if (adapter->adhoc_start_band & BAND_GN || adapter->adhoc_start_band & BAND_AN) { if (adapter->sec_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) chan_tlv->chan_scan_param[0].radio_type |= (IEEE80211_HT_PARAM_CHA_SEC_ABOVE << 4); else if (adapter->sec_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) chan_tlv->chan_scan_param[0].radio_type |= (IEEE80211_HT_PARAM_CHA_SEC_BELOW << 4); } dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Band = %d\n", chan_tlv->chan_scan_param[0].radio_type); pos += sizeof(chan_tlv->header) + sizeof(struct mwifiex_chan_scan_param_set); cmd_append_size += sizeof(chan_tlv->header) + sizeof(struct mwifiex_chan_scan_param_set); } cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ADHOC, &pos); if (priv->sec_info.wpa_enabled) { rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); if (rsn_ie_len == -1) return -1; cmd_append_size += rsn_ie_len; } if (adapter->adhoc_11n_enabled) { ht_cap = (struct mwifiex_ie_types_htcap *) pos; memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); ht_cap->header.len = cpu_to_le16(sizeof(struct ieee80211_ht_cap)); radio_type = mwifiex_band_to_radio_type( priv->adapter->config_bands); mwifiex_fill_cap_info(priv, radio_type, ht_cap); pos += sizeof(struct mwifiex_ie_types_htcap); cmd_append_size += sizeof(struct mwifiex_ie_types_htcap); ht_info = (struct mwifiex_ie_types_htinfo *) pos; memset(ht_info, 0, sizeof(struct mwifiex_ie_types_htinfo)); ht_info->header.type = cpu_to_le16(WLAN_EID_HT_INFORMATION); ht_info->header.len = cpu_to_le16(sizeof(struct ieee80211_ht_info)); ht_info->ht_info.control_chan = (u8) priv->curr_bss_params.bss_descriptor.channel; if (adapter->sec_chan_offset) { ht_info->ht_info.ht_param = adapter->sec_chan_offset; ht_info->ht_info.ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; } ht_info->ht_info.operation_mode = cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); ht_info->ht_info.basic_set[0] = 0xff; pos += sizeof(struct mwifiex_ie_types_htinfo); cmd_append_size += sizeof(struct mwifiex_ie_types_htinfo); } cmd->size = cpu_to_le16((u16)(sizeof(struct host_cmd_ds_802_11_ad_hoc_start) + S_DS_GEN + cmd_append_size)); if (adapter->adhoc_start_band == BAND_B) tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; else tmp_cap |= WLAN_CAPABILITY_SHORT_SLOT_TIME; adhoc_start->cap_info_bitmap = cpu_to_le16(tmp_cap); return 0; }
int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, struct mwifiex_bssdescriptor *bss_desc) { struct host_cmd_ds_802_11_associate *assoc = &cmd->params.associate; struct mwifiex_ie_types_ssid_param_set *ssid_tlv; struct mwifiex_ie_types_phy_param_set *phy_tlv; struct mwifiex_ie_types_ss_param_set *ss_tlv; struct mwifiex_ie_types_rates_param_set *rates_tlv; struct mwifiex_ie_types_auth_type *auth_tlv; struct mwifiex_ie_types_chan_list_param_set *chan_tlv; u8 rates[MWIFIEX_SUPPORTED_RATES]; u32 rates_size; u16 tmp_cap; u8 *pos; int rsn_ie_len = 0; pos = (u8 *) assoc; mwifiex_cfg_tx_buf(priv, bss_desc); cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE); priv->attempted_bss_desc = bss_desc; memcpy(assoc->peer_sta_addr, bss_desc->mac_address, sizeof(assoc->peer_sta_addr)); pos += sizeof(assoc->peer_sta_addr); assoc->listen_interval = cpu_to_le16(priv->listen_interval); assoc->beacon_period = cpu_to_le16(bss_desc->beacon_period); pos += sizeof(assoc->cap_info_bitmap); pos += sizeof(assoc->listen_interval); pos += sizeof(assoc->beacon_period); pos += sizeof(assoc->dtim_period); ssid_tlv = (struct mwifiex_ie_types_ssid_param_set *) pos; ssid_tlv->header.type = cpu_to_le16(WLAN_EID_SSID); ssid_tlv->header.len = cpu_to_le16((u16) bss_desc->ssid.ssid_len); memcpy(ssid_tlv->ssid, bss_desc->ssid.ssid, le16_to_cpu(ssid_tlv->header.len)); pos += sizeof(ssid_tlv->header) + le16_to_cpu(ssid_tlv->header.len); phy_tlv = (struct mwifiex_ie_types_phy_param_set *) pos; phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS); phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set)); memcpy(&phy_tlv->fh_ds.ds_param_set, &bss_desc->phy_param_set.ds_param_set.current_chan, sizeof(phy_tlv->fh_ds.ds_param_set)); pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len); ss_tlv = (struct mwifiex_ie_types_ss_param_set *) pos; ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS); ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set)); pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len); if (mwifiex_setup_rates_from_bssdesc (priv, bss_desc, rates, &rates_size)) return -1; priv->curr_bss_params.num_of_rates = rates_size; memcpy(&priv->curr_bss_params.data_rates, rates, rates_size); rates_tlv = (struct mwifiex_ie_types_rates_param_set *) pos; rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); rates_tlv->header.len = cpu_to_le16((u16) rates_size); memcpy(rates_tlv->rates, rates, rates_size); pos += sizeof(rates_tlv->header) + rates_size; dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: rates size = %d\n", rates_size); auth_tlv = (struct mwifiex_ie_types_auth_type *) pos; auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type)); if (priv->sec_info.wep_enabled) auth_tlv->auth_type = cpu_to_le16( (u16) priv->sec_info.authentication_mode); else auth_tlv->auth_type = cpu_to_le16(NL80211_AUTHTYPE_OPEN_SYSTEM); pos += sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len); if (IS_SUPPORT_MULTI_BANDS(priv->adapter) && !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info) && (!bss_desc->disable_11n) && (priv->adapter->config_bands & BAND_GN || priv->adapter->config_bands & BAND_AN) && (bss_desc->bcn_ht_cap) ) ) { chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); chan_tlv->header.len = cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); memset(chan_tlv->chan_scan_param, 0x00, sizeof(struct mwifiex_chan_scan_param_set)); chan_tlv->chan_scan_param[0].chan_number = (bss_desc->phy_param_set.ds_param_set.current_chan); dev_dbg(priv->adapter->dev, "info: Assoc: TLV Chan = %d\n", chan_tlv->chan_scan_param[0].chan_number); chan_tlv->chan_scan_param[0].radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); dev_dbg(priv->adapter->dev, "info: Assoc: TLV Band = %d\n", chan_tlv->chan_scan_param[0].radio_type); pos += sizeof(chan_tlv->header) + sizeof(struct mwifiex_chan_scan_param_set); } if (!priv->wps.session_enable) { if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); if (rsn_ie_len == -1) return -1; } if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) && (!bss_desc->disable_11n) && (priv->adapter->config_bands & BAND_GN || priv->adapter->config_bands & BAND_AN)) mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos); mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos); mwifiex_wmm_process_association_req(priv, &pos, &bss_desc->wmm_ie, bss_desc->bcn_ht_cap); if (priv->sec_info.wapi_enabled && priv->wapi_ie_len) mwifiex_cmd_append_wapi_ie(priv, &pos); mwifiex_cmd_append_generic_ie(priv, &pos); mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc); cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN); tmp_cap = bss_desc->cap_info_bitmap; if (priv->adapter->config_bands == BAND_B) tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; tmp_cap &= CAPINFO_MASK; dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", tmp_cap, CAPINFO_MASK); assoc->cap_info_bitmap = cpu_to_le16(tmp_cap); return 0; }