mac80211: add fast-rx path
[cascardo/linux.git] / net / mac80211 / cfg.c
index 166a29f..fc4730b 100644 (file)
@@ -65,11 +65,13 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
                return ret;
 
        if (type == NL80211_IFTYPE_AP_VLAN &&
-           params && params->use_4addr == 0)
+           params && params->use_4addr == 0) {
                RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
-       else if (type == NL80211_IFTYPE_STATION &&
-                params && params->use_4addr >= 0)
+               ieee80211_check_fast_rx_iface(sdata);
+       } else if (type == NL80211_IFTYPE_STATION &&
+                  params && params->use_4addr >= 0) {
                sdata->u.mgd.use_4addr = params->use_4addr;
+       }
 
        if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) {
                struct ieee80211_local *local = sdata->local;
@@ -339,8 +341,9 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
 
        switch (key->conf.cipher) {
        case WLAN_CIPHER_SUITE_TKIP:
-               iv32 = key->u.tkip.tx.iv32;
-               iv16 = key->u.tkip.tx.iv16;
+               pn64 = atomic64_read(&key->conf.tx_pn);
+               iv32 = TKIP_PN_TO_IV32(pn64);
+               iv16 = TKIP_PN_TO_IV16(pn64);
 
                if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
                    !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
@@ -731,6 +734,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
        sdata->vif.bss_conf.beacon_int = params->beacon_interval;
        sdata->vif.bss_conf.dtim_period = params->dtim_period;
        sdata->vif.bss_conf.enable_beacon = true;
+       sdata->vif.bss_conf.allow_p2p_go_ps = sdata->vif.p2p;
 
        sdata->vif.bss_conf.ssid_len = params->ssid_len;
        if (params->ssid_len)
@@ -1131,6 +1135,34 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                sta->sta.max_sp = params->max_sp;
        }
 
+       /* The sender might not have sent the last bit, consider it to be 0 */
+       if (params->ext_capab_len >= 8) {
+               u8 val = (params->ext_capab[7] &
+                         WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB) >> 7;
+
+               /* we did get all the bits, take the MSB as well */
+               if (params->ext_capab_len >= 9) {
+                       u8 val_msb = params->ext_capab[8] &
+                               WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB;
+                       val_msb <<= 1;
+                       val |= val_msb;
+               }
+
+               switch (val) {
+               case 1:
+                       sta->sta.max_amsdu_subframes = 32;
+                       break;
+               case 2:
+                       sta->sta.max_amsdu_subframes = 16;
+                       break;
+               case 3:
+                       sta->sta.max_amsdu_subframes = 8;
+                       break;
+               default:
+                       sta->sta.max_amsdu_subframes = 0;
+               }
+       }
+
        /*
         * cfg80211 validates this (1-2007) and allows setting the AID
         * only when creating a new station entry
@@ -1160,6 +1192,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
                                                  params->ht_capa, sta);
 
+       /* VHT can override some HT caps such as the A-MSDU max length */
        if (params->vht_capa)
                ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
                                                    params->vht_capa, sta);
@@ -1172,6 +1205,9 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                                              params->opmode_notif, band);
        }
 
+       if (params->support_p2p_ps >= 0)
+               sta->sta.support_p2p_ps = params->support_p2p_ps;
+
        if (ieee80211_vif_is_mesh(&sdata->vif))
                sta_apply_mesh_params(local, sta, params);
 
@@ -1333,6 +1369,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 
                        rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
                        new_4addr = true;
+                       __ieee80211_check_fast_rx_iface(vlansdata);
                }
 
                if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
@@ -1469,7 +1506,7 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop,
 
        memset(pinfo, 0, sizeof(*pinfo));
 
-       pinfo->generation = mesh_paths_generation;
+       pinfo->generation = mpath->sdata->u.mesh.mesh_paths_generation;
 
        pinfo->filled = MPATH_INFO_FRAME_QLEN |
                        MPATH_INFO_SN |
@@ -1547,7 +1584,7 @@ static void mpp_set_pinfo(struct mesh_path *mpath, u8 *mpp,
        memset(pinfo, 0, sizeof(*pinfo));
        memcpy(mpp, mpath->mpp, ETH_ALEN);
 
-       pinfo->generation = mpp_paths_generation;
+       pinfo->generation = mpath->sdata->u.mesh.mpp_paths_generation;
 }
 
 static int ieee80211_get_mpp(struct wiphy *wiphy, struct net_device *dev,
@@ -1855,6 +1892,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
                        sdata->flags |= IEEE80211_SDATA_DONT_BRIDGE_PACKETS;
                else
                        sdata->flags &= ~IEEE80211_SDATA_DONT_BRIDGE_PACKETS;
+               ieee80211_check_fast_rx_iface(sdata);
        }
 
        if (params->ht_opmode >= 0) {