1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <kunit/test.h>
4
5 #include "utils.h"
6
7 struct mctp_test_route {
8 struct mctp_route rt;
9 struct sk_buff_head pkts;
10 };
11
mctp_test_route_output(struct mctp_route * rt,struct sk_buff * skb)12 static int mctp_test_route_output(struct mctp_route *rt, struct sk_buff *skb)
13 {
14 struct mctp_test_route *test_rt = container_of(rt, struct mctp_test_route, rt);
15
16 skb_queue_tail(&test_rt->pkts, skb);
17
18 return 0;
19 }
20
21 /* local version of mctp_route_alloc() */
mctp_route_test_alloc(void)22 static struct mctp_test_route *mctp_route_test_alloc(void)
23 {
24 struct mctp_test_route *rt;
25
26 rt = kzalloc(sizeof(*rt), GFP_KERNEL);
27 if (!rt)
28 return NULL;
29
30 INIT_LIST_HEAD(&rt->rt.list);
31 refcount_set(&rt->rt.refs, 1);
32 rt->rt.output = mctp_test_route_output;
33
34 skb_queue_head_init(&rt->pkts);
35
36 return rt;
37 }
38
mctp_test_create_route(struct net * net,struct mctp_dev * dev,mctp_eid_t eid,unsigned int mtu)39 static struct mctp_test_route *mctp_test_create_route(struct net *net,
40 struct mctp_dev *dev,
41 mctp_eid_t eid,
42 unsigned int mtu)
43 {
44 struct mctp_test_route *rt;
45
46 rt = mctp_route_test_alloc();
47 if (!rt)
48 return NULL;
49
50 rt->rt.min = eid;
51 rt->rt.max = eid;
52 rt->rt.mtu = mtu;
53 rt->rt.type = RTN_UNSPEC;
54 if (dev)
55 mctp_dev_hold(dev);
56 rt->rt.dev = dev;
57
58 list_add_rcu(&rt->rt.list, &net->mctp.routes);
59
60 return rt;
61 }
62
mctp_test_route_destroy(struct kunit * test,struct mctp_test_route * rt)63 static void mctp_test_route_destroy(struct kunit *test,
64 struct mctp_test_route *rt)
65 {
66 unsigned int refs;
67
68 rtnl_lock();
69 list_del_rcu(&rt->rt.list);
70 rtnl_unlock();
71
72 skb_queue_purge(&rt->pkts);
73 if (rt->rt.dev)
74 mctp_dev_put(rt->rt.dev);
75
76 refs = refcount_read(&rt->rt.refs);
77 KUNIT_ASSERT_EQ_MSG(test, refs, 1, "route ref imbalance");
78
79 kfree_rcu(&rt->rt, rcu);
80 }
81
mctp_test_create_skb(const struct mctp_hdr * hdr,unsigned int data_len)82 static struct sk_buff *mctp_test_create_skb(const struct mctp_hdr *hdr,
83 unsigned int data_len)
84 {
85 size_t hdr_len = sizeof(*hdr);
86 struct sk_buff *skb;
87 unsigned int i;
88 u8 *buf;
89
90 skb = alloc_skb(hdr_len + data_len, GFP_KERNEL);
91 if (!skb)
92 return NULL;
93
94 memcpy(skb_put(skb, hdr_len), hdr, hdr_len);
95
96 buf = skb_put(skb, data_len);
97 for (i = 0; i < data_len; i++)
98 buf[i] = i & 0xff;
99
100 return skb;
101 }
102
__mctp_test_create_skb_data(const struct mctp_hdr * hdr,const void * data,size_t data_len)103 static struct sk_buff *__mctp_test_create_skb_data(const struct mctp_hdr *hdr,
104 const void *data,
105 size_t data_len)
106 {
107 size_t hdr_len = sizeof(*hdr);
108 struct sk_buff *skb;
109
110 skb = alloc_skb(hdr_len + data_len, GFP_KERNEL);
111 if (!skb)
112 return NULL;
113
114 memcpy(skb_put(skb, hdr_len), hdr, hdr_len);
115 memcpy(skb_put(skb, data_len), data, data_len);
116
117 return skb;
118 }
119
120 #define mctp_test_create_skb_data(h, d) \
121 __mctp_test_create_skb_data(h, d, sizeof(*d))
122
123 struct mctp_frag_test {
124 unsigned int mtu;
125 unsigned int msgsize;
126 unsigned int n_frags;
127 };
128
mctp_test_fragment(struct kunit * test)129 static void mctp_test_fragment(struct kunit *test)
130 {
131 const struct mctp_frag_test *params;
132 int rc, i, n, mtu, msgsize;
133 struct mctp_test_route *rt;
134 struct sk_buff *skb;
135 struct mctp_hdr hdr;
136 u8 seq;
137
138 params = test->param_value;
139 mtu = params->mtu;
140 msgsize = params->msgsize;
141
142 hdr.ver = 1;
143 hdr.src = 8;
144 hdr.dest = 10;
145 hdr.flags_seq_tag = MCTP_HDR_FLAG_TO;
146
147 skb = mctp_test_create_skb(&hdr, msgsize);
148 KUNIT_ASSERT_TRUE(test, skb);
149
150 rt = mctp_test_create_route(&init_net, NULL, 10, mtu);
151 KUNIT_ASSERT_TRUE(test, rt);
152
153 /* The refcount would usually be incremented as part of a route lookup,
154 * but we're setting the route directly here.
155 */
156 refcount_inc(&rt->rt.refs);
157
158 rc = mctp_do_fragment_route(&rt->rt, skb, mtu, MCTP_TAG_OWNER);
159 KUNIT_EXPECT_FALSE(test, rc);
160
161 n = rt->pkts.qlen;
162
163 KUNIT_EXPECT_EQ(test, n, params->n_frags);
164
165 for (i = 0;; i++) {
166 struct mctp_hdr *hdr2;
167 struct sk_buff *skb2;
168 u8 tag_mask, seq2;
169 bool first, last;
170
171 first = i == 0;
172 last = i == (n - 1);
173
174 skb2 = skb_dequeue(&rt->pkts);
175
176 if (!skb2)
177 break;
178
179 hdr2 = mctp_hdr(skb2);
180
181 tag_mask = MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO;
182
183 KUNIT_EXPECT_EQ(test, hdr2->ver, hdr.ver);
184 KUNIT_EXPECT_EQ(test, hdr2->src, hdr.src);
185 KUNIT_EXPECT_EQ(test, hdr2->dest, hdr.dest);
186 KUNIT_EXPECT_EQ(test, hdr2->flags_seq_tag & tag_mask,
187 hdr.flags_seq_tag & tag_mask);
188
189 KUNIT_EXPECT_EQ(test,
190 !!(hdr2->flags_seq_tag & MCTP_HDR_FLAG_SOM), first);
191 KUNIT_EXPECT_EQ(test,
192 !!(hdr2->flags_seq_tag & MCTP_HDR_FLAG_EOM), last);
193
194 seq2 = (hdr2->flags_seq_tag >> MCTP_HDR_SEQ_SHIFT) &
195 MCTP_HDR_SEQ_MASK;
196
197 if (first) {
198 seq = seq2;
199 } else {
200 seq++;
201 KUNIT_EXPECT_EQ(test, seq2, seq & MCTP_HDR_SEQ_MASK);
202 }
203
204 if (!last)
205 KUNIT_EXPECT_EQ(test, skb2->len, mtu);
206 else
207 KUNIT_EXPECT_LE(test, skb2->len, mtu);
208
209 kfree_skb(skb2);
210 }
211
212 mctp_test_route_destroy(test, rt);
213 }
214
215 static const struct mctp_frag_test mctp_frag_tests[] = {
216 {.mtu = 68, .msgsize = 63, .n_frags = 1},
217 {.mtu = 68, .msgsize = 64, .n_frags = 1},
218 {.mtu = 68, .msgsize = 65, .n_frags = 2},
219 {.mtu = 68, .msgsize = 66, .n_frags = 2},
220 {.mtu = 68, .msgsize = 127, .n_frags = 2},
221 {.mtu = 68, .msgsize = 128, .n_frags = 2},
222 {.mtu = 68, .msgsize = 129, .n_frags = 3},
223 {.mtu = 68, .msgsize = 130, .n_frags = 3},
224 };
225
mctp_frag_test_to_desc(const struct mctp_frag_test * t,char * desc)226 static void mctp_frag_test_to_desc(const struct mctp_frag_test *t, char *desc)
227 {
228 sprintf(desc, "mtu %d len %d -> %d frags",
229 t->msgsize, t->mtu, t->n_frags);
230 }
231
232 KUNIT_ARRAY_PARAM(mctp_frag, mctp_frag_tests, mctp_frag_test_to_desc);
233
234 struct mctp_rx_input_test {
235 struct mctp_hdr hdr;
236 bool input;
237 };
238
mctp_test_rx_input(struct kunit * test)239 static void mctp_test_rx_input(struct kunit *test)
240 {
241 const struct mctp_rx_input_test *params;
242 struct mctp_test_route *rt;
243 struct mctp_test_dev *dev;
244 struct sk_buff *skb;
245
246 params = test->param_value;
247
248 dev = mctp_test_create_dev();
249 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
250
251 rt = mctp_test_create_route(&init_net, dev->mdev, 8, 68);
252 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt);
253
254 skb = mctp_test_create_skb(¶ms->hdr, 1);
255 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb);
256
257 __mctp_cb(skb);
258
259 mctp_pkttype_receive(skb, dev->ndev, &mctp_packet_type, NULL);
260
261 KUNIT_EXPECT_EQ(test, !!rt->pkts.qlen, params->input);
262
263 mctp_test_route_destroy(test, rt);
264 mctp_test_destroy_dev(dev);
265 }
266
267 #define RX_HDR(_ver, _src, _dest, _fst) \
268 { .ver = _ver, .src = _src, .dest = _dest, .flags_seq_tag = _fst }
269
270 /* we have a route for EID 8 only */
271 static const struct mctp_rx_input_test mctp_rx_input_tests[] = {
272 { .hdr = RX_HDR(1, 10, 8, 0), .input = true },
273 { .hdr = RX_HDR(1, 10, 9, 0), .input = false }, /* no input route */
274 { .hdr = RX_HDR(2, 10, 8, 0), .input = false }, /* invalid version */
275 };
276
mctp_rx_input_test_to_desc(const struct mctp_rx_input_test * t,char * desc)277 static void mctp_rx_input_test_to_desc(const struct mctp_rx_input_test *t,
278 char *desc)
279 {
280 sprintf(desc, "{%x,%x,%x,%x}", t->hdr.ver, t->hdr.src, t->hdr.dest,
281 t->hdr.flags_seq_tag);
282 }
283
284 KUNIT_ARRAY_PARAM(mctp_rx_input, mctp_rx_input_tests,
285 mctp_rx_input_test_to_desc);
286
287 /* set up a local dev, route on EID 8, and a socket listening on type 0 */
__mctp_route_test_init(struct kunit * test,struct mctp_test_dev ** devp,struct mctp_test_route ** rtp,struct socket ** sockp)288 static void __mctp_route_test_init(struct kunit *test,
289 struct mctp_test_dev **devp,
290 struct mctp_test_route **rtp,
291 struct socket **sockp)
292 {
293 struct sockaddr_mctp addr;
294 struct mctp_test_route *rt;
295 struct mctp_test_dev *dev;
296 struct socket *sock;
297 int rc;
298
299 dev = mctp_test_create_dev();
300 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
301
302 rt = mctp_test_create_route(&init_net, dev->mdev, 8, 68);
303 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt);
304
305 rc = sock_create_kern(&init_net, AF_MCTP, SOCK_DGRAM, 0, &sock);
306 KUNIT_ASSERT_EQ(test, rc, 0);
307
308 addr.smctp_family = AF_MCTP;
309 addr.smctp_network = MCTP_NET_ANY;
310 addr.smctp_addr.s_addr = 8;
311 addr.smctp_type = 0;
312 rc = kernel_bind(sock, (struct sockaddr *)&addr, sizeof(addr));
313 KUNIT_ASSERT_EQ(test, rc, 0);
314
315 *rtp = rt;
316 *devp = dev;
317 *sockp = sock;
318 }
319
__mctp_route_test_fini(struct kunit * test,struct mctp_test_dev * dev,struct mctp_test_route * rt,struct socket * sock)320 static void __mctp_route_test_fini(struct kunit *test,
321 struct mctp_test_dev *dev,
322 struct mctp_test_route *rt,
323 struct socket *sock)
324 {
325 sock_release(sock);
326 mctp_test_route_destroy(test, rt);
327 mctp_test_destroy_dev(dev);
328 }
329
330 struct mctp_route_input_sk_test {
331 struct mctp_hdr hdr;
332 u8 type;
333 bool deliver;
334 };
335
mctp_test_route_input_sk(struct kunit * test)336 static void mctp_test_route_input_sk(struct kunit *test)
337 {
338 const struct mctp_route_input_sk_test *params;
339 struct sk_buff *skb, *skb2;
340 struct mctp_test_route *rt;
341 struct mctp_test_dev *dev;
342 struct socket *sock;
343 int rc;
344
345 params = test->param_value;
346
347 __mctp_route_test_init(test, &dev, &rt, &sock);
348
349 skb = mctp_test_create_skb_data(¶ms->hdr, ¶ms->type);
350 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb);
351
352 skb->dev = dev->ndev;
353 __mctp_cb(skb);
354
355 rc = mctp_route_input(&rt->rt, skb);
356
357 if (params->deliver) {
358 KUNIT_EXPECT_EQ(test, rc, 0);
359
360 skb2 = skb_recv_datagram(sock->sk, 0, 1, &rc);
361 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, skb2);
362 KUNIT_EXPECT_EQ(test, skb->len, 1);
363
364 skb_free_datagram(sock->sk, skb2);
365
366 } else {
367 KUNIT_EXPECT_NE(test, rc, 0);
368 skb2 = skb_recv_datagram(sock->sk, 0, 1, &rc);
369 KUNIT_EXPECT_PTR_EQ(test, skb2, NULL);
370 }
371
372 __mctp_route_test_fini(test, dev, rt, sock);
373 }
374
375 #define FL_S (MCTP_HDR_FLAG_SOM)
376 #define FL_E (MCTP_HDR_FLAG_EOM)
377 #define FL_T (MCTP_HDR_FLAG_TO)
378
379 static const struct mctp_route_input_sk_test mctp_route_input_sk_tests[] = {
380 { .hdr = RX_HDR(1, 10, 8, FL_S | FL_E | FL_T), .type = 0, .deliver = true },
381 { .hdr = RX_HDR(1, 10, 8, FL_S | FL_E | FL_T), .type = 1, .deliver = false },
382 { .hdr = RX_HDR(1, 10, 8, FL_S | FL_E), .type = 0, .deliver = false },
383 { .hdr = RX_HDR(1, 10, 8, FL_E | FL_T), .type = 0, .deliver = false },
384 { .hdr = RX_HDR(1, 10, 8, FL_T), .type = 0, .deliver = false },
385 { .hdr = RX_HDR(1, 10, 8, 0), .type = 0, .deliver = false },
386 };
387
mctp_route_input_sk_to_desc(const struct mctp_route_input_sk_test * t,char * desc)388 static void mctp_route_input_sk_to_desc(const struct mctp_route_input_sk_test *t,
389 char *desc)
390 {
391 sprintf(desc, "{%x,%x,%x,%x} type %d", t->hdr.ver, t->hdr.src,
392 t->hdr.dest, t->hdr.flags_seq_tag, t->type);
393 }
394
395 KUNIT_ARRAY_PARAM(mctp_route_input_sk, mctp_route_input_sk_tests,
396 mctp_route_input_sk_to_desc);
397
398 struct mctp_route_input_sk_reasm_test {
399 const char *name;
400 struct mctp_hdr hdrs[4];
401 int n_hdrs;
402 int rx_len;
403 };
404
mctp_test_route_input_sk_reasm(struct kunit * test)405 static void mctp_test_route_input_sk_reasm(struct kunit *test)
406 {
407 const struct mctp_route_input_sk_reasm_test *params;
408 struct sk_buff *skb, *skb2;
409 struct mctp_test_route *rt;
410 struct mctp_test_dev *dev;
411 struct socket *sock;
412 int i, rc;
413 u8 c;
414
415 params = test->param_value;
416
417 __mctp_route_test_init(test, &dev, &rt, &sock);
418
419 for (i = 0; i < params->n_hdrs; i++) {
420 c = i;
421 skb = mctp_test_create_skb_data(¶ms->hdrs[i], &c);
422 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb);
423
424 skb->dev = dev->ndev;
425 __mctp_cb(skb);
426
427 rc = mctp_route_input(&rt->rt, skb);
428 }
429
430 skb2 = skb_recv_datagram(sock->sk, 0, 1, &rc);
431
432 if (params->rx_len) {
433 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, skb2);
434 KUNIT_EXPECT_EQ(test, skb2->len, params->rx_len);
435 skb_free_datagram(sock->sk, skb2);
436
437 } else {
438 KUNIT_EXPECT_PTR_EQ(test, skb2, NULL);
439 }
440
441 __mctp_route_test_fini(test, dev, rt, sock);
442 }
443
444 #define RX_FRAG(f, s) RX_HDR(1, 10, 8, FL_T | (f) | ((s) << MCTP_HDR_SEQ_SHIFT))
445
446 static const struct mctp_route_input_sk_reasm_test mctp_route_input_sk_reasm_tests[] = {
447 {
448 .name = "single packet",
449 .hdrs = {
450 RX_FRAG(FL_S | FL_E, 0),
451 },
452 .n_hdrs = 1,
453 .rx_len = 1,
454 },
455 {
456 .name = "single packet, offset seq",
457 .hdrs = {
458 RX_FRAG(FL_S | FL_E, 1),
459 },
460 .n_hdrs = 1,
461 .rx_len = 1,
462 },
463 {
464 .name = "start & end packets",
465 .hdrs = {
466 RX_FRAG(FL_S, 0),
467 RX_FRAG(FL_E, 1),
468 },
469 .n_hdrs = 2,
470 .rx_len = 2,
471 },
472 {
473 .name = "start & end packets, offset seq",
474 .hdrs = {
475 RX_FRAG(FL_S, 1),
476 RX_FRAG(FL_E, 2),
477 },
478 .n_hdrs = 2,
479 .rx_len = 2,
480 },
481 {
482 .name = "start & end packets, out of order",
483 .hdrs = {
484 RX_FRAG(FL_E, 1),
485 RX_FRAG(FL_S, 0),
486 },
487 .n_hdrs = 2,
488 .rx_len = 0,
489 },
490 {
491 .name = "start, middle & end packets",
492 .hdrs = {
493 RX_FRAG(FL_S, 0),
494 RX_FRAG(0, 1),
495 RX_FRAG(FL_E, 2),
496 },
497 .n_hdrs = 3,
498 .rx_len = 3,
499 },
500 {
501 .name = "missing seq",
502 .hdrs = {
503 RX_FRAG(FL_S, 0),
504 RX_FRAG(FL_E, 2),
505 },
506 .n_hdrs = 2,
507 .rx_len = 0,
508 },
509 {
510 .name = "seq wrap",
511 .hdrs = {
512 RX_FRAG(FL_S, 3),
513 RX_FRAG(FL_E, 0),
514 },
515 .n_hdrs = 2,
516 .rx_len = 2,
517 },
518 };
519
mctp_route_input_sk_reasm_to_desc(const struct mctp_route_input_sk_reasm_test * t,char * desc)520 static void mctp_route_input_sk_reasm_to_desc(
521 const struct mctp_route_input_sk_reasm_test *t,
522 char *desc)
523 {
524 sprintf(desc, "%s", t->name);
525 }
526
527 KUNIT_ARRAY_PARAM(mctp_route_input_sk_reasm, mctp_route_input_sk_reasm_tests,
528 mctp_route_input_sk_reasm_to_desc);
529
530 static struct kunit_case mctp_test_cases[] = {
531 KUNIT_CASE_PARAM(mctp_test_fragment, mctp_frag_gen_params),
532 KUNIT_CASE_PARAM(mctp_test_rx_input, mctp_rx_input_gen_params),
533 KUNIT_CASE_PARAM(mctp_test_route_input_sk, mctp_route_input_sk_gen_params),
534 KUNIT_CASE_PARAM(mctp_test_route_input_sk_reasm,
535 mctp_route_input_sk_reasm_gen_params),
536 {}
537 };
538
539 static struct kunit_suite mctp_test_suite = {
540 .name = "mctp",
541 .test_cases = mctp_test_cases,
542 };
543
544 kunit_test_suite(mctp_test_suite);
545