cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ipheth.c (14448B)


      1/*
      2 * ipheth.c - Apple iPhone USB Ethernet driver
      3 *
      4 * Copyright (c) 2009 Diego Giagio <diego@giagio.com>
      5 * All rights reserved.
      6 *
      7 * Redistribution and use in source and binary forms, with or without
      8 * modification, are permitted provided that the following conditions
      9 * are met:
     10 * 1. Redistributions of source code must retain the above copyright
     11 *    notice, this list of conditions and the following disclaimer.
     12 * 2. Redistributions in binary form must reproduce the above copyright
     13 *    notice, this list of conditions and the following disclaimer in the
     14 *    documentation and/or other materials provided with the distribution.
     15 * 3. Neither the name of GIAGIO.COM nor the names of its contributors
     16 *    may be used to endorse or promote products derived from this software
     17 *    without specific prior written permission.
     18 *
     19 * Alternatively, provided that this notice is retained in full, this
     20 * software may be distributed under the terms of the GNU General
     21 * Public License ("GPL") version 2, in which case the provisions of the
     22 * GPL apply INSTEAD OF those given above.
     23 *
     24 * The provided data structures and external interfaces from this code
     25 * are not restricted to be used by modules with a GPL compatible license.
     26 *
     27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     31 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     32 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     33 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     37 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
     38 * DAMAGE.
     39 *
     40 *
     41 * Attention: iPhone device must be paired, otherwise it won't respond to our
     42 * driver. For more info: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver
     43 *
     44 */
     45
     46#include <linux/kernel.h>
     47#include <linux/errno.h>
     48#include <linux/slab.h>
     49#include <linux/module.h>
     50#include <linux/netdevice.h>
     51#include <linux/etherdevice.h>
     52#include <linux/ethtool.h>
     53#include <linux/usb.h>
     54#include <linux/workqueue.h>
     55
     56#define USB_VENDOR_APPLE        0x05ac
     57
     58#define IPHETH_USBINTF_CLASS    255
     59#define IPHETH_USBINTF_SUBCLASS 253
     60#define IPHETH_USBINTF_PROTO    1
     61
     62#define IPHETH_BUF_SIZE         1514
     63#define IPHETH_IP_ALIGN		2	/* padding at front of URB */
     64#define IPHETH_TX_TIMEOUT       (5 * HZ)
     65
     66#define IPHETH_INTFNUM          2
     67#define IPHETH_ALT_INTFNUM      1
     68
     69#define IPHETH_CTRL_ENDP        0x00
     70#define IPHETH_CTRL_BUF_SIZE    0x40
     71#define IPHETH_CTRL_TIMEOUT     (5 * HZ)
     72
     73#define IPHETH_CMD_GET_MACADDR   0x00
     74#define IPHETH_CMD_CARRIER_CHECK 0x45
     75
     76#define IPHETH_CARRIER_CHECK_TIMEOUT round_jiffies_relative(1 * HZ)
     77#define IPHETH_CARRIER_ON       0x04
     78
     79static const struct usb_device_id ipheth_table[] = {
     80	{ USB_VENDOR_AND_INTERFACE_INFO(USB_VENDOR_APPLE, IPHETH_USBINTF_CLASS,
     81					IPHETH_USBINTF_SUBCLASS,
     82					IPHETH_USBINTF_PROTO) },
     83	{ }
     84};
     85MODULE_DEVICE_TABLE(usb, ipheth_table);
     86
     87struct ipheth_device {
     88	struct usb_device *udev;
     89	struct usb_interface *intf;
     90	struct net_device *net;
     91	struct urb *tx_urb;
     92	struct urb *rx_urb;
     93	unsigned char *tx_buf;
     94	unsigned char *rx_buf;
     95	unsigned char *ctrl_buf;
     96	u8 bulk_in;
     97	u8 bulk_out;
     98	struct delayed_work carrier_work;
     99	bool confirmed_pairing;
    100};
    101
    102static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags);
    103
    104static int ipheth_alloc_urbs(struct ipheth_device *iphone)
    105{
    106	struct urb *tx_urb = NULL;
    107	struct urb *rx_urb = NULL;
    108	u8 *tx_buf = NULL;
    109	u8 *rx_buf = NULL;
    110
    111	tx_urb = usb_alloc_urb(0, GFP_KERNEL);
    112	if (tx_urb == NULL)
    113		goto error_nomem;
    114
    115	rx_urb = usb_alloc_urb(0, GFP_KERNEL);
    116	if (rx_urb == NULL)
    117		goto free_tx_urb;
    118
    119	tx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE,
    120				    GFP_KERNEL, &tx_urb->transfer_dma);
    121	if (tx_buf == NULL)
    122		goto free_rx_urb;
    123
    124	rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN,
    125				    GFP_KERNEL, &rx_urb->transfer_dma);
    126	if (rx_buf == NULL)
    127		goto free_tx_buf;
    128
    129
    130	iphone->tx_urb = tx_urb;
    131	iphone->rx_urb = rx_urb;
    132	iphone->tx_buf = tx_buf;
    133	iphone->rx_buf = rx_buf;
    134	return 0;
    135
    136free_tx_buf:
    137	usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, tx_buf,
    138			  tx_urb->transfer_dma);
    139free_rx_urb:
    140	usb_free_urb(rx_urb);
    141free_tx_urb:
    142	usb_free_urb(tx_urb);
    143error_nomem:
    144	return -ENOMEM;
    145}
    146
    147static void ipheth_free_urbs(struct ipheth_device *iphone)
    148{
    149	usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN, iphone->rx_buf,
    150			  iphone->rx_urb->transfer_dma);
    151	usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf,
    152			  iphone->tx_urb->transfer_dma);
    153	usb_free_urb(iphone->rx_urb);
    154	usb_free_urb(iphone->tx_urb);
    155}
    156
    157static void ipheth_kill_urbs(struct ipheth_device *dev)
    158{
    159	usb_kill_urb(dev->tx_urb);
    160	usb_kill_urb(dev->rx_urb);
    161}
    162
    163static void ipheth_rcvbulk_callback(struct urb *urb)
    164{
    165	struct ipheth_device *dev;
    166	struct sk_buff *skb;
    167	int status;
    168	char *buf;
    169	int len;
    170
    171	dev = urb->context;
    172	if (dev == NULL)
    173		return;
    174
    175	status = urb->status;
    176	switch (status) {
    177	case -ENOENT:
    178	case -ECONNRESET:
    179	case -ESHUTDOWN:
    180	case -EPROTO:
    181		return;
    182	case 0:
    183		break;
    184	default:
    185		dev_err(&dev->intf->dev, "%s: urb status: %d\n",
    186			__func__, status);
    187		return;
    188	}
    189
    190	if (urb->actual_length <= IPHETH_IP_ALIGN) {
    191		dev->net->stats.rx_length_errors++;
    192		return;
    193	}
    194	len = urb->actual_length - IPHETH_IP_ALIGN;
    195	buf = urb->transfer_buffer + IPHETH_IP_ALIGN;
    196
    197	skb = dev_alloc_skb(len);
    198	if (!skb) {
    199		dev_err(&dev->intf->dev, "%s: dev_alloc_skb: -ENOMEM\n",
    200			__func__);
    201		dev->net->stats.rx_dropped++;
    202		return;
    203	}
    204
    205	skb_put_data(skb, buf, len);
    206	skb->dev = dev->net;
    207	skb->protocol = eth_type_trans(skb, dev->net);
    208
    209	dev->net->stats.rx_packets++;
    210	dev->net->stats.rx_bytes += len;
    211	dev->confirmed_pairing = true;
    212	netif_rx(skb);
    213	ipheth_rx_submit(dev, GFP_ATOMIC);
    214}
    215
    216static void ipheth_sndbulk_callback(struct urb *urb)
    217{
    218	struct ipheth_device *dev;
    219	int status = urb->status;
    220
    221	dev = urb->context;
    222	if (dev == NULL)
    223		return;
    224
    225	if (status != 0 &&
    226	    status != -ENOENT &&
    227	    status != -ECONNRESET &&
    228	    status != -ESHUTDOWN)
    229		dev_err(&dev->intf->dev, "%s: urb status: %d\n",
    230		__func__, status);
    231
    232	if (status == 0)
    233		netif_wake_queue(dev->net);
    234	else
    235		// on URB error, trigger immediate poll
    236		schedule_delayed_work(&dev->carrier_work, 0);
    237}
    238
    239static int ipheth_carrier_set(struct ipheth_device *dev)
    240{
    241	struct usb_device *udev;
    242	int retval;
    243
    244	if (!dev->confirmed_pairing)
    245		return 0;
    246
    247	udev = dev->udev;
    248	retval = usb_control_msg(udev,
    249			usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP),
    250			IPHETH_CMD_CARRIER_CHECK, /* request */
    251			0xc0, /* request type */
    252			0x00, /* value */
    253			0x02, /* index */
    254			dev->ctrl_buf, IPHETH_CTRL_BUF_SIZE,
    255			IPHETH_CTRL_TIMEOUT);
    256	if (retval < 0) {
    257		dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n",
    258			__func__, retval);
    259		return retval;
    260	}
    261
    262	if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON) {
    263		netif_carrier_on(dev->net);
    264		if (dev->tx_urb->status != -EINPROGRESS)
    265			netif_wake_queue(dev->net);
    266	} else {
    267		netif_carrier_off(dev->net);
    268		netif_stop_queue(dev->net);
    269	}
    270	return 0;
    271}
    272
    273static void ipheth_carrier_check_work(struct work_struct *work)
    274{
    275	struct ipheth_device *dev = container_of(work, struct ipheth_device,
    276						 carrier_work.work);
    277
    278	ipheth_carrier_set(dev);
    279	schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT);
    280}
    281
    282static int ipheth_get_macaddr(struct ipheth_device *dev)
    283{
    284	struct usb_device *udev = dev->udev;
    285	struct net_device *net = dev->net;
    286	int retval;
    287
    288	retval = usb_control_msg(udev,
    289				 usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP),
    290				 IPHETH_CMD_GET_MACADDR, /* request */
    291				 0xc0, /* request type */
    292				 0x00, /* value */
    293				 0x02, /* index */
    294				 dev->ctrl_buf,
    295				 IPHETH_CTRL_BUF_SIZE,
    296				 IPHETH_CTRL_TIMEOUT);
    297	if (retval < 0) {
    298		dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n",
    299			__func__, retval);
    300	} else if (retval < ETH_ALEN) {
    301		dev_err(&dev->intf->dev,
    302			"%s: usb_control_msg: short packet: %d bytes\n",
    303			__func__, retval);
    304		retval = -EINVAL;
    305	} else {
    306		eth_hw_addr_set(net, dev->ctrl_buf);
    307		retval = 0;
    308	}
    309
    310	return retval;
    311}
    312
    313static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags)
    314{
    315	struct usb_device *udev = dev->udev;
    316	int retval;
    317
    318	usb_fill_bulk_urb(dev->rx_urb, udev,
    319			  usb_rcvbulkpipe(udev, dev->bulk_in),
    320			  dev->rx_buf, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN,
    321			  ipheth_rcvbulk_callback,
    322			  dev);
    323	dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
    324
    325	retval = usb_submit_urb(dev->rx_urb, mem_flags);
    326	if (retval)
    327		dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n",
    328			__func__, retval);
    329	return retval;
    330}
    331
    332static int ipheth_open(struct net_device *net)
    333{
    334	struct ipheth_device *dev = netdev_priv(net);
    335	struct usb_device *udev = dev->udev;
    336	int retval = 0;
    337
    338	usb_set_interface(udev, IPHETH_INTFNUM, IPHETH_ALT_INTFNUM);
    339
    340	retval = ipheth_carrier_set(dev);
    341	if (retval)
    342		return retval;
    343
    344	retval = ipheth_rx_submit(dev, GFP_KERNEL);
    345	if (retval)
    346		return retval;
    347
    348	schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT);
    349	return retval;
    350}
    351
    352static int ipheth_close(struct net_device *net)
    353{
    354	struct ipheth_device *dev = netdev_priv(net);
    355
    356	cancel_delayed_work_sync(&dev->carrier_work);
    357	netif_stop_queue(net);
    358	return 0;
    359}
    360
    361static netdev_tx_t ipheth_tx(struct sk_buff *skb, struct net_device *net)
    362{
    363	struct ipheth_device *dev = netdev_priv(net);
    364	struct usb_device *udev = dev->udev;
    365	int retval;
    366
    367	/* Paranoid */
    368	if (skb->len > IPHETH_BUF_SIZE) {
    369		WARN(1, "%s: skb too large: %d bytes\n", __func__, skb->len);
    370		dev->net->stats.tx_dropped++;
    371		dev_kfree_skb_any(skb);
    372		return NETDEV_TX_OK;
    373	}
    374
    375	memcpy(dev->tx_buf, skb->data, skb->len);
    376	if (skb->len < IPHETH_BUF_SIZE)
    377		memset(dev->tx_buf + skb->len, 0, IPHETH_BUF_SIZE - skb->len);
    378
    379	usb_fill_bulk_urb(dev->tx_urb, udev,
    380			  usb_sndbulkpipe(udev, dev->bulk_out),
    381			  dev->tx_buf, IPHETH_BUF_SIZE,
    382			  ipheth_sndbulk_callback,
    383			  dev);
    384	dev->tx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
    385
    386	netif_stop_queue(net);
    387	retval = usb_submit_urb(dev->tx_urb, GFP_ATOMIC);
    388	if (retval) {
    389		dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n",
    390			__func__, retval);
    391		dev->net->stats.tx_errors++;
    392		dev_kfree_skb_any(skb);
    393		netif_wake_queue(net);
    394	} else {
    395		dev->net->stats.tx_packets++;
    396		dev->net->stats.tx_bytes += skb->len;
    397		dev_consume_skb_any(skb);
    398	}
    399
    400	return NETDEV_TX_OK;
    401}
    402
    403static void ipheth_tx_timeout(struct net_device *net, unsigned int txqueue)
    404{
    405	struct ipheth_device *dev = netdev_priv(net);
    406
    407	dev_err(&dev->intf->dev, "%s: TX timeout\n", __func__);
    408	dev->net->stats.tx_errors++;
    409	usb_unlink_urb(dev->tx_urb);
    410}
    411
    412static u32 ipheth_ethtool_op_get_link(struct net_device *net)
    413{
    414	struct ipheth_device *dev = netdev_priv(net);
    415	return netif_carrier_ok(dev->net);
    416}
    417
    418static const struct ethtool_ops ops = {
    419	.get_link = ipheth_ethtool_op_get_link
    420};
    421
    422static const struct net_device_ops ipheth_netdev_ops = {
    423	.ndo_open = ipheth_open,
    424	.ndo_stop = ipheth_close,
    425	.ndo_start_xmit = ipheth_tx,
    426	.ndo_tx_timeout = ipheth_tx_timeout,
    427};
    428
    429static int ipheth_probe(struct usb_interface *intf,
    430			const struct usb_device_id *id)
    431{
    432	struct usb_device *udev = interface_to_usbdev(intf);
    433	struct usb_host_interface *hintf;
    434	struct usb_endpoint_descriptor *endp;
    435	struct ipheth_device *dev;
    436	struct net_device *netdev;
    437	int i;
    438	int retval;
    439
    440	netdev = alloc_etherdev(sizeof(struct ipheth_device));
    441	if (!netdev)
    442		return -ENOMEM;
    443
    444	netdev->netdev_ops = &ipheth_netdev_ops;
    445	netdev->watchdog_timeo = IPHETH_TX_TIMEOUT;
    446	strscpy(netdev->name, "eth%d", sizeof(netdev->name));
    447
    448	dev = netdev_priv(netdev);
    449	dev->udev = udev;
    450	dev->net = netdev;
    451	dev->intf = intf;
    452	dev->confirmed_pairing = false;
    453	/* Set up endpoints */
    454	hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM);
    455	if (hintf == NULL) {
    456		retval = -ENODEV;
    457		dev_err(&intf->dev, "Unable to find alternate settings interface\n");
    458		goto err_endpoints;
    459	}
    460
    461	for (i = 0; i < hintf->desc.bNumEndpoints; i++) {
    462		endp = &hintf->endpoint[i].desc;
    463		if (usb_endpoint_is_bulk_in(endp))
    464			dev->bulk_in = endp->bEndpointAddress;
    465		else if (usb_endpoint_is_bulk_out(endp))
    466			dev->bulk_out = endp->bEndpointAddress;
    467	}
    468	if (!(dev->bulk_in && dev->bulk_out)) {
    469		retval = -ENODEV;
    470		dev_err(&intf->dev, "Unable to find endpoints\n");
    471		goto err_endpoints;
    472	}
    473
    474	dev->ctrl_buf = kmalloc(IPHETH_CTRL_BUF_SIZE, GFP_KERNEL);
    475	if (dev->ctrl_buf == NULL) {
    476		retval = -ENOMEM;
    477		goto err_alloc_ctrl_buf;
    478	}
    479
    480	retval = ipheth_get_macaddr(dev);
    481	if (retval)
    482		goto err_get_macaddr;
    483
    484	INIT_DELAYED_WORK(&dev->carrier_work, ipheth_carrier_check_work);
    485
    486	retval = ipheth_alloc_urbs(dev);
    487	if (retval) {
    488		dev_err(&intf->dev, "error allocating urbs: %d\n", retval);
    489		goto err_alloc_urbs;
    490	}
    491
    492	usb_set_intfdata(intf, dev);
    493
    494	SET_NETDEV_DEV(netdev, &intf->dev);
    495	netdev->ethtool_ops = &ops;
    496
    497	retval = register_netdev(netdev);
    498	if (retval) {
    499		dev_err(&intf->dev, "error registering netdev: %d\n", retval);
    500		retval = -EIO;
    501		goto err_register_netdev;
    502	}
    503	// carrier down and transmit queues stopped until packet from device
    504	netif_carrier_off(netdev);
    505	netif_tx_stop_all_queues(netdev);
    506	dev_info(&intf->dev, "Apple iPhone USB Ethernet device attached\n");
    507	return 0;
    508
    509err_register_netdev:
    510	ipheth_free_urbs(dev);
    511err_alloc_urbs:
    512err_get_macaddr:
    513err_alloc_ctrl_buf:
    514	kfree(dev->ctrl_buf);
    515err_endpoints:
    516	free_netdev(netdev);
    517	return retval;
    518}
    519
    520static void ipheth_disconnect(struct usb_interface *intf)
    521{
    522	struct ipheth_device *dev;
    523
    524	dev = usb_get_intfdata(intf);
    525	if (dev != NULL) {
    526		unregister_netdev(dev->net);
    527		ipheth_kill_urbs(dev);
    528		ipheth_free_urbs(dev);
    529		kfree(dev->ctrl_buf);
    530		free_netdev(dev->net);
    531	}
    532	usb_set_intfdata(intf, NULL);
    533	dev_info(&intf->dev, "Apple iPhone USB Ethernet now disconnected\n");
    534}
    535
    536static struct usb_driver ipheth_driver = {
    537	.name =		"ipheth",
    538	.probe =	ipheth_probe,
    539	.disconnect =	ipheth_disconnect,
    540	.id_table =	ipheth_table,
    541	.disable_hub_initiated_lpm = 1,
    542};
    543
    544module_usb_driver(ipheth_driver);
    545
    546MODULE_AUTHOR("Diego Giagio <diego@giagio.com>");
    547MODULE_DESCRIPTION("Apple iPhone USB Ethernet driver");
    548MODULE_LICENSE("Dual BSD/GPL");