ipv4: flush route cache after change accept_local
[linux-2.6.git] / net / mac80211 / main.c
index d442674..3d90dad 100644 (file)
 #include <linux/skbuff.h>
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
-#include <linux/wireless.h>
 #include <linux/rtnetlink.h>
 #include <linux/bitmap.h>
 #include <linux/pm_qos_params.h>
+#include <linux/inetdevice.h>
 #include <net/net_namespace.h>
 #include <net/cfg80211.h>
 
 #include "cfg.h"
 #include "debugfs.h"
 
-
-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)
 {
@@ -54,6 +50,9 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
        if (local->monitors || local->scanning)
                new_flags |= FIF_BCN_PRBRESP_PROMISC;
 
+       if (local->fif_probe_req || local->probe_req_reg)
+               new_flags |= FIF_PROBE_REQ;
+
        if (local->fif_fcsfail)
                new_flags |= FIF_FCSFAIL;
 
@@ -72,7 +71,7 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
        spin_lock_bh(&local->filter_lock);
        changed_flags = local->filter_flags ^ new_flags;
 
-       mc = drv_prepare_multicast(local, local->mc_count, local->mc_list);
+       mc = drv_prepare_multicast(local, &local->mc_list);
        spin_unlock_bh(&local->filter_lock);
 
        /* be a bit nasty */
@@ -93,26 +92,89 @@ static void ieee80211_reconfig_filter(struct work_struct *work)
        ieee80211_configure_filter(local);
 }
 
+/*
+ * Returns true if we are logically configured to be on
+ * the operating channel AND the hardware-conf is currently
+ * configured on the operating channel.  Compares channel-type
+ * as well.
+ */
+bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local)
+{
+       struct ieee80211_channel *chan, *scan_chan;
+       enum nl80211_channel_type channel_type;
+
+       /* This logic needs to match logic in ieee80211_hw_config */
+       if (local->scan_channel) {
+               chan = local->scan_channel;
+               /* If scanning on oper channel, use whatever channel-type
+                * is currently in use.
+                */
+               if (chan == local->oper_channel)
+                       channel_type = local->_oper_channel_type;
+               else
+                       channel_type = NL80211_CHAN_NO_HT;
+       } else if (local->tmp_channel) {
+               chan = scan_chan = local->tmp_channel;
+               channel_type = local->tmp_channel_type;
+       } else {
+               chan = local->oper_channel;
+               channel_type = local->_oper_channel_type;
+       }
+
+       if (chan != local->oper_channel ||
+           channel_type != local->_oper_channel_type)
+               return false;
+
+       /* Check current hardware-config against oper_channel. */
+       if ((local->oper_channel != local->hw.conf.channel) ||
+           (local->_oper_channel_type != local->hw.conf.channel_type))
+               return false;
+
+       return true;
+}
+
 int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 {
        struct ieee80211_channel *chan, *scan_chan;
        int ret = 0;
        int power;
        enum nl80211_channel_type channel_type;
+       u32 offchannel_flag;
 
        might_sleep();
 
        scan_chan = local->scan_channel;
 
+       /* If this off-channel logic ever changes,  ieee80211_on_oper_channel
+        * may need to change as well.
+        */
+       offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
        if (scan_chan) {
                chan = scan_chan;
-               channel_type = NL80211_CHAN_NO_HT;
+               /* If scanning on oper channel, use whatever channel-type
+                * is currently in use.
+                */
+               if (chan == local->oper_channel)
+                       channel_type = local->_oper_channel_type;
+               else
+                       channel_type = NL80211_CHAN_NO_HT;
+       } else if (local->tmp_channel) {
+               chan = scan_chan = local->tmp_channel;
+               channel_type = local->tmp_channel_type;
        } else {
                chan = local->oper_channel;
-               channel_type = local->oper_channel_type;
+               channel_type = local->_oper_channel_type;
        }
 
-       if (chan != local->hw.conf.channel ||
+       if (chan != local->oper_channel ||
+           channel_type != local->_oper_channel_type)
+               local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
+       else
+               local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL;
+
+       offchannel_flag ^= local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
+
+       if (offchannel_flag || chan != local->hw.conf.channel ||
            channel_type != local->hw.conf.channel_type) {
                local->hw.conf.channel = chan;
                local->hw.conf.channel_type = channel_type;
@@ -131,7 +193,8 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
                changed |= IEEE80211_CONF_CHANGE_SMPS;
        }
 
-       if (scan_chan)
+       if ((local->scanning & SCAN_SW_SCANNING) ||
+           (local->scanning & SCAN_HW_SCANNING))
                power = chan->max_power;
        else
                power = local->power_constr_level ?
@@ -191,6 +254,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
                sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
        else if (sdata->vif.type == NL80211_IFTYPE_AP)
                sdata->vif.bss_conf.bssid = sdata->vif.addr;
+       else if (sdata->vif.type == NL80211_IFTYPE_WDS)
+               sdata->vif.bss_conf.bssid = NULL;
        else if (ieee80211_vif_is_mesh(&sdata->vif)) {
                sdata->vif.bss_conf.bssid = zero;
        } else {
@@ -201,6 +266,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_WDS:
        case NL80211_IFTYPE_MESH_POINT:
                break;
        default:
@@ -212,8 +278,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
        }
 
        if (changed & BSS_CHANGED_BEACON_ENABLED) {
-               if (local->quiescing || !netif_running(sdata->dev) ||
-                   test_bit(SCAN_SW_SCANNING, &local->scanning)) {
+               if (local->quiescing || !ieee80211_sdata_running(sdata) ||
+                   test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) {
                        sdata->vif.bss_conf.enable_beacon = false;
                } else {
                        /*
@@ -223,15 +289,18 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
                        switch (sdata->vif.type) {
                        case NL80211_IFTYPE_AP:
                                sdata->vif.bss_conf.enable_beacon =
-                                       !!rcu_dereference(sdata->u.ap.beacon);
+                                       !!sdata->u.ap.beacon;
                                break;
                        case NL80211_IFTYPE_ADHOC:
                                sdata->vif.bss_conf.enable_beacon =
-                                       !!rcu_dereference(sdata->u.ibss.presp);
+                                       !!sdata->u.ibss.presp;
                                break;
+#ifdef CONFIG_MAC80211_MESH
                        case NL80211_IFTYPE_MESH_POINT:
-                               sdata->vif.bss_conf.enable_beacon = true;
+                               sdata->vif.bss_conf.enable_beacon =
+                                       !!sdata->u.mesh.mesh_id_len;
                                break;
+#endif
                        default:
                                /* not reached */
                                WARN_ON(1);
@@ -257,7 +326,6 @@ static void ieee80211_tasklet_handler(unsigned long data)
 {
        struct ieee80211_local *local = (struct ieee80211_local *) data;
        struct sk_buff *skb;
-       struct ieee80211_ra_tid *ra_tid;
 
        while ((skb = skb_dequeue(&local->skb_queue)) ||
               (skb = skb_dequeue(&local->skb_queue_unreliable))) {
@@ -272,18 +340,6 @@ static void ieee80211_tasklet_handler(unsigned long data)
                        skb->pkt_type = 0;
                        ieee80211_tx_status(local_to_hw(local), skb);
                        break;
-               case IEEE80211_DELBA_MSG:
-                       ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
-                       ieee80211_stop_tx_ba_cb(ra_tid->vif, ra_tid->ra,
-                                               ra_tid->tid);
-                       dev_kfree_skb(skb);
-                       break;
-               case IEEE80211_ADDBA_MSG:
-                       ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
-                       ieee80211_start_tx_ba_cb(ra_tid->vif, ra_tid->ra,
-                                                ra_tid->tid);
-                       dev_kfree_skb(skb);
-                       break ;
                default:
                        WARN(1, "mac80211: Packet is of unknown type %d\n",
                             skb->pkt_type);
@@ -298,7 +354,17 @@ static void ieee80211_restart_work(struct work_struct *work)
        struct ieee80211_local *local =
                container_of(work, struct ieee80211_local, restart_work);
 
+       /* wait for scan work complete */
+       flush_workqueue(local->workqueue);
+
+       mutex_lock(&local->mtx);
+       WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
+            local->sched_scanning,
+               "%s called with hardware scan in progress\n", __func__);
+       mutex_unlock(&local->mtx);
+
        rtnl_lock();
+       ieee80211_scan_cancel(local);
        ieee80211_reconfig(local);
        rtnl_unlock();
 }
@@ -307,7 +373,12 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
 
-       /* use this reason, __ieee80211_resume will unblock it */
+       trace_api_restart_hw(local);
+
+       wiphy_info(hw->wiphy,
+                  "Hardware restart was requested\n");
+
+       /* use this reason, ieee80211_reconfig will unblock it */
        ieee80211_stop_queues_by_reason(hw,
                IEEE80211_QUEUE_STOP_REASON_SUSPEND);
 
@@ -321,10 +392,160 @@ static void ieee80211_recalc_smps_work(struct work_struct *work)
                container_of(work, struct ieee80211_local, recalc_smps);
 
        mutex_lock(&local->iflist_mtx);
-       ieee80211_recalc_smps(local, NULL);
+       ieee80211_recalc_smps(local);
        mutex_unlock(&local->iflist_mtx);
 }
 
+#ifdef CONFIG_INET
+static int ieee80211_ifa_changed(struct notifier_block *nb,
+                                unsigned long data, void *arg)
+{
+       struct in_ifaddr *ifa = arg;
+       struct ieee80211_local *local =
+               container_of(nb, struct ieee80211_local,
+                            ifa_notifier);
+       struct net_device *ndev = ifa->ifa_dev->dev;
+       struct wireless_dev *wdev = ndev->ieee80211_ptr;
+       struct in_device *idev;
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_bss_conf *bss_conf;
+       struct ieee80211_if_managed *ifmgd;
+       int c = 0;
+
+       /* Make sure it's our interface that got changed */
+       if (!wdev)
+               return NOTIFY_DONE;
+
+       if (wdev->wiphy != local->hw.wiphy)
+               return NOTIFY_DONE;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
+       bss_conf = &sdata->vif.bss_conf;
+
+       if (!ieee80211_sdata_running(sdata))
+               return NOTIFY_DONE;
+
+       /* ARP filtering is only supported in managed mode */
+       if (sdata->vif.type != NL80211_IFTYPE_STATION)
+               return NOTIFY_DONE;
+
+       idev = __in_dev_get_rtnl(sdata->dev);
+       if (!idev)
+               return NOTIFY_DONE;
+
+       ifmgd = &sdata->u.mgd;
+       mutex_lock(&ifmgd->mtx);
+
+       /* 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;
+               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 */
+       if (ifmgd->associated) {
+               bss_conf->arp_filter_enabled = sdata->arp_filter_state;
+               ieee80211_bss_info_change_notify(sdata,
+                                                BSS_CHANGED_ARP_FILTER);
+       }
+
+       mutex_unlock(&ifmgd->mtx);
+
+       return NOTIFY_DONE;
+}
+#endif
+
+static int ieee80211_napi_poll(struct napi_struct *napi, int budget)
+{
+       struct ieee80211_local *local =
+               container_of(napi, struct ieee80211_local, napi);
+
+       return local->ops->napi_poll(&local->hw, budget);
+}
+
+void ieee80211_napi_schedule(struct ieee80211_hw *hw)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+
+       napi_schedule(&local->napi);
+}
+EXPORT_SYMBOL(ieee80211_napi_schedule);
+
+void ieee80211_napi_complete(struct ieee80211_hw *hw)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+
+       napi_complete(&local->napi);
+}
+EXPORT_SYMBOL(ieee80211_napi_complete);
+
+/* There isn't a lot of sense in it, but you can transmit anything you like */
+static const struct ieee80211_txrx_stypes
+ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
+       [NL80211_IFTYPE_ADHOC] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4),
+       },
+       [NL80211_IFTYPE_STATION] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+                       BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
+       },
+       [NL80211_IFTYPE_AP] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+                       BIT(IEEE80211_STYPE_AUTH >> 4) |
+                       BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+                       BIT(IEEE80211_STYPE_ACTION >> 4),
+       },
+       [NL80211_IFTYPE_AP_VLAN] = {
+               /* copy AP */
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+                       BIT(IEEE80211_STYPE_AUTH >> 4) |
+                       BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+                       BIT(IEEE80211_STYPE_ACTION >> 4),
+       },
+       [NL80211_IFTYPE_P2P_CLIENT] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+                       BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
+       },
+       [NL80211_IFTYPE_P2P_GO] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+                       BIT(IEEE80211_STYPE_AUTH >> 4) |
+                       BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+                       BIT(IEEE80211_STYPE_ACTION >> 4),
+       },
+       [NL80211_IFTYPE_MESH_POINT] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+                       BIT(IEEE80211_STYPE_AUTH >> 4) |
+                       BIT(IEEE80211_STYPE_DEAUTH >> 4),
+       },
+};
+
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                                        const struct ieee80211_ops *ops)
 {
@@ -354,14 +575,18 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        if (!wiphy)
                return NULL;
 
+       wiphy->mgmt_stypes = ieee80211_default_mgmt_stypes;
+
+       wiphy->privid = mac80211_wiphy_privid;
+
        wiphy->flags |= WIPHY_FLAG_NETNS_OK |
                        WIPHY_FLAG_4ADDR_AP |
                        WIPHY_FLAG_4ADDR_STATION;
-       wiphy->privid = mac80211_wiphy_privid;
 
-       /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
-       wiphy->bss_priv_size = sizeof(struct ieee80211_bss) -
-                              sizeof(struct cfg80211_bss);
+       if (!ops->set_key)
+               wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+
+       wiphy->bss_priv_size = sizeof(struct ieee80211_bss);
 
        local = wiphy_priv(wiphy);
 
@@ -381,20 +606,39 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        /* set up some defaults */
        local->hw.queues = 1;
        local->hw.max_rates = 1;
+       local->hw.max_report_rates = 0;
+       local->hw.max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
        local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
        local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
        local->user_power_level = -1;
+       local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES;
+       local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;
 
        INIT_LIST_HEAD(&local->interfaces);
+
+       __hw_addr_init(&local->mc_list);
+
        mutex_init(&local->iflist_mtx);
-       mutex_init(&local->scan_mtx);
+       mutex_init(&local->mtx);
 
-       spin_lock_init(&local->key_lock);
+       mutex_init(&local->key_mtx);
        spin_lock_init(&local->filter_lock);
        spin_lock_init(&local->queue_stop_reason_lock);
 
+       /*
+        * 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);
 
+       ieee80211_work_init(local);
+
        INIT_WORK(&local->restart_work, ieee80211_restart_work);
 
        INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
@@ -408,10 +652,15 @@ 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++)
+       for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
                skb_queue_head_init(&local->pending[i]);
+               atomic_set(&local->agg_queue_stop[i], 0);
+       }
        tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
                     (unsigned long)local);
 
@@ -422,7 +671,12 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        skb_queue_head_init(&local->skb_queue);
        skb_queue_head_init(&local->skb_queue_unreliable);
 
-       spin_lock_init(&local->ampdu_lock);
+       /* init dummy netdev for use w/ NAPI */
+       init_dummy_netdev(&local->napi_dev);
+
+       ieee80211_led_names(local);
+
+       ieee80211_hw_roc_setup(local);
 
        return local_to_hw(local);
 }
@@ -431,11 +685,12 @@ 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, i, j, max_bitrates;
+       int channels, max_bitrates;
        bool supp_ht;
        static const u32 cipher_suites[] = {
+               /* keep WEP first, it may be removed below */
                WLAN_CIPHER_SUITE_WEP40,
                WLAN_CIPHER_SUITE_WEP104,
                WLAN_CIPHER_SUITE_TKIP,
@@ -445,6 +700,16 @@ 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;
+
        /*
         * generic code guarantees at least one band,
         * set this very early because much code assumes
@@ -477,25 +742,71 @@ 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;
 
        if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
                local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
        else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
                local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
 
+       WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)
+            && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK),
+            "U-APSD not supported with HW_PS_NULLFUNC_STACK\n");
+
        /*
         * Calculate scan IE length -- we need this to alloc
         * memory and to subtract from the driver limit. It
-        * includes the (extended) supported rates and HT
+        * includes the DS Params, (extended) supported rates, and HT
         * information -- SSID is the driver's responsibility.
         */
-       local->scan_ies_len = 4 + max_bitrates; /* (ext) supp rates */
+       local->scan_ies_len = 4 + max_bitrates /* (ext) supp rates */ +
+               3 /* DS Params */;
        if (supp_ht)
                local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap);
 
@@ -515,10 +826,47 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (local->hw.wiphy->max_scan_ie_len)
                local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len;
 
-       local->hw.wiphy->cipher_suites = cipher_suites;
-       local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
-       if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE))
-               local->hw.wiphy->n_cipher_suites--;
+       /* Set up cipher suites unless driver already did */
+       if (!local->hw.wiphy->cipher_suites) {
+               local->hw.wiphy->cipher_suites = cipher_suites;
+               local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+               if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE))
+                       local->hw.wiphy->n_cipher_suites--;
+       }
+       if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) {
+               if (local->hw.wiphy->cipher_suites == cipher_suites) {
+                       local->hw.wiphy->cipher_suites += 2;
+                       local->hw.wiphy->n_cipher_suites -= 2;
+               } else {
+                       u32 *suites;
+                       int r, w = 0;
+
+                       /* Filter out WEP */
+
+                       suites = kmemdup(
+                               local->hw.wiphy->cipher_suites,
+                               sizeof(u32) * local->hw.wiphy->n_cipher_suites,
+                               GFP_KERNEL);
+                       if (!suites)
+                               return -ENOMEM;
+                       for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) {
+                               u32 suite = local->hw.wiphy->cipher_suites[r];
+                               if (suite == WLAN_CIPHER_SUITE_WEP40 ||
+                                   suite == WLAN_CIPHER_SUITE_WEP104)
+                                       continue;
+                               suites[w++] = suite;
+                       }
+                       local->hw.wiphy->cipher_suites = suites;
+                       local->hw.wiphy->n_cipher_suites = w;
+                       local->wiphy_ciphers_allocated = true;
+               }
+       }
+
+       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)
@@ -532,7 +880,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                hw->queues = IEEE80211_MAX_QUEUES;
 
        local->workqueue =
-               create_singlethread_workqueue(wiphy_name(local->hw.wiphy));
+               alloc_ordered_workqueue(wiphy_name(local->hw.wiphy), 0);
        if (!local->workqueue) {
                result = -ENOMEM;
                goto fail_workqueue;
@@ -543,36 +891,38 @@ 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));
 
        debugfs_hw_add(local);
 
+       /*
+        * if the driver doesn't specify a max listen interval we
+        * use 5 which should be a safe default
+        */
        if (local->hw.max_listen_interval == 0)
-               local->hw.max_listen_interval = 1;
+               local->hw.max_listen_interval = 5;
 
        local->hw.conf.listen_interval = local->hw.max_listen_interval;
 
-       result = sta_info_start(local);
-       if (result < 0)
-               goto fail_sta_info;
+       local->dynamic_ps_forced_timeout = -1;
 
        result = ieee80211_wep_init(local);
-       if (result < 0) {
-               printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n",
-                      wiphy_name(local->hw.wiphy), result);
-               goto fail_wep;
-       }
+       if (result < 0)
+               wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
+                           result);
 
        rtnl_lock();
 
        result = ieee80211_init_rate_ctrl_alg(local,
                                              hw->rate_control_algorithm);
        if (result < 0) {
-               printk(KERN_DEBUG "%s: Failed to initialize rate control "
-                      "algorithm\n", wiphy_name(local->hw.wiphy));
+               wiphy_debug(local->hw.wiphy,
+                           "Failed to initialize rate control algorithm\n");
                goto fail_rate;
        }
 
@@ -581,54 +931,54 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                result = ieee80211_if_add(local, "wlan%d", NULL,
                                          NL80211_IFTYPE_STATION, NULL);
                if (result)
-                       printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
-                              wiphy_name(local->hw.wiphy));
+                       wiphy_warn(local->hw.wiphy,
+                                  "Failed to add default virtual iface\n");
        }
 
        rtnl_unlock();
 
        ieee80211_led_init(local);
 
-       /* alloc internal scan request */
-       i = 0;
-       local->int_scan_req->ssids = &local->scan_ssid;
-       local->int_scan_req->n_ssids = 1;
-       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
-               if (!hw->wiphy->bands[band])
-                       continue;
-               for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) {
-                       local->int_scan_req->channels[i] =
-                               &hw->wiphy->bands[band]->channels[j];
-                       i++;
-               }
-       }
-       local->int_scan_req->n_channels = i;
-
        local->network_latency_notifier.notifier_call =
                ieee80211_max_network_latency;
        result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY,
                                     &local->network_latency_notifier);
-
        if (result) {
                rtnl_lock();
                goto fail_pm_qos;
        }
 
+#ifdef CONFIG_INET
+       local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
+       result = register_inetaddr_notifier(&local->ifa_notifier);
+       if (result)
+               goto fail_ifa;
+#endif
+
+       netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll,
+                       local->hw.napi_weight);
+
        return 0;
 
+#ifdef CONFIG_INET
+ fail_ifa:
+       pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
+                              &local->network_latency_notifier);
+       rtnl_lock();
+#endif
  fail_pm_qos:
        ieee80211_led_exit(local);
        ieee80211_remove_interfaces(local);
  fail_rate:
        rtnl_unlock();
        ieee80211_wep_free(local);
- fail_wep:
        sta_info_stop(local);
- fail_sta_info:
        destroy_workqueue(local->workqueue);
  fail_workqueue:
        wiphy_unregister(local->hw.wiphy);
  fail_wiphy_register:
+       if (local->wiphy_ciphers_allocated)
+               kfree(local->hw.wiphy->cipher_suites);
        kfree(local->int_scan_req);
        return result;
 }
@@ -643,6 +993,9 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 
        pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
                               &local->network_latency_notifier);
+#ifdef CONFIG_INET
+       unregister_inetaddr_notifier(&local->ifa_notifier);
+#endif
 
        rtnl_lock();
 
@@ -655,21 +1008,28 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 
        rtnl_unlock();
 
+       /*
+        * Now all work items will be gone, but the
+        * timer might still be armed, so delete it
+        */
+       del_timer_sync(&local->work_timer);
+
+       cancel_work_sync(&local->restart_work);
        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) ||
            skb_queue_len(&local->skb_queue_unreliable))
-               printk(KERN_WARNING "%s: skb_queue not empty\n",
-                      wiphy_name(local->hw.wiphy));
+               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);
+       sta_info_stop(local);
        ieee80211_wep_free(local);
        ieee80211_led_exit(local);
        kfree(local->int_scan_req);
@@ -681,7 +1041,10 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
        struct ieee80211_local *local = hw_to_local(hw);
 
        mutex_destroy(&local->iflist_mtx);
-       mutex_destroy(&local->scan_mtx);
+       mutex_destroy(&local->mtx);
+
+       if (local->wiphy_ciphers_allocated)
+               kfree(local->hw.wiphy->cipher_suites);
 
        wiphy_free(local->hw.wiphy);
 }
@@ -700,6 +1063,10 @@ static int __init ieee80211_init(void)
        if (ret)
                return ret;
 
+       ret = rc80211_minstrel_ht_init();
+       if (ret)
+               goto err_minstrel;
+
        ret = rc80211_pid_init();
        if (ret)
                goto err_pid;
@@ -712,6 +1079,8 @@ static int __init ieee80211_init(void)
  err_netdev:
        rc80211_pid_exit();
  err_pid:
+       rc80211_minstrel_ht_exit();
+ err_minstrel:
        rc80211_minstrel_exit();
 
        return ret;
@@ -720,18 +1089,15 @@ static int __init ieee80211_init(void)
 static void __exit ieee80211_exit(void)
 {
        rc80211_pid_exit();
+       rc80211_minstrel_ht_exit();
        rc80211_minstrel_exit();
 
-       /*
-        * For key todo, it'll be empty by now but the work
-        * might still be scheduled.
-        */
-       flush_scheduled_work();
-
        if (mesh_allocated)
                ieee80211s_stop();
 
        ieee80211_iface_exit();
+
+       rcu_barrier();
 }