aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJussi Kivilinna <jussi.kivilinna@mbnet.fi>2013-02-18 03:29:30 -0500
committerJohn W. Linville <linville@tuxdriver.com>2013-02-18 15:30:40 -0500
commitbc6b89237acb3dee6af6e64e51a18255fef89cc2 (patch)
tree7a9d124856f3e1792c6e2272ad6c1464e3ffc705
parenta5f390562a375a315292648e2da865a12b42f280 (diff)
rtlwifi: usb: allocate URB control message setup_packet and data buffer separately
rtlwifi allocates both setup_packet and data buffer of control message urb, using shared kmalloc in _usbctrl_vendorreq_async_write. Structure used for allocating is: struct { u8 data[254]; struct usb_ctrlrequest dr; }; Because 'struct usb_ctrlrequest' is __packed, setup packet is unaligned and DMA mapping of both 'data' and 'dr' confuses ARM/sunxi, leading to memory corruptions and freezes. Patch changes setup packet to be allocated separately. [v2]: - Use WARN_ON_ONCE instead of WARN_ON Cc: <stable@vger.kernel.org> Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/rtlwifi/usb.c44
1 files changed, 28 insertions, 16 deletions
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c
index 476eaef5e4a9..156b52732f3d 100644
--- a/drivers/net/wireless/rtlwifi/usb.c
+++ b/drivers/net/wireless/rtlwifi/usb.c
@@ -42,8 +42,12 @@
42 42
43static void usbctrl_async_callback(struct urb *urb) 43static void usbctrl_async_callback(struct urb *urb)
44{ 44{
45 if (urb) 45 if (urb) {
46 kfree(urb->context); 46 /* free dr */
47 kfree(urb->setup_packet);
48 /* free databuf */
49 kfree(urb->transfer_buffer);
50 }
47} 51}
48 52
49static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request, 53static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
@@ -55,39 +59,47 @@ static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
55 u8 reqtype; 59 u8 reqtype;
56 struct usb_ctrlrequest *dr; 60 struct usb_ctrlrequest *dr;
57 struct urb *urb; 61 struct urb *urb;
58 struct rtl819x_async_write_data { 62 const u16 databuf_maxlen = REALTEK_USB_VENQT_MAX_BUF_SIZE;
59 u8 data[REALTEK_USB_VENQT_MAX_BUF_SIZE]; 63 u8 *databuf;
60 struct usb_ctrlrequest dr; 64
61 } *buf; 65 if (WARN_ON_ONCE(len > databuf_maxlen))
66 len = databuf_maxlen;
62 67
63 pipe = usb_sndctrlpipe(udev, 0); /* write_out */ 68 pipe = usb_sndctrlpipe(udev, 0); /* write_out */
64 reqtype = REALTEK_USB_VENQT_WRITE; 69 reqtype = REALTEK_USB_VENQT_WRITE;
65 70
66 buf = kmalloc(sizeof(*buf), GFP_ATOMIC); 71 dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
67 if (!buf) 72 if (!dr)
68 return -ENOMEM; 73 return -ENOMEM;
69 74
75 databuf = kmalloc(databuf_maxlen, GFP_ATOMIC);
76 if (!databuf) {
77 kfree(dr);
78 return -ENOMEM;
79 }
80
70 urb = usb_alloc_urb(0, GFP_ATOMIC); 81 urb = usb_alloc_urb(0, GFP_ATOMIC);
71 if (!urb) { 82 if (!urb) {
72 kfree(buf); 83 kfree(databuf);
84 kfree(dr);
73 return -ENOMEM; 85 return -ENOMEM;
74 } 86 }
75 87
76 dr = &buf->dr;
77
78 dr->bRequestType = reqtype; 88 dr->bRequestType = reqtype;
79 dr->bRequest = request; 89 dr->bRequest = request;
80 dr->wValue = cpu_to_le16(value); 90 dr->wValue = cpu_to_le16(value);
81 dr->wIndex = cpu_to_le16(index); 91 dr->wIndex = cpu_to_le16(index);
82 dr->wLength = cpu_to_le16(len); 92 dr->wLength = cpu_to_le16(len);
83 /* data are already in little-endian order */ 93 /* data are already in little-endian order */
84 memcpy(buf, pdata, len); 94 memcpy(databuf, pdata, len);
85 usb_fill_control_urb(urb, udev, pipe, 95 usb_fill_control_urb(urb, udev, pipe,
86 (unsigned char *)dr, buf, len, 96 (unsigned char *)dr, databuf, len,
87 usbctrl_async_callback, buf); 97 usbctrl_async_callback, NULL);
88 rc = usb_submit_urb(urb, GFP_ATOMIC); 98 rc = usb_submit_urb(urb, GFP_ATOMIC);
89 if (rc < 0) 99 if (rc < 0) {
90 kfree(buf); 100 kfree(databuf);
101 kfree(dr);
102 }
91 usb_free_urb(urb); 103 usb_free_urb(urb);
92 return rc; 104 return rc;
93} 105}