PERFORCE change 64714 for review

Sam Leffler sam at FreeBSD.org
Tue Nov 9 12:29:23 PST 2004


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

Change 64714 by sam at sam_ebb on 2004/11/09 20:28:25

	checkpoint ibss support

Affected files ...

.. //depot/projects/wifi/sys/net80211/ieee80211_input.c#11 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_node.c#9 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_node.h#8 edit

Differences ...

==== //depot/projects/wifi/sys/net80211/ieee80211_input.c#11 (text+ko) ====

@@ -190,8 +190,12 @@
 				}
 				bssid = wh->i_addr3;
 			}
-			if (type == IEEE80211_FC0_TYPE_DATA &&
-			    !IEEE80211_ADDR_EQ(bssid, ic->ic_bss->ni_bssid) &&
+			if (type != IEEE80211_FC0_TYPE_DATA)
+				break;
+			/*
+			 * Data frame, validate the bssid.
+			 */
+			if (!IEEE80211_ADDR_EQ(bssid, ic->ic_bss->ni_bssid) &&
 			    !IEEE80211_ADDR_EQ(bssid, ifp->if_broadcastaddr)) {
 				/* not interested in */
 				IEEE80211_DPRINTF(ic, IEEE80211_MSG_INPUT,
@@ -200,6 +204,24 @@
 				ic->ic_stats.is_rx_wrongbss++;
 				goto out;
 			}
+			/*
+			 * For adhoc mode we cons up a node when it doesn't
+			 * exist. This should probably done after an ACL check.
+			 */
+			if (ni == ic->ic_bss &&
+			    ic->ic_opmode != IEEE80211_M_HOSTAP) {
+				/*
+				 * Fake up a node for this newly
+				 * discovered member of the IBSS.
+				 */
+				ni = ieee80211_fakeup_adhoc_node(ic->ic_sta,
+						type == IEEE80211_FC0_TYPE_CTL ?
+						    wh->i_addr1 : wh->i_addr2);
+				if (ni == NULL) {
+					/* NB: stat kept for alloc failure */
+					goto err;
+				}
+			}
 			break;
 		default:
 			goto out;
@@ -1805,7 +1827,20 @@
 				    wh->i_addr2, chan, bchan, capinfo,
 				    bintval, erp, ssid, country);
 #endif
-			ni = ieee80211_dup_bss(&ic->ic_scan, wh->i_addr2);
+			/*
+			 * Create a new entry.  If scanning the entry goes
+			 * in the scan cache.  Otherwise, be particular when
+			 * operating in adhoc mode--only take nodes marked
+			 * as ibss participants so we don't populate our
+			 * neighbor table with unintersting sta's.
+			 */
+			if (ic->ic_state != IEEE80211_S_SCAN) {
+				if ((capinfo & IEEE80211_CAPINFO_IBSS) == 0)
+					return;
+				ni = ieee80211_fakeup_adhoc_node(ic->ic_sta,
+						wh->i_addr2);
+			} else
+				ni = ieee80211_dup_bss(&ic->ic_scan, wh->i_addr2);
 			if (ni == NULL)
 				return;
 			ni->ni_esslen = ssid[1];
@@ -1898,7 +1933,17 @@
 		IEEE80211_VERIFY_SSID(ic->ic_bss, ssid, "probe");
 
 		if (ni == ic->ic_bss) {
-			ni = ieee80211_dup_bss(ic->ic_sta, wh->i_addr2);
+			if (ic->ic_opmode == IEEE80211_M_IBSS) {
+				/*
+				 * 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);
+			} else
+				ni = ieee80211_dup_bss(ic->ic_sta, wh->i_addr2);
 			if (ni == NULL)
 				return;
 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,

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

@@ -63,10 +63,10 @@
 static void ieee80211_timeout_stations(struct ieee80211_node_table *);
 
 static void ieee80211_node_table_init(struct ieee80211com *ic,
-	struct ieee80211_node_table *nt, int inact,
+	struct ieee80211_node_table *nt, const char *name, int inact,
 	void (*timeout)(struct ieee80211_node_table *));
 static struct ieee80211_node_table *ieee80211_node_table_alloc(
-	struct ieee80211com *ic, int inact,
+	struct ieee80211com *ic, const char *name, int inact,
 	void (*timeout)(struct ieee80211_node_table *));
 static void ieee80211_node_table_cleanup(struct ieee80211_node_table *nt);
 
@@ -77,7 +77,7 @@
 {
 
 	ic->ic_sta = NULL;		/* defer to when we need it */
-	ieee80211_node_table_init(ic, &ic->ic_scan,
+	ieee80211_node_table_init(ic, &ic->ic_scan, "scan",
 		IEEE80211_INACT_SCAN, ieee80211_timeout_scan_candidates);
 
 	ic->ic_node_alloc = node_alloc;
@@ -327,21 +327,34 @@
 {
 	struct ieee80211_node *ni;
 
-	ni = ic->ic_bss;
 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
 		"%s: creating ibss\n", __func__);
 
-	ic->ic_sta = ieee80211_node_table_alloc(ic,
-			ic->ic_inact_init, ieee80211_timeout_stations);
+	/*
+	 * Create the station/neighbor table.  Note that for adhoc
+	 * mode we make the initial inactivity timer longer since
+	 * we create nodes only through discovery and they typically
+	 * are long-lived associations.
+	 */
+	if (ic->ic_opmode == IEEE80211_M_HOSTAP)
+		ic->ic_sta = ieee80211_node_table_alloc(ic,
+					"station", ic->ic_inact_init,
+					ieee80211_timeout_stations);
+	else
+		ic->ic_sta = ieee80211_node_table_alloc(ic,
+					"neighbor", ic->ic_inact_run,
+					ieee80211_timeout_stations);
 	if (ic->ic_sta == NULL) {
 		/*
 		 * Should remain in SCAN state and retry.
 		 */
+		/* XXX stat+msg */
 		return;
 	}
 
+	ni = ic->ic_bss;
 	ic->ic_flags |= IEEE80211_F_SIBSS;
-	ieee80211_set_chan(ic, ic->ic_bss, chan);
+	ieee80211_set_chan(ic, ni, chan);
 	IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr);
 	IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr);
 	if (ic->ic_opmode == IEEE80211_M_IBSS)
@@ -612,7 +625,43 @@
 		goto notfound;
 	}
 }
+ 
+/*
+ * Handle 802.11 ad hoc network merge.  The
+ * convention, set by the Wireless Ethernet Compatibility Alliance
+ * (WECA), is that an 802.11 station will change its BSSID to match
+ * the "oldest" 802.11 ad hoc network, on the same channel, that
+ * has the station's desired SSID.  The "oldest" 802.11 network
+ * sends beacons with the greatest TSF timestamp.
+ *
+ * The caller is assumed to validate TSF's before attempting a merge.
+ *
+ * Return !0 if the BSSID changed, 0 otherwise.
+ */
+int
+ieee80211_ibss_merge(struct ieee80211com *ic, struct ieee80211_node *ni)
+{
 
+	if (IEEE80211_ADDR_EQ(ni->ni_bssid, ic->ic_bss->ni_bssid)) {
+		/* unchanged, nothing to do */
+		return 0;
+	}
+	if (ieee80211_match_bss(ic, ni) != 0) {	/* capabilities mismatch */
+		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
+		    "%s: merge failed, capabilities mismatch\n", __func__);
+		ic->ic_stats.is_ibss_capmismatch++;
+		return 0;
+	}
+	IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
+		"%s: new bssid %s: %s preamble, %s slot time%s\n", __func__,
+		ether_sprintf(ni->ni_bssid),
+		ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long",
+		ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long",
+		ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : ""
+	);
+	return ieee80211_sta_join(ic, ni);
+}
+
 /*
  * Join the specified IBSS/BSS network.  The node is assumed to
  * be passed in with a held reference.
@@ -630,6 +679,7 @@
 		    IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
 		if (selbs->ni_rates.rs_nrates == 0) {
 			selbs->ni_fails++;
+			ic->ic_stats.is_ibss_norate++;
 			return 0;
 		}
 	}
@@ -742,7 +792,9 @@
 	int hash;
 
 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
-		"%s %s\n", __func__, ether_sprintf(macaddr));
+		"%s %s in %s table\n", __func__,
+		ether_sprintf(macaddr), nt->nt_name);
+
 	IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
 	hash = IEEE80211_NODE_HASH(macaddr);
 	ieee80211_node_initref(ni);		/* mark referenced */
@@ -845,15 +897,16 @@
 }
 
 /*
- * Fake up a node; this handles node discovery in
- * adhoc mode.  Note that for the driver's benefit
- * we we treat this like an association so the driver
- * has an opportunity to setup it's private state.
+ * Fake up a node; this handles node discovery in adhoc mode.
+ * Note that for the driver's benefit we we treat this like
+ * an association so the driver has an opportunity to setup
+ * it's private state.
  */
-static __inline struct ieee80211_node *
-fakeup_node(struct ieee80211com *ic, struct ieee80211_node_table *nt,
+struct ieee80211_node *
+ieee80211_fakeup_adhoc_node(struct ieee80211_node_table *nt,
 	const u_int8_t macaddr[IEEE80211_ADDR_LEN])
 {
+	struct ieee80211com *ic = nt->nt_ic;
 	struct ieee80211_node *ni;
 
 	ni = ieee80211_dup_bss(nt, macaddr);
@@ -862,21 +915,20 @@
 		ni->ni_rates = ic->ic_bss->ni_rates;
 		if (ic->ic_newassoc)
 			ic->ic_newassoc(ic, ni, 1);
-		/* XXX not sure how 802.1x works w/ IBSS */
+		/* XXX not right for 802.1x/WPA */
 		ieee80211_node_authorize(ic, ni);
+		ieee80211_ref_node(ni);		/* hold reference */
 	}
 	return ni;
 }
 
 /*
- * Locate the node for sender, track state, and then
- * pass the (referenced) node up to the 802.11 layer
- * for its use.  We are required to pass some node so
- * we fall back to ic_bss when this frame is from an
- * unknown sender.  The 802.11 layer knows this means the
- * sender wasn't in the node table and acts accordingly.
- * Note also that by convention we do not reference
- * count ic_bss, only other nodes (ic_bss is never free'd).
+ * Locate the node for sender, track state, and then pass the
+ * (referenced) node up to the 802.11 layer for its use.  We
+ * are required to pass some node so we fall back to ic_bss
+ * when this frame is from an unknown sender.  The 802.11 layer
+ * knows this means the sender wasn't in the node table and
+ * acts accordingly. 
  */
 struct ieee80211_node *
 #ifdef IEEE80211_DEBUG_REFCNT
@@ -892,10 +944,13 @@
 	struct ieee80211_node_table *nt;
 	struct ieee80211_node *ni;
 
-	if (ic->ic_opmode != IEEE80211_M_STA)
+	/* XXX may want scanned nodes in the neighbor table for adhoc */
+	if (ic->ic_opmode == IEEE80211_M_STA ||
+	    ic->ic_opmode == IEEE80211_M_MONITOR ||
+	    ic->ic_state == IEEE80211_S_SCAN /*XXX*/)
+		nt = &ic->ic_scan;
+	else
 		nt = ic->ic_sta;
-	else
-		nt = &ic->ic_scan;
 	/* XXX check ic_bss first in station mode */
 	/* XXX 4-address frames? */
 	IEEE80211_NODE_LOCK(nt);
@@ -905,10 +960,6 @@
 		ni = _ieee80211_find_node(nt, wh->i_addr2);
 	IEEE80211_NODE_UNLOCK(nt);
 
-	if (ni == NULL &&
-	    (ic->ic_opmode == IEEE80211_M_IBSS ||
-	     ic->ic_opmode == IEEE80211_M_AHDEMO))
-		ni = fakeup_node(ic, nt, wh->i_addr2);
 	return (ni != NULL ? ni : ieee80211_ref_node(ic->ic_bss));
 #undef IS_CTL
 }
@@ -944,7 +995,7 @@
 	if (ni == NULL &&
 	    (ic->ic_opmode == IEEE80211_M_IBSS ||
 	     ic->ic_opmode == IEEE80211_M_AHDEMO))
-		ni = fakeup_node(ic, nt, macaddr);
+		ni = ieee80211_fakeup_adhoc_node(nt, macaddr);
 	return ni;
 }
 
@@ -1029,14 +1080,14 @@
 _ieee80211_free_node(struct ieee80211_node *ni)
 {
 	struct ieee80211com *ic = ni->ni_ic;
+	struct ieee80211_node_table *nt = ni->ni_table;
 
 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
-		"%s %s\n", __func__, ether_sprintf(ni->ni_macaddr));
+		"%s %s in %s table\n", __func__, ether_sprintf(ni->ni_macaddr),
+		nt != NULL ? nt->nt_name : "<gone>");
 
 	IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
-	if (ni->ni_table != NULL) {
-		struct ieee80211_node_table *nt = ni->ni_table;
-
+	if (nt != NULL) {
 		TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
 		LIST_REMOVE(ni, ni_hash);
 	}
@@ -1111,7 +1162,7 @@
 	struct ieee80211_node *ni;
 
 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
-		"%s: free all nodes\n", __func__);
+		"%s: free all nodes in %s table\n", __func__, nt->nt_name);
 
 	while ((ni = TAILQ_FIRST(&nt->nt_node)) != NULL) {
 		if (ni->ni_associd != 0) {
@@ -1219,7 +1270,7 @@
 			 * in  LOR between the node lock and the driver lock.
 			 */
 			IEEE80211_NODE_UNLOCK(nt);
-			if (ieee80211_node_is_authorized(ni)) {
+			if (ni->ni_associd != 0) {
 				IEEE80211_SEND_MGMT(ic, ni,
 				    IEEE80211_FC0_SUBTYPE_DEAUTH,
 				    IEEE80211_REASON_AUTH_EXPIRE);
@@ -1454,12 +1505,15 @@
 		"station %s with aid %d leaves\n",
 		ether_sprintf(ni->ni_macaddr), IEEE80211_NODE_AID(ni));
 
-	KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP,
-		("not in ap mode, mode %u", ic->ic_opmode));
+	KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP ||
+		ic->ic_opmode == IEEE80211_M_IBSS ||
+		ic->ic_opmode == IEEE80211_M_AHDEMO,
+		("unexpected operating mode %u", ic->ic_opmode));
 	/*
 	 * If node wasn't previously associated all
 	 * we need to do is reclaim the reference.
 	 */
+	/* XXX ibss mode bypasses 11g and notification */
 	if (ni->ni_associd == 0)
 		goto done;
 	/*
@@ -1550,20 +1604,27 @@
 
 static void
 ieee80211_node_table_init(struct ieee80211com *ic,
-	struct ieee80211_node_table *nt, int inact,
+	struct ieee80211_node_table *nt,
+	const char *name, int inact,
 	void (*timeout)(struct ieee80211_node_table *))
 {
+
+	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
+		"%s %s table, inact %u\n", __func__, name, inact);
+
 	nt->nt_ic = ic;
 	/* XXX need unit */
 	IEEE80211_NODE_LOCK_INIT(nt, ic->ic_ifp->if_xname);
 	TAILQ_INIT(&nt->nt_node);
+	nt->nt_name = name;
 	nt->nt_scangen = 1;
 	nt->nt_inact_init = inact;
 	nt->nt_timeout = timeout;
 }
 
 static struct ieee80211_node_table *
-ieee80211_node_table_alloc(struct ieee80211com *ic, int inact,
+ieee80211_node_table_alloc(struct ieee80211com *ic,
+	const char *name, int inact,
 	void (*timeout)(struct ieee80211_node_table *))
 {
 	struct ieee80211_node_table *nt;
@@ -1575,13 +1636,17 @@
 		printf("%s: no memory node table!\n", __func__);
 		return NULL;
 	}
-	ieee80211_node_table_init(ic, nt, inact, timeout);
+	ieee80211_node_table_init(ic, nt, name, inact, timeout);
 	return nt;
 }
 
 void
 ieee80211_node_table_reset(struct ieee80211_node_table *nt)
 {
+
+	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
+		"%s %s table\n", __func__, nt->nt_name);
+
 	IEEE80211_NODE_LOCK(nt);
 	nt->nt_inact_timer = 0;
 	ieee80211_free_allnodes_locked(nt);
@@ -1591,6 +1656,10 @@
 static void
 ieee80211_node_table_cleanup(struct ieee80211_node_table *nt)
 {
+
+	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
+		"%s %s table\n", __func__, nt->nt_name);
+
 	ieee80211_free_allnodes_locked(nt);
 	IEEE80211_NODE_LOCK_DESTROY(nt);
 }
@@ -1601,6 +1670,10 @@
 void
 ieee80211_node_table_free(struct ieee80211_node_table *nt)
 {
+
+	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
+		"%s %s table\n", __func__, nt->nt_name);
+
 	IEEE80211_NODE_LOCK(nt);
 	nt->nt_inact_timer = 0;
 	ieee80211_node_table_cleanup(nt);

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

@@ -191,7 +191,7 @@
 extern	void ieee80211_node_detach(struct ieee80211com *);
 
 static __inline int
-ieee80211_node_is_authorized(struct ieee80211_node *ni)
+ieee80211_node_is_authorized(const struct ieee80211_node *ni)
 {
 	return (ni->ni_flags & IEEE80211_NODE_AUTH);
 }
@@ -206,6 +206,8 @@
 extern	void ieee80211_create_ibss(struct ieee80211com*,
 		struct ieee80211_channel *);
 extern	void ieee80211_end_scan(struct ieee80211com *);
+extern	int ieee80211_ibss_merge(struct ieee80211com *,
+		struct ieee80211_node *);
 extern	int ieee80211_sta_join(struct ieee80211com *,
 		struct ieee80211_node *);
 extern	void ieee80211_sta_leave(struct ieee80211com *,
@@ -222,6 +224,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];
+	const char		*nt_name;	/* for debugging */
 	u_int			nt_scangen;	/* gen# for timeout scan */
 	int			nt_inact_timer;	/* inactivity timer */
 	int			nt_inact_init;	/* initial node inact setting */
@@ -290,6 +293,9 @@
 		struct ieee80211_node *);
 extern	void ieee80211_dump_nodes(struct ieee80211_node_table *);
 
+extern	struct ieee80211_node *ieee80211_fakeup_adhoc_node(
+		struct ieee80211_node_table *nt,
+		const u_int8_t macaddr[]);
 extern	void ieee80211_node_join(struct ieee80211com *,
 		struct ieee80211_node *, int);
 extern	void ieee80211_node_leave(struct ieee80211com *,


More information about the p4-projects mailing list