mac80211: split extra TDLS IEs in setup frames
authorArik Nemtsov <arik@wizery.com>
Thu, 17 Jul 2014 14:14:20 +0000 (17:14 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 21 Jul 2014 10:14:03 +0000 (12:14 +0200)
When building TDLS setup frames, use the IE order mandates in the
specification, splitting extra IEs coming from usermode.

Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/tdls.c

index b61448acc4385cc0e595a37f7664d29a422400cb..8d6c9285752facb292a62a63e812701da1a18f18 100644 (file)
@@ -78,25 +78,91 @@ static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr,
        memcpy(lnkid->resp_sta, peer, ETH_ALEN);
 }
 
+static void
+ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
+                                  struct sk_buff *skb, const u8 *peer,
+                                  u8 action_code, const u8 *extra_ies,
+                                  size_t extra_ies_len)
+{
+       enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
+       size_t offset = 0, noffset;
+       u8 *pos;
+
+       ieee80211_add_srates_ie(sdata, skb, false, band);
+       ieee80211_add_ext_srates_ie(sdata, skb, false, band);
+
+       /* add any custom IEs that go before Extended Capabilities */
+       if (extra_ies_len) {
+               static const u8 before_ext_cap[] = {
+                       WLAN_EID_SUPP_RATES,
+                       WLAN_EID_COUNTRY,
+                       WLAN_EID_EXT_SUPP_RATES,
+                       WLAN_EID_SUPPORTED_CHANNELS,
+                       WLAN_EID_RSN,
+               };
+               noffset = ieee80211_ie_split(extra_ies, extra_ies_len,
+                                            before_ext_cap,
+                                            ARRAY_SIZE(before_ext_cap),
+                                            offset);
+               pos = skb_put(skb, noffset - offset);
+               memcpy(pos, extra_ies + offset, noffset - offset);
+               offset = noffset;
+       }
+
+       ieee80211_tdls_add_ext_capab(skb);
+
+       /* add any custom IEs that go before HT capabilities */
+       if (extra_ies_len) {
+               static const u8 before_ht_cap[] = {
+                       WLAN_EID_SUPP_RATES,
+                       WLAN_EID_COUNTRY,
+                       WLAN_EID_EXT_SUPP_RATES,
+                       WLAN_EID_SUPPORTED_CHANNELS,
+                       WLAN_EID_RSN,
+                       WLAN_EID_EXT_CAPABILITY,
+                       WLAN_EID_QOS_CAPA,
+                       WLAN_EID_FAST_BSS_TRANSITION,
+                       WLAN_EID_TIMEOUT_INTERVAL,
+                       WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
+               };
+               noffset = ieee80211_ie_split(extra_ies, extra_ies_len,
+                                            before_ht_cap,
+                                            ARRAY_SIZE(before_ht_cap),
+                                            offset);
+               pos = skb_put(skb, noffset - offset);
+               memcpy(pos, extra_ies + offset, noffset - offset);
+               offset = noffset;
+       }
+
+       /* add any remaining IEs */
+       if (extra_ies_len) {
+               noffset = extra_ies_len;
+               pos = skb_put(skb, noffset - offset);
+               memcpy(pos, extra_ies + offset, noffset - offset);
+       }
+}
+
 static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata,
                                   struct sk_buff *skb, const u8 *peer,
                                   u8 action_code, bool initiator,
                                   const u8 *extra_ies, size_t extra_ies_len)
 {
        const u8 *init_addr, *rsp_addr;
-       enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
 
        switch (action_code) {
        case WLAN_TDLS_SETUP_REQUEST:
        case WLAN_TDLS_SETUP_RESPONSE:
        case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
-               ieee80211_add_srates_ie(sdata, skb, false, band);
-               ieee80211_add_ext_srates_ie(sdata, skb, false, band);
-               ieee80211_tdls_add_ext_capab(skb);
+               ieee80211_tdls_add_setup_start_ies(sdata, skb, peer,
+                                                  action_code, extra_ies,
+                                                  extra_ies_len);
                break;
        case WLAN_TDLS_SETUP_CONFIRM:
        case WLAN_TDLS_TEARDOWN:
        case WLAN_TDLS_DISCOVERY_REQUEST:
+               if (extra_ies_len)
+                       memcpy(skb_put(skb, extra_ies_len), extra_ies,
+                              extra_ies_len);
                break;
        }
 
@@ -108,9 +174,6 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata,
                rsp_addr = sdata->vif.addr;
        }
 
-       if (extra_ies_len)
-               memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
-
        ieee80211_tdls_add_link_ie(skb, init_addr, rsp_addr,
                                   sdata->u.mgd.bssid);
 }