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

net1080.c (13735B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Net1080 based USB host-to-host cables
      4 * Copyright (C) 2000-2005 by David Brownell
      5 */
      6
      7// #define	DEBUG			// error path messages, extra info
      8// #define	VERBOSE			// more; success messages
      9
     10#include <linux/module.h>
     11#include <linux/netdevice.h>
     12#include <linux/etherdevice.h>
     13#include <linux/ethtool.h>
     14#include <linux/workqueue.h>
     15#include <linux/mii.h>
     16#include <linux/usb.h>
     17#include <linux/usb/usbnet.h>
     18#include <linux/slab.h>
     19
     20#include <asm/unaligned.h>
     21
     22
     23/*
     24 * Netchip 1080 driver ... http://www.netchip.com
     25 * (Sept 2004:  End-of-life announcement has been sent.)
     26 * Used in (some) LapLink cables
     27 */
     28
     29#define frame_errors	data[1]
     30
     31/*
     32 * NetChip framing of ethernet packets, supporting additional error
     33 * checks for links that may drop bulk packets from inside messages.
     34 * Odd USB length == always short read for last usb packet.
     35 *	- nc_header
     36 *	- Ethernet header (14 bytes)
     37 *	- payload
     38 *	- (optional padding byte, if needed so length becomes odd)
     39 *	- nc_trailer
     40 *
     41 * This framing is to be avoided for non-NetChip devices.
     42 */
     43
     44struct nc_header {		// packed:
     45	__le16	hdr_len;		// sizeof nc_header (LE, all)
     46	__le16	packet_len;		// payload size (including ethhdr)
     47	__le16	packet_id;		// detects dropped packets
     48#define MIN_HEADER	6
     49
     50	// all else is optional, and must start with:
     51	// __le16	vendorId;	// from usb-if
     52	// __le16	productId;
     53} __packed;
     54
     55#define	PAD_BYTE	((unsigned char)0xAC)
     56
     57struct nc_trailer {
     58	__le16	packet_id;
     59} __packed;
     60
     61// packets may use FLAG_FRAMING_NC and optional pad
     62#define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \
     63				+ sizeof (struct ethhdr) \
     64				+ (mtu) \
     65				+ 1 \
     66				+ sizeof (struct nc_trailer))
     67
     68#define MIN_FRAMED	FRAMED_SIZE(0)
     69
     70/* packets _could_ be up to 64KB... */
     71#define NC_MAX_PACKET	32767
     72
     73
     74/*
     75 * Zero means no timeout; else, how long a 64 byte bulk packet may be queued
     76 * before the hardware drops it.  If that's done, the driver will need to
     77 * frame network packets to guard against the dropped USB packets.  The win32
     78 * driver sets this for both sides of the link.
     79 */
     80#define	NC_READ_TTL_MS	((u8)255)	// ms
     81
     82/*
     83 * We ignore most registers and EEPROM contents.
     84 */
     85#define	REG_USBCTL	((u8)0x04)
     86#define REG_TTL		((u8)0x10)
     87#define REG_STATUS	((u8)0x11)
     88
     89/*
     90 * Vendor specific requests to read/write data
     91 */
     92#define	REQUEST_REGISTER	((u8)0x10)
     93#define	REQUEST_EEPROM		((u8)0x11)
     94
     95static int
     96nc_vendor_read(struct usbnet *dev, u8 req, u8 regnum, u16 *retval_ptr)
     97{
     98	int status = usbnet_read_cmd(dev, req,
     99				     USB_DIR_IN | USB_TYPE_VENDOR |
    100				     USB_RECIP_DEVICE,
    101				     0, regnum, retval_ptr,
    102				     sizeof *retval_ptr);
    103	if (status > 0)
    104		status = 0;
    105	if (!status)
    106		le16_to_cpus(retval_ptr);
    107	return status;
    108}
    109
    110static inline int
    111nc_register_read(struct usbnet *dev, u8 regnum, u16 *retval_ptr)
    112{
    113	return nc_vendor_read(dev, REQUEST_REGISTER, regnum, retval_ptr);
    114}
    115
    116static void
    117nc_vendor_write(struct usbnet *dev, u8 req, u8 regnum, u16 value)
    118{
    119	usbnet_write_cmd(dev, req,
    120			 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
    121			 value, regnum, NULL, 0);
    122}
    123
    124static inline void
    125nc_register_write(struct usbnet *dev, u8 regnum, u16 value)
    126{
    127	nc_vendor_write(dev, REQUEST_REGISTER, regnum, value);
    128}
    129
    130
    131#if 0
    132static void nc_dump_registers(struct usbnet *dev)
    133{
    134	u8	reg;
    135	u16	*vp = kmalloc(sizeof (u16));
    136
    137	if (!vp)
    138		return;
    139
    140	netdev_dbg(dev->net, "registers:\n");
    141	for (reg = 0; reg < 0x20; reg++) {
    142		int retval;
    143
    144		// reading some registers is trouble
    145		if (reg >= 0x08 && reg <= 0xf)
    146			continue;
    147		if (reg >= 0x12 && reg <= 0x1e)
    148			continue;
    149
    150		retval = nc_register_read(dev, reg, vp);
    151		if (retval < 0)
    152			netdev_dbg(dev->net, "reg [0x%x] ==> error %d\n",
    153				   reg, retval);
    154		else
    155			netdev_dbg(dev->net, "reg [0x%x] = 0x%x\n", reg, *vp);
    156	}
    157	kfree(vp);
    158}
    159#endif
    160
    161
    162/*-------------------------------------------------------------------------*/
    163
    164/*
    165 * Control register
    166 */
    167
    168#define	USBCTL_WRITABLE_MASK	0x1f0f
    169// bits 15-13 reserved, r/o
    170#define	USBCTL_ENABLE_LANG	(1 << 12)
    171#define	USBCTL_ENABLE_MFGR	(1 << 11)
    172#define	USBCTL_ENABLE_PROD	(1 << 10)
    173#define	USBCTL_ENABLE_SERIAL	(1 << 9)
    174#define	USBCTL_ENABLE_DEFAULTS	(1 << 8)
    175// bits 7-4 reserved, r/o
    176#define	USBCTL_FLUSH_OTHER	(1 << 3)
    177#define	USBCTL_FLUSH_THIS	(1 << 2)
    178#define	USBCTL_DISCONN_OTHER	(1 << 1)
    179#define	USBCTL_DISCONN_THIS	(1 << 0)
    180
    181static inline void nc_dump_usbctl(struct usbnet *dev, u16 usbctl)
    182{
    183	netif_dbg(dev, link, dev->net,
    184		  "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s; this%s%s; other%s%s; r/o 0x%x\n",
    185		  dev->udev->bus->bus_name, dev->udev->devpath,
    186		  usbctl,
    187		  (usbctl & USBCTL_ENABLE_LANG) ? " lang" : "",
    188		  (usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "",
    189		  (usbctl & USBCTL_ENABLE_PROD) ? " prod" : "",
    190		  (usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "",
    191		  (usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "",
    192
    193		  (usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "",
    194		  (usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "",
    195
    196		  (usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "",
    197		  (usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "",
    198
    199		  usbctl & ~USBCTL_WRITABLE_MASK);
    200}
    201
    202/*-------------------------------------------------------------------------*/
    203
    204/*
    205 * Status register
    206 */
    207
    208#define	STATUS_PORT_A		(1 << 15)
    209
    210#define	STATUS_CONN_OTHER	(1 << 14)
    211#define	STATUS_SUSPEND_OTHER	(1 << 13)
    212#define	STATUS_MAILBOX_OTHER	(1 << 12)
    213#define	STATUS_PACKETS_OTHER(n)	(((n) >> 8) & 0x03)
    214
    215#define	STATUS_CONN_THIS	(1 << 6)
    216#define	STATUS_SUSPEND_THIS	(1 << 5)
    217#define	STATUS_MAILBOX_THIS	(1 << 4)
    218#define	STATUS_PACKETS_THIS(n)	(((n) >> 0) & 0x03)
    219
    220#define	STATUS_UNSPEC_MASK	0x0c8c
    221#define	STATUS_NOISE_MASK 	((u16)~(0x0303|STATUS_UNSPEC_MASK))
    222
    223
    224static inline void nc_dump_status(struct usbnet *dev, u16 status)
    225{
    226	netif_dbg(dev, link, dev->net,
    227		  "net1080 %s-%s status 0x%x: this (%c) PKT=%d%s%s%s; other PKT=%d%s%s%s; unspec 0x%x\n",
    228		  dev->udev->bus->bus_name, dev->udev->devpath,
    229		  status,
    230
    231		  // XXX the packet counts don't seem right
    232		  // (1 at reset, not 0); maybe UNSPEC too
    233
    234		  (status & STATUS_PORT_A) ? 'A' : 'B',
    235		  STATUS_PACKETS_THIS(status),
    236		  (status & STATUS_CONN_THIS) ? " CON" : "",
    237		  (status & STATUS_SUSPEND_THIS) ? " SUS" : "",
    238		  (status & STATUS_MAILBOX_THIS) ? " MBOX" : "",
    239
    240		  STATUS_PACKETS_OTHER(status),
    241		  (status & STATUS_CONN_OTHER) ? " CON" : "",
    242		  (status & STATUS_SUSPEND_OTHER) ? " SUS" : "",
    243		  (status & STATUS_MAILBOX_OTHER) ? " MBOX" : "",
    244
    245		  status & STATUS_UNSPEC_MASK);
    246}
    247
    248/*-------------------------------------------------------------------------*/
    249
    250/*
    251 * TTL register
    252 */
    253
    254#define	TTL_OTHER(ttl)	(0x00ff & (ttl >> 8))
    255#define MK_TTL(this,other)	((u16)(((other)<<8)|(0x00ff&(this))))
    256
    257/*-------------------------------------------------------------------------*/
    258
    259static int net1080_reset(struct usbnet *dev)
    260{
    261	u16		usbctl, status, ttl;
    262	u16		vp;
    263	int		retval;
    264
    265	// nc_dump_registers(dev);
    266
    267	if ((retval = nc_register_read(dev, REG_STATUS, &vp)) < 0) {
    268		netdev_dbg(dev->net, "can't read %s-%s status: %d\n",
    269			   dev->udev->bus->bus_name, dev->udev->devpath, retval);
    270		goto done;
    271	}
    272	status = vp;
    273	nc_dump_status(dev, status);
    274
    275	if ((retval = nc_register_read(dev, REG_USBCTL, &vp)) < 0) {
    276		netdev_dbg(dev->net, "can't read USBCTL, %d\n", retval);
    277		goto done;
    278	}
    279	usbctl = vp;
    280	nc_dump_usbctl(dev, usbctl);
    281
    282	nc_register_write(dev, REG_USBCTL,
    283			USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER);
    284
    285	if ((retval = nc_register_read(dev, REG_TTL, &vp)) < 0) {
    286		netdev_dbg(dev->net, "can't read TTL, %d\n", retval);
    287		goto done;
    288	}
    289	ttl = vp;
    290
    291	nc_register_write(dev, REG_TTL,
    292			MK_TTL(NC_READ_TTL_MS, TTL_OTHER(ttl)) );
    293	netdev_dbg(dev->net, "assigned TTL, %d ms\n", NC_READ_TTL_MS);
    294
    295	netif_info(dev, link, dev->net, "port %c, peer %sconnected\n",
    296		   (status & STATUS_PORT_A) ? 'A' : 'B',
    297		   (status & STATUS_CONN_OTHER) ? "" : "dis");
    298	retval = 0;
    299
    300done:
    301	return retval;
    302}
    303
    304static int net1080_check_connect(struct usbnet *dev)
    305{
    306	int			retval;
    307	u16			status;
    308	u16			vp;
    309
    310	retval = nc_register_read(dev, REG_STATUS, &vp);
    311	status = vp;
    312	if (retval != 0) {
    313		netdev_dbg(dev->net, "net1080_check_conn read - %d\n", retval);
    314		return retval;
    315	}
    316	if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER)
    317		return -ENOLINK;
    318	return 0;
    319}
    320
    321static void nc_ensure_sync(struct usbnet *dev)
    322{
    323	if (++dev->frame_errors <= 5)
    324		return;
    325
    326	if (usbnet_write_cmd_async(dev, REQUEST_REGISTER,
    327					USB_DIR_OUT | USB_TYPE_VENDOR |
    328					USB_RECIP_DEVICE,
    329					USBCTL_FLUSH_THIS |
    330					USBCTL_FLUSH_OTHER,
    331					REG_USBCTL, NULL, 0))
    332		return;
    333
    334	netif_dbg(dev, rx_err, dev->net,
    335		  "flush net1080; too many framing errors\n");
    336	dev->frame_errors = 0;
    337}
    338
    339static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
    340{
    341	struct nc_header	*header;
    342	struct nc_trailer	*trailer;
    343	u16			hdr_len, packet_len;
    344
    345	/* This check is no longer done by usbnet */
    346	if (skb->len < dev->net->hard_header_len)
    347		return 0;
    348
    349	if (!(skb->len & 0x01)) {
    350		netdev_dbg(dev->net, "rx framesize %d range %d..%d mtu %d\n",
    351			   skb->len, dev->net->hard_header_len, dev->hard_mtu,
    352			   dev->net->mtu);
    353		dev->net->stats.rx_frame_errors++;
    354		nc_ensure_sync(dev);
    355		return 0;
    356	}
    357
    358	header = (struct nc_header *) skb->data;
    359	hdr_len = le16_to_cpup(&header->hdr_len);
    360	packet_len = le16_to_cpup(&header->packet_len);
    361	if (FRAMED_SIZE(packet_len) > NC_MAX_PACKET) {
    362		dev->net->stats.rx_frame_errors++;
    363		netdev_dbg(dev->net, "packet too big, %d\n", packet_len);
    364		nc_ensure_sync(dev);
    365		return 0;
    366	} else if (hdr_len < MIN_HEADER) {
    367		dev->net->stats.rx_frame_errors++;
    368		netdev_dbg(dev->net, "header too short, %d\n", hdr_len);
    369		nc_ensure_sync(dev);
    370		return 0;
    371	} else if (hdr_len > MIN_HEADER) {
    372		// out of band data for us?
    373		netdev_dbg(dev->net, "header OOB, %d bytes\n", hdr_len - MIN_HEADER);
    374		nc_ensure_sync(dev);
    375		// switch (vendor/product ids) { ... }
    376	}
    377	skb_pull(skb, hdr_len);
    378
    379	trailer = (struct nc_trailer *)
    380		(skb->data + skb->len - sizeof *trailer);
    381	skb_trim(skb, skb->len - sizeof *trailer);
    382
    383	if ((packet_len & 0x01) == 0) {
    384		if (skb->data [packet_len] != PAD_BYTE) {
    385			dev->net->stats.rx_frame_errors++;
    386			netdev_dbg(dev->net, "bad pad\n");
    387			return 0;
    388		}
    389		skb_trim(skb, skb->len - 1);
    390	}
    391	if (skb->len != packet_len) {
    392		dev->net->stats.rx_frame_errors++;
    393		netdev_dbg(dev->net, "bad packet len %d (expected %d)\n",
    394			   skb->len, packet_len);
    395		nc_ensure_sync(dev);
    396		return 0;
    397	}
    398	if (header->packet_id != get_unaligned(&trailer->packet_id)) {
    399		dev->net->stats.rx_fifo_errors++;
    400		netdev_dbg(dev->net, "(2+ dropped) rx packet_id mismatch 0x%x 0x%x\n",
    401			   le16_to_cpu(header->packet_id),
    402			   le16_to_cpu(trailer->packet_id));
    403		return 0;
    404	}
    405#if 0
    406	netdev_dbg(dev->net, "frame <rx h %d p %d id %d\n", header->hdr_len,
    407		   header->packet_len, header->packet_id);
    408#endif
    409	dev->frame_errors = 0;
    410	return 1;
    411}
    412
    413static struct sk_buff *
    414net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
    415{
    416	struct sk_buff		*skb2;
    417	struct nc_header	*header = NULL;
    418	struct nc_trailer	*trailer = NULL;
    419	int			padlen = sizeof (struct nc_trailer);
    420	int			len = skb->len;
    421
    422	if (!((len + padlen + sizeof (struct nc_header)) & 0x01))
    423		padlen++;
    424	if (!skb_cloned(skb)) {
    425		int	headroom = skb_headroom(skb);
    426		int	tailroom = skb_tailroom(skb);
    427
    428		if (padlen <= tailroom &&
    429		    sizeof(struct nc_header) <= headroom)
    430			/* There's enough head and tail room */
    431			goto encapsulate;
    432
    433		if ((sizeof (struct nc_header) + padlen) <
    434				(headroom + tailroom)) {
    435			/* There's enough total room, so just readjust */
    436			skb->data = memmove(skb->head
    437						+ sizeof (struct nc_header),
    438					    skb->data, skb->len);
    439			skb_set_tail_pointer(skb, len);
    440			goto encapsulate;
    441		}
    442	}
    443
    444	/* Create a new skb to use with the correct size */
    445	skb2 = skb_copy_expand(skb,
    446				sizeof (struct nc_header),
    447				padlen,
    448				flags);
    449	dev_kfree_skb_any(skb);
    450	if (!skb2)
    451		return skb2;
    452	skb = skb2;
    453
    454encapsulate:
    455	/* header first */
    456	header = skb_push(skb, sizeof *header);
    457	header->hdr_len = cpu_to_le16(sizeof (*header));
    458	header->packet_len = cpu_to_le16(len);
    459	header->packet_id = cpu_to_le16((u16)dev->xid++);
    460
    461	/* maybe pad; then trailer */
    462	if (!((skb->len + sizeof *trailer) & 0x01))
    463		skb_put_u8(skb, PAD_BYTE);
    464	trailer = skb_put(skb, sizeof *trailer);
    465	put_unaligned(header->packet_id, &trailer->packet_id);
    466#if 0
    467	netdev_dbg(dev->net, "frame >tx h %d p %d id %d\n",
    468		   header->hdr_len, header->packet_len,
    469		   header->packet_id);
    470#endif
    471	return skb;
    472}
    473
    474static int net1080_bind(struct usbnet *dev, struct usb_interface *intf)
    475{
    476	unsigned	extra = sizeof (struct nc_header)
    477				+ 1
    478				+ sizeof (struct nc_trailer);
    479
    480	dev->net->hard_header_len += extra;
    481	dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu;
    482	dev->hard_mtu = NC_MAX_PACKET;
    483	return usbnet_get_endpoints (dev, intf);
    484}
    485
    486static const struct driver_info	net1080_info = {
    487	.description =	"NetChip TurboCONNECT",
    488	.flags =	FLAG_POINTTOPOINT | FLAG_FRAMING_NC,
    489	.bind =		net1080_bind,
    490	.reset =	net1080_reset,
    491	.check_connect = net1080_check_connect,
    492	.rx_fixup =	net1080_rx_fixup,
    493	.tx_fixup =	net1080_tx_fixup,
    494};
    495
    496static const struct usb_device_id	products [] = {
    497{
    498	USB_DEVICE(0x0525, 0x1080),	// NetChip ref design
    499	.driver_info =	(unsigned long) &net1080_info,
    500}, {
    501	USB_DEVICE(0x06D0, 0x0622),	// Laplink Gold
    502	.driver_info =	(unsigned long) &net1080_info,
    503},
    504	{ },		// END
    505};
    506MODULE_DEVICE_TABLE(usb, products);
    507
    508static struct usb_driver net1080_driver = {
    509	.name =		"net1080",
    510	.id_table =	products,
    511	.probe =	usbnet_probe,
    512	.disconnect =	usbnet_disconnect,
    513	.suspend =	usbnet_suspend,
    514	.resume =	usbnet_resume,
    515	.disable_hub_initiated_lpm = 1,
    516};
    517
    518module_usb_driver(net1080_driver);
    519
    520MODULE_AUTHOR("David Brownell");
    521MODULE_DESCRIPTION("NetChip 1080 based USB Host-to-Host Links");
    522MODULE_LICENSE("GPL");