1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * mctp-usb.c - MCTP-over-USB (DMTF DSP0283) transport binding driver.
4 *
5 * DSP0283 is available at:
6 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0283_1.0.1.pdf
7 *
8 * Copyright (C) 2024-2025 Code Construct Pty Ltd
9 */
10
11 #include <linux/module.h>
12 #include <linux/netdevice.h>
13 #include <linux/usb.h>
14 #include <linux/usb/mctp-usb.h>
15
16 #include <net/mctp.h>
17 #include <net/mctpdevice.h>
18 #include <net/pkt_sched.h>
19
20 #include <uapi/linux/if_arp.h>
21
22 struct mctp_usb {
23 struct usb_device *usbdev;
24 struct usb_interface *intf;
25 bool stopped;
26
27 struct net_device *netdev;
28
29 u8 ep_in;
30 u8 ep_out;
31
32 struct urb *tx_urb;
33 struct urb *rx_urb;
34
35 struct delayed_work rx_retry_work;
36 };
37
mctp_usb_out_complete(struct urb * urb)38 static void mctp_usb_out_complete(struct urb *urb)
39 {
40 struct sk_buff *skb = urb->context;
41 struct net_device *netdev = skb->dev;
42 int status;
43
44 status = urb->status;
45
46 switch (status) {
47 case -ENOENT:
48 case -ECONNRESET:
49 case -ESHUTDOWN:
50 case -EPROTO:
51 netdev->stats.tx_dropped++;
52 break;
53 case 0:
54 netdev->stats.tx_packets++;
55 netdev->stats.tx_bytes += skb->len;
56 netif_wake_queue(netdev);
57 consume_skb(skb);
58 return;
59 default:
60 netdev_dbg(netdev, "unexpected tx urb status: %d\n", status);
61 netdev->stats.tx_dropped++;
62 }
63
64 kfree_skb(skb);
65 }
66
mctp_usb_start_xmit(struct sk_buff * skb,struct net_device * dev)67 static netdev_tx_t mctp_usb_start_xmit(struct sk_buff *skb,
68 struct net_device *dev)
69 {
70 struct mctp_usb *mctp_usb = netdev_priv(dev);
71 struct mctp_usb_hdr *hdr;
72 unsigned int plen;
73 struct urb *urb;
74 int rc;
75
76 plen = skb->len;
77
78 if (plen + sizeof(*hdr) > MCTP_USB_XFER_SIZE)
79 goto err_drop;
80
81 rc = skb_cow_head(skb, sizeof(*hdr));
82 if (rc)
83 goto err_drop;
84
85 hdr = skb_push(skb, sizeof(*hdr));
86 if (!hdr)
87 goto err_drop;
88
89 hdr->id = cpu_to_be16(MCTP_USB_DMTF_ID);
90 hdr->rsvd = 0;
91 hdr->len = plen + sizeof(*hdr);
92
93 urb = mctp_usb->tx_urb;
94
95 usb_fill_bulk_urb(urb, mctp_usb->usbdev,
96 usb_sndbulkpipe(mctp_usb->usbdev, mctp_usb->ep_out),
97 skb->data, skb->len,
98 mctp_usb_out_complete, skb);
99
100 rc = usb_submit_urb(urb, GFP_ATOMIC);
101 if (rc)
102 goto err_drop;
103 else
104 netif_stop_queue(dev);
105
106 return NETDEV_TX_OK;
107
108 err_drop:
109 dev->stats.tx_dropped++;
110 kfree_skb(skb);
111 return NETDEV_TX_OK;
112 }
113
114 static void mctp_usb_in_complete(struct urb *urb);
115
116 /* If we fail to queue an in urb atomically (either due to skb allocation or
117 * urb submission), we will schedule a rx queue in nonatomic context
118 * after a delay, specified in jiffies
119 */
120 static const unsigned long RX_RETRY_DELAY = HZ / 4;
121
mctp_usb_rx_queue(struct mctp_usb * mctp_usb,gfp_t gfp)122 static int mctp_usb_rx_queue(struct mctp_usb *mctp_usb, gfp_t gfp)
123 {
124 struct sk_buff *skb;
125 int rc;
126
127 skb = __netdev_alloc_skb(mctp_usb->netdev, MCTP_USB_XFER_SIZE, gfp);
128 if (!skb) {
129 rc = -ENOMEM;
130 goto err_retry;
131 }
132
133 usb_fill_bulk_urb(mctp_usb->rx_urb, mctp_usb->usbdev,
134 usb_rcvbulkpipe(mctp_usb->usbdev, mctp_usb->ep_in),
135 skb->data, MCTP_USB_XFER_SIZE,
136 mctp_usb_in_complete, skb);
137
138 rc = usb_submit_urb(mctp_usb->rx_urb, gfp);
139 if (rc) {
140 netdev_dbg(mctp_usb->netdev, "rx urb submit failure: %d\n", rc);
141 kfree_skb(skb);
142 if (rc == -ENOMEM)
143 goto err_retry;
144 }
145
146 return rc;
147
148 err_retry:
149 schedule_delayed_work(&mctp_usb->rx_retry_work, RX_RETRY_DELAY);
150 return rc;
151 }
152
mctp_usb_in_complete(struct urb * urb)153 static void mctp_usb_in_complete(struct urb *urb)
154 {
155 struct sk_buff *skb = urb->context;
156 struct net_device *netdev = skb->dev;
157 struct mctp_usb *mctp_usb = netdev_priv(netdev);
158 struct mctp_skb_cb *cb;
159 unsigned int len;
160 int status;
161
162 status = urb->status;
163
164 switch (status) {
165 case -ENOENT:
166 case -ECONNRESET:
167 case -ESHUTDOWN:
168 case -EPROTO:
169 kfree_skb(skb);
170 return;
171 case 0:
172 break;
173 default:
174 netdev_dbg(netdev, "unexpected rx urb status: %d\n", status);
175 kfree_skb(skb);
176 return;
177 }
178
179 len = urb->actual_length;
180 __skb_put(skb, len);
181
182 while (skb) {
183 struct sk_buff *skb2 = NULL;
184 struct mctp_usb_hdr *hdr;
185 u8 pkt_len; /* length of MCTP packet, no USB header */
186
187 hdr = skb_pull_data(skb, sizeof(*hdr));
188 if (!hdr)
189 break;
190
191 if (be16_to_cpu(hdr->id) != MCTP_USB_DMTF_ID) {
192 netdev_dbg(netdev, "rx: invalid id %04x\n",
193 be16_to_cpu(hdr->id));
194 break;
195 }
196
197 if (hdr->len <
198 sizeof(struct mctp_hdr) + sizeof(struct mctp_usb_hdr)) {
199 netdev_dbg(netdev, "rx: short packet (hdr) %d\n",
200 hdr->len);
201 break;
202 }
203
204 /* we know we have at least sizeof(struct mctp_usb_hdr) here */
205 pkt_len = hdr->len - sizeof(struct mctp_usb_hdr);
206 if (pkt_len > skb->len) {
207 netdev_dbg(netdev,
208 "rx: short packet (xfer) %d, actual %d\n",
209 hdr->len, skb->len);
210 break;
211 }
212
213 if (pkt_len < skb->len) {
214 /* more packets may follow - clone to a new
215 * skb to use on the next iteration
216 */
217 skb2 = skb_clone(skb, GFP_ATOMIC);
218 if (skb2) {
219 if (!skb_pull(skb2, pkt_len)) {
220 kfree_skb(skb2);
221 skb2 = NULL;
222 }
223 }
224 skb_trim(skb, pkt_len);
225 }
226
227 netdev->stats.rx_packets++;
228 netdev->stats.rx_bytes += skb->len;
229
230 skb->protocol = htons(ETH_P_MCTP);
231 skb_reset_network_header(skb);
232 cb = __mctp_cb(skb);
233 cb->halen = 0;
234 netif_rx(skb);
235
236 skb = skb2;
237 }
238
239 if (skb)
240 kfree_skb(skb);
241
242 mctp_usb_rx_queue(mctp_usb, GFP_ATOMIC);
243 }
244
mctp_usb_rx_retry_work(struct work_struct * work)245 static void mctp_usb_rx_retry_work(struct work_struct *work)
246 {
247 struct mctp_usb *mctp_usb = container_of(work, struct mctp_usb,
248 rx_retry_work.work);
249
250 if (READ_ONCE(mctp_usb->stopped))
251 return;
252
253 mctp_usb_rx_queue(mctp_usb, GFP_KERNEL);
254 }
255
mctp_usb_open(struct net_device * dev)256 static int mctp_usb_open(struct net_device *dev)
257 {
258 struct mctp_usb *mctp_usb = netdev_priv(dev);
259
260 WRITE_ONCE(mctp_usb->stopped, false);
261
262 return mctp_usb_rx_queue(mctp_usb, GFP_KERNEL);
263 }
264
mctp_usb_stop(struct net_device * dev)265 static int mctp_usb_stop(struct net_device *dev)
266 {
267 struct mctp_usb *mctp_usb = netdev_priv(dev);
268
269 netif_stop_queue(dev);
270
271 /* prevent RX submission retry */
272 WRITE_ONCE(mctp_usb->stopped, true);
273
274 usb_kill_urb(mctp_usb->rx_urb);
275 usb_kill_urb(mctp_usb->tx_urb);
276
277 cancel_delayed_work_sync(&mctp_usb->rx_retry_work);
278
279 return 0;
280 }
281
282 static const struct net_device_ops mctp_usb_netdev_ops = {
283 .ndo_start_xmit = mctp_usb_start_xmit,
284 .ndo_open = mctp_usb_open,
285 .ndo_stop = mctp_usb_stop,
286 };
287
mctp_usb_netdev_setup(struct net_device * dev)288 static void mctp_usb_netdev_setup(struct net_device *dev)
289 {
290 dev->type = ARPHRD_MCTP;
291
292 dev->mtu = MCTP_USB_MTU_MIN;
293 dev->min_mtu = MCTP_USB_MTU_MIN;
294 dev->max_mtu = MCTP_USB_MTU_MAX;
295
296 dev->hard_header_len = sizeof(struct mctp_usb_hdr);
297 dev->tx_queue_len = DEFAULT_TX_QUEUE_LEN;
298 dev->flags = IFF_NOARP;
299 dev->netdev_ops = &mctp_usb_netdev_ops;
300 }
301
mctp_usb_probe(struct usb_interface * intf,const struct usb_device_id * id)302 static int mctp_usb_probe(struct usb_interface *intf,
303 const struct usb_device_id *id)
304 {
305 struct usb_endpoint_descriptor *ep_in, *ep_out;
306 struct usb_host_interface *iface_desc;
307 struct net_device *netdev;
308 struct mctp_usb *dev;
309 int rc;
310
311 /* only one alternate */
312 iface_desc = intf->cur_altsetting;
313
314 rc = usb_find_common_endpoints(iface_desc, &ep_in, &ep_out, NULL, NULL);
315 if (rc) {
316 dev_err(&intf->dev, "invalid endpoints on device?\n");
317 return rc;
318 }
319
320 netdev = alloc_netdev(sizeof(*dev), "mctpusb%d", NET_NAME_ENUM,
321 mctp_usb_netdev_setup);
322 if (!netdev)
323 return -ENOMEM;
324
325 SET_NETDEV_DEV(netdev, &intf->dev);
326 dev = netdev_priv(netdev);
327 dev->netdev = netdev;
328 dev->usbdev = usb_get_dev(interface_to_usbdev(intf));
329 dev->intf = intf;
330 usb_set_intfdata(intf, dev);
331
332 dev->ep_in = ep_in->bEndpointAddress;
333 dev->ep_out = ep_out->bEndpointAddress;
334
335 dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
336 dev->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
337 if (!dev->tx_urb || !dev->rx_urb) {
338 rc = -ENOMEM;
339 goto err_free_urbs;
340 }
341
342 INIT_DELAYED_WORK(&dev->rx_retry_work, mctp_usb_rx_retry_work);
343
344 rc = mctp_register_netdev(netdev, NULL, MCTP_PHYS_BINDING_USB);
345 if (rc)
346 goto err_free_urbs;
347
348 return 0;
349
350 err_free_urbs:
351 usb_free_urb(dev->tx_urb);
352 usb_free_urb(dev->rx_urb);
353 free_netdev(netdev);
354 return rc;
355 }
356
mctp_usb_disconnect(struct usb_interface * intf)357 static void mctp_usb_disconnect(struct usb_interface *intf)
358 {
359 struct mctp_usb *dev = usb_get_intfdata(intf);
360
361 mctp_unregister_netdev(dev->netdev);
362 usb_free_urb(dev->tx_urb);
363 usb_free_urb(dev->rx_urb);
364 usb_put_dev(dev->usbdev);
365 free_netdev(dev->netdev);
366 }
367
368 static const struct usb_device_id mctp_usb_devices[] = {
369 { USB_INTERFACE_INFO(USB_CLASS_MCTP, 0x0, 0x1) },
370 { 0 },
371 };
372
373 MODULE_DEVICE_TABLE(usb, mctp_usb_devices);
374
375 static struct usb_driver mctp_usb_driver = {
376 .name = "mctp-usb",
377 .id_table = mctp_usb_devices,
378 .probe = mctp_usb_probe,
379 .disconnect = mctp_usb_disconnect,
380 };
381
382 module_usb_driver(mctp_usb_driver)
383
384 MODULE_LICENSE("GPL");
385 MODULE_AUTHOR("Jeremy Kerr <jk@codeconstruct.com.au>");
386 MODULE_DESCRIPTION("MCTP USB transport");
387