mac80211: add nl80211/cfg80211 handling of the new mesh root mode option.
[safe/jmp/linux-2.6] / net / mac80211 / main.c
index 3234f37..beb8718 100644 (file)
@@ -50,9 +50,9 @@ struct ieee80211_tx_status_rtap_hdr {
 } __attribute__ ((packed));
 
 
-/* must be called under mdev tx lock */
 void ieee80211_configure_filter(struct ieee80211_local *local)
 {
+       u64 mc;
        unsigned int changed_flags;
        unsigned int new_flags = 0;
 
@@ -62,7 +62,7 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
        if (atomic_read(&local->iff_allmultis))
                new_flags |= FIF_ALLMULTI;
 
-       if (local->monitors)
+       if (local->monitors || local->scanning)
                new_flags |= FIF_BCN_PRBRESP_PROMISC;
 
        if (local->fif_fcsfail)
@@ -77,20 +77,33 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
        if (local->fif_other_bss)
                new_flags |= FIF_OTHER_BSS;
 
+       if (local->fif_pspoll)
+               new_flags |= FIF_PSPOLL;
+
+       spin_lock_bh(&local->filter_lock);
        changed_flags = local->filter_flags ^ new_flags;
 
+       mc = drv_prepare_multicast(local, local->mc_count, local->mc_list);
+       spin_unlock_bh(&local->filter_lock);
+
        /* be a bit nasty */
        new_flags |= (1<<31);
 
-       drv_configure_filter(local, changed_flags, &new_flags,
-                            local->mc_count,
-                            local->mc_list);
+       drv_configure_filter(local, changed_flags, &new_flags, mc);
 
        WARN_ON(new_flags & (1<<31));
 
        local->filter_flags = new_flags & ~(1<<31);
 }
 
+static void ieee80211_reconfig_filter(struct work_struct *work)
+{
+       struct ieee80211_local *local =
+               container_of(work, struct ieee80211_local, reconfig_filter);
+
+       ieee80211_configure_filter(local);
+}
+
 int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 {
        struct ieee80211_channel *chan, *scan_chan;
@@ -198,7 +211,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
        }
 
        if (changed & BSS_CHANGED_BEACON_ENABLED) {
-               if (local->sw_scanning) {
+               if (local->quiescing || !netif_running(sdata->dev) ||
+                   test_bit(SCAN_SW_SCANNING, &local->scanning)) {
                        sdata->vif.bss_conf.enable_beacon = false;
                } else {
                        /*
@@ -227,9 +241,6 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 
        drv_bss_info_changed(local, &sdata->vif,
                             &sdata->vif.bss_conf, changed);
-
-       /* DEPRECATED */
-       local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int;
 }
 
 u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
@@ -310,6 +321,31 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
 {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
+       /*
+        * XXX: This is temporary!
+        *
+        *      The problem here is that when we get here, the driver will
+        *      quite likely have pretty much overwritten info->control by
+        *      using info->driver_data or info->rate_driver_data. Thus,
+        *      when passing out the frame to the driver again, we would be
+        *      passing completely bogus data since the driver would then
+        *      expect a properly filled info->control. In mac80211 itself
+        *      the same problem occurs, since we need info->control.vif
+        *      internally.
+        *
+        *      To fix this, we should send the frame through TX processing
+        *      again. However, it's not that simple, since the frame will
+        *      have been software-encrypted (if applicable) already, and
+        *      encrypting it again doesn't do much good. So to properly do
+        *      that, we not only have to skip the actual 'raw' encryption
+        *      (key selection etc. still has to be done!) but also the
+        *      sequence number assignment since that impacts the crypto
+        *      encapsulation, of course.
+        *
+        *      Hence, for now, fix the bug by just dropping the frame.
+        */
+       goto drop;
+
        sta->tx_filtered_count++;
 
        /*
@@ -349,13 +385,13 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
         *      can be unknown, for example with different interrupt status
         *      bits.
         */
-       if (test_sta_flags(sta, WLAN_STA_PS) &&
+       if (test_sta_flags(sta, WLAN_STA_PS_STA) &&
            skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
                skb_queue_tail(&sta->tx_filtered, skb);
                return;
        }
 
-       if (!test_sta_flags(sta, WLAN_STA_PS) &&
+       if (!test_sta_flags(sta, WLAN_STA_PS_STA) &&
            !(info->flags & IEEE80211_TX_INTFL_RETRIED)) {
                /* Software retry the packet once */
                info->flags |= IEEE80211_TX_INTFL_RETRIED;
@@ -363,13 +399,14 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
                return;
        }
 
+ drop:
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        if (net_ratelimit())
                printk(KERN_DEBUG "%s: dropped TX filtered frame, "
                       "queue_len=%d PS=%d @%lu\n",
                       wiphy_name(local->hw.wiphy),
                       skb_queue_len(&sta->tx_filtered),
-                      !!test_sta_flags(sta, WLAN_STA_PS), jiffies);
+                      !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
 #endif
        dev_kfree_skb(skb);
 }
@@ -409,7 +446,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        if (sta) {
                if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
-                   test_sta_flags(sta, WLAN_STA_PS)) {
+                   test_sta_flags(sta, WLAN_STA_PS_STA)) {
                        /*
                         * The STA is in power save mode, so assume
                         * that this TX packet failed because of that.
@@ -445,6 +482,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                }
 
                rate_control_tx_status(local, sband, sta, skb);
+               if (ieee80211_vif_is_mesh(&sta->sdata->vif))
+                       ieee80211s_update_metric(local, sta, skb);
        }
 
        rcu_read_unlock();
@@ -620,6 +659,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        if (!wiphy)
                return NULL;
 
+       wiphy->netnsok = true;
        wiphy->privid = mac80211_wiphy_privid;
 
        /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
@@ -646,7 +686,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        local->hw.max_rates = 1;
        local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
        local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
-       local->hw.conf.radio_enabled = true;
        local->user_power_level = -1;
 
        INIT_LIST_HEAD(&local->interfaces);
@@ -661,6 +700,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        INIT_WORK(&local->restart_work, ieee80211_restart_work);
 
+       INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
+
        INIT_WORK(&local->dynamic_ps_enable_work,
                  ieee80211_dynamic_ps_enable_work);
        INIT_WORK(&local->dynamic_ps_disable_work,
@@ -674,12 +715,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                skb_queue_head_init(&local->pending[i]);
        tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
                     (unsigned long)local);
-       tasklet_disable(&local->tx_pending_tasklet);
 
        tasklet_init(&local->tasklet,
                     ieee80211_tasklet_handler,
                     (unsigned long) local);
-       tasklet_disable(&local->tasklet);
 
        skb_queue_head_init(&local->skb_queue);
        skb_queue_head_init(&local->skb_queue_unreliable);
@@ -734,9 +773,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                supp_ht = supp_ht || sband->ht_cap.ht_supported;
        }
 
-       local->int_scan_req.n_channels = channels;
-       local->int_scan_req.channels = kzalloc(sizeof(void *) * channels, GFP_KERNEL);
-       if (!local->int_scan_req.channels)
+       local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) +
+                                     sizeof(void *) * channels, GFP_KERNEL);
+       if (!local->int_scan_req)
                return -ENOMEM;
 
        /* if low-level driver supports AP, we also support VLAN */
@@ -793,9 +832,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (hw->queues > IEEE80211_MAX_QUEUES)
                hw->queues = IEEE80211_MAX_QUEUES;
 
-       local->hw.workqueue =
+       local->workqueue =
                create_singlethread_workqueue(wiphy_name(local->hw.wiphy));
-       if (!local->hw.workqueue) {
+       if (!local->workqueue) {
                result = -ENOMEM;
                goto fail_workqueue;
        }
@@ -851,17 +890,18 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        /* alloc internal scan request */
        i = 0;
-       local->int_scan_req.ssids = &local->scan_ssid;
-       local->int_scan_req.n_ssids = 1;
+       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] =
+                       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;
@@ -884,12 +924,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
  fail_wep:
        sta_info_stop(local);
  fail_sta_info:
-       debugfs_hw_del(local);
-       destroy_workqueue(local->hw.workqueue);
+       destroy_workqueue(local->workqueue);
  fail_workqueue:
        wiphy_unregister(local->hw.wiphy);
  fail_wiphy_register:
-       kfree(local->int_scan_req.channels);
+       kfree(local->int_scan_req);
        return result;
 }
 EXPORT_SYMBOL(ieee80211_register_hw);
@@ -915,10 +954,11 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 
        rtnl_unlock();
 
+       cancel_work_sync(&local->reconfig_filter);
+
        ieee80211_clear_tx_pending(local);
        sta_info_stop(local);
        rate_control_deinitialize(local);
-       debugfs_hw_del(local);
 
        if (skb_queue_len(&local->skb_queue)
                        || skb_queue_len(&local->skb_queue_unreliable))
@@ -927,11 +967,11 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
        skb_queue_purge(&local->skb_queue);
        skb_queue_purge(&local->skb_queue_unreliable);
 
-       destroy_workqueue(local->hw.workqueue);
+       destroy_workqueue(local->workqueue);
        wiphy_unregister(local->hw.wiphy);
        ieee80211_wep_free(local);
        ieee80211_led_exit(local);
-       kfree(local->int_scan_req.channels);
+       kfree(local->int_scan_req);
 }
 EXPORT_SYMBOL(ieee80211_unregister_hw);