Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'net-mctp-improved-bind-handling'

Matt Johnston says:

====================
net: mctp: Improved bind handling

This series improves a couple of aspects of MCTP bind() handling.

MCTP wasn't checking whether the same MCTP type was bound by multiple
sockets. That would result in messages being received by an arbitrary
socket, which isn't useful behaviour. Instead it makes more sense to
have the duplicate binds fail, the same as other network protocols.
An exception is made for more-specific binds to particular MCTP
addresses.

It is also useful to be able to limit a bind to only receive incoming
request messages (MCTP TO bit set) from a specific peer+type, so that
individual processes can communicate with separate MCTP peers. One
example is a PLDM firmware update requester, which will initiate
communication with a device, and then the device will connect back to the
requester process.

These limited binds are implemented by a connect() call on the socket
prior to bind. connect() isn't used in the general case for MCTP, since
a plain send() wouldn't provide the required MCTP tag argument for
addressing.

Signed-off-by: Matt Johnston <matt@codeconstruct.com.au>
====================

Link: https://patch.msgid.link/20250710-mctp-bind-v4-0-8ec2f6460c56@codeconstruct.com.au
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

Paolo Abeni 55e8757c a8594c95

+637 -35
+4 -1
include/net/mctp.h
··· 69 69 70 70 /* bind() params */ 71 71 unsigned int bind_net; 72 - mctp_eid_t bind_addr; 72 + mctp_eid_t bind_local_addr; 73 + mctp_eid_t bind_peer_addr; 74 + unsigned int bind_peer_net; 75 + bool bind_peer_set; 73 76 __u8 bind_type; 74 77 75 78 /* sendmsg()/recvmsg() uses struct sockaddr_mctp_ext */
+16 -4
include/net/netns/mctp.h
··· 6 6 #ifndef __NETNS_MCTP_H__ 7 7 #define __NETNS_MCTP_H__ 8 8 9 + #include <linux/hash.h> 10 + #include <linux/hashtable.h> 9 11 #include <linux/mutex.h> 10 12 #include <linux/types.h> 13 + 14 + #define MCTP_BINDS_BITS 7 11 15 12 16 struct netns_mctp { 13 17 /* Only updated under RTNL, entries freed via RCU */ 14 18 struct list_head routes; 15 19 16 - /* Bound sockets: list of sockets bound by type. 17 - * This list is updated from non-atomic contexts (under bind_lock), 18 - * and read (under rcu) in packet rx 20 + /* Bound sockets: hash table of sockets, keyed by 21 + * (type, src_eid, dest_eid). 22 + * Specific src_eid/dest_eid entries also have an entry for 23 + * MCTP_ADDR_ANY. This list is updated from non-atomic contexts 24 + * (under bind_lock), and read (under rcu) in packet rx. 19 25 */ 20 26 struct mutex bind_lock; 21 - struct hlist_head binds; 27 + DECLARE_HASHTABLE(binds, MCTP_BINDS_BITS); 22 28 23 29 /* tag allocations. This list is read and updated from atomic contexts, 24 30 * but elements are free()ed after a RCU grace-period ··· 39 33 struct mutex neigh_lock; 40 34 struct list_head neighbours; 41 35 }; 36 + 37 + static inline u32 mctp_bind_hash(u8 type, u8 local_addr, u8 peer_addr) 38 + { 39 + return hash_32(type | (u32)local_addr << 8 | (u32)peer_addr << 16, 40 + MCTP_BINDS_BITS); 41 + } 42 42 43 43 #endif /* __NETNS_MCTP_H__ */
+139 -9
net/mctp/af_mctp.c
··· 53 53 { 54 54 struct sock *sk = sock->sk; 55 55 struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk); 56 + struct net *net = sock_net(&msk->sk); 56 57 struct sockaddr_mctp *smctp; 57 58 int rc; 58 59 ··· 74 73 75 74 lock_sock(sk); 76 75 77 - /* TODO: allow rebind */ 78 76 if (sk_hashed(sk)) { 79 77 rc = -EADDRINUSE; 80 78 goto out_release; 81 79 } 82 - msk->bind_net = smctp->smctp_network; 83 - msk->bind_addr = smctp->smctp_addr.s_addr; 84 - msk->bind_type = smctp->smctp_type & 0x7f; /* ignore the IC bit */ 80 + 81 + msk->bind_local_addr = smctp->smctp_addr.s_addr; 82 + 83 + /* MCTP_NET_ANY with a specific EID is resolved to the default net 84 + * at bind() time. 85 + * For bind_addr=MCTP_ADDR_ANY it is handled specially at route 86 + * lookup time. 87 + */ 88 + if (smctp->smctp_network == MCTP_NET_ANY && 89 + msk->bind_local_addr != MCTP_ADDR_ANY) { 90 + msk->bind_net = mctp_default_net(net); 91 + } else { 92 + msk->bind_net = smctp->smctp_network; 93 + } 94 + 95 + /* ignore the IC bit */ 96 + smctp->smctp_type &= 0x7f; 97 + 98 + if (msk->bind_peer_set) { 99 + if (msk->bind_type != smctp->smctp_type) { 100 + /* Prior connect() had a different type */ 101 + rc = -EINVAL; 102 + goto out_release; 103 + } 104 + 105 + if (msk->bind_net == MCTP_NET_ANY) { 106 + /* Restrict to the network passed to connect() */ 107 + msk->bind_net = msk->bind_peer_net; 108 + } 109 + 110 + if (msk->bind_net != msk->bind_peer_net) { 111 + /* connect() had a different net to bind() */ 112 + rc = -EINVAL; 113 + goto out_release; 114 + } 115 + } else { 116 + msk->bind_type = smctp->smctp_type; 117 + } 85 118 86 119 rc = sk->sk_prot->hash(sk); 87 120 88 121 out_release: 89 122 release_sock(sk); 90 123 124 + return rc; 125 + } 126 + 127 + /* Used to set a specific peer prior to bind. Not used for outbound 128 + * connections (Tag Owner set) since MCTP is a datagram protocol. 129 + */ 130 + static int mctp_connect(struct socket *sock, struct sockaddr *addr, 131 + int addrlen, int flags) 132 + { 133 + struct sock *sk = sock->sk; 134 + struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk); 135 + struct net *net = sock_net(&msk->sk); 136 + struct sockaddr_mctp *smctp; 137 + int rc; 138 + 139 + if (addrlen != sizeof(*smctp)) 140 + return -EINVAL; 141 + 142 + if (addr->sa_family != AF_MCTP) 143 + return -EAFNOSUPPORT; 144 + 145 + /* It's a valid sockaddr for MCTP, cast and do protocol checks */ 146 + smctp = (struct sockaddr_mctp *)addr; 147 + 148 + if (!mctp_sockaddr_is_ok(smctp)) 149 + return -EINVAL; 150 + 151 + /* Can't bind by tag */ 152 + if (smctp->smctp_tag) 153 + return -EINVAL; 154 + 155 + /* IC bit must be unset */ 156 + if (smctp->smctp_type & 0x80) 157 + return -EINVAL; 158 + 159 + lock_sock(sk); 160 + 161 + if (sk_hashed(sk)) { 162 + /* bind() already */ 163 + rc = -EADDRINUSE; 164 + goto out_release; 165 + } 166 + 167 + if (msk->bind_peer_set) { 168 + /* connect() already */ 169 + rc = -EADDRINUSE; 170 + goto out_release; 171 + } 172 + 173 + msk->bind_peer_set = true; 174 + msk->bind_peer_addr = smctp->smctp_addr.s_addr; 175 + msk->bind_type = smctp->smctp_type; 176 + if (smctp->smctp_network == MCTP_NET_ANY) 177 + msk->bind_peer_net = mctp_default_net(net); 178 + else 179 + msk->bind_peer_net = smctp->smctp_network; 180 + 181 + rc = 0; 182 + 183 + out_release: 184 + release_sock(sk); 91 185 return rc; 92 186 } 93 187 ··· 629 533 .family = PF_MCTP, 630 534 .release = mctp_release, 631 535 .bind = mctp_bind, 632 - .connect = sock_no_connect, 536 + .connect = mctp_connect, 633 537 .socketpair = sock_no_socketpair, 634 538 .accept = sock_no_accept, 635 539 .getname = sock_no_getname, ··· 696 600 697 601 INIT_HLIST_HEAD(&msk->keys); 698 602 timer_setup(&msk->key_expiry, mctp_sk_expire_keys, 0); 603 + msk->bind_peer_set = false; 699 604 return 0; 700 605 } 701 606 ··· 708 611 static int mctp_sk_hash(struct sock *sk) 709 612 { 710 613 struct net *net = sock_net(sk); 614 + struct sock *existing; 615 + struct mctp_sock *msk; 616 + mctp_eid_t remote; 617 + u32 hash; 618 + int rc; 619 + 620 + msk = container_of(sk, struct mctp_sock, sk); 621 + 622 + if (msk->bind_peer_set) 623 + remote = msk->bind_peer_addr; 624 + else 625 + remote = MCTP_ADDR_ANY; 626 + hash = mctp_bind_hash(msk->bind_type, msk->bind_local_addr, remote); 627 + 628 + mutex_lock(&net->mctp.bind_lock); 629 + 630 + /* Prevent duplicate binds. */ 631 + sk_for_each(existing, &net->mctp.binds[hash]) { 632 + struct mctp_sock *mex = 633 + container_of(existing, struct mctp_sock, sk); 634 + 635 + bool same_peer = (mex->bind_peer_set && msk->bind_peer_set && 636 + mex->bind_peer_addr == msk->bind_peer_addr) || 637 + (!mex->bind_peer_set && !msk->bind_peer_set); 638 + 639 + if (mex->bind_type == msk->bind_type && 640 + mex->bind_local_addr == msk->bind_local_addr && same_peer && 641 + mex->bind_net == msk->bind_net) { 642 + rc = -EADDRINUSE; 643 + goto out; 644 + } 645 + } 711 646 712 647 /* Bind lookup runs under RCU, remain live during that. */ 713 648 sock_set_flag(sk, SOCK_RCU_FREE); 714 649 715 - mutex_lock(&net->mctp.bind_lock); 716 - sk_add_node_rcu(sk, &net->mctp.binds); 717 - mutex_unlock(&net->mctp.bind_lock); 650 + sk_add_node_rcu(sk, &net->mctp.binds[hash]); 651 + rc = 0; 718 652 719 - return 0; 653 + out: 654 + mutex_unlock(&net->mctp.bind_lock); 655 + return rc; 720 656 } 721 657 722 658 static void mctp_sk_unhash(struct sock *sk)
+68 -17
net/mctp/route.c
··· 40 40 return 0; 41 41 } 42 42 43 - static struct mctp_sock *mctp_lookup_bind(struct net *net, struct sk_buff *skb) 43 + static struct mctp_sock *mctp_lookup_bind_details(struct net *net, 44 + struct sk_buff *skb, 45 + u8 type, u8 dest, 46 + u8 src, bool allow_net_any) 44 47 { 45 48 struct mctp_skb_cb *cb = mctp_cb(skb); 46 - struct mctp_hdr *mh; 47 49 struct sock *sk; 48 - u8 type; 50 + u8 hash; 49 51 50 - WARN_ON(!rcu_read_lock_held()); 52 + WARN_ON_ONCE(!rcu_read_lock_held()); 53 + 54 + hash = mctp_bind_hash(type, dest, src); 55 + 56 + sk_for_each_rcu(sk, &net->mctp.binds[hash]) { 57 + struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk); 58 + 59 + if (!allow_net_any && msk->bind_net == MCTP_NET_ANY) 60 + continue; 61 + 62 + if (msk->bind_net != MCTP_NET_ANY && msk->bind_net != cb->net) 63 + continue; 64 + 65 + if (msk->bind_type != type) 66 + continue; 67 + 68 + if (msk->bind_peer_set && 69 + !mctp_address_matches(msk->bind_peer_addr, src)) 70 + continue; 71 + 72 + if (!mctp_address_matches(msk->bind_local_addr, dest)) 73 + continue; 74 + 75 + return msk; 76 + } 77 + 78 + return NULL; 79 + } 80 + 81 + static struct mctp_sock *mctp_lookup_bind(struct net *net, struct sk_buff *skb) 82 + { 83 + struct mctp_sock *msk; 84 + struct mctp_hdr *mh; 85 + u8 type; 51 86 52 87 /* TODO: look up in skb->cb? */ 53 88 mh = mctp_hdr(skb); ··· 92 57 93 58 type = (*(u8 *)skb->data) & 0x7f; 94 59 95 - sk_for_each_rcu(sk, &net->mctp.binds) { 96 - struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk); 60 + /* Look for binds in order of widening scope. A given destination or 61 + * source address also implies matching on a particular network. 62 + * 63 + * - Matching destination and source 64 + * - Matching destination 65 + * - Matching source 66 + * - Matching network, any address 67 + * - Any network or address 68 + */ 97 69 98 - if (msk->bind_net != MCTP_NET_ANY && msk->bind_net != cb->net) 99 - continue; 100 - 101 - if (msk->bind_type != type) 102 - continue; 103 - 104 - if (!mctp_address_matches(msk->bind_addr, mh->dest)) 105 - continue; 106 - 70 + msk = mctp_lookup_bind_details(net, skb, type, mh->dest, mh->src, 71 + false); 72 + if (msk) 107 73 return msk; 108 - } 74 + msk = mctp_lookup_bind_details(net, skb, type, MCTP_ADDR_ANY, mh->src, 75 + false); 76 + if (msk) 77 + return msk; 78 + msk = mctp_lookup_bind_details(net, skb, type, mh->dest, MCTP_ADDR_ANY, 79 + false); 80 + if (msk) 81 + return msk; 82 + msk = mctp_lookup_bind_details(net, skb, type, MCTP_ADDR_ANY, 83 + MCTP_ADDR_ANY, false); 84 + if (msk) 85 + return msk; 86 + msk = mctp_lookup_bind_details(net, skb, type, MCTP_ADDR_ANY, 87 + MCTP_ADDR_ANY, true); 88 + if (msk) 89 + return msk; 109 90 110 91 return NULL; 111 92 } ··· 1722 1671 struct netns_mctp *ns = &net->mctp; 1723 1672 1724 1673 INIT_LIST_HEAD(&ns->routes); 1725 - INIT_HLIST_HEAD(&ns->binds); 1674 + hash_init(ns->binds); 1726 1675 mutex_init(&ns->bind_lock); 1727 1676 INIT_HLIST_HEAD(&ns->keys); 1728 1677 spin_lock_init(&ns->keys_lock);
+190 -4
net/mctp/test/route-test.c
··· 1164 1164 rc = mctp_dst_input(&dst, skb); 1165 1165 KUNIT_ASSERT_EQ(test, rc, 0); 1166 1166 1167 - mctp_test_dst_release(&dst, &tpq); 1168 - 1169 1167 skb2 = skb_recv_datagram(sock->sk, MSG_DONTWAIT, &rc); 1170 1168 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb2); 1171 1169 KUNIT_ASSERT_EQ(test, skb2->len, len); ··· 1177 1179 KUNIT_EXPECT_EQ(test, cb2->halen, sizeof(haddr)); 1178 1180 KUNIT_EXPECT_MEMEQ(test, cb2->haddr, haddr, sizeof(haddr)); 1179 1181 1180 - skb_free_datagram(sock->sk, skb2); 1181 - mctp_test_destroy_dev(dev); 1182 + kfree_skb(skb2); 1183 + __mctp_route_test_fini(test, dev, &dst, &tpq, sock); 1182 1184 } 1183 1185 1184 1186 static void mctp_test_route_gw_lookup(struct kunit *test) ··· 1408 1410 kfree_skb(skb); 1409 1411 } 1410 1412 1413 + struct mctp_bind_lookup_test { 1414 + /* header of incoming message */ 1415 + struct mctp_hdr hdr; 1416 + u8 ty; 1417 + /* mctp network of incoming interface (smctp_network) */ 1418 + unsigned int net; 1419 + 1420 + /* expected socket, matches .name in lookup_binds, NULL for dropped */ 1421 + const char *expect; 1422 + }; 1423 + 1424 + /* Single-packet TO-set message */ 1425 + #define LK(src, dst) RX_HDR(1, (src), (dst), FL_S | FL_E | FL_TO) 1426 + 1427 + /* Input message test cases for bind lookup tests. 1428 + * 1429 + * 10 and 11 are local EIDs. 1430 + * 20 and 21 are remote EIDs. 1431 + */ 1432 + static const struct mctp_bind_lookup_test mctp_bind_lookup_tests[] = { 1433 + /* both local-eid and remote-eid binds, remote eid is preferenced */ 1434 + { .hdr = LK(20, 10), .ty = 1, .net = 1, .expect = "remote20" }, 1435 + 1436 + { .hdr = LK(20, 255), .ty = 1, .net = 1, .expect = "remote20" }, 1437 + { .hdr = LK(20, 0), .ty = 1, .net = 1, .expect = "remote20" }, 1438 + { .hdr = LK(0, 255), .ty = 1, .net = 1, .expect = "any" }, 1439 + { .hdr = LK(0, 11), .ty = 1, .net = 1, .expect = "any" }, 1440 + { .hdr = LK(0, 0), .ty = 1, .net = 1, .expect = "any" }, 1441 + { .hdr = LK(0, 10), .ty = 1, .net = 1, .expect = "local10" }, 1442 + { .hdr = LK(21, 10), .ty = 1, .net = 1, .expect = "local10" }, 1443 + { .hdr = LK(21, 11), .ty = 1, .net = 1, .expect = "remote21local11" }, 1444 + 1445 + /* both src and dest set to eid=99. unusual, but accepted 1446 + * by MCTP stack currently. 1447 + */ 1448 + { .hdr = LK(99, 99), .ty = 1, .net = 1, .expect = "any" }, 1449 + 1450 + /* unbound smctp_type */ 1451 + { .hdr = LK(20, 10), .ty = 3, .net = 1, .expect = NULL }, 1452 + 1453 + /* smctp_network tests */ 1454 + 1455 + { .hdr = LK(0, 0), .ty = 1, .net = 7, .expect = "any" }, 1456 + { .hdr = LK(21, 10), .ty = 1, .net = 2, .expect = "any" }, 1457 + 1458 + /* remote EID 20 matches, but MCTP_NET_ANY in "remote20" resolved 1459 + * to net=1, so lookup doesn't match "remote20" 1460 + */ 1461 + { .hdr = LK(20, 10), .ty = 1, .net = 3, .expect = "any" }, 1462 + 1463 + { .hdr = LK(21, 10), .ty = 1, .net = 3, .expect = "remote21net3" }, 1464 + { .hdr = LK(21, 10), .ty = 1, .net = 4, .expect = "remote21net4" }, 1465 + { .hdr = LK(21, 10), .ty = 1, .net = 5, .expect = "remote21net5" }, 1466 + 1467 + { .hdr = LK(21, 10), .ty = 1, .net = 5, .expect = "remote21net5" }, 1468 + 1469 + { .hdr = LK(99, 10), .ty = 1, .net = 8, .expect = "local10net8" }, 1470 + 1471 + { .hdr = LK(99, 10), .ty = 1, .net = 9, .expect = "anynet9" }, 1472 + { .hdr = LK(0, 0), .ty = 1, .net = 9, .expect = "anynet9" }, 1473 + { .hdr = LK(99, 99), .ty = 1, .net = 9, .expect = "anynet9" }, 1474 + { .hdr = LK(20, 10), .ty = 1, .net = 9, .expect = "anynet9" }, 1475 + }; 1476 + 1477 + /* Binds to create during the lookup tests */ 1478 + static const struct mctp_test_bind_setup lookup_binds[] = { 1479 + /* any address and net, type 1 */ 1480 + { .name = "any", .bind_addr = MCTP_ADDR_ANY, 1481 + .bind_net = MCTP_NET_ANY, .bind_type = 1, }, 1482 + /* local eid 10, net 1 (resolved from MCTP_NET_ANY) */ 1483 + { .name = "local10", .bind_addr = 10, 1484 + .bind_net = MCTP_NET_ANY, .bind_type = 1, }, 1485 + /* local eid 10, net 8 */ 1486 + { .name = "local10net8", .bind_addr = 10, 1487 + .bind_net = 8, .bind_type = 1, }, 1488 + /* any EID, net 9 */ 1489 + { .name = "anynet9", .bind_addr = MCTP_ADDR_ANY, 1490 + .bind_net = 9, .bind_type = 1, }, 1491 + 1492 + /* remote eid 20, net 1, any local eid */ 1493 + { .name = "remote20", .bind_addr = MCTP_ADDR_ANY, 1494 + .bind_net = MCTP_NET_ANY, .bind_type = 1, 1495 + .have_peer = true, .peer_addr = 20, .peer_net = MCTP_NET_ANY, }, 1496 + 1497 + /* remote eid 20, net 1, local eid 11 */ 1498 + { .name = "remote21local11", .bind_addr = 11, 1499 + .bind_net = MCTP_NET_ANY, .bind_type = 1, 1500 + .have_peer = true, .peer_addr = 21, .peer_net = MCTP_NET_ANY, }, 1501 + 1502 + /* remote eid 21, specific net=3 for connect() */ 1503 + { .name = "remote21net3", .bind_addr = MCTP_ADDR_ANY, 1504 + .bind_net = MCTP_NET_ANY, .bind_type = 1, 1505 + .have_peer = true, .peer_addr = 21, .peer_net = 3, }, 1506 + 1507 + /* remote eid 21, net 4 for bind, specific net=4 for connect() */ 1508 + { .name = "remote21net4", .bind_addr = MCTP_ADDR_ANY, 1509 + .bind_net = 4, .bind_type = 1, 1510 + .have_peer = true, .peer_addr = 21, .peer_net = 4, }, 1511 + 1512 + /* remote eid 21, net 5 for bind, specific net=5 for connect() */ 1513 + { .name = "remote21net5", .bind_addr = MCTP_ADDR_ANY, 1514 + .bind_net = 5, .bind_type = 1, 1515 + .have_peer = true, .peer_addr = 21, .peer_net = 5, }, 1516 + }; 1517 + 1518 + static void mctp_bind_lookup_desc(const struct mctp_bind_lookup_test *t, 1519 + char *desc) 1520 + { 1521 + snprintf(desc, KUNIT_PARAM_DESC_SIZE, 1522 + "{src %d dst %d ty %d net %d expect %s}", 1523 + t->hdr.src, t->hdr.dest, t->ty, t->net, t->expect); 1524 + } 1525 + 1526 + KUNIT_ARRAY_PARAM(mctp_bind_lookup, mctp_bind_lookup_tests, 1527 + mctp_bind_lookup_desc); 1528 + 1529 + static void mctp_test_bind_lookup(struct kunit *test) 1530 + { 1531 + const struct mctp_bind_lookup_test *rx; 1532 + struct socket *socks[ARRAY_SIZE(lookup_binds)]; 1533 + struct sk_buff *skb_pkt = NULL, *skb_sock = NULL; 1534 + struct socket *sock_ty0, *sock_expect = NULL; 1535 + struct mctp_test_pktqueue tpq; 1536 + struct mctp_test_dev *dev; 1537 + struct mctp_dst dst; 1538 + int rc; 1539 + 1540 + rx = test->param_value; 1541 + 1542 + __mctp_route_test_init(test, &dev, &dst, &tpq, &sock_ty0, rx->net); 1543 + /* Create all binds */ 1544 + for (size_t i = 0; i < ARRAY_SIZE(lookup_binds); i++) { 1545 + mctp_test_bind_run(test, &lookup_binds[i], 1546 + &rc, &socks[i]); 1547 + KUNIT_ASSERT_EQ(test, rc, 0); 1548 + 1549 + /* Record the expected receive socket */ 1550 + if (rx->expect && 1551 + strcmp(rx->expect, lookup_binds[i].name) == 0) { 1552 + KUNIT_ASSERT_NULL(test, sock_expect); 1553 + sock_expect = socks[i]; 1554 + } 1555 + } 1556 + KUNIT_ASSERT_EQ(test, !!sock_expect, !!rx->expect); 1557 + 1558 + /* Create test message */ 1559 + skb_pkt = mctp_test_create_skb_data(&rx->hdr, &rx->ty); 1560 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb_pkt); 1561 + mctp_test_skb_set_dev(skb_pkt, dev); 1562 + mctp_test_pktqueue_init(&tpq); 1563 + 1564 + rc = mctp_dst_input(&dst, skb_pkt); 1565 + if (rx->expect) { 1566 + /* Test the message is received on the expected socket */ 1567 + KUNIT_EXPECT_EQ(test, rc, 0); 1568 + skb_sock = skb_recv_datagram(sock_expect->sk, 1569 + MSG_DONTWAIT, &rc); 1570 + if (!skb_sock) { 1571 + /* Find which socket received it instead */ 1572 + for (size_t i = 0; i < ARRAY_SIZE(lookup_binds); i++) { 1573 + skb_sock = skb_recv_datagram(socks[i]->sk, 1574 + MSG_DONTWAIT, &rc); 1575 + if (skb_sock) { 1576 + KUNIT_FAIL(test, 1577 + "received on incorrect socket '%s', expect '%s'", 1578 + lookup_binds[i].name, 1579 + rx->expect); 1580 + goto cleanup; 1581 + } 1582 + } 1583 + KUNIT_FAIL(test, "no message received"); 1584 + } 1585 + } else { 1586 + KUNIT_EXPECT_NE(test, rc, 0); 1587 + } 1588 + 1589 + cleanup: 1590 + kfree_skb(skb_sock); 1591 + kfree_skb(skb_pkt); 1592 + 1593 + /* Drop all binds */ 1594 + for (size_t i = 0; i < ARRAY_SIZE(lookup_binds); i++) 1595 + sock_release(socks[i]); 1596 + 1597 + __mctp_route_test_fini(test, dev, &dst, &tpq, sock_ty0); 1598 + } 1599 + 1411 1600 static struct kunit_case mctp_test_cases[] = { 1412 1601 KUNIT_CASE_PARAM(mctp_test_fragment, mctp_frag_gen_params), 1413 1602 KUNIT_CASE_PARAM(mctp_test_rx_input, mctp_rx_input_gen_params), ··· 1616 1431 KUNIT_CASE(mctp_test_route_gw_loop), 1617 1432 KUNIT_CASE_PARAM(mctp_test_route_gw_mtu, mctp_route_gw_mtu_gen_params), 1618 1433 KUNIT_CASE(mctp_test_route_gw_output), 1434 + KUNIT_CASE_PARAM(mctp_test_bind_lookup, mctp_bind_lookup_gen_params), 1619 1435 {} 1620 1436 }; 1621 1437
+167
net/mctp/test/sock-test.c
··· 215 215 __mctp_sock_test_fini(test, dev, rt, sock); 216 216 } 217 217 218 + static const struct mctp_test_bind_setup bind_addrany_netdefault_type1 = { 219 + .bind_addr = MCTP_ADDR_ANY, .bind_net = MCTP_NET_ANY, .bind_type = 1, 220 + }; 221 + 222 + static const struct mctp_test_bind_setup bind_addrany_net2_type1 = { 223 + .bind_addr = MCTP_ADDR_ANY, .bind_net = 2, .bind_type = 1, 224 + }; 225 + 226 + /* 1 is default net */ 227 + static const struct mctp_test_bind_setup bind_addr8_net1_type1 = { 228 + .bind_addr = 8, .bind_net = 1, .bind_type = 1, 229 + }; 230 + 231 + static const struct mctp_test_bind_setup bind_addrany_net1_type1 = { 232 + .bind_addr = MCTP_ADDR_ANY, .bind_net = 1, .bind_type = 1, 233 + }; 234 + 235 + /* 2 is an arbitrary net */ 236 + static const struct mctp_test_bind_setup bind_addr8_net2_type1 = { 237 + .bind_addr = 8, .bind_net = 2, .bind_type = 1, 238 + }; 239 + 240 + static const struct mctp_test_bind_setup bind_addr8_netdefault_type1 = { 241 + .bind_addr = 8, .bind_net = MCTP_NET_ANY, .bind_type = 1, 242 + }; 243 + 244 + static const struct mctp_test_bind_setup bind_addrany_net2_type2 = { 245 + .bind_addr = MCTP_ADDR_ANY, .bind_net = 2, .bind_type = 2, 246 + }; 247 + 248 + static const struct mctp_test_bind_setup bind_addrany_net2_type1_peer9 = { 249 + .bind_addr = MCTP_ADDR_ANY, .bind_net = 2, .bind_type = 1, 250 + .have_peer = true, .peer_addr = 9, .peer_net = 2, 251 + }; 252 + 253 + struct mctp_bind_pair_test { 254 + const struct mctp_test_bind_setup *bind1; 255 + const struct mctp_test_bind_setup *bind2; 256 + int error; 257 + }; 258 + 259 + /* Pairs of binds and whether they will conflict */ 260 + static const struct mctp_bind_pair_test mctp_bind_pair_tests[] = { 261 + /* Both ADDR_ANY, conflict */ 262 + { &bind_addrany_netdefault_type1, &bind_addrany_netdefault_type1, 263 + EADDRINUSE }, 264 + /* Same specific EID, conflict */ 265 + { &bind_addr8_netdefault_type1, &bind_addr8_netdefault_type1, 266 + EADDRINUSE }, 267 + /* ADDR_ANY vs specific EID, OK */ 268 + { &bind_addrany_netdefault_type1, &bind_addr8_netdefault_type1, 0 }, 269 + /* ADDR_ANY different types, OK */ 270 + { &bind_addrany_net2_type2, &bind_addrany_net2_type1, 0 }, 271 + /* ADDR_ANY different nets, OK */ 272 + { &bind_addrany_net2_type1, &bind_addrany_netdefault_type1, 0 }, 273 + 274 + /* specific EID, NET_ANY (resolves to default) 275 + * vs specific EID, explicit default net 1, conflict 276 + */ 277 + { &bind_addr8_netdefault_type1, &bind_addr8_net1_type1, EADDRINUSE }, 278 + 279 + /* specific EID, net 1 vs specific EID, net 2, ok */ 280 + { &bind_addr8_net1_type1, &bind_addr8_net2_type1, 0 }, 281 + 282 + /* ANY_ADDR, NET_ANY (doesn't resolve to default) 283 + * vs ADDR_ANY, explicit default net 1, OK 284 + */ 285 + { &bind_addrany_netdefault_type1, &bind_addrany_net1_type1, 0 }, 286 + 287 + /* specific remote peer doesn't conflict with any-peer bind */ 288 + { &bind_addrany_net2_type1_peer9, &bind_addrany_net2_type1, 0 }, 289 + 290 + /* bind() NET_ANY is allowed with a connect() net */ 291 + { &bind_addrany_net2_type1_peer9, &bind_addrany_netdefault_type1, 0 }, 292 + }; 293 + 294 + static void mctp_bind_pair_desc(const struct mctp_bind_pair_test *t, char *desc) 295 + { 296 + char peer1[25] = {0}, peer2[25] = {0}; 297 + 298 + if (t->bind1->have_peer) 299 + snprintf(peer1, sizeof(peer1), ", peer %d net %d", 300 + t->bind1->peer_addr, t->bind1->peer_net); 301 + if (t->bind2->have_peer) 302 + snprintf(peer2, sizeof(peer2), ", peer %d net %d", 303 + t->bind2->peer_addr, t->bind2->peer_net); 304 + 305 + snprintf(desc, KUNIT_PARAM_DESC_SIZE, 306 + "{bind(addr %d, type %d, net %d%s)} {bind(addr %d, type %d, net %d%s)} -> error %d", 307 + t->bind1->bind_addr, t->bind1->bind_type, 308 + t->bind1->bind_net, peer1, 309 + t->bind2->bind_addr, t->bind2->bind_type, 310 + t->bind2->bind_net, peer2, t->error); 311 + } 312 + 313 + KUNIT_ARRAY_PARAM(mctp_bind_pair, mctp_bind_pair_tests, mctp_bind_pair_desc); 314 + 315 + static void mctp_test_bind_invalid(struct kunit *test) 316 + { 317 + struct socket *sock; 318 + int rc; 319 + 320 + /* bind() fails if the bind() vs connect() networks mismatch. */ 321 + const struct mctp_test_bind_setup bind_connect_net_mismatch = { 322 + .bind_addr = MCTP_ADDR_ANY, .bind_net = 1, .bind_type = 1, 323 + .have_peer = true, .peer_addr = 9, .peer_net = 2, 324 + }; 325 + mctp_test_bind_run(test, &bind_connect_net_mismatch, &rc, &sock); 326 + KUNIT_EXPECT_EQ(test, -rc, EINVAL); 327 + sock_release(sock); 328 + } 329 + 330 + static int 331 + mctp_test_bind_conflicts_inner(struct kunit *test, 332 + const struct mctp_test_bind_setup *bind1, 333 + const struct mctp_test_bind_setup *bind2) 334 + { 335 + struct socket *sock1 = NULL, *sock2 = NULL, *sock3 = NULL; 336 + int bind_errno; 337 + 338 + /* Bind to first address, always succeeds */ 339 + mctp_test_bind_run(test, bind1, &bind_errno, &sock1); 340 + KUNIT_EXPECT_EQ(test, bind_errno, 0); 341 + 342 + /* A second identical bind always fails */ 343 + mctp_test_bind_run(test, bind1, &bind_errno, &sock2); 344 + KUNIT_EXPECT_EQ(test, -bind_errno, EADDRINUSE); 345 + 346 + /* A different bind, result is returned */ 347 + mctp_test_bind_run(test, bind2, &bind_errno, &sock3); 348 + 349 + if (sock1) 350 + sock_release(sock1); 351 + if (sock2) 352 + sock_release(sock2); 353 + if (sock3) 354 + sock_release(sock3); 355 + 356 + return bind_errno; 357 + } 358 + 359 + static void mctp_test_bind_conflicts(struct kunit *test) 360 + { 361 + const struct mctp_bind_pair_test *pair; 362 + int bind_errno; 363 + 364 + pair = test->param_value; 365 + 366 + bind_errno = 367 + mctp_test_bind_conflicts_inner(test, pair->bind1, pair->bind2); 368 + KUNIT_EXPECT_EQ(test, -bind_errno, pair->error); 369 + 370 + /* swapping the calls, the second bind should still fail */ 371 + bind_errno = 372 + mctp_test_bind_conflicts_inner(test, pair->bind2, pair->bind1); 373 + KUNIT_EXPECT_EQ(test, -bind_errno, pair->error); 374 + } 375 + 376 + static void mctp_test_assumptions(struct kunit *test) 377 + { 378 + /* check assumption of default net from bind_addr8_net1_type1 */ 379 + KUNIT_ASSERT_EQ(test, mctp_default_net(&init_net), 1); 380 + } 381 + 218 382 static struct kunit_case mctp_test_cases[] = { 383 + KUNIT_CASE(mctp_test_assumptions), 219 384 KUNIT_CASE(mctp_test_sock_sendmsg_extaddr), 220 385 KUNIT_CASE(mctp_test_sock_recvmsg_extaddr), 386 + KUNIT_CASE_PARAM(mctp_test_bind_conflicts, mctp_bind_pair_gen_params), 387 + KUNIT_CASE(mctp_test_bind_invalid), 221 388 {} 222 389 }; 223 390
+36
net/mctp/test/utils.c
··· 258 258 259 259 return skb; 260 260 } 261 + 262 + void mctp_test_bind_run(struct kunit *test, 263 + const struct mctp_test_bind_setup *setup, 264 + int *ret_bind_errno, struct socket **sock) 265 + { 266 + struct sockaddr_mctp addr; 267 + int rc; 268 + 269 + *ret_bind_errno = -EIO; 270 + 271 + rc = sock_create_kern(&init_net, AF_MCTP, SOCK_DGRAM, 0, sock); 272 + KUNIT_ASSERT_EQ(test, rc, 0); 273 + 274 + /* connect() if requested */ 275 + if (setup->have_peer) { 276 + memset(&addr, 0x0, sizeof(addr)); 277 + addr.smctp_family = AF_MCTP; 278 + addr.smctp_network = setup->peer_net; 279 + addr.smctp_addr.s_addr = setup->peer_addr; 280 + /* connect() type must match bind() type */ 281 + addr.smctp_type = setup->bind_type; 282 + rc = kernel_connect(*sock, (struct sockaddr *)&addr, 283 + sizeof(addr), 0); 284 + KUNIT_EXPECT_EQ(test, rc, 0); 285 + } 286 + 287 + /* bind() */ 288 + memset(&addr, 0x0, sizeof(addr)); 289 + addr.smctp_family = AF_MCTP; 290 + addr.smctp_network = setup->bind_net; 291 + addr.smctp_addr.s_addr = setup->bind_addr; 292 + addr.smctp_type = setup->bind_type; 293 + 294 + *ret_bind_errno = 295 + kernel_bind(*sock, (struct sockaddr *)&addr, sizeof(addr)); 296 + }
+17
net/mctp/test/utils.h
··· 31 31 struct sk_buff_head pkts; 32 32 }; 33 33 34 + struct mctp_test_bind_setup { 35 + mctp_eid_t bind_addr; 36 + int bind_net; 37 + u8 bind_type; 38 + 39 + bool have_peer; 40 + mctp_eid_t peer_addr; 41 + int peer_net; 42 + 43 + /* optional name. Used for comparison in "lookup" tests */ 44 + const char *name; 45 + }; 46 + 34 47 struct mctp_test_dev *mctp_test_create_dev(void); 35 48 struct mctp_test_dev *mctp_test_create_dev_lladdr(unsigned short lladdr_len, 36 49 const unsigned char *lladdr); ··· 73 60 74 61 #define mctp_test_create_skb_data(h, d) \ 75 62 __mctp_test_create_skb_data(h, d, sizeof(*d)) 63 + 64 + void mctp_test_bind_run(struct kunit *test, 65 + const struct mctp_test_bind_setup *setup, 66 + int *ret_bind_errno, struct socket **sock); 76 67 77 68 #endif /* __NET_MCTP_TEST_UTILS_H */