diff options
| -rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 103 |
1 files changed, 90 insertions, 13 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 9cf4069895c1..ff06c01a555b 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
| @@ -550,11 +550,17 @@ struct ftdi_private { | |||
| 550 | spinlock_t rx_lock; /* spinlock for receive state */ | 550 | spinlock_t rx_lock; /* spinlock for receive state */ |
| 551 | struct work_struct rx_work; | 551 | struct work_struct rx_work; |
| 552 | int rx_processed; | 552 | int rx_processed; |
| 553 | unsigned long rx_bytes; | ||
| 553 | 554 | ||
| 554 | __u16 interface; /* FT2232C port interface (0 for FT232/245) */ | 555 | __u16 interface; /* FT2232C port interface (0 for FT232/245) */ |
| 555 | 556 | ||
| 556 | int force_baud; /* if non-zero, force the baud rate to this value */ | 557 | int force_baud; /* if non-zero, force the baud rate to this value */ |
| 557 | int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ | 558 | int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ |
| 559 | |||
| 560 | spinlock_t tx_lock; /* spinlock for transmit state */ | ||
| 561 | unsigned long tx_bytes; | ||
| 562 | unsigned long tx_outstanding_bytes; | ||
| 563 | unsigned long tx_outstanding_urbs; | ||
| 558 | }; | 564 | }; |
| 559 | 565 | ||
| 560 | /* Used for TIOCMIWAIT */ | 566 | /* Used for TIOCMIWAIT */ |
| @@ -628,6 +634,9 @@ static struct usb_serial_driver ftdi_sio_device = { | |||
| 628 | #define HIGH 1 | 634 | #define HIGH 1 |
| 629 | #define LOW 0 | 635 | #define LOW 0 |
| 630 | 636 | ||
| 637 | /* number of outstanding urbs to prevent userspace DoS from happening */ | ||
| 638 | #define URB_UPPER_LIMIT 42 | ||
| 639 | |||
| 631 | /* | 640 | /* |
| 632 | * *************************************************************************** | 641 | * *************************************************************************** |
| 633 | * Utlity functions | 642 | * Utlity functions |
| @@ -1158,6 +1167,7 @@ static int ftdi_sio_attach (struct usb_serial *serial) | |||
| 1158 | } | 1167 | } |
| 1159 | 1168 | ||
| 1160 | spin_lock_init(&priv->rx_lock); | 1169 | spin_lock_init(&priv->rx_lock); |
| 1170 | spin_lock_init(&priv->tx_lock); | ||
| 1161 | init_waitqueue_head(&priv->delta_msr_wait); | 1171 | init_waitqueue_head(&priv->delta_msr_wait); |
| 1162 | /* This will push the characters through immediately rather | 1172 | /* This will push the characters through immediately rather |
| 1163 | than queue a task to deliver them */ | 1173 | than queue a task to deliver them */ |
| @@ -1272,6 +1282,13 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) | |||
| 1272 | 1282 | ||
| 1273 | dbg("%s", __FUNCTION__); | 1283 | dbg("%s", __FUNCTION__); |
| 1274 | 1284 | ||
| 1285 | spin_lock_irqsave(&priv->tx_lock, flags); | ||
| 1286 | priv->tx_bytes = 0; | ||
| 1287 | spin_unlock_irqrestore(&priv->tx_lock, flags); | ||
| 1288 | spin_lock_irqsave(&priv->rx_lock, flags); | ||
| 1289 | priv->rx_bytes = 0; | ||
| 1290 | spin_unlock_irqrestore(&priv->rx_lock, flags); | ||
| 1291 | |||
| 1275 | if (port->tty) | 1292 | if (port->tty) |
| 1276 | port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; | 1293 | port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; |
| 1277 | 1294 | ||
| @@ -1374,6 +1391,7 @@ static int ftdi_write (struct usb_serial_port *port, | |||
| 1374 | int data_offset ; /* will be 1 for the SIO and 0 otherwise */ | 1391 | int data_offset ; /* will be 1 for the SIO and 0 otherwise */ |
| 1375 | int status; | 1392 | int status; |
| 1376 | int transfer_size; | 1393 | int transfer_size; |
| 1394 | unsigned long flags; | ||
| 1377 | 1395 | ||
| 1378 | dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count); | 1396 | dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count); |
| 1379 | 1397 | ||
| @@ -1381,6 +1399,13 @@ static int ftdi_write (struct usb_serial_port *port, | |||
| 1381 | dbg("write request of 0 bytes"); | 1399 | dbg("write request of 0 bytes"); |
| 1382 | return 0; | 1400 | return 0; |
| 1383 | } | 1401 | } |
| 1402 | spin_lock_irqsave(&priv->tx_lock, flags); | ||
| 1403 | if (priv->tx_outstanding_urbs > URB_UPPER_LIMIT) { | ||
| 1404 | spin_unlock_irqrestore(&priv->tx_lock, flags); | ||
| 1405 | dbg("%s - write limit hit\n", __FUNCTION__); | ||
| 1406 | return 0; | ||
| 1407 | } | ||
| 1408 | spin_unlock_irqrestore(&priv->tx_lock, flags); | ||
| 1384 | 1409 | ||
| 1385 | data_offset = priv->write_offset; | 1410 | data_offset = priv->write_offset; |
| 1386 | dbg("data_offset set to %d",data_offset); | 1411 | dbg("data_offset set to %d",data_offset); |
| @@ -1447,6 +1472,12 @@ static int ftdi_write (struct usb_serial_port *port, | |||
| 1447 | err("%s - failed submitting write urb, error %d", __FUNCTION__, status); | 1472 | err("%s - failed submitting write urb, error %d", __FUNCTION__, status); |
| 1448 | count = status; | 1473 | count = status; |
| 1449 | kfree (buffer); | 1474 | kfree (buffer); |
| 1475 | } else { | ||
| 1476 | spin_lock_irqsave(&priv->tx_lock, flags); | ||
| 1477 | ++priv->tx_outstanding_urbs; | ||
| 1478 | priv->tx_outstanding_bytes += count; | ||
| 1479 | priv->tx_bytes += count; | ||
| 1480 | spin_unlock_irqrestore(&priv->tx_lock, flags); | ||
| 1450 | } | 1481 | } |
| 1451 | 1482 | ||
| 1452 | /* we are done with this urb, so let the host driver | 1483 | /* we are done with this urb, so let the host driver |
| @@ -1462,7 +1493,11 @@ static int ftdi_write (struct usb_serial_port *port, | |||
| 1462 | 1493 | ||
| 1463 | static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | 1494 | static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs) |
| 1464 | { | 1495 | { |
| 1496 | unsigned long flags; | ||
| 1465 | struct usb_serial_port *port = (struct usb_serial_port *)urb->context; | 1497 | struct usb_serial_port *port = (struct usb_serial_port *)urb->context; |
| 1498 | struct ftdi_private *priv; | ||
| 1499 | int data_offset; /* will be 1 for the SIO and 0 otherwise */ | ||
| 1500 | unsigned long countback; | ||
| 1466 | 1501 | ||
| 1467 | /* free up the transfer buffer, as usb_free_urb() does not do this */ | 1502 | /* free up the transfer buffer, as usb_free_urb() does not do this */ |
| 1468 | kfree (urb->transfer_buffer); | 1503 | kfree (urb->transfer_buffer); |
| @@ -1474,34 +1509,67 @@ static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
| 1474 | return; | 1509 | return; |
| 1475 | } | 1510 | } |
| 1476 | 1511 | ||
| 1512 | priv = usb_get_serial_port_data(port); | ||
| 1513 | if (!priv) { | ||
| 1514 | dbg("%s - bad port private data pointer - exiting", __FUNCTION__); | ||
| 1515 | return; | ||
| 1516 | } | ||
| 1517 | /* account for transferred data */ | ||
| 1518 | countback = urb->actual_length; | ||
| 1519 | data_offset = priv->write_offset; | ||
| 1520 | if (data_offset > 0) { | ||
| 1521 | /* Subtract the control bytes */ | ||
| 1522 | countback -= (data_offset * ((countback + (PKTSZ - 1)) / PKTSZ)); | ||
| 1523 | } | ||
| 1524 | spin_lock_irqsave(&priv->tx_lock, flags); | ||
| 1525 | --priv->tx_outstanding_urbs; | ||
| 1526 | priv->tx_outstanding_bytes -= countback; | ||
| 1527 | spin_unlock_irqrestore(&priv->tx_lock, flags); | ||
| 1528 | |||
| 1477 | usb_serial_port_softint(port); | 1529 | usb_serial_port_softint(port); |
| 1478 | } /* ftdi_write_bulk_callback */ | 1530 | } /* ftdi_write_bulk_callback */ |
| 1479 | 1531 | ||
| 1480 | 1532 | ||
| 1481 | static int ftdi_write_room( struct usb_serial_port *port ) | 1533 | static int ftdi_write_room( struct usb_serial_port *port ) |
| 1482 | { | 1534 | { |
| 1535 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
| 1536 | int room; | ||
| 1537 | unsigned long flags; | ||
| 1538 | |||
| 1483 | dbg("%s - port %d", __FUNCTION__, port->number); | 1539 | dbg("%s - port %d", __FUNCTION__, port->number); |
| 1484 | 1540 | ||
| 1485 | /* | 1541 | spin_lock_irqsave(&priv->tx_lock, flags); |
| 1486 | * We really can take anything the user throws at us | 1542 | if (priv->tx_outstanding_urbs < URB_UPPER_LIMIT) { |
| 1487 | * but let's pick a nice big number to tell the tty | 1543 | /* |
| 1488 | * layer that we have lots of free space | 1544 | * We really can take anything the user throws at us |
| 1489 | */ | 1545 | * but let's pick a nice big number to tell the tty |
| 1490 | return 2048; | 1546 | * layer that we have lots of free space |
| 1547 | */ | ||
| 1548 | room = 2048; | ||
| 1549 | } else { | ||
| 1550 | room = 0; | ||
| 1551 | } | ||
| 1552 | spin_unlock_irqrestore(&priv->tx_lock, flags); | ||
| 1553 | return room; | ||
| 1491 | } /* ftdi_write_room */ | 1554 | } /* ftdi_write_room */ |
| 1492 | 1555 | ||
| 1493 | 1556 | ||
| 1494 | static int ftdi_chars_in_buffer (struct usb_serial_port *port) | 1557 | static int ftdi_chars_in_buffer (struct usb_serial_port *port) |
| 1495 | { /* ftdi_chars_in_buffer */ | 1558 | { /* ftdi_chars_in_buffer */ |
| 1559 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
| 1560 | int buffered; | ||
| 1561 | unsigned long flags; | ||
| 1562 | |||
| 1496 | dbg("%s - port %d", __FUNCTION__, port->number); | 1563 | dbg("%s - port %d", __FUNCTION__, port->number); |
| 1497 | 1564 | ||
| 1498 | /* | 1565 | spin_lock_irqsave(&priv->tx_lock, flags); |
| 1499 | * We can't really account for how much data we | 1566 | buffered = (int)priv->tx_outstanding_bytes; |
| 1500 | * have sent out, but hasn't made it through to the | 1567 | spin_unlock_irqrestore(&priv->tx_lock, flags); |
| 1501 | * device, so just tell the tty layer that everything | 1568 | if (buffered < 0) { |
| 1502 | * is flushed. | 1569 | err("%s outstanding tx bytes is negative!", __FUNCTION__); |
| 1503 | */ | 1570 | buffered = 0; |
| 1504 | return 0; | 1571 | } |
| 1572 | return buffered; | ||
| 1505 | } /* ftdi_chars_in_buffer */ | 1573 | } /* ftdi_chars_in_buffer */ |
| 1506 | 1574 | ||
| 1507 | 1575 | ||
| @@ -1511,6 +1579,8 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
| 1511 | struct usb_serial_port *port = (struct usb_serial_port *)urb->context; | 1579 | struct usb_serial_port *port = (struct usb_serial_port *)urb->context; |
| 1512 | struct tty_struct *tty; | 1580 | struct tty_struct *tty; |
| 1513 | struct ftdi_private *priv; | 1581 | struct ftdi_private *priv; |
| 1582 | unsigned long countread; | ||
| 1583 | unsigned long flags; | ||
| 1514 | 1584 | ||
| 1515 | if (urb->number_of_packets > 0) { | 1585 | if (urb->number_of_packets > 0) { |
| 1516 | err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__, | 1586 | err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__, |
| @@ -1545,6 +1615,13 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
| 1545 | return; | 1615 | return; |
| 1546 | } | 1616 | } |
| 1547 | 1617 | ||
| 1618 | /* count data bytes, but not status bytes */ | ||
| 1619 | countread = urb->actual_length; | ||
| 1620 | countread -= 2 * ((countread + (PKTSZ - 1)) / PKTSZ); | ||
| 1621 | spin_lock_irqsave(&priv->rx_lock, flags); | ||
| 1622 | priv->rx_bytes += countread; | ||
| 1623 | spin_unlock_irqrestore(&priv->rx_lock, flags); | ||
| 1624 | |||
| 1548 | ftdi_process_read(port); | 1625 | ftdi_process_read(port); |
| 1549 | 1626 | ||
| 1550 | } /* ftdi_read_bulk_callback */ | 1627 | } /* ftdi_read_bulk_callback */ |
