/* This function parses WMM related parameters from cfg80211_ap_settings * structure and updates bss_config structure. */ void mwifiex_set_wmm_params(struct mwifiex_private *priv, struct mwifiex_uap_bss_param *bss_cfg, struct cfg80211_ap_settings *params) { const u8 *vendor_ie; struct ieee_types_header *wmm_ie; u8 wmm_oui[] = {0x00, 0x50, 0xf2, 0x02}; vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WMM, params->beacon.tail, params->beacon.tail_len); if (vendor_ie) { wmm_ie = (struct ieee_types_header *)vendor_ie; memcpy(&bss_cfg->wmm_info, wmm_ie + 1, sizeof(bss_cfg->wmm_info)); priv->wmm_enabled = 1; } else { memset(&bss_cfg->wmm_info, 0, sizeof(bss_cfg->wmm_info)); memcpy(&bss_cfg->wmm_info.oui, wmm_oui, sizeof(wmm_oui)); bss_cfg->wmm_info.subtype = MWIFIEX_WMM_SUBTYPE; bss_cfg->wmm_info.version = MWIFIEX_WMM_VERSION; priv->wmm_enabled = 0; } bss_cfg->qos_info = 0x00; return; }
/* This function checks if the vendor specified IE is present in passed buffer * and copies it to mwifiex_ie structure. * Function takes pointer to struct mwifiex_ie pointer as argument. * If the vendor specified IE is present then memory is allocated for * mwifiex_ie pointer and filled in with IE. Caller should take care of freeing * this memory. */ static int mwifiex_update_vs_ie(const u8 *ies, int ies_len, struct mwifiex_ie **ie_ptr, u16 mask, unsigned int oui, u8 oui_type) { struct ieee_types_header *vs_ie; struct mwifiex_ie *ie = *ie_ptr; const u8 *vendor_ie; vendor_ie = cfg80211_find_vendor_ie(oui, oui_type, ies, ies_len); if (vendor_ie) { if (!*ie_ptr) { *ie_ptr = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); if (!*ie_ptr) return -ENOMEM; ie = *ie_ptr; } vs_ie = (struct ieee_types_header *)vendor_ie; memcpy(ie->ie_buffer + le16_to_cpu(ie->ie_length), vs_ie, vs_ie->len + 2); le16_add_cpu(&ie->ie_length, vs_ie->len + 2); ie->mgmt_subtype_mask = cpu_to_le16(mask); ie->ie_index = cpu_to_le16(MWIFIEX_AUTO_IDX_MASK); } *ie_ptr = ie; return 0; }
/* This function parses different IEs-tail IEs, beacon IEs, probe response IEs, * association response IEs from cfg80211_ap_settings function and sets these IE * to FW. */ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, struct cfg80211_beacon_data *info) { struct mwifiex_ie *gen_ie; struct ieee_types_header *rsn_ie, *wpa_ie = NULL; u16 rsn_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0; const u8 *vendor_ie; if (info->tail && info->tail_len) { gen_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); if (!gen_ie) return -ENOMEM; gen_ie->ie_index = cpu_to_le16(rsn_idx); gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP | MGMT_MASK_ASSOC_RESP); rsn_ie = (void *)cfg80211_find_ie(WLAN_EID_RSN, info->tail, info->tail_len); if (rsn_ie) { memcpy(gen_ie->ie_buffer, rsn_ie, rsn_ie->len + 2); ie_len = rsn_ie->len + 2; gen_ie->ie_length = cpu_to_le16(ie_len); } vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WPA, info->tail, info->tail_len); if (vendor_ie) { wpa_ie = (struct ieee_types_header *)vendor_ie; memcpy(gen_ie->ie_buffer + ie_len, wpa_ie, wpa_ie->len + 2); ie_len += wpa_ie->len + 2; gen_ie->ie_length = cpu_to_le16(ie_len); } if (rsn_ie || wpa_ie) { if (mwifiex_update_uap_custom_ie(priv, gen_ie, &rsn_idx, NULL, NULL, NULL, NULL)) { kfree(gen_ie); return -1; } priv->rsn_idx = rsn_idx; } kfree(gen_ie); } return mwifiex_set_mgmt_beacon_data_ies(priv, info); }
BOOLEAN CFG80211_SyncPacketWmmIe(RTMP_ADAPTER *pAd, VOID *pData, ULONG dataLen) { const UINT WFA_OUI = 0x0050F2; const UCHAR WMM_OUI_TYPE = 0x2; UCHAR *wmm_ie = NULL; //hex_dump("probe_rsp_in:", pData, dataLen); #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) wmm_ie = (UCHAR *)cfg80211_find_vendor_ie(WFA_OUI, WMM_OUI_TYPE, pData, dataLen); #endif if (wmm_ie != NULL) { #ifdef RT_CFG80211_P2P_SUPPORT #ifdef UAPSD_SUPPORT if (pAd->ApCfg.MBSSID[CFG_GO_BSSID_IDX].wdev.UapsdInfo.bAPSDCapable == TRUE) { wmm_ie[8] |= 0x80; } #endif /* UAPSD_SUPPORT */ #endif /* RT_CFG80211_P2P_SUPPORT */ UINT i = QID_AC_BE; /* WMM: sync from driver's EDCA paramter */ for (i = QID_AC_BE; i <= QID_AC_VO; i++) { wmm_ie[10+ (i*4)] = (i << 5) + /* b5-6 is ACI */ ((UCHAR)pAd->ApCfg.BssEdcaParm.bACM[i] << 4) + /* b4 is ACM */ (pAd->ApCfg.BssEdcaParm.Aifsn[i] & 0x0f); /* b0-3 is AIFSN */ wmm_ie[11+ (i*4)] = (pAd->ApCfg.BssEdcaParm.Cwmax[i] << 4) + /* b5-8 is CWMAX */ (pAd->ApCfg.BssEdcaParm.Cwmin[i] & 0x0f); /* b0-3 is CWMIN */ wmm_ie[12+ (i*4)] = (UCHAR)(pAd->ApCfg.BssEdcaParm.Txop[i] & 0xff);/* low byte of TXOP */ wmm_ie[13+ (i*4)] = (UCHAR)(pAd->ApCfg.BssEdcaParm.Txop[i] >> 8); /* high byte of TXOP */ } return TRUE; } return FALSE; }
static INT CFG80211DRV_UpdateApSettingFromBeacon(PRTMP_ADAPTER pAd, UINT mbss_idx, CMD_RTPRIV_IOCTL_80211_BEACON *pBeacon) { PMULTISSID_STRUCT pMbss = &pAd->ApCfg.MBSSID[mbss_idx]; struct wifi_dev *wdev = &pMbss->wdev; const UCHAR *ssid_ie = NULL, *wpa_ie = NULL, *rsn_ie = NULL; const UINT WFA_OUI = 0x0050F2; const UCHAR WMM_OUI_TYPE = 0x2; UCHAR *wmm_ie = NULL; const UCHAR *supp_rates_ie = NULL; const UCHAR *ext_supp_rates_ie = NULL, *ht_cap = NULL, *ht_info = NULL; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)) const UCHAR CFG_HT_OP_EID = WLAN_EID_HT_OPERATION; #else const UCHAR CFG_HT_OP_EID = WLAN_EID_HT_INFORMATION; #endif /* LINUX_VERSION_CODE: 3.5.0 */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)) const UCHAR CFG_WPA_EID = WLAN_EID_VENDOR_SPECIFIC; #else const UCHAR CFG_WPA_EID = WLAN_EID_WPA; #endif /* LINUX_VERSION_CODE: 3.8.0 */ ssid_ie = cfg80211_find_ie(WLAN_EID_SSID, pBeacon->beacon_head+36, pBeacon->beacon_head_len-36); supp_rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, pBeacon->beacon_head+36, pBeacon->beacon_head_len-36); /* if it doesn't find WPA_IE in tail first 30 bytes. treat it as is not found */ wpa_ie = cfg80211_find_ie(CFG_WPA_EID, pBeacon->beacon_tail, pBeacon->beacon_tail_len); rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, pBeacon->beacon_tail, pBeacon->beacon_tail_len); wmm_ie = cfg80211_find_vendor_ie(WFA_OUI, WMM_OUI_TYPE, pBeacon->beacon_tail, pBeacon->beacon_tail_len); ht_cap = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, pBeacon->beacon_tail, pBeacon->beacon_tail_len); ht_info = cfg80211_find_ie(CFG_HT_OP_EID, pBeacon->beacon_tail, pBeacon->beacon_tail_len); /* SSID */ NdisZeroMemory(pMbss->Ssid, pMbss->SsidLen); if (ssid_ie == NULL) { NdisMoveMemory(pMbss->Ssid, "CFG_Linux_GO", 12); pMbss->SsidLen = 12; DBGPRINT(RT_DEBUG_ERROR,("CFG: SSID Not Found In Packet\n")); } else { pMbss->SsidLen = ssid_ie[1]; NdisCopyMemory(pMbss->Ssid, ssid_ie+2, pMbss->SsidLen); DBGPRINT(RT_DEBUG_TRACE,("CFG : SSID: %s, %d\n", pMbss->Ssid, pMbss->SsidLen)); } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)) if (pBeacon->hidden_ssid > 0 && pBeacon->hidden_ssid < 3) { pMbss->bHideSsid = TRUE; } else pMbss->bHideSsid = FALSE; if (pBeacon->hidden_ssid == 1) pMbss->SsidLen = 0; #endif /* LINUX_VERSION_CODE 3.4.0 */ /* WMM EDCA Paramter */ CFG80211_SyncPacketWmmIe(pAd, pBeacon->beacon_tail, pBeacon->beacon_tail_len); /* Security */ CFG80211_ParseBeaconIE(pAd, pMbss, wdev, wpa_ie, rsn_ie); pMbss->CapabilityInfo = CAP_GENERATE(1, 0, (wdev->WepStatus != Ndis802_11EncryptionDisabled), (pAd->CommonCfg.TxPreamble == Rt802_11PreambleLong ? 0 : 1), pAd->CommonCfg.bUseShortSlotTime, /*SpectrumMgmt*/FALSE); /* Disable Driver-Internal Rekey */ pMbss->WPAREKEY.ReKeyInterval = 0; pMbss->WPAREKEY.ReKeyMethod = DISABLE_REKEY; if (pBeacon->interval != 0) { DBGPRINT(RT_DEBUG_TRACE,("CFG_TIM New BI %d\n", pBeacon->interval)); pAd->CommonCfg.BeaconPeriod = pBeacon->interval; } if (pBeacon->dtim_period != 0) { DBGPRINT(RT_DEBUG_TRACE, ("CFG_TIM New DP %d\n", pBeacon->dtim_period)); pAd->ApCfg.DtimPeriod = pBeacon->dtim_period; } }
/* This function parses head and tail IEs, from cfg80211_beacon_data and sets * these IE to FW. */ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv, struct cfg80211_beacon_data *info) { struct mwifiex_ie *gen_ie; struct ieee_types_header *hdr; struct ieee80211_vendor_ie *vendorhdr; u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0; int left_len, parsed_len = 0; if (!info->tail || !info->tail_len) return 0; gen_ie = kzalloc(sizeof(*gen_ie), GFP_KERNEL); if (!gen_ie) return -ENOMEM; left_len = info->tail_len; /* Many IEs are generated in FW by parsing bss configuration. * Let's not add them here; else we may end up duplicating these IEs */ while (left_len > sizeof(struct ieee_types_header)) { hdr = (void *)(info->tail + parsed_len); switch (hdr->element_id) { case WLAN_EID_SSID: case WLAN_EID_SUPP_RATES: case WLAN_EID_COUNTRY: case WLAN_EID_PWR_CONSTRAINT: case WLAN_EID_EXT_SUPP_RATES: case WLAN_EID_HT_CAPABILITY: case WLAN_EID_HT_OPERATION: case WLAN_EID_VHT_CAPABILITY: case WLAN_EID_VHT_OPERATION: case WLAN_EID_VENDOR_SPECIFIC: break; default: memcpy(gen_ie->ie_buffer + ie_len, hdr, hdr->len + sizeof(struct ieee_types_header)); ie_len += hdr->len + sizeof(struct ieee_types_header); break; } left_len -= hdr->len + sizeof(struct ieee_types_header); parsed_len += hdr->len + sizeof(struct ieee_types_header); } /* parse only WPA vendor IE from tail, WMM IE is configured by * bss_config command */ vendorhdr = (void *)cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WPA, info->tail, info->tail_len); if (vendorhdr) { memcpy(gen_ie->ie_buffer + ie_len, vendorhdr, vendorhdr->len + sizeof(struct ieee_types_header)); ie_len += vendorhdr->len + sizeof(struct ieee_types_header); } if (!ie_len) { kfree(gen_ie); return 0; } gen_ie->ie_index = cpu_to_le16(gen_idx); gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP | MGMT_MASK_ASSOC_RESP); gen_ie->ie_length = cpu_to_le16(ie_len); if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL, NULL, NULL, NULL)) { kfree(gen_ie); return -1; } priv->gen_idx = gen_idx; kfree(gen_ie); return 0; }