Module Name: src Committed By: maxv Date: Tue Jan 16 15:55:14 UTC 2018
Modified Files: src/sys/net80211: ieee80211_input.c Log Message: Introduce ieee80211_recv_mgmt_assoc_req. To generate a diff of this commit: cvs rdiff -u -r1.99 -r1.100 src/sys/net80211/ieee80211_input.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/net80211/ieee80211_input.c diff -u src/sys/net80211/ieee80211_input.c:1.99 src/sys/net80211/ieee80211_input.c:1.100 --- src/sys/net80211/ieee80211_input.c:1.99 Tue Jan 16 15:48:32 2018 +++ src/sys/net80211/ieee80211_input.c Tue Jan 16 15:55:14 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: ieee80211_input.c,v 1.99 2018/01/16 15:48:32 maxv Exp $ */ +/* $NetBSD: ieee80211_input.c,v 1.100 2018/01/16 15:55:14 maxv Exp $ */ /* * Copyright (c) 2001 Atsushi Onoe @@ -37,7 +37,7 @@ __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_input.c,v 1.81 2005/08/10 16:22:29 sam Exp $"); #endif #ifdef __NetBSD__ -__KERNEL_RCSID(0, "$NetBSD: ieee80211_input.c,v 1.99 2018/01/16 15:48:32 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ieee80211_input.c,v 1.100 2018/01/16 15:55:14 maxv Exp $"); #endif #ifdef _KERNEL_OPT @@ -2449,6 +2449,225 @@ ieee80211_recv_mgmt_auth(struct ieee8021 } } +static void +ieee80211_recv_mgmt_assoc_req(struct ieee80211com *ic, struct mbuf *m0, + struct ieee80211_node *ni, int subtype, int rssi, u_int32_t rstamp) +{ + struct ieee80211_frame *wh; + u_int8_t *frm, *efrm; + u_int8_t *ssid, *rates, *xrates, *wpa, *wme; + int reassoc, resp; + u_int8_t rate; + IEEE80211_DEBUGVAR(char ebuf[3 * ETHER_ADDR_LEN]); + + wh = mtod(m0, struct ieee80211_frame *); + frm = (u_int8_t *)(wh + 1); + efrm = mtod(m0, u_int8_t *) + m0->m_len; + + u_int16_t capinfo, lintval; + struct ieee80211_rsnparms rsn; + u_int8_t reason; + + if (ic->ic_opmode != IEEE80211_M_HOSTAP || + ic->ic_state != IEEE80211_S_RUN) { + ic->ic_stats.is_rx_mgtdiscard++; + return; + } + + if (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { + reassoc = 1; + resp = IEEE80211_FC0_SUBTYPE_REASSOC_RESP; + } else { + reassoc = 0; + resp = IEEE80211_FC0_SUBTYPE_ASSOC_RESP; + } + /* + * asreq frame format + * [2] capability information + * [2] listen interval + * [6*] current AP address (reassoc only) + * [tlv] ssid + * [tlv] supported rates + * [tlv] extended supported rates + * [tlv] WPA or RSN + */ + IEEE80211_VERIFY_LENGTH(efrm - frm, (reassoc ? 10 : 4)); + if (!IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_bss->ni_bssid)) { + IEEE80211_DISCARD(ic, IEEE80211_MSG_ANY, + wh, ieee80211_mgt_subtype_name[subtype >> + IEEE80211_FC0_SUBTYPE_SHIFT], + "%s", "wrong bssid"); + ic->ic_stats.is_rx_assoc_bss++; + return; + } + capinfo = le16toh(*(u_int16_t *)frm); frm += 2; + lintval = le16toh(*(u_int16_t *)frm); frm += 2; + if (reassoc) + frm += 6; /* ignore current AP info */ + ssid = rates = xrates = wpa = wme = NULL; + while (frm < efrm) { + switch (*frm) { + case IEEE80211_ELEMID_SSID: + ssid = frm; + break; + case IEEE80211_ELEMID_RATES: + rates = frm; + break; + case IEEE80211_ELEMID_XRATES: + xrates = frm; + break; + /* XXX verify only one of RSN and WPA ie's? */ + case IEEE80211_ELEMID_RSN: + wpa = frm; + break; + case IEEE80211_ELEMID_VENDOR: + if (iswpaoui(frm)) + wpa = frm; + else if (iswmeinfo(frm)) + wme = frm; + /* XXX Atheros OUI support */ + break; + } + frm += frm[1] + 2; + } + IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE); + IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN); + IEEE80211_VERIFY_SSID(ic->ic_bss, ssid); + + if (ni == ic->ic_bss) { + IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, + "[%s] deny %s request, sta not authenticated\n", + ether_snprintf(ebuf, sizeof(ebuf), wh->i_addr2), + reassoc ? "reassoc" : "assoc"); + ieee80211_send_error(ic, ni, wh->i_addr2, + IEEE80211_FC0_SUBTYPE_DEAUTH, + IEEE80211_REASON_ASSOC_NOT_AUTHED); + ic->ic_stats.is_rx_assoc_notauth++; + return; + } + /* assert right associstion security credentials */ + if (wpa == NULL && (ic->ic_flags & IEEE80211_F_WPA)) { + IEEE80211_DPRINTF(ic, + IEEE80211_MSG_ASSOC | IEEE80211_MSG_WPA, + "[%s] no WPA/RSN IE in association request\n", + ether_snprintf(ebuf, sizeof(ebuf), wh->i_addr2)); + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_DEAUTH, + IEEE80211_REASON_RSN_REQUIRED); + ieee80211_node_leave(ic, ni); + /* XXX distinguish WPA/RSN? */ + ic->ic_stats.is_rx_assoc_badwpaie++; + return; + } + if (wpa != NULL) { + /* + * Parse WPA information element. Note that + * we initialize the param block from the node + * state so that information in the IE overrides + * our defaults. The resulting parameters are + * installed below after the association is assured. + */ + rsn = ni->ni_rsn; + if (wpa[0] != IEEE80211_ELEMID_RSN) + reason = ieee80211_parse_wpa(ic, wpa, &rsn, wh); + else + reason = ieee80211_parse_rsn(ic, wpa, &rsn, wh); + if (reason != 0) { + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_DEAUTH, reason); + ieee80211_node_leave(ic, ni); + /* XXX distinguish WPA/RSN? */ + ic->ic_stats.is_rx_assoc_badwpaie++; + return; + } + IEEE80211_DPRINTF(ic, + IEEE80211_MSG_ASSOC | IEEE80211_MSG_WPA, + "[%s] %s ie: mc %u/%u uc %u/%u key %u caps 0x%x\n", + ether_snprintf(ebuf, sizeof(ebuf), wh->i_addr2), + wpa[0] != IEEE80211_ELEMID_RSN ? "WPA" : "RSN", + rsn.rsn_mcastcipher, rsn.rsn_mcastkeylen, + rsn.rsn_ucastcipher, rsn.rsn_ucastkeylen, + rsn.rsn_keymgmt, rsn.rsn_caps); + } + /* discard challenge after association */ + if (ni->ni_challenge != NULL) { + free(ni->ni_challenge, M_DEVBUF); + ni->ni_challenge = NULL; + } + /* NB: 802.11 spec says to ignore station's privacy bit */ + if ((capinfo & IEEE80211_CAPINFO_ESS) == 0) { + IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, + "[%s] deny %s request, capability mismatch 0x%x\n", + ether_snprintf(ebuf, sizeof(ebuf), wh->i_addr2), + reassoc ? "reassoc" : "assoc", capinfo); + IEEE80211_SEND_MGMT(ic, ni, resp, + IEEE80211_STATUS_CAPINFO); + ieee80211_node_leave(ic, ni); + ic->ic_stats.is_rx_assoc_capmismatch++; + return; + } + rate = ieee80211_setup_rates(ni, rates, xrates, + IEEE80211_R_DOSORT | IEEE80211_R_DOFRATE | + IEEE80211_R_DONEGO | IEEE80211_R_DODEL); + /* + * If constrained to 11g-only stations reject an + * 11b-only station. We cheat a bit here by looking + * at the max negotiated xmit rate and assuming anyone + * with a best rate <24Mb/s is an 11b station. + */ + if ((rate & IEEE80211_RATE_BASIC) || + ((ic->ic_flags & IEEE80211_F_PUREG) && rate < 48)) { + IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, + "[%s] deny %s request, rate set mismatch\n", + ether_snprintf(ebuf, sizeof(ebuf), wh->i_addr2), + reassoc ? "reassoc" : "assoc"); + IEEE80211_SEND_MGMT(ic, ni, resp, + IEEE80211_STATUS_BASIC_RATE); + ieee80211_node_leave(ic, ni); + ic->ic_stats.is_rx_assoc_norate++; + return; + } + ni->ni_rssi = rssi; + ni->ni_rstamp = rstamp; + ni->ni_intval = lintval; + ni->ni_capinfo = capinfo; + ni->ni_chan = ic->ic_bss->ni_chan; + ni->ni_fhdwell = ic->ic_bss->ni_fhdwell; + ni->ni_fhindex = ic->ic_bss->ni_fhindex; + if (wpa != NULL) { + /* + * Record WPA/RSN parameters for station, mark + * node as using WPA and record information element + * for applications that require it. + */ + ni->ni_rsn = rsn; + ieee80211_saveie(&ni->ni_wpa_ie, wpa); + } else if (ni->ni_wpa_ie != NULL) { + /* + * Flush any state from a previous association. + */ + free(ni->ni_wpa_ie, M_DEVBUF); + ni->ni_wpa_ie = NULL; + } + if (wme != NULL) { + /* + * Record WME parameters for station, mark node + * as capable of QoS and record information + * element for applications that require it. + */ + ieee80211_saveie(&ni->ni_wme_ie, wme); + ni->ni_flags |= IEEE80211_NODE_QOS; + } else if (ni->ni_wme_ie != NULL) { + /* + * Flush any state from a previous association. + */ + free(ni->ni_wme_ie, M_DEVBUF); + ni->ni_wme_ie = NULL; + ni->ni_flags &= ~IEEE80211_NODE_QOS; + } + ieee80211_node_join(ic, ni, resp); +} + /* -------------------------------------------------------------------------- */ void @@ -2458,8 +2677,7 @@ ieee80211_recv_mgmt(struct ieee80211com #define ISREASSOC(_st) ((_st) == IEEE80211_FC0_SUBTYPE_REASSOC_RESP) struct ieee80211_frame *wh; u_int8_t *frm, *efrm; - u_int8_t *ssid, *rates, *xrates, *wpa, *wme; - int reassoc, resp; + u_int8_t *rates, *xrates, *wpa, *wme; u_int8_t rate; IEEE80211_DEBUGVAR(char ebuf[3 * ETHER_ADDR_LEN]); @@ -2482,211 +2700,9 @@ ieee80211_recv_mgmt(struct ieee80211com return; case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: - case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: { - u_int16_t capinfo, lintval; - struct ieee80211_rsnparms rsn; - u_int8_t reason; - - if (ic->ic_opmode != IEEE80211_M_HOSTAP || - ic->ic_state != IEEE80211_S_RUN) { - ic->ic_stats.is_rx_mgtdiscard++; - return; - } - - if (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { - reassoc = 1; - resp = IEEE80211_FC0_SUBTYPE_REASSOC_RESP; - } else { - reassoc = 0; - resp = IEEE80211_FC0_SUBTYPE_ASSOC_RESP; - } - /* - * asreq frame format - * [2] capability information - * [2] listen interval - * [6*] current AP address (reassoc only) - * [tlv] ssid - * [tlv] supported rates - * [tlv] extended supported rates - * [tlv] WPA or RSN - */ - IEEE80211_VERIFY_LENGTH(efrm - frm, (reassoc ? 10 : 4)); - if (!IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_bss->ni_bssid)) { - IEEE80211_DISCARD(ic, IEEE80211_MSG_ANY, - wh, ieee80211_mgt_subtype_name[subtype >> - IEEE80211_FC0_SUBTYPE_SHIFT], - "%s", "wrong bssid"); - ic->ic_stats.is_rx_assoc_bss++; - return; - } - capinfo = le16toh(*(u_int16_t *)frm); frm += 2; - lintval = le16toh(*(u_int16_t *)frm); frm += 2; - if (reassoc) - frm += 6; /* ignore current AP info */ - ssid = rates = xrates = wpa = wme = NULL; - while (frm < efrm) { - switch (*frm) { - case IEEE80211_ELEMID_SSID: - ssid = frm; - break; - case IEEE80211_ELEMID_RATES: - rates = frm; - break; - case IEEE80211_ELEMID_XRATES: - xrates = frm; - break; - /* XXX verify only one of RSN and WPA ie's? */ - case IEEE80211_ELEMID_RSN: - wpa = frm; - break; - case IEEE80211_ELEMID_VENDOR: - if (iswpaoui(frm)) - wpa = frm; - else if (iswmeinfo(frm)) - wme = frm; - /* XXX Atheros OUI support */ - break; - } - frm += frm[1] + 2; - } - IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE); - IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN); - IEEE80211_VERIFY_SSID(ic->ic_bss, ssid); - - if (ni == ic->ic_bss) { - IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, - "[%s] deny %s request, sta not authenticated\n", - ether_snprintf(ebuf, sizeof(ebuf), wh->i_addr2), - reassoc ? "reassoc" : "assoc"); - ieee80211_send_error(ic, ni, wh->i_addr2, - IEEE80211_FC0_SUBTYPE_DEAUTH, - IEEE80211_REASON_ASSOC_NOT_AUTHED); - ic->ic_stats.is_rx_assoc_notauth++; - return; - } - /* assert right associstion security credentials */ - if (wpa == NULL && (ic->ic_flags & IEEE80211_F_WPA)) { - IEEE80211_DPRINTF(ic, - IEEE80211_MSG_ASSOC | IEEE80211_MSG_WPA, - "[%s] no WPA/RSN IE in association request\n", - ether_snprintf(ebuf, sizeof(ebuf), wh->i_addr2)); - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_DEAUTH, - IEEE80211_REASON_RSN_REQUIRED); - ieee80211_node_leave(ic, ni); - /* XXX distinguish WPA/RSN? */ - ic->ic_stats.is_rx_assoc_badwpaie++; - return; - } - if (wpa != NULL) { - /* - * Parse WPA information element. Note that - * we initialize the param block from the node - * state so that information in the IE overrides - * our defaults. The resulting parameters are - * installed below after the association is assured. - */ - rsn = ni->ni_rsn; - if (wpa[0] != IEEE80211_ELEMID_RSN) - reason = ieee80211_parse_wpa(ic, wpa, &rsn, wh); - else - reason = ieee80211_parse_rsn(ic, wpa, &rsn, wh); - if (reason != 0) { - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_DEAUTH, reason); - ieee80211_node_leave(ic, ni); - /* XXX distinguish WPA/RSN? */ - ic->ic_stats.is_rx_assoc_badwpaie++; - return; - } - IEEE80211_DPRINTF(ic, - IEEE80211_MSG_ASSOC | IEEE80211_MSG_WPA, - "[%s] %s ie: mc %u/%u uc %u/%u key %u caps 0x%x\n", - ether_snprintf(ebuf, sizeof(ebuf), wh->i_addr2), - wpa[0] != IEEE80211_ELEMID_RSN ? "WPA" : "RSN", - rsn.rsn_mcastcipher, rsn.rsn_mcastkeylen, - rsn.rsn_ucastcipher, rsn.rsn_ucastkeylen, - rsn.rsn_keymgmt, rsn.rsn_caps); - } - /* discard challenge after association */ - if (ni->ni_challenge != NULL) { - free(ni->ni_challenge, M_DEVBUF); - ni->ni_challenge = NULL; - } - /* NB: 802.11 spec says to ignore station's privacy bit */ - if ((capinfo & IEEE80211_CAPINFO_ESS) == 0) { - IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, - "[%s] deny %s request, capability mismatch 0x%x\n", - ether_snprintf(ebuf, sizeof(ebuf), wh->i_addr2), - reassoc ? "reassoc" : "assoc", capinfo); - IEEE80211_SEND_MGMT(ic, ni, resp, - IEEE80211_STATUS_CAPINFO); - ieee80211_node_leave(ic, ni); - ic->ic_stats.is_rx_assoc_capmismatch++; - return; - } - rate = ieee80211_setup_rates(ni, rates, xrates, - IEEE80211_R_DOSORT | IEEE80211_R_DOFRATE | - IEEE80211_R_DONEGO | IEEE80211_R_DODEL); - /* - * If constrained to 11g-only stations reject an - * 11b-only station. We cheat a bit here by looking - * at the max negotiated xmit rate and assuming anyone - * with a best rate <24Mb/s is an 11b station. - */ - if ((rate & IEEE80211_RATE_BASIC) || - ((ic->ic_flags & IEEE80211_F_PUREG) && rate < 48)) { - IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, - "[%s] deny %s request, rate set mismatch\n", - ether_snprintf(ebuf, sizeof(ebuf), wh->i_addr2), - reassoc ? "reassoc" : "assoc"); - IEEE80211_SEND_MGMT(ic, ni, resp, - IEEE80211_STATUS_BASIC_RATE); - ieee80211_node_leave(ic, ni); - ic->ic_stats.is_rx_assoc_norate++; - return; - } - ni->ni_rssi = rssi; - ni->ni_rstamp = rstamp; - ni->ni_intval = lintval; - ni->ni_capinfo = capinfo; - ni->ni_chan = ic->ic_bss->ni_chan; - ni->ni_fhdwell = ic->ic_bss->ni_fhdwell; - ni->ni_fhindex = ic->ic_bss->ni_fhindex; - if (wpa != NULL) { - /* - * Record WPA/RSN parameters for station, mark - * node as using WPA and record information element - * for applications that require it. - */ - ni->ni_rsn = rsn; - ieee80211_saveie(&ni->ni_wpa_ie, wpa); - } else if (ni->ni_wpa_ie != NULL) { - /* - * Flush any state from a previous association. - */ - free(ni->ni_wpa_ie, M_DEVBUF); - ni->ni_wpa_ie = NULL; - } - if (wme != NULL) { - /* - * Record WME parameters for station, mark node - * as capable of QoS and record information - * element for applications that require it. - */ - ieee80211_saveie(&ni->ni_wme_ie, wme); - ni->ni_flags |= IEEE80211_NODE_QOS; - } else if (ni->ni_wme_ie != NULL) { - /* - * Flush any state from a previous association. - */ - free(ni->ni_wme_ie, M_DEVBUF); - ni->ni_wme_ie = NULL; - ni->ni_flags &= ~IEEE80211_NODE_QOS; - } - ieee80211_node_join(ic, ni, resp); - break; - } + case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: + ieee80211_recv_mgmt_assoc_req(ic, m0, ni, subtype, rssi, rstamp); + return; case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: {