Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi...
[firefly-linux-kernel-4.4.55.git] / net / mac80211 / cfg.c
index f4f7e7691077bf6fb47ab1dcb4d9de04bcec8844..808f5fcd1ced92127f8786700a759465e0708060 100644 (file)
@@ -928,11 +928,13 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
        /* TODO: make hostapd tell us what it wants */
        sdata->smps_mode = IEEE80211_SMPS_OFF;
        sdata->needed_rx_chains = sdata->local->rx_chains;
+       sdata->radar_required = params->radar_required;
 
        err = ieee80211_vif_use_channel(sdata, &params->chandef,
                                        IEEE80211_CHANCTX_SHARED);
        if (err)
                return err;
+       ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
 
        /*
         * Apply control port protocol, this allows us to
@@ -1047,6 +1049,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
        local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf);
        skb_queue_purge(&sdata->u.ap.ps.bc_buf);
 
+       ieee80211_vif_copy_chanctx_to_vlans(sdata, true);
        ieee80211_vif_release_channel(sdata);
 
        return 0;
@@ -1249,19 +1252,16 @@ static int sta_apply_parameters(struct ieee80211_local *local,
 
        if (params->ht_capa)
                ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
-                                                 params->ht_capa,
-                                                 &sta->sta.ht_cap);
+                                                 params->ht_capa, sta);
 
        if (params->vht_capa)
                ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
-                                                   params->vht_capa,
-                                                   &sta->sta.vht_cap);
+                                                   params->vht_capa, sta);
 
        if (ieee80211_vif_is_mesh(&sdata->vif)) {
 #ifdef CONFIG_MAC80211_MESH
+               u32 changed = 0;
                if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) {
-                       u32 changed = 0;
-
                        switch (params->plink_state) {
                        case NL80211_PLINK_ESTAB:
                                if (sta->plink_state != NL80211_PLINK_ESTAB)
@@ -1270,8 +1270,8 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                                sta->plink_state = params->plink_state;
 
                                ieee80211_mps_sta_status_update(sta);
-                               ieee80211_mps_set_sta_local_pm(sta,
-                                       sdata->u.mesh.mshcfg.power_mode);
+                               changed |= ieee80211_mps_set_sta_local_pm(sta,
+                                             sdata->u.mesh.mshcfg.power_mode);
                                break;
                        case NL80211_PLINK_LISTEN:
                        case NL80211_PLINK_BLOCKED:
@@ -1285,26 +1285,29 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                                sta->plink_state = params->plink_state;
 
                                ieee80211_mps_sta_status_update(sta);
-                               ieee80211_mps_local_status_update(sdata);
+                               changed |=
+                                     ieee80211_mps_local_status_update(sdata);
                                break;
                        default:
                                /*  nothing  */
                                break;
                        }
-                       ieee80211_bss_info_change_notify(sdata, changed);
                } else {
                        switch (params->plink_action) {
                        case PLINK_ACTION_OPEN:
-                               mesh_plink_open(sta);
+                               changed |= mesh_plink_open(sta);
                                break;
                        case PLINK_ACTION_BLOCK:
-                               mesh_plink_block(sta);
+                               changed |= mesh_plink_block(sta);
                                break;
                        }
                }
 
                if (params->local_pm)
-                       ieee80211_mps_set_sta_local_pm(sta, params->local_pm);
+                       changed |=
+                             ieee80211_mps_set_sta_local_pm(sta,
+                                                            params->local_pm);
+               ieee80211_bss_info_change_notify(sdata, changed);
 #endif
        }
 
@@ -1409,9 +1412,11 @@ static int ieee80211_change_station(struct wiphy *wiphy,
                return -ENOENT;
        }
 
-       /* in station mode, supported rates are only valid with TDLS */
+       /* in station mode, some updates are only valid with TDLS */
        if (sdata->vif.type == NL80211_IFTYPE_STATION &&
-           params->supported_rates &&
+           (params->supported_rates || params->ht_capa || params->vht_capa ||
+            params->sta_modify_mask ||
+            (params->sta_flags_mask & BIT(NL80211_STA_FLAG_WME))) &&
            !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
                mutex_unlock(&local->sta_mtx);
                return -EINVAL;
@@ -1495,13 +1500,13 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
                return -ENOENT;
        }
 
-       err = mesh_path_add(dst, sdata);
+       err = mesh_path_add(sdata, dst);
        if (err) {
                rcu_read_unlock();
                return err;
        }
 
-       mpath = mesh_path_lookup(dst, sdata);
+       mpath = mesh_path_lookup(sdata, dst);
        if (!mpath) {
                rcu_read_unlock();
                return -ENXIO;
@@ -1513,12 +1518,12 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
-                                u8 *dst)
+                              u8 *dst)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        if (dst)
-               return mesh_path_del(dst, sdata);
+               return mesh_path_del(sdata, dst);
 
        mesh_path_flush_by_iface(sdata);
        return 0;
@@ -1542,7 +1547,7 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
                return -ENOENT;
        }
 
-       mpath = mesh_path_lookup(dst, sdata);
+       mpath = mesh_path_lookup(sdata, dst);
        if (!mpath) {
                rcu_read_unlock();
                return -ENOENT;
@@ -1606,7 +1611,7 @@ static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        rcu_read_lock();
-       mpath = mesh_path_lookup(dst, sdata);
+       mpath = mesh_path_lookup(sdata, dst);
        if (!mpath) {
                rcu_read_unlock();
                return -ENOENT;
@@ -1627,7 +1632,7 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        rcu_read_lock();
-       mpath = mesh_path_lookup_by_idx(idx, sdata);
+       mpath = mesh_path_lookup_by_idx(sdata, idx);
        if (!mpath) {
                rcu_read_unlock();
                return -ENOENT;
@@ -1797,11 +1802,10 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
                conf->power_mode = nconf->power_mode;
                ieee80211_mps_local_status_update(sdata);
        }
-       if (_chg_mesh_attr(NL80211_MESHCONF_AWAKE_WINDOW, mask)) {
+       if (_chg_mesh_attr(NL80211_MESHCONF_AWAKE_WINDOW, mask))
                conf->dot11MeshAwakeWindowDuration =
                        nconf->dot11MeshAwakeWindowDuration;
-               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
-       }
+       ieee80211_mbss_info_change_notify(sdata, BSS_CHANGED_BEACON);
        return 0;
 }
 
@@ -1827,9 +1831,7 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
        if (err)
                return err;
 
-       ieee80211_start_mesh(sdata);
-
-       return 0;
+       return ieee80211_start_mesh(sdata);
 }
 
 static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
@@ -2083,7 +2085,8 @@ static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       memcpy(sdata->vif.bss_conf.mcast_rate, rate, sizeof(rate));
+       memcpy(sdata->vif.bss_conf.mcast_rate, rate,
+              sizeof(int) * IEEE80211_NUM_BANDS);
 
        return 0;
 }
@@ -2393,7 +2396,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
        INIT_LIST_HEAD(&roc->dependents);
 
        /* if there's one pending or we're scanning, queue this one */
-       if (!list_empty(&local->roc_list) || local->scanning)
+       if (!list_empty(&local->roc_list) ||
+           local->scanning || local->radar_detect_enabled)
                goto out_check_combine;
 
        /* if not HW assist, just queue & schedule work */
@@ -2643,6 +2647,37 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
        return ieee80211_cancel_roc(local, cookie, false);
 }
 
+static int ieee80211_start_radar_detection(struct wiphy *wiphy,
+                                          struct net_device *dev,
+                                          struct cfg80211_chan_def *chandef)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
+       unsigned long timeout;
+       int err;
+
+       if (!list_empty(&local->roc_list) || local->scanning)
+               return -EBUSY;
+
+       /* whatever, but channel contexts should not complain about that one */
+       sdata->smps_mode = IEEE80211_SMPS_OFF;
+       sdata->needed_rx_chains = local->rx_chains;
+       sdata->radar_required = true;
+
+       mutex_lock(&local->iflist_mtx);
+       err = ieee80211_vif_use_channel(sdata, chandef,
+                                       IEEE80211_CHANCTX_SHARED);
+       mutex_unlock(&local->iflist_mtx);
+       if (err)
+               return err;
+
+       timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS);
+       ieee80211_queue_delayed_work(&sdata->local->hw,
+                                    &sdata->dfs_cac_timer_work, timeout);
+
+       return 0;
+}
+
 static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                             struct ieee80211_channel *chan, bool offchan,
                             unsigned int wait, const u8 *buf, size_t len,
@@ -2747,7 +2782,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                goto out_unlock;
        }
 
-       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
+       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN |
+                                       IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
        if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
                IEEE80211_SKB_CB(skb)->hw_queue =
                        local->hw.offchannel_tx_hw_queue;
@@ -3249,13 +3285,19 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
                                     struct cfg80211_chan_def *chandef)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_chanctx_conf *chanctx_conf;
        int ret = -ENODATA;
 
        rcu_read_lock();
-       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
-       if (chanctx_conf) {
-               *chandef = chanctx_conf->def;
+       if (local->use_chanctx) {
+               chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+               if (chanctx_conf) {
+                       *chandef = chanctx_conf->def;
+                       ret = 0;
+               }
+       } else if (local->open_count == local->monitors) {
+               *chandef = local->monitor_chandef;
                ret = 0;
        }
        rcu_read_unlock();
@@ -3347,4 +3389,5 @@ struct cfg80211_ops mac80211_config_ops = {
        .get_et_stats = ieee80211_get_et_stats,
        .get_et_strings = ieee80211_get_et_strings,
        .get_channel = ieee80211_cfg_get_channel,
+       .start_radar_detection = ieee80211_start_radar_detection,
 };