From 77fcb66609b87cf27f7e07e571cb4a447df60bad Mon Sep 17 00:00:00 2001 From: Stefan Sperling Date: Sun, 15 Nov 2015 12:34:08 +0000 Subject: Expose 11n mode to the ifmedia layer and introduce the concept of MCS. Make sure 11n features are enabled only if media type is autoselect or 11n. 11n mode uses MCS (modulation & coding scheme) instead of rates like 11a/b/g. This means we'll have to take the current mode into account and decide whether to use a rate or an MCS for transmission. Receiving frames on legacy rates will still work in 11n mode. We just won't be using legacy rates to send data frames to an STA or AP we negotiated 11n features with. My initial plan was to grow the ieee80211_rateset structure and treat MCS just like rates. However, ieee80211_rateset corresponds to rates and xrates elements in management frames and is copied directly into such elements so its size cannot change. Thus, MCS stands on its own and corresponds to elements in management frames related to 11n HT capabilities. ok deraadt mpi phessler kettenis guenther --- sys/net80211/ieee80211.c | 182 +++++++++++++++++++++++++++++++++++++---- sys/net80211/ieee80211_node.h | 4 +- sys/net80211/ieee80211_proto.c | 35 ++++++-- sys/net80211/ieee80211_var.h | 7 +- 4 files changed, 202 insertions(+), 26 deletions(-) diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c index 0355126b2cf..e67312c2ffa 100644 --- a/sys/net80211/ieee80211.c +++ b/sys/net80211/ieee80211.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211.c,v 1.49 2015/11/15 10:21:58 stsp Exp $ */ +/* $OpenBSD: ieee80211.c,v 1.50 2015/11/15 12:34:07 stsp Exp $ */ /* $NetBSD: ieee80211.c,v 1.19 2004/06/06 05:45:29 dyoung Exp $ */ /*- @@ -111,6 +111,10 @@ ieee80211_channel_init(struct ifnet *ifp) ic->ic_modecaps |= 1<ic_modecaps |= 1<ic_modecaps |= 1<ic_curmode */ @@ -351,6 +355,34 @@ ieee80211_media_init(struct ifnet *ifp, if (ic->ic_caps & IEEE80211_C_MONITOR) ADD(ic, mword, IFM_IEEE80211_MONITOR); } + +#ifndef IEEE80211_NO_HT + if (ic->ic_modecaps & (1 << IEEE80211_MODE_11N)) { + mopt = IFM_IEEE80211_11N; + ADD(ic, IFM_AUTO, mopt); +#ifndef IEEE80211_STA_ONLY + if (ic->ic_caps & IEEE80211_C_IBSS) + ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_IBSS); + if (ic->ic_caps & IEEE80211_C_HOSTAP) + ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_HOSTAP); +#endif + for (i = 0; i < IEEE80211_HT_NUM_MCS; i++) { + if (!isset(ic->ic_sup_mcs, i)) + continue; + ADD(ic, IFM_IEEE80211_HT_MCS0 + i, mopt); +#ifndef IEEE80211_STA_ONLY + if (ic->ic_caps & IEEE80211_C_IBSS) + ADD(ic, IFM_IEEE80211_HT_MCS0 + i, + mopt | IFM_IEEE80211_IBSS); + if (ic->ic_caps & IEEE80211_C_HOSTAP) + ADD(ic, IFM_IEEE80211_HT_MCS0 + i, + mopt | IFM_IEEE80211_HOSTAP); +#endif + } + ic->ic_flags |= IEEE80211_F_HTON; /* enable 11n by default */ + } +#endif /* IEEE80211_NO_HT */ + ieee80211_media_status(ifp, &imr); ifmedia_set(&ic->ic_media, imr.ifm_active); @@ -400,6 +432,11 @@ ieee80211_media_change(struct ifnet *ifp) case IFM_IEEE80211_11G: newphymode = IEEE80211_MODE_11G; break; +#ifndef IEEE80211_NO_HT + case IFM_IEEE80211_11N: + newphymode = IEEE80211_MODE_11N; + break; +#endif case IFM_AUTO: newphymode = IEEE80211_MODE_AUTO; break; @@ -425,7 +462,21 @@ ieee80211_media_change(struct ifnet *ifp) * Next, the fixed/variable rate. */ i = -1; - if (IFM_SUBTYPE(ime->ifm_media) != IFM_AUTO) { + if (IFM_SUBTYPE(ime->ifm_media) >= IFM_IEEE80211_HT_MCS0 && + IFM_SUBTYPE(ime->ifm_media) <= IFM_IEEE80211_HT_MCS76) { +#ifndef IEEE80211_NO_HT + if ((ic->ic_modecaps & (1 << IEEE80211_MODE_11N)) == 0) + return EINVAL; + if (newphymode != IEEE80211_MODE_AUTO || + newphymode != IEEE80211_MODE_11N) + return EINVAL; + i = ieee80211_media2mcs(ime->ifm_media); + if (i == -1 || isclr(ic->ic_sup_mcs, i)) + return EINVAL; +#else + return EINVAL; +#endif + } else if (IFM_SUBTYPE(ime->ifm_media) != IFM_AUTO) { /* * Convert media subtype to rate. */ @@ -484,11 +535,17 @@ ieee80211_media_change(struct ifnet *ifp) */ if (newopmode == IEEE80211_M_HOSTAP && newphymode == IEEE80211_MODE_AUTO) { - for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++) - if (ic->ic_modecaps & (1<ic_modecaps & (1 << IEEE80211_MODE_11N)) + newphymode = IEEE80211_MODE_11N; + else +#endif + if (ic->ic_modecaps & (1 << IEEE80211_MODE_11A)) + newphymode = IEEE80211_MODE_11A; + else if (ic->ic_modecaps & (1 << IEEE80211_MODE_11G)) + newphymode = IEEE80211_MODE_11G; + else + newphymode = IEEE80211_MODE_11B; } #endif @@ -503,12 +560,33 @@ ieee80211_media_change(struct ifnet *ifp) } /* - * Committed to changes, install the rate setting. + * Committed to changes, install the MCS/rate setting. */ - if (ic->ic_fixed_rate != i) { - ic->ic_fixed_rate = i; /* set fixed tx rate */ - error = ENETRESET; + ic->ic_flags &= ~IEEE80211_F_HTON; +#ifndef IEEE80211_NO_HT + if ((ic->ic_modecaps & (1 << IEEE80211_MODE_11N)) && + (newphymode == IEEE80211_MODE_AUTO || + newphymode == IEEE80211_MODE_11N)) + ic->ic_flags |= IEEE80211_F_HTON; +#endif + if ((ic->ic_flags & IEEE80211_F_HTON) == 0) { +#ifndef IEEE80211_NO_HT + ic->ic_fixed_mcs = -1; +#endif + if (ic->ic_fixed_rate != i) { + ic->ic_fixed_rate = i; /* set fixed tx rate */ + error = ENETRESET; + } + } +#ifndef IEEE80211_NO_HT + else { + ic->ic_fixed_rate = -1; + if (ic->ic_fixed_mcs != i) { + ic->ic_fixed_mcs = i; /* set fixed mcs */ + error = ENETRESET; + } } +#endif /* * Handle operating mode change. @@ -560,9 +638,16 @@ ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr) switch (ic->ic_opmode) { case IEEE80211_M_STA: ni = ic->ic_bss; - /* calculate rate subtype */ - imr->ifm_active |= ieee80211_rate2media(ic, - ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode); +#ifndef IEEE80211_NO_HT + if (ic->ic_curmode == IEEE80211_MODE_11N) + imr->ifm_active |= ieee80211_mcs2media(ic, + ni->ni_txmcs, ic->ic_curmode); + else +#endif + /* calculate rate subtype */ + imr->ifm_active |= ieee80211_rate2media(ic, + ni->ni_rates.rs_rates[ni->ni_txrate], + ic->ic_curmode); break; #ifndef IEEE80211_STA_ONLY case IEEE80211_M_IBSS: @@ -595,6 +680,11 @@ ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr) imr->ifm_active |= IFM_IEEE80211_11A | IFM_IEEE80211_TURBO; break; +#ifndef IEEE80211_NO_HT + case IEEE80211_MODE_11N: + imr->ifm_active |= IFM_IEEE80211_11N; + break; +#endif } } @@ -672,6 +762,9 @@ ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode) IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */ IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_11G */ IEEE80211_CHAN_T, /* IEEE80211_MODE_TURBO */ +#ifndef IEEE80211_NO_HT + IEEE80211_CHAN_HT, /* IEEE80211_MODE_11N */ +#endif }; const struct ieee80211_channel *c; u_int modeflags; @@ -771,10 +864,12 @@ ieee80211_next_mode(struct ifnet *ifp) * Get the next supported mode */ for (++ic->ic_curmode; - ic->ic_curmode <= IEEE80211_MODE_TURBO; + ic->ic_curmode <= IEEE80211_MODE_MAX; ic->ic_curmode++) { /* Wrap around and ignore turbo mode */ - if (ic->ic_curmode >= IEEE80211_MODE_TURBO) { + if (ic->ic_curmode == IEEE80211_MODE_TURBO) + continue; + if (ic->ic_curmode >= IEEE80211_MODE_MAX) { ic->ic_curmode = IEEE80211_MODE_AUTO; break; } @@ -811,6 +906,11 @@ ieee80211_chan2mode(struct ieee80211com *ic, * characteristics. We assume that turbo-only channels * are not considered when the channel set is constructed. */ +#ifndef IEEE80211_NO_HT + if (IEEE80211_IS_CHAN_N(chan)) + return IEEE80211_MODE_11N; + else +#endif if (IEEE80211_IS_CHAN_T(chan)) return IEEE80211_MODE_TURBO; else if (IEEE80211_IS_CHAN_5GHZ(chan)) @@ -821,6 +921,56 @@ ieee80211_chan2mode(struct ieee80211com *ic, return IEEE80211_MODE_11B; } +#ifndef IEEE80211_NO_HT +/* + * Convert IEEE80211 MCS index to ifmedia subtype. + */ +uint64_t +ieee80211_mcs2media(struct ieee80211com *ic, int mcs, + enum ieee80211_phymode mode) +{ + switch (mode) { + case IEEE80211_MODE_11A: + case IEEE80211_MODE_TURBO: + case IEEE80211_MODE_11B: + case IEEE80211_MODE_11G: + /* these modes use rates, not MCS */ + panic("unexpected mode %d", mode); + break; + case IEEE80211_MODE_AUTO: + case IEEE80211_MODE_11N: + if (mcs >= 0 && mcs < IEEE80211_HT_NUM_MCS) + return (IFM_IEEE80211_11N | + (IFM_IEEE80211_HT_MCS0 + mcs)); + break; + } + + return IFM_AUTO; +} + +/* + * Convert ifmedia subtype to IEEE80211 MCS index. + */ +int +ieee80211_media2mcs(uint64_t mword) +{ + uint64_t subtype; + + subtype = IFM_SUBTYPE(mword); + + if (subtype == IFM_AUTO) + return -1; + else if (subtype == IFM_MANUAL || subtype == IFM_NONE) + return 0; + + if (subtype >= IFM_IEEE80211_HT_MCS0 && + subtype <= IFM_IEEE80211_HT_MCS76) + return (int)(subtype - IFM_IEEE80211_HT_MCS0); + + return -1; +} +#endif /* IEEE80211_NO_HT */ + /* * convert IEEE80211 rate value to ifmedia subtype. * ieee80211 rate is in unit of 0.5Mbps. diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h index 0f27250066e..59f17633cc4 100644 --- a/sys/net80211/ieee80211_node.h +++ b/sys/net80211/ieee80211_node.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_node.h,v 1.48 2015/11/15 10:07:03 stsp Exp $ */ +/* $OpenBSD: ieee80211_node.h,v 1.49 2015/11/15 12:34:07 stsp Exp $ */ /* $NetBSD: ieee80211_node.h,v 1.9 2004/04/30 22:57:32 dyoung Exp $ */ /*- @@ -241,6 +241,8 @@ struct ieee80211_node { /* Block Ack records */ struct ieee80211_tx_ba ni_tx_ba[IEEE80211_NUM_TID]; struct ieee80211_rx_ba ni_rx_ba[IEEE80211_NUM_TID]; + + int ni_txmcs; /* current MCS used for TX */ #endif /* others */ diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c index 411a7632630..9f1d6ebbf9e 100644 --- a/sys/net80211/ieee80211_proto.c +++ b/sys/net80211/ieee80211_proto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_proto.c,v 1.54 2015/11/15 11:14:17 stsp Exp $ */ +/* $OpenBSD: ieee80211_proto.c,v 1.55 2015/11/15 12:34:07 stsp Exp $ */ /* $NetBSD: ieee80211_proto.c,v 1.8 2004/04/30 23:58:20 dyoung Exp $ */ /*- @@ -75,6 +75,7 @@ const char * const ieee80211_phymode_name[] = { "11b", /* IEEE80211_MODE_11B */ "11g", /* IEEE80211_MODE_11G */ "turbo", /* IEEE80211_MODE_TURBO */ + "11n", /* IEEE80211_MODE_11N */ }; int ieee80211_newstate(struct ieee80211com *, enum ieee80211_state, int); @@ -96,6 +97,9 @@ ieee80211_proto_attach(struct ifnet *ifp) #endif ic->ic_fragthreshold = 2346; /* XXX not used yet */ ic->ic_fixed_rate = -1; /* no fixed rate */ +#ifndef IEEE80211_NO_HT + ic->ic_fixed_mcs = -1; /* no fixed mcs */ +#endif ic->ic_protmode = IEEE80211_PROT_CTSONLY; /* protocol state change handler */ @@ -891,8 +895,15 @@ justcleanup: /* initialize bss for probe request */ IEEE80211_ADDR_COPY(ni->ni_macaddr, etherbroadcastaddr); IEEE80211_ADDR_COPY(ni->ni_bssid, etherbroadcastaddr); - ni->ni_rates = ic->ic_sup_rates[ - ieee80211_chan2mode(ic, ni->ni_chan)]; +#ifndef IEEE80211_NO_HT + if (ic->ic_curmode == IEEE80211_MODE_11N) + ni->ni_rates = ic->ic_sup_rates[ + IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) ? + IEEE80211_MODE_11G : IEEE80211_MODE_11A]; + else +#endif + ni->ni_rates = ic->ic_sup_rates[ + ieee80211_chan2mode(ic, ni->ni_chan)]; ni->ni_associd = 0; ni->ni_rstamp = 0; switch (ostate) { @@ -1013,16 +1024,24 @@ justcleanup: ni->ni_esslen); rate = ni->ni_rates.rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL; - printf(" channel %d start %u%sMb", - ieee80211_chan2ieee(ic, ni->ni_chan), - rate / 2, (rate & 1) ? ".5" : ""); - printf(" %s preamble %s slot time%s\n", + printf(" channel %d", + ieee80211_chan2ieee(ic, ni->ni_chan)); +#ifndef IEEE80211_NO_HT + if (ni->ni_flags & IEEE80211_NODE_HT) + printf(" start MCS %u", ni->ni_txmcs); + else +#endif + printf(" start %u%sMb", + rate / 2, (rate & 1) ? ".5" : ""); + printf(" %s preamble %s slot time%s%s\n", (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? "short" : "long", (ic->ic_flags & IEEE80211_F_SHSLOT) ? "short" : "long", (ic->ic_flags & IEEE80211_F_USEPROT) ? - " protection enabled" : ""); + " protection enabled" : "", + (ni->ni_flags & IEEE80211_NODE_HT) ? + " HT enabled" : ""); } if (!(ic->ic_flags & IEEE80211_F_RSNON)) { /* diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h index eceffc80841..b2a1193060c 100644 --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_var.h,v 1.66 2015/11/15 01:05:25 stsp Exp $ */ +/* $OpenBSD: ieee80211_var.h,v 1.67 2015/11/15 12:34:07 stsp Exp $ */ /* $NetBSD: ieee80211_var.h,v 1.7 2004/05/06 03:07:10 dyoung Exp $ */ /*- @@ -400,6 +400,11 @@ int ieee80211_fix_rate(struct ieee80211com *, struct ieee80211_node *, int); uint64_t ieee80211_rate2media(struct ieee80211com *, int, enum ieee80211_phymode); int ieee80211_media2rate(uint64_t); +#ifndef IEEE80211_NO_HT +uint64_t ieee80211_mcs2media(struct ieee80211com *, int, + enum ieee80211_phymode); +int ieee80211_media2mcs(uint64_t); +#endif u_int8_t ieee80211_rate2plcp(u_int8_t, enum ieee80211_phymode); u_int8_t ieee80211_plcp2rate(u_int8_t, enum ieee80211_phymode); u_int ieee80211_mhz2ieee(u_int, u_int); -- cgit v1.2.3