Merge branch 'x86-platform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / net / mac80211 / iface.c
index 8664111d05663d47678f2088f4169a6ab80fdb96..bfb57dcc15381a53cdcc3768e943a6fb144b8c3a 100644 (file)
  */
 
 
+static u32 ieee80211_idle_off(struct ieee80211_local *local,
+                             const char *reason)
+{
+       if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE))
+               return 0;
+
+       local->hw.conf.flags &= ~IEEE80211_CONF_IDLE;
+       return IEEE80211_CONF_CHANGE_IDLE;
+}
+
+static u32 ieee80211_idle_on(struct ieee80211_local *local)
+{
+       if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
+               return 0;
+
+       drv_flush(local, false);
+
+       local->hw.conf.flags |= IEEE80211_CONF_IDLE;
+       return IEEE80211_CONF_CHANGE_IDLE;
+}
+
+static u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
+{
+       struct ieee80211_sub_if_data *sdata;
+       int count = 0;
+       bool working = false, scanning = false;
+       unsigned int led_trig_start = 0, led_trig_stop = 0;
+       struct ieee80211_roc_work *roc;
+
+#ifdef CONFIG_PROVE_LOCKING
+       WARN_ON(debug_locks && !lockdep_rtnl_is_held() &&
+               !lockdep_is_held(&local->iflist_mtx));
+#endif
+       lockdep_assert_held(&local->mtx);
+
+       list_for_each_entry(sdata, &local->interfaces, list) {
+               if (!ieee80211_sdata_running(sdata)) {
+                       sdata->vif.bss_conf.idle = true;
+                       continue;
+               }
+
+               sdata->old_idle = sdata->vif.bss_conf.idle;
+
+               /* do not count disabled managed interfaces */
+               if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+                   !sdata->u.mgd.associated &&
+                   !sdata->u.mgd.auth_data &&
+                   !sdata->u.mgd.assoc_data) {
+                       sdata->vif.bss_conf.idle = true;
+                       continue;
+               }
+               /* do not count unused IBSS interfaces */
+               if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
+                   !sdata->u.ibss.ssid_len) {
+                       sdata->vif.bss_conf.idle = true;
+                       continue;
+               }
+               /* count everything else */
+               sdata->vif.bss_conf.idle = false;
+               count++;
+       }
+
+       if (!local->ops->remain_on_channel) {
+               list_for_each_entry(roc, &local->roc_list, list) {
+                       working = true;
+                       roc->sdata->vif.bss_conf.idle = false;
+               }
+       }
+
+       sdata = rcu_dereference_protected(local->scan_sdata,
+                                         lockdep_is_held(&local->mtx));
+       if (sdata && !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) {
+               scanning = true;
+               sdata->vif.bss_conf.idle = false;
+       }
+
+       list_for_each_entry(sdata, &local->interfaces, list) {
+               if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+                   sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+                       continue;
+               if (sdata->old_idle == sdata->vif.bss_conf.idle)
+                       continue;
+               if (!ieee80211_sdata_running(sdata))
+                       continue;
+               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
+       }
+
+       if (working || scanning)
+               led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK;
+       else
+               led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK;
+
+       if (count)
+               led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED;
+       else
+               led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED;
+
+       ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop);
+
+       if (working)
+               return ieee80211_idle_off(local, "working");
+       if (scanning)
+               return ieee80211_idle_off(local, "scanning");
+       if (!count)
+               return ieee80211_idle_on(local);
+       else
+               return ieee80211_idle_off(local, "in use");
+
+       return 0;
+}
+
+void ieee80211_recalc_idle(struct ieee80211_local *local)
+{
+       u32 chg;
+
+       mutex_lock(&local->iflist_mtx);
+       chg = __ieee80211_recalc_idle(local);
+       mutex_unlock(&local->iflist_mtx);
+       if (chg)
+               ieee80211_hw_config(local, chg);
+}
+
 static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
 {
        int meshhdrlen;
@@ -57,9 +179,6 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
                return -EINVAL;
        }
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
        dev->mtu = new_mtu;
        return 0;
 }
@@ -100,15 +219,12 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_sub_if_data *nsdata;
-       struct net_device *dev = sdata->dev;
 
        ASSERT_RTNL();
 
        /* we hold the RTNL here so can safely walk the list */
        list_for_each_entry(nsdata, &local->interfaces, list) {
-               struct net_device *ndev = nsdata->dev;
-
-               if (ndev != dev && ieee80211_sdata_running(nsdata)) {
+               if (nsdata != sdata && ieee80211_sdata_running(nsdata)) {
                        /*
                         * Allow only a single IBSS interface to be up at any
                         * time. This is restricted because beacon distribution
@@ -127,7 +243,8 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
                         * The remaining checks are only performed for interfaces
                         * with the same MAC address.
                         */
-                       if (!ether_addr_equal(dev->dev_addr, ndev->dev_addr))
+                       if (!ether_addr_equal(sdata->vif.addr,
+                                             nsdata->vif.addr))
                                continue;
 
                        /*
@@ -217,17 +334,21 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
 static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata;
-       int ret;
+       int ret = 0;
 
        if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
                return 0;
 
+       mutex_lock(&local->iflist_mtx);
+
        if (local->monitor_sdata)
-               return 0;
+               goto out_unlock;
 
        sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
-       if (!sdata)
-               return -ENOMEM;
+       if (!sdata) {
+               ret = -ENOMEM;
+               goto out_unlock;
+       }
 
        /* set up data */
        sdata->local = local;
@@ -241,18 +362,19 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
        if (WARN_ON(ret)) {
                /* ok .. stupid driver, it asked for this! */
                kfree(sdata);
-               return ret;
+               goto out_unlock;
        }
 
        ret = ieee80211_check_queues(sdata);
        if (ret) {
                kfree(sdata);
-               return ret;
+               goto out_unlock;
        }
 
        rcu_assign_pointer(local->monitor_sdata, sdata);
-
-       return 0;
+ out_unlock:
+       mutex_unlock(&local->iflist_mtx);
+       return ret;
 }
 
 static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
@@ -262,10 +384,12 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
        if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
                return;
 
-       sdata = rtnl_dereference(local->monitor_sdata);
+       mutex_lock(&local->iflist_mtx);
 
+       sdata = rcu_dereference_protected(local->monitor_sdata,
+                                         lockdep_is_held(&local->iflist_mtx));
        if (!sdata)
-               return;
+               goto out_unlock;
 
        rcu_assign_pointer(local->monitor_sdata, NULL);
        synchronize_net();
@@ -273,6 +397,8 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
        drv_remove_interface(local, sdata);
 
        kfree(sdata);
+ out_unlock:
+       mutex_unlock(&local->iflist_mtx);
 }
 
 /*
@@ -520,7 +646,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
 
        clear_bit(SDATA_STATE_RUNNING, &sdata->state);
 
-       if (local->scan_sdata == sdata)
+       if (rcu_access_pointer(local->scan_sdata) == sdata)
                ieee80211_scan_cancel(local);
 
        /*
@@ -528,10 +654,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
         */
        netif_tx_stop_all_queues(sdata->dev);
 
-       /*
-        * Purge work for this interface.
-        */
-       ieee80211_work_purge(sdata);
+       ieee80211_roc_purge(sdata);
 
        /*
         * Remove all stations associated with this interface.
@@ -637,18 +760,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                ieee80211_configure_filter(local);
                break;
        default:
-               mutex_lock(&local->mtx);
-               if (local->hw_roc_dev == sdata->dev &&
-                   local->hw_roc_channel) {
-                       /* ignore return value since this is racy */
-                       drv_cancel_remain_on_channel(local);
-                       ieee80211_queue_work(&local->hw, &local->hw_roc_done);
-               }
-               mutex_unlock(&local->mtx);
-
-               flush_work(&local->hw_roc_start);
-               flush_work(&local->hw_roc_done);
-
                flush_work(&sdata->work);
                /*
                 * When we get here, the interface is marked down.
@@ -823,7 +934,7 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev,
 
        hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len));
 
-       return ieee80211_select_queue_80211(local, skb, hdr);
+       return ieee80211_select_queue_80211(sdata, skb, hdr);
 }
 
 static const struct net_device_ops ieee80211_monitorif_ops = {
@@ -1238,7 +1349,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
 
                if (__ffs64(mask) + hweight64(mask) != fls64(mask)) {
                        /* not a contiguous mask ... not handled now! */
-                       printk(KERN_DEBUG "not contiguous\n");
+                       pr_info("not contiguous\n");
                        break;
                }
 
@@ -1284,7 +1395,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
 }
 
 int ieee80211_if_add(struct ieee80211_local *local, const char *name,
-                    struct net_device **new_dev, enum nl80211_iftype type,
+                    struct wireless_dev **new_wdev, enum nl80211_iftype type,
                     struct vif_params *params)
 {
        struct net_device *ndev;
@@ -1364,6 +1475,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
                        sdata->u.mgd.use_4addr = params->use_4addr;
        }
 
+       ndev->features |= local->hw.netdev_features;
+
        ret = register_netdevice(ndev);
        if (ret)
                goto fail;
@@ -1372,8 +1485,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
        list_add_tail_rcu(&sdata->list, &local->interfaces);
        mutex_unlock(&local->iflist_mtx);
 
-       if (new_dev)
-               *new_dev = ndev;
+       if (new_wdev)
+               *new_wdev = &sdata->wdev;
 
        return 0;
 
@@ -1421,138 +1534,6 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
        list_del(&unreg_list);
 }
 
-static u32 ieee80211_idle_off(struct ieee80211_local *local,
-                             const char *reason)
-{
-       if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE))
-               return 0;
-
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       wiphy_debug(local->hw.wiphy, "device no longer idle - %s\n", reason);
-#endif
-
-       local->hw.conf.flags &= ~IEEE80211_CONF_IDLE;
-       return IEEE80211_CONF_CHANGE_IDLE;
-}
-
-static u32 ieee80211_idle_on(struct ieee80211_local *local)
-{
-       if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
-               return 0;
-
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       wiphy_debug(local->hw.wiphy, "device now idle\n");
-#endif
-
-       drv_flush(local, false);
-
-       local->hw.conf.flags |= IEEE80211_CONF_IDLE;
-       return IEEE80211_CONF_CHANGE_IDLE;
-}
-
-u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
-{
-       struct ieee80211_sub_if_data *sdata;
-       int count = 0;
-       bool working = false, scanning = false, hw_roc = false;
-       struct ieee80211_work *wk;
-       unsigned int led_trig_start = 0, led_trig_stop = 0;
-
-#ifdef CONFIG_PROVE_LOCKING
-       WARN_ON(debug_locks && !lockdep_rtnl_is_held() &&
-               !lockdep_is_held(&local->iflist_mtx));
-#endif
-       lockdep_assert_held(&local->mtx);
-
-       list_for_each_entry(sdata, &local->interfaces, list) {
-               if (!ieee80211_sdata_running(sdata)) {
-                       sdata->vif.bss_conf.idle = true;
-                       continue;
-               }
-
-               sdata->old_idle = sdata->vif.bss_conf.idle;
-
-               /* do not count disabled managed interfaces */
-               if (sdata->vif.type == NL80211_IFTYPE_STATION &&
-                   !sdata->u.mgd.associated &&
-                   !sdata->u.mgd.auth_data &&
-                   !sdata->u.mgd.assoc_data) {
-                       sdata->vif.bss_conf.idle = true;
-                       continue;
-               }
-               /* do not count unused IBSS interfaces */
-               if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
-                   !sdata->u.ibss.ssid_len) {
-                       sdata->vif.bss_conf.idle = true;
-                       continue;
-               }
-               /* count everything else */
-               sdata->vif.bss_conf.idle = false;
-               count++;
-       }
-
-       list_for_each_entry(wk, &local->work_list, list) {
-               working = true;
-               wk->sdata->vif.bss_conf.idle = false;
-       }
-
-       if (local->scan_sdata &&
-           !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) {
-               scanning = true;
-               local->scan_sdata->vif.bss_conf.idle = false;
-       }
-
-       if (local->hw_roc_channel)
-               hw_roc = true;
-
-       list_for_each_entry(sdata, &local->interfaces, list) {
-               if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
-                   sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-                       continue;
-               if (sdata->old_idle == sdata->vif.bss_conf.idle)
-                       continue;
-               if (!ieee80211_sdata_running(sdata))
-                       continue;
-               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
-       }
-
-       if (working || scanning || hw_roc)
-               led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK;
-       else
-               led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK;
-
-       if (count)
-               led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED;
-       else
-               led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED;
-
-       ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop);
-
-       if (hw_roc)
-               return ieee80211_idle_off(local, "hw remain-on-channel");
-       if (working)
-               return ieee80211_idle_off(local, "working");
-       if (scanning)
-               return ieee80211_idle_off(local, "scanning");
-       if (!count)
-               return ieee80211_idle_on(local);
-       else
-               return ieee80211_idle_off(local, "in use");
-
-       return 0;
-}
-
-void ieee80211_recalc_idle(struct ieee80211_local *local)
-{
-       u32 chg;
-
-       mutex_lock(&local->iflist_mtx);
-       chg = __ieee80211_recalc_idle(local);
-       mutex_unlock(&local->iflist_mtx);
-       if (chg)
-               ieee80211_hw_config(local, chg);
-}
-
 static int netdev_notify(struct notifier_block *nb,
                         unsigned long state,
                         void *ndev)