/* * This function prepares the correct firmware command and * issues it to set the multicast list. * * This function can be used to enable promiscuous mode, or enable all * multicast packets, or to enable selective multicast. */ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, struct mwifiex_multicast_list *mcast_list) { int ret = 0; u16 old_pkt_filter; old_pkt_filter = priv->curr_pkt_filter; if (mcast_list->mode == MWIFIEX_PROMISC_MODE) { dev_dbg(priv->adapter->dev, "info: Enable Promiscuous mode\n"); priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; } else { /* Multicast */ priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; if (mcast_list->mode == MWIFIEX_MULTICAST_MODE) { dev_dbg(priv->adapter->dev, "info: Enabling All Multicast!\n"); priv->curr_pkt_filter |= HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; } else { priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; if (mcast_list->num_multicast_addr) { dev_dbg(priv->adapter->dev, "info: Set multicast list=%d\n", mcast_list->num_multicast_addr); /* Set multicast addresses to firmware */ if (old_pkt_filter == priv->curr_pkt_filter) { /* Send request to firmware */ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_MULTICAST_ADR, HostCmd_ACT_GEN_SET, 0, mcast_list); } else { /* Send request to firmware */ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_MULTICAST_ADR, HostCmd_ACT_GEN_SET, 0, mcast_list); } } } } dev_dbg(priv->adapter->dev, "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n", old_pkt_filter, priv->curr_pkt_filter); if (old_pkt_filter != priv->curr_pkt_filter) { ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, HostCmd_ACT_GEN_SET, 0, &priv->curr_pkt_filter); } return ret; }
/* * IOCTL request handler to set WPA key. * * This function prepares the correct firmware command and * issues it, after validation checks. * * Current driver only supports key length of up to 32 bytes. * * This function can also be used to disable a currently set key. */ static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv, struct mwifiex_ds_encrypt_key *encrypt_key) { int ret; u8 remove_key = false; struct host_cmd_ds_802_11_key_material *ibss_key; /* Current driver only supports key length of up to 32 bytes */ if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) { dev_err(priv->adapter->dev, "key length too long\n"); return -1; } if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { /* * IBSS/WPA-None uses only one key (Group) for both receiving * and sending unicast and multicast packets. */ /* Send the key as PTK to firmware */ encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_KEY_MATERIAL, HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, encrypt_key); if (ret) return ret; ibss_key = &priv->aes_key; memset(ibss_key, 0, sizeof(struct host_cmd_ds_802_11_key_material)); /* Copy the key in the driver */ memcpy(ibss_key->key_param_set.key, encrypt_key->key_material, encrypt_key->key_len); memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len, sizeof(ibss_key->key_param_set.key_len)); ibss_key->key_param_set.key_type_id = cpu_to_le16(KEY_TYPE_ID_TKIP); ibss_key->key_param_set.key_info = cpu_to_le16(KEY_ENABLED); /* Send the key as GTK to firmware */ encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST; } if (!encrypt_key->key_index) encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; if (remove_key) ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_KEY_MATERIAL, HostCmd_ACT_GEN_SET, !(KEY_INFO_ENABLED), encrypt_key); else ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_KEY_MATERIAL, HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, encrypt_key); return ret; }
static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv, struct mwifiex_ds_encrypt_key *encrypt_key) { int ret; u8 remove_key = false; struct host_cmd_ds_802_11_key_material *ibss_key; if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) { dev_err(priv->adapter->dev, "key length too long\n"); return -1; } if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_KEY_MATERIAL, HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, encrypt_key); if (ret) return ret; ibss_key = &priv->aes_key; memset(ibss_key, 0, sizeof(struct host_cmd_ds_802_11_key_material)); memcpy(ibss_key->key_param_set.key, encrypt_key->key_material, encrypt_key->key_len); memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len, sizeof(ibss_key->key_param_set.key_len)); ibss_key->key_param_set.key_type_id = cpu_to_le16(KEY_TYPE_ID_TKIP); ibss_key->key_param_set.key_info = cpu_to_le16(KEY_ENABLED); encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST; } if (!encrypt_key->key_index) encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; if (remove_key) ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_KEY_MATERIAL, HostCmd_ACT_GEN_SET, !KEY_INFO_ENABLED, encrypt_key); else ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_KEY_MATERIAL, HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, encrypt_key); return ret; }
static int mwifiex_process_country_ie(struct mwifiex_private *priv, struct cfg80211_bss *bss) { const u8 *country_ie; u8 country_ie_len; struct mwifiex_802_11d_domain_reg *domain_info = &priv->adapter->domain_reg; rcu_read_lock(); country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); if (!country_ie) { rcu_read_unlock(); return 0; } country_ie_len = country_ie[1]; if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) { rcu_read_unlock(); return 0; } if (!strncmp(priv->adapter->country_code, &country_ie[2], 2)) { rcu_read_unlock(); wiphy_dbg(priv->wdev->wiphy, "11D: skip setting domain info in FW\n"); return 0; } memcpy(priv->adapter->country_code, &country_ie[2], 2); domain_info->country_code[0] = country_ie[2]; domain_info->country_code[1] = country_ie[3]; domain_info->country_code[2] = ' '; country_ie_len -= IEEE80211_COUNTRY_STRING_LEN; domain_info->no_of_triplet = country_ie_len / sizeof(struct ieee80211_country_ie_triplet); memcpy((u8 *)domain_info->triplet, &country_ie[2] + IEEE80211_COUNTRY_STRING_LEN, country_ie_len); rcu_read_unlock(); if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, HostCmd_ACT_GEN_SET, 0, NULL)) { wiphy_err(priv->adapter->wiphy, "11D: setting domain info in FW\n"); return -1; } mwifiex_dnld_txpwr_table(priv); return 0; }
/* * IOCTL request handler to set WEP network key. * * This function prepares the correct firmware command and * issues it, after validation checks. */ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, struct mwifiex_ds_encrypt_key *encrypt_key) { int ret; struct mwifiex_wep_key *wep_key; int index; if (priv->wep_key_curr_index >= NUM_WEP_KEYS) priv->wep_key_curr_index = 0; wep_key = &priv->wep_key[priv->wep_key_curr_index]; index = encrypt_key->key_index; if (encrypt_key->key_disable) { priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED; } else if (!encrypt_key->key_len) { /* Copy the required key as the current key */ wep_key = &priv->wep_key[index]; if (!wep_key->key_length) { dev_err(priv->adapter->dev, "key not set, so cannot enable it\n"); return -1; } priv->wep_key_curr_index = (u16) index; priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED; } else { wep_key = &priv->wep_key[index]; memset(wep_key, 0, sizeof(struct mwifiex_wep_key)); /* Copy the key in the driver */ memcpy(wep_key->key_material, encrypt_key->key_material, encrypt_key->key_len); wep_key->key_index = index; wep_key->key_length = encrypt_key->key_len; priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED; } if (wep_key->key_length) { /* Send request to firmware */ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_KEY_MATERIAL, HostCmd_ACT_GEN_SET, 0, NULL); if (ret) return ret; } if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; else priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL, HostCmd_ACT_GEN_SET, 0, &priv->curr_pkt_filter); return ret; }
static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, struct mwifiex_ds_encrypt_key *encrypt_key) { int ret; struct mwifiex_wep_key *wep_key; int index; if (priv->wep_key_curr_index >= NUM_WEP_KEYS) priv->wep_key_curr_index = 0; wep_key = &priv->wep_key[priv->wep_key_curr_index]; index = encrypt_key->key_index; if (encrypt_key->key_disable) { priv->sec_info.wep_enabled = 0; } else if (!encrypt_key->key_len) { wep_key = &priv->wep_key[index]; if (!wep_key->key_length) { dev_err(priv->adapter->dev, "key not set, so cannot enable it\n"); return -1; } priv->wep_key_curr_index = (u16) index; priv->sec_info.wep_enabled = 1; } else { wep_key = &priv->wep_key[index]; memset(wep_key, 0, sizeof(struct mwifiex_wep_key)); memcpy(wep_key->key_material, encrypt_key->key_material, encrypt_key->key_len); wep_key->key_index = index; wep_key->key_length = encrypt_key->key_len; priv->sec_info.wep_enabled = 1; } if (wep_key->key_length) { ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_KEY_MATERIAL, HostCmd_ACT_GEN_SET, 0, NULL); if (ret) return ret; } if (priv->sec_info.wep_enabled) priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; else priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL, HostCmd_ACT_GEN_SET, 0, &priv->curr_pkt_filter); return ret; }
/* * IOCTL request handler to get power save mode. * * This function prepares the correct firmware command and * issues it. */ int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode) { int ret; struct mwifiex_adapter *adapter = priv->adapter; u16 sub_cmd; if (*ps_mode) adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; else adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS; ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_PS_MODE_ENH, sub_cmd, BITMAP_STA_PS, NULL); if ((!ret) && (sub_cmd == DIS_AUTO_PS)) ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS, 0, NULL); return ret; }
static int mwifiex_process_country_ie(struct mwifiex_private *priv, struct cfg80211_bss *bss) { u8 *country_ie, country_ie_len; struct mwifiex_802_11d_domain_reg *domain_info = &priv->adapter->domain_reg; country_ie = (u8 *)ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); if (!country_ie) return 0; country_ie_len = country_ie[1]; if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) return 0; domain_info->country_code[0] = country_ie[2]; domain_info->country_code[1] = country_ie[3]; domain_info->country_code[2] = ' '; country_ie_len -= IEEE80211_COUNTRY_STRING_LEN; domain_info->no_of_triplet = country_ie_len / sizeof(struct ieee80211_country_ie_triplet); memcpy((u8 *)domain_info->triplet, &country_ie[2] + IEEE80211_COUNTRY_STRING_LEN, country_ie_len); if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, HostCmd_ACT_GEN_SET, 0, NULL)) { wiphy_err(priv->adapter->wiphy, "11D: setting domain info in FW\n"); return -1; } return 0; }
/* * 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 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; }
/* cfg80211 operation handler for start_ap. * Function sets beacon period, DTIM period, SSID and security into * AP config structure. * AP is configured with these settings and BSS is started. */ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *params) { struct mwifiex_uap_bss_param *bss_cfg; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) return -1; if (mwifiex_set_mgmt_ies(priv, params)) return -1; bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); if (!bss_cfg) return -ENOMEM; mwifiex_set_sys_config_invalid_data(bss_cfg); if (params->beacon_interval) bss_cfg->beacon_period = params->beacon_interval; if (params->dtim_period) bss_cfg->dtim_period = params->dtim_period; if (params->ssid && params->ssid_len) { memcpy(bss_cfg->ssid.ssid, params->ssid, params->ssid_len); bss_cfg->ssid.ssid_len = params->ssid_len; } switch (params->hidden_ssid) { case NL80211_HIDDEN_SSID_NOT_IN_USE: bss_cfg->bcast_ssid_ctl = 1; break; case NL80211_HIDDEN_SSID_ZERO_LEN: bss_cfg->bcast_ssid_ctl = 0; break; case NL80211_HIDDEN_SSID_ZERO_CONTENTS: /* firmware doesn't support this type of hidden SSID */ default: kfree(bss_cfg); return -EINVAL; } if (mwifiex_set_secure_params(priv, bss_cfg, params)) { kfree(bss_cfg); wiphy_err(wiphy, "Failed to parse secuirty parameters!\n"); return -1; } if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP, HostCmd_ACT_GEN_SET, 0, NULL)) { wiphy_err(wiphy, "Failed to stop the BSS\n"); kfree(bss_cfg); return -1; } if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG, HostCmd_ACT_GEN_SET, UAP_BSS_PARAMS_I, bss_cfg)) { wiphy_err(wiphy, "Failed to set the SSID\n"); kfree(bss_cfg); return -1; } kfree(bss_cfg); if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_BSS_START, HostCmd_ACT_GEN_SET, 0, NULL)) { wiphy_err(wiphy, "Failed to start the BSS\n"); return -1; } return 0; }
/* * CFG802.11 operation handler to set wiphy parameters. * * This function can be used to set the RTS threshold and the * Fragmentation threshold of the driver. */ static int mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) { struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_private *priv; struct mwifiex_uap_bss_param *bss_cfg; int ret, bss_started, i; for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; switch (priv->bss_role) { case MWIFIEX_BSS_ROLE_UAP: bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); if (!bss_cfg) return -ENOMEM; mwifiex_set_sys_config_invalid_data(bss_cfg); if (changed & WIPHY_PARAM_RTS_THRESHOLD) bss_cfg->rts_threshold = wiphy->rts_threshold; if (changed & WIPHY_PARAM_FRAG_THRESHOLD) bss_cfg->frag_threshold = wiphy->frag_threshold; if (changed & WIPHY_PARAM_RETRY_LONG) bss_cfg->retry_limit = wiphy->retry_long; bss_started = priv->bss_started; ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP, HostCmd_ACT_GEN_SET, 0, NULL); if (ret) { wiphy_err(wiphy, "Failed to stop the BSS\n"); kfree(bss_cfg); return ret; } ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG, HostCmd_ACT_GEN_SET, UAP_BSS_PARAMS_I, bss_cfg); kfree(bss_cfg); if (ret) { wiphy_err(wiphy, "Failed to set bss config\n"); return ret; } if (!bss_started) break; ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_BSS_START, HostCmd_ACT_GEN_SET, 0, NULL); if (ret) { wiphy_err(wiphy, "Failed to start BSS\n"); return ret; } break; case MWIFIEX_BSS_ROLE_STA: if (changed & WIPHY_PARAM_RTS_THRESHOLD) { ret = mwifiex_set_rts(priv, wiphy->rts_threshold); if (ret) return ret; } if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { ret = mwifiex_set_frag(priv, wiphy->frag_threshold); if (ret) return ret; } break; } } return 0; }
/* * This function handles events generated by firmware. * * This is a generic function and handles all events. * * Event specific routines are called by this function based * upon the generated event cause. * * For the following events, the function just forwards them to upper * layers, optionally recording the change - * - EVENT_LINK_SENSED * - EVENT_MIC_ERR_UNICAST * - EVENT_MIC_ERR_MULTICAST * - EVENT_PORT_RELEASE * - EVENT_RSSI_LOW * - EVENT_SNR_LOW * - EVENT_MAX_FAIL * - EVENT_RSSI_HIGH * - EVENT_SNR_HIGH * - EVENT_DATA_RSSI_LOW * - EVENT_DATA_SNR_LOW * - EVENT_DATA_RSSI_HIGH * - EVENT_DATA_SNR_HIGH * - EVENT_LINK_QUALITY * - EVENT_PRE_BEACON_LOST * - EVENT_IBSS_COALESCED * - EVENT_WEP_ICV_ERR * - EVENT_BW_CHANGE * - EVENT_HOSTWAKE_STAIE * * For the following events, no action is taken - * - EVENT_MIB_CHANGED * - EVENT_INIT_DONE * - EVENT_DUMMY_HOST_WAKEUP_SIGNAL * * Rest of the supported events requires driver handling - * - EVENT_DEAUTHENTICATED * - EVENT_DISASSOCIATED * - EVENT_LINK_LOST * - EVENT_PS_SLEEP * - EVENT_PS_AWAKE * - EVENT_DEEP_SLEEP_AWAKE * - EVENT_HS_ACT_REQ * - EVENT_ADHOC_BCN_LOST * - EVENT_BG_SCAN_REPORT * - EVENT_WMM_STATUS_CHANGE * - EVENT_ADDBA * - EVENT_DELBA * - EVENT_BA_STREAM_TIEMOUT * - EVENT_AMSDU_AGGR_CTRL */ int mwifiex_process_sta_event(struct mwifiex_private *priv) { struct mwifiex_adapter *adapter = priv->adapter; int ret = 0; u32 eventcause = adapter->event_cause; switch (eventcause) { case EVENT_DUMMY_HOST_WAKEUP_SIGNAL: dev_err(adapter->dev, "invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL," " ignoring it\n"); break; case EVENT_LINK_SENSED: dev_dbg(adapter->dev, "event: LINK_SENSED\n"); if (!netif_carrier_ok(priv->netdev)) netif_carrier_on(priv->netdev); if (netif_queue_stopped(priv->netdev)) mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); break; case EVENT_DEAUTHENTICATED: dev_dbg(adapter->dev, "event: Deauthenticated\n"); adapter->dbg.num_event_deauth++; if (priv->media_connected) mwifiex_reset_connect_state(priv); break; case EVENT_DISASSOCIATED: dev_dbg(adapter->dev, "event: Disassociated\n"); adapter->dbg.num_event_disassoc++; if (priv->media_connected) mwifiex_reset_connect_state(priv); break; case EVENT_LINK_LOST: dev_dbg(adapter->dev, "event: Link lost\n"); adapter->dbg.num_event_link_lost++; if (priv->media_connected) mwifiex_reset_connect_state(priv); break; case EVENT_PS_SLEEP: dev_dbg(adapter->dev, "info: EVENT: SLEEP\n"); adapter->ps_state = PS_STATE_PRE_SLEEP; mwifiex_check_ps_cond(adapter); break; case EVENT_PS_AWAKE: dev_dbg(adapter->dev, "info: EVENT: AWAKE\n"); if (!adapter->pps_uapsd_mode && priv->media_connected && adapter->sleep_period.period) { adapter->pps_uapsd_mode = true; dev_dbg(adapter->dev, "event: PPS/UAPSD mode activated\n"); } adapter->tx_lock_flag = false; if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) { if (mwifiex_check_last_packet_indication(priv)) { if (!adapter->data_sent) { if (!mwifiex_send_null_packet(priv, MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET | MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) adapter->ps_state = PS_STATE_SLEEP; return 0; } } } adapter->ps_state = PS_STATE_AWAKE; adapter->pm_wakeup_card_req = false; adapter->pm_wakeup_fw_try = false; break; case EVENT_DEEP_SLEEP_AWAKE: adapter->if_ops.wakeup_complete(adapter); dev_dbg(adapter->dev, "event: DS_AWAKE\n"); if (adapter->is_deep_sleep) adapter->is_deep_sleep = false; break; case EVENT_HS_ACT_REQ: dev_dbg(adapter->dev, "event: HS_ACT_REQ\n"); ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_HS_CFG_ENH, 0, 0, NULL); break; case EVENT_MIC_ERR_UNICAST: dev_dbg(adapter->dev, "event: UNICAST MIC ERROR\n"); break; case EVENT_MIC_ERR_MULTICAST: dev_dbg(adapter->dev, "event: MULTICAST MIC ERROR\n"); break; case EVENT_MIB_CHANGED: case EVENT_INIT_DONE: break; case EVENT_ADHOC_BCN_LOST: dev_dbg(adapter->dev, "event: ADHOC_BCN_LOST\n"); priv->adhoc_is_link_sensed = false; mwifiex_clean_txrx(priv); if (!netif_queue_stopped(priv->netdev)) mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); break; case EVENT_BG_SCAN_REPORT: dev_dbg(adapter->dev, "event: BGS_REPORT\n"); ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_BG_SCAN_QUERY, HostCmd_ACT_GEN_GET, 0, NULL); break; case EVENT_PORT_RELEASE: dev_dbg(adapter->dev, "event: PORT RELEASE\n"); break; case EVENT_WMM_STATUS_CHANGE: dev_dbg(adapter->dev, "event: WMM status changed\n"); ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_WMM_GET_STATUS, 0, 0, NULL); break; case EVENT_RSSI_LOW: dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n"); break; case EVENT_SNR_LOW: dev_dbg(adapter->dev, "event: Beacon SNR_LOW\n"); break; case EVENT_MAX_FAIL: dev_dbg(adapter->dev, "event: MAX_FAIL\n"); break; case EVENT_RSSI_HIGH: dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n"); break; case EVENT_SNR_HIGH: dev_dbg(adapter->dev, "event: Beacon SNR_HIGH\n"); break; case EVENT_DATA_RSSI_LOW: dev_dbg(adapter->dev, "event: Data RSSI_LOW\n"); break; case EVENT_DATA_SNR_LOW: dev_dbg(adapter->dev, "event: Data SNR_LOW\n"); break; case EVENT_DATA_RSSI_HIGH: dev_dbg(adapter->dev, "event: Data RSSI_HIGH\n"); break; case EVENT_DATA_SNR_HIGH: dev_dbg(adapter->dev, "event: Data SNR_HIGH\n"); break; case EVENT_LINK_QUALITY: dev_dbg(adapter->dev, "event: Link Quality\n"); break; case EVENT_PRE_BEACON_LOST: dev_dbg(adapter->dev, "event: Pre-Beacon Lost\n"); break; case EVENT_IBSS_COALESCED: dev_dbg(adapter->dev, "event: IBSS_COALESCED\n"); ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, HostCmd_ACT_GEN_GET, 0, NULL); break; case EVENT_ADDBA: dev_dbg(adapter->dev, "event: ADDBA Request\n"); mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP, HostCmd_ACT_GEN_SET, 0, adapter->event_body); break; case EVENT_DELBA: dev_dbg(adapter->dev, "event: DELBA Request\n"); mwifiex_11n_delete_ba_stream(priv, adapter->event_body); break; case EVENT_BA_STREAM_TIEMOUT: dev_dbg(adapter->dev, "event: BA Stream timeout\n"); mwifiex_11n_ba_stream_timeout(priv, (struct host_cmd_ds_11n_batimeout *) adapter->event_body); break; case EVENT_AMSDU_AGGR_CTRL: dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", *(u16 *) adapter->event_body); adapter->tx_buf_size = min(adapter->curr_tx_buf_size, le16_to_cpu(*(__le16 *) adapter->event_body)); dev_dbg(adapter->dev, "event: tx_buf_size %d\n", adapter->tx_buf_size); break; case EVENT_WEP_ICV_ERR: dev_dbg(adapter->dev, "event: WEP ICV error\n"); break; case EVENT_BW_CHANGE: dev_dbg(adapter->dev, "event: BW Change\n"); break; case EVENT_HOSTWAKE_STAIE: dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause); break; default: dev_dbg(adapter->dev, "event: unknown event id: %#x\n", eventcause); break; } return ret; }
/* * This function issues commands to initialize firmware. * * This is called after firmware download to bring the card to * working state. * * The following commands are issued sequentially - * - Function init (for first interface only) * - Read MAC address (for first interface only) * - Reconfigure Tx buffer size (for first interface only) * - Enable auto deep sleep (for first interface only) * - Get Tx rate * - Get Tx power * - Set IBSS coalescing status * - Set AMSDU aggregation control * - Set 11d control * - Set MAC control (this must be the last command to initialize firmware) */ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) { int ret; u16 enable = true; struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl; struct mwifiex_ds_auto_ds auto_ds; enum state_11d_t state_11d; struct mwifiex_ds_11n_tx_cfg tx_cfg; if (first_sta) { ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_FUNC_INIT, HostCmd_ACT_GEN_SET, 0, NULL); if (ret) return -1; /* Read MAC address from HW */ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_GET_HW_SPEC, HostCmd_ACT_GEN_GET, 0, NULL); if (ret) return -1; /* Reconfigure tx buf size */ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, HostCmd_ACT_GEN_SET, 0, &priv->adapter->tx_buf_size); if (ret) return -1; /* Enable IEEE PS by default */ priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_PS_MODE_ENH, EN_AUTO_PS, BITMAP_STA_PS, NULL); if (ret) return -1; } /* get tx rate */ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TX_RATE_CFG, HostCmd_ACT_GEN_GET, 0, NULL); if (ret) return -1; priv->data_rate = 0; /* get tx power */ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TXPWR_CFG, HostCmd_ACT_GEN_GET, 0, NULL); if (ret) return -1; /* set ibss coalescing_status */ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, HostCmd_ACT_GEN_SET, 0, &enable); if (ret) return -1; memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl)); amsdu_aggr_ctrl.enable = true; /* Send request to firmware */ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_AMSDU_AGGR_CTRL, HostCmd_ACT_GEN_SET, 0, &amsdu_aggr_ctrl); if (ret) return -1; /* MAC Control must be the last command in init_fw */ /* set MAC Control */ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, HostCmd_ACT_GEN_SET, 0, &priv->curr_pkt_filter); if (ret) return -1; if (first_sta) { /* Enable auto deep sleep */ auto_ds.auto_ds = DEEP_SLEEP_ON; auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME; ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_PS_MODE_ENH, EN_AUTO_PS, BITMAP_AUTO_DS, &auto_ds); if (ret) return -1; } /* Send cmd to FW to enable/disable 11D function */ state_11d = ENABLE_11D; ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB, HostCmd_ACT_GEN_SET, DOT11D_I, &state_11d); if (ret) dev_err(priv->adapter->dev, "11D: failed to enable 11D\n"); /* Send cmd to FW to configure 11n specific configuration * (Short GI, Channel BW, Green field support etc.) for transmit */ tx_cfg.tx_htcap = MWIFIEX_FW_DEF_HTTXCFG; ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_CFG, HostCmd_ACT_GEN_SET, 0, &tx_cfg); /* set last_init_cmd */ priv->adapter->last_init_cmd = HostCmd_CMD_11N_CFG; ret = -EINPROGRESS; return ret; }
/* * IOCTL request handler to set WEP network key. * * This function prepares the correct firmware command and * issues it, after validation checks. */ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, struct mwifiex_ds_encrypt_key *encrypt_key) { struct mwifiex_adapter *adapter = priv->adapter; int ret; struct mwifiex_wep_key *wep_key; int index; if (priv->wep_key_curr_index >= NUM_WEP_KEYS) priv->wep_key_curr_index = 0; wep_key = &priv->wep_key[priv->wep_key_curr_index]; index = encrypt_key->key_index; if (encrypt_key->key_disable) { priv->sec_info.wep_enabled = 0; } else if (!encrypt_key->key_len) { /* Copy the required key as the current key */ wep_key = &priv->wep_key[index]; if (!wep_key->key_length) { dev_err(adapter->dev, "key not set, so cannot enable it\n"); return -1; } if (adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2) { memcpy(encrypt_key->key_material, wep_key->key_material, wep_key->key_length); encrypt_key->key_len = wep_key->key_length; } priv->wep_key_curr_index = (u16) index; priv->sec_info.wep_enabled = 1; } else { wep_key = &priv->wep_key[index]; memset(wep_key, 0, sizeof(struct mwifiex_wep_key)); /* Copy the key in the driver */ memcpy(wep_key->key_material, encrypt_key->key_material, encrypt_key->key_len); wep_key->key_index = index; wep_key->key_length = encrypt_key->key_len; priv->sec_info.wep_enabled = 1; } if (wep_key->key_length) { void *enc_key; if (encrypt_key->key_disable) memset(&priv->wep_key[index], 0, sizeof(struct mwifiex_wep_key)); if (adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2) enc_key = encrypt_key; else enc_key = NULL; /* Send request to firmware */ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_KEY_MATERIAL, HostCmd_ACT_GEN_SET, 0, enc_key); if (ret) return ret; } if (priv->sec_info.wep_enabled) priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; else priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL, HostCmd_ACT_GEN_SET, 0, &priv->curr_pkt_filter); return ret; }
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; }
/* * IOCTL request handler to set host sleep configuration. * * This function prepares the correct firmware command and * issues it. */ int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg) { struct mwifiex_adapter *adapter = priv->adapter; int status = 0; u32 prev_cond = 0; if (!hs_cfg) return -ENOMEM; switch (action) { case HostCmd_ACT_GEN_SET: if (adapter->pps_uapsd_mode) { dev_dbg(adapter->dev, "info: Host Sleep IOCTL" " is blocked in UAPSD/PPS mode\n"); status = -1; break; } if (hs_cfg->is_invoke_hostcmd) { if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) { if (!adapter->is_hs_configured) /* Already cancelled */ break; /* Save previous condition */ prev_cond = le32_to_cpu(adapter->hs_cfg .conditions); adapter->hs_cfg.conditions = cpu_to_le32(hs_cfg->conditions); } else if (hs_cfg->conditions) { adapter->hs_cfg.conditions = cpu_to_le32(hs_cfg->conditions); adapter->hs_cfg.gpio = (u8)hs_cfg->gpio; if (hs_cfg->gap) adapter->hs_cfg.gap = (u8)hs_cfg->gap; } else if (adapter->hs_cfg.conditions == cpu_to_le32( HOST_SLEEP_CFG_CANCEL)) { /* Return failure if no parameters for HS enable */ status = -1; break; } if (cmd_type == MWIFIEX_SYNC_CMD) status = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_HS_CFG_ENH, HostCmd_ACT_GEN_SET, 0, &adapter->hs_cfg); else status = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_HS_CFG_ENH, HostCmd_ACT_GEN_SET, 0, &adapter->hs_cfg); if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) /* Restore previous condition */ adapter->hs_cfg.conditions = cpu_to_le32(prev_cond); } else { adapter->hs_cfg.conditions = cpu_to_le32(hs_cfg->conditions); adapter->hs_cfg.gpio = (u8)hs_cfg->gpio; adapter->hs_cfg.gap = (u8)hs_cfg->gap; } break; case HostCmd_ACT_GEN_GET: hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions); hs_cfg->gpio = adapter->hs_cfg.gpio; hs_cfg->gap = adapter->hs_cfg.gap; break; default: status = -1; break; } return status; }
/* * This function handles events generated by firmware. * * This is a generic function and handles all events. * * Event specific routines are called by this function based * upon the generated event cause. * * For the following events, the function just forwards them to upper * layers, optionally recording the change - * - EVENT_LINK_SENSED * - EVENT_MIC_ERR_UNICAST * - EVENT_MIC_ERR_MULTICAST * - EVENT_PORT_RELEASE * - EVENT_RSSI_LOW * - EVENT_SNR_LOW * - EVENT_MAX_FAIL * - EVENT_RSSI_HIGH * - EVENT_SNR_HIGH * - EVENT_DATA_RSSI_LOW * - EVENT_DATA_SNR_LOW * - EVENT_DATA_RSSI_HIGH * - EVENT_DATA_SNR_HIGH * - EVENT_LINK_QUALITY * - EVENT_PRE_BEACON_LOST * - EVENT_IBSS_COALESCED * - EVENT_WEP_ICV_ERR * - EVENT_BW_CHANGE * - EVENT_HOSTWAKE_STAIE * * For the following events, no action is taken - * - EVENT_MIB_CHANGED * - EVENT_INIT_DONE * - EVENT_DUMMY_HOST_WAKEUP_SIGNAL * * Rest of the supported events requires driver handling - * - EVENT_DEAUTHENTICATED * - EVENT_DISASSOCIATED * - EVENT_LINK_LOST * - EVENT_PS_SLEEP * - EVENT_PS_AWAKE * - EVENT_DEEP_SLEEP_AWAKE * - EVENT_HS_ACT_REQ * - EVENT_ADHOC_BCN_LOST * - EVENT_BG_SCAN_REPORT * - EVENT_WMM_STATUS_CHANGE * - EVENT_ADDBA * - EVENT_DELBA * - EVENT_BA_STREAM_TIEMOUT * - EVENT_AMSDU_AGGR_CTRL */ int mwifiex_process_sta_event(struct mwifiex_private *priv) { struct mwifiex_adapter *adapter = priv->adapter; int ret = 0; u32 eventcause = adapter->event_cause; u16 ctrl, reason_code; switch (eventcause) { case EVENT_DUMMY_HOST_WAKEUP_SIGNAL: dev_err(adapter->dev, "invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL, ignore it\n"); break; case EVENT_LINK_SENSED: dev_dbg(adapter->dev, "event: LINK_SENSED\n"); if (!netif_carrier_ok(priv->netdev)) netif_carrier_on(priv->netdev); mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); break; case EVENT_DEAUTHENTICATED: dev_dbg(adapter->dev, "event: Deauthenticated\n"); if (priv->wps.session_enable) { dev_dbg(adapter->dev, "info: receive deauth event in wps session\n"); break; } adapter->dbg.num_event_deauth++; if (priv->media_connected) { reason_code = le16_to_cpu(*(__le16 *)adapter->event_body); mwifiex_reset_connect_state(priv, reason_code); } break; case EVENT_DISASSOCIATED: dev_dbg(adapter->dev, "event: Disassociated\n"); if (priv->wps.session_enable) { dev_dbg(adapter->dev, "info: receive disassoc event in wps session\n"); break; } adapter->dbg.num_event_disassoc++; if (priv->media_connected) { reason_code = le16_to_cpu(*(__le16 *)adapter->event_body); mwifiex_reset_connect_state(priv, reason_code); } break; case EVENT_LINK_LOST: dev_dbg(adapter->dev, "event: Link lost\n"); adapter->dbg.num_event_link_lost++; if (priv->media_connected) { reason_code = le16_to_cpu(*(__le16 *)adapter->event_body); mwifiex_reset_connect_state(priv, reason_code); } break; case EVENT_PS_SLEEP: dev_dbg(adapter->dev, "info: EVENT: SLEEP\n"); adapter->ps_state = PS_STATE_PRE_SLEEP; mwifiex_check_ps_cond(adapter); break; case EVENT_PS_AWAKE: dev_dbg(adapter->dev, "info: EVENT: AWAKE\n"); if (!adapter->pps_uapsd_mode && priv->media_connected && adapter->sleep_period.period) { adapter->pps_uapsd_mode = true; dev_dbg(adapter->dev, "event: PPS/UAPSD mode activated\n"); } adapter->tx_lock_flag = false; if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) { if (mwifiex_check_last_packet_indication(priv)) { if (adapter->data_sent) { adapter->ps_state = PS_STATE_AWAKE; adapter->pm_wakeup_card_req = false; adapter->pm_wakeup_fw_try = false; break; } if (!mwifiex_send_null_packet (priv, MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET | MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) adapter->ps_state = PS_STATE_SLEEP; return 0; } } adapter->ps_state = PS_STATE_AWAKE; adapter->pm_wakeup_card_req = false; adapter->pm_wakeup_fw_try = false; break; case EVENT_DEEP_SLEEP_AWAKE: adapter->if_ops.wakeup_complete(adapter); dev_dbg(adapter->dev, "event: DS_AWAKE\n"); if (adapter->is_deep_sleep) adapter->is_deep_sleep = false; break; case EVENT_HS_ACT_REQ: dev_dbg(adapter->dev, "event: HS_ACT_REQ\n"); ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_HS_CFG_ENH, 0, 0, NULL); break; case EVENT_MIC_ERR_UNICAST: dev_dbg(adapter->dev, "event: UNICAST MIC ERROR\n"); cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid, NL80211_KEYTYPE_PAIRWISE, -1, NULL, GFP_KERNEL); break; case EVENT_MIC_ERR_MULTICAST: dev_dbg(adapter->dev, "event: MULTICAST MIC ERROR\n"); cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid, NL80211_KEYTYPE_GROUP, -1, NULL, GFP_KERNEL); break; case EVENT_MIB_CHANGED: case EVENT_INIT_DONE: break; case EVENT_ADHOC_BCN_LOST: dev_dbg(adapter->dev, "event: ADHOC_BCN_LOST\n"); priv->adhoc_is_link_sensed = false; mwifiex_clean_txrx(priv); mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); break; case EVENT_BG_SCAN_REPORT: dev_dbg(adapter->dev, "event: BGS_REPORT\n"); ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_BG_SCAN_QUERY, HostCmd_ACT_GEN_GET, 0, NULL); break; case EVENT_PORT_RELEASE: dev_dbg(adapter->dev, "event: PORT RELEASE\n"); break; case EVENT_WMM_STATUS_CHANGE: dev_dbg(adapter->dev, "event: WMM status changed\n"); ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_WMM_GET_STATUS, 0, 0, NULL); break; case EVENT_RSSI_LOW: cfg80211_cqm_rssi_notify(priv->netdev, NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, GFP_KERNEL); mwifiex_send_cmd_async(priv, HostCmd_CMD_RSSI_INFO, HostCmd_ACT_GEN_GET, 0, NULL); priv->subsc_evt_rssi_state = RSSI_LOW_RECVD; dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n"); break; case EVENT_SNR_LOW: dev_dbg(adapter->dev, "event: Beacon SNR_LOW\n"); break; case EVENT_MAX_FAIL: dev_dbg(adapter->dev, "event: MAX_FAIL\n"); break; case EVENT_RSSI_HIGH: cfg80211_cqm_rssi_notify(priv->netdev, NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, GFP_KERNEL); mwifiex_send_cmd_async(priv, HostCmd_CMD_RSSI_INFO, HostCmd_ACT_GEN_GET, 0, NULL); priv->subsc_evt_rssi_state = RSSI_HIGH_RECVD; dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n"); break; case EVENT_SNR_HIGH: dev_dbg(adapter->dev, "event: Beacon SNR_HIGH\n"); break; case EVENT_DATA_RSSI_LOW: dev_dbg(adapter->dev, "event: Data RSSI_LOW\n"); break; case EVENT_DATA_SNR_LOW: dev_dbg(adapter->dev, "event: Data SNR_LOW\n"); break; case EVENT_DATA_RSSI_HIGH: dev_dbg(adapter->dev, "event: Data RSSI_HIGH\n"); break; case EVENT_DATA_SNR_HIGH: dev_dbg(adapter->dev, "event: Data SNR_HIGH\n"); break; case EVENT_LINK_QUALITY: dev_dbg(adapter->dev, "event: Link Quality\n"); break; case EVENT_PRE_BEACON_LOST: dev_dbg(adapter->dev, "event: Pre-Beacon Lost\n"); break; case EVENT_IBSS_COALESCED: dev_dbg(adapter->dev, "event: IBSS_COALESCED\n"); ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, HostCmd_ACT_GEN_GET, 0, NULL); break; case EVENT_ADDBA: dev_dbg(adapter->dev, "event: ADDBA Request\n"); mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP, HostCmd_ACT_GEN_SET, 0, adapter->event_body); break; case EVENT_DELBA: dev_dbg(adapter->dev, "event: DELBA Request\n"); mwifiex_11n_delete_ba_stream(priv, adapter->event_body); break; case EVENT_BA_STREAM_TIEMOUT: dev_dbg(adapter->dev, "event: BA Stream timeout\n"); mwifiex_11n_ba_stream_timeout(priv, (struct host_cmd_ds_11n_batimeout *) adapter->event_body); break; case EVENT_AMSDU_AGGR_CTRL: ctrl = le16_to_cpu(*(__le16 *)adapter->event_body); dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", ctrl); adapter->tx_buf_size = min_t(u16, adapter->curr_tx_buf_size, ctrl); dev_dbg(adapter->dev, "event: tx_buf_size %d\n", adapter->tx_buf_size); break; case EVENT_WEP_ICV_ERR: dev_dbg(adapter->dev, "event: WEP ICV error\n"); break; case EVENT_BW_CHANGE: dev_dbg(adapter->dev, "event: BW Change\n"); break; case EVENT_HOSTWAKE_STAIE: dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause); break; case EVENT_REMAIN_ON_CHAN_EXPIRED: dev_dbg(adapter->dev, "event: Remain on channel expired\n"); cfg80211_remain_on_channel_expired(priv->wdev, priv->roc_cfg.cookie, &priv->roc_cfg.chan, GFP_ATOMIC); memset(&priv->roc_cfg, 0x00, sizeof(struct mwifiex_roc_cfg)); break; case EVENT_CHANNEL_SWITCH_ANN: dev_dbg(adapter->dev, "event: Channel Switch Announcement\n"); priv->csa_expire_time = jiffies + msecs_to_jiffies(DFS_CHAN_MOVE_TIME); priv->csa_chan = priv->curr_bss_params.bss_descriptor.channel; ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_DEAUTHENTICATE, HostCmd_ACT_GEN_SET, 0, priv->curr_bss_params.bss_descriptor.mac_address); break; default: dev_dbg(adapter->dev, "event: unknown event id: %#x\n", eventcause); break; } return ret; }
/* * 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; }
/* This function prepares IE data buffer for command to be sent to FW */ static int mwifiex_update_autoindex_ies(struct mwifiex_private *priv, struct mwifiex_ie_list *ie_list) { u16 travel_len, index, mask; s16 input_len; struct mwifiex_ie *ie; u8 *tmp; input_len = le16_to_cpu(ie_list->len); travel_len = sizeof(struct host_cmd_tlv); ie_list->len = 0; while (input_len > 0) { ie = (struct mwifiex_ie *)(((u8 *)ie_list) + travel_len); input_len -= le16_to_cpu(ie->ie_length) + MWIFIEX_IE_HDR_SIZE; travel_len += le16_to_cpu(ie->ie_length) + MWIFIEX_IE_HDR_SIZE; index = le16_to_cpu(ie->ie_index); mask = le16_to_cpu(ie->mgmt_subtype_mask); if (index == MWIFIEX_AUTO_IDX_MASK) { /* automatic addition */ if (mwifiex_ie_get_autoidx(priv, mask, ie, &index)) return -1; if (index == MWIFIEX_AUTO_IDX_MASK) return -1; tmp = (u8 *)&priv->mgmt_ie[index].ie_buffer; memcpy(tmp, &ie->ie_buffer, le16_to_cpu(ie->ie_length)); priv->mgmt_ie[index].ie_length = ie->ie_length; priv->mgmt_ie[index].ie_index = cpu_to_le16(index); priv->mgmt_ie[index].mgmt_subtype_mask = cpu_to_le16(mask); ie->ie_index = cpu_to_le16(index); } else { if (mask != MWIFIEX_DELETE_MASK) return -1; /* * Check if this index is being used on any * other interface. */ if (mwifiex_ie_index_used_by_other_intf(priv, index)) return -1; ie->ie_length = 0; memcpy(&priv->mgmt_ie[index], ie, sizeof(struct mwifiex_ie)); } le16_add_cpu(&ie_list->len, le16_to_cpu(priv->mgmt_ie[index].ie_length) + MWIFIEX_IE_HDR_SIZE); } if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) return mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG, HostCmd_ACT_GEN_SET, UAP_CUSTOM_IE_I, ie_list); return 0; }