Module Name: src
Committed By: maxv
Date: Tue Jan 16 15:42:52 UTC 2018
Modified Files:
src/sys/net80211: ieee80211_input.c
Log Message:
Start splitting ieee80211_recv_mgmt.
To generate a diff of this commit:
cvs rdiff -u -r1.97 -r1.98 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.97 src/sys/net80211/ieee80211_input.c:1.98
--- src/sys/net80211/ieee80211_input.c:1.97 Tue Jan 16 15:18:37 2018
+++ src/sys/net80211/ieee80211_input.c Tue Jan 16 15:42:52 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: ieee80211_input.c,v 1.97 2018/01/16 15:18:37 maxv Exp $ */
+/* $NetBSD: ieee80211_input.c,v 1.98 2018/01/16 15:42:52 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.97 2018/01/16 15:18:37 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ieee80211_input.c,v 1.98 2018/01/16 15:42:52 maxv Exp $");
#endif
#ifdef _KERNEL_OPT
@@ -2001,369 +2001,403 @@ ieee80211_update_adhoc_node(struct ieee8
}
}
-void
-ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
+/* -------------------------------------------------------------------------- */
+
+static void
+ieee80211_recv_mgmt_beacon(struct ieee80211com *ic, struct mbuf *m0,
struct ieee80211_node *ni, int subtype, int rssi, u_int32_t rstamp)
{
-#define ISPROBE(_st) ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
-#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, allocbs;
- u_int8_t rate;
IEEE80211_DEBUGVAR(char ebuf[3 * ETHER_ADDR_LEN]);
+ struct ieee80211_scanparams scan;
wh = mtod(m0, struct ieee80211_frame *);
frm = (u_int8_t *)(wh + 1);
efrm = mtod(m0, u_int8_t *) + m0->m_len;
- switch (subtype) {
- case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
- case IEEE80211_FC0_SUBTYPE_BEACON: {
- struct ieee80211_scanparams scan;
-
- /*
- * We process beacon/probe response frames:
- * o when scanning, or
- * o station mode when associated (to collect state
- * updates such as 802.11g slot time), or
- * o adhoc mode (to discover neighbors)
- * Frames otherwise received are discarded.
- */
- if (!((ic->ic_flags & IEEE80211_F_SCAN) ||
- (ic->ic_opmode == IEEE80211_M_STA && ni->ni_associd) ||
- ic->ic_opmode == IEEE80211_M_IBSS)) {
- ic->ic_stats.is_rx_mgtdiscard++;
- return;
- }
-
- /*
- * beacon/probe response frame format
- * [8] time stamp
- * [2] beacon interval
- * [2] capability information
- * [tlv] ssid
- * [tlv] supported rates
- * [tlv] country information
- * [tlv] parameter set (FH/DS)
- * [tlv] erp information
- * [tlv] extended supported rates
- * [tlv] WME
- * [tlv] WPA or RSN
- */
- IEEE80211_VERIFY_LENGTH(efrm - frm, 12);
- memset(&scan, 0, sizeof(scan));
- scan.tstamp = frm; frm += 8;
- scan.bintval = le16toh(*(u_int16_t *)frm); frm += 2;
- scan.capinfo = le16toh(*(u_int16_t *)frm); frm += 2;
- scan.bchan = ieee80211_chan2ieee(ic, ic->ic_curchan);
- scan.chan = scan.bchan;
-
- while (frm + 1 < efrm) {
- IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2);
+ /*
+ * We process beacon/probe response frames:
+ * o when scanning, or
+ * o station mode when associated (to collect state
+ * updates such as 802.11g slot time), or
+ * o adhoc mode (to discover neighbors)
+ * Frames otherwise received are discarded.
+ */
+ if (!((ic->ic_flags & IEEE80211_F_SCAN) ||
+ (ic->ic_opmode == IEEE80211_M_STA && ni->ni_associd) ||
+ ic->ic_opmode == IEEE80211_M_IBSS)) {
+ ic->ic_stats.is_rx_mgtdiscard++;
+ return;
+ }
- switch (*frm) {
- case IEEE80211_ELEMID_SSID:
- scan.ssid = frm;
- break;
- case IEEE80211_ELEMID_RATES:
- scan.rates = frm;
- break;
- case IEEE80211_ELEMID_COUNTRY:
- scan.country = frm;
- break;
- case IEEE80211_ELEMID_FHPARMS:
- IEEE80211_VERIFY_LENGTH(frm[1], 5);
- if (ic->ic_phytype == IEEE80211_T_FH) {
- scan.fhdwell = LE_READ_2(&frm[2]);
- scan.chan = IEEE80211_FH_CHAN(frm[4], frm[5]);
- scan.fhindex = frm[6];
- }
- break;
- case IEEE80211_ELEMID_DSPARMS:
- /*
- * XXX hack this since depending on phytype
- * is problematic for multi-mode devices.
- */
- IEEE80211_VERIFY_LENGTH(frm[1], 1);
- if (ic->ic_phytype != IEEE80211_T_FH)
- scan.chan = frm[2];
- break;
- case IEEE80211_ELEMID_TIM:
- /* XXX ATIM? */
- IEEE80211_VERIFY_LENGTH(frm[1], 5);
- scan.tim = frm;
- scan.timoff = frm - mtod(m0, u_int8_t *);
- break;
- case IEEE80211_ELEMID_IBSSPARMS:
- break;
- case IEEE80211_ELEMID_XRATES:
- scan.xrates = frm;
- break;
- case IEEE80211_ELEMID_ERP:
- if (frm[1] != 1) {
- IEEE80211_DISCARD_IE(ic,
- IEEE80211_MSG_ELEMID, wh, "ERP",
- "bad len %u", frm[1]);
- ic->ic_stats.is_rx_elem_toobig++;
- break;
- }
- scan.erp = frm[2];
- break;
- case IEEE80211_ELEMID_RSN:
- scan.wpa = frm;
- break;
- case IEEE80211_ELEMID_VENDOR:
- if (iswpaoui(frm))
- scan.wpa = frm;
- else if (iswmeparam(frm) || iswmeinfo(frm))
- scan.wme = frm;
- /* XXX Atheros OUI support */
- break;
- default:
- IEEE80211_DISCARD_IE(ic, IEEE80211_MSG_ELEMID,
- wh, "unhandled",
- "id %u, len %u", *frm, frm[1]);
- ic->ic_stats.is_rx_elem_unknown++;
+ /*
+ * beacon/probe response frame format
+ * [8] time stamp
+ * [2] beacon interval
+ * [2] capability information
+ * [tlv] ssid
+ * [tlv] supported rates
+ * [tlv] country information
+ * [tlv] parameter set (FH/DS)
+ * [tlv] erp information
+ * [tlv] extended supported rates
+ * [tlv] WME
+ * [tlv] WPA or RSN
+ */
+ IEEE80211_VERIFY_LENGTH(efrm - frm, 12);
+ memset(&scan, 0, sizeof(scan));
+ scan.tstamp = frm; frm += 8;
+ scan.bintval = le16toh(*(u_int16_t *)frm); frm += 2;
+ scan.capinfo = le16toh(*(u_int16_t *)frm); frm += 2;
+ scan.bchan = ieee80211_chan2ieee(ic, ic->ic_curchan);
+ scan.chan = scan.bchan;
+
+ while (frm + 1 < efrm) {
+ IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2);
+
+ switch (*frm) {
+ case IEEE80211_ELEMID_SSID:
+ scan.ssid = frm;
+ break;
+ case IEEE80211_ELEMID_RATES:
+ scan.rates = frm;
+ break;
+ case IEEE80211_ELEMID_COUNTRY:
+ scan.country = frm;
+ break;
+ case IEEE80211_ELEMID_FHPARMS:
+ IEEE80211_VERIFY_LENGTH(frm[1], 5);
+ if (ic->ic_phytype == IEEE80211_T_FH) {
+ scan.fhdwell = LE_READ_2(&frm[2]);
+ scan.chan = IEEE80211_FH_CHAN(frm[4], frm[5]);
+ scan.fhindex = frm[6];
+ }
+ break;
+ case IEEE80211_ELEMID_DSPARMS:
+ /*
+ * XXX hack this since depending on phytype
+ * is problematic for multi-mode devices.
+ */
+ IEEE80211_VERIFY_LENGTH(frm[1], 1);
+ if (ic->ic_phytype != IEEE80211_T_FH)
+ scan.chan = frm[2];
+ break;
+ case IEEE80211_ELEMID_TIM:
+ /* XXX ATIM? */
+ IEEE80211_VERIFY_LENGTH(frm[1], 5);
+ scan.tim = frm;
+ scan.timoff = frm - mtod(m0, u_int8_t *);
+ break;
+ case IEEE80211_ELEMID_IBSSPARMS:
+ break;
+ case IEEE80211_ELEMID_XRATES:
+ scan.xrates = frm;
+ break;
+ case IEEE80211_ELEMID_ERP:
+ if (frm[1] != 1) {
+ IEEE80211_DISCARD_IE(ic,
+ IEEE80211_MSG_ELEMID, wh, "ERP",
+ "bad len %u", frm[1]);
+ ic->ic_stats.is_rx_elem_toobig++;
break;
}
-
- frm += frm[1] + 2;
+ scan.erp = frm[2];
+ break;
+ case IEEE80211_ELEMID_RSN:
+ scan.wpa = frm;
+ break;
+ case IEEE80211_ELEMID_VENDOR:
+ if (iswpaoui(frm))
+ scan.wpa = frm;
+ else if (iswmeparam(frm) || iswmeinfo(frm))
+ scan.wme = frm;
+ /* XXX Atheros OUI support */
+ break;
+ default:
+ IEEE80211_DISCARD_IE(ic, IEEE80211_MSG_ELEMID,
+ wh, "unhandled",
+ "id %u, len %u", *frm, frm[1]);
+ ic->ic_stats.is_rx_elem_unknown++;
+ break;
}
- IEEE80211_VERIFY_ELEMENT(scan.rates, IEEE80211_RATE_MAXSIZE);
- IEEE80211_VERIFY_ELEMENT(scan.ssid, IEEE80211_NWID_LEN);
+ frm += frm[1] + 2;
+ }
- if (
+ IEEE80211_VERIFY_ELEMENT(scan.rates, IEEE80211_RATE_MAXSIZE);
+ IEEE80211_VERIFY_ELEMENT(scan.ssid, IEEE80211_NWID_LEN);
+
+ if (
#if IEEE80211_CHAN_MAX < 255
- scan.chan > IEEE80211_CHAN_MAX ||
+ scan.chan > IEEE80211_CHAN_MAX ||
#endif
- isclr(ic->ic_chan_active, scan.chan)) {
- IEEE80211_DISCARD(ic,
- IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
- wh, ieee80211_mgt_subtype_name[subtype >>
- IEEE80211_FC0_SUBTYPE_SHIFT],
- "invalid channel %u", scan.chan);
- ic->ic_stats.is_rx_badchan++;
- return;
+ isclr(ic->ic_chan_active, scan.chan)) {
+ IEEE80211_DISCARD(ic,
+ IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
+ wh, ieee80211_mgt_subtype_name[subtype >>
+ IEEE80211_FC0_SUBTYPE_SHIFT],
+ "invalid channel %u", scan.chan);
+ ic->ic_stats.is_rx_badchan++;
+ return;
+ }
+ if (scan.chan != scan.bchan &&
+ ic->ic_phytype != IEEE80211_T_FH) {
+ /*
+ * Frame was received on a channel different from the
+ * one indicated in the DS params element id;
+ * silently discard it.
+ *
+ * NB: this can happen due to signal leakage.
+ * But we should take it for FH phy because
+ * the rssi value should be correct even for
+ * different hop pattern in FH.
+ */
+ IEEE80211_DISCARD(ic,
+ IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
+ wh, ieee80211_mgt_subtype_name[subtype >>
+ IEEE80211_FC0_SUBTYPE_SHIFT],
+ "for off-channel %u", scan.chan);
+ ic->ic_stats.is_rx_chanmismatch++;
+ return;
+ }
+ if (!(IEEE80211_BINTVAL_MIN <= scan.bintval &&
+ scan.bintval <= IEEE80211_BINTVAL_MAX)) {
+ IEEE80211_DISCARD(ic,
+ IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
+ wh, ieee80211_mgt_subtype_name[subtype >>
+ IEEE80211_FC0_SUBTYPE_SHIFT],
+ "bogus beacon interval", scan.bintval);
+ ic->ic_stats.is_rx_badbintval++;
+ return;
+ }
+
+ if (ni != ic->ic_bss) {
+ ni = ieee80211_refine_node_for_beacon(ic, ni,
+ &ic->ic_channels[scan.chan], scan.ssid);
+ }
+ /*
+ * Count frame now that we know it's to be processed.
+ */
+ if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) {
+ ic->ic_stats.is_rx_beacon++; /* XXX remove */
+ IEEE80211_NODE_STAT(ni, rx_beacons);
+ } else
+ IEEE80211_NODE_STAT(ni, rx_proberesp);
+
+ /*
+ * When operating in station mode, check for state updates.
+ * Be careful to ignore beacons received while doing a
+ * background scan. We consider only 11g/WMM stuff right now.
+ */
+ if (ic->ic_opmode == IEEE80211_M_STA &&
+ ni->ni_associd != 0 &&
+ ((ic->ic_flags & IEEE80211_F_SCAN) == 0 ||
+ IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid))) {
+ /* record tsf of last beacon */
+ memcpy(ni->ni_tstamp.data, scan.tstamp,
+ sizeof(ni->ni_tstamp));
+ if (ni->ni_erp != scan.erp) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
+ "[%s] erp change: was 0x%x, now 0x%x\n",
+ ether_snprintf(ebuf, sizeof(ebuf),
+ wh->i_addr2), ni->ni_erp, scan.erp);
+ if (ic->ic_curmode == IEEE80211_MODE_11G &&
+ (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION))
+ ic->ic_flags |= IEEE80211_F_USEPROT;
+ else
+ ic->ic_flags &= ~IEEE80211_F_USEPROT;
+ ni->ni_erp = scan.erp;
+ /* XXX statistic */
}
- if (scan.chan != scan.bchan &&
- ic->ic_phytype != IEEE80211_T_FH) {
+ if ((ni->ni_capinfo ^ scan.capinfo) & IEEE80211_CAPINFO_SHORT_SLOTTIME) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
+ "[%s] capabilities change: before 0x%x,"
+ " now 0x%x\n",
+ ether_snprintf(ebuf, sizeof(ebuf),
+ wh->i_addr2),
+ ni->ni_capinfo, scan.capinfo);
/*
- * Frame was received on a channel different from the
- * one indicated in the DS params element id;
- * silently discard it.
- *
- * NB: this can happen due to signal leakage.
- * But we should take it for FH phy because
- * the rssi value should be correct even for
- * different hop pattern in FH.
+ * NB: we assume short preamble doesn't
+ * change dynamically
*/
- IEEE80211_DISCARD(ic,
- IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
- wh, ieee80211_mgt_subtype_name[subtype >>
- IEEE80211_FC0_SUBTYPE_SHIFT],
- "for off-channel %u", scan.chan);
- ic->ic_stats.is_rx_chanmismatch++;
- return;
- }
- if (!(IEEE80211_BINTVAL_MIN <= scan.bintval &&
- scan.bintval <= IEEE80211_BINTVAL_MAX)) {
- IEEE80211_DISCARD(ic,
- IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
- wh, ieee80211_mgt_subtype_name[subtype >>
- IEEE80211_FC0_SUBTYPE_SHIFT],
- "bogus beacon interval", scan.bintval);
- ic->ic_stats.is_rx_badbintval++;
- return;
- }
-
- if (ni != ic->ic_bss) {
- ni = ieee80211_refine_node_for_beacon(ic, ni,
- &ic->ic_channels[scan.chan], scan.ssid);
- }
- /*
- * Count frame now that we know it's to be processed.
- */
- if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) {
- ic->ic_stats.is_rx_beacon++; /* XXX remove */
- IEEE80211_NODE_STAT(ni, rx_beacons);
- } else
- IEEE80211_NODE_STAT(ni, rx_proberesp);
+ ieee80211_set_shortslottime(ic,
+ ic->ic_curmode == IEEE80211_MODE_11A ||
+ (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME));
+ ni->ni_capinfo = scan.capinfo;
+ /* XXX statistic */
+ }
+ if (scan.wme != NULL &&
+ (ni->ni_flags & IEEE80211_NODE_QOS) &&
+ ieee80211_parse_wmeparams(ic, scan.wme, wh) > 0)
+ ieee80211_wme_updateparams(ic);
+ if (scan.tim != NULL) {
+ struct ieee80211_tim_ie *ie =
+ (struct ieee80211_tim_ie *) scan.tim;
- /*
- * When operating in station mode, check for state updates.
- * Be careful to ignore beacons received while doing a
- * background scan. We consider only 11g/WMM stuff right now.
- */
- if (ic->ic_opmode == IEEE80211_M_STA &&
- ni->ni_associd != 0 &&
- ((ic->ic_flags & IEEE80211_F_SCAN) == 0 ||
- IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid))) {
- /* record tsf of last beacon */
- memcpy(ni->ni_tstamp.data, scan.tstamp,
- sizeof(ni->ni_tstamp));
- if (ni->ni_erp != scan.erp) {
- IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
- "[%s] erp change: was 0x%x, now 0x%x\n",
- ether_snprintf(ebuf, sizeof(ebuf),
- wh->i_addr2), ni->ni_erp, scan.erp);
- if (ic->ic_curmode == IEEE80211_MODE_11G &&
- (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION))
- ic->ic_flags |= IEEE80211_F_USEPROT;
- else
- ic->ic_flags &= ~IEEE80211_F_USEPROT;
- ni->ni_erp = scan.erp;
- /* XXX statistic */
- }
- if ((ni->ni_capinfo ^ scan.capinfo) & IEEE80211_CAPINFO_SHORT_SLOTTIME) {
- IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
- "[%s] capabilities change: before 0x%x,"
- " now 0x%x\n",
- ether_snprintf(ebuf, sizeof(ebuf),
- wh->i_addr2),
- ni->ni_capinfo, scan.capinfo);
- /*
- * NB: we assume short preamble doesn't
- * change dynamically
- */
- ieee80211_set_shortslottime(ic,
- ic->ic_curmode == IEEE80211_MODE_11A ||
- (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME));
- ni->ni_capinfo = scan.capinfo;
- /* XXX statistic */
- }
- if (scan.wme != NULL &&
- (ni->ni_flags & IEEE80211_NODE_QOS) &&
- ieee80211_parse_wmeparams(ic, scan.wme, wh) > 0)
- ieee80211_wme_updateparams(ic);
- if (scan.tim != NULL) {
- struct ieee80211_tim_ie *ie =
- (struct ieee80211_tim_ie *) scan.tim;
-
- ni->ni_dtim_count = ie->tim_count;
- ni->ni_dtim_period = ie->tim_period;
- }
- if (ic->ic_flags & IEEE80211_F_SCAN)
- ieee80211_add_scan(ic, &scan, wh,
- subtype, rssi, rstamp);
- ic->ic_bmiss_count = 0;
- return;
+ ni->ni_dtim_count = ie->tim_count;
+ ni->ni_dtim_period = ie->tim_period;
}
- /*
- * If scanning, just pass information to the scan module.
- */
- if (ic->ic_flags & IEEE80211_F_SCAN) {
- if (ic->ic_flags_ext & IEEE80211_FEXT_PROBECHAN) {
- /*
- * Actively scanning a channel marked passive;
- * send a probe request now that we know there
- * is 802.11 traffic present.
- *
- * XXX check if the beacon we recv'd gives
- * us what we need and suppress the probe req
- */
- ieee80211_probe_curchan(ic, 1);
- ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
- }
+ if (ic->ic_flags & IEEE80211_F_SCAN)
ieee80211_add_scan(ic, &scan, wh,
subtype, rssi, rstamp);
- return;
- }
- if (scan.capinfo & IEEE80211_CAPINFO_IBSS)
- ieee80211_update_adhoc_node(ic, ni, wh, &scan, rssi,
- rstamp);
- break;
+ ic->ic_bmiss_count = 0;
+ return;
}
- case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
- if (ic->ic_opmode == IEEE80211_M_STA ||
- ic->ic_state != IEEE80211_S_RUN) {
- ic->ic_stats.is_rx_mgtdiscard++;
- return;
+ /*
+ * If scanning, just pass information to the scan module.
+ */
+ if (ic->ic_flags & IEEE80211_F_SCAN) {
+ if (ic->ic_flags_ext & IEEE80211_FEXT_PROBECHAN) {
+ /*
+ * Actively scanning a channel marked passive;
+ * send a probe request now that we know there
+ * is 802.11 traffic present.
+ *
+ * XXX check if the beacon we recv'd gives
+ * us what we need and suppress the probe req
+ */
+ ieee80211_probe_curchan(ic, 1);
+ ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
}
- if (IEEE80211_IS_MULTICAST(wh->i_addr2)) {
- /* frame must be directed */
- ic->ic_stats.is_rx_mgtdiscard++; /* XXX stat */
- return;
+ ieee80211_add_scan(ic, &scan, wh,
+ subtype, rssi, rstamp);
+ return;
+ }
+ if (scan.capinfo & IEEE80211_CAPINFO_IBSS)
+ ieee80211_update_adhoc_node(ic, ni, wh, &scan, rssi, rstamp);
+}
+
+static void
+ieee80211_recv_mgmt_probe_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;
+ int allocbs;
+ 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;
+
+ if (ic->ic_opmode == IEEE80211_M_STA ||
+ ic->ic_state != IEEE80211_S_RUN) {
+ ic->ic_stats.is_rx_mgtdiscard++;
+ return;
+ }
+ if (IEEE80211_IS_MULTICAST(wh->i_addr2)) {
+ /* frame must be directed */
+ ic->ic_stats.is_rx_mgtdiscard++; /* XXX stat */
+ return;
+ }
+
+ /*
+ * prreq frame format
+ * [tlv] ssid
+ * [tlv] supported rates
+ * [tlv] extended supported rates
+ */
+ ssid = rates = xrates = 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;
}
+ 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 ((ic->ic_flags & IEEE80211_F_HIDESSID) && ssid[1] == 0) {
+ IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
+ wh, ieee80211_mgt_subtype_name[subtype >>
+ IEEE80211_FC0_SUBTYPE_SHIFT],
+ "%s", "no ssid with ssid suppression enabled");
+ ic->ic_stats.is_rx_ssidmismatch++; /*XXX*/
+ return;
+ }
- /*
- * prreq frame format
- * [tlv] ssid
- * [tlv] supported rates
- * [tlv] extended supported rates
- */
- ssid = rates = xrates = 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;
- }
- frm += frm[1] + 2;
+ if (ni == ic->ic_bss) {
+ if (ic->ic_opmode != IEEE80211_M_IBSS)
+ ni = ieee80211_tmp_node(ic, wh->i_addr2);
+ else if (IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr))
+ ;
+ else {
+ /*
+ * XXX Cannot tell if the sender is operating
+ * in ibss mode. But we need a new node to
+ * send the response so blindly add them to the
+ * neighbor table.
+ */
+ ni = ieee80211_fakeup_adhoc_node(&ic->ic_sta,
+ wh->i_addr2);
}
- IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE);
- IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN);
- IEEE80211_VERIFY_SSID(ic->ic_bss, ssid);
- if ((ic->ic_flags & IEEE80211_F_HIDESSID) && ssid[1] == 0) {
- IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
- wh, ieee80211_mgt_subtype_name[subtype >>
- IEEE80211_FC0_SUBTYPE_SHIFT],
- "%s", "no ssid with ssid suppression enabled");
- ic->ic_stats.is_rx_ssidmismatch++; /*XXX*/
+ if (ni == NULL)
return;
- }
+ allocbs = 1;
+ } else
+ allocbs = 0;
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
+ "[%s] recv probe req\n", ether_snprintf(
+ ebuf, sizeof(ebuf), wh->i_addr2));
+ ni->ni_rssi = rssi;
+ ni->ni_rstamp = rstamp;
+ rate = ieee80211_setup_rates(ni, rates, xrates,
+ IEEE80211_R_DOSORT | IEEE80211_R_DOFRATE
+ | IEEE80211_R_DONEGO | IEEE80211_R_DODEL);
+ if (rate & IEEE80211_RATE_BASIC) {
+ IEEE80211_DISCARD(ic, IEEE80211_MSG_XRATE,
+ wh, ieee80211_mgt_subtype_name[subtype >>
+ IEEE80211_FC0_SUBTYPE_SHIFT],
+ "%s", "recv'd rate set invalid");
+ } else {
+ IEEE80211_SEND_MGMT(ic, ni,
+ IEEE80211_FC0_SUBTYPE_PROBE_RESP, 0);
+ }
+ if (allocbs && ic->ic_opmode != IEEE80211_M_IBSS) {
+ /* reclaim immediately */
+ ieee80211_free_node(ni);
+ }
+}
- if (ni == ic->ic_bss) {
- if (ic->ic_opmode != IEEE80211_M_IBSS)
- ni = ieee80211_tmp_node(ic, wh->i_addr2);
- else if (IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr))
- ;
- else {
- /*
- * XXX Cannot tell if the sender is operating
- * in ibss mode. But we need a new node to
- * send the response so blindly add them to the
- * neighbor table.
- */
- ni = ieee80211_fakeup_adhoc_node(&ic->ic_sta,
- wh->i_addr2);
- }
- if (ni == NULL)
- return;
- allocbs = 1;
- } else
- allocbs = 0;
- IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
- "[%s] recv probe req\n", ether_snprintf(
- ebuf, sizeof(ebuf), wh->i_addr2));
- ni->ni_rssi = rssi;
- ni->ni_rstamp = rstamp;
- rate = ieee80211_setup_rates(ni, rates, xrates,
- IEEE80211_R_DOSORT | IEEE80211_R_DOFRATE
- | IEEE80211_R_DONEGO | IEEE80211_R_DODEL);
- if (rate & IEEE80211_RATE_BASIC) {
- IEEE80211_DISCARD(ic, IEEE80211_MSG_XRATE,
- wh, ieee80211_mgt_subtype_name[subtype >>
- IEEE80211_FC0_SUBTYPE_SHIFT],
- "%s", "recv'd rate set invalid");
- } else {
- IEEE80211_SEND_MGMT(ic, ni,
- IEEE80211_FC0_SUBTYPE_PROBE_RESP, 0);
- }
- if (allocbs && ic->ic_opmode != IEEE80211_M_IBSS) {
- /* reclaim immediately */
- ieee80211_free_node(ni);
- }
- break;
+/* -------------------------------------------------------------------------- */
+
+void
+ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
+ struct ieee80211_node *ni, int subtype, int rssi, u_int32_t rstamp)
+{
+#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 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;
+
+ switch (subtype) {
+ case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
+ case IEEE80211_FC0_SUBTYPE_BEACON:
+ ieee80211_recv_mgmt_beacon(ic, m0, ni, subtype, rssi, rstamp);
+ return;
+
+ case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
+ ieee80211_recv_mgmt_probe_req(ic, m0, ni, subtype, rssi, rstamp);
+ return;
case IEEE80211_FC0_SUBTYPE_AUTH: {
u_int16_t algo, seq, status;
@@ -2855,7 +2889,6 @@ ieee80211_recv_mgmt(struct ieee80211com
break;
}
#undef ISREASSOC
-#undef ISPROBE
}
#undef IEEE80211_VERIFY_LENGTH
#undef IEEE80211_VERIFY_ELEMENT