wlan-ap: fix tethering driver

This commit is contained in:
GL.iNet-Xinfa.Deng 2022-04-06 20:11:03 +08:00
parent d1a8080dcb
commit afbeb5f69f

View File

@ -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;