Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney...
[cascardo/linux.git] / net / mac80211 / cfg.c
index 343da1e..e75d5c5 100644 (file)
@@ -20,6 +20,7 @@
 #include "cfg.h"
 #include "rate.h"
 #include "mesh.h"
+#include "wme.h"
 
 static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy,
                                                const char *name,
@@ -190,7 +191,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                 * receive the key. When wpa_supplicant has roamed
                 * using FT, it attempts to set the key before
                 * association has completed, this rejects that attempt
-                * so it will set the key again after assocation.
+                * so it will set the key again after association.
                 *
                 * TODO: accept the key if we have a station entry and
                 *       add it to the device after the station.
@@ -229,6 +230,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        case NUM_NL80211_IFTYPES:
        case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_P2P_GO:
+       case NL80211_IFTYPE_OCB:
                /* shouldn't happen */
                WARN_ON_ONCE(1);
                break;
@@ -1040,6 +1042,13 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                        clear_sta_flag(sta, WLAN_STA_TDLS_PEER);
        }
 
+       /* mark TDLS channel switch support, if the AP allows it */
+       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
+           !sdata->u.mgd.tdls_chan_switch_prohibited &&
+           params->ext_capab_len >= 4 &&
+           params->ext_capab[3] & WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH)
+               set_sta_flag(sta, WLAN_STA_TDLS_CHAN_SWITCH);
+
        if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) {
                sta->sta.uapsd_queues = params->uapsd_queues;
                sta->sta.max_sp = params->max_sp;
@@ -1225,14 +1234,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
-                                const u8 *mac)
+                                struct station_del_parameters *params)
 {
        struct ieee80211_sub_if_data *sdata;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (mac)
-               return sta_info_destroy_addr_bss(sdata, mac);
+       if (params->mac)
+               return sta_info_destroy_addr_bss(sdata, params->mac);
 
        sta_info_flush(sdata);
        return 0;
@@ -1516,6 +1525,57 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
+static void mpp_set_pinfo(struct mesh_path *mpath, u8 *mpp,
+                         struct mpath_info *pinfo)
+{
+       memset(pinfo, 0, sizeof(*pinfo));
+       memcpy(mpp, mpath->mpp, ETH_ALEN);
+
+       pinfo->generation = mpp_paths_generation;
+}
+
+static int ieee80211_get_mpp(struct wiphy *wiphy, struct net_device *dev,
+                            u8 *dst, u8 *mpp, struct mpath_info *pinfo)
+
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct mesh_path *mpath;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       rcu_read_lock();
+       mpath = mpp_path_lookup(sdata, dst);
+       if (!mpath) {
+               rcu_read_unlock();
+               return -ENOENT;
+       }
+       memcpy(dst, mpath->dst, ETH_ALEN);
+       mpp_set_pinfo(mpath, mpp, pinfo);
+       rcu_read_unlock();
+       return 0;
+}
+
+static int ieee80211_dump_mpp(struct wiphy *wiphy, struct net_device *dev,
+                             int idx, u8 *dst, u8 *mpp,
+                             struct mpath_info *pinfo)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct mesh_path *mpath;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       rcu_read_lock();
+       mpath = mpp_path_lookup_by_idx(sdata, idx);
+       if (!mpath) {
+               rcu_read_unlock();
+               return -ENOENT;
+       }
+       memcpy(dst, mpath->dst, ETH_ALEN);
+       mpp_set_pinfo(mpath, mpp, pinfo);
+       rcu_read_unlock();
+       return 0;
+}
+
 static int ieee80211_get_mesh_config(struct wiphy *wiphy,
                                struct net_device *dev,
                                struct mesh_config *conf)
@@ -1966,6 +2026,17 @@ static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
        return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev));
 }
 
+static int ieee80211_join_ocb(struct wiphy *wiphy, struct net_device *dev,
+                             struct ocb_setup *setup)
+{
+       return ieee80211_ocb_join(IEEE80211_DEV_TO_SUB_IF(dev), setup);
+}
+
+static int ieee80211_leave_ocb(struct wiphy *wiphy, struct net_device *dev)
+{
+       return ieee80211_ocb_leave(IEEE80211_DEV_TO_SUB_IF(dev));
+}
+
 static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev,
                                    int rate[IEEE80211_NUM_BANDS])
 {
@@ -2081,6 +2152,9 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy,
        struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
 
+       if (local->ops->get_txpower)
+               return drv_get_txpower(local, sdata, dbm);
+
        if (!local->use_chanctx)
                *dbm = local->hw.conf.power_level;
        else
@@ -2850,11 +2924,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
                if (sdata->reserved_ready)
                        return 0;
 
-               err = ieee80211_vif_use_reserved_context(sdata);
-               if (err)
-                       return err;
-
-               return 0;
+               return ieee80211_vif_use_reserved_context(sdata);
        }
 
        if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
@@ -2868,7 +2938,6 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
                return err;
 
        ieee80211_bss_info_change_notify(sdata, changed);
-       cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
 
        if (sdata->csa_block_tx) {
                ieee80211_wake_vif_queues(local, sdata,
@@ -2876,6 +2945,12 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
                sdata->csa_block_tx = false;
        }
 
+       err = drv_post_channel_switch(sdata);
+       if (err)
+               return err;
+
+       cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
+
        return 0;
 }
 
@@ -3053,9 +3128,11 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_channel_switch ch_switch;
        struct ieee80211_chanctx_conf *conf;
        struct ieee80211_chanctx *chanctx;
-       int err, changed = 0;
+       u32 changed = 0;
+       int err;
 
        sdata_assert_lock(sdata);
        lockdep_assert_held(&local->mtx);
@@ -3088,6 +3165,16 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                goto out;
        }
 
+       ch_switch.timestamp = 0;
+       ch_switch.device_timestamp = 0;
+       ch_switch.block_tx = params->block_tx;
+       ch_switch.chandef = params->chandef;
+       ch_switch.count = params->count;
+
+       err = drv_pre_channel_switch(sdata, &ch_switch);
+       if (err)
+               goto out;
+
        err = ieee80211_vif_reserve_chanctx(sdata, &params->chandef,
                                            chanctx->mode,
                                            params->radar_required);
@@ -3115,6 +3202,9 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                ieee80211_stop_vif_queues(local, sdata,
                                          IEEE80211_QUEUE_STOP_REASON_CSA);
 
+       cfg80211_ch_switch_started_notify(sdata->dev, &sdata->csa_chandef,
+                                         params->count);
+
        if (changed) {
                ieee80211_bss_info_change_notify(sdata, changed);
                drv_channel_switch_beacon(sdata, &params->chandef);
@@ -3431,6 +3521,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
 
        info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS |
                       IEEE80211_TX_INTFL_NL80211_FRAME_TX;
+       info->band = band;
 
        skb_set_queue_mapping(skb, IEEE80211_AC_VO);
        skb->priority = 7;
@@ -3438,7 +3529,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
                nullfunc->qos_ctrl = cpu_to_le16(7);
 
        local_bh_disable();
-       ieee80211_xmit(sdata, skb, band);
+       ieee80211_xmit(sdata, skb);
        local_bh_enable();
        rcu_read_unlock();
 
@@ -3521,6 +3612,76 @@ static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy,
        return ret;
 }
 
+static int ieee80211_add_tx_ts(struct wiphy *wiphy, struct net_device *dev,
+                              u8 tsid, const u8 *peer, u8 up,
+                              u16 admitted_time)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       int ac = ieee802_1d_to_ac[up];
+
+       if (sdata->vif.type != NL80211_IFTYPE_STATION)
+               return -EOPNOTSUPP;
+
+       if (!(sdata->wmm_acm & BIT(up)))
+               return -EINVAL;
+
+       if (ifmgd->tx_tspec[ac].admitted_time)
+               return -EBUSY;
+
+       if (admitted_time) {
+               ifmgd->tx_tspec[ac].admitted_time = 32 * admitted_time;
+               ifmgd->tx_tspec[ac].tsid = tsid;
+               ifmgd->tx_tspec[ac].up = up;
+       }
+
+       return 0;
+}
+
+static int ieee80211_del_tx_ts(struct wiphy *wiphy, struct net_device *dev,
+                              u8 tsid, const u8 *peer)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       int ac;
+
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+               struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
+
+               /* skip unused entries */
+               if (!tx_tspec->admitted_time)
+                       continue;
+
+               if (tx_tspec->tsid != tsid)
+                       continue;
+
+               /* due to this new packets will be reassigned to non-ACM ACs */
+               tx_tspec->up = -1;
+
+               /* Make sure that all packets have been sent to avoid to
+                * restore the QoS params on packets that are still on the
+                * queues.
+                */
+               synchronize_net();
+               ieee80211_flush_queues(local, sdata);
+
+               /* restore the normal QoS parameters
+                * (unconditionally to avoid races)
+                */
+               tx_tspec->action = TX_TSPEC_ACTION_STOP_DOWNGRADE;
+               tx_tspec->downgraded = false;
+               ieee80211_sta_handle_tspec_ac_params(sdata);
+
+               /* finally clear all the data */
+               memset(tx_tspec, 0, sizeof(*tx_tspec));
+
+               return 0;
+       }
+
+       return -ENOENT;
+}
+
 const struct cfg80211_ops mac80211_config_ops = {
        .add_virtual_intf = ieee80211_add_iface,
        .del_virtual_intf = ieee80211_del_iface,
@@ -3547,11 +3708,15 @@ const struct cfg80211_ops mac80211_config_ops = {
        .change_mpath = ieee80211_change_mpath,
        .get_mpath = ieee80211_get_mpath,
        .dump_mpath = ieee80211_dump_mpath,
+       .get_mpp = ieee80211_get_mpp,
+       .dump_mpp = ieee80211_dump_mpp,
        .update_mesh_config = ieee80211_update_mesh_config,
        .get_mesh_config = ieee80211_get_mesh_config,
        .join_mesh = ieee80211_join_mesh,
        .leave_mesh = ieee80211_leave_mesh,
 #endif
+       .join_ocb = ieee80211_join_ocb,
+       .leave_ocb = ieee80211_leave_ocb,
        .change_bss = ieee80211_change_bss,
        .set_txq_params = ieee80211_set_txq_params,
        .set_monitor_channel = ieee80211_set_monitor_channel,
@@ -3587,6 +3752,8 @@ const struct cfg80211_ops mac80211_config_ops = {
        .set_rekey_data = ieee80211_set_rekey_data,
        .tdls_oper = ieee80211_tdls_oper,
        .tdls_mgmt = ieee80211_tdls_mgmt,
+       .tdls_channel_switch = ieee80211_tdls_channel_switch,
+       .tdls_cancel_channel_switch = ieee80211_tdls_cancel_channel_switch,
        .probe_client = ieee80211_probe_client,
        .set_noack_map = ieee80211_set_noack_map,
 #ifdef CONFIG_PM
@@ -3597,4 +3764,6 @@ const struct cfg80211_ops mac80211_config_ops = {
        .channel_switch = ieee80211_channel_switch,
        .set_qos_map = ieee80211_set_qos_map,
        .set_ap_chanwidth = ieee80211_set_ap_chanwidth,
+       .add_tx_ts = ieee80211_add_tx_ts,
+       .del_tx_ts = ieee80211_del_tx_ts,
 };