11n: HT negotiation fixes

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

11n: HT negotiation fixes

Stefan Sperling-5
Some APs will not negotiate 11n (aka HT) if the vendor-specific WME
(Wireless Multimedia Extensions) info element is missing in probe
and association requests. WME info essentially tells the other end
that we're QoS capable, which is a requirement for 11n (e.g. A-MPDUs
are sent in QoS data frames).
The 802.11-2012 standard defines other ways of indicating QoS support
which we already use. WME is not part of this standard but I'm adding
it for interoperability. FreeBSD and Linux send a WME info element, too.
Since this is an ugly vendor-specific element I decided to use magic
numbers instead of IEEE80211_ defines. I have no document explaining
what these numbers really mean, and Linux and FreeBSD use different
terminology. I put the names FreeBSD uses in comments.

Also, fix bugs where the wrong flag was checked to determine whether
11n-related elements should be included in management frames.
If 11n mode is enabled (F_HTON flag) we can always include 11n related
elements in management frames we send out, regardless of whether the
other STAs or APs support 11n.
The NODE_HT flag is only set once HT has been negotiated with a peer,
i.e. after exchanging assoc request and response with the AP.
Checking this flag earlier, e.g. in ieee80211_get_assoc_resp(), is wrong.

Index: net80211/ieee80211_output.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_output.c,v
retrieving revision 1.101
diff -u -p -r1.101 ieee80211_output.c
--- net80211/ieee80211_output.c 24 Nov 2015 12:32:53 -0000 1.101
+++ net80211/ieee80211_output.c 12 Dec 2015 10:12:58 -0000
@@ -94,6 +94,7 @@ struct mbuf *ieee80211_get_addba_resp(st
     struct ieee80211_node *, u_int8_t, u_int8_t, u_int16_t);
 struct mbuf *ieee80211_get_delba(struct ieee80211com *,
     struct ieee80211_node *, u_int8_t, u_int8_t, u_int16_t);
+uint8_t *ieee80211_add_wme_info(uint8_t *, struct ieee80211com *);
 #endif
 struct mbuf *ieee80211_get_sa_query(struct ieee80211com *,
     struct ieee80211_node *, u_int8_t);
@@ -831,6 +832,26 @@ ieee80211_add_qos_capability(u_int8_t *f
  return frm;
 }
 
+#ifndef IEEE80211_NO_HT
+/*
+ * Add a Wifi-Alliance WME (aka WMM) info element to a frame.
+ * WME is a requirement for Wifi-Alliance compliance and some
+ * 11n APs will not negotiate HT if this element is missing.
+ */
+uint8_t *
+ieee80211_add_wme_info(uint8_t *frm, struct ieee80211com *ic)
+{
+ *frm++ = IEEE80211_ELEMID_VENDOR;
+ *frm++ = 7;
+ memcpy(frm, MICROSOFT_OUI, 3); frm += 3;
+ *frm++ = 2; /* OUI type */
+ *frm++ = 0; /* OUI subtype */
+ *frm++ = 1; /* version */
+ *frm++ = 0; /* info */
+
+ return frm;
+}
+#endif
 /*
  * Add an RSN element to a frame (see 802.11-2012 8.4.2.27)
  */
@@ -1097,7 +1118,7 @@ ieee80211_get_probe_req(struct ieee80211
     2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) +
     ((rs->rs_nrates > IEEE80211_RATE_SIZE) ?
  2 + rs->rs_nrates - IEEE80211_RATE_SIZE : 0) +
-    ((ni->ni_flags & IEEE80211_NODE_HT) ? 28 : 0));
+    ((ic->ic_flags & IEEE80211_F_HTON) ? 28 + 9 : 0));
  if (m == NULL)
  return NULL;
 
@@ -1107,8 +1128,10 @@ ieee80211_get_probe_req(struct ieee80211
  if (rs->rs_nrates > IEEE80211_RATE_SIZE)
  frm = ieee80211_add_xrates(frm, rs);
 #ifndef IEEE80211_NO_HT
- if (ni->ni_flags & IEEE80211_NODE_HT)
+ if (ic->ic_flags & IEEE80211_F_HTON) {
  frm = ieee80211_add_htcaps(frm, ic);
+ frm = ieee80211_add_wme_info(frm, ic);
+ }
 #endif
 
  m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
@@ -1278,7 +1301,7 @@ ieee80211_get_assoc_req(struct ieee80211
     (((ic->ic_flags & IEEE80211_F_RSNON) &&
       (ni->ni_rsnprotos & IEEE80211_PROTO_WPA)) ?
  2 + IEEE80211_WPAIE_MAXLEN : 0) +
-    ((ni->ni_flags & IEEE80211_NODE_HT) ? 28 : 0));
+    ((ic->ic_flags & IEEE80211_F_HTON) ? 28 + 9 : 0));
  if (m == NULL)
  return NULL;
 
@@ -1310,8 +1333,10 @@ ieee80211_get_assoc_req(struct ieee80211
     (ni->ni_rsnprotos & IEEE80211_PROTO_WPA))
  frm = ieee80211_add_wpa(frm, ic, ni);
 #ifndef IEEE80211_NO_HT
- if (ni->ni_flags & IEEE80211_NODE_HT)
+ if (ic->ic_flags & IEEE80211_F_HTON) {
  frm = ieee80211_add_htcaps(frm, ic);
+ frm = ieee80211_add_wme_info(frm, ic);
+ }
 #endif
 
  m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
@@ -1347,7 +1372,7 @@ ieee80211_get_assoc_resp(struct ieee8021
  2 + rs->rs_nrates - IEEE80211_RATE_SIZE : 0) +
     ((ni->ni_flags & IEEE80211_NODE_QOS) ? 2 + 18 : 0) +
     ((status == IEEE80211_STATUS_TRY_AGAIN_LATER) ? 2 + 7 : 0) +
-    ((ni->ni_flags & IEEE80211_NODE_HT) ? 28 + 24 : 0));
+    ((ic->ic_flags & IEEE80211_F_HTON) ? 28 + 24 : 0));
  if (m == NULL)
  return NULL;
 
@@ -1370,7 +1395,7 @@ ieee80211_get_assoc_resp(struct ieee8021
  frm = ieee80211_add_tie(frm, 3, 1000 /* XXX */);
  }
 #ifndef IEEE80211_NO_HT
- if (ni->ni_flags & IEEE80211_NODE_HT) {
+ if (ic->ic_flags & IEEE80211_F_HTON) {
  frm = ieee80211_add_htcaps(frm, ic);
  frm = ieee80211_add_htop(frm, ic);
  }


Reply | Threaded
Open this post in threaded view
|

Re: 11n: HT negotiation fixes

Martin Pieuchot
On 12/12/15(Sat) 11:34, Stefan Sperling wrote:

> Some APs will not negotiate 11n (aka HT) if the vendor-specific WME
> (Wireless Multimedia Extensions) info element is missing in probe
> and association requests. WME info essentially tells the other end
> that we're QoS capable, which is a requirement for 11n (e.g. A-MPDUs
> are sent in QoS data frames).
> The 802.11-2012 standard defines other ways of indicating QoS support
> which we already use. WME is not part of this standard but I'm adding
> it for interoperability. FreeBSD and Linux send a WME info element, too.
> Since this is an ugly vendor-specific element I decided to use magic
> numbers instead of IEEE80211_ defines. I have no document explaining
> what these numbers really mean, and Linux and FreeBSD use different
> terminology. I put the names FreeBSD uses in comments.
>
> Also, fix bugs where the wrong flag was checked to determine whether
> 11n-related elements should be included in management frames.
> If 11n mode is enabled (F_HTON flag) we can always include 11n related
> elements in management frames we send out, regardless of whether the
> other STAs or APs support 11n.
> The NODE_HT flag is only set once HT has been negotiated with a peer,
> i.e. after exchanging assoc request and response with the AP.
> Checking this flag earlier, e.g. in ieee80211_get_assoc_resp(), is wrong.

ok mpi@

> Index: net80211/ieee80211_output.c
> ===================================================================
> RCS file: /cvs/src/sys/net80211/ieee80211_output.c,v
> retrieving revision 1.101
> diff -u -p -r1.101 ieee80211_output.c
> --- net80211/ieee80211_output.c 24 Nov 2015 12:32:53 -0000 1.101
> +++ net80211/ieee80211_output.c 12 Dec 2015 10:12:58 -0000
> @@ -94,6 +94,7 @@ struct mbuf *ieee80211_get_addba_resp(st
>      struct ieee80211_node *, u_int8_t, u_int8_t, u_int16_t);
>  struct mbuf *ieee80211_get_delba(struct ieee80211com *,
>      struct ieee80211_node *, u_int8_t, u_int8_t, u_int16_t);
> +uint8_t *ieee80211_add_wme_info(uint8_t *, struct ieee80211com *);
>  #endif
>  struct mbuf *ieee80211_get_sa_query(struct ieee80211com *,
>      struct ieee80211_node *, u_int8_t);
> @@ -831,6 +832,26 @@ ieee80211_add_qos_capability(u_int8_t *f
>   return frm;
>  }
>  
> +#ifndef IEEE80211_NO_HT
> +/*
> + * Add a Wifi-Alliance WME (aka WMM) info element to a frame.
> + * WME is a requirement for Wifi-Alliance compliance and some
> + * 11n APs will not negotiate HT if this element is missing.
> + */
> +uint8_t *
> +ieee80211_add_wme_info(uint8_t *frm, struct ieee80211com *ic)
> +{
> + *frm++ = IEEE80211_ELEMID_VENDOR;
> + *frm++ = 7;
> + memcpy(frm, MICROSOFT_OUI, 3); frm += 3;
> + *frm++ = 2; /* OUI type */
> + *frm++ = 0; /* OUI subtype */
> + *frm++ = 1; /* version */
> + *frm++ = 0; /* info */
> +
> + return frm;
> +}
> +#endif
>  /*
>   * Add an RSN element to a frame (see 802.11-2012 8.4.2.27)
>   */
> @@ -1097,7 +1118,7 @@ ieee80211_get_probe_req(struct ieee80211
>      2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) +
>      ((rs->rs_nrates > IEEE80211_RATE_SIZE) ?
>   2 + rs->rs_nrates - IEEE80211_RATE_SIZE : 0) +
> -    ((ni->ni_flags & IEEE80211_NODE_HT) ? 28 : 0));
> +    ((ic->ic_flags & IEEE80211_F_HTON) ? 28 + 9 : 0));
>   if (m == NULL)
>   return NULL;
>  
> @@ -1107,8 +1128,10 @@ ieee80211_get_probe_req(struct ieee80211
>   if (rs->rs_nrates > IEEE80211_RATE_SIZE)
>   frm = ieee80211_add_xrates(frm, rs);
>  #ifndef IEEE80211_NO_HT
> - if (ni->ni_flags & IEEE80211_NODE_HT)
> + if (ic->ic_flags & IEEE80211_F_HTON) {
>   frm = ieee80211_add_htcaps(frm, ic);
> + frm = ieee80211_add_wme_info(frm, ic);
> + }
>  #endif
>  
>   m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
> @@ -1278,7 +1301,7 @@ ieee80211_get_assoc_req(struct ieee80211
>      (((ic->ic_flags & IEEE80211_F_RSNON) &&
>        (ni->ni_rsnprotos & IEEE80211_PROTO_WPA)) ?
>   2 + IEEE80211_WPAIE_MAXLEN : 0) +
> -    ((ni->ni_flags & IEEE80211_NODE_HT) ? 28 : 0));
> +    ((ic->ic_flags & IEEE80211_F_HTON) ? 28 + 9 : 0));
>   if (m == NULL)
>   return NULL;
>  
> @@ -1310,8 +1333,10 @@ ieee80211_get_assoc_req(struct ieee80211
>      (ni->ni_rsnprotos & IEEE80211_PROTO_WPA))
>   frm = ieee80211_add_wpa(frm, ic, ni);
>  #ifndef IEEE80211_NO_HT
> - if (ni->ni_flags & IEEE80211_NODE_HT)
> + if (ic->ic_flags & IEEE80211_F_HTON) {
>   frm = ieee80211_add_htcaps(frm, ic);
> + frm = ieee80211_add_wme_info(frm, ic);
> + }
>  #endif
>  
>   m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
> @@ -1347,7 +1372,7 @@ ieee80211_get_assoc_resp(struct ieee8021
>   2 + rs->rs_nrates - IEEE80211_RATE_SIZE : 0) +
>      ((ni->ni_flags & IEEE80211_NODE_QOS) ? 2 + 18 : 0) +
>      ((status == IEEE80211_STATUS_TRY_AGAIN_LATER) ? 2 + 7 : 0) +
> -    ((ni->ni_flags & IEEE80211_NODE_HT) ? 28 + 24 : 0));
> +    ((ic->ic_flags & IEEE80211_F_HTON) ? 28 + 24 : 0));
>   if (m == NULL)
>   return NULL;
>  
> @@ -1370,7 +1395,7 @@ ieee80211_get_assoc_resp(struct ieee8021
>   frm = ieee80211_add_tie(frm, 3, 1000 /* XXX */);
>   }
>  #ifndef IEEE80211_NO_HT
> - if (ni->ni_flags & IEEE80211_NODE_HT) {
> + if (ic->ic_flags & IEEE80211_F_HTON) {
>   frm = ieee80211_add_htcaps(frm, ic);
>   frm = ieee80211_add_htop(frm, ic);
>   }
>
>