Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Management Component Transport Protocol (MCTP) - serial transport
0004  * binding. This driver is an implementation of the DMTF specificiation
0005  * "DSP0253 - Management Component Transport Protocol (MCTP) Serial Transport
0006  * Binding", available at:
0007  *
0008  *  https://www.dmtf.org/sites/default/files/standards/documents/DSP0253_1.0.0.pdf
0009  *
0010  * This driver provides DSP0253-type MCTP-over-serial transport using a Linux
0011  * tty device, by setting the N_MCTP line discipline on the tty.
0012  *
0013  * Copyright (c) 2021 Code Construct
0014  */
0015 
0016 #include <linux/idr.h>
0017 #include <linux/if_arp.h>
0018 #include <linux/module.h>
0019 #include <linux/skbuff.h>
0020 #include <linux/tty.h>
0021 #include <linux/workqueue.h>
0022 #include <linux/crc-ccitt.h>
0023 
0024 #include <linux/mctp.h>
0025 #include <net/mctp.h>
0026 #include <net/pkt_sched.h>
0027 
0028 #define MCTP_SERIAL_MTU     68 /* base mtu (64) + mctp header */
0029 #define MCTP_SERIAL_FRAME_MTU   (MCTP_SERIAL_MTU + 6) /* + serial framing */
0030 
0031 #define MCTP_SERIAL_VERSION 0x1 /* DSP0253 defines a single version: 1 */
0032 
0033 #define BUFSIZE         MCTP_SERIAL_FRAME_MTU
0034 
0035 #define BYTE_FRAME      0x7e
0036 #define BYTE_ESC        0x7d
0037 
0038 static DEFINE_IDA(mctp_serial_ida);
0039 
0040 enum mctp_serial_state {
0041     STATE_IDLE,
0042     STATE_START,
0043     STATE_HEADER,
0044     STATE_DATA,
0045     STATE_ESCAPE,
0046     STATE_TRAILER,
0047     STATE_DONE,
0048     STATE_ERR,
0049 };
0050 
0051 struct mctp_serial {
0052     struct net_device   *netdev;
0053     struct tty_struct   *tty;
0054 
0055     int         idx;
0056 
0057     /* protects our rx & tx state machines; held during both paths */
0058     spinlock_t      lock;
0059 
0060     struct work_struct  tx_work;
0061     enum mctp_serial_state  txstate, rxstate;
0062     u16         txfcs, rxfcs, rxfcs_rcvd;
0063     unsigned int        txlen, rxlen;
0064     unsigned int        txpos, rxpos;
0065     unsigned char       txbuf[BUFSIZE],
0066                 rxbuf[BUFSIZE];
0067 };
0068 
0069 static bool needs_escape(unsigned char c)
0070 {
0071     return c == BYTE_ESC || c == BYTE_FRAME;
0072 }
0073 
0074 static int next_chunk_len(struct mctp_serial *dev)
0075 {
0076     int i;
0077 
0078     /* either we have no bytes to send ... */
0079     if (dev->txpos == dev->txlen)
0080         return 0;
0081 
0082     /* ... or the next byte to send is an escaped byte; requiring a
0083      * single-byte chunk...
0084      */
0085     if (needs_escape(dev->txbuf[dev->txpos]))
0086         return 1;
0087 
0088     /* ... or we have one or more bytes up to the next escape - this chunk
0089      * will be those non-escaped bytes, and does not include the escaped
0090      * byte.
0091      */
0092     for (i = 1; i + dev->txpos + 1 < dev->txlen; i++) {
0093         if (needs_escape(dev->txbuf[dev->txpos + i + 1]))
0094             break;
0095     }
0096 
0097     return i;
0098 }
0099 
0100 static int write_chunk(struct mctp_serial *dev, unsigned char *buf, int len)
0101 {
0102     return dev->tty->ops->write(dev->tty, buf, len);
0103 }
0104 
0105 static void mctp_serial_tx_work(struct work_struct *work)
0106 {
0107     struct mctp_serial *dev = container_of(work, struct mctp_serial,
0108                            tx_work);
0109     unsigned char c, buf[3];
0110     unsigned long flags;
0111     int len, txlen;
0112 
0113     spin_lock_irqsave(&dev->lock, flags);
0114 
0115     /* txstate represents the next thing to send */
0116     switch (dev->txstate) {
0117     case STATE_START:
0118         dev->txpos = 0;
0119         fallthrough;
0120     case STATE_HEADER:
0121         buf[0] = BYTE_FRAME;
0122         buf[1] = MCTP_SERIAL_VERSION;
0123         buf[2] = dev->txlen;
0124 
0125         if (!dev->txpos)
0126             dev->txfcs = crc_ccitt(0, buf + 1, 2);
0127 
0128         txlen = write_chunk(dev, buf + dev->txpos, 3 - dev->txpos);
0129         if (txlen <= 0) {
0130             dev->txstate = STATE_ERR;
0131         } else {
0132             dev->txpos += txlen;
0133             if (dev->txpos == 3) {
0134                 dev->txstate = STATE_DATA;
0135                 dev->txpos = 0;
0136             }
0137         }
0138         break;
0139 
0140     case STATE_ESCAPE:
0141         buf[0] = dev->txbuf[dev->txpos] & ~0x20;
0142         txlen = write_chunk(dev, buf, 1);
0143         if (txlen <= 0) {
0144             dev->txstate = STATE_ERR;
0145         } else {
0146             dev->txpos += txlen;
0147             if (dev->txpos == dev->txlen) {
0148                 dev->txstate = STATE_TRAILER;
0149                 dev->txpos = 0;
0150             }
0151         }
0152 
0153         break;
0154 
0155     case STATE_DATA:
0156         len = next_chunk_len(dev);
0157         if (len) {
0158             c = dev->txbuf[dev->txpos];
0159             if (len == 1 && needs_escape(c)) {
0160                 buf[0] = BYTE_ESC;
0161                 buf[1] = c & ~0x20;
0162                 dev->txfcs = crc_ccitt_byte(dev->txfcs, c);
0163                 txlen = write_chunk(dev, buf, 2);
0164                 if (txlen == 2)
0165                     dev->txpos++;
0166                 else if (txlen == 1)
0167                     dev->txstate = STATE_ESCAPE;
0168                 else
0169                     dev->txstate = STATE_ERR;
0170             } else {
0171                 txlen = write_chunk(dev,
0172                             dev->txbuf + dev->txpos,
0173                             len);
0174                 if (txlen <= 0) {
0175                     dev->txstate = STATE_ERR;
0176                 } else {
0177                     dev->txfcs = crc_ccitt(dev->txfcs,
0178                                    dev->txbuf +
0179                                    dev->txpos,
0180                                    txlen);
0181                     dev->txpos += txlen;
0182                 }
0183             }
0184             if (dev->txstate == STATE_DATA &&
0185                 dev->txpos == dev->txlen) {
0186                 dev->txstate = STATE_TRAILER;
0187                 dev->txpos = 0;
0188             }
0189             break;
0190         }
0191         dev->txstate = STATE_TRAILER;
0192         dev->txpos = 0;
0193         fallthrough;
0194 
0195     case STATE_TRAILER:
0196         buf[0] = dev->txfcs >> 8;
0197         buf[1] = dev->txfcs & 0xff;
0198         buf[2] = BYTE_FRAME;
0199         txlen = write_chunk(dev, buf + dev->txpos, 3 - dev->txpos);
0200         if (txlen <= 0) {
0201             dev->txstate = STATE_ERR;
0202         } else {
0203             dev->txpos += txlen;
0204             if (dev->txpos == 3) {
0205                 dev->txstate = STATE_DONE;
0206                 dev->txpos = 0;
0207             }
0208         }
0209         break;
0210     default:
0211         netdev_err_once(dev->netdev, "invalid tx state %d\n",
0212                 dev->txstate);
0213     }
0214 
0215     if (dev->txstate == STATE_DONE) {
0216         dev->netdev->stats.tx_packets++;
0217         dev->netdev->stats.tx_bytes += dev->txlen;
0218         dev->txlen = 0;
0219         dev->txpos = 0;
0220         clear_bit(TTY_DO_WRITE_WAKEUP, &dev->tty->flags);
0221         dev->txstate = STATE_IDLE;
0222         spin_unlock_irqrestore(&dev->lock, flags);
0223 
0224         netif_wake_queue(dev->netdev);
0225     } else {
0226         spin_unlock_irqrestore(&dev->lock, flags);
0227     }
0228 }
0229 
0230 static netdev_tx_t mctp_serial_tx(struct sk_buff *skb, struct net_device *ndev)
0231 {
0232     struct mctp_serial *dev = netdev_priv(ndev);
0233     unsigned long flags;
0234 
0235     WARN_ON(dev->txstate != STATE_IDLE);
0236 
0237     if (skb->len > MCTP_SERIAL_MTU) {
0238         dev->netdev->stats.tx_dropped++;
0239         goto out;
0240     }
0241 
0242     spin_lock_irqsave(&dev->lock, flags);
0243     netif_stop_queue(dev->netdev);
0244     skb_copy_bits(skb, 0, dev->txbuf, skb->len);
0245     dev->txpos = 0;
0246     dev->txlen = skb->len;
0247     dev->txstate = STATE_START;
0248     spin_unlock_irqrestore(&dev->lock, flags);
0249 
0250     set_bit(TTY_DO_WRITE_WAKEUP, &dev->tty->flags);
0251     schedule_work(&dev->tx_work);
0252 
0253 out:
0254     kfree_skb(skb);
0255     return NETDEV_TX_OK;
0256 }
0257 
0258 static void mctp_serial_tty_write_wakeup(struct tty_struct *tty)
0259 {
0260     struct mctp_serial *dev = tty->disc_data;
0261 
0262     schedule_work(&dev->tx_work);
0263 }
0264 
0265 static void mctp_serial_rx(struct mctp_serial *dev)
0266 {
0267     struct mctp_skb_cb *cb;
0268     struct sk_buff *skb;
0269 
0270     if (dev->rxfcs != dev->rxfcs_rcvd) {
0271         dev->netdev->stats.rx_dropped++;
0272         dev->netdev->stats.rx_crc_errors++;
0273         return;
0274     }
0275 
0276     skb = netdev_alloc_skb(dev->netdev, dev->rxlen);
0277     if (!skb) {
0278         dev->netdev->stats.rx_dropped++;
0279         return;
0280     }
0281 
0282     skb->protocol = htons(ETH_P_MCTP);
0283     skb_put_data(skb, dev->rxbuf, dev->rxlen);
0284     skb_reset_network_header(skb);
0285 
0286     cb = __mctp_cb(skb);
0287     cb->halen = 0;
0288 
0289     netif_rx(skb);
0290     dev->netdev->stats.rx_packets++;
0291     dev->netdev->stats.rx_bytes += dev->rxlen;
0292 }
0293 
0294 static void mctp_serial_push_header(struct mctp_serial *dev, unsigned char c)
0295 {
0296     switch (dev->rxpos) {
0297     case 0:
0298         if (c == BYTE_FRAME)
0299             dev->rxpos++;
0300         else
0301             dev->rxstate = STATE_ERR;
0302         break;
0303     case 1:
0304         if (c == MCTP_SERIAL_VERSION) {
0305             dev->rxpos++;
0306             dev->rxfcs = crc_ccitt_byte(0, c);
0307         } else {
0308             dev->rxstate = STATE_ERR;
0309         }
0310         break;
0311     case 2:
0312         if (c > MCTP_SERIAL_FRAME_MTU) {
0313             dev->rxstate = STATE_ERR;
0314         } else {
0315             dev->rxlen = c;
0316             dev->rxpos = 0;
0317             dev->rxstate = STATE_DATA;
0318             dev->rxfcs = crc_ccitt_byte(dev->rxfcs, c);
0319         }
0320         break;
0321     }
0322 }
0323 
0324 static void mctp_serial_push_trailer(struct mctp_serial *dev, unsigned char c)
0325 {
0326     switch (dev->rxpos) {
0327     case 0:
0328         dev->rxfcs_rcvd = c << 8;
0329         dev->rxpos++;
0330         break;
0331     case 1:
0332         dev->rxfcs_rcvd |= c;
0333         dev->rxpos++;
0334         break;
0335     case 2:
0336         if (c != BYTE_FRAME) {
0337             dev->rxstate = STATE_ERR;
0338         } else {
0339             mctp_serial_rx(dev);
0340             dev->rxlen = 0;
0341             dev->rxpos = 0;
0342             dev->rxstate = STATE_IDLE;
0343         }
0344         break;
0345     }
0346 }
0347 
0348 static void mctp_serial_push(struct mctp_serial *dev, unsigned char c)
0349 {
0350     switch (dev->rxstate) {
0351     case STATE_IDLE:
0352         dev->rxstate = STATE_HEADER;
0353         fallthrough;
0354     case STATE_HEADER:
0355         mctp_serial_push_header(dev, c);
0356         break;
0357 
0358     case STATE_ESCAPE:
0359         c |= 0x20;
0360         fallthrough;
0361     case STATE_DATA:
0362         if (dev->rxstate != STATE_ESCAPE && c == BYTE_ESC) {
0363             dev->rxstate = STATE_ESCAPE;
0364         } else {
0365             dev->rxfcs = crc_ccitt_byte(dev->rxfcs, c);
0366             dev->rxbuf[dev->rxpos] = c;
0367             dev->rxpos++;
0368             dev->rxstate = STATE_DATA;
0369             if (dev->rxpos == dev->rxlen) {
0370                 dev->rxpos = 0;
0371                 dev->rxstate = STATE_TRAILER;
0372             }
0373         }
0374         break;
0375 
0376     case STATE_TRAILER:
0377         mctp_serial_push_trailer(dev, c);
0378         break;
0379 
0380     case STATE_ERR:
0381         if (c == BYTE_FRAME)
0382             dev->rxstate = STATE_IDLE;
0383         break;
0384 
0385     default:
0386         netdev_err_once(dev->netdev, "invalid rx state %d\n",
0387                 dev->rxstate);
0388     }
0389 }
0390 
0391 static void mctp_serial_tty_receive_buf(struct tty_struct *tty,
0392                     const unsigned char *c,
0393                     const char *f, int len)
0394 {
0395     struct mctp_serial *dev = tty->disc_data;
0396     int i;
0397 
0398     if (!netif_running(dev->netdev))
0399         return;
0400 
0401     /* we don't (currently) use the flag bytes, just data. */
0402     for (i = 0; i < len; i++)
0403         mctp_serial_push(dev, c[i]);
0404 }
0405 
0406 static void mctp_serial_uninit(struct net_device *ndev)
0407 {
0408     struct mctp_serial *dev = netdev_priv(ndev);
0409 
0410     cancel_work_sync(&dev->tx_work);
0411 }
0412 
0413 static const struct net_device_ops mctp_serial_netdev_ops = {
0414     .ndo_start_xmit = mctp_serial_tx,
0415     .ndo_uninit = mctp_serial_uninit,
0416 };
0417 
0418 static void mctp_serial_setup(struct net_device *ndev)
0419 {
0420     ndev->type = ARPHRD_MCTP;
0421 
0422     /* we limit at the fixed MTU, which is also the MCTP-standard
0423      * baseline MTU, so is also our minimum
0424      */
0425     ndev->mtu = MCTP_SERIAL_MTU;
0426     ndev->max_mtu = MCTP_SERIAL_MTU;
0427     ndev->min_mtu = MCTP_SERIAL_MTU;
0428 
0429     ndev->hard_header_len = 0;
0430     ndev->addr_len = 0;
0431     ndev->tx_queue_len = DEFAULT_TX_QUEUE_LEN;
0432     ndev->flags = IFF_NOARP;
0433     ndev->netdev_ops = &mctp_serial_netdev_ops;
0434     ndev->needs_free_netdev = true;
0435 }
0436 
0437 static int mctp_serial_open(struct tty_struct *tty)
0438 {
0439     struct mctp_serial *dev;
0440     struct net_device *ndev;
0441     char name[32];
0442     int idx, rc;
0443 
0444     if (!capable(CAP_NET_ADMIN))
0445         return -EPERM;
0446 
0447     if (!tty->ops->write)
0448         return -EOPNOTSUPP;
0449 
0450     idx = ida_alloc(&mctp_serial_ida, GFP_KERNEL);
0451     if (idx < 0)
0452         return idx;
0453 
0454     snprintf(name, sizeof(name), "mctpserial%d", idx);
0455     ndev = alloc_netdev(sizeof(*dev), name, NET_NAME_ENUM,
0456                 mctp_serial_setup);
0457     if (!ndev) {
0458         rc = -ENOMEM;
0459         goto free_ida;
0460     }
0461 
0462     dev = netdev_priv(ndev);
0463     dev->idx = idx;
0464     dev->tty = tty;
0465     dev->netdev = ndev;
0466     dev->txstate = STATE_IDLE;
0467     dev->rxstate = STATE_IDLE;
0468     spin_lock_init(&dev->lock);
0469     INIT_WORK(&dev->tx_work, mctp_serial_tx_work);
0470 
0471     rc = register_netdev(ndev);
0472     if (rc)
0473         goto free_netdev;
0474 
0475     tty->receive_room = 64 * 1024;
0476     tty->disc_data = dev;
0477 
0478     return 0;
0479 
0480 free_netdev:
0481     free_netdev(ndev);
0482 
0483 free_ida:
0484     ida_free(&mctp_serial_ida, idx);
0485     return rc;
0486 }
0487 
0488 static void mctp_serial_close(struct tty_struct *tty)
0489 {
0490     struct mctp_serial *dev = tty->disc_data;
0491     int idx = dev->idx;
0492 
0493     unregister_netdev(dev->netdev);
0494     ida_free(&mctp_serial_ida, idx);
0495 }
0496 
0497 static struct tty_ldisc_ops mctp_ldisc = {
0498     .owner      = THIS_MODULE,
0499     .num        = N_MCTP,
0500     .name       = "mctp",
0501     .open       = mctp_serial_open,
0502     .close      = mctp_serial_close,
0503     .receive_buf    = mctp_serial_tty_receive_buf,
0504     .write_wakeup   = mctp_serial_tty_write_wakeup,
0505 };
0506 
0507 static int __init mctp_serial_init(void)
0508 {
0509     return tty_register_ldisc(&mctp_ldisc);
0510 }
0511 
0512 static void __exit mctp_serial_exit(void)
0513 {
0514     tty_unregister_ldisc(&mctp_ldisc);
0515 }
0516 
0517 module_init(mctp_serial_init);
0518 module_exit(mctp_serial_exit);
0519 
0520 MODULE_LICENSE("GPL v2");
0521 MODULE_AUTHOR("Jeremy Kerr <jk@codeconstruct.com.au>");
0522 MODULE_DESCRIPTION("MCTP Serial transport");