Commit bc6b8923 authored by Jussi Kivilinna's avatar Jussi Kivilinna Committed by John W. Linville

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: default avatarJussi Kivilinna <jussi.kivilinna@mbnet.fi>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent a5f39056
...@@ -42,8 +42,12 @@ ...@@ -42,8 +42,12 @@
static void usbctrl_async_callback(struct urb *urb) static void usbctrl_async_callback(struct urb *urb)
{ {
if (urb) if (urb) {
kfree(urb->context); /* free dr */
kfree(urb->setup_packet);
/* free databuf */
kfree(urb->transfer_buffer);
}
} }
static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request, static 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,39 +59,47 @@ static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
u8 reqtype; u8 reqtype;
struct usb_ctrlrequest *dr; struct usb_ctrlrequest *dr;
struct urb *urb; struct urb *urb;
struct rtl819x_async_write_data { const u16 databuf_maxlen = REALTEK_USB_VENQT_MAX_BUF_SIZE;
u8 data[REALTEK_USB_VENQT_MAX_BUF_SIZE]; u8 *databuf;
struct usb_ctrlrequest dr;
} *buf; if (WARN_ON_ONCE(len > databuf_maxlen))
len = databuf_maxlen;
pipe = usb_sndctrlpipe(udev, 0); /* write_out */ pipe = usb_sndctrlpipe(udev, 0); /* write_out */
reqtype = REALTEK_USB_VENQT_WRITE; reqtype = REALTEK_USB_VENQT_WRITE;
buf = kmalloc(sizeof(*buf), GFP_ATOMIC); dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
if (!buf) if (!dr)
return -ENOMEM; return -ENOMEM;
databuf = kmalloc(databuf_maxlen, GFP_ATOMIC);
if (!databuf) {
kfree(dr);
return -ENOMEM;
}
urb = usb_alloc_urb(0, GFP_ATOMIC); urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) { if (!urb) {
kfree(buf); kfree(databuf);
kfree(dr);
return -ENOMEM; return -ENOMEM;
} }
dr = &buf->dr;
dr->bRequestType = reqtype; dr->bRequestType = reqtype;
dr->bRequest = request; dr->bRequest = request;
dr->wValue = cpu_to_le16(value); dr->wValue = cpu_to_le16(value);
dr->wIndex = cpu_to_le16(index); dr->wIndex = cpu_to_le16(index);
dr->wLength = cpu_to_le16(len); dr->wLength = cpu_to_le16(len);
/* data are already in little-endian order */ /* data are already in little-endian order */
memcpy(buf, pdata, len); memcpy(databuf, pdata, len);
usb_fill_control_urb(urb, udev, pipe, usb_fill_control_urb(urb, udev, pipe,
(unsigned char *)dr, buf, len, (unsigned char *)dr, databuf, len,
usbctrl_async_callback, buf); usbctrl_async_callback, NULL);
rc = usb_submit_urb(urb, GFP_ATOMIC); rc = usb_submit_urb(urb, GFP_ATOMIC);
if (rc < 0) if (rc < 0) {
kfree(buf); kfree(databuf);
kfree(dr);
}
usb_free_urb(urb); usb_free_urb(urb);
return rc; return rc;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment