162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <kunit/test.h> 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include "utils.h" 662306a36Sopenharmony_ci 762306a36Sopenharmony_cistruct mctp_test_route { 862306a36Sopenharmony_ci struct mctp_route rt; 962306a36Sopenharmony_ci struct sk_buff_head pkts; 1062306a36Sopenharmony_ci}; 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic int mctp_test_route_output(struct mctp_route *rt, struct sk_buff *skb) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci struct mctp_test_route *test_rt = container_of(rt, struct mctp_test_route, rt); 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci skb_queue_tail(&test_rt->pkts, skb); 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci return 0; 1962306a36Sopenharmony_ci} 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* local version of mctp_route_alloc() */ 2262306a36Sopenharmony_cistatic struct mctp_test_route *mctp_route_test_alloc(void) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci struct mctp_test_route *rt; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci rt = kzalloc(sizeof(*rt), GFP_KERNEL); 2762306a36Sopenharmony_ci if (!rt) 2862306a36Sopenharmony_ci return NULL; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci INIT_LIST_HEAD(&rt->rt.list); 3162306a36Sopenharmony_ci refcount_set(&rt->rt.refs, 1); 3262306a36Sopenharmony_ci rt->rt.output = mctp_test_route_output; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci skb_queue_head_init(&rt->pkts); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci return rt; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic struct mctp_test_route *mctp_test_create_route(struct net *net, 4062306a36Sopenharmony_ci struct mctp_dev *dev, 4162306a36Sopenharmony_ci mctp_eid_t eid, 4262306a36Sopenharmony_ci unsigned int mtu) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci struct mctp_test_route *rt; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci rt = mctp_route_test_alloc(); 4762306a36Sopenharmony_ci if (!rt) 4862306a36Sopenharmony_ci return NULL; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci rt->rt.min = eid; 5162306a36Sopenharmony_ci rt->rt.max = eid; 5262306a36Sopenharmony_ci rt->rt.mtu = mtu; 5362306a36Sopenharmony_ci rt->rt.type = RTN_UNSPEC; 5462306a36Sopenharmony_ci if (dev) 5562306a36Sopenharmony_ci mctp_dev_hold(dev); 5662306a36Sopenharmony_ci rt->rt.dev = dev; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci list_add_rcu(&rt->rt.list, &net->mctp.routes); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci return rt; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void mctp_test_route_destroy(struct kunit *test, 6462306a36Sopenharmony_ci struct mctp_test_route *rt) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci unsigned int refs; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci rtnl_lock(); 6962306a36Sopenharmony_ci list_del_rcu(&rt->rt.list); 7062306a36Sopenharmony_ci rtnl_unlock(); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci skb_queue_purge(&rt->pkts); 7362306a36Sopenharmony_ci if (rt->rt.dev) 7462306a36Sopenharmony_ci mctp_dev_put(rt->rt.dev); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci refs = refcount_read(&rt->rt.refs); 7762306a36Sopenharmony_ci KUNIT_ASSERT_EQ_MSG(test, refs, 1, "route ref imbalance"); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci kfree_rcu(&rt->rt, rcu); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic struct sk_buff *mctp_test_create_skb(const struct mctp_hdr *hdr, 8362306a36Sopenharmony_ci unsigned int data_len) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci size_t hdr_len = sizeof(*hdr); 8662306a36Sopenharmony_ci struct sk_buff *skb; 8762306a36Sopenharmony_ci unsigned int i; 8862306a36Sopenharmony_ci u8 *buf; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci skb = alloc_skb(hdr_len + data_len, GFP_KERNEL); 9162306a36Sopenharmony_ci if (!skb) 9262306a36Sopenharmony_ci return NULL; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci memcpy(skb_put(skb, hdr_len), hdr, hdr_len); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci buf = skb_put(skb, data_len); 9762306a36Sopenharmony_ci for (i = 0; i < data_len; i++) 9862306a36Sopenharmony_ci buf[i] = i & 0xff; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return skb; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic struct sk_buff *__mctp_test_create_skb_data(const struct mctp_hdr *hdr, 10462306a36Sopenharmony_ci const void *data, 10562306a36Sopenharmony_ci size_t data_len) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci size_t hdr_len = sizeof(*hdr); 10862306a36Sopenharmony_ci struct sk_buff *skb; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci skb = alloc_skb(hdr_len + data_len, GFP_KERNEL); 11162306a36Sopenharmony_ci if (!skb) 11262306a36Sopenharmony_ci return NULL; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci memcpy(skb_put(skb, hdr_len), hdr, hdr_len); 11562306a36Sopenharmony_ci memcpy(skb_put(skb, data_len), data, data_len); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return skb; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#define mctp_test_create_skb_data(h, d) \ 12162306a36Sopenharmony_ci __mctp_test_create_skb_data(h, d, sizeof(*d)) 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistruct mctp_frag_test { 12462306a36Sopenharmony_ci unsigned int mtu; 12562306a36Sopenharmony_ci unsigned int msgsize; 12662306a36Sopenharmony_ci unsigned int n_frags; 12762306a36Sopenharmony_ci}; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic void mctp_test_fragment(struct kunit *test) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci const struct mctp_frag_test *params; 13262306a36Sopenharmony_ci int rc, i, n, mtu, msgsize; 13362306a36Sopenharmony_ci struct mctp_test_route *rt; 13462306a36Sopenharmony_ci struct sk_buff *skb; 13562306a36Sopenharmony_ci struct mctp_hdr hdr; 13662306a36Sopenharmony_ci u8 seq; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci params = test->param_value; 13962306a36Sopenharmony_ci mtu = params->mtu; 14062306a36Sopenharmony_ci msgsize = params->msgsize; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci hdr.ver = 1; 14362306a36Sopenharmony_ci hdr.src = 8; 14462306a36Sopenharmony_ci hdr.dest = 10; 14562306a36Sopenharmony_ci hdr.flags_seq_tag = MCTP_HDR_FLAG_TO; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci skb = mctp_test_create_skb(&hdr, msgsize); 14862306a36Sopenharmony_ci KUNIT_ASSERT_TRUE(test, skb); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci rt = mctp_test_create_route(&init_net, NULL, 10, mtu); 15162306a36Sopenharmony_ci KUNIT_ASSERT_TRUE(test, rt); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci rc = mctp_do_fragment_route(&rt->rt, skb, mtu, MCTP_TAG_OWNER); 15462306a36Sopenharmony_ci KUNIT_EXPECT_FALSE(test, rc); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci n = rt->pkts.qlen; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, n, params->n_frags); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci for (i = 0;; i++) { 16162306a36Sopenharmony_ci struct mctp_hdr *hdr2; 16262306a36Sopenharmony_ci struct sk_buff *skb2; 16362306a36Sopenharmony_ci u8 tag_mask, seq2; 16462306a36Sopenharmony_ci bool first, last; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci first = i == 0; 16762306a36Sopenharmony_ci last = i == (n - 1); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci skb2 = skb_dequeue(&rt->pkts); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (!skb2) 17262306a36Sopenharmony_ci break; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci hdr2 = mctp_hdr(skb2); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci tag_mask = MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, hdr2->ver, hdr.ver); 17962306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, hdr2->src, hdr.src); 18062306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, hdr2->dest, hdr.dest); 18162306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, hdr2->flags_seq_tag & tag_mask, 18262306a36Sopenharmony_ci hdr.flags_seq_tag & tag_mask); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, 18562306a36Sopenharmony_ci !!(hdr2->flags_seq_tag & MCTP_HDR_FLAG_SOM), first); 18662306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, 18762306a36Sopenharmony_ci !!(hdr2->flags_seq_tag & MCTP_HDR_FLAG_EOM), last); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci seq2 = (hdr2->flags_seq_tag >> MCTP_HDR_SEQ_SHIFT) & 19062306a36Sopenharmony_ci MCTP_HDR_SEQ_MASK; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (first) { 19362306a36Sopenharmony_ci seq = seq2; 19462306a36Sopenharmony_ci } else { 19562306a36Sopenharmony_ci seq++; 19662306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, seq2, seq & MCTP_HDR_SEQ_MASK); 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (!last) 20062306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, skb2->len, mtu); 20162306a36Sopenharmony_ci else 20262306a36Sopenharmony_ci KUNIT_EXPECT_LE(test, skb2->len, mtu); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci kfree_skb(skb2); 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci mctp_test_route_destroy(test, rt); 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic const struct mctp_frag_test mctp_frag_tests[] = { 21162306a36Sopenharmony_ci {.mtu = 68, .msgsize = 63, .n_frags = 1}, 21262306a36Sopenharmony_ci {.mtu = 68, .msgsize = 64, .n_frags = 1}, 21362306a36Sopenharmony_ci {.mtu = 68, .msgsize = 65, .n_frags = 2}, 21462306a36Sopenharmony_ci {.mtu = 68, .msgsize = 66, .n_frags = 2}, 21562306a36Sopenharmony_ci {.mtu = 68, .msgsize = 127, .n_frags = 2}, 21662306a36Sopenharmony_ci {.mtu = 68, .msgsize = 128, .n_frags = 2}, 21762306a36Sopenharmony_ci {.mtu = 68, .msgsize = 129, .n_frags = 3}, 21862306a36Sopenharmony_ci {.mtu = 68, .msgsize = 130, .n_frags = 3}, 21962306a36Sopenharmony_ci}; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic void mctp_frag_test_to_desc(const struct mctp_frag_test *t, char *desc) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci sprintf(desc, "mtu %d len %d -> %d frags", 22462306a36Sopenharmony_ci t->msgsize, t->mtu, t->n_frags); 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ciKUNIT_ARRAY_PARAM(mctp_frag, mctp_frag_tests, mctp_frag_test_to_desc); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistruct mctp_rx_input_test { 23062306a36Sopenharmony_ci struct mctp_hdr hdr; 23162306a36Sopenharmony_ci bool input; 23262306a36Sopenharmony_ci}; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic void mctp_test_rx_input(struct kunit *test) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci const struct mctp_rx_input_test *params; 23762306a36Sopenharmony_ci struct mctp_test_route *rt; 23862306a36Sopenharmony_ci struct mctp_test_dev *dev; 23962306a36Sopenharmony_ci struct sk_buff *skb; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci params = test->param_value; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci dev = mctp_test_create_dev(); 24462306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci rt = mctp_test_create_route(&init_net, dev->mdev, 8, 68); 24762306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci skb = mctp_test_create_skb(¶ms->hdr, 1); 25062306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci __mctp_cb(skb); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci mctp_pkttype_receive(skb, dev->ndev, &mctp_packet_type, NULL); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, !!rt->pkts.qlen, params->input); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci mctp_test_route_destroy(test, rt); 25962306a36Sopenharmony_ci mctp_test_destroy_dev(dev); 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci#define RX_HDR(_ver, _src, _dest, _fst) \ 26362306a36Sopenharmony_ci { .ver = _ver, .src = _src, .dest = _dest, .flags_seq_tag = _fst } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci/* we have a route for EID 8 only */ 26662306a36Sopenharmony_cistatic const struct mctp_rx_input_test mctp_rx_input_tests[] = { 26762306a36Sopenharmony_ci { .hdr = RX_HDR(1, 10, 8, 0), .input = true }, 26862306a36Sopenharmony_ci { .hdr = RX_HDR(1, 10, 9, 0), .input = false }, /* no input route */ 26962306a36Sopenharmony_ci { .hdr = RX_HDR(2, 10, 8, 0), .input = false }, /* invalid version */ 27062306a36Sopenharmony_ci}; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic void mctp_rx_input_test_to_desc(const struct mctp_rx_input_test *t, 27362306a36Sopenharmony_ci char *desc) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci sprintf(desc, "{%x,%x,%x,%x}", t->hdr.ver, t->hdr.src, t->hdr.dest, 27662306a36Sopenharmony_ci t->hdr.flags_seq_tag); 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ciKUNIT_ARRAY_PARAM(mctp_rx_input, mctp_rx_input_tests, 28062306a36Sopenharmony_ci mctp_rx_input_test_to_desc); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/* set up a local dev, route on EID 8, and a socket listening on type 0 */ 28362306a36Sopenharmony_cistatic void __mctp_route_test_init(struct kunit *test, 28462306a36Sopenharmony_ci struct mctp_test_dev **devp, 28562306a36Sopenharmony_ci struct mctp_test_route **rtp, 28662306a36Sopenharmony_ci struct socket **sockp) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct sockaddr_mctp addr = {0}; 28962306a36Sopenharmony_ci struct mctp_test_route *rt; 29062306a36Sopenharmony_ci struct mctp_test_dev *dev; 29162306a36Sopenharmony_ci struct socket *sock; 29262306a36Sopenharmony_ci int rc; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci dev = mctp_test_create_dev(); 29562306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci rt = mctp_test_create_route(&init_net, dev->mdev, 8, 68); 29862306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci rc = sock_create_kern(&init_net, AF_MCTP, SOCK_DGRAM, 0, &sock); 30162306a36Sopenharmony_ci KUNIT_ASSERT_EQ(test, rc, 0); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci addr.smctp_family = AF_MCTP; 30462306a36Sopenharmony_ci addr.smctp_network = MCTP_NET_ANY; 30562306a36Sopenharmony_ci addr.smctp_addr.s_addr = 8; 30662306a36Sopenharmony_ci addr.smctp_type = 0; 30762306a36Sopenharmony_ci rc = kernel_bind(sock, (struct sockaddr *)&addr, sizeof(addr)); 30862306a36Sopenharmony_ci KUNIT_ASSERT_EQ(test, rc, 0); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci *rtp = rt; 31162306a36Sopenharmony_ci *devp = dev; 31262306a36Sopenharmony_ci *sockp = sock; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic void __mctp_route_test_fini(struct kunit *test, 31662306a36Sopenharmony_ci struct mctp_test_dev *dev, 31762306a36Sopenharmony_ci struct mctp_test_route *rt, 31862306a36Sopenharmony_ci struct socket *sock) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci sock_release(sock); 32162306a36Sopenharmony_ci mctp_test_route_destroy(test, rt); 32262306a36Sopenharmony_ci mctp_test_destroy_dev(dev); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistruct mctp_route_input_sk_test { 32662306a36Sopenharmony_ci struct mctp_hdr hdr; 32762306a36Sopenharmony_ci u8 type; 32862306a36Sopenharmony_ci bool deliver; 32962306a36Sopenharmony_ci}; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic void mctp_test_route_input_sk(struct kunit *test) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci const struct mctp_route_input_sk_test *params; 33462306a36Sopenharmony_ci struct sk_buff *skb, *skb2; 33562306a36Sopenharmony_ci struct mctp_test_route *rt; 33662306a36Sopenharmony_ci struct mctp_test_dev *dev; 33762306a36Sopenharmony_ci struct socket *sock; 33862306a36Sopenharmony_ci int rc; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci params = test->param_value; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci __mctp_route_test_init(test, &dev, &rt, &sock); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci skb = mctp_test_create_skb_data(¶ms->hdr, ¶ms->type); 34562306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci skb->dev = dev->ndev; 34862306a36Sopenharmony_ci __mctp_cb(skb); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci rc = mctp_route_input(&rt->rt, skb); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (params->deliver) { 35362306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, rc, 0); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci skb2 = skb_recv_datagram(sock->sk, MSG_DONTWAIT, &rc); 35662306a36Sopenharmony_ci KUNIT_EXPECT_NOT_ERR_OR_NULL(test, skb2); 35762306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, skb->len, 1); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci skb_free_datagram(sock->sk, skb2); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci } else { 36262306a36Sopenharmony_ci KUNIT_EXPECT_NE(test, rc, 0); 36362306a36Sopenharmony_ci skb2 = skb_recv_datagram(sock->sk, MSG_DONTWAIT, &rc); 36462306a36Sopenharmony_ci KUNIT_EXPECT_NULL(test, skb2); 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci __mctp_route_test_fini(test, dev, rt, sock); 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci#define FL_S (MCTP_HDR_FLAG_SOM) 37162306a36Sopenharmony_ci#define FL_E (MCTP_HDR_FLAG_EOM) 37262306a36Sopenharmony_ci#define FL_TO (MCTP_HDR_FLAG_TO) 37362306a36Sopenharmony_ci#define FL_T(t) ((t) & MCTP_HDR_TAG_MASK) 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic const struct mctp_route_input_sk_test mctp_route_input_sk_tests[] = { 37662306a36Sopenharmony_ci { .hdr = RX_HDR(1, 10, 8, FL_S | FL_E | FL_TO), .type = 0, .deliver = true }, 37762306a36Sopenharmony_ci { .hdr = RX_HDR(1, 10, 8, FL_S | FL_E | FL_TO), .type = 1, .deliver = false }, 37862306a36Sopenharmony_ci { .hdr = RX_HDR(1, 10, 8, FL_S | FL_E), .type = 0, .deliver = false }, 37962306a36Sopenharmony_ci { .hdr = RX_HDR(1, 10, 8, FL_E | FL_TO), .type = 0, .deliver = false }, 38062306a36Sopenharmony_ci { .hdr = RX_HDR(1, 10, 8, FL_TO), .type = 0, .deliver = false }, 38162306a36Sopenharmony_ci { .hdr = RX_HDR(1, 10, 8, 0), .type = 0, .deliver = false }, 38262306a36Sopenharmony_ci}; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic void mctp_route_input_sk_to_desc(const struct mctp_route_input_sk_test *t, 38562306a36Sopenharmony_ci char *desc) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci sprintf(desc, "{%x,%x,%x,%x} type %d", t->hdr.ver, t->hdr.src, 38862306a36Sopenharmony_ci t->hdr.dest, t->hdr.flags_seq_tag, t->type); 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ciKUNIT_ARRAY_PARAM(mctp_route_input_sk, mctp_route_input_sk_tests, 39262306a36Sopenharmony_ci mctp_route_input_sk_to_desc); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistruct mctp_route_input_sk_reasm_test { 39562306a36Sopenharmony_ci const char *name; 39662306a36Sopenharmony_ci struct mctp_hdr hdrs[4]; 39762306a36Sopenharmony_ci int n_hdrs; 39862306a36Sopenharmony_ci int rx_len; 39962306a36Sopenharmony_ci}; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic void mctp_test_route_input_sk_reasm(struct kunit *test) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci const struct mctp_route_input_sk_reasm_test *params; 40462306a36Sopenharmony_ci struct sk_buff *skb, *skb2; 40562306a36Sopenharmony_ci struct mctp_test_route *rt; 40662306a36Sopenharmony_ci struct mctp_test_dev *dev; 40762306a36Sopenharmony_ci struct socket *sock; 40862306a36Sopenharmony_ci int i, rc; 40962306a36Sopenharmony_ci u8 c; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci params = test->param_value; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci __mctp_route_test_init(test, &dev, &rt, &sock); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci for (i = 0; i < params->n_hdrs; i++) { 41662306a36Sopenharmony_ci c = i; 41762306a36Sopenharmony_ci skb = mctp_test_create_skb_data(¶ms->hdrs[i], &c); 41862306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci skb->dev = dev->ndev; 42162306a36Sopenharmony_ci __mctp_cb(skb); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci rc = mctp_route_input(&rt->rt, skb); 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci skb2 = skb_recv_datagram(sock->sk, MSG_DONTWAIT, &rc); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (params->rx_len) { 42962306a36Sopenharmony_ci KUNIT_EXPECT_NOT_ERR_OR_NULL(test, skb2); 43062306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, skb2->len, params->rx_len); 43162306a36Sopenharmony_ci skb_free_datagram(sock->sk, skb2); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci } else { 43462306a36Sopenharmony_ci KUNIT_EXPECT_NULL(test, skb2); 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci __mctp_route_test_fini(test, dev, rt, sock); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci#define RX_FRAG(f, s) RX_HDR(1, 10, 8, FL_TO | (f) | ((s) << MCTP_HDR_SEQ_SHIFT)) 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic const struct mctp_route_input_sk_reasm_test mctp_route_input_sk_reasm_tests[] = { 44362306a36Sopenharmony_ci { 44462306a36Sopenharmony_ci .name = "single packet", 44562306a36Sopenharmony_ci .hdrs = { 44662306a36Sopenharmony_ci RX_FRAG(FL_S | FL_E, 0), 44762306a36Sopenharmony_ci }, 44862306a36Sopenharmony_ci .n_hdrs = 1, 44962306a36Sopenharmony_ci .rx_len = 1, 45062306a36Sopenharmony_ci }, 45162306a36Sopenharmony_ci { 45262306a36Sopenharmony_ci .name = "single packet, offset seq", 45362306a36Sopenharmony_ci .hdrs = { 45462306a36Sopenharmony_ci RX_FRAG(FL_S | FL_E, 1), 45562306a36Sopenharmony_ci }, 45662306a36Sopenharmony_ci .n_hdrs = 1, 45762306a36Sopenharmony_ci .rx_len = 1, 45862306a36Sopenharmony_ci }, 45962306a36Sopenharmony_ci { 46062306a36Sopenharmony_ci .name = "start & end packets", 46162306a36Sopenharmony_ci .hdrs = { 46262306a36Sopenharmony_ci RX_FRAG(FL_S, 0), 46362306a36Sopenharmony_ci RX_FRAG(FL_E, 1), 46462306a36Sopenharmony_ci }, 46562306a36Sopenharmony_ci .n_hdrs = 2, 46662306a36Sopenharmony_ci .rx_len = 2, 46762306a36Sopenharmony_ci }, 46862306a36Sopenharmony_ci { 46962306a36Sopenharmony_ci .name = "start & end packets, offset seq", 47062306a36Sopenharmony_ci .hdrs = { 47162306a36Sopenharmony_ci RX_FRAG(FL_S, 1), 47262306a36Sopenharmony_ci RX_FRAG(FL_E, 2), 47362306a36Sopenharmony_ci }, 47462306a36Sopenharmony_ci .n_hdrs = 2, 47562306a36Sopenharmony_ci .rx_len = 2, 47662306a36Sopenharmony_ci }, 47762306a36Sopenharmony_ci { 47862306a36Sopenharmony_ci .name = "start & end packets, out of order", 47962306a36Sopenharmony_ci .hdrs = { 48062306a36Sopenharmony_ci RX_FRAG(FL_E, 1), 48162306a36Sopenharmony_ci RX_FRAG(FL_S, 0), 48262306a36Sopenharmony_ci }, 48362306a36Sopenharmony_ci .n_hdrs = 2, 48462306a36Sopenharmony_ci .rx_len = 0, 48562306a36Sopenharmony_ci }, 48662306a36Sopenharmony_ci { 48762306a36Sopenharmony_ci .name = "start, middle & end packets", 48862306a36Sopenharmony_ci .hdrs = { 48962306a36Sopenharmony_ci RX_FRAG(FL_S, 0), 49062306a36Sopenharmony_ci RX_FRAG(0, 1), 49162306a36Sopenharmony_ci RX_FRAG(FL_E, 2), 49262306a36Sopenharmony_ci }, 49362306a36Sopenharmony_ci .n_hdrs = 3, 49462306a36Sopenharmony_ci .rx_len = 3, 49562306a36Sopenharmony_ci }, 49662306a36Sopenharmony_ci { 49762306a36Sopenharmony_ci .name = "missing seq", 49862306a36Sopenharmony_ci .hdrs = { 49962306a36Sopenharmony_ci RX_FRAG(FL_S, 0), 50062306a36Sopenharmony_ci RX_FRAG(FL_E, 2), 50162306a36Sopenharmony_ci }, 50262306a36Sopenharmony_ci .n_hdrs = 2, 50362306a36Sopenharmony_ci .rx_len = 0, 50462306a36Sopenharmony_ci }, 50562306a36Sopenharmony_ci { 50662306a36Sopenharmony_ci .name = "seq wrap", 50762306a36Sopenharmony_ci .hdrs = { 50862306a36Sopenharmony_ci RX_FRAG(FL_S, 3), 50962306a36Sopenharmony_ci RX_FRAG(FL_E, 0), 51062306a36Sopenharmony_ci }, 51162306a36Sopenharmony_ci .n_hdrs = 2, 51262306a36Sopenharmony_ci .rx_len = 2, 51362306a36Sopenharmony_ci }, 51462306a36Sopenharmony_ci}; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic void mctp_route_input_sk_reasm_to_desc( 51762306a36Sopenharmony_ci const struct mctp_route_input_sk_reasm_test *t, 51862306a36Sopenharmony_ci char *desc) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci sprintf(desc, "%s", t->name); 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ciKUNIT_ARRAY_PARAM(mctp_route_input_sk_reasm, mctp_route_input_sk_reasm_tests, 52462306a36Sopenharmony_ci mctp_route_input_sk_reasm_to_desc); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistruct mctp_route_input_sk_keys_test { 52762306a36Sopenharmony_ci const char *name; 52862306a36Sopenharmony_ci mctp_eid_t key_peer_addr; 52962306a36Sopenharmony_ci mctp_eid_t key_local_addr; 53062306a36Sopenharmony_ci u8 key_tag; 53162306a36Sopenharmony_ci struct mctp_hdr hdr; 53262306a36Sopenharmony_ci bool deliver; 53362306a36Sopenharmony_ci}; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci/* test packet rx in the presence of various key configurations */ 53662306a36Sopenharmony_cistatic void mctp_test_route_input_sk_keys(struct kunit *test) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci const struct mctp_route_input_sk_keys_test *params; 53962306a36Sopenharmony_ci struct mctp_test_route *rt; 54062306a36Sopenharmony_ci struct sk_buff *skb, *skb2; 54162306a36Sopenharmony_ci struct mctp_test_dev *dev; 54262306a36Sopenharmony_ci struct mctp_sk_key *key; 54362306a36Sopenharmony_ci struct netns_mctp *mns; 54462306a36Sopenharmony_ci struct mctp_sock *msk; 54562306a36Sopenharmony_ci struct socket *sock; 54662306a36Sopenharmony_ci unsigned long flags; 54762306a36Sopenharmony_ci int rc; 54862306a36Sopenharmony_ci u8 c; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci params = test->param_value; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci dev = mctp_test_create_dev(); 55362306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci rt = mctp_test_create_route(&init_net, dev->mdev, 8, 68); 55662306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci rc = sock_create_kern(&init_net, AF_MCTP, SOCK_DGRAM, 0, &sock); 55962306a36Sopenharmony_ci KUNIT_ASSERT_EQ(test, rc, 0); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci msk = container_of(sock->sk, struct mctp_sock, sk); 56262306a36Sopenharmony_ci mns = &sock_net(sock->sk)->mctp; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci /* set the incoming tag according to test params */ 56562306a36Sopenharmony_ci key = mctp_key_alloc(msk, params->key_local_addr, params->key_peer_addr, 56662306a36Sopenharmony_ci params->key_tag, GFP_KERNEL); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, key); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci spin_lock_irqsave(&mns->keys_lock, flags); 57162306a36Sopenharmony_ci mctp_reserve_tag(&init_net, key, msk); 57262306a36Sopenharmony_ci spin_unlock_irqrestore(&mns->keys_lock, flags); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* create packet and route */ 57562306a36Sopenharmony_ci c = 0; 57662306a36Sopenharmony_ci skb = mctp_test_create_skb_data(¶ms->hdr, &c); 57762306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci skb->dev = dev->ndev; 58062306a36Sopenharmony_ci __mctp_cb(skb); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci rc = mctp_route_input(&rt->rt, skb); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* (potentially) receive message */ 58562306a36Sopenharmony_ci skb2 = skb_recv_datagram(sock->sk, MSG_DONTWAIT, &rc); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (params->deliver) 58862306a36Sopenharmony_ci KUNIT_EXPECT_NOT_ERR_OR_NULL(test, skb2); 58962306a36Sopenharmony_ci else 59062306a36Sopenharmony_ci KUNIT_EXPECT_PTR_EQ(test, skb2, NULL); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (skb2) 59362306a36Sopenharmony_ci skb_free_datagram(sock->sk, skb2); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci mctp_key_unref(key); 59662306a36Sopenharmony_ci __mctp_route_test_fini(test, dev, rt, sock); 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic const struct mctp_route_input_sk_keys_test mctp_route_input_sk_keys_tests[] = { 60062306a36Sopenharmony_ci { 60162306a36Sopenharmony_ci .name = "direct match", 60262306a36Sopenharmony_ci .key_peer_addr = 9, 60362306a36Sopenharmony_ci .key_local_addr = 8, 60462306a36Sopenharmony_ci .key_tag = 1, 60562306a36Sopenharmony_ci .hdr = RX_HDR(1, 9, 8, FL_S | FL_E | FL_T(1)), 60662306a36Sopenharmony_ci .deliver = true, 60762306a36Sopenharmony_ci }, 60862306a36Sopenharmony_ci { 60962306a36Sopenharmony_ci .name = "flipped src/dest", 61062306a36Sopenharmony_ci .key_peer_addr = 8, 61162306a36Sopenharmony_ci .key_local_addr = 9, 61262306a36Sopenharmony_ci .key_tag = 1, 61362306a36Sopenharmony_ci .hdr = RX_HDR(1, 9, 8, FL_S | FL_E | FL_T(1)), 61462306a36Sopenharmony_ci .deliver = false, 61562306a36Sopenharmony_ci }, 61662306a36Sopenharmony_ci { 61762306a36Sopenharmony_ci .name = "peer addr mismatch", 61862306a36Sopenharmony_ci .key_peer_addr = 9, 61962306a36Sopenharmony_ci .key_local_addr = 8, 62062306a36Sopenharmony_ci .key_tag = 1, 62162306a36Sopenharmony_ci .hdr = RX_HDR(1, 10, 8, FL_S | FL_E | FL_T(1)), 62262306a36Sopenharmony_ci .deliver = false, 62362306a36Sopenharmony_ci }, 62462306a36Sopenharmony_ci { 62562306a36Sopenharmony_ci .name = "tag value mismatch", 62662306a36Sopenharmony_ci .key_peer_addr = 9, 62762306a36Sopenharmony_ci .key_local_addr = 8, 62862306a36Sopenharmony_ci .key_tag = 1, 62962306a36Sopenharmony_ci .hdr = RX_HDR(1, 9, 8, FL_S | FL_E | FL_T(2)), 63062306a36Sopenharmony_ci .deliver = false, 63162306a36Sopenharmony_ci }, 63262306a36Sopenharmony_ci { 63362306a36Sopenharmony_ci .name = "TO mismatch", 63462306a36Sopenharmony_ci .key_peer_addr = 9, 63562306a36Sopenharmony_ci .key_local_addr = 8, 63662306a36Sopenharmony_ci .key_tag = 1, 63762306a36Sopenharmony_ci .hdr = RX_HDR(1, 9, 8, FL_S | FL_E | FL_T(1) | FL_TO), 63862306a36Sopenharmony_ci .deliver = false, 63962306a36Sopenharmony_ci }, 64062306a36Sopenharmony_ci { 64162306a36Sopenharmony_ci .name = "broadcast response", 64262306a36Sopenharmony_ci .key_peer_addr = MCTP_ADDR_ANY, 64362306a36Sopenharmony_ci .key_local_addr = 8, 64462306a36Sopenharmony_ci .key_tag = 1, 64562306a36Sopenharmony_ci .hdr = RX_HDR(1, 11, 8, FL_S | FL_E | FL_T(1)), 64662306a36Sopenharmony_ci .deliver = true, 64762306a36Sopenharmony_ci }, 64862306a36Sopenharmony_ci { 64962306a36Sopenharmony_ci .name = "any local match", 65062306a36Sopenharmony_ci .key_peer_addr = 12, 65162306a36Sopenharmony_ci .key_local_addr = MCTP_ADDR_ANY, 65262306a36Sopenharmony_ci .key_tag = 1, 65362306a36Sopenharmony_ci .hdr = RX_HDR(1, 12, 8, FL_S | FL_E | FL_T(1)), 65462306a36Sopenharmony_ci .deliver = true, 65562306a36Sopenharmony_ci }, 65662306a36Sopenharmony_ci}; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic void mctp_route_input_sk_keys_to_desc( 65962306a36Sopenharmony_ci const struct mctp_route_input_sk_keys_test *t, 66062306a36Sopenharmony_ci char *desc) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci sprintf(desc, "%s", t->name); 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ciKUNIT_ARRAY_PARAM(mctp_route_input_sk_keys, mctp_route_input_sk_keys_tests, 66662306a36Sopenharmony_ci mctp_route_input_sk_keys_to_desc); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic struct kunit_case mctp_test_cases[] = { 66962306a36Sopenharmony_ci KUNIT_CASE_PARAM(mctp_test_fragment, mctp_frag_gen_params), 67062306a36Sopenharmony_ci KUNIT_CASE_PARAM(mctp_test_rx_input, mctp_rx_input_gen_params), 67162306a36Sopenharmony_ci KUNIT_CASE_PARAM(mctp_test_route_input_sk, mctp_route_input_sk_gen_params), 67262306a36Sopenharmony_ci KUNIT_CASE_PARAM(mctp_test_route_input_sk_reasm, 67362306a36Sopenharmony_ci mctp_route_input_sk_reasm_gen_params), 67462306a36Sopenharmony_ci KUNIT_CASE_PARAM(mctp_test_route_input_sk_keys, 67562306a36Sopenharmony_ci mctp_route_input_sk_keys_gen_params), 67662306a36Sopenharmony_ci {} 67762306a36Sopenharmony_ci}; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic struct kunit_suite mctp_test_suite = { 68062306a36Sopenharmony_ci .name = "mctp", 68162306a36Sopenharmony_ci .test_cases = mctp_test_cases, 68262306a36Sopenharmony_ci}; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_cikunit_test_suite(mctp_test_suite); 685