1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * mctp-usblib-test.c - MCTP-over-USB (DMTF DSP0283) transport helper library, 4 * unit test definitions. 5 * 6 * Copyright (C) 2026 Code Construct Pty Ltd 7 */ 8 9 #include <uapi/linux/netdevice.h> 10 #include <linux/netdevice.h> 11 #include <kunit/test.h> 12 #include <linux/if_arp.h> 13 #include <net/mctp.h> 14 #include <net/mctpdevice.h> 15 #include <linux/usb/mctp-usb.h> 16 17 struct mctp_usblib_test_dev { 18 struct net_device *ndev; 19 struct mctp_dev *mdev; 20 struct sk_buff_head rx_pkts; 21 }; 22 23 struct mctp_usblib_test_ctx { 24 struct mctp_usblib_test_dev *dev; 25 struct mctp_route rt; 26 }; 27 28 static netdev_tx_t mctp_usblib_dev_tx(struct sk_buff *skb, 29 struct net_device *ndev) 30 { 31 /* we don't track any TXed packets at present */ 32 kfree_skb(skb); 33 return NETDEV_TX_OK; 34 } 35 36 static const struct net_device_ops mctp_test_netdev_ops = { 37 .ndo_start_xmit = mctp_usblib_dev_tx, 38 }; 39 40 static const u16 ep_maxpacket = 512; 41 static const mctp_eid_t local_eid = 8; 42 43 static void mctp_usblib_dev_setup(struct net_device *ndev) 44 { 45 ndev->type = ARPHRD_MCTP; 46 ndev->mtu = 8192; 47 ndev->flags = IFF_NOARP; 48 ndev->netdev_ops = &mctp_test_netdev_ops; 49 ndev->needs_free_netdev = true; 50 ndev->pcpu_stat_type = NETDEV_PCPU_STAT_DSTATS; 51 } 52 53 static void mctp_usblib_test_dev_action(void *data) 54 { 55 struct mctp_usblib_test_dev *dev = data; 56 57 skb_queue_purge(&dev->rx_pkts); 58 if (dev->mdev) 59 mctp_dev_put(dev->mdev); 60 unregister_netdev(dev->ndev); 61 } 62 63 static struct mctp_usblib_test_dev * 64 mctp_usblib_test_create_dev(struct kunit *test) 65 { 66 struct mctp_usblib_test_dev *dev; 67 struct net_device *ndev; 68 int rc; 69 70 ndev = alloc_netdev(sizeof(*dev), "mctptest%d", NET_NAME_ENUM, 71 mctp_usblib_dev_setup); 72 if (!ndev) 73 return NULL; 74 75 dev = netdev_priv(ndev); 76 dev->ndev = ndev; 77 skb_queue_head_init(&dev->rx_pkts); 78 79 rc = register_netdev(ndev); 80 if (rc) { 81 free_netdev(ndev); 82 return NULL; 83 } 84 85 rc = kunit_add_action_or_reset(test, mctp_usblib_test_dev_action, dev); 86 if (rc) 87 return NULL; 88 89 rcu_read_lock(); 90 dev->mdev = __mctp_dev_get(ndev); 91 if (dev->mdev) 92 dev->mdev->net = mctp_default_net(dev_net(ndev)); 93 rcu_read_unlock(); 94 95 if (!dev->mdev) 96 return NULL; 97 98 rtnl_lock(); 99 rc = dev_open(ndev, NULL); 100 rtnl_unlock(); 101 if (rc) 102 return NULL; 103 104 return dev; 105 } 106 107 static int mctp_usblib_test_dst_output(struct mctp_dst *dst, 108 struct sk_buff *skb) 109 { 110 struct mctp_usblib_test_dev *dev = netdev_priv(skb->dev); 111 112 skb_queue_tail(&dev->rx_pkts, skb); 113 114 return 0; 115 } 116 117 static void mctp_usblib_test_fini_action(void *data) 118 { 119 struct mctp_usblib_test_ctx *ctx = data; 120 121 /* The device will have been destroyed, so ->rt will be unlinked. 122 * Just ensure that the refcount is as expected. 123 */ 124 KUNIT_EXPECT_TRUE(current->kunit_test, 125 refcount_dec_and_test(&ctx->rt.refs)); 126 127 kfree(ctx); 128 } 129 130 static struct mctp_usblib_test_ctx *mctp_usblib_test_init(struct kunit *test) 131 { 132 struct mctp_usblib_test_ctx *ctx; 133 struct mctp_route *rt; 134 int rc; 135 136 ctx = kzalloc_obj(*ctx); 137 KUNIT_ASSERT_NOT_NULL(test, ctx); 138 139 INIT_LIST_HEAD(&ctx->rt.list); 140 rt = &ctx->rt; 141 refcount_set(&rt->refs, 1); 142 143 rc = kunit_add_action_or_reset(test, mctp_usblib_test_fini_action, ctx); 144 KUNIT_ASSERT_EQ(test, rc, 0); 145 146 ctx->dev = mctp_usblib_test_create_dev(test); 147 KUNIT_ASSERT_NOT_NULL(test, ctx->dev); 148 149 rt->min = local_eid; 150 rt->max = local_eid; 151 rt->dst_type = MCTP_ROUTE_DIRECT; 152 rt->type = RTN_LOCAL; 153 rt->dev = ctx->dev->mdev; 154 rt->output = mctp_usblib_test_dst_output; 155 156 rtnl_lock(); 157 list_add_rcu(&ctx->rt.list, &init_net.mctp.routes); 158 refcount_inc(&rt->refs); 159 rtnl_unlock(); 160 161 return ctx; 162 } 163 164 /* Init a MCTP-over-USB packet within a buffer. @len is the length of the 165 * buffer to write, @payload_len is the reported size of the MCTP-over-USB 166 * packet. 167 */ 168 static void mctp_usblib_test_init_pkt(void *data, size_t len, 169 size_t payload_len) 170 { 171 struct { 172 struct mctp_usb_hdr usb; 173 struct mctp_hdr mctp; 174 } hdr; 175 176 hdr.usb.id = cpu_to_be16(MCTP_USB_DMTF_ID); 177 hdr.usb.len = cpu_to_be16(payload_len); 178 hdr.mctp.ver = 1; 179 hdr.mctp.dest = local_eid; 180 hdr.mctp.src = 0; 181 hdr.mctp.flags_seq_tag = 0; 182 183 memcpy(data, &hdr, min(len, sizeof(hdr))); 184 if (len > sizeof(hdr)) 185 memset(data + sizeof(hdr), 0, len - sizeof(hdr)); 186 } 187 188 static void action_rx_fini(void *data) 189 { 190 struct mctp_usblib_rx *rx = data; 191 192 mctp_usblib_rx_fini(rx); 193 kfree(rx); 194 } 195 196 static struct mctp_usblib_rx * 197 mctp_usblib_test_rx_init(struct kunit *test, bool span) 198 { 199 struct mctp_usblib_rx *rx; 200 int rc; 201 202 rx = kzalloc_obj(*rx); 203 if (rx) { 204 rc = kunit_add_action_or_reset(test, action_rx_fini, rx); 205 KUNIT_ASSERT_EQ(test, rc, 0); 206 } 207 KUNIT_ASSERT_NOT_NULL(test, rx); 208 209 rc = mctp_usblib_rx_init(rx, ep_maxpacket, span); 210 KUNIT_ASSERT_EQ(test, rc, 0); 211 212 return rx; 213 } 214 215 /* Wrappers for usblib's rx_complete callback, which is intended to be called 216 * from atomic context 217 */ 218 static int mctp_usblib_test_rx_complete(struct net_device *netdev, 219 struct mctp_usblib_rx *rx, size_t len) 220 { 221 int rc; 222 223 local_bh_disable(); 224 rc = mctp_usblib_rx_complete(netdev, rx, len); 225 local_bh_enable(); 226 227 return rc; 228 } 229 230 /* Single packet, starting on a transfer boundary, contained entirely within 231 * the transfer 232 */ 233 static void mctp_usblib_test_rx_single(struct kunit *test) 234 { 235 struct mctp_usblib_test_dev *dev; 236 struct mctp_usblib_test_ctx *ctx; 237 struct mctp_usblib_rx *rx; 238 struct sk_buff *skb; 239 size_t len; 240 void *buf; 241 int rc; 242 243 ctx = mctp_usblib_test_init(test); 244 dev = ctx->dev; 245 246 rx = mctp_usblib_test_rx_init(test, true); 247 248 rc = mctp_usblib_rx_prepare(dev->ndev, rx, 249 &buf, &len, GFP_KERNEL); 250 KUNIT_ASSERT_EQ(test, rc, 0); 251 252 /* we should always have a maxpacket of transfer available */ 253 KUNIT_ASSERT_GE(test, len, ep_maxpacket); 254 255 mctp_usblib_test_init_pkt(buf, 8, 8); 256 257 rc = mctp_usblib_test_rx_complete(dev->ndev, rx, 8); 258 KUNIT_ASSERT_EQ(test, rc, 0); 259 260 skb = __skb_dequeue(&dev->rx_pkts); 261 KUNIT_EXPECT_NOT_NULL(test, skb); 262 if (skb) 263 KUNIT_EXPECT_EQ(test, skb->len, 4); 264 kfree_skb(skb); 265 } 266 267 struct mctp_usblib_test_pkt_span { 268 const char *name; 269 size_t n_pkts; 270 size_t pkts[6]; 271 size_t n_xfers; 272 size_t xfers[6]; 273 }; 274 275 static void 276 mctp_usblib_test_pkt_span_to_desc(const struct mctp_usblib_test_pkt_span *t, 277 char *desc) 278 { 279 strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); 280 } 281 282 static void 283 mctp_usblib_test_pkt_span_validate(struct kunit *test, 284 const struct mctp_usblib_test_pkt_span *span, 285 size_t *len) 286 { 287 size_t pkt_len = 0, xfer_len = 0; 288 unsigned int i; 289 290 for (i = 0; i < span->n_pkts; i++) { 291 KUNIT_ASSERT_GE_MSG(test, span->pkts[i], 8, 292 "pkt[%u] len too small (%zu) for %s", 293 i, span->pkts[i], span->name); 294 pkt_len += span->pkts[i]; 295 } 296 297 for (i = 0; i < span->n_xfers; i++) 298 xfer_len += span->xfers[i]; 299 300 KUNIT_ASSERT_EQ_MSG(test, pkt_len, xfer_len, 301 "invalid pkt_len (%zu) != xfer_len (%zu) for %s", 302 pkt_len, xfer_len, span->name); 303 304 *len = pkt_len; 305 } 306 307 static void mctp_usblib_test_rx_pkt_span(struct kunit *test) 308 { 309 const struct mctp_usblib_test_pkt_span *pkt_span = test->param_value; 310 size_t len, xfer_len, off, xfer_off; 311 struct mctp_usblib_test_dev *dev; 312 struct mctp_usblib_test_ctx *ctx; 313 struct mctp_usblib_rx *rx; 314 unsigned int i; 315 u8 *pktbuf; 316 void *buf; 317 int rc; 318 319 mctp_usblib_test_pkt_span_validate(test, pkt_span, &len); 320 pktbuf = kunit_kmalloc_array(test, 1, len, GFP_KERNEL); 321 KUNIT_ASSERT_NOT_NULL(test, pktbuf); 322 323 /* lay out packets */ 324 for (off = 0, i = 0; i < pkt_span->n_pkts; i++) { 325 len = pkt_span->pkts[i]; 326 mctp_usblib_test_init_pkt(pktbuf + off, len, len); 327 off += len; 328 } 329 330 ctx = mctp_usblib_test_init(test); 331 dev = ctx->dev; 332 333 rx = mctp_usblib_test_rx_init(test, true); 334 335 /* feed transfers */ 336 for (off = 0, xfer_off = 0, i = 0; i < pkt_span->n_xfers;) { 337 xfer_len = pkt_span->xfers[i] - xfer_off; 338 rc = mctp_usblib_rx_prepare(dev->ndev, rx, 339 &buf, &len, GFP_KERNEL); 340 KUNIT_ASSERT_EQ(test, rc, 0); 341 342 KUNIT_ASSERT_GE(test, len, ep_maxpacket); 343 344 len = min(len, xfer_len); 345 memcpy(buf, pktbuf + off, len); 346 347 if (len == xfer_len) { 348 /* whole/end xfer, proceed to next */ 349 xfer_off = 0; 350 i++; 351 } else { 352 /* partial */ 353 xfer_off += len; 354 } 355 356 rc = mctp_usblib_test_rx_complete(dev->ndev, rx, len); 357 KUNIT_ASSERT_EQ(test, rc, 0); 358 off += len; 359 } 360 361 /* check received packets */ 362 KUNIT_EXPECT_EQ(test, dev->rx_pkts.qlen, pkt_span->n_pkts); 363 for (i = 0; ; i++) { 364 struct sk_buff *skb = __skb_dequeue(&dev->rx_pkts); 365 366 if (!skb) 367 break; 368 369 if (i < pkt_span->n_pkts) 370 KUNIT_EXPECT_EQ(test, skb->len, pkt_span->pkts[i] - 4); 371 372 kfree_skb(skb); 373 } 374 } 375 376 static const struct mctp_usblib_test_pkt_span mctp_usblib_test_pkt_spans[] = { 377 /* One packet completely within a transfer */ 378 { "1p1x-complete", 1, { 8 }, 1, { 8 } }, 379 /* Two small packets combined within one transfer */ 380 { "2p1x-combined", 2, { 8, 8 }, 1, { 16 } }, 381 /* A packet split over two transfers, at the MCTP payload */ 382 { "1p2x-split-payload", 1, { 16 }, 2, { 8, 8 } }, 383 /* A packet split over two transfers, at the USB transport header */ 384 { "1p2x-split-usbhdr", 1, { 16 }, 2, { 2, 14 } }, 385 /* A packet split over two transfers, at the MCTP header */ 386 { "1p2x-split-mctphdr", 1, { 16 }, 2, { 6, 10 } }, 387 /* Single packet split over 3 transfers, middle entirely continuation */ 388 { "1p3x-split", 1, { 12 }, 3, { 4, 4, 4 } }, 389 /* Max-sized single transfer */ 390 { "1p1x-large", 1, { 8191 }, 1, { 8191 } }, 391 /* Two large packets, split at the worst-case for allocation, with a 392 * single byte continuing the span 393 */ 394 { "2p2x-large-split", 2, { 8190, 8190 }, 2, { 8191, 8189 } }, 395 }; 396 397 KUNIT_ARRAY_PARAM(mctp_usblib_test_rx_pkt_span, mctp_usblib_test_pkt_spans, 398 mctp_usblib_test_pkt_span_to_desc); 399 400 static struct kunit_case mctp_usblib_test_cases[] = { 401 KUNIT_CASE(mctp_usblib_test_rx_single), 402 KUNIT_CASE_PARAM(mctp_usblib_test_rx_pkt_span, 403 mctp_usblib_test_rx_pkt_span_gen_params), 404 {} 405 }; 406 407 static struct kunit_suite mctp_usblib_test_suite = { 408 .name = "mctp-usblib", 409 .test_cases = mctp_usblib_test_cases, 410 }; 411 412 kunit_test_suite(mctp_usblib_test_suite); 413