rt2x00: Properly reserve room for descriptors in skbs.
authorGertjan van Wingerde <gwingerde@gmail.com>
Thu, 3 Jun 2010 08:51:45 +0000 (10:51 +0200)
committerIvo van Doorn <IvDoorn@gmail.com>
Thu, 3 Jun 2010 08:51:45 +0000 (10:51 +0200)
Instead of fiddling with the skb->data pointer and thereby risking
out of bounds accesses, properly reserve the space needed in an
skb for descriptors.

Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com>
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
16 files changed:
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800lib.h
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00lib.h
drivers/net/wireless/rt2x00/rt2x00pci.c
drivers/net/wireless/rt2x00/rt2x00pci.h
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00usb.c
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c

index 1e543ac2f86fd060389cb1d13144154e063fd961..1eb882e15fb454c325a0b5772408456527dc9aba 100644 (file)
@@ -1229,7 +1229,7 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
                }
                txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
 
-               rt2x00lib_txdone(entry, &txdesc);
+               rt2x00pci_txdone(entry, &txdesc);
        }
 }
 
index 1582cabd3a1ea6d6c9159e621de7baebcc9ee168..a29cb212f89ad61819ce2fd2d19c468add0b8428 100644 (file)
@@ -1365,7 +1365,7 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
                }
                txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
 
-               rt2x00lib_txdone(entry, &txdesc);
+               rt2x00pci_txdone(entry, &txdesc);
        }
 }
 
index d19f29a53523bd5abbf62a6a59ded5076d1b5684..9dab1dccdaff063185a348e1e84d6e2aee61d1eb 100644 (file)
@@ -1034,7 +1034,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txd = (__le32 *)(skb->data - TXD_DESC_SIZE);
+       __le32 *txd = (__le32 *) skb->data;
        u32 word;
 
        /*
@@ -1080,6 +1080,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        /*
         * Register descriptor details in skb frame descriptor.
         */
+       skbdesc->flags |= SKBDESC_DESC_IN_SKB;
        skbdesc->desc = txd;
        skbdesc->desc_len = TXD_DESC_SIZE;
 }
@@ -1107,6 +1108,12 @@ static void rt2500usb_write_beacon(struct queue_entry *entry,
        rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
        rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
 
+       /*
+        * Add space for the descriptor in front of the skb.
+        */
+       skb_push(entry->skb, TXD_DESC_SIZE);
+       memset(entry->skb->data, 0, TXD_DESC_SIZE);
+
        /*
         * Write the TX descriptor for the beacon.
         */
@@ -1117,11 +1124,6 @@ static void rt2500usb_write_beacon(struct queue_entry *entry,
         */
        rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
 
-       /*
-        * Take the descriptor in front of the skb into account.
-        */
-       skb_push(entry->skb, TXD_DESC_SIZE);
-
        /*
         * USB devices cannot blindly pass the skb->len as the
         * length of the data to usb_fill_bulk_urb. Pass the skb
index db4250d1c8b35cc68abfe078a10753d5ad97e198..3258301aa29cfb3d6e90c39ab74084cdf21f9c15 100644 (file)
@@ -282,9 +282,8 @@ int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
 }
 EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready);
 
-void rt2800_write_txwi(struct sk_buff *skb, struct txentry_desc *txdesc)
+void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
 {
-       __le32 *txwi = (__le32 *)(skb->data - TXWI_DESC_SIZE);
        u32 word;
 
        /*
index 94de999e229032841ea9793b89e4ffd7f4810354..0f0a13c61e683b61a727d89a81aca8f8b138bebd 100644 (file)
@@ -111,7 +111,7 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
                        const u8 command, const u8 token,
                        const u8 arg0, const u8 arg1);
 
-void rt2800_write_txwi(struct sk_buff *skb, struct txentry_desc *txdesc);
+void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc);
 void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *txdesc);
 
 extern const struct rt2x00debug rt2800_rt2x00debug;
index 72e4f29a2fc73fbe8e3bb6960fcce97e70cd3d1e..db61a78e32b0c2054f54b0427e7f41fb8dfc86e2 100644 (file)
@@ -616,7 +616,7 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
 static void rt2800pci_write_tx_datadesc(struct queue_entry* entry,
                                         struct txentry_desc *txdesc)
 {
-       rt2800_write_txwi(entry->skb, txdesc);
+       rt2800_write_txwi((__le32 *) entry->skb->data, txdesc);
 }
 
 
@@ -692,27 +692,29 @@ static void rt2800pci_write_beacon(struct queue_entry *entry,
        rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
        rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 
+       /*
+        * Add space for the TXWI in front of the skb.
+        */
+       skb_push(entry->skb, TXWI_DESC_SIZE);
+       memset(entry->skb, 0, TXWI_DESC_SIZE);
+
        /*
         * Register descriptor details in skb frame descriptor.
         */
-       skbdesc->desc = entry->skb->data - TXWI_DESC_SIZE;
+       skbdesc->flags |= SKBDESC_DESC_IN_SKB;
+       skbdesc->desc = entry->skb->data;
        skbdesc->desc_len = TXWI_DESC_SIZE;
 
        /*
         * Add the TXWI for the beacon to the skb.
         */
-       rt2800_write_txwi(entry->skb, txdesc);
+       rt2800_write_txwi((__le32 *)entry->skb->data, txdesc);
 
        /*
         * Dump beacon to userspace through debugfs.
         */
        rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
 
-       /*
-        * Adjust skb to take TXWI into account.
-        */
-       skb_push(entry->skb, TXWI_DESC_SIZE);
-
        /*
         * Write entire beacon with TXWI to register.
         */
@@ -888,8 +890,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
 
                /* Check if we got a match by looking at WCID/ACK/PID
                 * fields */
-               txwi = (__le32 *)(entry->skb->data -
-                                 rt2x00dev->ops->extra_tx_headroom);
+               txwi = (__le32 *) entry->skb->data;
 
                rt2x00_desc_read(txwi, 1, &word);
                tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
@@ -934,7 +935,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
                __set_bit(TXDONE_FALLBACK, &txdesc.flags);
 
 
-               rt2x00lib_txdone(entry, &txdesc);
+               rt2x00pci_txdone(entry, &txdesc);
        }
 }
 
index d0d8060040baece5709f36a47ed742a580ce33e6..ee407f1387537a89874db1a4d333be2e574dd6c1 100644 (file)
@@ -400,13 +400,14 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txi = (__le32 *)(skb->data - TXWI_DESC_SIZE - TXINFO_DESC_SIZE);
+       __le32 *txi = (__le32 *) skb->data;
+       __le32 *txwi = (__le32 *) (skb->data + TXINFO_DESC_SIZE);
        u32 word;
 
        /*
         * Initialize TXWI descriptor
         */
-       rt2800_write_txwi(skb, txdesc);
+       rt2800_write_txwi(txwi, txdesc);
 
        /*
         * Initialize TXINFO descriptor
@@ -426,6 +427,7 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        /*
         * Register descriptor details in skb frame descriptor.
         */
+       skbdesc->flags |= SKBDESC_DESC_IN_SKB;
        skbdesc->desc = txi;
        skbdesc->desc_len = TXINFO_DESC_SIZE + TXWI_DESC_SIZE;
 }
@@ -449,27 +451,29 @@ static void rt2800usb_write_beacon(struct queue_entry *entry,
        rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
        rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 
+       /*
+        * Add space for the TXWI in front of the skb.
+        */
+       skb_push(entry->skb, TXWI_DESC_SIZE);
+       memset(entry->skb, 0, TXWI_DESC_SIZE);
+
        /*
         * Register descriptor details in skb frame descriptor.
         */
-       skbdesc->desc = entry->skb->data - TXWI_DESC_SIZE;
+       skbdesc->flags |= SKBDESC_DESC_IN_SKB;
+       skbdesc->desc = entry->skb->data;
        skbdesc->desc_len = TXWI_DESC_SIZE;
 
        /*
         * Add the TXWI for the beacon to the skb.
         */
-       rt2800_write_txwi(entry->skb, txdesc);
+       rt2800_write_txwi((__le32 *) entry->skb->data, txdesc);
 
        /*
         * Dump beacon to userspace through debugfs.
         */
        rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
 
-       /*
-        * Adjust skb to take TXWI into account.
-        */
-       skb_push(entry->skb, TXWI_DESC_SIZE);
-
        /*
         * Write entire beacon with descriptor to register.
         */
index 811844be00530a4adb2450c0ea4753150d5770ce..889a372367f618724a5245ae3c8977250ce6dab0 100644 (file)
@@ -1001,6 +1001,13 @@ static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev)
  */
 void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
 
+/**
+ * rt2x00queue_unmap_skb - Unmap a skb from DMA.
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @skb: The skb to unmap.
+ */
+void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
+
 /**
  * rt2x00queue_get_queue - Convert queue index to queue pointer
  * @rt2x00dev: Pointer to &struct rt2x00_dev.
index 2ed32e02a06fb846bc7532d09835f223ac03a5dc..0b8efe8e678557b67dcca1d1df16fec4a0ade537 100644 (file)
@@ -210,11 +210,6 @@ void rt2x00lib_txdone(struct queue_entry *entry,
        unsigned int i;
        bool success;
 
-       /*
-        * Unmap the skb.
-        */
-       rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
-
        /*
         * Remove L2 padding which was added during
         */
index 0ca40e1fe699bfa09bcf07d3fd6d8c0f30f35aee..822affc9b4cad91201064fbd1bdf68d771de8944 100644 (file)
@@ -104,13 +104,6 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
 struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
                                        struct queue_entry *entry);
 
-/**
- * rt2x00queue_unmap_skb - Unmap a skb from DMA.
- * @rt2x00dev: Pointer to &struct rt2x00_dev.
- * @skb: The skb to unmap.
- */
-void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
-
 /**
  * rt2x00queue_free_skb - free a skb
  * @rt2x00dev: Pointer to &struct rt2x00_dev.
index 494b960e811ce8837c4a10058c4061177ced0b11..d583ee070b47cc16b53be46a6df8f13fa5b7c74a 100644 (file)
@@ -81,12 +81,24 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry,
                return -EINVAL;
        }
 
+       /*
+        * Add the requested extra tx headroom in front of the skb.
+        */
+       skb_push(entry->skb, rt2x00dev->ops->extra_tx_headroom);
+       memset(entry->skb->data, 0, rt2x00dev->ops->extra_tx_headroom);
+
        /*
         * Call the driver's write_tx_datadesc function, if it exists.
         */
        if (rt2x00dev->ops->lib->write_tx_datadesc)
                rt2x00dev->ops->lib->write_tx_datadesc(entry, txdesc);
 
+       /*
+        * Map the skb to DMA.
+        */
+       if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags))
+               rt2x00queue_map_txskb(rt2x00dev, entry->skb);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
@@ -94,6 +106,34 @@ EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
 /*
  * TX/RX data handlers.
  */
+void rt2x00pci_txdone(struct queue_entry *entry,
+                     struct txdone_entry_desc *txdesc)
+{
+       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+
+       /*
+        * Unmap the skb.
+        */
+       rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
+
+       /*
+        * Remove the extra tx headroom from the skb.
+        */
+       skb_pull(entry->skb, rt2x00dev->ops->extra_tx_headroom);
+
+       /*
+        * Signal that the TX descriptor is no longer in the skb.
+        */
+       skbdesc->flags &= ~SKBDESC_DESC_IN_SKB;
+
+       /*
+        * Pass on to rt2x00lib.
+        */
+       rt2x00lib_txdone(entry, txdesc);
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_txdone);
+
 void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
 {
        struct data_queue *queue = rt2x00dev->rx;
index 51bcef3839ce3ae52fe00974de87d0978f43ef4f..00528b8a754daf166f084c7d676fdf9ee1ab5b7c 100644 (file)
@@ -108,6 +108,14 @@ struct queue_entry_priv_pci {
        dma_addr_t desc_dma;
 };
 
+/**
+ * rt2x00pci_txdone - Handle TX done events.
+ * @entry: The queue entry for which a TX done event was received.
+ * @txdesc: The TX done descriptor for the entry.
+ */
+void rt2x00pci_txdone(struct queue_entry *entry,
+                     struct txdone_entry_desc *txdesc);
+
 /**
  * rt2x00pci_rxdone - Handle RX done events
  * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
index cf7bfe774e004c23bbce9e31e119ec61457c0946..35858b178e8f81725cf8c7550d59e0d06c03f30d 100644 (file)
@@ -100,21 +100,8 @@ void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
 
-       /*
-        * If device has requested headroom, we should make sure that
-        * is also mapped to the DMA so it can be used for transfering
-        * additional descriptor information to the hardware.
-        */
-       skb_push(skb, rt2x00dev->ops->extra_tx_headroom);
-
        skbdesc->skb_dma =
            dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE);
-
-       /*
-        * Restore data pointer to original location again.
-        */
-       skb_pull(skb, rt2x00dev->ops->extra_tx_headroom);
-
        skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
 }
 EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
@@ -130,16 +117,12 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
        }
 
        if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) {
-               /*
-                * Add headroom to the skb length, it has been removed
-                * by the driver, but it was actually mapped to DMA.
-                */
-               dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma,
-                                skb->len + rt2x00dev->ops->extra_tx_headroom,
+               dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
                                 DMA_TO_DEVICE);
                skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX;
        }
 }
+EXPORT_SYMBOL_GPL(rt2x00queue_unmap_skb);
 
 void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
 {
@@ -534,9 +517,6 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
                return -EIO;
        }
 
-       if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
-               rt2x00queue_map_txskb(queue->rt2x00dev, skb);
-
        set_bit(ENTRY_DATA_PENDING, &entry->flags);
 
        rt2x00queue_index_inc(queue, Q_INDEX);
index 25cc376d388e7e29f0cfee708e7588d6ae8c6e47..5e123519f8cb589bb5d4292374cf3522059282ff 100644 (file)
@@ -197,6 +197,11 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
            !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
                return;
 
+       /*
+        * Remove the descriptor from the front of the skb.
+        */
+       skb_pull(entry->skb, entry->queue->desc_size);
+
        /*
         * Obtain the status about this packet.
         * Note that when the status is 0 it does not mean the
@@ -242,12 +247,6 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry,
                          entry->skb->data, length,
                          rt2x00usb_interrupt_txdone, entry);
 
-       /*
-        * Make sure the skb->data pointer points to the frame, not the
-        * descriptor.
-        */
-       skb_pull(entry->skb, entry->queue->desc_size);
-
        /*
         * Call the driver's write_tx_datadesc function, if it exists.
         */
index a7205c1711de2e012aa7b0576807e66820541543..243df08ae91049ab97c26d35470d560986f2cbcb 100644 (file)
@@ -2110,7 +2110,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
                        __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
                        txdesc.retry = 0;
 
-                       rt2x00lib_txdone(entry_done, &txdesc);
+                       rt2x00pci_txdone(entry_done, &txdesc);
                        entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
                }
 
@@ -2130,7 +2130,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
                }
                txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
 
-               rt2x00lib_txdone(entry, &txdesc);
+               rt2x00pci_txdone(entry, &txdesc);
        }
 }
 
index bd9a53e5fd9fc4f2808a0e60663804d8bd1d3be2..4ab38c3641cc020699a97c3c0234d6484a9728a1 100644 (file)
@@ -1442,7 +1442,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                  struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txd = (__le32 *)(skb->data - TXD_DESC_SIZE);
+       __le32 *txd = (__le32 *) skb->data;
        u32 word;
 
        /*
@@ -1505,6 +1505,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        /*
         * Register descriptor details in skb frame descriptor.
         */
+       skbdesc->flags |= SKBDESC_DESC_IN_SKB;
        skbdesc->desc = txd;
        skbdesc->desc_len = TXD_DESC_SIZE;
 }
@@ -1527,6 +1528,12 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
        rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
        rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 
+       /*
+        * Add space for the descriptor in front of the skb.
+        */
+       skb_push(entry->skb, TXD_DESC_SIZE);
+       memset(entry->skb->data, 0, TXD_DESC_SIZE);
+
        /*
         * Write the TX descriptor for the beacon.
         */
@@ -1537,11 +1544,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
         */
        rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
 
-       /*
-        * Take the descriptor in front of the skb into account.
-        */
-       skb_push(entry->skb, TXD_DESC_SIZE);
-
        /*
         * Write entire beacon with descriptor to register.
         */