aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvo van Doorn <ivdoorn@gmail.com>2007-11-27 15:49:29 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:05:08 -0500
commit4d8dd66c1659ba0d1b110ed0488f4f6ffbc90e71 (patch)
tree03ae5e8fc993ec504f099ddb5d1f40f3a371289d
parent08992f7fb139c7dbaf593402312ee5a055352f05 (diff)
rt2x00: Add TX/RX frame dumping facility
This adds TX/RX frame dumping capabilities through debugfs. The intention is that with this approach debugging of rt2x00 is simplified since _all_ frames going in and out of the device are send to debugfs as well along with additional information like the hardware descriptor. Based on the patch by Mattias Nissler. Mattias also has some tools that will make the dumped frames available to wireshark: http://www-user.rhrk.uni-kl.de/~nissler/rt2x00/ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c182
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c20
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dump.h121
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h6
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c6
7 files changed, 337 insertions, 10 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 31e48c25a692..ba874cff8648 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -623,7 +623,7 @@ struct rt2x00_dev {
623 * required for deregistration of debugfs. 623 * required for deregistration of debugfs.
624 */ 624 */
625#ifdef CONFIG_RT2X00_LIB_DEBUGFS 625#ifdef CONFIG_RT2X00_LIB_DEBUGFS
626 const struct rt2x00debug_intf *debugfs_intf; 626 struct rt2x00debug_intf *debugfs_intf;
627#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ 627#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
628 628
629 /* 629 /*
@@ -791,6 +791,12 @@ struct rt2x00_dev {
791 ring_loop(__entry, (__dev)->tx, ring_end(__dev)) 791 ring_loop(__entry, (__dev)->tx, ring_end(__dev))
792 792
793/* 793/*
794 * Compute an array index from a pointer to an element and the base pointer.
795 */
796#define ARRAY_INDEX(__elem, __base) \
797 ( ((char *)(__elem) - (char *)(__base)) / sizeof(*(__elem)) )
798
799/*
794 * Generic RF access. 800 * Generic RF access.
795 * The RF is being accessed by word index. 801 * The RF is being accessed by word index.
796 */ 802 */
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 3aa7e0ab513b..e72c98133c05 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -26,10 +26,12 @@
26#include <linux/debugfs.h> 26#include <linux/debugfs.h>
27#include <linux/kernel.h> 27#include <linux/kernel.h>
28#include <linux/module.h> 28#include <linux/module.h>
29#include <linux/poll.h>
29#include <linux/uaccess.h> 30#include <linux/uaccess.h>
30 31
31#include "rt2x00.h" 32#include "rt2x00.h"
32#include "rt2x00lib.h" 33#include "rt2x00lib.h"
34#include "rt2x00dump.h"
33 35
34#define PRINT_LINE_LEN_MAX 32 36#define PRINT_LINE_LEN_MAX 32
35 37
@@ -58,6 +60,8 @@ struct rt2x00debug_intf {
58 * - eeprom offset/value files 60 * - eeprom offset/value files
59 * - bbp offset/value files 61 * - bbp offset/value files
60 * - rf offset/value files 62 * - rf offset/value files
63 * - frame dump folder
64 * - frame dump file
61 */ 65 */
62 struct dentry *driver_folder; 66 struct dentry *driver_folder;
63 struct dentry *driver_entry; 67 struct dentry *driver_entry;
@@ -72,6 +76,24 @@ struct rt2x00debug_intf {
72 struct dentry *bbp_val_entry; 76 struct dentry *bbp_val_entry;
73 struct dentry *rf_off_entry; 77 struct dentry *rf_off_entry;
74 struct dentry *rf_val_entry; 78 struct dentry *rf_val_entry;
79 struct dentry *frame_folder;
80 struct dentry *frame_dump_entry;
81
82 /*
83 * The frame dump file only allows a single reader,
84 * so we need to store the current state here.
85 */
86 unsigned long frame_dump_flags;
87#define FRAME_DUMP_FILE_OPEN 1
88
89 /*
90 * We queue each frame before dumping it to the user,
91 * per read command we will pass a single skb structure
92 * so we should be prepared to queue multiple sk buffers
93 * before sending it to userspace.
94 */
95 struct sk_buff_head frame_dump_skbqueue;
96 wait_queue_head_t frame_dump_waitqueue;
75 97
76 /* 98 /*
77 * Driver and chipset files will use a data buffer 99 * Driver and chipset files will use a data buffer
@@ -90,6 +112,63 @@ struct rt2x00debug_intf {
90 unsigned int offset_rf; 112 unsigned int offset_rf;
91}; 113};
92 114
115void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
116 struct sk_buff *skb)
117{
118 struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
119 struct skb_desc *desc = get_skb_desc(skb);
120 struct sk_buff *skbcopy;
121 struct rt2x00dump_hdr *dump_hdr;
122 struct timeval timestamp;
123 unsigned int ring_index;
124 unsigned int entry_index;
125
126 do_gettimeofday(&timestamp);
127 ring_index = ARRAY_INDEX(desc->ring, rt2x00dev->rx);
128 entry_index = ARRAY_INDEX(desc->entry, desc->ring->entry);
129
130 if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags))
131 return;
132
133 if (skb_queue_len(&intf->frame_dump_skbqueue) > 20) {
134 DEBUG(rt2x00dev, "txrx dump queue length exceeded.\n");
135 return;
136 }
137
138 skbcopy = alloc_skb(sizeof(*dump_hdr) + desc->desc_len + desc->data_len,
139 GFP_ATOMIC);
140 if (!skbcopy) {
141 DEBUG(rt2x00dev, "Failed to copy skb for dump.\n");
142 return;
143 }
144
145 dump_hdr = (struct rt2x00dump_hdr *)skb_put(skbcopy, sizeof(*dump_hdr));
146 dump_hdr->version = cpu_to_le32(DUMP_HEADER_VERSION);
147 dump_hdr->header_length = cpu_to_le32(sizeof(*dump_hdr));
148 dump_hdr->desc_length = cpu_to_le32(desc->desc_len);
149 dump_hdr->data_length = cpu_to_le32(desc->data_len);
150 dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt);
151 dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf);
152 dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev);
153 dump_hdr->type = cpu_to_le16(desc->frame_type);
154 dump_hdr->ring_index = ring_index;
155 dump_hdr->entry_index = entry_index;
156 dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec);
157 dump_hdr->timestamp_usec = cpu_to_le32(timestamp.tv_usec);
158
159 memcpy(skb_put(skbcopy, desc->desc_len), desc->desc, desc->desc_len);
160 memcpy(skb_put(skbcopy, desc->data_len), desc->data, desc->data_len);
161
162 skb_queue_tail(&intf->frame_dump_skbqueue, skbcopy);
163 wake_up_interruptible(&intf->frame_dump_waitqueue);
164
165 /*
166 * Verify that the file has not been closed while we were working.
167 */
168 if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags))
169 skb_queue_purge(&intf->frame_dump_skbqueue);
170}
171
93static int rt2x00debug_file_open(struct inode *inode, struct file *file) 172static int rt2x00debug_file_open(struct inode *inode, struct file *file)
94{ 173{
95 struct rt2x00debug_intf *intf = inode->i_private; 174 struct rt2x00debug_intf *intf = inode->i_private;
@@ -111,6 +190,89 @@ static int rt2x00debug_file_release(struct inode *inode, struct file *file)
111 return 0; 190 return 0;
112} 191}
113 192
193static int rt2x00debug_open_ring_dump(struct inode *inode, struct file *file)
194{
195 struct rt2x00debug_intf *intf = inode->i_private;
196 int retval;
197
198 retval = rt2x00debug_file_open(inode, file);
199 if (retval)
200 return retval;
201
202 if (test_and_set_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags)) {
203 rt2x00debug_file_release(inode, file);
204 return -EBUSY;
205 }
206
207 return 0;
208}
209
210static int rt2x00debug_release_ring_dump(struct inode *inode, struct file *file)
211{
212 struct rt2x00debug_intf *intf = inode->i_private;
213
214 skb_queue_purge(&intf->frame_dump_skbqueue);
215
216 clear_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags);
217
218 return rt2x00debug_file_release(inode, file);
219}
220
221static ssize_t rt2x00debug_read_ring_dump(struct file *file,
222 char __user *buf,
223 size_t length,
224 loff_t *offset)
225{
226 struct rt2x00debug_intf *intf = file->private_data;
227 struct sk_buff *skb;
228 size_t status;
229 int retval;
230
231 if (file->f_flags & O_NONBLOCK)
232 return -EAGAIN;
233
234 retval =
235 wait_event_interruptible(intf->frame_dump_waitqueue,
236 (skb =
237 skb_dequeue(&intf->frame_dump_skbqueue)));
238 if (retval)
239 return retval;
240
241 status = min((size_t)skb->len, length);
242 if (copy_to_user(buf, skb->data, status)) {
243 status = -EFAULT;
244 goto exit;
245 }
246
247 *offset += status;
248
249exit:
250 kfree_skb(skb);
251
252 return status;
253}
254
255static unsigned int rt2x00debug_poll_ring_dump(struct file *file,
256 poll_table *wait)
257{
258 struct rt2x00debug_intf *intf = file->private_data;
259
260 poll_wait(file, &intf->frame_dump_waitqueue, wait);
261
262 if (!skb_queue_empty(&intf->frame_dump_skbqueue))
263 return POLLOUT | POLLWRNORM;
264
265 return 0;
266}
267
268static const struct file_operations rt2x00debug_fop_ring_dump = {
269 .owner = THIS_MODULE,
270 .read = rt2x00debug_read_ring_dump,
271 .poll = rt2x00debug_poll_ring_dump,
272 .open = rt2x00debug_open_ring_dump,
273 .release = rt2x00debug_release_ring_dump,
274};
275
114#define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \ 276#define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \
115static ssize_t rt2x00debug_read_##__name(struct file *file, \ 277static ssize_t rt2x00debug_read_##__name(struct file *file, \
116 char __user *buf, \ 278 char __user *buf, \
@@ -339,6 +501,20 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
339 501
340#undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY 502#undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY
341 503
504 intf->frame_folder =
505 debugfs_create_dir("frame", intf->driver_folder);
506 if (IS_ERR(intf->frame_folder))
507 goto exit;
508
509 intf->frame_dump_entry =
510 debugfs_create_file("dump", S_IRUGO, intf->frame_folder,
511 intf, &rt2x00debug_fop_ring_dump);
512 if (IS_ERR(intf->frame_dump_entry))
513 goto exit;
514
515 skb_queue_head_init(&intf->frame_dump_skbqueue);
516 init_waitqueue_head(&intf->frame_dump_waitqueue);
517
342 return; 518 return;
343 519
344exit: 520exit:
@@ -350,11 +526,15 @@ exit:
350 526
351void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) 527void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
352{ 528{
353 const struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf; 529 struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
354 530
355 if (unlikely(!intf)) 531 if (unlikely(!intf))
356 return; 532 return;
357 533
534 skb_queue_purge(&intf->frame_dump_skbqueue);
535
536 debugfs_remove(intf->frame_dump_entry);
537 debugfs_remove(intf->frame_folder);
358 debugfs_remove(intf->rf_val_entry); 538 debugfs_remove(intf->rf_val_entry);
359 debugfs_remove(intf->rf_off_entry); 539 debugfs_remove(intf->rf_off_entry);
360 debugfs_remove(intf->bbp_val_entry); 540 debugfs_remove(intf->bbp_val_entry);
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 4f32ee8f4cb7..48e251561f83 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -28,6 +28,7 @@
28 28
29#include "rt2x00.h" 29#include "rt2x00.h"
30#include "rt2x00lib.h" 30#include "rt2x00lib.h"
31#include "rt2x00dump.h"
31 32
32/* 33/*
33 * Ring handler. 34 * Ring handler.
@@ -511,9 +512,11 @@ void rt2x00lib_txdone(struct data_entry *entry,
511 } 512 }
512 513
513 /* 514 /*
514 * Send the tx_status to mac80211, 515 * Send the tx_status to mac80211 & debugfs.
515 * that method also cleans up the skb structure. 516 * mac80211 will clean up the skb structure.
516 */ 517 */
518 get_skb_desc(entry->skb)->frame_type = DUMP_FRAME_TXDONE;
519 rt2x00debug_dump_frame(rt2x00dev, entry->skb);
517 ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb, tx_status); 520 ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb, tx_status);
518 entry->skb = NULL; 521 entry->skb = NULL;
519} 522}
@@ -563,8 +566,10 @@ void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb,
563 rx_status->antenna = rt2x00dev->link.ant.active.rx; 566 rx_status->antenna = rt2x00dev->link.ant.active.rx;
564 567
565 /* 568 /*
566 * Send frame to mac80211 569 * Send frame to mac80211 & debugfs
567 */ 570 */
571 get_skb_desc(skb)->frame_type = DUMP_FRAME_RXDONE;
572 rt2x00debug_dump_frame(rt2x00dev, skb);
568 ieee80211_rx_irqsafe(rt2x00dev->hw, skb, rx_status); 573 ieee80211_rx_irqsafe(rt2x00dev->hw, skb, rx_status);
569} 574}
570EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); 575EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
@@ -715,6 +720,15 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
715 */ 720 */
716 skbdesc->entry->skb = skb; 721 skbdesc->entry->skb = skb;
717 memcpy(&skbdesc->entry->tx_status.control, control, sizeof(*control)); 722 memcpy(&skbdesc->entry->tx_status.control, control, sizeof(*control));
723
724 /*
725 * The frame has been completely initialized and ready
726 * for sending to the device. The caller will push the
727 * frame to the device, but we are going to push the
728 * frame to debugfs here.
729 */
730 skbdesc->frame_type = DUMP_FRAME_TX;
731 rt2x00debug_dump_frame(rt2x00dev, skb);
718} 732}
719EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc); 733EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc);
720 734
diff --git a/drivers/net/wireless/rt2x00/rt2x00dump.h b/drivers/net/wireless/rt2x00/rt2x00dump.h
new file mode 100644
index 000000000000..99f3f367adce
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00dump.h
@@ -0,0 +1,121 @@
1/*
2 Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
3 <http://rt2x00.serialmonkey.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the
17 Free Software Foundation, Inc.,
18 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21/*
22 Module: rt2x00dump
23 Abstract: Data structures for the rt2x00debug & userspace.
24 */
25
26#ifndef RT2X00DUMP_H
27#define RT2X00DUMP_H
28
29/**
30 * DOC: Introduction
31 *
32 * This header is intended to be exported to userspace,
33 * to make the structures and enumerations available to userspace
34 * applications. This means that all data types should be exportable.
35 *
36 * When rt2x00 is compiled with debugfs support enabled,
37 * it is possible to capture all data coming in and out of the device
38 * by reading the frame dump file. This file can have only a single reader.
39 * The following frames will be reported:
40 * - All incoming frames (rx)
41 * - All outgoing frames (tx, including beacon and atim)
42 * - All completed frames (txdone including atim)
43 *
44 * The data is send to the file using the following format:
45 *
46 * [rt2x00dump header][hardware descriptor][ieee802.11 frame]
47 *
48 * rt2x00dump header: The description of the dumped frame, as well as
49 * additional information usefull for debugging. See &rt2x00dump_hdr.
50 * hardware descriptor: Descriptor that was used to receive or transmit
51 * the frame.
52 * ieee802.11 frame: The actual frame that was received or transmitted.
53 */
54
55/**
56 * enum rt2x00_dump_type - Frame type
57 *
58 * These values are used for the @type member of &rt2x00dump_hdr.
59 * @DUMP_FRAME_RXDONE: This frame has been received by the hardware.
60 * @DUMP_FRAME_TX: This frame is queued for transmission to the hardware.
61 * @DUMP_FRAME_TXDONE: This frame indicates the device has handled
62 * the tx event which has either succeeded or failed. A frame
63 * with this type should also have been reported with as a
64 * %DUMP_FRAME_TX frame.
65 */
66enum rt2x00_dump_type {
67 DUMP_FRAME_RXDONE = 1,
68 DUMP_FRAME_TX = 2,
69 DUMP_FRAME_TXDONE = 3,
70};
71
72/**
73 * struct rt2x00dump_hdr - Dump frame header
74 *
75 * Each frame dumped to the debugfs file starts with this header
76 * attached. This header contains the description of the actual
77 * frame which was dumped.
78 *
79 * New fields inside the structure must be appended to the end of
80 * the structure. This way userspace tools compiled for earlier
81 * header versions can still correctly handle the frame dump
82 * (although they will not handle all data passed to them in the dump).
83 *
84 * @version: Header version should always be set to %DUMP_HEADER_VERSION.
85 * This field must be checked by userspace to determine if it can
86 * handle this frame.
87 * @header_length: The length of the &rt2x00dump_hdr structure. This is
88 * used for compatibility reasons so userspace can easily determine
89 * the location of the next field in the dump.
90 * @desc_length: The length of the device descriptor.
91 * @data_length: The length of the frame data (including the ieee802.11 header.
92 * @chip_rt: RT chipset
93 * @chip_rf: RF chipset
94 * @chip_rev: Chipset revision
95 * @type: The frame type (&rt2x00_dump_type)
96 * @ring_index: The index number of the data ring.
97 * @entry_index: The index number of the entry inside the data ring.
98 * @timestamp_sec: Timestamp - seconds
99 * @timestamp_usec: Timestamp - microseconds
100 */
101struct rt2x00dump_hdr {
102 __le32 version;
103#define DUMP_HEADER_VERSION 2
104
105 __le32 header_length;
106 __le32 desc_length;
107 __le32 data_length;
108
109 __le16 chip_rt;
110 __le16 chip_rf;
111 __le32 chip_rev;
112
113 __le16 type;
114 __u8 ring_index;
115 __u8 entry_index;
116
117 __le32 timestamp_sec;
118 __le32 timestamp_usec;
119};
120
121#endif /* RT2X00DUMP_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 73194112f45c..0bf10ffec70a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -80,6 +80,7 @@ static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
80#ifdef CONFIG_RT2X00_LIB_DEBUGFS 80#ifdef CONFIG_RT2X00_LIB_DEBUGFS
81void rt2x00debug_register(struct rt2x00_dev *rt2x00dev); 81void rt2x00debug_register(struct rt2x00_dev *rt2x00dev);
82void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev); 82void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
83void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
83#else 84#else
84static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) 85static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
85{ 86{
@@ -88,6 +89,11 @@ static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
88static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) 89static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
89{ 90{
90} 91}
92
93static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
94 struct skb_buff *skb)
95{
96}
91#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ 97#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
92 98
93/* 99/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index c1d7c10e58fe..483380819f9d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -178,8 +178,8 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
178 * Fill in skb descriptor 178 * Fill in skb descriptor
179 */ 179 */
180 skbdesc = get_skb_desc(skb); 180 skbdesc = get_skb_desc(skb);
181 skbdesc->desc_len = desc.size; 181 skbdesc->desc_len = entry->ring->desc_size;
182 skbdesc->data_len = entry->ring->desc_size; 182 skbdesc->data_len = skb->len;
183 skbdesc->desc = entry->priv; 183 skbdesc->desc = entry->priv;
184 skbdesc->data = skb->data; 184 skbdesc->data = skb->data;
185 skbdesc->ring = ring; 185 skbdesc->ring = ring;
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index fd6b61c97619..9778fae313ab 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -307,9 +307,9 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
307 * Fill in skb descriptor 307 * Fill in skb descriptor
308 */ 308 */
309 skbdesc = get_skb_desc(entry->skb); 309 skbdesc = get_skb_desc(entry->skb);
310 skbdesc->desc_len = desc.size; 310 skbdesc->desc_len = entry->ring->desc_size;
311 skbdesc->data_len = entry->ring->desc_size; 311 skbdesc->data_len = entry->skb->len;
312 skbdesc->desc = entry->skb->data + desc.size; 312 skbdesc->desc = entry->skb->data - skbdesc->desc_len;
313 skbdesc->data = entry->skb->data; 313 skbdesc->data = entry->skb->data;
314 skbdesc->ring = ring; 314 skbdesc->ring = ring;
315 skbdesc->entry = entry; 315 skbdesc->entry = entry;