Skip to content

Commit

Permalink
mctp: Implement extended addressing
Browse files Browse the repository at this point in the history
This change allows an extended address struct - struct sockaddr_mctp_ext
- to be passed to sendmsg/recvmsg. This allows userspace to specify
output ifindex and physical address information (for sendmsg) or receive
the input ifindex/physaddr for incoming messages (for recvmsg). This is
typically used by userspace for MCTP address discovery and assignment
operations.

The extended addressing facility is conditional on a new sockopt:
MCTP_OPT_ADDR_EXT; userspace must explicitly enable addressing before
the kernel will consume/populate the extended address data.

Includes a fix for an uninitialised var:
Reported-by: kernel test robot <lkp@intel.com>

Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jeremy Kerr authored and David S. Miller committed Oct 26, 2021
1 parent 971f5c4 commit 99ce45d
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 39 deletions.
1 change: 1 addition & 0 deletions include/linux/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ struct ucred {
#define SOL_TLS 282
#define SOL_XDP 283
#define SOL_MPTCP 284
#define SOL_MCTP 285

/* IPX options */
#define IPX_TYPE 1
Expand Down
13 changes: 9 additions & 4 deletions include/net/mctp.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <linux/bits.h>
#include <linux/mctp.h>
#include <linux/netdevice.h>
#include <net/net_namespace.h>
#include <net/sock.h>

Expand Down Expand Up @@ -58,6 +59,9 @@ struct mctp_sock {
mctp_eid_t bind_addr;
__u8 bind_type;

/* sendmsg()/recvmsg() uses struct sockaddr_mctp_ext */
bool addr_ext;

/* list of mctp_sk_key, for incoming tag lookup. updates protected
* by sk->net->keys_lock
*/
Expand Down Expand Up @@ -153,7 +157,10 @@ struct mctp_sk_key {
struct mctp_skb_cb {
unsigned int magic;
unsigned int net;
int ifindex; /* extended/direct addressing if set */
mctp_eid_t src;
unsigned char halen;
unsigned char haddr[MAX_ADDR_LEN];
};

/* skb control-block accessors with a little extra debugging for initial
Expand All @@ -177,6 +184,7 @@ static inline struct mctp_skb_cb *mctp_cb(struct sk_buff *skb)
{
struct mctp_skb_cb *cb = (void *)skb->cb;

BUILD_BUG_ON(sizeof(struct mctp_skb_cb) > sizeof(skb->cb));
WARN_ON(cb->magic != 0x4d435450);
return (void *)(skb->cb);
}
Expand All @@ -189,8 +197,7 @@ static inline struct mctp_skb_cb *mctp_cb(struct sk_buff *skb)
*
* Updates to the route table are performed under rtnl; all reads under RCU,
* so routes cannot be referenced over a RCU grace period. Specifically: A
* caller cannot block between mctp_route_lookup and passing the route to
* mctp_do_route.
* caller cannot block between mctp_route_lookup and mctp_route_release()
*/
struct mctp_route {
mctp_eid_t min, max;
Expand All @@ -210,8 +217,6 @@ struct mctp_route {
struct mctp_route *mctp_route_lookup(struct net *net, unsigned int dnet,
mctp_eid_t daddr);

int mctp_do_route(struct mctp_route *rt, struct sk_buff *skb);

int mctp_local_output(struct sock *sk, struct mctp_route *rt,
struct sk_buff *skb, mctp_eid_t daddr, u8 req_tag);

Expand Down
11 changes: 11 additions & 0 deletions include/uapi/linux/mctp.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <linux/types.h>
#include <linux/socket.h>
#include <linux/netdevice.h>

typedef __u8 mctp_eid_t;

Expand All @@ -28,6 +29,14 @@ struct sockaddr_mctp {
__u8 __smctp_pad1;
};

struct sockaddr_mctp_ext {
struct sockaddr_mctp smctp_base;
int smctp_ifindex;
__u8 smctp_halen;
__u8 __smctp_pad0[3];
__u8 smctp_haddr[MAX_ADDR_LEN];
};

#define MCTP_NET_ANY 0x0

#define MCTP_ADDR_NULL 0x00
Expand All @@ -36,4 +45,6 @@ struct sockaddr_mctp {
#define MCTP_TAG_MASK 0x07
#define MCTP_TAG_OWNER 0x08

#define MCTP_OPT_ADDR_EXT 1

#endif /* __UAPI_MCTP_H */
86 changes: 76 additions & 10 deletions net/mctp/af_mctp.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ static int mctp_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
const int hlen = MCTP_HEADER_MAXLEN + sizeof(struct mctp_hdr);
int rc, addrlen = msg->msg_namelen;
struct sock *sk = sock->sk;
struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
struct mctp_skb_cb *cb;
struct mctp_route *rt;
struct sk_buff *skb;
Expand All @@ -100,11 +101,6 @@ static int mctp_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
if (addr->smctp_network == MCTP_NET_ANY)
addr->smctp_network = mctp_default_net(sock_net(sk));

rt = mctp_route_lookup(sock_net(sk), addr->smctp_network,
addr->smctp_addr.s_addr);
if (!rt)
return -EHOSTUNREACH;

skb = sock_alloc_send_skb(sk, hlen + 1 + len,
msg->msg_flags & MSG_DONTWAIT, &rc);
if (!skb)
Expand All @@ -116,26 +112,53 @@ static int mctp_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
*(u8 *)skb_put(skb, 1) = addr->smctp_type;

rc = memcpy_from_msg((void *)skb_put(skb, len), msg, len);
if (rc < 0) {
kfree_skb(skb);
return rc;
}
if (rc < 0)
goto err_free;

/* set up cb */
cb = __mctp_cb(skb);
cb->net = addr->smctp_network;

/* direct addressing */
if (msk->addr_ext && addrlen >= sizeof(struct sockaddr_mctp_ext)) {
DECLARE_SOCKADDR(struct sockaddr_mctp_ext *,
extaddr, msg->msg_name);

if (extaddr->smctp_halen > sizeof(cb->haddr)) {
rc = -EINVAL;
goto err_free;
}

cb->ifindex = extaddr->smctp_ifindex;
cb->halen = extaddr->smctp_halen;
memcpy(cb->haddr, extaddr->smctp_haddr, cb->halen);

rt = NULL;
} else {
rt = mctp_route_lookup(sock_net(sk), addr->smctp_network,
addr->smctp_addr.s_addr);
if (!rt) {
rc = -EHOSTUNREACH;
goto err_free;
}
}

rc = mctp_local_output(sk, rt, skb, addr->smctp_addr.s_addr,
addr->smctp_tag);

return rc ? : len;

err_free:
kfree_skb(skb);
return rc;
}

static int mctp_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
int flags)
{
DECLARE_SOCKADDR(struct sockaddr_mctp *, addr, msg->msg_name);
struct sock *sk = sock->sk;
struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
struct sk_buff *skb;
size_t msglen;
u8 type;
Expand Down Expand Up @@ -181,6 +204,16 @@ static int mctp_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
addr->smctp_tag = hdr->flags_seq_tag &
(MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO);
msg->msg_namelen = sizeof(*addr);

if (msk->addr_ext) {
DECLARE_SOCKADDR(struct sockaddr_mctp_ext *, ae,
msg->msg_name);
msg->msg_namelen = sizeof(*ae);
ae->smctp_ifindex = cb->ifindex;
ae->smctp_halen = cb->halen;
memset(ae->smctp_haddr, 0x0, sizeof(ae->smctp_haddr));
memcpy(ae->smctp_haddr, cb->haddr, cb->halen);
}
}

rc = len;
Expand All @@ -196,12 +229,45 @@ static int mctp_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
static int mctp_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int optlen)
{
return -EINVAL;
struct mctp_sock *msk = container_of(sock->sk, struct mctp_sock, sk);
int val;

if (level != SOL_MCTP)
return -EINVAL;

if (optname == MCTP_OPT_ADDR_EXT) {
if (optlen != sizeof(int))
return -EINVAL;
if (copy_from_sockptr(&val, optval, sizeof(int)))
return -EFAULT;
msk->addr_ext = val;
return 0;
}

return -ENOPROTOOPT;
}

static int mctp_getsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user *optlen)
{
struct mctp_sock *msk = container_of(sock->sk, struct mctp_sock, sk);
int len, val;

if (level != SOL_MCTP)
return -EINVAL;

if (get_user(len, optlen))
return -EFAULT;

if (optname == MCTP_OPT_ADDR_EXT) {
if (len != sizeof(int))
return -EINVAL;
val = !!msk->addr_ext;
if (copy_to_user(optval, &val, len))
return -EFAULT;
return 0;
}

return -EINVAL;
}

Expand Down
Loading

0 comments on commit 99ce45d

Please sign in to comment.