diff --git a/files-wlan-ap/openwrt/target/linux/ipq807x/patches/201-fix-tethering-ipheth.patch b/files-wlan-ap/openwrt/target/linux/ipq807x/patches/201-fix-tethering-ipheth.patch index b2b4de0..2b43b13 100644 --- a/files-wlan-ap/openwrt/target/linux/ipq807x/patches/201-fix-tethering-ipheth.patch +++ b/files-wlan-ap/openwrt/target/linux/ipq807x/patches/201-fix-tethering-ipheth.patch @@ -9,3 +9,185 @@ #define IPHETH_IP_ALIGN 2 /* padding at front of URB */ #define IPHETH_TX_TIMEOUT (5 * HZ) +@@ -87,7 +87,7 @@ + #define IPHETH_CARRIER_CHECK_TIMEOUT round_jiffies_relative(1 * HZ) + #define IPHETH_CARRIER_ON 0x04 + +-static struct usb_device_id ipheth_table[] = { ++static const struct usb_device_id ipheth_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO( + USB_VENDOR_APPLE, USB_PRODUCT_IPHONE, + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, +@@ -140,7 +140,6 @@ struct ipheth_device { + struct usb_device *udev; + struct usb_interface *intf; + struct net_device *net; +- struct sk_buff *tx_skb; + struct urb *tx_urb; + struct urb *rx_urb; + unsigned char *tx_buf; +@@ -149,6 +148,8 @@ struct ipheth_device { + u8 bulk_in; + u8 bulk_out; + struct delayed_work carrier_work; ++ bool confirmed_pairing; ++ int tx_in_use; + }; + + static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags); +@@ -229,6 +230,7 @@ static void ipheth_rcvbulk_callback(stru + case -ENOENT: + case -ECONNRESET: + case -ESHUTDOWN: ++ case -EPROTO: + return; + case 0: + break; +@@ -253,13 +255,13 @@ static void ipheth_rcvbulk_callback(stru + return; + } + +- memcpy(skb_put(skb, len), buf, len); ++ 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; +- ++ dev->confirmed_pairing = true; + netif_rx(skb); + ipheth_rx_submit(dev, GFP_ATOMIC); + } +@@ -280,15 +282,26 @@ static void ipheth_sndbulk_callback(stru + dev_err(&dev->intf->dev, "%s: urb status: %d\n", + __func__, status); + +- dev_kfree_skb_irq(dev->tx_skb); +- netif_wake_queue(dev->net); ++ dev->tx_in_use = false; ++ ++ if (status == 0) ++ netif_wake_queue(dev->net); ++ else ++ // on URB error, trigger immediate poll ++ schedule_delayed_work(&dev->carrier_work, 0); + } + + static int ipheth_carrier_set(struct ipheth_device *dev) + { +- struct usb_device *udev = dev->udev; ++ struct usb_device *udev; + int retval; + ++ if (!dev) ++ return 0; ++ if (!dev->confirmed_pairing) ++ return 0; ++ ++ udev = dev->udev; + retval = usb_control_msg(udev, + usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP), + IPHETH_CMD_CARRIER_CHECK, /* request */ +@@ -303,11 +316,14 @@ static int ipheth_carrier_set(struct iph + return retval; + } + +- if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON) ++ if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON) { + netif_carrier_on(dev->net); +- else ++ if (dev->tx_urb->status != -EINPROGRESS && dev->tx_in_use == false) ++ netif_wake_queue(dev->net); ++ } else { + netif_carrier_off(dev->net); +- ++ netif_stop_queue(dev->net); ++ } + return 0; + } + +@@ -376,6 +392,8 @@ static int ipheth_open(struct net_device + struct usb_device *udev = dev->udev; + int retval = 0; + ++ dev->tx_in_use = false; ++ + usb_set_interface(udev, IPHETH_INTFNUM, IPHETH_ALT_INTFNUM); + + retval = ipheth_carrier_set(dev); +@@ -387,7 +405,6 @@ static int ipheth_open(struct net_device + return retval; + + schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT); +- netif_start_queue(net); + return retval; + } + +@@ -410,10 +427,18 @@ static int ipheth_tx(struct sk_buff *skb + if (skb->len > IPHETH_BUF_SIZE) { + WARN(1, "%s: skb too large: %d bytes\n", __func__, skb->len); + dev->net->stats.tx_dropped++; +- dev_kfree_skb_irq(skb); ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++ } ++ ++ if (dev->tx_in_use) { ++ dev->net->stats.tx_dropped++; ++ dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + ++ dev->tx_in_use = true; ++ + 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); +@@ -425,18 +450,22 @@ static int ipheth_tx(struct sk_buff *skb + dev); + dev->tx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + ++ netif_stop_queue(net); + retval = usb_submit_urb(dev->tx_urb, GFP_ATOMIC); + if (retval) { + dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n", + __func__, retval); + dev->net->stats.tx_errors++; +- dev_kfree_skb_irq(skb); ++ dev_kfree_skb_any(skb); ++ netif_wake_queue(net); ++ if (atomic_read(&dev->tx_urb->use_count) != 0) { ++ atomic_dec(&dev->tx_urb->use_count); ++ } ++ dev->tx_in_use = false; + } else { +- dev->tx_skb = skb; +- + dev->net->stats.tx_packets++; + dev->net->stats.tx_bytes += skb->len; +- netif_stop_queue(net); ++ dev_consume_skb_any(skb); + } + + return NETDEV_TX_OK; +@@ -491,7 +520,7 @@ static int ipheth_probe(struct usb_inter + dev->udev = udev; + dev->net = netdev; + dev->intf = intf; +- ++ dev->confirmed_pairing = false; + /* Set up endpoints */ + hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM); + if (hintf == NULL) { +@@ -542,7 +571,9 @@ static int ipheth_probe(struct usb_inter + retval = -EIO; + goto err_register_netdev; + } +- ++ // carrier down and transmit queues stopped until packet from device ++ netif_carrier_off(netdev); ++ netif_tx_stop_all_queues(netdev); + dev_info(&intf->dev, "Apple iPhone USB Ethernet device attached\n"); + return 0; +