svn commit: r245928 - head/sys/net80211

Adrian Chadd adrian at FreeBSD.org
Sat Jan 26 00:37:55 UTC 2013


Author: adrian
Date: Sat Jan 26 00:37:54 2013
New Revision: 245928
URL: http://svnweb.freebsd.org/changeset/base/245928

Log:
  Initial cut at making IBSS support 802.11n aware.
  
  * Add HTINFO field decoding to ieee80211_ies_expand() - it's likely not
    100% correct as it's not looking at the draft 11n HTINFO location,
    but I don't think anyone will care.
  
  * When doing an IBSS join make sure the 11n channel configuration
    is used - otherwise the 11a/11bg channel will be used
    and there won't be any chance for an upgrade to 11n.
  
  * When creating an IBSS network, ensure the channel is updated to an
    11n channel so other 11n nodes can see it and speak to it with MCS
    rates.
  
  * Add a bit of code that's disabled for now which handles the HT
    field updating.  This won't work out very well with lots of adhoc
    nodes as we'd end up ping-ponging between the HT configuration for
    each node.  Instead, we should likely only pay attention to the
    "master" node we initially associated against and then ensure we
    propagate that information forward in our subsequent beacons.  However,
    due to the nature of IBSS (ie, there's no specific "master" node in
    the specification) it's unclear which node we should lift the HT
    parameters from.
  
    So for now this assumes the HT parameters are squirreled away in the
    initial beacon/probe response.
  
  So there's some trickiness here.
  
  With ap/sta pairing, the probe response just populates a legacy node
  and the association request/response is what is used for negotiation
  11n-ness (and upgrading things as needed.)
  
  With ibss networks, the pairing is done with probe request/response,
  with discovery being done by creating nodes when new beacons in the
  IBSS / BSSID are heard.  There's no assoc request/response frames going on.
  
  So the trick here has been to figure out where to upgrade things.
  I don't like how I just taught ieee80211_sta_join() to "speak" HT -
  I'd rather there be an upgrade path when an IBSS node joins and there
  are HT parameters present.  Once I've done that, I'll kill this
  HT special casing that's going on in ieee80211_sta_join().
  
  Tested:
  
  * AR9280, AR5416, AR5212 - basic iperf and ping interoperability tests
    whilst in a non-encrypted adhoc network.
  
  TODO:
  
  * Fix up the HT upgrade path for IBSS nodes rather than adding code
    in ieee80211_sta_join(), then remove my code from there.
  
  * When associating, there's a concept of a "master" node in the IBSS
    which is the node you first joined the network through.  It's possible
    the correct thing to do is to listen to HT updates and configure WME
    parameters from that node.  However, once that node goes away, which
    node(s) should be listened to for configuration changes?
  
    For things like HT channel width, it's likely going to be ok to
    just associate as HT40 and then use the per-neighbor rate control
    and HTINFO/HTCAP fields to figure out which rates and configuration
    to speak.  Ie, for a 20MHz 11n node, just speak 20MHz rates to
    it.  It shouldn't "change", like what goes on in AP/STA configurations.

Modified:
  head/sys/net80211/ieee80211_adhoc.c
  head/sys/net80211/ieee80211_node.c
  head/sys/net80211/ieee80211_scan_sta.c

Modified: head/sys/net80211/ieee80211_adhoc.c
==============================================================================
--- head/sys/net80211/ieee80211_adhoc.c	Sat Jan 26 00:14:34 2013	(r245927)
+++ head/sys/net80211/ieee80211_adhoc.c	Sat Jan 26 00:37:54 2013	(r245928)
@@ -688,6 +688,7 @@ adhoc_recv_mgmt(struct ieee80211_node *n
 	struct ieee80211_frame *wh;
 	uint8_t *frm, *efrm, *sfrm;
 	uint8_t *ssid, *rates, *xrates;
+	int ht_state_change = 0;
 
 	wh = mtod(m0, struct ieee80211_frame *);
 	frm = (uint8_t *)&wh[1];
@@ -748,10 +749,27 @@ adhoc_recv_mgmt(struct ieee80211_node *n
 				memcpy(ni->ni_tstamp.data, scan.tstamp,
 					sizeof(ni->ni_tstamp));
 			}
+			/*
+			 * This isn't enabled yet - otherwise it would
+			 * update the HT parameters and channel width
+			 * from any node, which could lead to lots of
+			 * strange behaviour if the 11n nodes aren't
+			 * exactly configured to match.
+			 */
+#if 0
+			if (scan.htcap != NULL && scan.htinfo != NULL &&
+			    (vap->iv_flags_ht & IEEE80211_FHT_HT)) {
+				if (ieee80211_ht_updateparams(ni,
+				    scan.htcap, scan.htinfo))
+					ht_state_change = 1;
+			}
+#endif
 			if (ni != NULL) {
 				IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
 				ni->ni_noise = nf;
 			}
+			if (ht_state_change)
+				ieee80211_update_chw(ic);
 		}
 		break;
 	}

Modified: head/sys/net80211/ieee80211_node.c
==============================================================================
--- head/sys/net80211/ieee80211_node.c	Sat Jan 26 00:14:34 2013	(r245927)
+++ head/sys/net80211/ieee80211_node.c	Sat Jan 26 00:37:54 2013	(r245928)
@@ -771,6 +771,7 @@ ieee80211_sta_join(struct ieee80211vap *
 		/* XXX msg */
 		return 0;
 	}
+
 	/*
 	 * Expand scan state into node's format.
 	 * XXX may not need all this stuff
@@ -821,6 +822,29 @@ ieee80211_sta_join(struct ieee80211vap *
 		IEEE80211_F_DOSORT);
 	if (ieee80211_iserp_rateset(&ni->ni_rates))
 		ni->ni_flags |= IEEE80211_NODE_ERP;
+
+	/*
+	 * Setup HT state for this node if it's available, otherwise
+	 * non-STA modes won't pick this state up.
+	 *
+	 * For IBSS and related modes that don't go through an
+	 * association request/response, the only appropriate place
+	 * to setup the HT state is here.
+	 */
+	if (ni->ni_ies.htinfo_ie != NULL &&
+	    ni->ni_ies.htcap_ie != NULL &&
+	    vap->iv_flags_ht & IEEE80211_FHT_HT) {
+		ieee80211_ht_node_init(ni);
+		ieee80211_ht_updateparams(ni,
+		    ni->ni_ies.htcap_ie,
+		    ni->ni_ies.htinfo_ie);
+		ieee80211_setup_htrates(ni, ni->ni_ies.htcap_ie,
+		    IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
+		ieee80211_setup_basic_htrates(ni, ni->ni_ies.htinfo_ie);
+	}
+	/* XXX else check for ath FF? */
+	/* XXX QoS? Difficult given that WME config is specific to a master */
+
 	ieee80211_node_setuptxparms(ni);
 	ieee80211_ratectl_node_init(ni);
 
@@ -938,6 +962,9 @@ ieee80211_ies_expand(struct ieee80211_ie
 		case IEEE80211_ELEMID_HTCAP:
 			ies->htcap_ie = ie;
 			break;
+		case IEEE80211_ELEMID_HTINFO:
+			ies->htinfo_ie = ie;
+			break;
 #ifdef IEEE80211_SUPPORT_MESH
 		case IEEE80211_ELEMID_MESHID:
 			ies->meshid_ie = ie;
@@ -1404,7 +1431,7 @@ ieee80211_fakeup_adhoc_node(struct ieee8
 {
 	struct ieee80211_node *ni;
 
-	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
+	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE | IEEE80211_MSG_ASSOC,
 	    "%s: mac<%s>\n", __func__, ether_sprintf(macaddr));
 	ni = ieee80211_dup_bss(vap, macaddr);
 	if (ni != NULL) {
@@ -1444,6 +1471,8 @@ ieee80211_init_neighbor(struct ieee80211
 	const struct ieee80211_frame *wh,
 	const struct ieee80211_scanparams *sp)
 {
+	int do_ht_setup = 0;
+
 	ni->ni_esslen = sp->ssid[1];
 	memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]);
 	IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
@@ -1469,12 +1498,41 @@ ieee80211_init_neighbor(struct ieee80211
 		if (ni->ni_ies.ath_ie != NULL)
 			ieee80211_parse_ath(ni, ni->ni_ies.ath_ie);
 #endif
+		if (ni->ni_ies.htcap_ie != NULL)
+			ieee80211_parse_htcap(ni, ni->ni_ies.htcap_ie);
+		if (ni->ni_ies.htinfo_ie != NULL)
+			ieee80211_parse_htinfo(ni, ni->ni_ies.htinfo_ie);
+
+		if ((ni->ni_ies.htcap_ie != NULL) &&
+		    (ni->ni_ies.htinfo_ie != NULL) &&
+		    (ni->ni_vap->iv_flags_ht & IEEE80211_FHT_HT)) {
+			do_ht_setup = 1;
+		}
 	}
 
 	/* NB: must be after ni_chan is setup */
 	ieee80211_setup_rates(ni, sp->rates, sp->xrates,
 		IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
 		IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
+
+	/*
+	 * If the neighbor is HT compatible, flip that on.
+	 */
+	if (do_ht_setup) {
+		IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC,
+		    "%s: doing HT setup\n", __func__);
+		ieee80211_ht_node_init(ni);
+		ieee80211_ht_updateparams(ni,
+		    ni->ni_ies.htcap_ie,
+		    ni->ni_ies.htinfo_ie);
+		ieee80211_setup_htrates(ni,
+		    ni->ni_ies.htcap_ie,
+		    IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
+		ieee80211_setup_basic_htrates(ni,
+		    ni->ni_ies.htinfo_ie);
+		ieee80211_node_setuptxparms(ni);
+		ieee80211_ratectl_node_init(ni);
+	}
 }
 
 /*
@@ -1490,7 +1548,7 @@ ieee80211_add_neighbor(struct ieee80211v
 {
 	struct ieee80211_node *ni;
 
-	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
+	IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
 	    "%s: mac<%s>\n", __func__, ether_sprintf(wh->i_addr2));
 	ni = ieee80211_dup_bss(vap, wh->i_addr2);/* XXX alloc_node? */
 	if (ni != NULL) {

Modified: head/sys/net80211/ieee80211_scan_sta.c
==============================================================================
--- head/sys/net80211/ieee80211_scan_sta.c	Sat Jan 26 00:14:34 2013	(r245927)
+++ head/sys/net80211/ieee80211_scan_sta.c	Sat Jan 26 00:37:54 2013	(r245928)
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
 #ifdef IEEE80211_SUPPORT_MESH
 #include <net80211/ieee80211_mesh.h>
 #endif
+#include <net80211/ieee80211_ratectl.h>
 
 #include <net/bpf.h>
 
@@ -1567,6 +1568,7 @@ adhoc_pick_bss(struct ieee80211_scan_sta
 	struct sta_table *st = ss->ss_priv;
 	struct sta_entry *selbs;
 	struct ieee80211_channel *chan;
+	struct ieee80211com *ic = vap->iv_ic;
 
 	KASSERT(vap->iv_opmode == IEEE80211_M_IBSS ||
 		vap->iv_opmode == IEEE80211_M_AHDEMO ||
@@ -1612,15 +1614,19 @@ notfound:
 			 */
 			if (vap->iv_des_chan == IEEE80211_CHAN_ANYC ||
 			    IEEE80211_IS_CHAN_RADAR(vap->iv_des_chan)) {
-				struct ieee80211com *ic = vap->iv_ic;
-
 				chan = adhoc_pick_channel(ss, 0);
-				if (chan != NULL)
-					chan = ieee80211_ht_adjust_channel(ic,
-					    chan, vap->iv_flags_ht);
 			} else
 				chan = vap->iv_des_chan;
 			if (chan != NULL) {
+				struct ieee80211com *ic = vap->iv_ic;
+				/*
+				 * Create a HT capable IBSS; the per-node
+				 * probe request/response will result in
+				 * "correct" rate control capabilities being
+				 * negotiated.
+				 */
+				chan = ieee80211_ht_adjust_channel(ic,
+				    chan, vap->iv_flags_ht);
 				ieee80211_create_ibss(vap, chan);
 				return 1;
 			}
@@ -1644,6 +1650,14 @@ notfound:
 	chan = selbs->base.se_chan;
 	if (selbs->se_flags & STA_DEMOTE11B)
 		chan = demote11b(vap, chan);
+	/*
+	 * If HT is available, make it a possibility here.
+	 * The intent is to enable HT20/HT40 when joining a non-HT
+	 * IBSS node; we can then advertise HT IEs and speak HT
+	 * to any subsequent nodes that support it.
+	 */
+	chan = ieee80211_ht_adjust_channel(ic,
+	    chan, vap->iv_flags_ht);
 	if (!ieee80211_sta_join(vap, chan, &selbs->base))
 		goto notfound;
 	return 1;				/* terminate scan */


More information about the svn-src-all mailing list