Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
[linux-2.6.git] / net / mac80211 / main.c
index ae656b6..2306d75 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
 #include <linux/bitmap.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.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)
 {
@@ -51,7 +47,7 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
        if (atomic_read(&local->iff_allmultis))
                new_flags |= FIF_ALLMULTI;
 
-       if (local->monitors || local->scanning)
+       if (local->monitors || test_bit(SCAN_SW_SCANNING, &local->scanning))
                new_flags |= FIF_BCN_PRBRESP_PROMISC;
 
        if (local->fif_probe_req || local->probe_req_reg)
@@ -98,7 +94,7 @@ static void ieee80211_reconfig_filter(struct work_struct *work)
 
 int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 {
-       struct ieee80211_channel *chan, *scan_chan;
+       struct ieee80211_channel *chan;
        int ret = 0;
        int power;
        enum nl80211_channel_type channel_type;
@@ -106,23 +102,33 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 
        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;
-               local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
-       } else if (local->tmp_channel &&
-                  local->oper_channel != local->tmp_channel) {
-               chan = scan_chan = local->tmp_channel;
+       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 = local->tmp_channel;
                channel_type = local->tmp_channel_type;
-               local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
        } else {
                chan = local->oper_channel;
                channel_type = local->_oper_channel_type;
-               local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL;
        }
+
+       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 ||
@@ -144,11 +150,13 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
                changed |= IEEE80211_CONF_CHANGE_SMPS;
        }
 
-       if (scan_chan)
+       if (test_bit(SCAN_SW_SCANNING, &local->scanning) ||
+           test_bit(SCAN_HW_SCANNING, &local->scanning))
                power = chan->max_power;
        else
                power = local->power_constr_level ?
-                       (chan->max_power - local->power_constr_level) :
+                       min(chan->max_power,
+                               (chan->max_reg_power  - local->power_constr_level)) :
                        chan->max_power;
 
        if (local->user_power_level >= 0)
@@ -191,15 +199,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
                return;
 
        if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-               /*
-                * While not associated, claim a BSSID of all-zeroes
-                * so that drivers don't do any weird things with the
-                * BSSID at that time.
-                */
-               if (sdata->vif.bss_conf.assoc)
-                       sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid;
-               else
-                       sdata->vif.bss_conf.bssid = zero;
+               sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid;
        } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
                sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
        else if (sdata->vif.type == NL80211_IFTYPE_AP)
@@ -229,7 +229,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 
        if (changed & BSS_CHANGED_BEACON_ENABLED) {
                if (local->quiescing || !ieee80211_sdata_running(sdata) ||
-                   test_bit(SCAN_SW_SCANNING, &local->scanning)) {
+                   test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) {
                        sdata->vif.bss_conf.enable_beacon = false;
                } else {
                        /*
@@ -275,6 +275,8 @@ u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
 static void ieee80211_tasklet_handler(unsigned long data)
 {
        struct ieee80211_local *local = (struct ieee80211_local *) data;
+       struct sta_info *sta, *tmp;
+       struct skb_eosp_msg_data *eosp_data;
        struct sk_buff *skb;
 
        while ((skb = skb_dequeue(&local->skb_queue)) ||
@@ -290,6 +292,18 @@ static void ieee80211_tasklet_handler(unsigned long data)
                        skb->pkt_type = 0;
                        ieee80211_tx_status(local_to_hw(local), skb);
                        break;
+               case IEEE80211_EOSP_MSG:
+                       eosp_data = (void *)skb->cb;
+                       for_each_sta_info(local, eosp_data->sta, sta, tmp) {
+                               /* skip wrong virtual interface */
+                               if (memcmp(eosp_data->iface,
+                                          sta->sdata->vif.addr, ETH_ALEN))
+                                       continue;
+                               clear_sta_flag(sta, WLAN_STA_SP);
+                               break;
+                       }
+                       dev_kfree_skb(skb);
+                       break;
                default:
                        WARN(1, "mac80211: Packet is of unknown type %d\n",
                             skb->pkt_type);
@@ -308,7 +322,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);
 
@@ -324,6 +339,9 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
 
        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);
@@ -368,9 +386,6 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
        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;
@@ -399,7 +414,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
        }
        bss_conf->arp_addr_cnt = c;
 
-       /* Configure driver only if associated */
+       /* Configure driver only if associated (which also implies it is up) */
        if (ifmgd->associated) {
                bss_conf->arp_filter_enabled = sdata->arp_filter_state;
                ieee80211_bss_info_change_notify(sdata,
@@ -484,6 +499,25 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
                        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),
+       },
+};
+
+static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = {
+       .ampdu_params_info = IEEE80211_HT_AMPDU_PARM_FACTOR |
+                            IEEE80211_HT_AMPDU_PARM_DENSITY,
+
+       .cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+                               IEEE80211_HT_CAP_MAX_AMSDU |
+                               IEEE80211_HT_CAP_SGI_40),
+       .mcs = {
+               .rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff,
+                            0xff, 0xff, 0xff, 0xff, 0xff, },
+       },
 };
 
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
@@ -493,6 +527,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        int priv_size, i;
        struct wiphy *wiphy;
 
+       if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove)))
+               return NULL;
+
        /* Ensure 32-byte alignment of our private data and hw private data.
         * We use the wiphy priv data for both our ieee80211_local and for
         * the driver's private data
@@ -517,11 +554,20 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        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_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS;
-       wiphy->privid = mac80211_wiphy_privid;
+                       WIPHY_FLAG_REPORTS_OBSS |
+                       WIPHY_FLAG_OFFCHAN_TX |
+                       WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+
+       wiphy->features = NL80211_FEATURE_SK_TX_STATUS |
+                         NL80211_FEATURE_HT_IBSS;
+
+       if (!ops->set_key)
+               wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
 
        wiphy->bss_priv_size = sizeof(struct ieee80211_bss);
 
@@ -531,7 +577,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
 
-       BUG_ON(!ops->tx);
+       BUG_ON(!ops->tx && !ops->tx_frags);
        BUG_ON(!ops->start);
        BUG_ON(!ops->stop);
        BUG_ON(!ops->config);
@@ -544,11 +590,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        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.max_tx_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;
+       wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
 
        INIT_LIST_HEAD(&local->interfaces);
 
@@ -561,6 +610,16 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        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);
@@ -578,6 +637,14 @@ 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);
+
+       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);
 
        for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
@@ -597,6 +664,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        /* 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);
 }
 EXPORT_SYMBOL(ieee80211_alloc_hw);
@@ -604,7 +675,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;
@@ -619,6 +690,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->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan)
+               return -EINVAL;
+
        if (hw->max_report_rates == 0)
                hw->max_report_rates = hw->max_rates;
 
@@ -654,18 +735,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;
 
@@ -741,6 +855,16 @@ 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;
+
+       /* mac80211 based drivers don't support internal TDLS setup */
+       if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)
+               local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
+
        result = wiphy_register(local->hw.wiphy);
        if (result < 0)
                goto fail_wiphy_register;
@@ -764,10 +888,8 @@ 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.
         */
-       BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM !=
-                       sizeof(struct ieee80211_tx_status_rtap_hdr));
        local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom,
-                                  sizeof(struct ieee80211_tx_status_rtap_hdr));
+                                  IEEE80211_TX_STATUS_HEADROOM);
 
        debugfs_hw_add(local);
 
@@ -782,15 +904,13 @@ 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",
                            result);
 
+       ieee80211_led_init(local);
+
        rtnl_lock();
 
        result = ieee80211_init_rate_ctrl_alg(local,
@@ -812,8 +932,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        rtnl_unlock();
 
-       ieee80211_led_init(local);
-
        local->network_latency_notifier.notifier_call =
                ieee80211_max_network_latency;
        result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY,
@@ -848,7 +966,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);
@@ -894,7 +1011,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) ||
@@ -902,15 +1018,24 @@ 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);
+       sta_info_stop(local);
        ieee80211_wep_free(local);
        ieee80211_led_exit(local);
        kfree(local->int_scan_req);
 }
 EXPORT_SYMBOL(ieee80211_unregister_hw);
 
+static int ieee80211_free_ack_frame(int id, void *p, void *data)
+{
+       WARN_ONCE(1, "Have pending ack frames!\n");
+       kfree_skb(p);
+       return 0;
+}
+
 void ieee80211_free_hw(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
@@ -921,6 +1046,10 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
        if (local->wiphy_ciphers_allocated)
                kfree(local->hw.wiphy->cipher_suites);
 
+       idr_for_each(&local->ack_status_frames,
+                    ieee80211_free_ack_frame, NULL);
+       idr_destroy(&local->ack_status_frames);
+
        wiphy_free(local->hw.wiphy);
 }
 EXPORT_SYMBOL(ieee80211_free_hw);
@@ -971,6 +1100,8 @@ static void __exit ieee80211_exit(void)
                ieee80211s_stop();
 
        ieee80211_iface_exit();
+
+       rcu_barrier();
 }