Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions include/uapi/linux/mctp.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ struct mctp_fq_addr {
#define MCTP_TAG_PREALLOC 0x10

#define MCTP_OPT_ADDR_EXT 1
#define MCTP_OPT_ROUTE_SRCADDR 2

/* Query structure for MCTP_OPT_ROUTE_SRCADDR getsockopt.
*
* Caller fills in @net and @daddr before calling getsockopt.
* Performs a route lookup and returns the local source EID in @saddr.
*/
struct mctp_route_srcaddr {
unsigned int net;
mctp_eid_t daddr;
mctp_eid_t saddr;
__u8 __pad[2];
};

#define SIOCMCTPALLOCTAG (SIOCPROTOPRIVATE + 0)
#define SIOCMCTPDROPTAG (SIOCPROTOPRIVATE + 1)
Expand Down
33 changes: 33 additions & 0 deletions net/mctp/af_mctp.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,39 @@ static int mctp_getsockopt(struct socket *sock, int level, int optname,
return 0;
}

if (optname == MCTP_OPT_ROUTE_SRCADDR) {
struct mctp_route_srcaddr rsa;
struct mctp_dst dst;
unsigned int net;
int rc;

if (len != sizeof(rsa))
return -EINVAL;

if (copy_from_user(&rsa, optval, sizeof(rsa)))
return -EFAULT;

net = rsa.net;
if (net == MCTP_NET_ANY)
net = mctp_default_net(sock_net(sock->sk));

rc = mctp_route_lookup(sock_net(sock->sk), net, rsa.daddr, &dst);
if (rc)
return rc;

rsa.saddr = dst.saddr;
mctp_dst_release(&dst);

if (rsa.saddr == MCTP_ADDR_NULL)
return -EADDRNOTAVAIL;

if (put_user(sizeof(rsa), optlen))
return -EFAULT;
if (copy_to_user(optval, &rsa, sizeof(rsa)))
return -EFAULT;
return 0;
}

return -ENOPROTOOPT;
}

Expand Down
49 changes: 49 additions & 0 deletions net/mctp/test/sock-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,10 +379,59 @@ static void mctp_test_assumptions(struct kunit *test)
KUNIT_ASSERT_EQ(test, mctp_default_net(&init_net), 1);
}

static void mctp_test_getsockopt_route_srcaddr(struct kunit *test)
{
struct mctp_route_srcaddr rsa = {
.net = MCTP_INITIAL_DEFAULT_NET,
.daddr = 9,
};
struct mctp_test_route *rt;
struct mctp_test_dev *dev;
struct socket *sock;
int optlen = sizeof(rsa);
int rc;

__mctp_sock_test_init(test, &dev, &rt, &sock);

/* Query the source EID for destination EID 9; the device has
* local EID 8, so the route lookup should return saddr=8.
*/
rc = mctp_getsockopt(sock, SOL_MCTP, MCTP_OPT_ROUTE_SRCADDR,
(char __user *)&rsa, (int __user *)&optlen);
KUNIT_EXPECT_EQ(test, rc, 0);
KUNIT_EXPECT_EQ(test, (int)rsa.saddr, 8);
KUNIT_EXPECT_EQ(test, optlen, (int)sizeof(rsa));

__mctp_sock_test_fini(test, dev, rt, sock);
}

static void mctp_test_getsockopt_route_srcaddr_no_route(struct kunit *test)
{
struct mctp_route_srcaddr rsa = {
.net = MCTP_INITIAL_DEFAULT_NET,
.daddr = 99, /* no route for this EID */
};
struct mctp_test_route *rt;
struct mctp_test_dev *dev;
struct socket *sock;
int optlen = sizeof(rsa);
int rc;

__mctp_sock_test_init(test, &dev, &rt, &sock);

rc = mctp_getsockopt(sock, SOL_MCTP, MCTP_OPT_ROUTE_SRCADDR,
(char __user *)&rsa, (int __user *)&optlen);
KUNIT_EXPECT_EQ(test, rc, -EHOSTUNREACH);

__mctp_sock_test_fini(test, dev, rt, sock);
}

static struct kunit_case mctp_test_cases[] = {
KUNIT_CASE(mctp_test_assumptions),
KUNIT_CASE(mctp_test_sock_sendmsg_extaddr),
KUNIT_CASE(mctp_test_sock_recvmsg_extaddr),
KUNIT_CASE(mctp_test_getsockopt_route_srcaddr),
KUNIT_CASE(mctp_test_getsockopt_route_srcaddr_no_route),
KUNIT_CASE_PARAM(mctp_test_bind_conflicts, mctp_bind_pair_gen_params),
KUNIT_CASE(mctp_test_bind_invalid),
{}
Expand Down