/* * Process information elements from association response frame. * This includes rate negociation, wmm parameter updating and etc. */ static int mlme_process_asresp_elements(struct ieee80211_node *ni, u_int8_t *frm, u_int32_t ie_len) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_rsnparms *rsn = &vap->iv_rsn; struct ieee80211com *ic = ni->ni_ic; u_int8_t *efrm = frm + ie_len; u_int8_t *rates, *xrates, *wme, *htcap, *tspecie, *athextcap; u_int8_t qosinfo; int ht_rates_allowed; ASSERT((vap->iv_opmode != IEEE80211_M_STA) || (ni == vap->iv_bss)); rates = xrates = wme = htcap = tspecie = athextcap = NULL; while (frm < efrm) { switch (*frm) { case IEEE80211_ELEMID_RATES: rates = frm; break; case IEEE80211_ELEMID_XRATES: xrates = frm; break; case IEEE80211_ELEMID_HTCAP_ANA: htcap = (u_int8_t *)&((struct ieee80211_ie_htcap *)frm)->hc_ie; break; case IEEE80211_ELEMID_HTCAP: if (htcap == NULL) { htcap = (u_int8_t *)&((struct ieee80211_ie_htcap *)frm)->hc_ie; } break; case IEEE80211_ELEMID_VENDOR: if (iswmeoui(frm, WME_PARAM_OUI_SUBTYPE)) wme = frm; else if (iswmeoui(frm, WME_INFO_OUI_SUBTYPE)) wme = frm; else if (iswmeoui(frm, WME_TSPEC_OUI_SUBTYPE)) tspecie = frm; else if(ishtcap(frm)) { if (htcap == NULL) { htcap = (u_int8_t *)&((struct vendor_ie_htcap *)frm)->hc_ie; } } else if (isatheros_extcap_oui(frm)) athextcap = frm; break; } frm += frm[1] + 2; } if (!rates || (rates[1] > IEEE80211_RATE_MAXSIZE)) { /* XXX: msg + stats */ return -EINVAL; } if (!ieee80211_setup_rates(ni, rates, xrates, IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | IEEE80211_F_DOXSECT)) { printk("%s: association failed (rate set mismatch)\n", __func__); return -EINVAL; } /* * U-APSD is enabled/disabled per-association. */ if (wme != NULL) { /* Parse IE according to subtype */ if (iswmeparam(wme)) { /* Association is QOS-enabled */ ieee80211node_set_flag(ni, IEEE80211_NODE_QOS); if (vap->iv_opmode != IEEE80211_M_BTAMP && ieee80211_parse_wmeparams(vap, wme, &qosinfo, 1) >= 0) { /* Check if association is UAPSD-enabled */ if (qosinfo & WME_CAPINFO_UAPSD_EN) { ieee80211node_set_flag(ni, IEEE80211_NODE_UAPSD); } else { ieee80211node_clear_flag(ni, IEEE80211_NODE_UAPSD); } ieee80211_wme_updateparams(vap); } } else { /*** QOS requires WME Param */ ieee80211node_clear_flag(ni, IEEE80211_NODE_QOS); if (ieee80211_parse_wmeinfo(vap, wme, &qosinfo) >= 0) { /* Check if association is UAPSD-enabled */ if (qosinfo & WME_CAPINFO_UAPSD_EN) { ieee80211node_set_flag(ni, IEEE80211_NODE_UAPSD); } else { ieee80211node_clear_flag(ni, IEEE80211_NODE_UAPSD); } ieee80211_wme_updateinfo(vap); } } } else { ieee80211node_clear_flag(ni, IEEE80211_NODE_QOS); ieee80211node_clear_flag(ni, IEEE80211_NODE_UAPSD); } if ((tspecie != NULL) && (ieee80211_parse_tspecparams(vap, tspecie) >= 0)) { /* store the tspec */ } if (athextcap != NULL) ieee80211_process_athextcap_ie(ni, athextcap); /* * With WEP and TKIP encryption algorithms: * Disable aggregation if IEEE80211_NODE_WEPTKIPAGGR is not set. * Disable 11n if IEEE80211_FEXT_WEP_TKIP_HTRATE is not set. */ ht_rates_allowed = IEEE80211_IS_CHAN_11N(ic->ic_curchan); if (IEEE80211_VAP_IS_PRIVACY_ENABLED(vap) && (RSN_CIPHER_IS_WEP(rsn) || (RSN_CIPHER_IS_TKIP(rsn) && !RSN_CIPHER_IS_CCMP(rsn)))) { ieee80211node_set_flag(ni, IEEE80211_NODE_WEPTKIP); if (ieee80211_ic_wep_tkip_htrate_is_set(ic)) { if (!ieee80211_has_weptkipaggr(ni)) ieee80211node_set_flag(ni, IEEE80211_NODE_NOAMPDU); } else { ht_rates_allowed = 0; } } /* 11n - HT rates not allowed using WEP and TKIP */ if ((htcap != NULL) && (ht_rates_allowed)) { /* record capabilities, mark node as capable of HT */ ieee80211_parse_htcap(ni, htcap); if (!ieee80211_setup_ht_rates(ni, htcap, IEEE80211_F_DOFRATE | IEEE80211_F_DOXSECT | IEEE80211_F_DOBRS)) { printk("%s: association failed (rate set mismatch)\n", __func__); return -EINVAL; } #ifdef ATH_SUPPORT_TxBF // set keycache for txbf after sta associated successfully. if ( ni->ni_explicit_compbf || ni->ni_explicit_noncompbf || ni->ni_implicit_bf){ struct ieee80211com *ic = vap->iv_ic; ieee80211_set_TxBF_keycache(ic,ni); ni->ni_bf_update_cv = 1; ni->ni_allow_cv_update = 1; } #endif } else { /* * Flush any state from a previous association. */ ieee80211node_clear_flag(ni, IEEE80211_NODE_HT); IEEE80211_NODE_CLEAR_HTCAP(ni); } return EOK; }
void ath6kl_tgt_sony_get_scaninfo_event(struct ath6kl_vif *vif, u8 *datap, u32 len) { struct wmi_bss_info_hdr2 *bih; u8 *buf; struct ieee80211_channel *channel; struct ieee80211_mgmt *mgmt; //struct cfg80211_bss *bss; if (len <= sizeof(struct wmi_bss_info_hdr2)) return; bih = (struct wmi_bss_info_hdr2 *) datap; buf = datap + sizeof(struct wmi_bss_info_hdr2); len -= sizeof(struct wmi_bss_info_hdr2); printk( "bss info evt - ch %u, snr %d, rssi %d, bssid \"%pM\" " "frame_type=%d\n", bih->ch, bih->snr, bih->snr - 95, bih->bssid, bih->frame_type); if (bih->frame_type != BEACON_FTYPE && bih->frame_type != PROBERESP_FTYPE) return; /* Only update BSS table for now */ channel = ieee80211_get_channel(vif->wdev->wiphy, le16_to_cpu(bih->ch)); if (channel == NULL) return; if (len < 8 + 2 + 2) return; /* * In theory, use of cfg80211_inform_bss_ath6kl() would be more natural here * since we do not have the full frame. However, at least for now, * cfg80211 can only distinguish Beacon and Probe Response frames from * each other when using cfg80211_inform_bss_frame_ath6kl(), so let's build a * fake IEEE 802.11 header to be able to take benefit of this. */ mgmt = kmalloc(24 + len, GFP_ATOMIC); if (mgmt == NULL) return; if (bih->frame_type == BEACON_FTYPE) { mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); memset(mgmt->da, 0xff, ETH_ALEN); } else { struct net_device *dev = vif->net_dev; mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); memcpy(mgmt->da, dev->dev_addr, ETH_ALEN); } mgmt->duration = cpu_to_le16(0); memcpy(mgmt->sa, bih->bssid, ETH_ALEN); memcpy(mgmt->bssid, bih->bssid, ETH_ALEN); mgmt->seq_ctrl = cpu_to_le16(0); memcpy(&mgmt->u.beacon, buf, len); {//save to scan information database athcfg_wcmd_scan_result_t scan_entry; memset(&scan_entry,0x00,sizeof(athcfg_wcmd_scan_result_t)); scan_entry.isr_freq = bih->ch; scan_entry.isr_ieee = (unsigned char)ieee80211_frequency_to_channel_ath6kl(bih->ch); scan_entry.isr_rssi = (bih->snr < 0) ? 0 : bih->snr; memcpy(&scan_entry.isr_bssid[0],&bih->bssid[0],ATHCFG_WCMD_ADDR_LEN); scan_entry.isr_capinfo = le16_to_cpu(mgmt->u.beacon.capab_info); //parse ie information { struct ieee80211_ie_header *ie_element; unsigned char *temp_ptr; int remained_len; ie_element = (struct ieee80211_ie_header *)&(mgmt->u.beacon.variable); remained_len = len - 5*sizeof(u8); while(remained_len >= 0) { remained_len = remained_len - sizeof(struct ieee80211_ie_header)- ie_element->length; if (ie_element->length == 0) { ie_element += 1; /* next IE */ continue; } if (remained_len < ie_element->length) { /* Incomplete/bad info element */ //printk("EOF\n"); break; } temp_ptr = (unsigned char *)ie_element; temp_ptr = temp_ptr+sizeof(struct ieee80211_ie_header);//point to data area switch (ie_element->element_id) { case IEEE80211_ELEMID_SSID: memcpy(&scan_entry.isr_ssid,temp_ptr,ie_element->length); //printk("info_element->length=%d\n",ie_element->length); //printk("SSID=%s\n",scan_entry.isr_ssid); break; case IEEE80211_ELEMID_RATES: memcpy(&scan_entry.isr_rates[0],temp_ptr,ie_element->length); scan_entry.isr_nrates = ie_element->length; break; case IEEE80211_ELEMID_XRATES: memcpy(&scan_entry.isr_rates[scan_entry.isr_nrates],temp_ptr,ie_element->length); scan_entry.isr_nrates += ie_element->length; break; case IEEE80211_ELEMID_ERP: memcpy(&scan_entry.isr_erp,temp_ptr,ie_element->length); break; case IEEE80211_ELEMID_RSN: scan_entry.isr_rsn_ie.len = ie_element->length; memcpy(&scan_entry.isr_rsn_ie.data,temp_ptr,ie_element->length); break; case IEEE80211_ELEMID_HTCAP_ANA: if (scan_entry.isr_htcap_ie.len == 0) { scan_entry.isr_htcap_ie.len = ie_element->length; memcpy(&scan_entry.isr_htcap_ie.data[0],temp_ptr,ie_element->length); } break; case IEEE80211_ELEMID_HTINFO_ANA: /* we only care if there isn't already an HT IE (ANA) */ if (scan_entry.isr_htinfo_ie.len == 0) { scan_entry.isr_htinfo_ie.len = ie_element->length; memcpy(&scan_entry.isr_htinfo_ie.data[0],temp_ptr,ie_element->length); } break; case IEEE80211_ELEMID_HTCAP: /* we only care if there isn't already an HT IE (ANA) */ if (scan_entry.isr_htcap_ie.len == 0) { scan_entry.isr_htcap_ie.len = ie_element->length; memcpy(&scan_entry.isr_htcap_ie.data[0],temp_ptr,ie_element->length); } break; case IEEE80211_ELEMID_HTINFO: /* we only care if there isn't already an HT IE (ANA) */ if (scan_entry.isr_htinfo_ie.len == 0) { scan_entry.isr_htinfo_ie.len = ie_element->length; memcpy(&scan_entry.isr_htinfo_ie.data[0],temp_ptr,ie_element->length); } break; case IEEE80211_ELEMID_VENDOR: if (iswpaoui((u_int8_t *) ie_element)) { scan_entry.isr_wpa_ie.len = ie_element->length; memcpy(&scan_entry.isr_wpa_ie.data[0],temp_ptr,ie_element->length); } else if (iswpsoui((u_int8_t *) ie_element)) { scan_entry.isr_wps_ie.len = ie_element->length; memcpy(&scan_entry.isr_wps_ie.data[0],temp_ptr,ie_element->length); } else if (iswmeparam((u_int8_t *) ie_element)) { scan_entry.isr_wme_ie.len = ie_element->length; memcpy(&scan_entry.isr_wme_ie.data[0],temp_ptr,ie_element->length); } else if (isatherosoui((u_int8_t *) ie_element)) { scan_entry.isr_ath_ie.len = ie_element->length; memcpy(&scan_entry.isr_ath_ie.data[0],temp_ptr,ie_element->length); } else if (ishtcap((u_int8_t *) ie_element)) { if (scan_entry.isr_htcap_ie.len == 0) { scan_entry.isr_htcap_ie.len = ie_element->length; memcpy(&scan_entry.isr_htcap_ie.data[0],temp_ptr,ie_element->length); } } else if (ishtinfo((u_int8_t *) ie_element)) { if (scan_entry.isr_htinfo_ie.len == 0) { scan_entry.isr_htinfo_ie.len = ie_element->length; memcpy(&scan_entry.isr_htinfo_ie.data[0],temp_ptr,ie_element->length); } } else { //printk("Unknow know !!info_element->length=%d\n",ie_element->length); } break; default: //printk("Unknow know info_element->length=%d\n",ie_element->length); break; } ie_element = (struct ieee80211_ie_header *)(temp_ptr + ie_element->length); } } //find the exist entry or add new one { int i,entry_match_item; bool entry_match = 0; if(total_bss_info >= 100) { printk("Excess max entry 100\n"); kfree(mgmt); return; } for(i=0;i<total_bss_info;i++) { if(scaninfor_db[i].isr_freq == scan_entry.isr_freq) { if(memcmp(scaninfor_db[i].isr_bssid ,scan_entry.isr_bssid,ATHCFG_WCMD_ADDR_LEN) == 0) { //find it if(strcmp(scaninfor_db[i].isr_ssid ,scan_entry.isr_ssid) == 0) { //update it entry_match = 1; entry_match_item = i; //printk("fully match!! i=%d,update it,total_bss_info=%d\n",i,total_bss_info); memcpy(&scaninfor_db[i],&scan_entry,sizeof(athcfg_wcmd_scan_result_t)); break; } } } } if(entry_match == 0) { memcpy(&scaninfor_db[total_bss_info],&scan_entry,sizeof(athcfg_wcmd_scan_result_t)); #if 0 printk("[%d]Freq=%d\n",total_bss_info,scaninfor_db[total_bss_info].isr_freq); printk("[%d]CH=%d\n",total_bss_info,scaninfor_db[total_bss_info].isr_ieee); printk("[%d]RSSI=%d\n",total_bss_info,scaninfor_db[total_bss_info].isr_rssi); printk("[%d]BSSID=%pM\n",total_bss_info,scaninfor_db[total_bss_info].isr_bssid); printk("[%d]SSID=%s\n",total_bss_info,scaninfor_db[total_bss_info].isr_ssid); printk("[%d]isr_htinfo_ie.len=%d\n",total_bss_info,scaninfor_db[total_bss_info].isr_htinfo_ie.len); #endif total_bss_info++; //printk(" next entry=%d\n",total_bss_info); } else { #if 0 printk("[%d]Freq=%d\n",entry_match_item,scaninfor_db[entry_match_item].isr_freq); printk("[%d]CH=%d\n",entry_match_item,scaninfor_db[entry_match_item].isr_ieee); printk("[%d]RSSI=%d\n",entry_match_item,scaninfor_db[entry_match_item].isr_rssi); printk("[%d]BSSID=%pM\n",entry_match_item,scaninfor_db[entry_match_item].isr_bssid); printk("[%d]SSID=%s\n",entry_match_item,scaninfor_db[entry_match_item].isr_ssid); printk("[%d]isr_htinfo_ie.len=%d\n",entry_match_item,scaninfor_db[entry_match_item].isr_htinfo_ie.len); #endif } } } kfree(mgmt); ///total_bss_info++; return; }