Index: ieee80211_scan_sta.c =================================================================== --- ieee80211_scan_sta.c (revision 244051) +++ ieee80211_scan_sta.c (working copy) @@ -51,6 +51,7 @@ #ifdef IEEE80211_SUPPORT_MESH #include #endif +#include #include @@ -1567,6 +1568,7 @@ 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 @@ */ 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 @@ 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 */ Index: ieee80211_node.c =================================================================== --- ieee80211_node.c (revision 244051) +++ ieee80211_node.c (working copy) @@ -771,6 +771,10 @@ /* XXX msg */ return 0; } + + IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, + "%s: mac<%s>\n", __func__, ether_sprintf(se->se_bssid)); + /* * Expand scan state into node's format. * XXX may not need all this stuff @@ -821,6 +825,38 @@ 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. + */ + IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, + "%s: htinfo=%p, htcap=%p\n", + __func__, + ni->ni_ies.htinfo_ie, + ni->ni_ies.htcap_ie); + + /* + * If we have HT information, set it up here. + * + * 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 +974,9 @@ 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; @@ -1194,7 +1233,9 @@ IEEE80211_ADDR_COPY(ni->ni_bssid, bss->ni_bssid); ieee80211_node_initref(ni); /* mark referenced */ /* NB: required by ieee80211_fix_rate */ - ieee80211_node_set_chan(ni, bss->ni_chan); + ieee80211_node_set_chan(ni, + ieee80211_ht_adjust_channel(ic, bss->ni_chan, + ieee80211_htchanflags(bss->ni_chan))); ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE); ni->ni_txpower = bss->ni_txpower; @@ -1404,7 +1445,7 @@ { struct ieee80211_node *ni; - IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, + IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, "%s: mac<%s>\n", __func__, ether_sprintf(macaddr)); ni = ieee80211_dup_bss(vap, macaddr); if (ni != NULL) { @@ -1444,6 +1485,8 @@ 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 +1512,44 @@ 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); + } + + IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC, + "%s: done\n", __func__); } /* @@ -1490,7 +1565,7 @@ { 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) { Index: ieee80211_adhoc.c =================================================================== --- ieee80211_adhoc.c (revision 244078) +++ ieee80211_adhoc.c (working copy) @@ -688,6 +688,7 @@ 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,18 @@ memcpy(ni->ni_tstamp.data, scan.tstamp, sizeof(ni->ni_tstamp)); } + 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; + } if (ni != NULL) { IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi); ni->ni_noise = nf; } + if (ht_state_change) + ieee80211_update_chw(ic); } break; }