ipv4: flush route cache after change accept_local
[linux-2.6.git] / net / mac80211 / main.c
index 562d298..3d90dad 100644 (file)
 #include "cfg.h"
 #include "debugfs.h"
 
-
-static bool ieee80211_disable_40mhz_24ghz;
-module_param(ieee80211_disable_40mhz_24ghz, bool, 0644);
-MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz,
-                "Disable 40MHz support in the 2.4GHz band");
-
 static struct lock_class_key ieee80211_rx_skb_queue_class;
 
 void ieee80211_configure_filter(struct ieee80211_local *local)
@@ -364,7 +358,8 @@ static void ieee80211_restart_work(struct work_struct *work)
        flush_workqueue(local->workqueue);
 
        mutex_lock(&local->mtx);
-       WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
+       WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
+            local->sched_scanning,
                "%s called with hardware scan in progress\n", __func__);
        mutex_unlock(&local->mtx);
 
@@ -545,7 +540,9 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
        },
        [NL80211_IFTYPE_MESH_POINT] = {
                .tx = 0xffff,
-               .rx = BIT(IEEE80211_STYPE_ACTION >> 4),
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+                       BIT(IEEE80211_STYPE_AUTH >> 4) |
+                       BIT(IEEE80211_STYPE_DEAUTH >> 4),
        },
 };
 
@@ -584,8 +581,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        wiphy->flags |= WIPHY_FLAG_NETNS_OK |
                        WIPHY_FLAG_4ADDR_AP |
-                       WIPHY_FLAG_4ADDR_STATION |
-                       WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS;
+                       WIPHY_FLAG_4ADDR_STATION;
 
        if (!ops->set_key)
                wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
@@ -656,6 +652,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        setup_timer(&local->dynamic_ps_timer,
                    ieee80211_dynamic_ps_timer, (unsigned long) local);
 
+       INIT_WORK(&local->sched_scan_stopped_work,
+                 ieee80211_sched_scan_stopped_work);
+
        sta_info_init(local);
 
        for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
@@ -686,7 +685,7 @@ EXPORT_SYMBOL(ieee80211_alloc_hw);
 int ieee80211_register_hw(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
-       int result;
+       int result, i;
        enum ieee80211_band band;
        int channels, max_bitrates;
        bool supp_ht;
@@ -701,6 +700,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                WLAN_CIPHER_SUITE_AES_CMAC
        };
 
+       if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns)
+#ifdef CONFIG_PM
+           && (!local->ops->suspend || !local->ops->resume)
+#endif
+           )
+               return -EINVAL;
+
        if (hw->max_report_rates == 0)
                hw->max_report_rates = hw->max_rates;
 
@@ -726,18 +732,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                }
                channels += sband->n_channels;
 
-               /*
-                * Since ieee80211_disable_40mhz_24ghz is global, we can
-                * modify the sband's ht data even if the driver uses a
-                * global structure for that.
-                */
-               if (ieee80211_disable_40mhz_24ghz &&
-                   band == IEEE80211_BAND_2GHZ &&
-                   sband->ht_cap.ht_supported) {
-                       sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-                       sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40;
-               }
-
                if (max_bitrates < sband->n_bitrates)
                        max_bitrates = sband->n_bitrates;
                supp_ht = supp_ht || sband->ht_cap.ht_supported;
@@ -748,18 +742,51 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (!local->int_scan_req)
                return -ENOMEM;
 
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               if (!local->hw.wiphy->bands[band])
+                       continue;
+               local->int_scan_req->rates[band] = (u32) -1;
+       }
+
        /* if low-level driver supports AP, we also support VLAN */
-       if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP))
-               local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
+       if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
+               hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
+               hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN);
+       }
 
        /* mac80211 always supports monitor */
-       local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+       hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+       hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
+
+       /*
+        * mac80211 doesn't support more than 1 channel, and also not more
+        * than one IBSS interface
+        */
+       for (i = 0; i < hw->wiphy->n_iface_combinations; i++) {
+               const struct ieee80211_iface_combination *c;
+               int j;
+
+               c = &hw->wiphy->iface_combinations[i];
+
+               if (c->num_different_channels > 1)
+                       return -EINVAL;
+
+               for (j = 0; j < c->n_limits; j++)
+                       if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) &&
+                           c->limits[j].max > 1)
+                               return -EINVAL;
+       }
 
 #ifndef CONFIG_MAC80211_MESH
        /* mesh depends on Kconfig, but drivers should set it if they want */
        local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT);
 #endif
 
+       /* if the underlying driver supports mesh, mac80211 will (at least)
+        * provide routing of mesh authentication frames to userspace */
+       if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_MESH_POINT))
+               local->hw.wiphy->flags |= WIPHY_FLAG_MESH_AUTH;
+
        /* mac80211 supports control port protocol changing */
        local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL;
 
@@ -838,6 +865,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (!local->ops->remain_on_channel)
                local->hw.wiphy->max_remain_on_channel_duration = 5000;
 
+       if (local->ops->sched_scan_start)
+               local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+
        result = wiphy_register(local->hw.wiphy);
        if (result < 0)
                goto fail_wiphy_register;
@@ -861,8 +891,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
         * and we need some headroom for passing the frame to monitor
         * interfaces, but never both at the same time.
         */
+#ifndef __CHECKER__
        BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM !=
                        sizeof(struct ieee80211_tx_status_rtap_hdr));
+#endif
        local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom,
                                   sizeof(struct ieee80211_tx_status_rtap_hdr));
 
@@ -879,10 +911,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        local->dynamic_ps_forced_timeout = -1;
 
-       result = sta_info_start(local);
-       if (result < 0)
-               goto fail_sta_info;
-
        result = ieee80211_wep_init(local);
        if (result < 0)
                wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
@@ -945,7 +973,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        rtnl_unlock();
        ieee80211_wep_free(local);
        sta_info_stop(local);
- fail_sta_info:
        destroy_workqueue(local->workqueue);
  fail_workqueue:
        wiphy_unregister(local->hw.wiphy);
@@ -991,7 +1018,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
        cancel_work_sync(&local->reconfig_filter);
 
        ieee80211_clear_tx_pending(local);
-       sta_info_stop(local);
        rate_control_deinitialize(local);
 
        if (skb_queue_len(&local->skb_queue) ||
@@ -1003,6 +1029,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 
        destroy_workqueue(local->workqueue);
        wiphy_unregister(local->hw.wiphy);
+       sta_info_stop(local);
        ieee80211_wep_free(local);
        ieee80211_led_exit(local);
        kfree(local->int_scan_req);
@@ -1069,6 +1096,8 @@ static void __exit ieee80211_exit(void)
                ieee80211s_stop();
 
        ieee80211_iface_exit();
+
+       rcu_barrier();
 }