PERFORCE change 81299 for review

Sam Leffler sam at FreeBSD.org
Mon Aug 1 17:56:50 GMT 2005


http://perforce.freebsd.org/chv.cgi?CH=81299

Change 81299 by sam at sam_ebb on 2005/08/01 17:56:25

	checkpoint changes to move keycache up to the 802.11 layer
	to fix race conditions; still needsz fixup for split tx/rx
	keys used for tkip on some cards

Affected files ...

.. //depot/projects/wifi/sys/dev/ath/if_ath.c#93 edit
.. //depot/projects/wifi/sys/dev/ath/if_athvar.h#40 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_crypto.c#15 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_node.c#57 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_node.h#27 edit

Differences ...

==== //depot/projects/wifi/sys/dev/ath/if_ath.c#93 (text+ko) ====

@@ -1938,32 +1938,17 @@
 	struct ath_softc *sc = ic->ic_ifp->if_softc;
 	struct ath_hal *ah = sc->sc_ah;
 	const struct ieee80211_cipher *cip = k->wk_cipher;
-	struct ieee80211_node *ni;
 	u_int keyix = k->wk_keyix;
 
 	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: delete key %u\n", __func__, keyix);
 
 	ath_hal_keyreset(ah, keyix);
 	/*
-	 * Check the key->node map and flush any ref.
-	 */
-	ni = sc->sc_keyixmap[keyix];
-	if (ni != NULL) {
-		ieee80211_free_node(ni);
-		sc->sc_keyixmap[keyix] = NULL;
-	}
-	/*
 	 * Handle split tx/rx keying required for TKIP with h/w MIC.
 	 */
 	if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
-	    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic) {
+	    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic)
 		ath_hal_keyreset(ah, keyix+32);		/* RX key */
-		ni = sc->sc_keyixmap[keyix+32];
-		if (ni != NULL) {			/* as above... */
-			ieee80211_free_node(ni);
-			sc->sc_keyixmap[keyix+32] = NULL;
-		}
-	}
 	if (keyix >= IEEE80211_WEP_NKID) {
 		/*
 		 * Don't touch keymap entries for global keys so
@@ -2973,6 +2958,7 @@
 	ds = bf->bf_desc;
 	ds->ds_link = bf->bf_daddr;	/* link to self */
 	ds->ds_data = bf->bf_segs[0].ds_addr;
+	ds->ds_vdata = mtod(m, u_int32_t);/*XXX*/
 	ath_hal_setuprxdesc(ah, ds
 		, m->m_len		/* buffer size */
 		, 0
@@ -3294,51 +3280,22 @@
 		/*
 		 * Locate the node for sender, track state, and then
 		 * pass the (referenced) node up to the 802.11 layer
-		 * for its use.  If the sender is unknown spam the
-		 * frame; it'll be dropped where it's not wanted.
+		 * for its use.
+		 */
+		ni = ieee80211_find_rxnode_withkey(ic,
+			mtod(m, const struct ieee80211_frame_min *),
+			ds->ds_rxstat.rs_keyix == HAL_RXKEYIX_INVALID ?
+				IEEE80211_KEYIX_NONE : ds->ds_rxstat.rs_keyix);
+		/*
+		 * Track rx rssi and do any rx antenna management.
+		 */
+		an = ATH_NODE(ni);
+		ATH_RSSI_LPF(an->an_avgrssi, ds->ds_rxstat.rs_rssi);
+		/*
+		 * Send frame up for processing.
 		 */
-		if (ds->ds_rxstat.rs_keyix != HAL_RXKEYIX_INVALID &&
-		    (ni = sc->sc_keyixmap[ds->ds_rxstat.rs_keyix]) != NULL &&
-		    ieee80211_node_refcnt(ni) > 1) {
-			/*
-			 * Fast path: node is present in the key map;
-			 * grab a reference for processing the frame.
-			 */
-			an = ATH_NODE(ieee80211_ref_node(ni));
-			ATH_RSSI_LPF(an->an_avgrssi, ds->ds_rxstat.rs_rssi);
-			type = ieee80211_input(ic, m, ni,
-				ds->ds_rxstat.rs_rssi, ds->ds_rxstat.rs_tstamp);
-		} else {
-			/*
-			 * Locate the node for sender, track state, and then
-			 * pass the (referenced) node up to the 802.11 layer
-			 * for its use.
-			 */
-			ni = ieee80211_find_rxnode(ic,
-				mtod(m, const struct ieee80211_frame_min *));
-			/*
-			 * Track rx rssi and do any rx antenna management.
-			 */
-			an = ATH_NODE(ni);
-			ATH_RSSI_LPF(an->an_avgrssi, ds->ds_rxstat.rs_rssi);
-			/*
-			 * Send frame up for processing.
-			 */
-			type = ieee80211_input(ic, m, ni,
-				ds->ds_rxstat.rs_rssi, ds->ds_rxstat.rs_tstamp);
-			if (ni != ic->ic_bss) {
-				u_int16_t keyix;
-				/*
-				 * If the station has a key cache slot assigned
-				 * update the key->node mapping table.
-				 */
-				keyix = ni->ni_ucastkey.wk_keyix;
-				if (keyix != IEEE80211_KEYIX_NONE &&
-				    sc->sc_keyixmap[keyix] == NULL)
-					sc->sc_keyixmap[keyix] =
-						ieee80211_ref_node(ni);
-			}
-		}
+		type = ieee80211_input(ic, m, ni,
+			ds->ds_rxstat.rs_rssi, ds->ds_rxstat.rs_tstamp);
 		ieee80211_free_node(ni);
 		if (sc->sc_diversity) {
 			/*

==== //depot/projects/wifi/sys/dev/ath/if_athvar.h#40 (text+ko) ====

@@ -256,7 +256,6 @@
 	HAL_INT			sc_imask;	/* interrupt mask copy */
 	u_int			sc_keymax;	/* size of key cache */
 	u_int8_t		sc_keymap[ATH_KEYBYTES];/* key use bit map */
-	struct ieee80211_node	*sc_keyixmap[ATH_KEYMAX];/* key ix->node map */
 
 	u_int			sc_ledpin;	/* GPIO pin for driving LED */
 	u_int			sc_ledon;	/* pin setting for LED on */

==== //depot/projects/wifi/sys/net80211/ieee80211_crypto.c#15 (text+ko) ====

@@ -416,6 +416,11 @@
 			ic->ic_stats.is_crypto_delkey++;
 			/* XXX recovery? */
 		}
+		/*
+		 * Clear any unicast key index -> node mapping.
+		 */
+		if ((key->wk_flags & IEEE80211_KEY_GROUP) == 0)
+			ieee80211_node_delkey(&ic->ic_sta, keyix);
 	}
 	cipher_detach(key);
 	memset(key, 0, sizeof(*key));

==== //depot/projects/wifi/sys/net80211/ieee80211_node.c#57 (text+ko) ====

@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_node.c,v 1.58 2005/07/27 02:53:09 sam Exp $");
+__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_node.c,v 1.59 2005/07/31 06:12:32 sam Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h> 
@@ -892,6 +892,11 @@
 	return ni;
 }
 
+#define	IS_CTL(wh) \
+	((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
+#define	IS_PSPOLL(wh) \
+	((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL)
+
 /*
  * Locate the node for sender, track state, and then pass the
  * (referenced) node up to the 802.11 layer for its use.  We
@@ -909,10 +914,6 @@
 	const struct ieee80211_frame_min *wh)
 #endif
 {
-#define	IS_CTL(wh) \
-	((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
-#define	IS_PSPOLL(wh) \
-	((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL)
 	struct ieee80211_node_table *nt;
 	struct ieee80211_node *ni;
 
@@ -924,12 +925,65 @@
 		ni = _ieee80211_find_node(nt, wh->i_addr1);
 	else
 		ni = _ieee80211_find_node(nt, wh->i_addr2);
+	if (ni == NULL)
+		ni = ieee80211_ref_node(ic->ic_bss);
+	IEEE80211_NODE_UNLOCK(nt);
+
+	return ni;
+}
+
+/*
+ * Like ieee80211_find_rxnode but use the supplied h/w
+ * key index as a hint to locate the node in the key
+ * mapping table.  If an entry is present at the key
+ * index we return it; otherwise do a normal lookup and
+ * update the mapping table if the station has a unicast
+ * key assigned to it.
+ */
+struct ieee80211_node *
+#ifdef IEEE80211_DEBUG_REFCNT
+ieee80211_find_rxnode_withkey_debug(struct ieee80211com *ic,
+	const struct ieee80211_frame_min *wh, , u_int16_t keyix,
+	const char *func, int line)
+#else
+ieee80211_find_rxnode_withkey(struct ieee80211com *ic,
+	const struct ieee80211_frame_min *wh, u_int16_t keyix)
+#endif
+{
+	struct ieee80211_node_table *nt;
+	struct ieee80211_node *ni;
+
+	nt = &ic->ic_sta;
+	IEEE80211_NODE_LOCK(nt);
+	KASSERT(keyix == IEEE80211_KEYIX_NONE || keyix < 128,
+		("keyix %u out of bounds (1)", keyix));
+	ni = (keyix != IEEE80211_KEYIX_NONE) ? nt->nt_keyixmap[keyix] : NULL;
+	if (ni == NULL) {
+		if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/)
+			ni = _ieee80211_find_node(nt, wh->i_addr1);
+		else
+			ni = _ieee80211_find_node(nt, wh->i_addr2);
+		if (ni == NULL)
+			ni = ieee80211_ref_node(ic->ic_bss);
+		/*
+		 * If the station has a unicast key cache slot
+		 * assigned update the key->node mapping table.
+		 */
+		keyix = ni->ni_ucastkey.wk_keyix;
+		KASSERT(keyix == IEEE80211_KEYIX_NONE || keyix < 128,
+			("keyix %u out of bounds (2)", keyix));
+		/* XXX can keyixmap[keyix] != NULL? */
+		if (keyix != IEEE80211_KEYIX_NONE &&
+		    nt->nt_keyixmap[keyix] == NULL)
+			nt->nt_keyixmap[keyix] = ieee80211_ref_node(ni);
+	} else
+		ieee80211_ref_node(ni);
 	IEEE80211_NODE_UNLOCK(nt);
 
-	return (ni != NULL ? ni : ieee80211_ref_node(ic->ic_bss));
+	return ni;
+}
 #undef IS_PSPOLL
 #undef IS_CTL
-}
 
 /*
  * Return a reference to the appropriate node for sending
@@ -948,15 +1002,16 @@
 
 	/*
 	 * The destination address should be in the node table
-	 * unless we are operating in station mode or this is a
-	 * multicast/broadcast frame.
+	 * unless this is a multicast/broadcast frame.  We can
+	 * also ptimize station mode operation, all frames go
+	 * to the bss node.
 	 */
-	if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(macaddr))
-		return ieee80211_ref_node(ic->ic_bss);
-
 	/* XXX can't hold lock across dup_bss 'cuz of recursive locking */
 	IEEE80211_NODE_LOCK(nt);
-	ni = _ieee80211_find_node(nt, macaddr);
+	if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(macaddr))
+		ni = ieee80211_ref_node(ic->ic_bss);
+	else
+		ni = _ieee80211_find_node(nt, macaddr);
 	IEEE80211_NODE_UNLOCK(nt);
 
 	if (ni == NULL) {
@@ -1068,23 +1123,35 @@
 		"%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line, ni,
 		 ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)-1);
 #endif
-	if (ieee80211_node_dectestref(ni)) {
-		/*
-		 * Beware; if the node is marked gone then it's already
-		 * been removed from the table and we cannot assume the
-		 * table still exists.  Regardless, there's no need to lock
-		 * the table.
-		 */
-		if (ni->ni_table != NULL) {
-			IEEE80211_NODE_LOCK(nt);
+	if (nt != NULL) {
+		IEEE80211_NODE_LOCK(nt);
+		if (ieee80211_node_dectestref(ni))
 			_ieee80211_free_node(ni);
-			IEEE80211_NODE_UNLOCK(nt);
-		} else
-			_ieee80211_free_node(ni);
+		IEEE80211_NODE_UNLOCK(nt);
+	} else {
+		_ieee80211_free_node(ni);
 	}
 }
 
 /*
+ * Callback from the crypto code when a unicast h/w key
+ * is deleted; clear any mapping table entry for the key.
+ */
+void
+ieee80211_node_delkey(struct ieee80211_node_table *nt, u_int16_t keyix)
+{
+	struct ieee80211_node *ni;
+
+	IEEE80211_NODE_LOCK(nt);
+	ni = nt->nt_keyixmap[keyix];
+	nt->nt_keyixmap[keyix] = NULL;;
+	IEEE80211_NODE_UNLOCK(nt);
+
+	if (ni != NULL)
+		ieee80211_free_node(ni);
+}
+
+/*
  * Reclaim a node.  If this is the last reference count then
  * do the normal free work.  Otherwise remove it from the node
  * table and mark it gone by clearing the back-reference.
@@ -1092,11 +1159,26 @@
 static void
 node_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
 {
+	u_int16_t keyix;
 
+	IEEE80211_NODE_LOCK_ASSERT(nt);
+
 	IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_NODE,
 		"%s: remove %p<%s> from %s table, refcnt %d\n",
 		__func__, ni, ether_sprintf(ni->ni_macaddr),
 		nt->nt_name, ieee80211_node_refcnt(ni)-1);
+	/*
+	 * Clear any entry in the unicast key mapping table.
+	 * We need to do it here so rx lookups don't find it
+	 * in the mapping table even if it's not in the hash
+	 * table.  We cannot depend on the mapping table entry
+	 * being cleared because the node may not be free'd.
+	 */
+	keyix = ni->ni_ucastkey.wk_keyix;
+	if (keyix != IEEE80211_KEYIX_NONE && nt->nt_keyixmap[keyix] == ni) {
+		nt->nt_keyixmap[keyix] = NULL;
+		ieee80211_node_decref(ni);
+	}
 	if (!ieee80211_node_dectestref(ni)) {
 		/*
 		 * Other references are present, just remove the
@@ -1208,6 +1290,14 @@
 				    IEEE80211_MSG_INACT | IEEE80211_MSG_NODE,
 				    ni, "%s",
 				    "probe station due to inactivity");
+				/*
+				 * Grab a reference before unlocking the table
+				 * so the node cannot be reclaimed before we
+				 * send the frame. ieee80211_send_nulldata
+				 * understands we've done this and reclaims the
+				 * ref for us as needed.
+				 */
+				ieee80211_ref_node(ni);
 				IEEE80211_NODE_UNLOCK(nt);
 				ieee80211_send_nulldata(ni);
 				/* XXX stat? */

==== //depot/projects/wifi/sys/net80211/ieee80211_node.h#27 (text+ko) ====

@@ -210,6 +210,7 @@
 	ieee80211_node_lock_t	nt_nodelock;	/* on node table */
 	TAILQ_HEAD(, ieee80211_node) nt_node;	/* information of all nodes */
 	LIST_HEAD(, ieee80211_node) nt_hash[IEEE80211_NODE_HASHSIZE];
+	struct ieee80211_node	*nt_keyixmap[128];/* key ix -> node map */
 	const char		*nt_name;	/* for debugging */
 	ieee80211_scan_lock_t	nt_scanlock;	/* on nt_scangen */
 	u_int			nt_scangen;	/* gen# for timeout scan */
@@ -224,14 +225,14 @@
 #ifdef IEEE80211_DEBUG_REFCNT
 void	ieee80211_free_node_debug(struct ieee80211_node *,
 		const char *func, int line);
-struct ieee80211_node *ieee80211_find_node_debug(
-		struct ieee80211_node_table *, const u_int8_t *,
+struct ieee80211_node *ieee80211_find_node_debug(struct ieee80211_node_table *,
+		const u_int8_t *,
 		const char *func, int line);
-struct ieee80211_node * ieee80211_find_rxnode_debug(
-		struct ieee80211com *, const struct ieee80211_frame_min *,
+struct ieee80211_node * ieee80211_find_rxnode_debug(struct ieee80211com *,
+		const struct ieee80211_frame_min *,
 		const char *func, int line);
-struct ieee80211_node *ieee80211_find_txnode_debug(
-		struct ieee80211com *, const u_int8_t *,
+struct ieee80211_node *ieee80211_find_txnode_debug(struct ieee80211com *,
+		const u_int8_t *,
 		const char *func, int line);
 struct ieee80211_node *ieee80211_find_node_with_ssid_debug(
 		struct ieee80211_node_table *, const u_int8_t *macaddr,
@@ -249,16 +250,19 @@
 	ieee80211_find_node_with_ssid_debug(nt, mac, sl, ss, __func__, __LINE__)
 #else
 void	ieee80211_free_node(struct ieee80211_node *);
-struct ieee80211_node *ieee80211_find_node(
-		struct ieee80211_node_table *, const u_int8_t *);
-struct ieee80211_node * ieee80211_find_rxnode(
-		struct ieee80211com *, const struct ieee80211_frame_min *);
-struct ieee80211_node *ieee80211_find_txnode(
-		struct ieee80211com *, const u_int8_t *);
+struct ieee80211_node *ieee80211_find_node(struct ieee80211_node_table *,
+		const u_int8_t *);
+struct ieee80211_node * ieee80211_find_rxnode(struct ieee80211com *,
+		const struct ieee80211_frame_min *);
+struct ieee80211_node * ieee80211_find_rxnode_withkey(struct ieee80211com *,
+		const struct ieee80211_frame_min *, u_int16_t keyix);
+struct ieee80211_node *ieee80211_find_txnode(struct ieee80211com *,
+		const u_int8_t *);
 struct ieee80211_node *ieee80211_find_node_with_ssid(
 		struct ieee80211_node_table *, const u_int8_t *macaddr,
 		u_int ssidlen, const u_int8_t *ssid);
 #endif
+void	ieee80211_node_delkey(struct ieee80211_node_table *, u_int16_t keyix);
 void	ieee80211_node_timeout(void *arg);
 
 typedef void ieee80211_iter_func(void *, struct ieee80211_node *);


More information about the p4-projects mailing list