📄 ieee80211_input.c.svn-base
字号:
/* should not come here */ break; case IEEE80211_M_HOSTAP: if (vap->iv_state != IEEE80211_S_RUN || seq != IEEE80211_AUTH_OPEN_REQUEST) { vap->iv_stats.is_rx_bad_auth++; return; } /* always accept open authentication requests */ if (ni == vap->iv_bss) { ni = ieee80211_dup_bss(vap, wh->i_addr2, 0); if (ni == NULL) return; tmpnode = 1; } IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_AUTH, seq + 1); IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH, ni, "station authenticated (%s)", "open"); /* * When 802.1x is not in use mark the port * authorized at this point so traffic can flow. */ if (ni->ni_authmode != IEEE80211_AUTH_8021X) ieee80211_node_authorize(ni); if (tmpnode) ieee80211_unref_node(&ni); break; case IEEE80211_M_STA: if (vap->iv_state != IEEE80211_S_AUTH || seq != IEEE80211_AUTH_OPEN_RESPONSE) { vap->iv_stats.is_rx_bad_auth++; return; } if (status != 0) { IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH, ni, "open auth failed (reason %d)", status); vap->iv_stats.is_rx_auth_fail++; ieee80211_new_state(vap, IEEE80211_S_SCAN, IEEE80211_SCAN_FAIL_STATUS); } else ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0); break; case IEEE80211_M_MONITOR: break; }}/* * Send a management frame error response to the specified * station. If ni is associated with the station then use * it; otherwise allocate a temporary node suitable for * transmitting the frame and then free the reference so * it will go away as soon as the frame has been transmitted. */static voidieee80211_send_error(struct ieee80211_node *ni, const u_int8_t *mac, int subtype, int arg){ struct ieee80211vap *vap = ni->ni_vap; int istmp; if (ni == vap->iv_bss) { ni = ieee80211_dup_bss(vap, mac, 1); if (ni == NULL) { /* XXX msg */ return; } istmp = 1; } else istmp = 0; IEEE80211_SEND_MGMT(ni, subtype, arg); if (istmp) ieee80211_unref_node(&ni);}static intalloc_challenge(struct ieee80211_node *ni){ if (ni->ni_challenge == NULL) MALLOC(ni->ni_challenge, u_int32_t*, IEEE80211_CHALLENGE_LEN, M_DEVBUF, M_NOWAIT); if (ni->ni_challenge == NULL) { IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH, ni, "%s", "shared key challenge alloc failed"); /* XXX statistic */ } return (ni->ni_challenge != NULL);}/* XXX TODO: add statistics */static voidieee80211_auth_shared(struct ieee80211_node *ni, struct ieee80211_frame *wh, u_int8_t *frm, u_int8_t *efrm, int rssi, u_int64_t rtsf, u_int16_t seq, u_int16_t status){ struct ieee80211vap *vap = ni->ni_vap; u_int8_t *challenge; int allocbs = 0, estatus = 0; /* * NB: this can happen as we allow pre-shared key * authentication to be enabled w/o wep being turned * on so that configuration of these can be done * in any order. It may be better to enforce the * ordering in which case this check would just be * for sanity/consistency. */ if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, ni->ni_macaddr, "shared key auth", "%s", " PRIVACY is disabled"); estatus = IEEE80211_STATUS_ALG; goto bad; } /* * Pre-shared key authentication is evil; accept * it only if explicitly configured (it is supported * mainly for compatibility with clients like OS X). */ if (ni->ni_authmode != IEEE80211_AUTH_AUTO && ni->ni_authmode != IEEE80211_AUTH_SHARED) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, ni->ni_macaddr, "shared key auth", "bad sta auth mode %u", ni->ni_authmode); vap->iv_stats.is_rx_bad_auth++; /* XXX maybe a unique error? */ estatus = IEEE80211_STATUS_ALG; goto bad; } challenge = NULL; if (frm + 1 < efrm) { if ((frm[1] + 2) > (efrm - frm)) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, ni->ni_macaddr, "shared key auth", "ie %d/%d too long", frm[0], (frm[1] + 2) - (efrm - frm)); vap->iv_stats.is_rx_bad_auth++; estatus = IEEE80211_STATUS_CHALLENGE; goto bad; } if (*frm == IEEE80211_ELEMID_CHALLENGE) challenge = frm; frm += frm[1] + 2; } switch (seq) { case IEEE80211_AUTH_SHARED_CHALLENGE: case IEEE80211_AUTH_SHARED_RESPONSE: if (challenge == NULL) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, ni->ni_macaddr, "shared key auth", "%s", "no challenge"); vap->iv_stats.is_rx_bad_auth++; estatus = IEEE80211_STATUS_CHALLENGE; goto bad; } if (challenge[1] != IEEE80211_CHALLENGE_LEN) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, ni->ni_macaddr, "shared key auth", "bad challenge len %d", challenge[1]); vap->iv_stats.is_rx_bad_auth++; estatus = IEEE80211_STATUS_CHALLENGE; goto bad; } default: break; } switch (vap->iv_opmode) { case IEEE80211_M_MONITOR: case IEEE80211_M_AHDEMO: case IEEE80211_M_IBSS: case IEEE80211_M_WDS: IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, ni->ni_macaddr, "shared key auth", "bad operating mode %u", vap->iv_opmode); return; case IEEE80211_M_HOSTAP: if (vap->iv_state != IEEE80211_S_RUN) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, ni->ni_macaddr, "shared key auth", "bad state %u", vap->iv_state); estatus = IEEE80211_STATUS_ALG; /* XXX */ goto bad; } switch (seq) { case IEEE80211_AUTH_SHARED_REQUEST: if (ni == vap->iv_bss) { ni = ieee80211_dup_bss(vap, wh->i_addr2, 0); if (ni == NULL) { /* NB: no way to return an error */ return; } allocbs = 1; } ni->ni_rssi = rssi; ni->ni_rtsf = rtsf; ni->ni_last_rx = jiffies; if (!alloc_challenge(ni)) { if (allocbs) ieee80211_unref_node(&ni); /* NB: don't return error so they rexmit */ return; } get_random_bytes(ni->ni_challenge, IEEE80211_CHALLENGE_LEN); IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH, ni, "shared key %sauth request", allocbs ? "" : "re"); break; case IEEE80211_AUTH_SHARED_RESPONSE: if (ni == vap->iv_bss) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, ni->ni_macaddr, "shared key response", "%s", "unknown station"); /* NB: don't send a response */ return; } if (ni->ni_challenge == NULL) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, ni->ni_macaddr, "shared key response", "%s", "no challenge recorded"); vap->iv_stats.is_rx_bad_auth++; estatus = IEEE80211_STATUS_CHALLENGE; goto bad; } if (memcmp(ni->ni_challenge, &challenge[2], challenge[1]) != 0) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, ni->ni_macaddr, "shared key response", "%s", "challenge mismatch"); vap->iv_stats.is_rx_auth_fail++; estatus = IEEE80211_STATUS_CHALLENGE; goto bad; } IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH, ni, "station authenticated (%s)", "shared key"); ieee80211_node_authorize(ni); break; default: IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, ni->ni_macaddr, "shared key auth", "bad seq %d", seq); vap->iv_stats.is_rx_bad_auth++; estatus = IEEE80211_STATUS_SEQUENCE; goto bad; } IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_AUTH, seq + 1); break; case IEEE80211_M_STA: if (vap->iv_state != IEEE80211_S_AUTH) return; switch (seq) { case IEEE80211_AUTH_SHARED_PASS: if (ni->ni_challenge != NULL) { FREE(ni->ni_challenge, M_DEVBUF); ni->ni_challenge = NULL; } if (status != 0) { IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH, ieee80211_getbssid(vap, wh), "shared key auth failed (reason %d)", status); vap->iv_stats.is_rx_auth_fail++; /* XXX IEEE80211_SCAN_FAIL_STATUS */ goto bad; } ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0); break; case IEEE80211_AUTH_SHARED_CHALLENGE: if (!alloc_challenge(ni)) goto bad; /* XXX could optimize by passing recvd challenge */ memcpy(ni->ni_challenge, &challenge[2], challenge[1]); IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_AUTH, seq + 1); break; default: IEEE80211_DISCARD(vap, IEEE80211_MSG_AUTH, wh, "shared key auth", "bad seq %d", seq); vap->iv_stats.is_rx_bad_auth++; goto bad; } break; } if (allocbs) ieee80211_unref_node(&ni); return;bad: /* Send an error response; but only when operating as an AP. */ if (vap->iv_opmode == IEEE80211_M_HOSTAP) { /* XXX hack to workaround calling convention */ ieee80211_send_error(ni, wh->i_addr2, IEEE80211_FC0_SUBTYPE_AUTH, (seq + 1) | (estatus<<16)); /* Remove node state if it exists and isn't just a * temporary copy of the bss (dereferenced later) */ if (!allocbs && (ni != vap->iv_bss)) ieee80211_node_leave(ni); } else if (vap->iv_opmode == IEEE80211_M_STA) { /* * Kick the state machine. This short-circuits * using the mgt frame timeout to trigger the * state transition. */ if (vap->iv_state == IEEE80211_S_AUTH) ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); } if (allocbs) ieee80211_unref_node(&ni);}/* Verify the existence and length of __elem or get out. */#define IEEE80211_VERIFY_ELEMENT(__elem, __maxlen) do { \ if ((__elem) == NULL) { \ IEEE80211_DISCARD(vap, IEEE80211_MSG_ELEMID, \ wh, ieee80211_mgt_subtype_name[subtype >> \ IEEE80211_FC0_SUBTYPE_SHIFT], \ "%s", "no " #__elem); \ vap->iv_stats.is_rx_elem_missing++; \ return 0; \ } \ if ((__elem)[1] > (__maxlen)) { \ IEEE80211_DISCARD(vap, IEEE80211_MSG_ELEMID, \ wh, ieee80211_mgt_subtype_name[subtype >> \ IEEE80211_FC0_SUBTYPE_SHIFT], \ "bad " #__elem " len %d", (__elem)[1]); \ vap->iv_stats.is_rx_elem_toobig++; \ return 0; \ } \} while (0)#define IEEE80211_VERIFY_LENGTH(_len, _minlen) do { \ if ((_len) < (_minlen)) { \ IEEE80211_DISCARD(vap, IEEE80211_MSG_ELEMID, \ wh, ieee80211_mgt_subtype_name[subtype >> \ IEEE80211_FC0_SUBTYPE_SHIFT], \ "%s", "ie too short"); \ vap->iv_stats.is_rx_elem_toosmall++; \ return 0; \ } \} while (0)#ifdef IEEE80211_DEBUGstatic voidieee80211_ssid_mismatch(struct ieee80211vap *vap, const char *tag, u_int8_t mac[IEEE80211_ADDR_LEN], u_int8_t *ssid){ printk("[" MAC_FMT "] discard %s frame, ssid mismatch: ", MAC_ADDR(mac), tag); ieee80211_print_essid(ssid + 2, ssid[1]); printk("\n");}#define IEEE80211_VERIFY_SSID(_ni, _ssid) do { \ if ((_ssid)[1] != 0 && \ ((_ssid)[1] != (_ni)->ni_esslen || \ memcmp((_ssid) + 2, (_ni)->ni_essid, (_ssid)[1]) != 0)) { \ if (ieee80211_msg_input(vap)) \ ieee80211_ssid_mismatch(vap, \ ieee80211_mgt_subtype_name[subtype >> \ IEEE80211_FC0_SUBTYPE_SHIFT], \ wh->i_addr2, _ssid); \ vap->iv_stats.is_rx_ssidmismatch++; \ return 0; \ } \} while (0)#else /* !IEEE80211_DEBUG */#define IEEE80211_VERIFY_SSID(_ni, _ssid) do { \ if ((_ssid)[1] != 0 && \ ((_ssid)[1] != (_ni)->ni_esslen || \ memcmp((_ssid) + 2, (_ni)->ni_essid, (_ssid)[1]) != 0)) { \ vap->iv_stats.is_rx_ssidmismatch++; \ return 0; \ } \} while (0)#endif /* !IEEE80211_DEBUG *//* unaligned little endian access */#define LE_READ_2(p) \ ((u_int16_t) \ ((((const u_int8_t *)(p))[0] ) | \ (((const u_int8_t *)(p))[1] << 8)))#define LE_READ_4(p) \ ((u_int32_t) \ ((((const u_int8_t *)(p))[0] ) | \ (((const u_int8_t *)(p))[1] << 8) | \ (((const u_int8_t *)(p))[2] << 16) | \ (((const u_int8_t *)(p))[3] << 24)))static __inline intiswpaoui(const u_int8_t *frm){ return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);}static __inline intiswmeoui(const u_int8_t *frm){ return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);}static __inline intiswmeparam(const u_int8_t *frm){ return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && frm[6] == WME_PARAM_OUI_SUBTYPE;}static __inline intiswmeinfo(const u_int8_t *frm){ return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && frm[6] == WME_INFO_OUI_SUBTYPE;}static __inline intisatherosoui(const u_int8_t *frm){ return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);}/* * Convert a WPA cipher selector OUI to an internal * cipher algorithm. Where appropriate we also * record any key length. */static intwpa_cipher(u_int8_t *sel, u_int8_t *keylen){#define WPA_SEL(x) (((x) << 24) | WPA_OUI) u_int32_t w = LE_READ_4(sel); switch (w) { case WPA_SEL(WPA_CSE_NULL):
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -