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