PERFORCE change 47057 for review
Sam Leffler
sam at FreeBSD.org
Mon Feb 16 14:44:26 PST 2004
http://perforce.freebsd.org/chv.cgi?CH=47057
Change 47057 by sam at sam_ebb on 2004/02/16 14:44:05
backport madwifi work for 802.1x and 11g:
o redo pspoll receive handling to eliminate extra node lookup
(already had the node in hand)
o pull out doprint logic into a separate function
o redo input path so pspoll control frames are not discarded
because of frame length
o correct authorized port check
o correct refcnt reclamation when doing internal bridge work
o replace uess of ieee80211_alloc_node with ieee80211_dup_bss
so new nodes properly inherit state
o correct problem where existing nodes weren't having their
rssi+rstamp updated on reassociation and the like
o pull out shared key challenge allocation work into a routine
o replace explicit arc4random usage with get_random_bytes
portability wrapper
o move is_rx_nodealloc counter to the node allocation routines
o use new privacy capability flag instead of WEP usage
o move aid management code to ieee80211_node_leave
o correct check for running out of aid's
o add callbacks to the authenticator when stations associate
and deassociate (this kicks the 802.1x state machine)
o fix two refcnt leaks that could occur in error conditions
Affected files ...
.. //depot/projects/netperf+sockets/sys/net80211/ieee80211_input.c#17 edit
Differences ...
==== //depot/projects/netperf+sockets/sys/net80211/ieee80211_input.c#17 (text+ko) ====
@@ -73,8 +73,28 @@
static struct mbuf *ieee80211_defrag(struct ieee80211com *,
struct ieee80211_node *, struct mbuf *);
static struct mbuf *ieee80211_decap(struct ieee80211com *, struct mbuf *);
-static void ieee80211_recv_pspoll(struct ieee80211com *, struct mbuf *,
- int rssi, u_int32_t rstamp);
+static void ieee80211_recv_pspoll(struct ieee80211com *,
+ struct ieee80211_node *, struct mbuf *);
+
+#ifdef IEEE80211_DEBUG
+/*
+ * Decide if a received frame management frame should
+ * printed when debugging is enabled. This filters some
+ * of the less interesting frames that come frequently
+ * (e.g. beacons).
+ */
+static __inline int
+doprint(struct ieee80211com *ic, int subtype)
+{
+ switch (subtype) {
+ case IEEE80211_FC0_SUBTYPE_BEACON:
+ return (ic->ic_state == IEEE80211_S_SCAN);
+ case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
+ return (ic->ic_opmode == IEEE80211_M_IBSS);
+ }
+ return 1;
+}
+#endif
/*
* Process a received frame. The node associated with the sender
@@ -93,7 +113,6 @@
struct ifnet *ifp = ic->ic_ifp;
struct ieee80211_frame *wh;
struct ether_header *eh;
- struct mbuf *m1;
int len;
u_int8_t dir, type, subtype;
u_int8_t *bssid;
@@ -109,16 +128,30 @@
KASSERT(m->m_pkthdr.len >= sizeof(struct ieee80211_frame_min),
("frame length too short: %u", m->m_pkthdr.len));
+
/*
* In monitor mode, send everything directly to bpf.
* Also do not process frames w/o i_addr2 any further.
* XXX may want to include the CRC
*/
- if (ic->ic_opmode == IEEE80211_M_MONITOR ||
- m->m_pkthdr.len < sizeof(struct ieee80211_frame_min))
+ if (ic->ic_opmode == IEEE80211_M_MONITOR)
goto out;
+ if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min)) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
+ ("%s: frame too short, len %u\n",
+ __func__, m->m_pkthdr.len));
+ ic->ic_stats.is_rx_tooshort++;
+ goto out;
+ }
+ /*
+ * Bit of a cheat here, we use a pointer for a 3-address
+ * frame format but don't reference fields past outside
+ * ieee80211_frame_min w/o first validating the data is
+ * present.
+ */
wh = mtod(m, struct ieee80211_frame *);
+
if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
IEEE80211_FC0_VERSION_0) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
@@ -130,19 +163,7 @@
dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
- /*
- * NB: We are not yet prepared to handle control frames,
- * but permitting drivers to send them to us allows
- * them to go through bpf tapping at the 802.11 layer.
- */
- if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) {
- /* XXX statistic */
- IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
- ("%s: frame too short, len %u\n",
- __func__, m->m_pkthdr.len));
- ic->ic_stats.is_rx_tooshort++;
- goto out; /* XXX */
- }
+ subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
if (ic->ic_state != IEEE80211_S_SCAN) {
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
@@ -160,9 +181,17 @@
case IEEE80211_M_IBSS:
case IEEE80211_M_AHDEMO:
case IEEE80211_M_HOSTAP:
- if (dir == IEEE80211_FC1_DIR_NODS)
+ if (dir == IEEE80211_FC1_DIR_NODS) {
+ if (m->m_pkthdr.len <
+ sizeof(struct ieee80211_frame)) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
+ ("%s: frame too short, len %u\n",
+ __func__, m->m_pkthdr.len));
+ ic->ic_stats.is_rx_tooshort++;
+ goto out;
+ }
bssid = wh->i_addr3;
- else
+ } else
bssid = wh->i_addr1;
if (!IEEE80211_ADDR_EQ(bssid, ic->ic_bss->ni_bssid) &&
!IEEE80211_ADDR_EQ(bssid, ifp->if_broadcastaddr) &&
@@ -170,15 +199,13 @@
IEEE80211_FC0_TYPE_DATA) {
/* not interested in */
IEEE80211_DPRINTF(ic, IEEE80211_MSG_INPUT,
- ("[%s] discard frame from bss %s\n",
- ieee80211_state_name[ic->ic_state],
- ether_sprintf(bssid)));
+ ("[%s] discard frame from bss %s\n",
+ ieee80211_state_name[ic->ic_state],
+ ether_sprintf(bssid)));
ic->ic_stats.is_rx_wrongbss++;
goto out;
}
break;
- case IEEE80211_M_MONITOR:
- goto out;
default:
/* XXX catch bad values */
goto out;
@@ -202,7 +229,7 @@
ic->ic_stats.is_rx_dup++; /* XXX per-station stat */
goto out;
}
- ni->ni_inact = 0;
+ ni->ni_inact = 0; /* XXX move up? */
}
/*
@@ -237,6 +264,13 @@
switch (type) {
case IEEE80211_FC0_TYPE_DATA:
+ if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
+ ("%s: data frame too short, len %u\n",
+ __func__, m->m_pkthdr.len));
+ ic->ic_stats.is_rx_tooshort++;
+ goto out; /* XXX */
+ }
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
if (dir != IEEE80211_FC1_DIR_FROMDS) {
@@ -275,7 +309,7 @@
IEEE80211_DPRINTF(ic, IEEE80211_MSG_INPUT,
("%s: data from unknown src %s\n",
__func__, ether_sprintf(wh->i_addr2)));
- /* NB: caller deals with reference */
+ /* NB: caller deals with reference to ic_bss */
ni = ieee80211_dup_bss(ic, wh->i_addr2);
if (ni != NULL) {
IEEE80211_SEND_MGMT(ic, ni,
@@ -296,22 +330,9 @@
ic->ic_stats.is_rx_notassoc++;
goto err;
}
- /*
- * When station is to be authenticated with 802.1x
- * deny any data frames until authentication has
- * been completed.
- */
- if (ni->ni_authmode == IEEE80211_AUTH_8021X &&
- (ni->ni_flags & IEEE80211_NODE_AUTH) == 0) {
- IEEE80211_DPRINTF(ic, IEEE80211_MSG_INPUT,
- ("%s: data from unauthenticated src %s\n",
- __func__, ether_sprintf(wh->i_addr2)));
- ic->ic_stats.is_rx_not1xauth++;
- /* XXX node statistic */
- goto err;
- }
break;
- case IEEE80211_M_MONITOR:
+ default:
+ /* XXX here to keep compiler happy */
break;
}
if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
@@ -351,12 +372,28 @@
ic->ic_stats.is_rx_decap++;
goto err;
}
+ eh = mtod(m, struct ether_header *);
+ /*
+ * Deny any non-PAE frames received prior to authorization.
+ * For open/shared-key authentication the port is mark
+ * authorized after authentication completes. For 802.1x
+ * the port is not marked authorized by the authenticator.
+ */
+ if ((ni->ni_flags & IEEE80211_NODE_AUTH) == 0 &&
+ eh->ether_type != htons(ETHERTYPE_PAE)) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_INPUT,
+ ("%s: discard data from %s on unauthorized port\n",
+ __func__, ether_sprintf(wh->i_addr2)));
+ ic->ic_stats.is_rx_unauth++;
+ /* XXX node statistic */
+ goto err;
+ }
ifp->if_ipackets++;
/* perform as a bridge within the AP */
- m1 = NULL;
if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
- eh = mtod(m, struct ether_header *);
+ struct mbuf *m1 = NULL;
+
if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
m1 = m_copypacket(m, M_DONTWAIT);
if (m1 == NULL)
@@ -364,6 +401,8 @@
else
m1->m_flags |= M_MCAST;
} else {
+ /* XXX this dups work done in ieee80211_encap */
+ /* check if destination is associated */
struct ieee80211_node *ni1 =
ieee80211_find_node(ic, eh->ether_dhost);
if (ni1 != NULL) {
@@ -371,7 +410,8 @@
m1 = m;
m = NULL;
}
- ieee80211_unref_node(&ni1);
+ /* XXX statistic? */
+ ieee80211_free_node(ic, ni1);
}
}
if (m1 != NULL) {
@@ -405,7 +445,6 @@
ic->ic_stats.is_rx_ahdemo_mgt++;
goto out;
}
- subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
/* drop frames without interest */
if (ic->ic_state == IEEE80211_S_SCAN) {
@@ -421,30 +460,22 @@
goto out;
}
}
-
- if (ieee80211_msg_debug(ic)) {
- /* avoid to print too many frames */
- int doprint = 0;
-
- switch (subtype) {
- case IEEE80211_FC0_SUBTYPE_BEACON:
- if (ic->ic_state == IEEE80211_S_SCAN)
- doprint = 1;
- break;
- case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
- if (ic->ic_opmode == IEEE80211_M_IBSS)
- doprint = 1;
- break;
- default:
- doprint = 1;
- break;
- }
- if (doprint || ieee80211_msg_dumppkts(ic))
- if_printf(ifp, "received %s from %s rssi %d\n",
- ieee80211_mgt_subtype_name[subtype
- >> IEEE80211_FC0_SUBTYPE_SHIFT],
- ether_sprintf(wh->i_addr2), rssi);
+ if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) {
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
+ ("%s: mgt data frame too short, len %u\n",
+ __func__, m->m_pkthdr.len));
+ ic->ic_stats.is_rx_tooshort++;
+ goto out;
+ }
+#ifdef IEEE80211_DEBUG
+ if ((ieee80211_msg_debug(ic) && doprint(ic, subtype)) ||
+ ieee80211_msg_dumppkts(ic)) {
+ if_printf(ifp, "received %s from %s rssi %d\n",
+ ieee80211_mgt_subtype_name[subtype
+ >> IEEE80211_FC0_SUBTYPE_SHIFT],
+ ether_sprintf(wh->i_addr2), rssi);
}
+#endif
if (ic->ic_rawbpf)
bpf_mtap(ic->ic_rawbpf, m);
(*ic->ic_recv_mgmt)(ic, m, ni, subtype, rssi, rstamp);
@@ -455,19 +486,18 @@
ic->ic_stats.is_rx_ctl++;
if (ic->ic_opmode != IEEE80211_M_HOSTAP)
goto out;
- subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
if (subtype == IEEE80211_FC0_SUBTYPE_PS_POLL) {
/* XXX statistic */
/* Dump out a single packet from the host */
IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER,
("got power save probe from %s\n",
ether_sprintf(wh->i_addr2)));
- ieee80211_recv_pspoll(ic, m, rssi, rstamp);
+ ieee80211_recv_pspoll(ic, ni, m);
}
goto out;
default:
IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
- ("%s: bad type %x\n", __func__, type));
+ ("%s: bad frame type %x\n", __func__, type));
/* should not come here */
break;
}
@@ -736,19 +766,17 @@
ic->ic_stats.is_rx_bad_auth++;
return;
}
+ /* always accept open authentication requests */
if (ni == ic->ic_bss) {
- ni = ieee80211_alloc_node(ic, wh->i_addr2);
- if (ni == NULL) {
- ic->ic_stats.is_rx_nodealloc++;
+ ni = ieee80211_dup_bss(ic, wh->i_addr2);
+ if (ni == NULL)
return;
- }
IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid);
- ni->ni_rssi = rssi;
- ni->ni_rstamp = rstamp;
- ni->ni_chan = ic->ic_bss->ni_chan;
allocbs = 1;
} else
allocbs = 0;
+ ni->ni_rssi = rssi;
+ ni->ni_rstamp = rstamp;
IEEE80211_SEND_MGMT(ic, ni,
IEEE80211_FC0_SUBTYPE_AUTH, seq + 1);
IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
@@ -782,14 +810,28 @@
}
}
+static int
+alloc_challenge(struct ieee80211com *ic, 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_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
+ ("%s: challenge alloc failed\n", __func__));
+ /* XXX statistic */
+ }
+ return (ni->ni_challenge != NULL);
+}
+
/* XXX TODO: add statistics */
static void
ieee80211_auth_shared(struct ieee80211com *ic, struct ieee80211_frame *wh,
u_int8_t *frm, u_int8_t *efrm, struct ieee80211_node *ni, int rssi,
u_int32_t rstamp, u_int16_t seq, u_int16_t status)
{
- u_int8_t *challenge = NULL;
- int allocbs, i, estatus;
+ u_int8_t *challenge;
+ int allocbs, estatus;
/*
* NB: this can happen as we allow pre-shared key
@@ -820,6 +862,7 @@
goto bad;
}
+ challenge = NULL;
if (frm + 1 < efrm) {
if ((frm[1] + 2) > (efrm - frm)) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH,
@@ -871,35 +914,24 @@
switch (seq) {
case IEEE80211_AUTH_SHARED_REQUEST:
if (ni == ic->ic_bss) {
- ni = ieee80211_alloc_node(ic, wh->i_addr2);
+ ni = ieee80211_dup_bss(ic, wh->i_addr2);
if (ni == NULL) {
- ic->ic_stats.is_rx_nodealloc++;
/* NB: no way to return an error */
return;
}
IEEE80211_ADDR_COPY(ni->ni_bssid,
ic->ic_bss->ni_bssid);
- ni->ni_rssi = rssi;
- ni->ni_rstamp = rstamp;
- ni->ni_chan = ic->ic_bss->ni_chan;
allocbs = 1;
} else
allocbs = 0;
- 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_DPRINTF(ic, IEEE80211_MSG_AUTH,
- ("%s: challenge alloc failed\n",
- __func__));
- /* XXX statistic */
+ ni->ni_rssi = rssi;
+ ni->ni_rstamp = rstamp;
+ if (!alloc_challenge(ic, ni)) {
/* NB: don't return error so they rexmit */
return;
}
- for (i = IEEE80211_CHALLENGE_LEN / sizeof(u_int32_t);
- --i >= 0; )
- ni->ni_challenge[i] = arc4random();
+ get_random_bytes(ni->ni_challenge,
+ IEEE80211_CHALLENGE_LEN);
IEEE80211_DPRINTF(ic,
IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
("shared key %sauth request from station %s\n",
@@ -913,7 +945,6 @@
/* NB: don't send a response */
return;
}
- allocbs = 1;
if (ni->ni_challenge == NULL) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH,
("%s: no challenge recorded\n", __func__));
@@ -961,6 +992,7 @@
("%s: auth failed (reason %d) for %s\n",
__func__, status,
ether_sprintf(wh->i_addr3)));
+ /* XXX can this happen? */
if (ni != ic->ic_bss)
ni->ni_fails++;
ic->ic_stats.is_rx_auth_fail++;
@@ -970,16 +1002,9 @@
wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
break;
case IEEE80211_AUTH_SHARED_CHALLENGE:
- if (ni->ni_challenge == NULL)
- MALLOC(ni->ni_challenge, u_int32_t *,
- challenge[1], M_DEVBUF, M_NOWAIT);
- if (ni->ni_challenge == NULL) {
- IEEE80211_DPRINTF(ic,
- IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
- ("%s: challenge alloc failed\n", __func__));
- /* XXX statistic */
+ if (!alloc_challenge(ic, ni))
return;
- }
+ /* XXX could optimize by passing recvd challenge */
memcpy(ni->ni_challenge, &challenge[2], challenge[1]);
IEEE80211_SEND_MGMT(ic, ni,
IEEE80211_FC0_SUBTYPE_AUTH, seq + 1);
@@ -1216,10 +1241,8 @@
#endif
if (ni == NULL) {
ni = ieee80211_alloc_node(ic, wh->i_addr2);
- if (ni == NULL) {
- ic->ic_stats.is_rx_nodealloc++;
+ if (ni == NULL)
return;
- }
ni->ni_esslen = ssid[1];
memset(ni->ni_essid, 0, sizeof(ni->ni_essid));
memcpy(ni->ni_essid, ssid + 2, ssid[1]);
@@ -1260,7 +1283,7 @@
}
/* NB: must be after ni_chan is setup */
ieee80211_setup_rates(ic, ni, rates, xrates, IEEE80211_F_DOSORT);
- ieee80211_unref_node(&ni);
+ ieee80211_unref_node(&ni); /* NB: do not free */
break;
}
@@ -1311,12 +1334,10 @@
if (ni == ic->ic_bss) {
ni = ieee80211_dup_bss(ic, wh->i_addr2);
- if (ni == NULL) {
- ic->ic_stats.is_rx_nodealloc++;
+ if (ni == NULL)
return;
- }
IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
- ("%s: new req from %s\n",
+ ("%s: new probe req from %s\n",
__func__, ether_sprintf(wh->i_addr2)));
allocbs = 1;
} else
@@ -1335,7 +1356,18 @@
IEEE80211_FC0_SUBTYPE_PROBE_RESP, 0);
}
if (allocbs) {
- /* XXX just use free? */
+ /*
+ * When operating as an AP we discard the node's
+ * state until the station requests authentication.
+ * This may be better done by holding it and setting
+ * a short timer for reclaiming it but reduces the
+ * possibility of stations flooding us with probe
+ * requests causing our memory use to grow quickly
+ * (though this can still happen if they send
+ * authentication requests). When operating in ibss
+ * mode we hold the node but with a zero reference
+ * count; this is the current convention (XXX).
+ */
if (ic->ic_opmode == IEEE80211_M_HOSTAP)
ieee80211_free_node(ic, ni);
else
@@ -1388,7 +1420,7 @@
u_int16_t capinfo, bintval;
if (ic->ic_opmode != IEEE80211_M_HOSTAP ||
- (ic->ic_state != IEEE80211_S_RUN))
+ ic->ic_state != IEEE80211_S_RUN)
return;
if (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
@@ -1410,7 +1442,8 @@
IEEE80211_VERIFY_LENGTH(efrm - frm, (reassoc ? 10 : 4));
if (!IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_bss->ni_bssid)) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
- ("%s: ignore assoc request from other bss %s\n",
+ ("%s: ignore assoc request with bss %s not "
+ "our own\n",
__func__, ether_sprintf(wh->i_addr2)));
ic->ic_stats.is_rx_assoc_bss++;
return;
@@ -1470,17 +1503,16 @@
/* XXX per-node cipher suite */
/* XXX some stations use the privacy bit for handling APs
that suport both encrypted and unencrypted traffic */
+ /* NB: PRIVACY flag bits are assumed to match */
if ((capinfo & IEEE80211_CAPINFO_ESS) == 0 ||
- (capinfo & IEEE80211_CAPINFO_PRIVACY) !=
- ((ic->ic_flags & IEEE80211_F_WEPON) ?
- IEEE80211_CAPINFO_PRIVACY : 0)) {
+ (capinfo & IEEE80211_CAPINFO_PRIVACY) ^
+ (ic->ic_flags & IEEE80211_F_PRIVACY)) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
("%s: capability mismatch %x for %s\n",
__func__, capinfo, ether_sprintf(wh->i_addr2)));
- IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
- ni->ni_associd = 0;
IEEE80211_SEND_MGMT(ic, ni, resp,
IEEE80211_STATUS_CAPINFO);
+ ieee80211_node_leave(ic, ni);
ic->ic_stats.is_rx_assoc_capmismatch++;
return;
}
@@ -1491,10 +1523,9 @@
IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
("%s: rate mismatch for %s\n",
__func__, ether_sprintf(wh->i_addr2)));
- IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
- ni->ni_associd = 0;
IEEE80211_SEND_MGMT(ic, ni, resp,
IEEE80211_STATUS_BASIC_RATE);
+ ieee80211_node_leave(ic, ni);
ic->ic_stats.is_rx_assoc_norate++;
return;
}
@@ -1509,7 +1540,7 @@
u_int16_t aid;
/*
- * It would be clever to search the bitmap
+ * It would be good to search the bitmap
* more efficiently, but this will do for now.
*/
for (aid = 1; aid < ic->ic_max_aid; aid++) {
@@ -1517,10 +1548,10 @@
ic->ic_aid_bitmap))
break;
}
-
- if (ic->ic_bss->ni_associd >= ic->ic_max_aid) {
+ if (aid >= ic->ic_max_aid) {
IEEE80211_SEND_MGMT(ic, ni, resp,
IEEE80211_REASON_ASSOC_TOOMANY);
+ ieee80211_node_leave(ic, ni);
return;
}
ni->ni_associd = aid | 0xc000;
@@ -1574,7 +1605,6 @@
ni->ni_flags |= IEEE80211_NODE_ERP;
} else
newassoc = 0;
- IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS);
IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG,
("station %s %s associated at aid %d\n",
(newassoc ? "newly" : "already"),
@@ -1583,6 +1613,11 @@
/* give driver a chance to setup state like ni_txrate */
if (ic->ic_newassoc)
(*ic->ic_newassoc)(ic, ni, newassoc);
+ IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS);
+ /* XXX may need a delay here? */
+ /* tell the authenticator about new station */
+ if (ni->ni_authmode == IEEE80211_AUTH_8021X)
+ (*ic->ic_node_join)(ic, ni);
break;
}
@@ -1605,6 +1640,7 @@
IEEE80211_VERIFY_LENGTH(efrm - frm, 6);
ni = ic->ic_bss;
ni->ni_capinfo = le16toh(*(u_int16_t *)frm);
+ frm += 2;
if (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
else
@@ -1613,7 +1649,6 @@
ic->ic_flags |= IEEE80211_F_SHSLOT;
else
ic->ic_flags &= ~IEEE80211_F_SHSLOT;
- frm += 2;
status = le16toh(*(u_int16_t *)frm);
frm += 2;
@@ -1673,8 +1708,6 @@
"peer (reason %d)\n",
ether_sprintf(ni->ni_macaddr), reason));
ieee80211_node_leave(ic, ni);
- /* node will be free'd on return */
- ieee80211_unref_node(&ni);
}
break;
default:
@@ -1703,11 +1736,7 @@
("station %s disassociated by "
"peer (reason %d)\n",
ether_sprintf(ni->ni_macaddr), reason));
- IEEE80211_AID_CLR(ni->ni_associd,
- ic->ic_aid_bitmap);
- ni->ni_associd = 0;
ieee80211_node_leave(ic, ni);
- ieee80211_unref_node(&ni); /* XXX??? */
}
break;
default:
@@ -1728,27 +1757,25 @@
#undef IEEE80211_VERIFY_ELEMENT
static void
-ieee80211_recv_pspoll(struct ieee80211com *ic, struct mbuf *m0, int rssi,
- u_int32_t rstamp)
+ieee80211_recv_pspoll(struct ieee80211com *ic,
+ struct ieee80211_node *ni, struct mbuf *m0)
{
struct ifnet *ifp = ic->ic_ifp;
- struct ieee80211_frame *wh;
- struct ieee80211_node *ni;
+ struct ieee80211_frame_min *wh;
struct mbuf *m;
u_int16_t aid;
if (ic->ic_set_tim == NULL) /* No powersaving functionality */
return;
-
- wh = mtod(m0, struct ieee80211_frame *);
-
- if ((ni = ieee80211_find_node(ic, wh->i_addr2)) == NULL) {
+ if (ni == ic->ic_bss) {
+ wh = mtod(m0, struct ieee80211_frame_min *);
IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER | IEEE80211_MSG_DEBUG,
("station %s sent bogus power save poll\n",
ether_sprintf(wh->i_addr2)));
- /* XXX statistic */
return;
}
+
+ wh = mtod(m0, struct ieee80211_frame_min *);
memcpy(&aid, wh->i_dur, sizeof(wh->i_dur));
if ((aid & 0xc000) != 0xc000) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER | IEEE80211_MSG_DEBUG,
@@ -1774,7 +1801,7 @@
/* XXX statistic */
return;
}
- wh = mtod(m, struct ieee80211_frame *);
+ wh = mtod(m, struct ieee80211_frame_min *);
/*
* If this is the last packet, turn off the TIM fields.
More information about the p4-projects
mailing list