History

usbnet: ipheth: prevent TX queue timeouts when device not ready

iOS devices require the host to be "trusted" before servicing network packets. Establishing trust requires the user to confirm a dialog on the iOS device.Until trust is established, the iOS device will silently discard network packets from the host. Currently, the ipheth driver does not detect whether an iOS device has established trust with the host, and immediately sets up the transmit queues. This causes the following problems: - Kernel taint due to WARN() in netdev watchdog. - Dmesg spam ("TX timeout"). - Disruption of user space networking activity (dhcpd, etc...) when new interface comes up but cannot be used. - Unnecessary host and device wakeups and USB traffic Example dmesg output: [ 1101.319778] NETDEV WATCHDOG: eth1 (ipheth): transmit queue 0 timed out [ 1101.319817] ------------[ cut here ]------------ [ 1101.319828] WARNING: CPU: 0 PID: 0 at net/sched/sch_generic.c:316 dev_watchdog+0x20f/0x220 [ 1101.319831] Modules linked in: ipheth usbmon nvidia_drm(PO) nvidia_modeset(PO) nvidia(PO) iwlmvm mac80211 iwlwifi btusb btrtl btbcm btintel qmi_wwan bluetooth cfg80211 ecdh_generic thinkpad_acpi rfkill [last unloaded: ipheth] [ 1101.319861] CPU: 0 PID: 0 Comm: swapper/0 Tainted: P O 4.13.12.1 #1 [ 1101.319864] Hardware name: LENOVO 20ENCTO1WW/20ENCTO1WW, BIOS N1EET62W (1.35 ) 11/10/2016 [ 1101.319867] task: ffffffff81e11500 task.stack: ffffffff81e00000 [ 1101.319873] RIP: 0010:dev_watchdog+0x20f/0x220 [ 1101.319876] RSP: 0018:ffff8810a3c03e98 EFLAGS: 00010292 [ 1101.319880] RAX: 000000000000003a RBX: 0000000000000000 RCX: 0000000000000000 [ 1101.319883] RDX: ffff8810a3c15c48 RSI: ffffffff81ccbfc2 RDI: 00000000ffffffff [ 1101.319886] RBP: ffff880c04ebc41c R08: 0000000000000000 R09: 0000000000000379 [ 1101.319889] R10: 00000100696589d0 R11: 0000000000000378 R12: ffff880c04ebc000 [ 1101.319892] R13: 0000000000000000 R14: 0000000000000001 R15: ffff880c2865fc80 [ 1101.319896] FS: 0000000000000000(0000) GS:ffff8810a3c00000(0000) knlGS:0000000000000000 [ 1101.319899] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 1101.319902] CR2: 00007f3ff24ac000 CR3: 0000000001e0a000 CR4: 00000000003406f0 [ 1101.319905] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 1101.319908] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 1101.319910] Call Trace: [ 1101.319914] <IRQ> [ 1101.319921] ? dev_graft_qdisc+0x70/0x70 [ 1101.319928] ? dev_graft_qdisc+0x70/0x70 [ 1101.319934] ? call_timer_fn+0x2e/0x170 [ 1101.319939] ? dev_graft_qdisc+0x70/0x70 [ 1101.319944] ? run_timer_softirq+0x1ea/0x440 [ 1101.319951] ? timerqueue_add+0x54/0x80 [ 1101.319956] ? enqueue_hrtimer+0x38/0xa0 [ 1101.319963] ? __do_softirq+0xed/0x2e7 [ 1101.319970] ? irq_exit+0xb4/0xc0 [ 1101.319976] ? smp_apic_timer_interrupt+0x39/0x50 [ 1101.319981] ? apic_timer_interrupt+0x8c/0xa0 [ 1101.319983] </IRQ> [ 1101.319992] ? cpuidle_enter_state+0xfa/0x2a0 [ 1101.319999] ? do_idle+0x1a3/0x1f0 [ 1101.320004] ? cpu_startup_entry+0x5f/0x70 [ 1101.320011] ? start_kernel+0x444/0x44c [ 1101.320017] ? early_idt_handler_array+0x120/0x120 [ 1101.320023] ? x86_64_start_kernel+0x145/0x154 [ 1101.320028] ? secondary_startup_64+0x9f/0x9f [ 1101.320033] Code: 20 04 00 00 eb 9f 4c 89 e7 c6 05 59 44 71 00 01 e8 a7 df fd ff 89 d9 4c 89 e6 48 c7 c7 70 b7 cd 81 48 89 c2 31 c0 e8 97 64 90 ff <0f> ff eb bf 66 66 66 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 [ 1101.320103] ---[ end trace 0cc4d251e2b57080 ]--- [ 1101.320110] ipheth 1-5:4.2: ipheth_tx_timeout: TX timeout The last message "TX timeout" is repeated every 5 seconds until trust is established or the device is disconnected, filling up dmesg. The proposed patch eliminates the problem by, upon connection, keeping the TX queue and carrier disabled until a packet is first received from the iOS device. This is reflected by the confirmed_pairing variable in the device structure. Only after at least one packet has been received from the iOS device, the transmit queue and carrier are brought up during the periodic device poll in ipheth_carrier_set. Because the iOS device will always send a packet immediately upon trust being established, this should not delay the interface becoming useable. To prevent failed UBRs in ipheth_rcvbulk_callback from perpetually re-enabling the queue if it was disabled, a new check is added so only successful transfers re-enable the queue, whereas failed transfers only trigger an immediate poll. This has the added benefit of removing the periodic control requests to the iOS device until trust has been established and thus should reduce wakeup events on both the host and the iOS device.

Alexander Kappner committed 9 years ago

Commit bb1b40c1 parent feb88921 file · +21 −9Browse files

Unified · Split

drivers/net/usb/ipheth.c+21−9
@@ -149,6 +149,7 @@ struct ipheth_device { · 148 unmodified lines
149 u8 bulk_in;149 u8 bulk_in;
150 u8 bulk_out;150 u8 bulk_out;
151 struct delayed_work carrier_work;151 struct delayed_work carrier_work;
152 bool confirmed_pairing;
152};153};
153 154
154static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags);155static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags);
@@ -259,7 +260,7 @@ static void ipheth_rcvbulk_callback(struct urb *urb) · 104 unmodified lines
259 260
260 dev->net->stats.rx_packets++;261 dev->net->stats.rx_packets++;
261 dev->net->stats.rx_bytes += len;262 dev->net->stats.rx_bytes += len;
262 263 dev->confirmed_pairing = true;
263 netif_rx(skb);264 netif_rx(skb);
264 ipheth_rx_submit(dev, GFP_ATOMIC);265 ipheth_rx_submit(dev, GFP_ATOMIC);
265}266}
@@ -281,14 +282,21 @@ static void ipheth_sndbulk_callback(struct urb *urb) · 15 unmodified lines
281 __func__, status);282 __func__, status);
282 283
283 dev_kfree_skb_irq(dev->tx_skb);284 dev_kfree_skb_irq(dev->tx_skb);
284 netif_wake_queue(dev->net);285 if (status == 0)
286 netif_wake_queue(dev->net);
287 else
288 // on URB error, trigger immediate poll
289 schedule_delayed_work(&dev->carrier_work, 0);
285}290}
286 291
287static int ipheth_carrier_set(struct ipheth_device *dev)292static int ipheth_carrier_set(struct ipheth_device *dev)
288{293{
289 struct usb_device *udev = dev->udev;294 struct usb_device *udev = dev->udev;
290 int retval;295 int retval;
291 296 if (!dev)
297 return 0;
298 if (!dev->confirmed_pairing)
299 return 0;
292 retval = usb_control_msg(udev,300 retval = usb_control_msg(udev,
293 usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP),301 usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP),
294 IPHETH_CMD_CARRIER_CHECK, /* request */302 IPHETH_CMD_CARRIER_CHECK, /* request */
@@ -303,11 +311,14 @@ static int ipheth_carrier_set(struct ipheth_device *dev) · 8 unmodified lines
303 return retval;311 return retval;
304 }312 }
305 313
306 if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON)314 if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON) {
307 netif_carrier_on(dev->net);315 netif_carrier_on(dev->net);
308 else316 if (dev->tx_urb->status != -EINPROGRESS)
317 netif_wake_queue(dev->net);
318 } else {
309 netif_carrier_off(dev->net);319 netif_carrier_off(dev->net);
310 320 netif_stop_queue(dev->net);
321 }
311 return 0;322 return 0;
312}323}
313 324
@@ -387,7 +398,6 @@ static int ipheth_open(struct net_device *net) · 73 unmodified lines
387 return retval;398 return retval;
388 399
389 schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT);400 schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT);
390 netif_start_queue(net);
391 return retval;401 return retval;
392}402}
393 403
@@ -491,7 +501,7 @@ static int ipheth_probe(struct usb_interface *intf, · 97 unmodified lines
491 dev->udev = udev;501 dev->udev = udev;
492 dev->net = netdev;502 dev->net = netdev;
493 dev->intf = intf;503 dev->intf = intf;
494 504 dev->confirmed_pairing = false;
495 /* Set up endpoints */505 /* Set up endpoints */
496 hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM);506 hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM);
497 if (hintf == NULL) {507 if (hintf == NULL) {
@@ -542,7 +552,9 @@ static int ipheth_probe(struct usb_interface *intf, · 44 unmodified lines
542 retval = -EIO;552 retval = -EIO;
543 goto err_register_netdev;553 goto err_register_netdev;
544 }554 }
545 555 // carrier down and transmit queues stopped until packet from device
556 netif_carrier_off(netdev);
557 netif_tx_stop_all_queues(netdev);
546 dev_info(&intf->dev, "Apple iPhone USB Ethernet device attached\n");558 dev_info(&intf->dev, "Apple iPhone USB Ethernet device attached\n");
547 return 0;559 return 0;
548 560