diff --git a/kernel.spec b/kernel.spec index b709489..a90d5e1 100644 --- a/kernel.spec +++ b/kernel.spec @@ -673,6 +673,8 @@ Patch700: linux-2.6-e1000-ich9-montevina.patch Patch800: linux-2.6-crash-driver.patch +Patch1000: usb-wwan-ioctls.patch + # crypto/ # virt + ksm patches @@ -1453,6 +1455,9 @@ ApplyPatch create-sys-fs-cgroup-to-mount-cgroupfs-on.patch # /dev/crash driver. ApplyPatch linux-2.6-crash-driver.patch +# usb-wwan: implement TIOCGSERIAL and TIOCSSERIAL to avoid blocking close(2) +ApplyPatch usb-wwan-ioctls.patch + # Hack e1000e to work on Montevina SDV ApplyPatch linux-2.6-e1000-ich9-montevina.patch @@ -2265,6 +2270,9 @@ fi # and build. %changelog +* Tue Oct 11 2011 Dave Jones +- usb-wwan: implement TIOCGSERIAL and TIOCSSERIAL to avoid blocking close(2) + * Fri Sep 23 2011 Josh Boyer 2.6.35.14-98 - CVE-2011-1161 CVE-2011-1161: tpm: infoleaks diff --git a/usb-wwan-ioctls.patch b/usb-wwan-ioctls.patch new file mode 100644 index 0000000..d2e6f96 --- /dev/null +++ b/usb-wwan-ioctls.patch @@ -0,0 +1,136 @@ +commit 02303f73373aa1da19dbec510ec5a4e2576f9610 +Author: Dan Williams +Date: Fri Nov 19 16:04:00 2010 -0600 + + usb-wwan: implement TIOCGSERIAL and TIOCSSERIAL to avoid blocking close(2) + + Some devices (ex ZTE 2726) simply don't respond at all when data is sent + to some of their USB interfaces. The data gets stuck in the TTYs queue + and sits there until close(2), which them blocks because closing_wait + defaults to 30 seconds (even though the fd is O_NONBLOCK). This is + rarely desired. Implement the standard mechanism to adjust closing_wait + and let applications handle it how they want to. + + Signed-off-by: Dan Williams + +diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c +index 2297fb1..2a56cc3 100644 +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -989,6 +989,7 @@ static struct usb_serial_driver option_1port_device = { + .set_termios = usb_wwan_set_termios, + .tiocmget = usb_wwan_tiocmget, + .tiocmset = usb_wwan_tiocmset, ++ .ioctl = usb_wwan_ioctl, + .attach = usb_wwan_startup, + .disconnect = usb_wwan_disconnect, + .release = usb_wwan_release, +diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h +index 2be298a..3ab77c5 100644 +--- a/drivers/usb/serial/usb-wwan.h ++++ b/drivers/usb/serial/usb-wwan.h +@@ -18,6 +18,8 @@ extern void usb_wwan_set_termios(struct tty_struct *tty, + extern int usb_wwan_tiocmget(struct tty_struct *tty, struct file *file); + extern int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear); ++extern int usb_wwan_ioctl(struct tty_struct *tty, struct file *file, ++ unsigned int cmd, unsigned long arg); + extern int usb_wwan_send_setup(struct usb_serial_port *port); + extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count); +diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c +index fbc9467..660b7ca 100644 +--- a/drivers/usb/serial/usb_wwan.c ++++ b/drivers/usb/serial/usb_wwan.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include "usb-wwan.h" + + static int debug; +@@ -123,6 +124,83 @@ int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file, + } + EXPORT_SYMBOL(usb_wwan_tiocmset); + ++static int get_serial_info(struct usb_serial_port *port, ++ struct serial_struct __user *retinfo) ++{ ++ struct serial_struct tmp; ++ ++ if (!retinfo) ++ return -EFAULT; ++ ++ memset(&tmp, 0, sizeof(tmp)); ++ tmp.line = port->serial->minor; ++ tmp.port = port->number; ++ tmp.baud_base = tty_get_baud_rate(port->port.tty); ++ tmp.close_delay = port->port.close_delay / 10; ++ tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? ++ ASYNC_CLOSING_WAIT_NONE : ++ port->port.closing_wait / 10; ++ ++ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) ++ return -EFAULT; ++ return 0; ++} ++ ++static int set_serial_info(struct usb_serial_port *port, ++ struct serial_struct __user *newinfo) ++{ ++ struct serial_struct new_serial; ++ unsigned int closing_wait, close_delay; ++ int retval = 0; ++ ++ if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) ++ return -EFAULT; ++ ++ close_delay = new_serial.close_delay * 10; ++ closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? ++ ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; ++ ++ mutex_lock(&port->port.mutex); ++ ++ if (!capable(CAP_SYS_ADMIN)) { ++ if ((close_delay != port->port.close_delay) || ++ (closing_wait != port->port.closing_wait)) ++ retval = -EPERM; ++ else ++ retval = -EOPNOTSUPP; ++ } else { ++ port->port.close_delay = close_delay; ++ port->port.closing_wait = closing_wait; ++ } ++ ++ mutex_unlock(&port->port.mutex); ++ return retval; ++} ++ ++int usb_wwan_ioctl(struct tty_struct *tty, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct usb_serial_port *port = tty->driver_data; ++ ++ dbg("%s cmd 0x%04x", __func__, cmd); ++ ++ switch (cmd) { ++ case TIOCGSERIAL: ++ return get_serial_info(port, ++ (struct serial_struct __user *) arg); ++ case TIOCSSERIAL: ++ return set_serial_info(port, ++ (struct serial_struct __user *) arg); ++ default: ++ break; ++ } ++ ++ dbg("%s arg not supported", __func__); ++ ++ return -ENOIOCTLCMD; ++} ++EXPORT_SYMBOL(usb_wwan_ioctl); ++ + /* Write */ + int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count)