static void printies(const u_int8_t *vp, int ielen, int maxcols) { while (ielen > 0) { switch (vp[0]) { case IEEE80211_ELEMID_VENDOR: if (iswpaoui(vp)) printie(" WPA", vp, 2 + vp[1], maxcols); else if (iswmeoui(vp)) printie(" WME", vp, 2 + vp[1], maxcols); else if (isatherosoui(vp)) printie(" ATH", vp, 2 + vp[1], maxcols); else printie(" VEN", vp, 2 + vp[1], maxcols); break; case IEEE80211_ELEMID_RSN: printie(" RSN", vp, 2 + vp[1], maxcols); break; default: printie(" ???", vp, 2 + vp[1], maxcols); break; } ielen -= 2 + vp[1]; vp += 2 + vp[1]; } }
static void getIEs(const u_int8_t *vp, int ielen, int maxcols, u_int8_t *str_out) { char *ptr = (char *)str_out; int iTemp = 0; while (ielen > 0 && iTemp < maxcols) { switch (vp[0]) { case IEEE80211_ELEMID_VENDOR: if (iswpaoui(vp)) sprintf(ptr, " WPA"); else if (iswmeoui(vp)) sprintf(ptr, " WME"); else if (isatherosoui(vp)) sprintf(ptr, " ATH"); else sprintf(ptr, " VEN"); ptr += 4 ; iTemp++; break; case IEEE80211_ELEMID_RSN: sprintf(ptr, " RSN"); ptr += 4; iTemp++; break; default: //sprintf(str_out, " ???"); break; } ielen -= 2+vp[1]; vp += 2+vp[1]; } *ptr = '\0'; }
/* * 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; }