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