diff --git a/target/linux/generic/backport-5.15/796-v6.5-01-usbnet-ipheth-fix-risk-of-NULL-pointer-deallocation.patch b/target/linux/generic/backport-5.15/796-v6.5-01-usbnet-ipheth-fix-risk-of-NULL-pointer-deallocation.patch new file mode 100644 index 0000000000..d9d6f36fce --- /dev/null +++ b/target/linux/generic/backport-5.15/796-v6.5-01-usbnet-ipheth-fix-risk-of-NULL-pointer-deallocation.patch @@ -0,0 +1,30 @@ +From 2203718c2f59ffdd6c78d54e5add594aebb4461e Mon Sep 17 00:00:00 2001 +From: Georgi Valkov +Date: Wed, 7 Jun 2023 15:56:59 +0200 +Subject: [PATCH 1/4] usbnet: ipheth: fix risk of NULL pointer deallocation + +The cleanup precedure in ipheth_probe will attempt to free a +NULL pointer in dev->ctrl_buf if the memory allocation for +this buffer is not successful. While kfree ignores NULL pointers, +and the existing code is safe, it is a better design to rearrange +the goto labels and avoid this. + +Signed-off-by: Georgi Valkov +Signed-off-by: Foster Snowhill +Signed-off-by: David S. Miller +--- + drivers/net/usb/ipheth.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/usb/ipheth.c ++++ b/drivers/net/usb/ipheth.c +@@ -510,8 +510,8 @@ err_register_netdev: + ipheth_free_urbs(dev); + err_alloc_urbs: + err_get_macaddr: +-err_alloc_ctrl_buf: + kfree(dev->ctrl_buf); ++err_alloc_ctrl_buf: + err_endpoints: + free_netdev(netdev); + return retval; diff --git a/target/linux/generic/backport-5.15/796-v6.5-02-usbnet-ipheth-transmit-URBs-without-trailing-padding.patch b/target/linux/generic/backport-5.15/796-v6.5-02-usbnet-ipheth-transmit-URBs-without-trailing-padding.patch new file mode 100644 index 0000000000..adfec356d9 --- /dev/null +++ b/target/linux/generic/backport-5.15/796-v6.5-02-usbnet-ipheth-transmit-URBs-without-trailing-padding.patch @@ -0,0 +1,35 @@ +From 3e65efcca87a9bb5f3b864e0a43d167bc0a8688c Mon Sep 17 00:00:00 2001 +From: Foster Snowhill +Date: Wed, 7 Jun 2023 15:57:00 +0200 +Subject: [PATCH 2/4] usbnet: ipheth: transmit URBs without trailing padding + +The behaviour of the official iOS tethering driver on macOS is to not +transmit any trailing padding at the end of URBs. This is applicable +to both NCM and legacy modes, including older devices. + +Adapt the driver to not include trailing padding in TX URBs, matching +the behaviour of the official macOS driver. + +Signed-off-by: Foster Snowhill +Tested-by: Georgi Valkov +Signed-off-by: David S. Miller +--- + drivers/net/usb/ipheth.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/drivers/net/usb/ipheth.c ++++ b/drivers/net/usb/ipheth.c +@@ -373,12 +373,10 @@ static netdev_tx_t ipheth_tx(struct sk_b + } + + memcpy(dev->tx_buf, skb->data, skb->len); +- if (skb->len < IPHETH_BUF_SIZE) +- memset(dev->tx_buf + skb->len, 0, IPHETH_BUF_SIZE - skb->len); + + usb_fill_bulk_urb(dev->tx_urb, udev, + usb_sndbulkpipe(udev, dev->bulk_out), +- dev->tx_buf, IPHETH_BUF_SIZE, ++ dev->tx_buf, skb->len, + ipheth_sndbulk_callback, + dev); + dev->tx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; diff --git a/target/linux/generic/backport-5.15/796-v6.5-03-usbnet-ipheth-add-CDC-NCM-support.patch b/target/linux/generic/backport-5.15/796-v6.5-03-usbnet-ipheth-add-CDC-NCM-support.patch new file mode 100644 index 0000000000..e3f2b9c331 --- /dev/null +++ b/target/linux/generic/backport-5.15/796-v6.5-03-usbnet-ipheth-add-CDC-NCM-support.patch @@ -0,0 +1,326 @@ +From a2d274c62e44b1995c170595db3865c6fe701226 Mon Sep 17 00:00:00 2001 +From: Foster Snowhill +Date: Wed, 7 Jun 2023 15:57:01 +0200 +Subject: [PATCH 3/4] usbnet: ipheth: add CDC NCM support + +Recent iOS releases support CDC NCM encapsulation on RX. This mode is +the default on macOS and Windows. In this mode, an iOS device may include +one or more Ethernet frames inside a single URB. + +Freshly booted iOS devices start in legacy mode, but are put into +NCM mode by the official Apple driver. When reconnecting such a device +from a macOS/Windows machine to a Linux host, the device stays in +NCM mode, making it unusable with the legacy ipheth driver code. + +To correctly support such a device, the driver has to either support +the NCM mode too, or put the device back into legacy mode. + +To match the behaviour of the macOS/Windows driver, and since there +is no documented control command to revert to legacy mode, implement +NCM support. The device is attempted to be put into NCM mode by default, +and falls back to legacy mode if the attempt fails. + +Signed-off-by: Foster Snowhill +Tested-by: Georgi Valkov +Signed-off-by: David S. Miller +--- + drivers/net/usb/ipheth.c | 180 +++++++++++++++++++++++++++++++++------ + 1 file changed, 155 insertions(+), 25 deletions(-) + +--- a/drivers/net/usb/ipheth.c ++++ b/drivers/net/usb/ipheth.c +@@ -52,6 +52,7 @@ + #include + #include + #include ++#include + + #define USB_VENDOR_APPLE 0x05ac + +@@ -59,8 +60,12 @@ + #define IPHETH_USBINTF_SUBCLASS 253 + #define IPHETH_USBINTF_PROTO 1 + +-#define IPHETH_BUF_SIZE 1514 + #define IPHETH_IP_ALIGN 2 /* padding at front of URB */ ++#define IPHETH_NCM_HEADER_SIZE (12 + 96) /* NCMH + NCM0 */ ++#define IPHETH_TX_BUF_SIZE ETH_FRAME_LEN ++#define IPHETH_RX_BUF_SIZE_LEGACY (IPHETH_IP_ALIGN + ETH_FRAME_LEN) ++#define IPHETH_RX_BUF_SIZE_NCM 65536 ++ + #define IPHETH_TX_TIMEOUT (5 * HZ) + + #define IPHETH_INTFNUM 2 +@@ -71,6 +76,7 @@ + #define IPHETH_CTRL_TIMEOUT (5 * HZ) + + #define IPHETH_CMD_GET_MACADDR 0x00 ++#define IPHETH_CMD_ENABLE_NCM 0x04 + #define IPHETH_CMD_CARRIER_CHECK 0x45 + + #define IPHETH_CARRIER_CHECK_TIMEOUT round_jiffies_relative(1 * HZ) +@@ -97,6 +103,8 @@ struct ipheth_device { + u8 bulk_out; + struct delayed_work carrier_work; + bool confirmed_pairing; ++ int (*rcvbulk_callback)(struct urb *urb); ++ size_t rx_buf_len; + }; + + static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags); +@@ -116,12 +124,12 @@ static int ipheth_alloc_urbs(struct iphe + if (rx_urb == NULL) + goto free_tx_urb; + +- tx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE, ++ tx_buf = usb_alloc_coherent(iphone->udev, IPHETH_TX_BUF_SIZE, + GFP_KERNEL, &tx_urb->transfer_dma); + if (tx_buf == NULL) + goto free_rx_urb; + +- rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN, ++ rx_buf = usb_alloc_coherent(iphone->udev, iphone->rx_buf_len, + GFP_KERNEL, &rx_urb->transfer_dma); + if (rx_buf == NULL) + goto free_tx_buf; +@@ -134,7 +142,7 @@ static int ipheth_alloc_urbs(struct iphe + return 0; + + free_tx_buf: +- usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, tx_buf, ++ usb_free_coherent(iphone->udev, IPHETH_TX_BUF_SIZE, tx_buf, + tx_urb->transfer_dma); + free_rx_urb: + usb_free_urb(rx_urb); +@@ -146,9 +154,9 @@ error_nomem: + + static void ipheth_free_urbs(struct ipheth_device *iphone) + { +- usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN, iphone->rx_buf, ++ usb_free_coherent(iphone->udev, iphone->rx_buf_len, iphone->rx_buf, + iphone->rx_urb->transfer_dma); +- usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf, ++ usb_free_coherent(iphone->udev, IPHETH_TX_BUF_SIZE, iphone->tx_buf, + iphone->tx_urb->transfer_dma); + usb_free_urb(iphone->rx_urb); + usb_free_urb(iphone->tx_urb); +@@ -160,15 +168,106 @@ static void ipheth_kill_urbs(struct iphe + usb_kill_urb(dev->rx_urb); + } + +-static void ipheth_rcvbulk_callback(struct urb *urb) ++static int ipheth_consume_skb(char *buf, int len, struct ipheth_device *dev) + { +- struct ipheth_device *dev; + struct sk_buff *skb; +- int status; ++ ++ skb = dev_alloc_skb(len); ++ if (!skb) { ++ dev->net->stats.rx_dropped++; ++ return -ENOMEM; ++ } ++ ++ skb_put_data(skb, buf, len); ++ skb->dev = dev->net; ++ skb->protocol = eth_type_trans(skb, dev->net); ++ ++ dev->net->stats.rx_packets++; ++ dev->net->stats.rx_bytes += len; ++ netif_rx(skb); ++ ++ return 0; ++} ++ ++static int ipheth_rcvbulk_callback_legacy(struct urb *urb) ++{ ++ struct ipheth_device *dev; ++ char *buf; ++ int len; ++ ++ dev = urb->context; ++ ++ if (urb->actual_length <= IPHETH_IP_ALIGN) { ++ dev->net->stats.rx_length_errors++; ++ return -EINVAL; ++ } ++ len = urb->actual_length - IPHETH_IP_ALIGN; ++ buf = urb->transfer_buffer + IPHETH_IP_ALIGN; ++ ++ return ipheth_consume_skb(buf, len, dev); ++} ++ ++static int ipheth_rcvbulk_callback_ncm(struct urb *urb) ++{ ++ struct usb_cdc_ncm_nth16 *ncmh; ++ struct usb_cdc_ncm_ndp16 *ncm0; ++ struct usb_cdc_ncm_dpe16 *dpe; ++ struct ipheth_device *dev; ++ int retval = -EINVAL; + char *buf; + int len; + + dev = urb->context; ++ ++ if (urb->actual_length < IPHETH_NCM_HEADER_SIZE) { ++ dev->net->stats.rx_length_errors++; ++ return retval; ++ } ++ ++ ncmh = urb->transfer_buffer; ++ if (ncmh->dwSignature != cpu_to_le32(USB_CDC_NCM_NTH16_SIGN) || ++ le16_to_cpu(ncmh->wNdpIndex) >= urb->actual_length) { ++ dev->net->stats.rx_errors++; ++ return retval; ++ } ++ ++ ncm0 = urb->transfer_buffer + le16_to_cpu(ncmh->wNdpIndex); ++ if (ncm0->dwSignature != cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN) || ++ le16_to_cpu(ncmh->wHeaderLength) + le16_to_cpu(ncm0->wLength) >= ++ urb->actual_length) { ++ dev->net->stats.rx_errors++; ++ return retval; ++ } ++ ++ dpe = ncm0->dpe16; ++ while (le16_to_cpu(dpe->wDatagramIndex) != 0 && ++ le16_to_cpu(dpe->wDatagramLength) != 0) { ++ if (le16_to_cpu(dpe->wDatagramIndex) >= urb->actual_length || ++ le16_to_cpu(dpe->wDatagramIndex) + ++ le16_to_cpu(dpe->wDatagramLength) > urb->actual_length) { ++ dev->net->stats.rx_length_errors++; ++ return retval; ++ } ++ ++ buf = urb->transfer_buffer + le16_to_cpu(dpe->wDatagramIndex); ++ len = le16_to_cpu(dpe->wDatagramLength); ++ ++ retval = ipheth_consume_skb(buf, len, dev); ++ if (retval != 0) ++ return retval; ++ ++ dpe++; ++ } ++ ++ return 0; ++} ++ ++static void ipheth_rcvbulk_callback(struct urb *urb) ++{ ++ struct ipheth_device *dev; ++ int retval, status; ++ ++ dev = urb->context; + if (dev == NULL) + return; + +@@ -191,25 +290,27 @@ static void ipheth_rcvbulk_callback(stru + dev->net->stats.rx_length_errors++; + return; + } +- len = urb->actual_length - IPHETH_IP_ALIGN; +- buf = urb->transfer_buffer + IPHETH_IP_ALIGN; + +- skb = dev_alloc_skb(len); +- if (!skb) { +- dev_err(&dev->intf->dev, "%s: dev_alloc_skb: -ENOMEM\n", +- __func__); +- dev->net->stats.rx_dropped++; ++ /* RX URBs starting with 0x00 0x01 do not encapsulate Ethernet frames, ++ * but rather are control frames. Their purpose is not documented, and ++ * they don't affect driver functionality, okay to drop them. ++ * There is usually just one 4-byte control frame as the very first ++ * URB received from the bulk IN endpoint. ++ */ ++ if (unlikely ++ (((char *)urb->transfer_buffer)[0] == 0 && ++ ((char *)urb->transfer_buffer)[1] == 1)) ++ goto rx_submit; ++ ++ retval = dev->rcvbulk_callback(urb); ++ if (retval != 0) { ++ dev_err(&dev->intf->dev, "%s: callback retval: %d\n", ++ __func__, retval); + return; + } + +- skb_put_data(skb, buf, len); +- skb->dev = dev->net; +- skb->protocol = eth_type_trans(skb, dev->net); +- +- dev->net->stats.rx_packets++; +- dev->net->stats.rx_bytes += len; ++rx_submit: + dev->confirmed_pairing = true; +- netif_rx(skb); + ipheth_rx_submit(dev, GFP_ATOMIC); + } + +@@ -310,6 +411,27 @@ static int ipheth_get_macaddr(struct iph + return retval; + } + ++static int ipheth_enable_ncm(struct ipheth_device *dev) ++{ ++ struct usb_device *udev = dev->udev; ++ int retval; ++ ++ retval = usb_control_msg(udev, ++ usb_sndctrlpipe(udev, IPHETH_CTRL_ENDP), ++ IPHETH_CMD_ENABLE_NCM, /* request */ ++ 0x41, /* request type */ ++ 0x00, /* value */ ++ 0x02, /* index */ ++ NULL, ++ 0, ++ IPHETH_CTRL_TIMEOUT); ++ ++ dev_info(&dev->intf->dev, "%s: usb_control_msg: %d\n", ++ __func__, retval); ++ ++ return retval; ++} ++ + static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags) + { + struct usb_device *udev = dev->udev; +@@ -317,7 +439,7 @@ static int ipheth_rx_submit(struct iphet + + usb_fill_bulk_urb(dev->rx_urb, udev, + usb_rcvbulkpipe(udev, dev->bulk_in), +- dev->rx_buf, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN, ++ dev->rx_buf, dev->rx_buf_len, + ipheth_rcvbulk_callback, + dev); + dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; +@@ -365,7 +487,7 @@ static netdev_tx_t ipheth_tx(struct sk_b + int retval; + + /* Paranoid */ +- if (skb->len > IPHETH_BUF_SIZE) { ++ if (skb->len > IPHETH_TX_BUF_SIZE) { + WARN(1, "%s: skb too large: %d bytes\n", __func__, skb->len); + dev->net->stats.tx_dropped++; + dev_kfree_skb_any(skb); +@@ -448,6 +570,8 @@ static int ipheth_probe(struct usb_inter + dev->net = netdev; + dev->intf = intf; + dev->confirmed_pairing = false; ++ dev->rx_buf_len = IPHETH_RX_BUF_SIZE_LEGACY; ++ dev->rcvbulk_callback = ipheth_rcvbulk_callback_legacy; + /* Set up endpoints */ + hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM); + if (hintf == NULL) { +@@ -479,6 +603,12 @@ static int ipheth_probe(struct usb_inter + if (retval) + goto err_get_macaddr; + ++ retval = ipheth_enable_ncm(dev); ++ if (!retval) { ++ dev->rx_buf_len = IPHETH_RX_BUF_SIZE_NCM; ++ dev->rcvbulk_callback = ipheth_rcvbulk_callback_ncm; ++ } ++ + INIT_DELAYED_WORK(&dev->carrier_work, ipheth_carrier_check_work); + + retval = ipheth_alloc_urbs(dev); diff --git a/target/linux/generic/backport-5.15/796-v6.5-04-usbnet-ipheth-update-Kconfig-description.patch b/target/linux/generic/backport-5.15/796-v6.5-04-usbnet-ipheth-update-Kconfig-description.patch new file mode 100644 index 0000000000..2ab7e8fedd --- /dev/null +++ b/target/linux/generic/backport-5.15/796-v6.5-04-usbnet-ipheth-update-Kconfig-description.patch @@ -0,0 +1,36 @@ +From 0c6e9d32ef0ccfcf2d875cbcff23bf345a54d585 Mon Sep 17 00:00:00 2001 +From: Foster Snowhill +Date: Wed, 7 Jun 2023 15:57:02 +0200 +Subject: [PATCH 4/4] usbnet: ipheth: update Kconfig description + +This module has for a long time not been limited to iPhone <= 3GS. +Update description to match the actual state of the driver. + +Remove dead link from 2010, instead reference an existing userspace +iOS device pairing implementation as part of libimobiledevice. + +Signed-off-by: Foster Snowhill +Signed-off-by: David S. Miller +--- + drivers/net/usb/Kconfig | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +--- a/drivers/net/usb/Kconfig ++++ b/drivers/net/usb/Kconfig +@@ -582,12 +582,10 @@ config USB_IPHETH + default n + help + Module used to share Internet connection (tethering) from your +- iPhone (Original, 3G and 3GS) to your system. +- Note that you need userspace libraries and programs that are needed +- to pair your device with your system and that understand the iPhone +- protocol. +- +- For more information: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver ++ iPhone to your system. ++ Note that you need a corresponding userspace library/program ++ to pair your device with your system, for example usbmuxd ++ . + + config USB_SIERRA_NET + tristate "USB-to-WWAN Driver for Sierra Wireless modems" diff --git a/target/linux/generic/backport-6.1/796-v6.5-01-usbnet-ipheth-fix-risk-of-NULL-pointer-deallocation.patch b/target/linux/generic/backport-6.1/796-v6.5-01-usbnet-ipheth-fix-risk-of-NULL-pointer-deallocation.patch new file mode 100644 index 0000000000..d9d6f36fce --- /dev/null +++ b/target/linux/generic/backport-6.1/796-v6.5-01-usbnet-ipheth-fix-risk-of-NULL-pointer-deallocation.patch @@ -0,0 +1,30 @@ +From 2203718c2f59ffdd6c78d54e5add594aebb4461e Mon Sep 17 00:00:00 2001 +From: Georgi Valkov +Date: Wed, 7 Jun 2023 15:56:59 +0200 +Subject: [PATCH 1/4] usbnet: ipheth: fix risk of NULL pointer deallocation + +The cleanup precedure in ipheth_probe will attempt to free a +NULL pointer in dev->ctrl_buf if the memory allocation for +this buffer is not successful. While kfree ignores NULL pointers, +and the existing code is safe, it is a better design to rearrange +the goto labels and avoid this. + +Signed-off-by: Georgi Valkov +Signed-off-by: Foster Snowhill +Signed-off-by: David S. Miller +--- + drivers/net/usb/ipheth.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/usb/ipheth.c ++++ b/drivers/net/usb/ipheth.c +@@ -510,8 +510,8 @@ err_register_netdev: + ipheth_free_urbs(dev); + err_alloc_urbs: + err_get_macaddr: +-err_alloc_ctrl_buf: + kfree(dev->ctrl_buf); ++err_alloc_ctrl_buf: + err_endpoints: + free_netdev(netdev); + return retval; diff --git a/target/linux/generic/backport-6.1/796-v6.5-02-usbnet-ipheth-transmit-URBs-without-trailing-padding.patch b/target/linux/generic/backport-6.1/796-v6.5-02-usbnet-ipheth-transmit-URBs-without-trailing-padding.patch new file mode 100644 index 0000000000..adfec356d9 --- /dev/null +++ b/target/linux/generic/backport-6.1/796-v6.5-02-usbnet-ipheth-transmit-URBs-without-trailing-padding.patch @@ -0,0 +1,35 @@ +From 3e65efcca87a9bb5f3b864e0a43d167bc0a8688c Mon Sep 17 00:00:00 2001 +From: Foster Snowhill +Date: Wed, 7 Jun 2023 15:57:00 +0200 +Subject: [PATCH 2/4] usbnet: ipheth: transmit URBs without trailing padding + +The behaviour of the official iOS tethering driver on macOS is to not +transmit any trailing padding at the end of URBs. This is applicable +to both NCM and legacy modes, including older devices. + +Adapt the driver to not include trailing padding in TX URBs, matching +the behaviour of the official macOS driver. + +Signed-off-by: Foster Snowhill +Tested-by: Georgi Valkov +Signed-off-by: David S. Miller +--- + drivers/net/usb/ipheth.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/drivers/net/usb/ipheth.c ++++ b/drivers/net/usb/ipheth.c +@@ -373,12 +373,10 @@ static netdev_tx_t ipheth_tx(struct sk_b + } + + memcpy(dev->tx_buf, skb->data, skb->len); +- if (skb->len < IPHETH_BUF_SIZE) +- memset(dev->tx_buf + skb->len, 0, IPHETH_BUF_SIZE - skb->len); + + usb_fill_bulk_urb(dev->tx_urb, udev, + usb_sndbulkpipe(udev, dev->bulk_out), +- dev->tx_buf, IPHETH_BUF_SIZE, ++ dev->tx_buf, skb->len, + ipheth_sndbulk_callback, + dev); + dev->tx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; diff --git a/target/linux/generic/backport-6.1/796-v6.5-03-usbnet-ipheth-add-CDC-NCM-support.patch b/target/linux/generic/backport-6.1/796-v6.5-03-usbnet-ipheth-add-CDC-NCM-support.patch new file mode 100644 index 0000000000..e3f2b9c331 --- /dev/null +++ b/target/linux/generic/backport-6.1/796-v6.5-03-usbnet-ipheth-add-CDC-NCM-support.patch @@ -0,0 +1,326 @@ +From a2d274c62e44b1995c170595db3865c6fe701226 Mon Sep 17 00:00:00 2001 +From: Foster Snowhill +Date: Wed, 7 Jun 2023 15:57:01 +0200 +Subject: [PATCH 3/4] usbnet: ipheth: add CDC NCM support + +Recent iOS releases support CDC NCM encapsulation on RX. This mode is +the default on macOS and Windows. In this mode, an iOS device may include +one or more Ethernet frames inside a single URB. + +Freshly booted iOS devices start in legacy mode, but are put into +NCM mode by the official Apple driver. When reconnecting such a device +from a macOS/Windows machine to a Linux host, the device stays in +NCM mode, making it unusable with the legacy ipheth driver code. + +To correctly support such a device, the driver has to either support +the NCM mode too, or put the device back into legacy mode. + +To match the behaviour of the macOS/Windows driver, and since there +is no documented control command to revert to legacy mode, implement +NCM support. The device is attempted to be put into NCM mode by default, +and falls back to legacy mode if the attempt fails. + +Signed-off-by: Foster Snowhill +Tested-by: Georgi Valkov +Signed-off-by: David S. Miller +--- + drivers/net/usb/ipheth.c | 180 +++++++++++++++++++++++++++++++++------ + 1 file changed, 155 insertions(+), 25 deletions(-) + +--- a/drivers/net/usb/ipheth.c ++++ b/drivers/net/usb/ipheth.c +@@ -52,6 +52,7 @@ + #include + #include + #include ++#include + + #define USB_VENDOR_APPLE 0x05ac + +@@ -59,8 +60,12 @@ + #define IPHETH_USBINTF_SUBCLASS 253 + #define IPHETH_USBINTF_PROTO 1 + +-#define IPHETH_BUF_SIZE 1514 + #define IPHETH_IP_ALIGN 2 /* padding at front of URB */ ++#define IPHETH_NCM_HEADER_SIZE (12 + 96) /* NCMH + NCM0 */ ++#define IPHETH_TX_BUF_SIZE ETH_FRAME_LEN ++#define IPHETH_RX_BUF_SIZE_LEGACY (IPHETH_IP_ALIGN + ETH_FRAME_LEN) ++#define IPHETH_RX_BUF_SIZE_NCM 65536 ++ + #define IPHETH_TX_TIMEOUT (5 * HZ) + + #define IPHETH_INTFNUM 2 +@@ -71,6 +76,7 @@ + #define IPHETH_CTRL_TIMEOUT (5 * HZ) + + #define IPHETH_CMD_GET_MACADDR 0x00 ++#define IPHETH_CMD_ENABLE_NCM 0x04 + #define IPHETH_CMD_CARRIER_CHECK 0x45 + + #define IPHETH_CARRIER_CHECK_TIMEOUT round_jiffies_relative(1 * HZ) +@@ -97,6 +103,8 @@ struct ipheth_device { + u8 bulk_out; + struct delayed_work carrier_work; + bool confirmed_pairing; ++ int (*rcvbulk_callback)(struct urb *urb); ++ size_t rx_buf_len; + }; + + static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags); +@@ -116,12 +124,12 @@ static int ipheth_alloc_urbs(struct iphe + if (rx_urb == NULL) + goto free_tx_urb; + +- tx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE, ++ tx_buf = usb_alloc_coherent(iphone->udev, IPHETH_TX_BUF_SIZE, + GFP_KERNEL, &tx_urb->transfer_dma); + if (tx_buf == NULL) + goto free_rx_urb; + +- rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN, ++ rx_buf = usb_alloc_coherent(iphone->udev, iphone->rx_buf_len, + GFP_KERNEL, &rx_urb->transfer_dma); + if (rx_buf == NULL) + goto free_tx_buf; +@@ -134,7 +142,7 @@ static int ipheth_alloc_urbs(struct iphe + return 0; + + free_tx_buf: +- usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, tx_buf, ++ usb_free_coherent(iphone->udev, IPHETH_TX_BUF_SIZE, tx_buf, + tx_urb->transfer_dma); + free_rx_urb: + usb_free_urb(rx_urb); +@@ -146,9 +154,9 @@ error_nomem: + + static void ipheth_free_urbs(struct ipheth_device *iphone) + { +- usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN, iphone->rx_buf, ++ usb_free_coherent(iphone->udev, iphone->rx_buf_len, iphone->rx_buf, + iphone->rx_urb->transfer_dma); +- usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf, ++ usb_free_coherent(iphone->udev, IPHETH_TX_BUF_SIZE, iphone->tx_buf, + iphone->tx_urb->transfer_dma); + usb_free_urb(iphone->rx_urb); + usb_free_urb(iphone->tx_urb); +@@ -160,15 +168,106 @@ static void ipheth_kill_urbs(struct iphe + usb_kill_urb(dev->rx_urb); + } + +-static void ipheth_rcvbulk_callback(struct urb *urb) ++static int ipheth_consume_skb(char *buf, int len, struct ipheth_device *dev) + { +- struct ipheth_device *dev; + struct sk_buff *skb; +- int status; ++ ++ skb = dev_alloc_skb(len); ++ if (!skb) { ++ dev->net->stats.rx_dropped++; ++ return -ENOMEM; ++ } ++ ++ skb_put_data(skb, buf, len); ++ skb->dev = dev->net; ++ skb->protocol = eth_type_trans(skb, dev->net); ++ ++ dev->net->stats.rx_packets++; ++ dev->net->stats.rx_bytes += len; ++ netif_rx(skb); ++ ++ return 0; ++} ++ ++static int ipheth_rcvbulk_callback_legacy(struct urb *urb) ++{ ++ struct ipheth_device *dev; ++ char *buf; ++ int len; ++ ++ dev = urb->context; ++ ++ if (urb->actual_length <= IPHETH_IP_ALIGN) { ++ dev->net->stats.rx_length_errors++; ++ return -EINVAL; ++ } ++ len = urb->actual_length - IPHETH_IP_ALIGN; ++ buf = urb->transfer_buffer + IPHETH_IP_ALIGN; ++ ++ return ipheth_consume_skb(buf, len, dev); ++} ++ ++static int ipheth_rcvbulk_callback_ncm(struct urb *urb) ++{ ++ struct usb_cdc_ncm_nth16 *ncmh; ++ struct usb_cdc_ncm_ndp16 *ncm0; ++ struct usb_cdc_ncm_dpe16 *dpe; ++ struct ipheth_device *dev; ++ int retval = -EINVAL; + char *buf; + int len; + + dev = urb->context; ++ ++ if (urb->actual_length < IPHETH_NCM_HEADER_SIZE) { ++ dev->net->stats.rx_length_errors++; ++ return retval; ++ } ++ ++ ncmh = urb->transfer_buffer; ++ if (ncmh->dwSignature != cpu_to_le32(USB_CDC_NCM_NTH16_SIGN) || ++ le16_to_cpu(ncmh->wNdpIndex) >= urb->actual_length) { ++ dev->net->stats.rx_errors++; ++ return retval; ++ } ++ ++ ncm0 = urb->transfer_buffer + le16_to_cpu(ncmh->wNdpIndex); ++ if (ncm0->dwSignature != cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN) || ++ le16_to_cpu(ncmh->wHeaderLength) + le16_to_cpu(ncm0->wLength) >= ++ urb->actual_length) { ++ dev->net->stats.rx_errors++; ++ return retval; ++ } ++ ++ dpe = ncm0->dpe16; ++ while (le16_to_cpu(dpe->wDatagramIndex) != 0 && ++ le16_to_cpu(dpe->wDatagramLength) != 0) { ++ if (le16_to_cpu(dpe->wDatagramIndex) >= urb->actual_length || ++ le16_to_cpu(dpe->wDatagramIndex) + ++ le16_to_cpu(dpe->wDatagramLength) > urb->actual_length) { ++ dev->net->stats.rx_length_errors++; ++ return retval; ++ } ++ ++ buf = urb->transfer_buffer + le16_to_cpu(dpe->wDatagramIndex); ++ len = le16_to_cpu(dpe->wDatagramLength); ++ ++ retval = ipheth_consume_skb(buf, len, dev); ++ if (retval != 0) ++ return retval; ++ ++ dpe++; ++ } ++ ++ return 0; ++} ++ ++static void ipheth_rcvbulk_callback(struct urb *urb) ++{ ++ struct ipheth_device *dev; ++ int retval, status; ++ ++ dev = urb->context; + if (dev == NULL) + return; + +@@ -191,25 +290,27 @@ static void ipheth_rcvbulk_callback(stru + dev->net->stats.rx_length_errors++; + return; + } +- len = urb->actual_length - IPHETH_IP_ALIGN; +- buf = urb->transfer_buffer + IPHETH_IP_ALIGN; + +- skb = dev_alloc_skb(len); +- if (!skb) { +- dev_err(&dev->intf->dev, "%s: dev_alloc_skb: -ENOMEM\n", +- __func__); +- dev->net->stats.rx_dropped++; ++ /* RX URBs starting with 0x00 0x01 do not encapsulate Ethernet frames, ++ * but rather are control frames. Their purpose is not documented, and ++ * they don't affect driver functionality, okay to drop them. ++ * There is usually just one 4-byte control frame as the very first ++ * URB received from the bulk IN endpoint. ++ */ ++ if (unlikely ++ (((char *)urb->transfer_buffer)[0] == 0 && ++ ((char *)urb->transfer_buffer)[1] == 1)) ++ goto rx_submit; ++ ++ retval = dev->rcvbulk_callback(urb); ++ if (retval != 0) { ++ dev_err(&dev->intf->dev, "%s: callback retval: %d\n", ++ __func__, retval); + return; + } + +- skb_put_data(skb, buf, len); +- skb->dev = dev->net; +- skb->protocol = eth_type_trans(skb, dev->net); +- +- dev->net->stats.rx_packets++; +- dev->net->stats.rx_bytes += len; ++rx_submit: + dev->confirmed_pairing = true; +- netif_rx(skb); + ipheth_rx_submit(dev, GFP_ATOMIC); + } + +@@ -310,6 +411,27 @@ static int ipheth_get_macaddr(struct iph + return retval; + } + ++static int ipheth_enable_ncm(struct ipheth_device *dev) ++{ ++ struct usb_device *udev = dev->udev; ++ int retval; ++ ++ retval = usb_control_msg(udev, ++ usb_sndctrlpipe(udev, IPHETH_CTRL_ENDP), ++ IPHETH_CMD_ENABLE_NCM, /* request */ ++ 0x41, /* request type */ ++ 0x00, /* value */ ++ 0x02, /* index */ ++ NULL, ++ 0, ++ IPHETH_CTRL_TIMEOUT); ++ ++ dev_info(&dev->intf->dev, "%s: usb_control_msg: %d\n", ++ __func__, retval); ++ ++ return retval; ++} ++ + static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags) + { + struct usb_device *udev = dev->udev; +@@ -317,7 +439,7 @@ static int ipheth_rx_submit(struct iphet + + usb_fill_bulk_urb(dev->rx_urb, udev, + usb_rcvbulkpipe(udev, dev->bulk_in), +- dev->rx_buf, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN, ++ dev->rx_buf, dev->rx_buf_len, + ipheth_rcvbulk_callback, + dev); + dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; +@@ -365,7 +487,7 @@ static netdev_tx_t ipheth_tx(struct sk_b + int retval; + + /* Paranoid */ +- if (skb->len > IPHETH_BUF_SIZE) { ++ if (skb->len > IPHETH_TX_BUF_SIZE) { + WARN(1, "%s: skb too large: %d bytes\n", __func__, skb->len); + dev->net->stats.tx_dropped++; + dev_kfree_skb_any(skb); +@@ -448,6 +570,8 @@ static int ipheth_probe(struct usb_inter + dev->net = netdev; + dev->intf = intf; + dev->confirmed_pairing = false; ++ dev->rx_buf_len = IPHETH_RX_BUF_SIZE_LEGACY; ++ dev->rcvbulk_callback = ipheth_rcvbulk_callback_legacy; + /* Set up endpoints */ + hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM); + if (hintf == NULL) { +@@ -479,6 +603,12 @@ static int ipheth_probe(struct usb_inter + if (retval) + goto err_get_macaddr; + ++ retval = ipheth_enable_ncm(dev); ++ if (!retval) { ++ dev->rx_buf_len = IPHETH_RX_BUF_SIZE_NCM; ++ dev->rcvbulk_callback = ipheth_rcvbulk_callback_ncm; ++ } ++ + INIT_DELAYED_WORK(&dev->carrier_work, ipheth_carrier_check_work); + + retval = ipheth_alloc_urbs(dev); diff --git a/target/linux/generic/backport-6.1/796-v6.5-04-usbnet-ipheth-update-Kconfig-description.patch b/target/linux/generic/backport-6.1/796-v6.5-04-usbnet-ipheth-update-Kconfig-description.patch new file mode 100644 index 0000000000..9089c4d8c3 --- /dev/null +++ b/target/linux/generic/backport-6.1/796-v6.5-04-usbnet-ipheth-update-Kconfig-description.patch @@ -0,0 +1,36 @@ +From 0c6e9d32ef0ccfcf2d875cbcff23bf345a54d585 Mon Sep 17 00:00:00 2001 +From: Foster Snowhill +Date: Wed, 7 Jun 2023 15:57:02 +0200 +Subject: [PATCH 4/4] usbnet: ipheth: update Kconfig description + +This module has for a long time not been limited to iPhone <= 3GS. +Update description to match the actual state of the driver. + +Remove dead link from 2010, instead reference an existing userspace +iOS device pairing implementation as part of libimobiledevice. + +Signed-off-by: Foster Snowhill +Signed-off-by: David S. Miller +--- + drivers/net/usb/Kconfig | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +--- a/drivers/net/usb/Kconfig ++++ b/drivers/net/usb/Kconfig +@@ -583,12 +583,10 @@ config USB_IPHETH + default n + help + Module used to share Internet connection (tethering) from your +- iPhone (Original, 3G and 3GS) to your system. +- Note that you need userspace libraries and programs that are needed +- to pair your device with your system and that understand the iPhone +- protocol. +- +- For more information: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver ++ iPhone to your system. ++ Note that you need a corresponding userspace library/program ++ to pair your device with your system, for example usbmuxd ++ . + + config USB_SIERRA_NET + tristate "USB-to-WWAN Driver for Sierra Wireless modems"