mirror of https://gitee.com/openkylin/linux.git
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>
This commit is contained in:
parent
a5f390562a
commit
bc6b89237a
|
@ -42,8 +42,12 @@
|
|||
|
||||
static void usbctrl_async_callback(struct urb *urb)
|
||||
{
|
||||
if (urb)
|
||||
kfree(urb->context);
|
||||
if (urb) {
|
||||
/* free dr */
|
||||
kfree(urb->setup_packet);
|
||||
/* free databuf */
|
||||
kfree(urb->transfer_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
|
||||
|
@ -55,25 +59,31 @@ static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
|
|||
u8 reqtype;
|
||||
struct usb_ctrlrequest *dr;
|
||||
struct urb *urb;
|
||||
struct rtl819x_async_write_data {
|
||||
u8 data[REALTEK_USB_VENQT_MAX_BUF_SIZE];
|
||||
struct usb_ctrlrequest dr;
|
||||
} *buf;
|
||||
const u16 databuf_maxlen = REALTEK_USB_VENQT_MAX_BUF_SIZE;
|
||||
u8 *databuf;
|
||||
|
||||
if (WARN_ON_ONCE(len > databuf_maxlen))
|
||||
len = databuf_maxlen;
|
||||
|
||||
pipe = usb_sndctrlpipe(udev, 0); /* write_out */
|
||||
reqtype = REALTEK_USB_VENQT_WRITE;
|
||||
|
||||
buf = kmalloc(sizeof(*buf), GFP_ATOMIC);
|
||||
if (!buf)
|
||||
dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
|
||||
if (!dr)
|
||||
return -ENOMEM;
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!urb) {
|
||||
kfree(buf);
|
||||
databuf = kmalloc(databuf_maxlen, GFP_ATOMIC);
|
||||
if (!databuf) {
|
||||
kfree(dr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dr = &buf->dr;
|
||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!urb) {
|
||||
kfree(databuf);
|
||||
kfree(dr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dr->bRequestType = reqtype;
|
||||
dr->bRequest = request;
|
||||
|
@ -81,13 +91,15 @@ static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
|
|||
dr->wIndex = cpu_to_le16(index);
|
||||
dr->wLength = cpu_to_le16(len);
|
||||
/* data are already in little-endian order */
|
||||
memcpy(buf, pdata, len);
|
||||
memcpy(databuf, pdata, len);
|
||||
usb_fill_control_urb(urb, udev, pipe,
|
||||
(unsigned char *)dr, buf, len,
|
||||
usbctrl_async_callback, buf);
|
||||
(unsigned char *)dr, databuf, len,
|
||||
usbctrl_async_callback, NULL);
|
||||
rc = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (rc < 0)
|
||||
kfree(buf);
|
||||
if (rc < 0) {
|
||||
kfree(databuf);
|
||||
kfree(dr);
|
||||
}
|
||||
usb_free_urb(urb);
|
||||
return rc;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue