[NET]: Cleanup calling netdev notifiers.
[safe/jmp/linux-2.6] / net / mac80211 / tx.c
index b65ff65..ca262a9 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/skbuff.h>
 #include <linux/etherdevice.h>
 #include <linux/bitmap.h>
+#include <linux/rcupdate.h>
+#include <net/net_namespace.h>
 #include <net/ieee80211_radiotap.h>
 #include <net/cfg80211.h>
 #include <net/mac80211.h>
@@ -426,20 +428,22 @@ ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx)
 static ieee80211_txrx_result
 ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx)
 {
-       tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID;
+       struct ieee80211_key *key;
 
        if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
                tx->key = NULL;
-       else if (tx->sta && tx->sta->key)
-               tx->key = tx->sta->key;
-       else if (tx->sdata->default_key)
-               tx->key = tx->sdata->default_key;
+       else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
+               tx->key = key;
+       else if ((key = rcu_dereference(tx->sdata->default_key)))
+               tx->key = key;
        else if (tx->sdata->drop_unencrypted &&
                 !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) {
                I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
                return TXRX_DROP;
-       } else
+       } else {
                tx->key = NULL;
+               tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+       }
 
        if (tx->key) {
                tx->key->tx_rx_count++;
@@ -541,9 +545,8 @@ static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb)
                        return -1;
        } else {
                tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
-               if (tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) {
-                       if (ieee80211_wep_add_iv(tx->local, skb, tx->key) ==
-                           NULL)
+               if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) {
+                       if (!ieee80211_wep_add_iv(tx->local, skb, tx->key))
                                return -1;
                }
        }
@@ -721,6 +724,15 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
                }
        }
 
+       /*
+        * Tell hardware to not encrypt when we had sw crypto.
+        * Because we use the same flag to internally indicate that
+        * no (software) encryption should be done, we have to set it
+        * after all crypto handlers.
+        */
+       if (tx->key && !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+               tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+
        return TXRX_CONTINUE;
 }
 
@@ -743,8 +755,6 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
         * 1 usec = 1/8 * (1080 / 10) = 13.5 */
 
        if (mode->mode == MODE_IEEE80211A ||
-           mode->mode == MODE_ATHEROS_TURBO ||
-           mode->mode == MODE_ATHEROS_TURBOG ||
            (mode->mode == MODE_IEEE80211G &&
             tx->u.tx.rate->flags & IEEE80211_RATE_ERP))
                hdrtime = CHAN_UTIL_HDR_SHORT;
@@ -832,7 +842,6 @@ __ieee80211_parse_tx_radiotap(
         */
 
        control->retry_limit = 1; /* no retry */
-       control->key_idx = HW_KEY_IDX_INVALID;
        control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS |
                            IEEE80211_TXCTL_USE_CTS_PROTECT);
        control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT |
@@ -950,8 +959,6 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
        tx->dev = dev; /* use original interface */
        tx->local = local;
        tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       tx->sta = sta_info_get(local, hdr->addr1);
-       tx->fc = le16_to_cpu(hdr->frame_control);
 
        /*
         * set defaults for things that can be set by
@@ -976,6 +983,8 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
                res = TXRX_QUEUED; /* indication it was monitor packet */
        }
 
+       tx->sta = sta_info_get(local, hdr->addr1);
+       tx->fc = le16_to_cpu(hdr->frame_control);
        tx->u.tx.control = control;
        if (is_multicast_ether_addr(hdr->addr1)) {
                tx->flags &= ~IEEE80211_TXRXD_TXUNICAST;
@@ -1018,7 +1027,7 @@ static int inline ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
        struct net_device *dev;
 
        pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
-       dev = dev_get_by_index(pkt_data->ifindex);
+       dev = dev_get_by_index(&init_net, pkt_data->ifindex);
        if (unlikely(dev && !is_ieee80211_device(dev, mdev))) {
                dev_put(dev);
                dev = NULL;
@@ -1111,6 +1120,12 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
                return 0;
        }
 
+       /*
+        * key references are protected using RCU and this requires that
+        * we are in a read-site RCU section during receive processing
+        */
+       rcu_read_lock();
+
        sta = tx.sta;
        tx.u.tx.mgmt_interface = mgmt;
        tx.u.tx.mode = local->hw.conf.mode;
@@ -1138,6 +1153,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
 
        if (unlikely(res == TXRX_QUEUED)) {
                I802_DEBUG_INC(local->tx_handlers_queued);
+               rcu_read_unlock();
                return 0;
        }
 
@@ -1195,6 +1211,7 @@ retry:
                store->last_frag_rate_ctrl_probe =
                        !!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG);
        }
+       rcu_read_unlock();
        return 0;
 
  drop:
@@ -1204,6 +1221,7 @@ retry:
                if (tx.u.tx.extra_frag[i])
                        dev_kfree_skb(tx.u.tx.extra_frag[i]);
        kfree(tx.u.tx.extra_frag);
+       rcu_read_unlock();
        return 0;
 }
 
@@ -1226,7 +1244,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
        memset(&control, 0, sizeof(struct ieee80211_tx_control));
 
        if (pkt_data->ifindex)
-               odev = dev_get_by_index(pkt_data->ifindex);
+               odev = dev_get_by_index(&init_net, pkt_data->ifindex);
        if (unlikely(odev && !is_ieee80211_device(odev, dev))) {
                dev_put(odev);
                odev = NULL;
@@ -1486,7 +1504,20 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
                nh_pos += encaps_len;
                h_pos += encaps_len;
        }
-       memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
+
+       if (fc & IEEE80211_STYPE_QOS_DATA) {
+               __le16 *qos_control;
+
+               qos_control = (__le16*) skb_push(skb, 2);
+               memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2);
+               /*
+                * Maybe we could actually set some fields here, for now just
+                * initialise to zero to indicate no special operation.
+                */
+               *qos_control = 0;
+       } else
+               memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
+
        nh_pos += hdrlen;
        h_pos += hdrlen;
 
@@ -1497,8 +1528,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
                pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE;
 
        skb->dev = local->mdev;
-       sdata->stats.tx_packets++;
-       sdata->stats.tx_bytes += skb->len;
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
 
        /* Update skb pointers to various headers since this modified frame
         * is going to go through Linux networking code that may potentially
@@ -1571,8 +1602,8 @@ int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (!(fc & IEEE80211_FCTL_PROTECTED))
                pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
 
-       sdata->stats.tx_packets++;
-       sdata->stats.tx_bytes += skb->len;
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
 
        dev_queue_xmit(skb);
 
@@ -1722,7 +1753,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,
        u8 *b_head, *b_tail;
        int bh_len, bt_len;
 
-       bdev = dev_get_by_index(if_id);
+       bdev = dev_get_by_index(&init_net, if_id);
        if (bdev) {
                sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
                ap = &sdata->u.ap;
@@ -1836,7 +1867,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_if_ap *bss = NULL;
 
-       bdev = dev_get_by_index(if_id);
+       bdev = dev_get_by_index(&init_net, if_id);
        if (bdev) {
                sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
                bss = &sdata->u.ap;
@@ -1870,6 +1901,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
        }
        sta = tx.sta;
        tx.flags |= IEEE80211_TXRXD_TXPS_BUFFERED;
+       tx.u.tx.mode = local->hw.conf.mode;
 
        for (handler = local->tx_handlers; *handler != NULL; handler++) {
                res = (*handler)(&tx);