📄 ieee80211_input.c
字号:
case WPA_SEL(WPA_ASE_NONE): return WPA_ASE_NONE; } return 0; /* NB: so is discarded */#undef WPA_SEL}/* * Parse a WPA information element to collect parameters * and validate the parameters against what has been * configured for the system. */static intieee80211_parse_wpa(struct ieee80211vap *vap, u_int8_t *frm, struct ieee80211_rsnparms *rsn_parm, const struct ieee80211_frame *wh){ u_int8_t len = frm[1]; u_int32_t w; int n; /* * Check the length once for fixed parts: OUI, type, * version, mcast cipher, and 2 selector counts. * Other, variable-length data, must be checked separately. */ if (!(vap->iv_flags & IEEE80211_F_WPA1)) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA, wh, "WPA", "vap not WPA, flags 0x%x", vap->iv_flags); return IEEE80211_REASON_IE_INVALID; } if (len < 14) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA, wh, "WPA", "too short, len %u", len); return IEEE80211_REASON_IE_INVALID; } frm += 6, len -= 4; /* NB: len is payload only */ /* NB: iswapoui already validated the OUI and type */ w = LE_READ_2(frm); if (w != WPA_VERSION) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA, wh, "WPA", "bad version %u", w); return IEEE80211_REASON_IE_INVALID; } frm += 2; len -= 2; /* multicast/group cipher */ w = wpa_cipher(frm, &rsn_parm->rsn_mcastkeylen); if (w != rsn_parm->rsn_mcastcipher) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA, wh, "WPA", "mcast cipher mismatch; got %u, expected %u", w, rsn_parm->rsn_mcastcipher); return IEEE80211_REASON_IE_INVALID; } frm += 4; len -= 4; /* unicast ciphers */ n = LE_READ_2(frm); frm += 2; len -= 2; if (len < n*4+2) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA, wh, "WPA", "ucast cipher data too short; len %u, n %u", len, n); return IEEE80211_REASON_IE_INVALID; } w = 0; for (; n > 0; n--) { w |= 1 << wpa_cipher(frm, &rsn_parm->rsn_ucastkeylen); frm += 4; len -= 4; } w &= rsn_parm->rsn_ucastcipherset; if (w == 0) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA, wh, "WPA", "%s", "ucast cipher set empty"); return IEEE80211_REASON_IE_INVALID; } if (w & (1 << IEEE80211_CIPHER_TKIP)) rsn_parm->rsn_ucastcipher = IEEE80211_CIPHER_TKIP; else rsn_parm->rsn_ucastcipher = IEEE80211_CIPHER_AES_CCM; /* key management algorithms */ n = LE_READ_2(frm); frm += 2; len -= 2; if (len < n * 4) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA, wh, "WPA", "key mgmt alg data too short; len %u, n %u", len, n); return IEEE80211_REASON_IE_INVALID; } w = 0; for (; n > 0; n--) { w |= wpa_keymgmt(frm); frm += 4; len -= 4; } w &= rsn_parm->rsn_keymgmtset; if (w == 0) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA, wh, "WPA", "%s", "no acceptable key mgmt alg"); return IEEE80211_REASON_IE_INVALID; } if (w & WPA_ASE_8021X_UNSPEC) rsn_parm->rsn_keymgmt = WPA_ASE_8021X_UNSPEC; else rsn_parm->rsn_keymgmt = WPA_ASE_8021X_PSK; if (len > 2) /* optional capabilities */ rsn_parm->rsn_caps = LE_READ_2(frm); return 0;}/* * Convert an RSN cipher selector OUI to an internal * cipher algorithm. Where appropriate we also * record any key length. */static intrsn_cipher(u_int8_t *sel, u_int8_t *keylen){#define RSN_SEL(x) (((x) << 24) | RSN_OUI) u_int32_t w = LE_READ_4(sel); switch (w) { case RSN_SEL(RSN_CSE_NULL): return IEEE80211_CIPHER_NONE; case RSN_SEL(RSN_CSE_WEP40): if (keylen) *keylen = 40 / NBBY; return IEEE80211_CIPHER_WEP; case RSN_SEL(RSN_CSE_WEP104): if (keylen) *keylen = 104 / NBBY; return IEEE80211_CIPHER_WEP; case RSN_SEL(RSN_CSE_TKIP): return IEEE80211_CIPHER_TKIP; case RSN_SEL(RSN_CSE_CCMP): return IEEE80211_CIPHER_AES_CCM; case RSN_SEL(RSN_CSE_WRAP): return IEEE80211_CIPHER_AES_OCB; } return 32; /* NB: so 1<< is discarded */#undef RSN_SEL}/* * Convert an RSN key management/authentication algorithm * to an internal code. */static intrsn_keymgmt(u_int8_t *sel){#define RSN_SEL(x) (((x) << 24) | RSN_OUI) u_int32_t w = LE_READ_4(sel); switch (w) { case RSN_SEL(RSN_ASE_8021X_UNSPEC): return RSN_ASE_8021X_UNSPEC; case RSN_SEL(RSN_ASE_8021X_PSK): return RSN_ASE_8021X_PSK; case RSN_SEL(RSN_ASE_NONE): return RSN_ASE_NONE; } return 0; /* NB: so is discarded */#undef RSN_SEL}/* * Parse a WPA/RSN information element to collect parameters * and validate the parameters against what has been * configured for the system. */static intieee80211_parse_rsn(struct ieee80211vap *vap, u_int8_t *frm, struct ieee80211_rsnparms *rsn_parm, const struct ieee80211_frame *wh){ u_int8_t len = frm[1]; u_int32_t w; int n; /* * Check the length once for fixed parts: * version, mcast cipher, and 2 selector counts. * Other, variable-length data, must be checked separately. */ if (!(vap->iv_flags & IEEE80211_F_WPA2)) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA, wh, "RSN", "vap not RSN, flags 0x%x", vap->iv_flags); return IEEE80211_REASON_IE_INVALID; } if (len < 10) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA, wh, "RSN", "too short, len %u", len); return IEEE80211_REASON_IE_INVALID; } frm += 2; w = LE_READ_2(frm); if (w != RSN_VERSION) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA, wh, "RSN", "bad version %u", w); return IEEE80211_REASON_IE_INVALID; } frm += 2; len -= 2; /* multicast/group cipher */ w = rsn_cipher(frm, &rsn_parm->rsn_mcastkeylen); if (w != rsn_parm->rsn_mcastcipher) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA, wh, "RSN", "mcast cipher mismatch; got %u, expected %u", w, rsn_parm->rsn_mcastcipher); return IEEE80211_REASON_IE_INVALID; } frm += 4; len -= 4; /* unicast ciphers */ n = LE_READ_2(frm); frm += 2; len -= 2; if (len < n * 4 + 2) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA, wh, "RSN", "ucast cipher data too short; len %u, n %u", len, n); return IEEE80211_REASON_IE_INVALID; } w = 0; for (; n > 0; n--) { w |= 1 << rsn_cipher(frm, &rsn_parm->rsn_ucastkeylen); frm += 4; len -= 4; } w &= rsn_parm->rsn_ucastcipherset; if (w == 0) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA, wh, "RSN", "%s", "ucast cipher set empty"); return IEEE80211_REASON_IE_INVALID; } if (w & (1<<IEEE80211_CIPHER_TKIP)) rsn_parm->rsn_ucastcipher = IEEE80211_CIPHER_TKIP; else rsn_parm->rsn_ucastcipher = IEEE80211_CIPHER_AES_CCM; /* key management algorithms */ n = LE_READ_2(frm); frm += 2; len -= 2; if (len < n * 4) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA, wh, "RSN", "key mgmt alg data too short; len %u, n %u", len, n); return IEEE80211_REASON_IE_INVALID; } w = 0; for (; n > 0; n--) { w |= rsn_keymgmt(frm); frm += 4; len -= 4; } w &= rsn_parm->rsn_keymgmtset; if (w == 0) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA, wh, "RSN", "%s", "no acceptable key mgmt alg"); return IEEE80211_REASON_IE_INVALID; } if (w & RSN_ASE_8021X_UNSPEC) rsn_parm->rsn_keymgmt = RSN_ASE_8021X_UNSPEC; else rsn_parm->rsn_keymgmt = RSN_ASE_8021X_PSK; /* optional RSN capabilities */ if (len > 2) rsn_parm->rsn_caps = LE_READ_2(frm); /* XXXPMKID */ return 0;}voidieee80211_saveie(u_int8_t **iep, const u_int8_t *ie){ u_int ielen = ie[1] + 2; /* * Record information element for later use. */ if (*iep == NULL || (*iep)[1] != ie[1]) { if (*iep != NULL) FREE(*iep, M_DEVBUF); MALLOC(*iep, void*, ielen, M_DEVBUF, M_NOWAIT); } if (*iep != NULL) memcpy(*iep, ie, ielen);}EXPORT_SYMBOL(ieee80211_saveie);static intieee80211_parse_wmeie(u_int8_t *frm, const struct ieee80211_frame *wh, struct ieee80211_node *ni){ u_int len = frm[1]; if (len != 7) { IEEE80211_DISCARD_IE(ni->ni_vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WME, wh, "WME IE", "too short, len %u", len); return -1; } ni->ni_uapsd = frm[WME_CAPINFO_IE_OFFSET]; if (ni->ni_uapsd) { ni->ni_flags |= IEEE80211_NODE_UAPSD; switch (WME_UAPSD_MAXSP(ni->ni_uapsd)) { case 1: ni->ni_uapsd_maxsp = 2; break; case 2: ni->ni_uapsd_maxsp = 4; break; case 3: ni->ni_uapsd_maxsp = 6; break; default: ni->ni_uapsd_maxsp = WME_UAPSD_NODE_MAXQDEPTH; } } IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_POWER, ni, "UAPSD bit settings from STA: %02x", ni->ni_uapsd); return 1;}static intieee80211_parse_wmeparams(struct ieee80211vap *vap, u_int8_t *frm, const struct ieee80211_frame *wh, u_int8_t *qosinfo){#define MS(_v, _f) (((_v) & _f) >> _f##_S) struct ieee80211_wme_state *wme = &vap->iv_ic->ic_wme; u_int len = frm[1], qosinfo_count; int i; *qosinfo = 0; if (len < sizeof(struct ieee80211_wme_param)-2) { IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WME, wh, "WME", "too short, len %u", len); return -1; } *qosinfo = frm[__offsetof(struct ieee80211_wme_param, param_qosInfo)]; qosinfo_count = *qosinfo & WME_QOSINFO_COUNT; /* XXX do proper check for wraparound */ if (qosinfo_count == wme->wme_wmeChanParams.cap_info_count) return 0; frm += __offsetof(struct ieee80211_wme_param, params_acParams); for (i = 0; i < WME_NUM_AC; i++) { struct wmeParams *wmep = &wme->wme_wmeChanParams.cap_wmeParams[i]; /* NB: ACI not used */ wmep->wmep_acm = MS(frm[0], WME_PARAM_ACM); wmep->wmep_aifsn = MS(frm[0], WME_PARAM_AIFSN); wmep->wmep_logcwmin = MS(frm[1], WME_PARAM_LOGCWMIN); wmep->wmep_logcwmax = MS(frm[1], WME_PARAM_LOGCWMAX); wmep->wmep_txopLimit = LE_READ_2(frm + 2); frm += 4; } wme->wme_wmeChanParams.cap_info_count = qosinfo_count; return 1;#undef MS}static voidieee80211_parse_athParams(struct ieee80211_node *ni, u_int8_t *ie){ struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct ieee80211_ie_athAdvCap *athIe = (struct ieee80211_ie_athAdvCap *) ie; ni->ni_ath_flags = athIe->athAdvCap_capability; if (ni->ni_ath_flags & IEEE80211_ATHC_COMP) ni->ni_ath_defkeyindex = LE_READ_2(&athIe->athAdvCap_defKeyIndex);#if 0 /* NB: too noisy */ IEEE80211_NOTE(vap, IEEE80211_MSG_SUPG, ni, "recv ath params: caps 0x%x flags 0x%x defkeyix %u", athIe->athAdvCap_capability, ni->ni_ath_flags, ni->ni_ath_defkeyindex);#endif#ifdef ATH_SUPERG_DYNTURBO if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_ATHC_TURBOP)) { u_int16_t curflags, newflags; /* * Check for turbo mode switch. Calculate flags * for the new mode and effect the switch. */ newflags = curflags = ic->ic_bsschan->ic_flags; /* NB: ATHC_BOOST is not in ic_ath_cap, so get it from the ie */ if (athIe->athAdvCap_capability & IEEE80211_ATHC_BOOST) newflags |= IEEE80211_CHAN_TURBO; else newflags &= ~IEEE80211_CHAN_TURBO; if (newflags != curflags) ieee80211_dturbo_switch(ic, newflags); }#endif /* ATH_SUPERG_DYNTURBO */}voidieee80211_saveath(struct ieee80211_node *ni, u_int8_t *ie){ const struct ieee80211_ie_athAdvCap *athIe = (const struct ieee80211_ie_athAdvCap *) ie; ni->ni_ath_flags = athIe->athAdvCap_capability; if (ni->ni_ath_flags & IEEE80211_ATHC_COMP) ni->ni_ath_defkeyindex = LE_READ_2(&athIe->athAdvCap_defKeyIndex); ieee80211_saveie(&ni->ni_ath_ie, ie);}struct ieee80211_channel *ieee80211_doth_findchan(struct ieee80211vap *vap, u_int8_t chan){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -