mac80211: implement RANN processing and forwarding
[safe/jmp/linux-2.6] / net / mac80211 / util.c
index dbf66b5..da86e15 100644 (file)
@@ -275,16 +275,12 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
 
        __clear_bit(reason, &local->queue_stop_reasons[queue]);
 
-       if (!skb_queue_empty(&local->pending[queue]) &&
-           local->queue_stop_reasons[queue] ==
-                               BIT(IEEE80211_QUEUE_STOP_REASON_PENDING))
-               tasklet_schedule(&local->tx_pending_tasklet);
-
        if (local->queue_stop_reasons[queue] != 0)
                /* someone still has this queue stopped */
                return;
 
-       netif_wake_subqueue(local->mdev, queue);
+       if (!skb_queue_empty(&local->pending[queue]))
+               tasklet_schedule(&local->tx_pending_tasklet);
 }
 
 void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
@@ -313,14 +309,6 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
        if (WARN_ON(queue >= hw->queues))
                return;
 
-       /*
-        * Only stop if it was previously running, this is necessary
-        * for correct pending packets handling because there we may
-        * start (but not wake) the queue and rely on that.
-        */
-       if (!local->queue_stop_reasons[queue])
-               netif_stop_subqueue(local->mdev, queue);
-
        __set_bit(reason, &local->queue_stop_reasons[queue]);
 }
 
@@ -348,11 +336,16 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
        struct ieee80211_hw *hw = &local->hw;
        unsigned long flags;
        int queue = skb_get_queue_mapping(skb);
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+       if (WARN_ON(!info->control.vif)) {
+               kfree_skb(skb);
+               return;
+       }
 
        spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
        __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
-       __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_PENDING);
-       skb_queue_tail(&local->pending[queue], skb);
+       __skb_queue_tail(&local->pending[queue], skb);
        __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 }
@@ -371,18 +364,21 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local,
                        IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
 
        while ((skb = skb_dequeue(skbs))) {
+               struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+               if (WARN_ON(!info->control.vif)) {
+                       kfree_skb(skb);
+                       continue;
+               }
+
                ret++;
                queue = skb_get_queue_mapping(skb);
-               skb_queue_tail(&local->pending[queue], skb);
+               __skb_queue_tail(&local->pending[queue], skb);
        }
 
-       for (i = 0; i < hw->queues; i++) {
-               if (ret)
-                       __ieee80211_stop_queue(hw, i,
-                               IEEE80211_QUEUE_STOP_REASON_PENDING);
+       for (i = 0; i < hw->queues; i++)
                __ieee80211_wake_queue(hw, i,
                        IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
-       }
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 
        return ret;
@@ -413,11 +409,16 @@ EXPORT_SYMBOL(ieee80211_stop_queues);
 int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
 {
        struct ieee80211_local *local = hw_to_local(hw);
+       unsigned long flags;
+       int ret;
 
        if (WARN_ON(queue >= hw->queues))
                return true;
 
-       return __netif_subqueue_stopped(local->mdev, queue);
+       spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+       ret = !!local->queue_stop_reasons[queue];
+       spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+       return ret;
 }
 EXPORT_SYMBOL(ieee80211_queue_stopped);
 
@@ -510,6 +511,46 @@ void ieee80211_iterate_active_interfaces_atomic(
 }
 EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
 
+/*
+ * Nothing should have been stuffed into the workqueue during
+ * the suspend->resume cycle. If this WARN is seen then there
+ * is a bug with either the driver suspend or something in
+ * mac80211 stuffing into the workqueue which we haven't yet
+ * cleared during mac80211's suspend cycle.
+ */
+static bool ieee80211_can_queue_work(struct ieee80211_local *local)
+{
+        if (WARN(local->suspended, "queueing ieee80211 work while "
+                "going to suspend\n"))
+                return false;
+
+       return true;
+}
+
+void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+
+       if (!ieee80211_can_queue_work(local))
+               return;
+
+       queue_work(local->workqueue, work);
+}
+EXPORT_SYMBOL(ieee80211_queue_work);
+
+void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
+                                 struct delayed_work *dwork,
+                                 unsigned long delay)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+
+       if (!ieee80211_can_queue_work(local))
+               return;
+
+       queue_delayed_work(local->workqueue, dwork, delay);
+}
+EXPORT_SYMBOL(ieee80211_queue_delayed_work);
+
 void ieee802_11_parse_elems(u8 *start, size_t len,
                            struct ieee802_11_elems *elems)
 {
@@ -644,6 +685,10 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
                        elems->perr = pos;
                        elems->perr_len = elen;
                        break;
+               case WLAN_EID_RANN:
+                       if (elen >= sizeof(struct ieee80211_rann_ie))
+                               elems->rann = (void *)pos;
+                       break;
                case WLAN_EID_CHANNEL_SWITCH:
                        elems->ch_switch_elem = pos;
                        elems->ch_switch_elem_len = elen;
@@ -761,20 +806,6 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
        ieee80211_set_wmm_default(sdata);
 }
 
-void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
-                     int encrypt)
-{
-       skb->dev = sdata->local->mdev;
-       skb_set_mac_header(skb, 0);
-       skb_set_network_header(skb, 0);
-       skb_set_transport_header(skb, 0);
-
-       skb->iif = sdata->dev->ifindex;
-       skb->do_not_encrypt = !encrypt;
-
-       dev_queue_xmit(skb);
-}
-
 u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
                              enum ieee80211_band band)
 {
@@ -845,13 +876,14 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
 }
 
 int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
-                            const u8 *ie, size_t ie_len)
+                            const u8 *ie, size_t ie_len,
+                            enum ieee80211_band band)
 {
        struct ieee80211_supported_band *sband;
        u8 *pos, *supp_rates_len, *esupp_rates_len = NULL;
        int i;
 
-       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+       sband = local->hw.wiphy->bands[band];
 
        pos = buffer;
 
@@ -939,7 +971,8 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
        memcpy(pos, ssid, ssid_len);
        pos += ssid_len;
 
-       skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len));
+       skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len,
+                                             local->hw.conf.channel->band));
 
        ieee80211_tx_skb(sdata, skb, 0);
 }
@@ -980,6 +1013,16 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
        return supp_rates;
 }
 
+void ieee80211_stop_device(struct ieee80211_local *local)
+{
+       ieee80211_led_radio(local, false);
+
+       cancel_work_sync(&local->reconfig_filter);
+       drv_stop(local);
+
+       flush_workqueue(local->workqueue);
+}
+
 int ieee80211_reconfig(struct ieee80211_local *local)
 {
        struct ieee80211_hw *hw = &local->hw;
@@ -1049,9 +1092,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        /* reconfigure hardware */
        ieee80211_hw_config(local, ~0);
 
-       netif_addr_lock_bh(local->mdev);
        ieee80211_configure_filter(local);
-       netif_addr_unlock_bh(local->mdev);
 
        /* Finally also reconfigure all the BSS information */
        list_for_each_entry(sdata, &local->interfaces, list) {
@@ -1127,3 +1168,4 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 #endif
        return 0;
 }
+