]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/mac80211/mesh.c
Merge tag 'mlx5-updates-2017-06-16' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / net / mac80211 / mesh.c
index 7e0498bb933768e0888c90eda738dad0442f13be..a550c707cd8a6130ef5756cedf2fa4738ae9a0e7 100644 (file)
@@ -345,7 +345,7 @@ int mesh_add_vendor_ies(struct ieee80211_sub_if_data *sdata,
                data = ifmsh->ie + offset;
                if (skb_tailroom(skb) < len)
                        return -ENOMEM;
-               memcpy(skb_put(skb, len), data, len);
+               skb_put_data(skb, data, len);
        }
 
        return 0;
@@ -369,7 +369,7 @@ int mesh_add_rsn_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
 
        if (skb_tailroom(skb) < len)
                return -ENOMEM;
-       memcpy(skb_put(skb, len), data, len);
+       skb_put_data(skb, data, len);
 
        return 0;
 }
@@ -690,6 +690,9 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
                   2 + sizeof(struct ieee80211_channel_sw_ie) +
                   /* Mesh Channel Switch Parameters */
                   2 + sizeof(struct ieee80211_mesh_chansw_params_ie) +
+                  /* Channel Switch Wrapper + Wide Bandwidth CSA IE */
+                  2 + 2 + sizeof(struct ieee80211_wide_bw_chansw_ie) +
+                  2 + sizeof(struct ieee80211_sec_chan_offs_ie) +
                   2 + 8 + /* supported rates */
                   2 + 3; /* DS params */
        tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
@@ -716,8 +719,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
        bcn->head = ((u8 *) bcn) + sizeof(*bcn);
 
        /* fill in the head */
-       mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
-       memset(mgmt, 0, hdr_len);
+       mgmt = skb_put_zero(skb, hdr_len);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_BEACON);
        eth_broadcast_addr(mgmt->da);
@@ -736,8 +738,12 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
        rcu_read_lock();
        csa = rcu_dereference(ifmsh->csa);
        if (csa) {
-               pos = skb_put(skb, 13);
-               memset(pos, 0, 13);
+               enum nl80211_channel_type ct;
+               struct cfg80211_chan_def *chandef;
+               int ie_len = 2 + sizeof(struct ieee80211_channel_sw_ie) +
+                            2 + sizeof(struct ieee80211_mesh_chansw_params_ie);
+
+               pos = skb_put_zero(skb, ie_len);
                *pos++ = WLAN_EID_CHANNEL_SWITCH;
                *pos++ = 3;
                *pos++ = 0x0;
@@ -760,6 +766,37 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
                pos += 2;
                put_unaligned_le16(ifmsh->pre_value, pos);
                pos += 2;
+
+               switch (csa->settings.chandef.width) {
+               case NL80211_CHAN_WIDTH_40:
+                       ie_len = 2 + sizeof(struct ieee80211_sec_chan_offs_ie);
+                       pos = skb_put_zero(skb, ie_len);
+
+                       *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; /* EID */
+                       *pos++ = 1;                                 /* len */
+                       ct = cfg80211_get_chandef_type(&csa->settings.chandef);
+                       if (ct == NL80211_CHAN_HT40PLUS)
+                               *pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+                       else
+                               *pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+                       break;
+               case NL80211_CHAN_WIDTH_80:
+               case NL80211_CHAN_WIDTH_80P80:
+               case NL80211_CHAN_WIDTH_160:
+                       /* Channel Switch Wrapper + Wide Bandwidth CSA IE */
+                       ie_len = 2 + 2 +
+                                sizeof(struct ieee80211_wide_bw_chansw_ie);
+                       pos = skb_put_zero(skb, ie_len);
+
+                       *pos++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER; /* EID */
+                       *pos++ = 5;                               /* len */
+                       /* put sub IE */
+                       chandef = &csa->settings.chandef;
+                       ieee80211_ie_build_wide_bw_cs(pos, chandef);
+                       break;
+               default:
+                       break;
+               }
        }
        rcu_read_unlock();
 
@@ -948,12 +985,14 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
        if (!sband)
                return false;
 
-       sta_flags = IEEE80211_STA_DISABLE_VHT;
+       sta_flags = 0;
        switch (sdata->vif.bss_conf.chandef.width) {
        case NL80211_CHAN_WIDTH_20_NOHT:
                sta_flags |= IEEE80211_STA_DISABLE_HT;
        case NL80211_CHAN_WIDTH_20:
                sta_flags |= IEEE80211_STA_DISABLE_40MHZ;
+       case NL80211_CHAN_WIDTH_40:
+               sta_flags |= IEEE80211_STA_DISABLE_VHT;
                break;
        default:
                break;
@@ -1086,8 +1125,8 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
                goto out;
 
        skb_reserve(presp, local->tx_headroom);
-       memcpy(skb_put(presp, bcn->head_len), bcn->head, bcn->head_len);
-       memcpy(skb_put(presp, bcn->tail_len), bcn->tail, bcn->tail_len);
+       skb_put_data(presp, bcn->head, bcn->head_len);
+       skb_put_data(presp, bcn->tail, bcn->tail_len);
        hdr = (struct ieee80211_mgmt *) presp->data;
        hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                         IEEE80211_STYPE_PROBE_RESP);
@@ -1226,7 +1265,7 @@ static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
        if (!skb)
                return -ENOMEM;
        skb_reserve(skb, local->tx_headroom);
-       mgmt_fwd = (struct ieee80211_mgmt *) skb_put(skb, len);
+       mgmt_fwd = skb_put(skb, len);
 
        /* offset_ttl is based on whether the secondary channel
         * offset is available or not. Subtract 1 from the mesh TTL
@@ -1262,7 +1301,7 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
        pos = mgmt->u.action.u.chan_switch.variable;
        baselen = offsetof(struct ieee80211_mgmt,
                           u.action.u.chan_switch.variable);
-       ieee802_11_parse_elems(pos, len - baselen, false, &elems);
+       ieee802_11_parse_elems(pos, len - baselen, true, &elems);
 
        ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl;
        if (!--ifmsh->chsw_ttl)