]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/mac80211/main.c
Merge tag 'late-mvebu-rebased' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
[karo-tx-linux.git] / net / mac80211 / main.c
index 39cfe8f10ad2dc50d929709715b2763c8e2cccd7..1a8591b77a13d1ff1e41a67f6c8ed8c57daa83e9 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/inetdevice.h>
 #include <net/net_namespace.h>
 #include <net/cfg80211.h>
+#include <net/addrconf.h>
 
 #include "ieee80211_i.h"
 #include "driver-ops.h"
@@ -33,8 +34,6 @@
 #include "cfg.h"
 #include "debugfs.h"
 
-static struct lock_class_key ieee80211_rx_skb_queue_class;
-
 void ieee80211_configure_filter(struct ieee80211_local *local)
 {
        u64 mc;
@@ -349,27 +348,19 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
 
        /* Copy the addresses to the bss_conf list */
        ifa = idev->ifa_list;
-       while (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN && ifa) {
-               bss_conf->arp_addr_list[c] = ifa->ifa_address;
+       while (ifa) {
+               if (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN)
+                       bss_conf->arp_addr_list[c] = ifa->ifa_address;
                ifa = ifa->ifa_next;
                c++;
        }
 
-       /* If not all addresses fit the list, disable filtering */
-       if (ifa) {
-               sdata->arp_filter_state = false;
-               c = 0;
-       } else {
-               sdata->arp_filter_state = true;
-       }
        bss_conf->arp_addr_cnt = c;
 
        /* Configure driver only if associated (which also implies it is up) */
-       if (ifmgd->associated) {
-               bss_conf->arp_filter_enabled = sdata->arp_filter_state;
+       if (ifmgd->associated)
                ieee80211_bss_info_change_notify(sdata,
                                                 BSS_CHANGED_ARP_FILTER);
-       }
 
        mutex_unlock(&ifmgd->mtx);
 
@@ -377,6 +368,37 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
 }
 #endif
 
+#if IS_ENABLED(CONFIG_IPV6)
+static int ieee80211_ifa6_changed(struct notifier_block *nb,
+                                 unsigned long data, void *arg)
+{
+       struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg;
+       struct inet6_dev *idev = ifa->idev;
+       struct net_device *ndev = ifa->idev->dev;
+       struct ieee80211_local *local =
+               container_of(nb, struct ieee80211_local, ifa6_notifier);
+       struct wireless_dev *wdev = ndev->ieee80211_ptr;
+       struct ieee80211_sub_if_data *sdata;
+
+       /* Make sure it's our interface that got changed */
+       if (!wdev || wdev->wiphy != local->hw.wiphy)
+               return NOTIFY_DONE;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
+
+       /*
+        * For now only support station mode. This is mostly because
+        * doing AP would have to handle AP_VLAN in some way ...
+        */
+       if (sdata->vif.type != NL80211_IFTYPE_STATION)
+               return NOTIFY_DONE;
+
+       drv_ipv6_addr_change(local, sdata, idev);
+
+       return NOTIFY_DONE;
+}
+#endif
+
 static int ieee80211_napi_poll(struct napi_struct *napi, int budget)
 {
        struct ieee80211_local *local =
@@ -479,6 +501,11 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = {
        },
 };
 
+static const u8 extended_capabilities[] = {
+       0, 0, 0, 0, 0, 0, 0,
+       WLAN_EXT_CAPA8_OPMODE_NOTIF,
+};
+
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                                        const struct ieee80211_ops *ops)
 {
@@ -535,14 +562,17 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                        WIPHY_FLAG_REPORTS_OBSS |
                        WIPHY_FLAG_OFFCHAN_TX;
 
+       wiphy->extended_capabilities = extended_capabilities;
+       wiphy->extended_capabilities_mask = extended_capabilities;
+       wiphy->extended_capabilities_len = ARRAY_SIZE(extended_capabilities);
+
        if (ops->remain_on_channel)
                wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 
        wiphy->features |= NL80211_FEATURE_SK_TX_STATUS |
                           NL80211_FEATURE_SAE |
                           NL80211_FEATURE_HT_IBSS |
-                          NL80211_FEATURE_VIF_TXPOWER |
-                          NL80211_FEATURE_FULL_AP_CLIENT_STATE;
+                          NL80211_FEATURE_VIF_TXPOWER;
 
        if (!ops->hw_scan)
                wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
@@ -589,25 +619,19 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        mutex_init(&local->key_mtx);
        spin_lock_init(&local->filter_lock);
+       spin_lock_init(&local->rx_path_lock);
        spin_lock_init(&local->queue_stop_reason_lock);
 
        INIT_LIST_HEAD(&local->chanctx_list);
        mutex_init(&local->chanctx_mtx);
 
-       /*
-        * The rx_skb_queue is only accessed from tasklets,
-        * but other SKB queues are used from within IRQ
-        * context. Therefore, this one needs a different
-        * locking class so our direct, non-irq-safe use of
-        * the queue's lock doesn't throw lockdep warnings.
-        */
-       skb_queue_head_init_class(&local->rx_skb_queue,
-                                 &ieee80211_rx_skb_queue_class);
-
        INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
 
        INIT_WORK(&local->restart_work, ieee80211_restart_work);
 
+       INIT_WORK(&local->radar_detected_work,
+                 ieee80211_dfs_radar_detected_work);
+
        INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
        local->smps_mode = IEEE80211_SMPS_OFF;
 
@@ -623,8 +647,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        spin_lock_init(&local->ack_status_lock);
        idr_init(&local->ack_status_frames);
-       /* preallocate at least one entry */
-       idr_pre_get(&local->ack_status_frames, GFP_KERNEL);
 
        sta_info_init(local);
 
@@ -683,9 +705,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                return -EINVAL;
 #endif
 
-       if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan)
-               return -EINVAL;
-
        if (!local->use_chanctx) {
                for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
                        const struct ieee80211_iface_combination *comb;
@@ -703,6 +722,16 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                 */
                if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS))
                        return -EINVAL;
+
+               /* DFS currently not supported with channel context drivers */
+               for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
+                       const struct ieee80211_iface_combination *comb;
+
+                       comb = &local->hw.wiphy->iface_combinations[i];
+
+                       if (comb->radar_detect_widths)
+                               return -EINVAL;
+               }
        }
 
        /* Only HW csum features are currently compatible with mac80211 */
@@ -985,12 +1014,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                goto fail_ifa;
 #endif
 
+#if IS_ENABLED(CONFIG_IPV6)
+       local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed;
+       result = register_inet6addr_notifier(&local->ifa6_notifier);
+       if (result)
+               goto fail_ifa6;
+#endif
+
        netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll,
                        local->hw.napi_weight);
 
        return 0;
 
+#if IS_ENABLED(CONFIG_IPV6)
+ fail_ifa6:
 #ifdef CONFIG_INET
+       unregister_inetaddr_notifier(&local->ifa_notifier);
+#endif
+#endif
+#if defined(CONFIG_INET) || defined(CONFIG_IPV6)
  fail_ifa:
        pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
                               &local->network_latency_notifier);
@@ -1026,6 +1068,9 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 #ifdef CONFIG_INET
        unregister_inetaddr_notifier(&local->ifa_notifier);
 #endif
+#if IS_ENABLED(CONFIG_IPV6)
+       unregister_inet6addr_notifier(&local->ifa6_notifier);
+#endif
 
        rtnl_lock();
 
@@ -1049,7 +1094,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
                wiphy_warn(local->hw.wiphy, "skb_queue not empty\n");
        skb_queue_purge(&local->skb_queue);
        skb_queue_purge(&local->skb_queue_unreliable);
-       skb_queue_purge(&local->rx_skb_queue);
 
        destroy_workqueue(local->workqueue);
        wiphy_unregister(local->hw.wiphy);
@@ -1127,8 +1171,7 @@ static void __exit ieee80211_exit(void)
        rc80211_minstrel_ht_exit();
        rc80211_minstrel_exit();
 
-       if (mesh_allocated)
-               ieee80211s_stop();
+       ieee80211s_stop();
 
        ieee80211_iface_exit();