diff options
Diffstat (limited to 'drivers')
-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 */ |