2010-04-18 16:35:16 +08:00
|
|
|
/*
|
|
|
|
* ipheth.c - Apple iPhone USB Ethernet driver
|
|
|
|
*
|
|
|
|
* Copyright (c) 2009 Diego Giagio <diego@giagio.com>
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of GIAGIO.COM nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* Alternatively, provided that this notice is retained in full, this
|
|
|
|
* software may be distributed under the terms of the GNU General
|
|
|
|
* Public License ("GPL") version 2, in which case the provisions of the
|
|
|
|
* GPL apply INSTEAD OF those given above.
|
|
|
|
*
|
|
|
|
* The provided data structures and external interfaces from this code
|
|
|
|
* are not restricted to be used by modules with a GPL compatible license.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
|
|
* DAMAGE.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Attention: iPhone device must be paired, otherwise it won't respond to our
|
|
|
|
* driver. For more info: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/netdevice.h>
|
|
|
|
#include <linux/etherdevice.h>
|
|
|
|
#include <linux/ethtool.h>
|
|
|
|
#include <linux/usb.h>
|
|
|
|
#include <linux/workqueue.h>
|
|
|
|
|
|
|
|
#define USB_VENDOR_APPLE 0x05ac
|
|
|
|
#define USB_PRODUCT_IPHONE 0x1290
|
|
|
|
#define USB_PRODUCT_IPHONE_3G 0x1292
|
|
|
|
#define USB_PRODUCT_IPHONE_3GS 0x1294
|
2010-08-23 18:39:29 +08:00
|
|
|
#define USB_PRODUCT_IPHONE_4 0x1297
|
2012-06-25 15:04:47 +08:00
|
|
|
#define USB_PRODUCT_IPAD 0x129a
|
2014-05-30 18:17:00 +08:00
|
|
|
#define USB_PRODUCT_IPAD_2 0x12a2
|
|
|
|
#define USB_PRODUCT_IPAD_3 0x12a6
|
2013-07-02 06:00:06 +08:00
|
|
|
#define USB_PRODUCT_IPAD_MINI 0x12ab
|
2011-08-31 13:12:05 +08:00
|
|
|
#define USB_PRODUCT_IPHONE_4_VZW 0x129c
|
2012-02-15 15:50:15 +08:00
|
|
|
#define USB_PRODUCT_IPHONE_4S 0x12a0
|
2012-10-14 15:07:21 +08:00
|
|
|
#define USB_PRODUCT_IPHONE_5 0x12a8
|
2010-04-18 16:35:16 +08:00
|
|
|
|
|
|
|
#define IPHETH_USBINTF_CLASS 255
|
|
|
|
#define IPHETH_USBINTF_SUBCLASS 253
|
|
|
|
#define IPHETH_USBINTF_PROTO 1
|
|
|
|
|
|
|
|
#define IPHETH_BUF_SIZE 1516
|
2011-05-03 15:49:25 +08:00
|
|
|
#define IPHETH_IP_ALIGN 2 /* padding at front of URB */
|
2010-04-18 16:35:16 +08:00
|
|
|
#define IPHETH_TX_TIMEOUT (5 * HZ)
|
|
|
|
|
|
|
|
#define IPHETH_INTFNUM 2
|
|
|
|
#define IPHETH_ALT_INTFNUM 1
|
|
|
|
|
|
|
|
#define IPHETH_CTRL_ENDP 0x00
|
|
|
|
#define IPHETH_CTRL_BUF_SIZE 0x40
|
|
|
|
#define IPHETH_CTRL_TIMEOUT (5 * HZ)
|
|
|
|
|
|
|
|
#define IPHETH_CMD_GET_MACADDR 0x00
|
|
|
|
#define IPHETH_CMD_CARRIER_CHECK 0x45
|
|
|
|
|
|
|
|
#define IPHETH_CARRIER_CHECK_TIMEOUT round_jiffies_relative(1 * HZ)
|
|
|
|
#define IPHETH_CARRIER_ON 0x04
|
|
|
|
|
2017-08-08 23:58:03 +08:00
|
|
|
static const struct usb_device_id ipheth_table[] = {
|
2010-04-18 16:35:16 +08:00
|
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(
|
|
|
|
USB_VENDOR_APPLE, USB_PRODUCT_IPHONE,
|
|
|
|
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
|
|
|
|
IPHETH_USBINTF_PROTO) },
|
|
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(
|
|
|
|
USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_3G,
|
|
|
|
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
|
|
|
|
IPHETH_USBINTF_PROTO) },
|
|
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(
|
|
|
|
USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_3GS,
|
|
|
|
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
|
|
|
|
IPHETH_USBINTF_PROTO) },
|
2010-08-23 18:39:29 +08:00
|
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(
|
|
|
|
USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4,
|
|
|
|
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
|
|
|
|
IPHETH_USBINTF_PROTO) },
|
2012-06-25 15:04:47 +08:00
|
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(
|
|
|
|
USB_VENDOR_APPLE, USB_PRODUCT_IPAD,
|
|
|
|
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
|
2014-05-30 18:17:00 +08:00
|
|
|
IPHETH_USBINTF_PROTO) },
|
|
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(
|
|
|
|
USB_VENDOR_APPLE, USB_PRODUCT_IPAD_2,
|
|
|
|
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
|
|
|
|
IPHETH_USBINTF_PROTO) },
|
|
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(
|
|
|
|
USB_VENDOR_APPLE, USB_PRODUCT_IPAD_3,
|
|
|
|
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
|
2012-06-25 15:04:47 +08:00
|
|
|
IPHETH_USBINTF_PROTO) },
|
2013-07-02 06:00:06 +08:00
|
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(
|
|
|
|
USB_VENDOR_APPLE, USB_PRODUCT_IPAD_MINI,
|
|
|
|
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
|
|
|
|
IPHETH_USBINTF_PROTO) },
|
2011-08-31 13:12:05 +08:00
|
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(
|
|
|
|
USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4_VZW,
|
|
|
|
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
|
|
|
|
IPHETH_USBINTF_PROTO) },
|
2012-02-15 15:50:15 +08:00
|
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(
|
|
|
|
USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4S,
|
|
|
|
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
|
|
|
|
IPHETH_USBINTF_PROTO) },
|
2012-10-14 15:07:21 +08:00
|
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(
|
|
|
|
USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_5,
|
|
|
|
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
|
|
|
|
IPHETH_USBINTF_PROTO) },
|
2010-04-18 16:35:16 +08:00
|
|
|
{ }
|
|
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(usb, ipheth_table);
|
|
|
|
|
|
|
|
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;
|
|
|
|
unsigned char *rx_buf;
|
|
|
|
unsigned char *ctrl_buf;
|
|
|
|
u8 bulk_in;
|
|
|
|
u8 bulk_out;
|
|
|
|
struct delayed_work carrier_work;
|
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.
Signed-off-by: Alexander Kappner <agk@godking.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-14 09:44:20 +08:00
|
|
|
bool confirmed_pairing;
|
2010-04-18 16:35:16 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags);
|
|
|
|
|
|
|
|
static int ipheth_alloc_urbs(struct ipheth_device *iphone)
|
|
|
|
{
|
|
|
|
struct urb *tx_urb = NULL;
|
|
|
|
struct urb *rx_urb = NULL;
|
|
|
|
u8 *tx_buf = NULL;
|
|
|
|
u8 *rx_buf = NULL;
|
|
|
|
|
|
|
|
tx_urb = usb_alloc_urb(0, GFP_KERNEL);
|
|
|
|
if (tx_urb == NULL)
|
2010-04-27 07:20:12 +08:00
|
|
|
goto error_nomem;
|
2010-04-18 16:35:16 +08:00
|
|
|
|
|
|
|
rx_urb = usb_alloc_urb(0, GFP_KERNEL);
|
|
|
|
if (rx_urb == NULL)
|
2010-04-27 07:20:12 +08:00
|
|
|
goto free_tx_urb;
|
2010-04-18 16:35:16 +08:00
|
|
|
|
2010-04-12 19:17:25 +08:00
|
|
|
tx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE,
|
|
|
|
GFP_KERNEL, &tx_urb->transfer_dma);
|
2010-04-18 16:35:16 +08:00
|
|
|
if (tx_buf == NULL)
|
2010-04-27 07:20:12 +08:00
|
|
|
goto free_rx_urb;
|
2010-04-18 16:35:16 +08:00
|
|
|
|
2010-04-12 19:17:25 +08:00
|
|
|
rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE,
|
|
|
|
GFP_KERNEL, &rx_urb->transfer_dma);
|
2010-04-18 16:35:16 +08:00
|
|
|
if (rx_buf == NULL)
|
2010-04-27 07:20:12 +08:00
|
|
|
goto free_tx_buf;
|
2010-04-18 16:35:16 +08:00
|
|
|
|
|
|
|
|
|
|
|
iphone->tx_urb = tx_urb;
|
|
|
|
iphone->rx_urb = rx_urb;
|
|
|
|
iphone->tx_buf = tx_buf;
|
|
|
|
iphone->rx_buf = rx_buf;
|
|
|
|
return 0;
|
|
|
|
|
2010-04-27 07:20:12 +08:00
|
|
|
free_tx_buf:
|
2010-04-12 19:17:25 +08:00
|
|
|
usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, tx_buf,
|
|
|
|
tx_urb->transfer_dma);
|
2010-04-27 07:20:12 +08:00
|
|
|
free_rx_urb:
|
2010-04-18 16:35:16 +08:00
|
|
|
usb_free_urb(rx_urb);
|
2010-04-27 07:20:12 +08:00
|
|
|
free_tx_urb:
|
2010-04-18 16:35:16 +08:00
|
|
|
usb_free_urb(tx_urb);
|
2010-04-27 07:20:12 +08:00
|
|
|
error_nomem:
|
2010-04-18 16:35:16 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ipheth_free_urbs(struct ipheth_device *iphone)
|
|
|
|
{
|
2010-04-12 19:17:25 +08:00
|
|
|
usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->rx_buf,
|
|
|
|
iphone->rx_urb->transfer_dma);
|
|
|
|
usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf,
|
|
|
|
iphone->tx_urb->transfer_dma);
|
2010-04-18 16:35:16 +08:00
|
|
|
usb_free_urb(iphone->rx_urb);
|
|
|
|
usb_free_urb(iphone->tx_urb);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ipheth_kill_urbs(struct ipheth_device *dev)
|
|
|
|
{
|
|
|
|
usb_kill_urb(dev->tx_urb);
|
|
|
|
usb_kill_urb(dev->rx_urb);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ipheth_rcvbulk_callback(struct urb *urb)
|
|
|
|
{
|
|
|
|
struct ipheth_device *dev;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
int status;
|
|
|
|
char *buf;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
dev = urb->context;
|
|
|
|
if (dev == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
status = urb->status;
|
|
|
|
switch (status) {
|
|
|
|
case -ENOENT:
|
|
|
|
case -ECONNRESET:
|
|
|
|
case -ESHUTDOWN:
|
|
|
|
return;
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
default:
|
2012-04-26 03:37:48 +08:00
|
|
|
dev_err(&dev->intf->dev, "%s: urb status: %d\n",
|
|
|
|
__func__, status);
|
2010-04-18 16:35:16 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-05-03 15:49:25 +08:00
|
|
|
if (urb->actual_length <= IPHETH_IP_ALIGN) {
|
|
|
|
dev->net->stats.rx_length_errors++;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
len = urb->actual_length - IPHETH_IP_ALIGN;
|
|
|
|
buf = urb->transfer_buffer + IPHETH_IP_ALIGN;
|
2010-04-18 16:35:16 +08:00
|
|
|
|
2011-05-03 15:49:25 +08:00
|
|
|
skb = dev_alloc_skb(len);
|
2010-04-18 16:35:16 +08:00
|
|
|
if (!skb) {
|
2012-04-26 03:37:48 +08:00
|
|
|
dev_err(&dev->intf->dev, "%s: dev_alloc_skb: -ENOMEM\n",
|
|
|
|
__func__);
|
2010-04-18 16:35:16 +08:00
|
|
|
dev->net->stats.rx_dropped++;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
networking: introduce and use skb_put_data()
A common pattern with skb_put() is to just want to memcpy()
some data into the new space, introduce skb_put_data() for
this.
An spatch similar to the one for skb_put_zero() converts many
of the places using it:
@@
identifier p, p2;
expression len, skb, data;
type t, t2;
@@
(
-p = skb_put(skb, len);
+p = skb_put_data(skb, data, len);
|
-p = (t)skb_put(skb, len);
+p = skb_put_data(skb, data, len);
)
(
p2 = (t2)p;
-memcpy(p2, data, len);
|
-memcpy(p, data, len);
)
@@
type t, t2;
identifier p, p2;
expression skb, data;
@@
t *p;
...
(
-p = skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
|
-p = (t *)skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
)
(
p2 = (t2)p;
-memcpy(p2, data, sizeof(*p));
|
-memcpy(p, data, sizeof(*p));
)
@@
expression skb, len, data;
@@
-memcpy(skb_put(skb, len), data, len);
+skb_put_data(skb, data, len);
(again, manually post-processed to retain some comments)
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 20:29:20 +08:00
|
|
|
skb_put_data(skb, buf, len);
|
2010-04-18 16:35:16 +08:00
|
|
|
skb->dev = dev->net;
|
|
|
|
skb->protocol = eth_type_trans(skb, dev->net);
|
|
|
|
|
|
|
|
dev->net->stats.rx_packets++;
|
|
|
|
dev->net->stats.rx_bytes += len;
|
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.
Signed-off-by: Alexander Kappner <agk@godking.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-14 09:44:20 +08:00
|
|
|
dev->confirmed_pairing = true;
|
2010-04-18 16:35:16 +08:00
|
|
|
netif_rx(skb);
|
|
|
|
ipheth_rx_submit(dev, GFP_ATOMIC);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ipheth_sndbulk_callback(struct urb *urb)
|
|
|
|
{
|
|
|
|
struct ipheth_device *dev;
|
2010-07-02 21:51:55 +08:00
|
|
|
int status = urb->status;
|
2010-04-18 16:35:16 +08:00
|
|
|
|
|
|
|
dev = urb->context;
|
|
|
|
if (dev == NULL)
|
|
|
|
return;
|
|
|
|
|
2010-07-02 21:51:55 +08:00
|
|
|
if (status != 0 &&
|
|
|
|
status != -ENOENT &&
|
|
|
|
status != -ECONNRESET &&
|
|
|
|
status != -ESHUTDOWN)
|
2012-04-26 03:37:48 +08:00
|
|
|
dev_err(&dev->intf->dev, "%s: urb status: %d\n",
|
|
|
|
__func__, status);
|
2010-04-18 16:35:16 +08:00
|
|
|
|
|
|
|
dev_kfree_skb_irq(dev->tx_skb);
|
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.
Signed-off-by: Alexander Kappner <agk@godking.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-14 09:44:20 +08:00
|
|
|
if (status == 0)
|
|
|
|
netif_wake_queue(dev->net);
|
|
|
|
else
|
|
|
|
// on URB error, trigger immediate poll
|
|
|
|
schedule_delayed_work(&dev->carrier_work, 0);
|
2010-04-18 16:35:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int ipheth_carrier_set(struct ipheth_device *dev)
|
|
|
|
{
|
|
|
|
struct usb_device *udev = dev->udev;
|
|
|
|
int retval;
|
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.
Signed-off-by: Alexander Kappner <agk@godking.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-14 09:44:20 +08:00
|
|
|
if (!dev)
|
|
|
|
return 0;
|
|
|
|
if (!dev->confirmed_pairing)
|
|
|
|
return 0;
|
2010-04-18 16:35:16 +08:00
|
|
|
retval = usb_control_msg(udev,
|
|
|
|
usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP),
|
|
|
|
IPHETH_CMD_CARRIER_CHECK, /* request */
|
|
|
|
0xc0, /* request type */
|
|
|
|
0x00, /* value */
|
|
|
|
0x02, /* index */
|
|
|
|
dev->ctrl_buf, IPHETH_CTRL_BUF_SIZE,
|
|
|
|
IPHETH_CTRL_TIMEOUT);
|
|
|
|
if (retval < 0) {
|
2012-04-26 03:37:48 +08:00
|
|
|
dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n",
|
|
|
|
__func__, retval);
|
2010-04-18 16:35:16 +08:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
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.
Signed-off-by: Alexander Kappner <agk@godking.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-14 09:44:20 +08:00
|
|
|
if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON) {
|
2010-04-18 16:35:16 +08:00
|
|
|
netif_carrier_on(dev->net);
|
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.
Signed-off-by: Alexander Kappner <agk@godking.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-14 09:44:20 +08:00
|
|
|
if (dev->tx_urb->status != -EINPROGRESS)
|
|
|
|
netif_wake_queue(dev->net);
|
|
|
|
} else {
|
2010-04-18 16:35:16 +08:00
|
|
|
netif_carrier_off(dev->net);
|
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.
Signed-off-by: Alexander Kappner <agk@godking.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-14 09:44:20 +08:00
|
|
|
netif_stop_queue(dev->net);
|
|
|
|
}
|
2010-04-18 16:35:16 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ipheth_carrier_check_work(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct ipheth_device *dev = container_of(work, struct ipheth_device,
|
|
|
|
carrier_work.work);
|
|
|
|
|
|
|
|
ipheth_carrier_set(dev);
|
|
|
|
schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ipheth_get_macaddr(struct ipheth_device *dev)
|
|
|
|
{
|
|
|
|
struct usb_device *udev = dev->udev;
|
|
|
|
struct net_device *net = dev->net;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
retval = usb_control_msg(udev,
|
|
|
|
usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP),
|
|
|
|
IPHETH_CMD_GET_MACADDR, /* request */
|
|
|
|
0xc0, /* request type */
|
|
|
|
0x00, /* value */
|
|
|
|
0x02, /* index */
|
|
|
|
dev->ctrl_buf,
|
|
|
|
IPHETH_CTRL_BUF_SIZE,
|
|
|
|
IPHETH_CTRL_TIMEOUT);
|
|
|
|
if (retval < 0) {
|
2012-04-26 03:37:48 +08:00
|
|
|
dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n",
|
|
|
|
__func__, retval);
|
2010-04-18 16:35:16 +08:00
|
|
|
} else if (retval < ETH_ALEN) {
|
2012-04-26 03:37:48 +08:00
|
|
|
dev_err(&dev->intf->dev,
|
|
|
|
"%s: usb_control_msg: short packet: %d bytes\n",
|
2010-04-18 16:35:16 +08:00
|
|
|
__func__, retval);
|
|
|
|
retval = -EINVAL;
|
|
|
|
} else {
|
|
|
|
memcpy(net->dev_addr, dev->ctrl_buf, ETH_ALEN);
|
|
|
|
retval = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags)
|
|
|
|
{
|
|
|
|
struct usb_device *udev = dev->udev;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
usb_fill_bulk_urb(dev->rx_urb, udev,
|
|
|
|
usb_rcvbulkpipe(udev, dev->bulk_in),
|
|
|
|
dev->rx_buf, IPHETH_BUF_SIZE,
|
|
|
|
ipheth_rcvbulk_callback,
|
|
|
|
dev);
|
|
|
|
dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
|
|
|
|
|
|
|
retval = usb_submit_urb(dev->rx_urb, mem_flags);
|
|
|
|
if (retval)
|
2012-04-26 03:37:48 +08:00
|
|
|
dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n",
|
|
|
|
__func__, retval);
|
2010-04-18 16:35:16 +08:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ipheth_open(struct net_device *net)
|
|
|
|
{
|
|
|
|
struct ipheth_device *dev = netdev_priv(net);
|
|
|
|
struct usb_device *udev = dev->udev;
|
|
|
|
int retval = 0;
|
|
|
|
|
|
|
|
usb_set_interface(udev, IPHETH_INTFNUM, IPHETH_ALT_INTFNUM);
|
|
|
|
|
|
|
|
retval = ipheth_carrier_set(dev);
|
|
|
|
if (retval)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
retval = ipheth_rx_submit(dev, GFP_KERNEL);
|
|
|
|
if (retval)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ipheth_close(struct net_device *net)
|
|
|
|
{
|
|
|
|
struct ipheth_device *dev = netdev_priv(net);
|
|
|
|
|
|
|
|
cancel_delayed_work_sync(&dev->carrier_work);
|
|
|
|
netif_stop_queue(net);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ipheth_tx(struct sk_buff *skb, struct net_device *net)
|
|
|
|
{
|
|
|
|
struct ipheth_device *dev = netdev_priv(net);
|
|
|
|
struct usb_device *udev = dev->udev;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
/* Paranoid */
|
|
|
|
if (skb->len > IPHETH_BUF_SIZE) {
|
2010-10-30 19:08:34 +08:00
|
|
|
WARN(1, "%s: skb too large: %d bytes\n", __func__, skb->len);
|
2010-04-18 16:35:16 +08:00
|
|
|
dev->net->stats.tx_dropped++;
|
|
|
|
dev_kfree_skb_irq(skb);
|
|
|
|
return NETDEV_TX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
ipheth_sndbulk_callback,
|
|
|
|
dev);
|
|
|
|
dev->tx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
|
|
|
|
|
|
|
retval = usb_submit_urb(dev->tx_urb, GFP_ATOMIC);
|
|
|
|
if (retval) {
|
2012-04-26 03:37:48 +08:00
|
|
|
dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n",
|
|
|
|
__func__, retval);
|
2010-04-18 16:35:16 +08:00
|
|
|
dev->net->stats.tx_errors++;
|
|
|
|
dev_kfree_skb_irq(skb);
|
|
|
|
} else {
|
|
|
|
dev->tx_skb = skb;
|
|
|
|
|
|
|
|
dev->net->stats.tx_packets++;
|
|
|
|
dev->net->stats.tx_bytes += skb->len;
|
|
|
|
netif_stop_queue(net);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NETDEV_TX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ipheth_tx_timeout(struct net_device *net)
|
|
|
|
{
|
|
|
|
struct ipheth_device *dev = netdev_priv(net);
|
|
|
|
|
2012-04-26 03:37:48 +08:00
|
|
|
dev_err(&dev->intf->dev, "%s: TX timeout\n", __func__);
|
2010-04-18 16:35:16 +08:00
|
|
|
dev->net->stats.tx_errors++;
|
|
|
|
usb_unlink_urb(dev->tx_urb);
|
|
|
|
}
|
|
|
|
|
|
|
|
static u32 ipheth_ethtool_op_get_link(struct net_device *net)
|
|
|
|
{
|
|
|
|
struct ipheth_device *dev = netdev_priv(net);
|
|
|
|
return netif_carrier_ok(dev->net);
|
|
|
|
}
|
|
|
|
|
2012-01-06 03:10:23 +08:00
|
|
|
static const struct ethtool_ops ops = {
|
2010-04-18 16:35:16 +08:00
|
|
|
.get_link = ipheth_ethtool_op_get_link
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct net_device_ops ipheth_netdev_ops = {
|
2011-06-08 16:09:13 +08:00
|
|
|
.ndo_open = ipheth_open,
|
|
|
|
.ndo_stop = ipheth_close,
|
|
|
|
.ndo_start_xmit = ipheth_tx,
|
|
|
|
.ndo_tx_timeout = ipheth_tx_timeout,
|
2010-04-18 16:35:16 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static int ipheth_probe(struct usb_interface *intf,
|
|
|
|
const struct usb_device_id *id)
|
|
|
|
{
|
|
|
|
struct usb_device *udev = interface_to_usbdev(intf);
|
|
|
|
struct usb_host_interface *hintf;
|
|
|
|
struct usb_endpoint_descriptor *endp;
|
|
|
|
struct ipheth_device *dev;
|
|
|
|
struct net_device *netdev;
|
|
|
|
int i;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
netdev = alloc_etherdev(sizeof(struct ipheth_device));
|
|
|
|
if (!netdev)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
netdev->netdev_ops = &ipheth_netdev_ops;
|
|
|
|
netdev->watchdog_timeo = IPHETH_TX_TIMEOUT;
|
2010-09-08 15:50:47 +08:00
|
|
|
strcpy(netdev->name, "eth%d");
|
2010-04-18 16:35:16 +08:00
|
|
|
|
|
|
|
dev = netdev_priv(netdev);
|
|
|
|
dev->udev = udev;
|
|
|
|
dev->net = netdev;
|
|
|
|
dev->intf = intf;
|
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.
Signed-off-by: Alexander Kappner <agk@godking.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-14 09:44:20 +08:00
|
|
|
dev->confirmed_pairing = false;
|
2010-04-18 16:35:16 +08:00
|
|
|
/* Set up endpoints */
|
|
|
|
hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM);
|
|
|
|
if (hintf == NULL) {
|
|
|
|
retval = -ENODEV;
|
2012-04-26 03:37:48 +08:00
|
|
|
dev_err(&intf->dev, "Unable to find alternate settings interface\n");
|
2010-04-18 16:35:16 +08:00
|
|
|
goto err_endpoints;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < hintf->desc.bNumEndpoints; i++) {
|
|
|
|
endp = &hintf->endpoint[i].desc;
|
|
|
|
if (usb_endpoint_is_bulk_in(endp))
|
|
|
|
dev->bulk_in = endp->bEndpointAddress;
|
|
|
|
else if (usb_endpoint_is_bulk_out(endp))
|
|
|
|
dev->bulk_out = endp->bEndpointAddress;
|
|
|
|
}
|
|
|
|
if (!(dev->bulk_in && dev->bulk_out)) {
|
|
|
|
retval = -ENODEV;
|
2012-04-26 03:37:48 +08:00
|
|
|
dev_err(&intf->dev, "Unable to find endpoints\n");
|
2010-04-18 16:35:16 +08:00
|
|
|
goto err_endpoints;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev->ctrl_buf = kmalloc(IPHETH_CTRL_BUF_SIZE, GFP_KERNEL);
|
|
|
|
if (dev->ctrl_buf == NULL) {
|
|
|
|
retval = -ENOMEM;
|
|
|
|
goto err_alloc_ctrl_buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = ipheth_get_macaddr(dev);
|
|
|
|
if (retval)
|
|
|
|
goto err_get_macaddr;
|
|
|
|
|
|
|
|
INIT_DELAYED_WORK(&dev->carrier_work, ipheth_carrier_check_work);
|
|
|
|
|
|
|
|
retval = ipheth_alloc_urbs(dev);
|
|
|
|
if (retval) {
|
2012-04-26 03:37:48 +08:00
|
|
|
dev_err(&intf->dev, "error allocating urbs: %d\n", retval);
|
2010-04-18 16:35:16 +08:00
|
|
|
goto err_alloc_urbs;
|
|
|
|
}
|
|
|
|
|
|
|
|
usb_set_intfdata(intf, dev);
|
|
|
|
|
|
|
|
SET_NETDEV_DEV(netdev, &intf->dev);
|
2014-05-11 08:12:32 +08:00
|
|
|
netdev->ethtool_ops = &ops;
|
2010-04-18 16:35:16 +08:00
|
|
|
|
|
|
|
retval = register_netdev(netdev);
|
|
|
|
if (retval) {
|
2012-04-26 03:37:48 +08:00
|
|
|
dev_err(&intf->dev, "error registering netdev: %d\n", retval);
|
2010-04-18 16:35:16 +08:00
|
|
|
retval = -EIO;
|
|
|
|
goto err_register_netdev;
|
|
|
|
}
|
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.
Signed-off-by: Alexander Kappner <agk@godking.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-14 09:44:20 +08:00
|
|
|
// carrier down and transmit queues stopped until packet from device
|
|
|
|
netif_carrier_off(netdev);
|
|
|
|
netif_tx_stop_all_queues(netdev);
|
2010-04-18 16:35:16 +08:00
|
|
|
dev_info(&intf->dev, "Apple iPhone USB Ethernet device attached\n");
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_register_netdev:
|
|
|
|
ipheth_free_urbs(dev);
|
|
|
|
err_alloc_urbs:
|
|
|
|
err_get_macaddr:
|
|
|
|
err_alloc_ctrl_buf:
|
|
|
|
kfree(dev->ctrl_buf);
|
|
|
|
err_endpoints:
|
|
|
|
free_netdev(netdev);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ipheth_disconnect(struct usb_interface *intf)
|
|
|
|
{
|
|
|
|
struct ipheth_device *dev;
|
|
|
|
|
|
|
|
dev = usb_get_intfdata(intf);
|
|
|
|
if (dev != NULL) {
|
|
|
|
unregister_netdev(dev->net);
|
|
|
|
ipheth_kill_urbs(dev);
|
|
|
|
ipheth_free_urbs(dev);
|
|
|
|
kfree(dev->ctrl_buf);
|
|
|
|
free_netdev(dev->net);
|
|
|
|
}
|
|
|
|
usb_set_intfdata(intf, NULL);
|
|
|
|
dev_info(&intf->dev, "Apple iPhone USB Ethernet now disconnected\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct usb_driver ipheth_driver = {
|
|
|
|
.name = "ipheth",
|
|
|
|
.probe = ipheth_probe,
|
|
|
|
.disconnect = ipheth_disconnect,
|
|
|
|
.id_table = ipheth_table,
|
2012-04-24 01:08:51 +08:00
|
|
|
.disable_hub_initiated_lpm = 1,
|
2010-04-18 16:35:16 +08:00
|
|
|
};
|
|
|
|
|
2011-11-19 01:44:20 +08:00
|
|
|
module_usb_driver(ipheth_driver);
|
2010-04-18 16:35:16 +08:00
|
|
|
|
|
|
|
MODULE_AUTHOR("Diego Giagio <diego@giagio.com>");
|
|
|
|
MODULE_DESCRIPTION("Apple iPhone USB Ethernet driver");
|
|
|
|
MODULE_LICENSE("Dual BSD/GPL");
|