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

cdc-phonet.c (10149B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * phonet.c -- USB CDC Phonet host driver
      4 *
      5 * Copyright (C) 2008-2009 Nokia Corporation. All rights reserved.
      6 *
      7 * Author: RĂ©mi Denis-Courmont
      8 */
      9
     10#include <linux/kernel.h>
     11#include <linux/mm.h>
     12#include <linux/module.h>
     13#include <linux/gfp.h>
     14#include <linux/usb.h>
     15#include <linux/usb/cdc.h>
     16#include <linux/netdevice.h>
     17#include <linux/if_arp.h>
     18#include <linux/if_phonet.h>
     19#include <linux/phonet.h>
     20
     21#define PN_MEDIA_USB	0x1B
     22
     23static const unsigned rxq_size = 17;
     24
     25struct usbpn_dev {
     26	struct net_device	*dev;
     27
     28	struct usb_interface	*intf, *data_intf;
     29	struct usb_device	*usb;
     30	unsigned int		tx_pipe, rx_pipe;
     31	u8 active_setting;
     32	u8 disconnected;
     33
     34	unsigned		tx_queue;
     35	spinlock_t		tx_lock;
     36
     37	spinlock_t		rx_lock;
     38	struct sk_buff		*rx_skb;
     39	struct urb		*urbs[];
     40};
     41
     42static void tx_complete(struct urb *req);
     43static void rx_complete(struct urb *req);
     44
     45/*
     46 * Network device callbacks
     47 */
     48static netdev_tx_t usbpn_xmit(struct sk_buff *skb, struct net_device *dev)
     49{
     50	struct usbpn_dev *pnd = netdev_priv(dev);
     51	struct urb *req = NULL;
     52	unsigned long flags;
     53	int err;
     54
     55	if (skb->protocol != htons(ETH_P_PHONET))
     56		goto drop;
     57
     58	req = usb_alloc_urb(0, GFP_ATOMIC);
     59	if (!req)
     60		goto drop;
     61	usb_fill_bulk_urb(req, pnd->usb, pnd->tx_pipe, skb->data, skb->len,
     62				tx_complete, skb);
     63	req->transfer_flags = URB_ZERO_PACKET;
     64	err = usb_submit_urb(req, GFP_ATOMIC);
     65	if (err) {
     66		usb_free_urb(req);
     67		goto drop;
     68	}
     69
     70	spin_lock_irqsave(&pnd->tx_lock, flags);
     71	pnd->tx_queue++;
     72	if (pnd->tx_queue >= dev->tx_queue_len)
     73		netif_stop_queue(dev);
     74	spin_unlock_irqrestore(&pnd->tx_lock, flags);
     75	return NETDEV_TX_OK;
     76
     77drop:
     78	dev_kfree_skb(skb);
     79	dev->stats.tx_dropped++;
     80	return NETDEV_TX_OK;
     81}
     82
     83static void tx_complete(struct urb *req)
     84{
     85	struct sk_buff *skb = req->context;
     86	struct net_device *dev = skb->dev;
     87	struct usbpn_dev *pnd = netdev_priv(dev);
     88	int status = req->status;
     89	unsigned long flags;
     90
     91	switch (status) {
     92	case 0:
     93		dev->stats.tx_bytes += skb->len;
     94		break;
     95
     96	case -ENOENT:
     97	case -ECONNRESET:
     98	case -ESHUTDOWN:
     99		dev->stats.tx_aborted_errors++;
    100		fallthrough;
    101	default:
    102		dev->stats.tx_errors++;
    103		dev_dbg(&dev->dev, "TX error (%d)\n", status);
    104	}
    105	dev->stats.tx_packets++;
    106
    107	spin_lock_irqsave(&pnd->tx_lock, flags);
    108	pnd->tx_queue--;
    109	netif_wake_queue(dev);
    110	spin_unlock_irqrestore(&pnd->tx_lock, flags);
    111
    112	dev_kfree_skb_any(skb);
    113	usb_free_urb(req);
    114}
    115
    116static int rx_submit(struct usbpn_dev *pnd, struct urb *req, gfp_t gfp_flags)
    117{
    118	struct net_device *dev = pnd->dev;
    119	struct page *page;
    120	int err;
    121
    122	page = __dev_alloc_page(gfp_flags | __GFP_NOMEMALLOC);
    123	if (!page)
    124		return -ENOMEM;
    125
    126	usb_fill_bulk_urb(req, pnd->usb, pnd->rx_pipe, page_address(page),
    127				PAGE_SIZE, rx_complete, dev);
    128	req->transfer_flags = 0;
    129	err = usb_submit_urb(req, gfp_flags);
    130	if (unlikely(err)) {
    131		dev_dbg(&dev->dev, "RX submit error (%d)\n", err);
    132		put_page(page);
    133	}
    134	return err;
    135}
    136
    137static void rx_complete(struct urb *req)
    138{
    139	struct net_device *dev = req->context;
    140	struct usbpn_dev *pnd = netdev_priv(dev);
    141	struct page *page = virt_to_page(req->transfer_buffer);
    142	struct sk_buff *skb;
    143	unsigned long flags;
    144	int status = req->status;
    145
    146	switch (status) {
    147	case 0:
    148		spin_lock_irqsave(&pnd->rx_lock, flags);
    149		skb = pnd->rx_skb;
    150		if (!skb) {
    151			skb = pnd->rx_skb = netdev_alloc_skb(dev, 12);
    152			if (likely(skb)) {
    153				/* Can't use pskb_pull() on page in IRQ */
    154				skb_put_data(skb, page_address(page), 1);
    155				skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
    156						page, 1, req->actual_length,
    157						PAGE_SIZE);
    158				page = NULL;
    159			}
    160		} else {
    161			skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
    162					page, 0, req->actual_length,
    163					PAGE_SIZE);
    164			page = NULL;
    165		}
    166		if (req->actual_length < PAGE_SIZE)
    167			pnd->rx_skb = NULL; /* Last fragment */
    168		else
    169			skb = NULL;
    170		spin_unlock_irqrestore(&pnd->rx_lock, flags);
    171		if (skb) {
    172			skb->protocol = htons(ETH_P_PHONET);
    173			skb_reset_mac_header(skb);
    174			__skb_pull(skb, 1);
    175			skb->dev = dev;
    176			dev->stats.rx_packets++;
    177			dev->stats.rx_bytes += skb->len;
    178
    179			netif_rx(skb);
    180		}
    181		goto resubmit;
    182
    183	case -ENOENT:
    184	case -ECONNRESET:
    185	case -ESHUTDOWN:
    186		req = NULL;
    187		break;
    188
    189	case -EOVERFLOW:
    190		dev->stats.rx_over_errors++;
    191		dev_dbg(&dev->dev, "RX overflow\n");
    192		break;
    193
    194	case -EILSEQ:
    195		dev->stats.rx_crc_errors++;
    196		break;
    197	}
    198
    199	dev->stats.rx_errors++;
    200resubmit:
    201	if (page)
    202		put_page(page);
    203	if (req)
    204		rx_submit(pnd, req, GFP_ATOMIC);
    205}
    206
    207static int usbpn_close(struct net_device *dev);
    208
    209static int usbpn_open(struct net_device *dev)
    210{
    211	struct usbpn_dev *pnd = netdev_priv(dev);
    212	int err;
    213	unsigned i;
    214	unsigned num = pnd->data_intf->cur_altsetting->desc.bInterfaceNumber;
    215
    216	err = usb_set_interface(pnd->usb, num, pnd->active_setting);
    217	if (err)
    218		return err;
    219
    220	for (i = 0; i < rxq_size; i++) {
    221		struct urb *req = usb_alloc_urb(0, GFP_KERNEL);
    222
    223		if (!req || rx_submit(pnd, req, GFP_KERNEL)) {
    224			usb_free_urb(req);
    225			usbpn_close(dev);
    226			return -ENOMEM;
    227		}
    228		pnd->urbs[i] = req;
    229	}
    230
    231	netif_wake_queue(dev);
    232	return 0;
    233}
    234
    235static int usbpn_close(struct net_device *dev)
    236{
    237	struct usbpn_dev *pnd = netdev_priv(dev);
    238	unsigned i;
    239	unsigned num = pnd->data_intf->cur_altsetting->desc.bInterfaceNumber;
    240
    241	netif_stop_queue(dev);
    242
    243	for (i = 0; i < rxq_size; i++) {
    244		struct urb *req = pnd->urbs[i];
    245
    246		if (!req)
    247			continue;
    248		usb_kill_urb(req);
    249		usb_free_urb(req);
    250		pnd->urbs[i] = NULL;
    251	}
    252
    253	return usb_set_interface(pnd->usb, num, !pnd->active_setting);
    254}
    255
    256static int usbpn_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
    257				void __user *data, int cmd)
    258{
    259	struct if_phonet_req *req = (struct if_phonet_req *)ifr;
    260
    261	switch (cmd) {
    262	case SIOCPNGAUTOCONF:
    263		req->ifr_phonet_autoconf.device = PN_DEV_PC;
    264		return 0;
    265	}
    266	return -ENOIOCTLCMD;
    267}
    268
    269static const struct net_device_ops usbpn_ops = {
    270	.ndo_open	= usbpn_open,
    271	.ndo_stop	= usbpn_close,
    272	.ndo_start_xmit = usbpn_xmit,
    273	.ndo_siocdevprivate = usbpn_siocdevprivate,
    274};
    275
    276static void usbpn_setup(struct net_device *dev)
    277{
    278	const u8 addr = PN_MEDIA_USB;
    279
    280	dev->features		= 0;
    281	dev->netdev_ops		= &usbpn_ops;
    282	dev->header_ops		= &phonet_header_ops;
    283	dev->type		= ARPHRD_PHONET;
    284	dev->flags		= IFF_POINTOPOINT | IFF_NOARP;
    285	dev->mtu		= PHONET_MAX_MTU;
    286	dev->min_mtu		= PHONET_MIN_MTU;
    287	dev->max_mtu		= PHONET_MAX_MTU;
    288	dev->hard_header_len	= 1;
    289	dev->addr_len		= 1;
    290	dev_addr_set(dev, &addr);
    291	dev->tx_queue_len	= 3;
    292
    293	dev->needs_free_netdev	= true;
    294}
    295
    296/*
    297 * USB driver callbacks
    298 */
    299static const struct usb_device_id usbpn_ids[] = {
    300	{
    301		.match_flags = USB_DEVICE_ID_MATCH_VENDOR
    302			| USB_DEVICE_ID_MATCH_INT_CLASS
    303			| USB_DEVICE_ID_MATCH_INT_SUBCLASS,
    304		.idVendor = 0x0421, /* Nokia */
    305		.bInterfaceClass = USB_CLASS_COMM,
    306		.bInterfaceSubClass = 0xFE,
    307	},
    308	{ },
    309};
    310
    311MODULE_DEVICE_TABLE(usb, usbpn_ids);
    312
    313static struct usb_driver usbpn_driver;
    314
    315static int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id)
    316{
    317	static const char ifname[] = "usbpn%d";
    318	const struct usb_cdc_union_desc *union_header = NULL;
    319	const struct usb_host_interface *data_desc;
    320	struct usb_interface *data_intf;
    321	struct usb_device *usbdev = interface_to_usbdev(intf);
    322	struct net_device *dev;
    323	struct usbpn_dev *pnd;
    324	u8 *data;
    325	int phonet = 0;
    326	int len, err;
    327	struct usb_cdc_parsed_header hdr;
    328
    329	data = intf->altsetting->extra;
    330	len = intf->altsetting->extralen;
    331	cdc_parse_cdc_header(&hdr, intf, data, len);
    332	union_header = hdr.usb_cdc_union_desc;
    333	phonet = hdr.phonet_magic_present;
    334
    335	if (!union_header || !phonet)
    336		return -EINVAL;
    337
    338	data_intf = usb_ifnum_to_if(usbdev, union_header->bSlaveInterface0);
    339	if (data_intf == NULL)
    340		return -ENODEV;
    341	/* Data interface has one inactive and one active setting */
    342	if (data_intf->num_altsetting != 2)
    343		return -EINVAL;
    344	if (data_intf->altsetting[0].desc.bNumEndpoints == 0 &&
    345	    data_intf->altsetting[1].desc.bNumEndpoints == 2)
    346		data_desc = data_intf->altsetting + 1;
    347	else
    348	if (data_intf->altsetting[0].desc.bNumEndpoints == 2 &&
    349	    data_intf->altsetting[1].desc.bNumEndpoints == 0)
    350		data_desc = data_intf->altsetting;
    351	else
    352		return -EINVAL;
    353
    354	dev = alloc_netdev(struct_size(pnd, urbs, rxq_size), ifname,
    355			   NET_NAME_UNKNOWN, usbpn_setup);
    356	if (!dev)
    357		return -ENOMEM;
    358
    359	pnd = netdev_priv(dev);
    360	SET_NETDEV_DEV(dev, &intf->dev);
    361
    362	pnd->dev = dev;
    363	pnd->usb = usbdev;
    364	pnd->intf = intf;
    365	pnd->data_intf = data_intf;
    366	spin_lock_init(&pnd->tx_lock);
    367	spin_lock_init(&pnd->rx_lock);
    368	/* Endpoints */
    369	if (usb_pipein(data_desc->endpoint[0].desc.bEndpointAddress)) {
    370		pnd->rx_pipe = usb_rcvbulkpipe(usbdev,
    371			data_desc->endpoint[0].desc.bEndpointAddress);
    372		pnd->tx_pipe = usb_sndbulkpipe(usbdev,
    373			data_desc->endpoint[1].desc.bEndpointAddress);
    374	} else {
    375		pnd->rx_pipe = usb_rcvbulkpipe(usbdev,
    376			data_desc->endpoint[1].desc.bEndpointAddress);
    377		pnd->tx_pipe = usb_sndbulkpipe(usbdev,
    378			data_desc->endpoint[0].desc.bEndpointAddress);
    379	}
    380	pnd->active_setting = data_desc - data_intf->altsetting;
    381
    382	err = usb_driver_claim_interface(&usbpn_driver, data_intf, pnd);
    383	if (err)
    384		goto out;
    385
    386	/* Force inactive mode until the network device is brought UP */
    387	usb_set_interface(usbdev, union_header->bSlaveInterface0,
    388				!pnd->active_setting);
    389	usb_set_intfdata(intf, pnd);
    390
    391	err = register_netdev(dev);
    392	if (err) {
    393		/* Set disconnected flag so that disconnect() returns early. */
    394		pnd->disconnected = 1;
    395		usb_driver_release_interface(&usbpn_driver, data_intf);
    396		goto out;
    397	}
    398
    399	dev_dbg(&dev->dev, "USB CDC Phonet device found\n");
    400	return 0;
    401
    402out:
    403	usb_set_intfdata(intf, NULL);
    404	free_netdev(dev);
    405	return err;
    406}
    407
    408static void usbpn_disconnect(struct usb_interface *intf)
    409{
    410	struct usbpn_dev *pnd = usb_get_intfdata(intf);
    411
    412	if (pnd->disconnected)
    413		return;
    414
    415	pnd->disconnected = 1;
    416	usb_driver_release_interface(&usbpn_driver,
    417			(pnd->intf == intf) ? pnd->data_intf : pnd->intf);
    418	unregister_netdev(pnd->dev);
    419}
    420
    421static struct usb_driver usbpn_driver = {
    422	.name =		"cdc_phonet",
    423	.probe =	usbpn_probe,
    424	.disconnect =	usbpn_disconnect,
    425	.id_table =	usbpn_ids,
    426	.disable_hub_initiated_lpm = 1,
    427};
    428
    429module_usb_driver(usbpn_driver);
    430
    431MODULE_AUTHOR("Remi Denis-Courmont");
    432MODULE_DESCRIPTION("USB CDC Phonet host interface");
    433MODULE_LICENSE("GPL");