.. | .. |
---|
23 | 23 | #include "u_ether.h" |
---|
24 | 24 | #include "u_ether_configfs.h" |
---|
25 | 25 | #include "u_ncm.h" |
---|
| 26 | +#include "configfs.h" |
---|
26 | 27 | |
---|
27 | 28 | /* |
---|
28 | 29 | * This function is a "CDC Network Control Model" (CDC NCM) Ethernet link. |
---|
.. | .. |
---|
35 | 36 | |
---|
36 | 37 | /* to trigger crc/non-crc ndp signature */ |
---|
37 | 38 | |
---|
38 | | -#define NCM_NDP_HDR_CRC_MASK 0x01000000 |
---|
39 | 39 | #define NCM_NDP_HDR_CRC 0x01000000 |
---|
40 | | -#define NCM_NDP_HDR_NOCRC 0x00000000 |
---|
41 | 40 | |
---|
42 | 41 | enum ncm_notify_state { |
---|
43 | 42 | NCM_NOTIFY_NONE, /* don't notify */ |
---|
.. | .. |
---|
86 | 85 | /* peak (theoretical) bulk transfer rate in bits-per-second */ |
---|
87 | 86 | static inline unsigned ncm_bitrate(struct usb_gadget *g) |
---|
88 | 87 | { |
---|
89 | | - if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER_PLUS) |
---|
| 88 | + if (!g) |
---|
| 89 | + return 0; |
---|
| 90 | + else if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER_PLUS) |
---|
90 | 91 | return 4250000000U; |
---|
91 | 92 | else if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) |
---|
92 | 93 | return 3750000000U; |
---|
.. | .. |
---|
379 | 380 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, |
---|
380 | 381 | |
---|
381 | 382 | /* the following 2 values can be tweaked if necessary */ |
---|
382 | | - /* .bMaxBurst = 0, */ |
---|
| 383 | + .bMaxBurst = 15, |
---|
383 | 384 | /* .bmAttributes = 0, */ |
---|
384 | 385 | }; |
---|
385 | 386 | |
---|
.. | .. |
---|
529 | 530 | { |
---|
530 | 531 | ncm->parser_opts = &ndp16_opts; |
---|
531 | 532 | ncm->is_crc = false; |
---|
| 533 | + ncm->ndp_sign = ncm->parser_opts->ndp_sign; |
---|
532 | 534 | ncm->port.cdc_filter = DEFAULT_FILTER; |
---|
533 | 535 | |
---|
534 | 536 | /* doesn't make sense for ncm, fixed size used */ |
---|
.. | .. |
---|
811 | 813 | case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) |
---|
812 | 814 | | USB_CDC_SET_CRC_MODE: |
---|
813 | 815 | { |
---|
814 | | - int ndp_hdr_crc = 0; |
---|
815 | | - |
---|
816 | 816 | if (w_length != 0 || w_index != ncm->ctrl_id) |
---|
817 | 817 | goto invalid; |
---|
818 | 818 | switch (w_value) { |
---|
819 | 819 | case 0x0000: |
---|
820 | 820 | ncm->is_crc = false; |
---|
821 | | - ndp_hdr_crc = NCM_NDP_HDR_NOCRC; |
---|
822 | 821 | DBG(cdev, "non-CRC mode selected\n"); |
---|
823 | 822 | break; |
---|
824 | 823 | case 0x0001: |
---|
825 | 824 | ncm->is_crc = true; |
---|
826 | | - ndp_hdr_crc = NCM_NDP_HDR_CRC; |
---|
827 | 825 | DBG(cdev, "CRC mode selected\n"); |
---|
828 | 826 | break; |
---|
829 | 827 | default: |
---|
830 | 828 | goto invalid; |
---|
831 | 829 | } |
---|
832 | | - ncm->ndp_sign = ncm->parser_opts->ndp_sign | ndp_hdr_crc; |
---|
833 | 830 | value = 0; |
---|
834 | 831 | break; |
---|
835 | 832 | } |
---|
.. | .. |
---|
846 | 843 | ctrl->bRequestType, ctrl->bRequest, |
---|
847 | 844 | w_value, w_index, w_length); |
---|
848 | 845 | } |
---|
| 846 | + ncm->ndp_sign = ncm->parser_opts->ndp_sign | |
---|
| 847 | + (ncm->is_crc ? NCM_NDP_HDR_CRC : 0); |
---|
849 | 848 | |
---|
850 | 849 | /* respond with data transfer or status phase? */ |
---|
851 | 850 | if (value >= 0) { |
---|
.. | .. |
---|
1181 | 1180 | struct sk_buff_head *list) |
---|
1182 | 1181 | { |
---|
1183 | 1182 | struct f_ncm *ncm = func_to_ncm(&port->func); |
---|
1184 | | - __le16 *tmp = (void *) skb->data; |
---|
| 1183 | + unsigned char *ntb_ptr = skb->data; |
---|
| 1184 | + __le16 *tmp; |
---|
1185 | 1185 | unsigned index, index2; |
---|
1186 | 1186 | int ndp_index; |
---|
1187 | 1187 | unsigned dg_len, dg_len2; |
---|
.. | .. |
---|
1194 | 1194 | const struct ndp_parser_opts *opts = ncm->parser_opts; |
---|
1195 | 1195 | unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0; |
---|
1196 | 1196 | int dgram_counter; |
---|
| 1197 | + int to_process = skb->len; |
---|
| 1198 | + |
---|
| 1199 | +parse_ntb: |
---|
| 1200 | + tmp = (__le16 *)ntb_ptr; |
---|
1197 | 1201 | |
---|
1198 | 1202 | /* dwSignature */ |
---|
1199 | 1203 | if (get_unaligned_le32(tmp) != opts->nth_sign) { |
---|
.. | .. |
---|
1240 | 1244 | * walk through NDP |
---|
1241 | 1245 | * dwSignature |
---|
1242 | 1246 | */ |
---|
1243 | | - tmp = (void *)(skb->data + ndp_index); |
---|
| 1247 | + tmp = (__le16 *)(ntb_ptr + ndp_index); |
---|
1244 | 1248 | if (get_unaligned_le32(tmp) != ncm->ndp_sign) { |
---|
1245 | 1249 | INFO(port->func.config->cdev, "Wrong NDP SIGN\n"); |
---|
1246 | 1250 | goto err; |
---|
.. | .. |
---|
1297 | 1301 | if (ncm->is_crc) { |
---|
1298 | 1302 | uint32_t crc, crc2; |
---|
1299 | 1303 | |
---|
1300 | | - crc = get_unaligned_le32(skb->data + |
---|
| 1304 | + crc = get_unaligned_le32(ntb_ptr + |
---|
1301 | 1305 | index + dg_len - |
---|
1302 | 1306 | crc_len); |
---|
1303 | 1307 | crc2 = ~crc32_le(~0, |
---|
1304 | | - skb->data + index, |
---|
| 1308 | + ntb_ptr + index, |
---|
1305 | 1309 | dg_len - crc_len); |
---|
1306 | 1310 | if (crc != crc2) { |
---|
1307 | 1311 | INFO(port->func.config->cdev, |
---|
.. | .. |
---|
1328 | 1332 | dg_len - crc_len); |
---|
1329 | 1333 | if (skb2 == NULL) |
---|
1330 | 1334 | goto err; |
---|
1331 | | - skb_put_data(skb2, skb->data + index, |
---|
| 1335 | + skb_put_data(skb2, ntb_ptr + index, |
---|
1332 | 1336 | dg_len - crc_len); |
---|
1333 | 1337 | |
---|
1334 | 1338 | skb_queue_tail(list, skb2); |
---|
.. | .. |
---|
1341 | 1345 | } while (ndp_len > 2 * (opts->dgram_item_len * 2)); |
---|
1342 | 1346 | } while (ndp_index); |
---|
1343 | 1347 | |
---|
1344 | | - dev_consume_skb_any(skb); |
---|
1345 | | - |
---|
1346 | 1348 | VDBG(port->func.config->cdev, |
---|
1347 | 1349 | "Parsed NTB with %d frames\n", dgram_counter); |
---|
| 1350 | + |
---|
| 1351 | + to_process -= block_len; |
---|
| 1352 | + if (to_process != 0) { |
---|
| 1353 | + ntb_ptr = (unsigned char *)(ntb_ptr + block_len); |
---|
| 1354 | + goto parse_ntb; |
---|
| 1355 | + } |
---|
| 1356 | + |
---|
| 1357 | + dev_consume_skb_any(skb); |
---|
| 1358 | + |
---|
1348 | 1359 | return 0; |
---|
1349 | 1360 | err: |
---|
1350 | 1361 | skb_queue_purge(list); |
---|
.. | .. |
---|
1432 | 1443 | return -EINVAL; |
---|
1433 | 1444 | |
---|
1434 | 1445 | ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst); |
---|
| 1446 | + |
---|
| 1447 | + if (cdev->use_os_string) { |
---|
| 1448 | + f->os_desc_table = kzalloc(sizeof(*f->os_desc_table), |
---|
| 1449 | + GFP_KERNEL); |
---|
| 1450 | + if (!f->os_desc_table) |
---|
| 1451 | + return -ENOMEM; |
---|
| 1452 | + f->os_desc_n = 1; |
---|
| 1453 | + f->os_desc_table[0].os_desc = &ncm_opts->ncm_os_desc; |
---|
| 1454 | + } |
---|
| 1455 | + |
---|
1435 | 1456 | /* |
---|
1436 | 1457 | * in drivers/usb/gadget/configfs.c:configfs_composite_bind() |
---|
1437 | 1458 | * configurations are bound in sequence with list_for_each_entry, |
---|
.. | .. |
---|
1445 | 1466 | status = gether_register_netdev(ncm_opts->net); |
---|
1446 | 1467 | mutex_unlock(&ncm_opts->lock); |
---|
1447 | 1468 | if (status) |
---|
1448 | | - return status; |
---|
| 1469 | + goto fail; |
---|
1449 | 1470 | ncm_opts->bound = true; |
---|
1450 | 1471 | } |
---|
1451 | 1472 | us = usb_gstrings_attach(cdev, ncm_strings, |
---|
1452 | 1473 | ARRAY_SIZE(ncm_string_defs)); |
---|
1453 | | - if (IS_ERR(us)) |
---|
1454 | | - return PTR_ERR(us); |
---|
| 1474 | + if (IS_ERR(us)) { |
---|
| 1475 | + status = PTR_ERR(us); |
---|
| 1476 | + goto fail; |
---|
| 1477 | + } |
---|
1455 | 1478 | ncm_control_intf.iInterface = us[STRING_CTRL_IDX].id; |
---|
1456 | 1479 | ncm_data_nop_intf.iInterface = us[STRING_DATA_IDX].id; |
---|
1457 | 1480 | ncm_data_intf.iInterface = us[STRING_DATA_IDX].id; |
---|
.. | .. |
---|
1467 | 1490 | |
---|
1468 | 1491 | ncm_control_intf.bInterfaceNumber = status; |
---|
1469 | 1492 | ncm_union_desc.bMasterInterface0 = status; |
---|
| 1493 | + |
---|
| 1494 | + if (cdev->use_os_string) |
---|
| 1495 | + f->os_desc_table[0].if_id = |
---|
| 1496 | + ncm_iad_desc.bFirstInterface; |
---|
1470 | 1497 | |
---|
1471 | 1498 | status = usb_interface_id(c, f); |
---|
1472 | 1499 | if (status < 0) |
---|
.. | .. |
---|
1547 | 1574 | return 0; |
---|
1548 | 1575 | |
---|
1549 | 1576 | fail: |
---|
| 1577 | + kfree(f->os_desc_table); |
---|
| 1578 | + f->os_desc_n = 0; |
---|
| 1579 | + |
---|
1550 | 1580 | if (ncm->notify_req) { |
---|
1551 | 1581 | kfree(ncm->notify_req->buf); |
---|
1552 | 1582 | usb_ep_free_request(ncm->notify, ncm->notify_req); |
---|
.. | .. |
---|
1601 | 1631 | gether_cleanup(netdev_priv(opts->net)); |
---|
1602 | 1632 | else |
---|
1603 | 1633 | free_netdev(opts->net); |
---|
| 1634 | + kfree(opts->ncm_interf_group); |
---|
1604 | 1635 | kfree(opts); |
---|
1605 | 1636 | } |
---|
1606 | 1637 | |
---|
1607 | 1638 | static struct usb_function_instance *ncm_alloc_inst(void) |
---|
1608 | 1639 | { |
---|
1609 | 1640 | struct f_ncm_opts *opts; |
---|
| 1641 | + struct usb_os_desc *descs[1]; |
---|
| 1642 | + char *names[1]; |
---|
| 1643 | + struct config_group *ncm_interf_group; |
---|
1610 | 1644 | |
---|
1611 | 1645 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); |
---|
1612 | 1646 | if (!opts) |
---|
1613 | 1647 | return ERR_PTR(-ENOMEM); |
---|
| 1648 | + opts->ncm_os_desc.ext_compat_id = opts->ncm_ext_compat_id; |
---|
| 1649 | + |
---|
1614 | 1650 | mutex_init(&opts->lock); |
---|
1615 | 1651 | opts->func_inst.free_func_inst = ncm_free_inst; |
---|
1616 | 1652 | opts->net = gether_setup_default(); |
---|
.. | .. |
---|
1619 | 1655 | kfree(opts); |
---|
1620 | 1656 | return ERR_CAST(net); |
---|
1621 | 1657 | } |
---|
| 1658 | + INIT_LIST_HEAD(&opts->ncm_os_desc.ext_prop); |
---|
| 1659 | + |
---|
| 1660 | + descs[0] = &opts->ncm_os_desc; |
---|
| 1661 | + names[0] = "ncm"; |
---|
1622 | 1662 | |
---|
1623 | 1663 | config_group_init_type_name(&opts->func_inst.group, "", &ncm_func_type); |
---|
| 1664 | + ncm_interf_group = |
---|
| 1665 | + usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs, |
---|
| 1666 | + names, THIS_MODULE); |
---|
| 1667 | + if (IS_ERR(ncm_interf_group)) { |
---|
| 1668 | + ncm_free_inst(&opts->func_inst); |
---|
| 1669 | + return ERR_CAST(ncm_interf_group); |
---|
| 1670 | + } |
---|
| 1671 | + opts->ncm_interf_group = ncm_interf_group; |
---|
1624 | 1672 | |
---|
1625 | 1673 | return &opts->func_inst; |
---|
1626 | 1674 | } |
---|
.. | .. |
---|
1646 | 1694 | |
---|
1647 | 1695 | hrtimer_cancel(&ncm->task_timer); |
---|
1648 | 1696 | |
---|
| 1697 | + kfree(f->os_desc_table); |
---|
| 1698 | + f->os_desc_n = 0; |
---|
| 1699 | + |
---|
1649 | 1700 | ncm_string_defs[0].id = 0; |
---|
1650 | 1701 | usb_free_all_descriptors(f); |
---|
1651 | 1702 | |
---|