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

mctp-serial.c (11357B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Management Component Transport Protocol (MCTP) - serial transport
      4 * binding. This driver is an implementation of the DMTF specificiation
      5 * "DSP0253 - Management Component Transport Protocol (MCTP) Serial Transport
      6 * Binding", available at:
      7 *
      8 *  https://www.dmtf.org/sites/default/files/standards/documents/DSP0253_1.0.0.pdf
      9 *
     10 * This driver provides DSP0253-type MCTP-over-serial transport using a Linux
     11 * tty device, by setting the N_MCTP line discipline on the tty.
     12 *
     13 * Copyright (c) 2021 Code Construct
     14 */
     15
     16#include <linux/idr.h>
     17#include <linux/if_arp.h>
     18#include <linux/module.h>
     19#include <linux/skbuff.h>
     20#include <linux/tty.h>
     21#include <linux/workqueue.h>
     22#include <linux/crc-ccitt.h>
     23
     24#include <linux/mctp.h>
     25#include <net/mctp.h>
     26#include <net/pkt_sched.h>
     27
     28#define MCTP_SERIAL_MTU		68 /* base mtu (64) + mctp header */
     29#define MCTP_SERIAL_FRAME_MTU	(MCTP_SERIAL_MTU + 6) /* + serial framing */
     30
     31#define MCTP_SERIAL_VERSION	0x1 /* DSP0253 defines a single version: 1 */
     32
     33#define BUFSIZE			MCTP_SERIAL_FRAME_MTU
     34
     35#define BYTE_FRAME		0x7e
     36#define BYTE_ESC		0x7d
     37
     38static DEFINE_IDA(mctp_serial_ida);
     39
     40enum mctp_serial_state {
     41	STATE_IDLE,
     42	STATE_START,
     43	STATE_HEADER,
     44	STATE_DATA,
     45	STATE_ESCAPE,
     46	STATE_TRAILER,
     47	STATE_DONE,
     48	STATE_ERR,
     49};
     50
     51struct mctp_serial {
     52	struct net_device	*netdev;
     53	struct tty_struct	*tty;
     54
     55	int			idx;
     56
     57	/* protects our rx & tx state machines; held during both paths */
     58	spinlock_t		lock;
     59
     60	struct work_struct	tx_work;
     61	enum mctp_serial_state	txstate, rxstate;
     62	u16			txfcs, rxfcs, rxfcs_rcvd;
     63	unsigned int		txlen, rxlen;
     64	unsigned int		txpos, rxpos;
     65	unsigned char		txbuf[BUFSIZE],
     66				rxbuf[BUFSIZE];
     67};
     68
     69static bool needs_escape(unsigned char c)
     70{
     71	return c == BYTE_ESC || c == BYTE_FRAME;
     72}
     73
     74static int next_chunk_len(struct mctp_serial *dev)
     75{
     76	int i;
     77
     78	/* either we have no bytes to send ... */
     79	if (dev->txpos == dev->txlen)
     80		return 0;
     81
     82	/* ... or the next byte to send is an escaped byte; requiring a
     83	 * single-byte chunk...
     84	 */
     85	if (needs_escape(dev->txbuf[dev->txpos]))
     86		return 1;
     87
     88	/* ... or we have one or more bytes up to the next escape - this chunk
     89	 * will be those non-escaped bytes, and does not include the escaped
     90	 * byte.
     91	 */
     92	for (i = 1; i + dev->txpos + 1 < dev->txlen; i++) {
     93		if (needs_escape(dev->txbuf[dev->txpos + i + 1]))
     94			break;
     95	}
     96
     97	return i;
     98}
     99
    100static int write_chunk(struct mctp_serial *dev, unsigned char *buf, int len)
    101{
    102	return dev->tty->ops->write(dev->tty, buf, len);
    103}
    104
    105static void mctp_serial_tx_work(struct work_struct *work)
    106{
    107	struct mctp_serial *dev = container_of(work, struct mctp_serial,
    108					       tx_work);
    109	unsigned char c, buf[3];
    110	unsigned long flags;
    111	int len, txlen;
    112
    113	spin_lock_irqsave(&dev->lock, flags);
    114
    115	/* txstate represents the next thing to send */
    116	switch (dev->txstate) {
    117	case STATE_START:
    118		dev->txpos = 0;
    119		fallthrough;
    120	case STATE_HEADER:
    121		buf[0] = BYTE_FRAME;
    122		buf[1] = MCTP_SERIAL_VERSION;
    123		buf[2] = dev->txlen;
    124
    125		if (!dev->txpos)
    126			dev->txfcs = crc_ccitt(0, buf + 1, 2);
    127
    128		txlen = write_chunk(dev, buf + dev->txpos, 3 - dev->txpos);
    129		if (txlen <= 0) {
    130			dev->txstate = STATE_ERR;
    131		} else {
    132			dev->txpos += txlen;
    133			if (dev->txpos == 3) {
    134				dev->txstate = STATE_DATA;
    135				dev->txpos = 0;
    136			}
    137		}
    138		break;
    139
    140	case STATE_ESCAPE:
    141		buf[0] = dev->txbuf[dev->txpos] & ~0x20;
    142		txlen = write_chunk(dev, buf, 1);
    143		if (txlen <= 0) {
    144			dev->txstate = STATE_ERR;
    145		} else {
    146			dev->txpos += txlen;
    147			if (dev->txpos == dev->txlen) {
    148				dev->txstate = STATE_TRAILER;
    149				dev->txpos = 0;
    150			}
    151		}
    152
    153		break;
    154
    155	case STATE_DATA:
    156		len = next_chunk_len(dev);
    157		if (len) {
    158			c = dev->txbuf[dev->txpos];
    159			if (len == 1 && needs_escape(c)) {
    160				buf[0] = BYTE_ESC;
    161				buf[1] = c & ~0x20;
    162				dev->txfcs = crc_ccitt_byte(dev->txfcs, c);
    163				txlen = write_chunk(dev, buf, 2);
    164				if (txlen == 2)
    165					dev->txpos++;
    166				else if (txlen == 1)
    167					dev->txstate = STATE_ESCAPE;
    168				else
    169					dev->txstate = STATE_ERR;
    170			} else {
    171				txlen = write_chunk(dev,
    172						    dev->txbuf + dev->txpos,
    173						    len);
    174				if (txlen <= 0) {
    175					dev->txstate = STATE_ERR;
    176				} else {
    177					dev->txfcs = crc_ccitt(dev->txfcs,
    178							       dev->txbuf +
    179							       dev->txpos,
    180							       txlen);
    181					dev->txpos += txlen;
    182				}
    183			}
    184			if (dev->txstate == STATE_DATA &&
    185			    dev->txpos == dev->txlen) {
    186				dev->txstate = STATE_TRAILER;
    187				dev->txpos = 0;
    188			}
    189			break;
    190		}
    191		dev->txstate = STATE_TRAILER;
    192		dev->txpos = 0;
    193		fallthrough;
    194
    195	case STATE_TRAILER:
    196		buf[0] = dev->txfcs >> 8;
    197		buf[1] = dev->txfcs & 0xff;
    198		buf[2] = BYTE_FRAME;
    199		txlen = write_chunk(dev, buf + dev->txpos, 3 - dev->txpos);
    200		if (txlen <= 0) {
    201			dev->txstate = STATE_ERR;
    202		} else {
    203			dev->txpos += txlen;
    204			if (dev->txpos == 3) {
    205				dev->txstate = STATE_DONE;
    206				dev->txpos = 0;
    207			}
    208		}
    209		break;
    210	default:
    211		netdev_err_once(dev->netdev, "invalid tx state %d\n",
    212				dev->txstate);
    213	}
    214
    215	if (dev->txstate == STATE_DONE) {
    216		dev->netdev->stats.tx_packets++;
    217		dev->netdev->stats.tx_bytes += dev->txlen;
    218		dev->txlen = 0;
    219		dev->txpos = 0;
    220		clear_bit(TTY_DO_WRITE_WAKEUP, &dev->tty->flags);
    221		dev->txstate = STATE_IDLE;
    222		spin_unlock_irqrestore(&dev->lock, flags);
    223
    224		netif_wake_queue(dev->netdev);
    225	} else {
    226		spin_unlock_irqrestore(&dev->lock, flags);
    227	}
    228}
    229
    230static netdev_tx_t mctp_serial_tx(struct sk_buff *skb, struct net_device *ndev)
    231{
    232	struct mctp_serial *dev = netdev_priv(ndev);
    233	unsigned long flags;
    234
    235	WARN_ON(dev->txstate != STATE_IDLE);
    236
    237	if (skb->len > MCTP_SERIAL_MTU) {
    238		dev->netdev->stats.tx_dropped++;
    239		goto out;
    240	}
    241
    242	spin_lock_irqsave(&dev->lock, flags);
    243	netif_stop_queue(dev->netdev);
    244	skb_copy_bits(skb, 0, dev->txbuf, skb->len);
    245	dev->txpos = 0;
    246	dev->txlen = skb->len;
    247	dev->txstate = STATE_START;
    248	spin_unlock_irqrestore(&dev->lock, flags);
    249
    250	set_bit(TTY_DO_WRITE_WAKEUP, &dev->tty->flags);
    251	schedule_work(&dev->tx_work);
    252
    253out:
    254	kfree_skb(skb);
    255	return NETDEV_TX_OK;
    256}
    257
    258static void mctp_serial_tty_write_wakeup(struct tty_struct *tty)
    259{
    260	struct mctp_serial *dev = tty->disc_data;
    261
    262	schedule_work(&dev->tx_work);
    263}
    264
    265static void mctp_serial_rx(struct mctp_serial *dev)
    266{
    267	struct mctp_skb_cb *cb;
    268	struct sk_buff *skb;
    269
    270	if (dev->rxfcs != dev->rxfcs_rcvd) {
    271		dev->netdev->stats.rx_dropped++;
    272		dev->netdev->stats.rx_crc_errors++;
    273		return;
    274	}
    275
    276	skb = netdev_alloc_skb(dev->netdev, dev->rxlen);
    277	if (!skb) {
    278		dev->netdev->stats.rx_dropped++;
    279		return;
    280	}
    281
    282	skb->protocol = htons(ETH_P_MCTP);
    283	skb_put_data(skb, dev->rxbuf, dev->rxlen);
    284	skb_reset_network_header(skb);
    285
    286	cb = __mctp_cb(skb);
    287	cb->halen = 0;
    288
    289	netif_rx(skb);
    290	dev->netdev->stats.rx_packets++;
    291	dev->netdev->stats.rx_bytes += dev->rxlen;
    292}
    293
    294static void mctp_serial_push_header(struct mctp_serial *dev, unsigned char c)
    295{
    296	switch (dev->rxpos) {
    297	case 0:
    298		if (c == BYTE_FRAME)
    299			dev->rxpos++;
    300		else
    301			dev->rxstate = STATE_ERR;
    302		break;
    303	case 1:
    304		if (c == MCTP_SERIAL_VERSION) {
    305			dev->rxpos++;
    306			dev->rxfcs = crc_ccitt_byte(0, c);
    307		} else {
    308			dev->rxstate = STATE_ERR;
    309		}
    310		break;
    311	case 2:
    312		if (c > MCTP_SERIAL_FRAME_MTU) {
    313			dev->rxstate = STATE_ERR;
    314		} else {
    315			dev->rxlen = c;
    316			dev->rxpos = 0;
    317			dev->rxstate = STATE_DATA;
    318			dev->rxfcs = crc_ccitt_byte(dev->rxfcs, c);
    319		}
    320		break;
    321	}
    322}
    323
    324static void mctp_serial_push_trailer(struct mctp_serial *dev, unsigned char c)
    325{
    326	switch (dev->rxpos) {
    327	case 0:
    328		dev->rxfcs_rcvd = c << 8;
    329		dev->rxpos++;
    330		break;
    331	case 1:
    332		dev->rxfcs_rcvd |= c;
    333		dev->rxpos++;
    334		break;
    335	case 2:
    336		if (c != BYTE_FRAME) {
    337			dev->rxstate = STATE_ERR;
    338		} else {
    339			mctp_serial_rx(dev);
    340			dev->rxlen = 0;
    341			dev->rxpos = 0;
    342			dev->rxstate = STATE_IDLE;
    343		}
    344		break;
    345	}
    346}
    347
    348static void mctp_serial_push(struct mctp_serial *dev, unsigned char c)
    349{
    350	switch (dev->rxstate) {
    351	case STATE_IDLE:
    352		dev->rxstate = STATE_HEADER;
    353		fallthrough;
    354	case STATE_HEADER:
    355		mctp_serial_push_header(dev, c);
    356		break;
    357
    358	case STATE_ESCAPE:
    359		c |= 0x20;
    360		fallthrough;
    361	case STATE_DATA:
    362		if (dev->rxstate != STATE_ESCAPE && c == BYTE_ESC) {
    363			dev->rxstate = STATE_ESCAPE;
    364		} else {
    365			dev->rxfcs = crc_ccitt_byte(dev->rxfcs, c);
    366			dev->rxbuf[dev->rxpos] = c;
    367			dev->rxpos++;
    368			dev->rxstate = STATE_DATA;
    369			if (dev->rxpos == dev->rxlen) {
    370				dev->rxpos = 0;
    371				dev->rxstate = STATE_TRAILER;
    372			}
    373		}
    374		break;
    375
    376	case STATE_TRAILER:
    377		mctp_serial_push_trailer(dev, c);
    378		break;
    379
    380	case STATE_ERR:
    381		if (c == BYTE_FRAME)
    382			dev->rxstate = STATE_IDLE;
    383		break;
    384
    385	default:
    386		netdev_err_once(dev->netdev, "invalid rx state %d\n",
    387				dev->rxstate);
    388	}
    389}
    390
    391static void mctp_serial_tty_receive_buf(struct tty_struct *tty,
    392					const unsigned char *c,
    393					const char *f, int len)
    394{
    395	struct mctp_serial *dev = tty->disc_data;
    396	int i;
    397
    398	if (!netif_running(dev->netdev))
    399		return;
    400
    401	/* we don't (currently) use the flag bytes, just data. */
    402	for (i = 0; i < len; i++)
    403		mctp_serial_push(dev, c[i]);
    404}
    405
    406static void mctp_serial_uninit(struct net_device *ndev)
    407{
    408	struct mctp_serial *dev = netdev_priv(ndev);
    409
    410	cancel_work_sync(&dev->tx_work);
    411}
    412
    413static const struct net_device_ops mctp_serial_netdev_ops = {
    414	.ndo_start_xmit = mctp_serial_tx,
    415	.ndo_uninit = mctp_serial_uninit,
    416};
    417
    418static void mctp_serial_setup(struct net_device *ndev)
    419{
    420	ndev->type = ARPHRD_MCTP;
    421
    422	/* we limit at the fixed MTU, which is also the MCTP-standard
    423	 * baseline MTU, so is also our minimum
    424	 */
    425	ndev->mtu = MCTP_SERIAL_MTU;
    426	ndev->max_mtu = MCTP_SERIAL_MTU;
    427	ndev->min_mtu = MCTP_SERIAL_MTU;
    428
    429	ndev->hard_header_len = 0;
    430	ndev->addr_len = 0;
    431	ndev->tx_queue_len = DEFAULT_TX_QUEUE_LEN;
    432	ndev->flags = IFF_NOARP;
    433	ndev->netdev_ops = &mctp_serial_netdev_ops;
    434	ndev->needs_free_netdev = true;
    435}
    436
    437static int mctp_serial_open(struct tty_struct *tty)
    438{
    439	struct mctp_serial *dev;
    440	struct net_device *ndev;
    441	char name[32];
    442	int idx, rc;
    443
    444	if (!capable(CAP_NET_ADMIN))
    445		return -EPERM;
    446
    447	if (!tty->ops->write)
    448		return -EOPNOTSUPP;
    449
    450	idx = ida_alloc(&mctp_serial_ida, GFP_KERNEL);
    451	if (idx < 0)
    452		return idx;
    453
    454	snprintf(name, sizeof(name), "mctpserial%d", idx);
    455	ndev = alloc_netdev(sizeof(*dev), name, NET_NAME_ENUM,
    456			    mctp_serial_setup);
    457	if (!ndev) {
    458		rc = -ENOMEM;
    459		goto free_ida;
    460	}
    461
    462	dev = netdev_priv(ndev);
    463	dev->idx = idx;
    464	dev->tty = tty;
    465	dev->netdev = ndev;
    466	dev->txstate = STATE_IDLE;
    467	dev->rxstate = STATE_IDLE;
    468	spin_lock_init(&dev->lock);
    469	INIT_WORK(&dev->tx_work, mctp_serial_tx_work);
    470
    471	rc = register_netdev(ndev);
    472	if (rc)
    473		goto free_netdev;
    474
    475	tty->receive_room = 64 * 1024;
    476	tty->disc_data = dev;
    477
    478	return 0;
    479
    480free_netdev:
    481	free_netdev(ndev);
    482
    483free_ida:
    484	ida_free(&mctp_serial_ida, idx);
    485	return rc;
    486}
    487
    488static void mctp_serial_close(struct tty_struct *tty)
    489{
    490	struct mctp_serial *dev = tty->disc_data;
    491	int idx = dev->idx;
    492
    493	unregister_netdev(dev->netdev);
    494	ida_free(&mctp_serial_ida, idx);
    495}
    496
    497static struct tty_ldisc_ops mctp_ldisc = {
    498	.owner		= THIS_MODULE,
    499	.num		= N_MCTP,
    500	.name		= "mctp",
    501	.open		= mctp_serial_open,
    502	.close		= mctp_serial_close,
    503	.receive_buf	= mctp_serial_tty_receive_buf,
    504	.write_wakeup	= mctp_serial_tty_write_wakeup,
    505};
    506
    507static int __init mctp_serial_init(void)
    508{
    509	return tty_register_ldisc(&mctp_ldisc);
    510}
    511
    512static void __exit mctp_serial_exit(void)
    513{
    514	tty_unregister_ldisc(&mctp_ldisc);
    515}
    516
    517module_init(mctp_serial_init);
    518module_exit(mctp_serial_exit);
    519
    520MODULE_LICENSE("GPL v2");
    521MODULE_AUTHOR("Jeremy Kerr <jk@codeconstruct.com.au>");
    522MODULE_DESCRIPTION("MCTP Serial transport");