From 869897d2e5c17fa5f3474a9be1d29a41de8510ec Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Tue, 22 Nov 2016 01:22:54 +0000 Subject: [PATCH] [net80211] flesh out more IBSS 11n support * Pepper comments around which describe what state(s) we're in when faking up 11n nodes. * By default don't fake it up as 11n until we properly negotiate the 11n capabilities using probe request/response frames. * Send a probe request with our HT information, as the 802.11-2012 spec suggests. * Reassociate with the driver if we've been promoted. This is done because although learning a peer via beacons can learn 11n state, learning peers via hearing probe frames and broadcast frames does not. Thus, sometimes you end up with an 11n peer in the peer table and sometimes you don't. Note that the probe request/response exchange may not actually succeed. Ideally we'd put the peer into some blocking state until we've exchanged probe request/reponse to learn capabilities, or we timeout and just stay non-11n. This is more an experiment to get 11n IBSS nodes actually discovering each other and be able to transmit. There are other issues that creep up which I'll attempt to address in future commits. Tested: * AR9380 NICs in 11n mode. Reviewed by: avos Differential Revision: https://reviews.freebsd.org/D8365 --- sys/net80211/ieee80211_adhoc.c | 37 +++++++++++++++++- sys/net80211/ieee80211_node.c | 71 +++++++++++++++++++++++++++++++++- 2 files changed, 104 insertions(+), 4 deletions(-) diff --git a/sys/net80211/ieee80211_adhoc.c b/sys/net80211/ieee80211_adhoc.c index f32892651e4e..435a584c92f2 100644 --- a/sys/net80211/ieee80211_adhoc.c +++ b/sys/net80211/ieee80211_adhoc.c @@ -427,8 +427,12 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m, goto err; } /* - * Fake up a node for this newly - * discovered member of the IBSS. + * Fake up a node for this newly discovered member + * of the IBSS. + * + * Note: This doesn't "upgrade" the node to 11n; + * that will happen after a probe request/response + * exchange. */ ni = ieee80211_fakeup_adhoc_node(vap, wh->i_addr2); if (ni == NULL) { @@ -773,12 +777,35 @@ adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, ni = ieee80211_add_neighbor(vap, wh, &scan); else ni = NULL; + + /* + * Send a probe request so we announce 11n + * capabilities. + */ + ieee80211_send_probereq(ni, /* node */ + vap->iv_myaddr, /* SA */ + ni->ni_macaddr, /* DA */ + vap->iv_bss->ni_bssid, /* BSSID */ + vap->iv_bss->ni_essid, + vap->iv_bss->ni_esslen); /* SSID */ + } else if (ni->ni_capinfo == 0) { /* * Update faked node created on transmit. * Note this also updates the tsf. */ ieee80211_init_neighbor(ni, wh, &scan); + + /* + * Send a probe request so we announce 11n + * capabilities. + */ + ieee80211_send_probereq(ni, /* node */ + vap->iv_myaddr, /* SA */ + ni->ni_macaddr, /* DA */ + vap->iv_bss->ni_bssid, /* BSSID */ + vap->iv_bss->ni_essid, + vap->iv_bss->ni_esslen); /* SSID */ } else { /* * Record tsf for potential resync. @@ -889,6 +916,12 @@ adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, */ ieee80211_send_proberesp(vap, wh->i_addr2, is11bclient(rates, xrates) ? IEEE80211_SEND_LEGACY_11B : 0); + + /* + * Note: we don't benefit from stashing the probe request + * IEs away to use for IBSS negotiation, because we + * typically don't get all of the IEs. + */ break; case IEEE80211_FC0_SUBTYPE_ACTION: diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index 05746ad9561e..2d1c03f806fe 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -324,10 +324,11 @@ ieee80211_create_ibss(struct ieee80211vap* vap, struct ieee80211_channel *chan) struct ieee80211_node *ni; IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: creating %s on channel %u%c\n", __func__, + "%s: creating %s on channel %u%c flags 0x%08x\n", __func__, ieee80211_opmode_name[vap->iv_opmode], ieee80211_chan2ieee(ic, chan), - ieee80211_channel_type_char(chan)); + ieee80211_channel_type_char(chan), + chan->ic_flags); ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr); if (ni == NULL) { @@ -408,6 +409,14 @@ ieee80211_create_ibss(struct ieee80211vap* vap, struct ieee80211_channel *chan) } } + /* XXX TODO: other bits and pieces - eg fast-frames? */ + + /* If we're an 11n channel then initialise the 11n bits */ + if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { + /* XXX what else? */ + ieee80211_ht_node_init(ni); + } + (void) ieee80211_sta_join1(ieee80211_ref_node(ni)); } @@ -1549,6 +1558,9 @@ ieee80211_fakeup_adhoc_node(struct ieee80211vap *vap, * so we can do interesting things (e.g. use * WME to disable ACK's). */ + /* + * XXX TODO: 11n? + */ if (vap->iv_flags & IEEE80211_F_WME) ni->ni_flags |= IEEE80211_NODE_QOS; #ifdef IEEE80211_SUPPORT_SUPERG @@ -1558,8 +1570,44 @@ ieee80211_fakeup_adhoc_node(struct ieee80211vap *vap, } ieee80211_node_setuptxparms(ni); ieee80211_ratectl_node_init(ni); + + /* + * XXX TODO: 11n? At least 20MHz, at least A-MPDU RX, + * not A-MPDU TX; not 11n rates, etc. We'll cycle + * that after we hear that we can indeed do 11n + * (either by a beacon frame or by a probe response.) + */ + + /* + * This is the first time we see the node. + */ if (ic->ic_newassoc != NULL) ic->ic_newassoc(ni, 1); + + /* + * Kick off a probe request to the given node; + * we will then use the probe response to update + * 11n/etc configuration state. + * + * XXX TODO: this isn't guaranteed, and until we get + * a probe response, we won't be able to actually + * do anything 802.11n related to the node. + * So if this does indeed work, maybe we should hold + * off on sending responses until we get the probe + * response, or just default to some sensible subset + * of 802.11n behaviour (eg always allow aggregation + * negotiation TO us, but not FROM us, etc) so we + * aren't entirely busted. + */ + if (vap->iv_opmode == IEEE80211_M_IBSS) { + ieee80211_send_probereq(ni, /* node */ + vap->iv_myaddr, /* SA */ + ni->ni_macaddr, /* DA */ + vap->iv_bss->ni_bssid, /* BSSID */ + vap->iv_bss->ni_essid, + vap->iv_bss->ni_esslen); /* SSID */ + } + /* XXX not right for 802.1x/WPA */ ieee80211_node_authorize(ni); } @@ -1632,6 +1680,21 @@ ieee80211_init_neighbor(struct ieee80211_node *ni, ni->ni_ies.htinfo_ie); ieee80211_node_setuptxparms(ni); ieee80211_ratectl_node_init(ni); + + /* Reassociate; we're now 11n */ + /* + * XXX TODO: this is the wrong thing to do - + * we're calling it with isnew=1 so the ath(4) + * driver reinitialises the rate tables. + * This "mostly" works for ath(4), but it won't + * be right for firmware devices which allocate + * node states. + * + * So, do we just create a new node and delete + * the old one? Or? + */ + if (ni->ni_ic->ic_newassoc) + ni->ni_ic->ic_newassoc(ni, 1); } } @@ -1809,6 +1872,10 @@ ieee80211_find_txnode(struct ieee80211vap *vap, * caller to be consistent with * ieee80211_find_node_locked. */ + /* + * XXX TODO: this doesn't fake up 11n state; we need + * to find another way to get it upgraded. + */ ni = ieee80211_fakeup_adhoc_node(vap, macaddr); if (ni != NULL) (void) ieee80211_ref_node(ni);