diff options
Diffstat (limited to 'net/mctp/test/utils.c')
-rw-r--r-- | net/mctp/test/utils.c | 232 |
1 files changed, 230 insertions, 2 deletions
diff --git a/net/mctp/test/utils.c b/net/mctp/test/utils.c index 565763eb0211..953d41902771 100644 --- a/net/mctp/test/utils.c +++ b/net/mctp/test/utils.c @@ -26,19 +26,22 @@ static void mctp_test_dev_setup(struct net_device *ndev) ndev->type = ARPHRD_MCTP; ndev->mtu = MCTP_DEV_TEST_MTU; ndev->hard_header_len = 0; - ndev->addr_len = 0; ndev->tx_queue_len = DEFAULT_TX_QUEUE_LEN; ndev->flags = IFF_NOARP; ndev->netdev_ops = &mctp_test_netdev_ops; ndev->needs_free_netdev = true; } -struct mctp_test_dev *mctp_test_create_dev(void) +static struct mctp_test_dev *__mctp_test_create_dev(unsigned short lladdr_len, + const unsigned char *lladdr) { struct mctp_test_dev *dev; struct net_device *ndev; int rc; + if (WARN_ON(lladdr_len > MAX_ADDR_LEN)) + return NULL; + ndev = alloc_netdev(sizeof(*dev), "mctptest%d", NET_NAME_ENUM, mctp_test_dev_setup); if (!ndev) @@ -46,6 +49,8 @@ struct mctp_test_dev *mctp_test_create_dev(void) dev = netdev_priv(ndev); dev->ndev = ndev; + ndev->addr_len = lladdr_len; + dev_addr_set(ndev, lladdr); rc = register_netdev(ndev); if (rc) { @@ -61,8 +66,231 @@ struct mctp_test_dev *mctp_test_create_dev(void) return dev; } +struct mctp_test_dev *mctp_test_create_dev(void) +{ + return __mctp_test_create_dev(0, NULL); +} + +struct mctp_test_dev *mctp_test_create_dev_lladdr(unsigned short lladdr_len, + const unsigned char *lladdr) +{ + return __mctp_test_create_dev(lladdr_len, lladdr); +} + void mctp_test_destroy_dev(struct mctp_test_dev *dev) { mctp_dev_put(dev->mdev); unregister_netdev(dev->ndev); } + +static const unsigned int test_pktqueue_magic = 0x5f713aef; + +void mctp_test_pktqueue_init(struct mctp_test_pktqueue *tpq) +{ + tpq->magic = test_pktqueue_magic; + skb_queue_head_init(&tpq->pkts); +} + +static int mctp_test_dst_output(struct mctp_dst *dst, struct sk_buff *skb) +{ + struct kunit *test = current->kunit_test; + struct mctp_test_pktqueue *tpq = test->priv; + + KUNIT_ASSERT_EQ(test, tpq->magic, test_pktqueue_magic); + + skb_queue_tail(&tpq->pkts, skb); + + return 0; +} + +/* local version of mctp_route_alloc() */ +static struct mctp_test_route *mctp_route_test_alloc(void) +{ + struct mctp_test_route *rt; + + rt = kzalloc(sizeof(*rt), GFP_KERNEL); + if (!rt) + return NULL; + + INIT_LIST_HEAD(&rt->rt.list); + refcount_set(&rt->rt.refs, 1); + rt->rt.output = mctp_test_dst_output; + + return rt; +} + +struct mctp_test_route *mctp_test_create_route_direct(struct net *net, + struct mctp_dev *dev, + mctp_eid_t eid, + unsigned int mtu) +{ + struct mctp_test_route *rt; + + rt = mctp_route_test_alloc(); + if (!rt) + return NULL; + + rt->rt.min = eid; + rt->rt.max = eid; + rt->rt.mtu = mtu; + rt->rt.type = RTN_UNSPEC; + rt->rt.dst_type = MCTP_ROUTE_DIRECT; + if (dev) + mctp_dev_hold(dev); + rt->rt.dev = dev; + + list_add_rcu(&rt->rt.list, &net->mctp.routes); + + return rt; +} + +struct mctp_test_route *mctp_test_create_route_gw(struct net *net, + unsigned int netid, + mctp_eid_t eid, + mctp_eid_t gw, + unsigned int mtu) +{ + struct mctp_test_route *rt; + + rt = mctp_route_test_alloc(); + if (!rt) + return NULL; + + rt->rt.min = eid; + rt->rt.max = eid; + rt->rt.mtu = mtu; + rt->rt.type = RTN_UNSPEC; + rt->rt.dst_type = MCTP_ROUTE_GATEWAY; + rt->rt.gateway.eid = gw; + rt->rt.gateway.net = netid; + + list_add_rcu(&rt->rt.list, &net->mctp.routes); + + return rt; +} + +/* Convenience function for our test dst; release with mctp_test_dst_release() + */ +void mctp_test_dst_setup(struct kunit *test, struct mctp_dst *dst, + struct mctp_test_dev *dev, + struct mctp_test_pktqueue *tpq, unsigned int mtu) +{ + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, dev); + + memset(dst, 0, sizeof(*dst)); + + dst->dev = dev->mdev; + __mctp_dev_get(dst->dev->dev); + dst->mtu = mtu; + dst->output = mctp_test_dst_output; + mctp_test_pktqueue_init(tpq); + test->priv = tpq; +} + +void mctp_test_dst_release(struct mctp_dst *dst, + struct mctp_test_pktqueue *tpq) +{ + mctp_dst_release(dst); + skb_queue_purge(&tpq->pkts); +} + +void mctp_test_route_destroy(struct kunit *test, struct mctp_test_route *rt) +{ + unsigned int refs; + + rtnl_lock(); + list_del_rcu(&rt->rt.list); + rtnl_unlock(); + + if (rt->rt.dst_type == MCTP_ROUTE_DIRECT && rt->rt.dev) + mctp_dev_put(rt->rt.dev); + + refs = refcount_read(&rt->rt.refs); + KUNIT_ASSERT_EQ_MSG(test, refs, 1, "route ref imbalance"); + + kfree_rcu(&rt->rt, rcu); +} + +void mctp_test_skb_set_dev(struct sk_buff *skb, struct mctp_test_dev *dev) +{ + struct mctp_skb_cb *cb; + + cb = mctp_cb(skb); + cb->net = READ_ONCE(dev->mdev->net); + skb->dev = dev->ndev; +} + +struct sk_buff *mctp_test_create_skb(const struct mctp_hdr *hdr, + unsigned int data_len) +{ + size_t hdr_len = sizeof(*hdr); + struct sk_buff *skb; + unsigned int i; + u8 *buf; + + skb = alloc_skb(hdr_len + data_len, GFP_KERNEL); + if (!skb) + return NULL; + + __mctp_cb(skb); + memcpy(skb_put(skb, hdr_len), hdr, hdr_len); + + buf = skb_put(skb, data_len); + for (i = 0; i < data_len; i++) + buf[i] = i & 0xff; + + return skb; +} + +struct sk_buff *__mctp_test_create_skb_data(const struct mctp_hdr *hdr, + const void *data, size_t data_len) +{ + size_t hdr_len = sizeof(*hdr); + struct sk_buff *skb; + + skb = alloc_skb(hdr_len + data_len, GFP_KERNEL); + if (!skb) + return NULL; + + __mctp_cb(skb); + memcpy(skb_put(skb, hdr_len), hdr, hdr_len); + memcpy(skb_put(skb, data_len), data, data_len); + + return skb; +} + +void mctp_test_bind_run(struct kunit *test, + const struct mctp_test_bind_setup *setup, + int *ret_bind_errno, struct socket **sock) +{ + struct sockaddr_mctp addr; + int rc; + + *ret_bind_errno = -EIO; + + rc = sock_create_kern(&init_net, AF_MCTP, SOCK_DGRAM, 0, sock); + KUNIT_ASSERT_EQ(test, rc, 0); + + /* connect() if requested */ + if (setup->have_peer) { + memset(&addr, 0x0, sizeof(addr)); + addr.smctp_family = AF_MCTP; + addr.smctp_network = setup->peer_net; + addr.smctp_addr.s_addr = setup->peer_addr; + /* connect() type must match bind() type */ + addr.smctp_type = setup->bind_type; + rc = kernel_connect(*sock, (struct sockaddr *)&addr, + sizeof(addr), 0); + KUNIT_EXPECT_EQ(test, rc, 0); + } + + /* bind() */ + memset(&addr, 0x0, sizeof(addr)); + addr.smctp_family = AF_MCTP; + addr.smctp_network = setup->bind_net; + addr.smctp_addr.s_addr = setup->bind_addr; + addr.smctp_type = setup->bind_type; + + *ret_bind_errno = + kernel_bind(*sock, (struct sockaddr *)&addr, sizeof(addr)); +} |