mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	mctp: Implement extended addressing
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>
This commit is contained in:
		
							parent
							
								
									971f5c4079
								
							
						
					
					
						commit
						99ce45d5e7
					
				
					 5 changed files with 170 additions and 39 deletions
				
			
		| 
						 | 
					@ -365,6 +365,7 @@ struct ucred {
 | 
				
			||||||
#define SOL_TLS		282
 | 
					#define SOL_TLS		282
 | 
				
			||||||
#define SOL_XDP		283
 | 
					#define SOL_XDP		283
 | 
				
			||||||
#define SOL_MPTCP	284
 | 
					#define SOL_MPTCP	284
 | 
				
			||||||
 | 
					#define SOL_MCTP	285
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* IPX options */
 | 
					/* IPX options */
 | 
				
			||||||
#define IPX_TYPE	1
 | 
					#define IPX_TYPE	1
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/bits.h>
 | 
					#include <linux/bits.h>
 | 
				
			||||||
#include <linux/mctp.h>
 | 
					#include <linux/mctp.h>
 | 
				
			||||||
 | 
					#include <linux/netdevice.h>
 | 
				
			||||||
#include <net/net_namespace.h>
 | 
					#include <net/net_namespace.h>
 | 
				
			||||||
#include <net/sock.h>
 | 
					#include <net/sock.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,6 +59,9 @@ struct mctp_sock {
 | 
				
			||||||
	mctp_eid_t	bind_addr;
 | 
						mctp_eid_t	bind_addr;
 | 
				
			||||||
	__u8		bind_type;
 | 
						__u8		bind_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* sendmsg()/recvmsg() uses struct sockaddr_mctp_ext */
 | 
				
			||||||
 | 
						bool		addr_ext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* list of mctp_sk_key, for incoming tag lookup. updates protected
 | 
						/* list of mctp_sk_key, for incoming tag lookup. updates protected
 | 
				
			||||||
	 * by sk->net->keys_lock
 | 
						 * by sk->net->keys_lock
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
| 
						 | 
					@ -153,7 +157,10 @@ struct mctp_sk_key {
 | 
				
			||||||
struct mctp_skb_cb {
 | 
					struct mctp_skb_cb {
 | 
				
			||||||
	unsigned int	magic;
 | 
						unsigned int	magic;
 | 
				
			||||||
	unsigned int	net;
 | 
						unsigned int	net;
 | 
				
			||||||
 | 
						int		ifindex; /* extended/direct addressing if set */
 | 
				
			||||||
	mctp_eid_t	src;
 | 
						mctp_eid_t	src;
 | 
				
			||||||
 | 
						unsigned char	halen;
 | 
				
			||||||
 | 
						unsigned char	haddr[MAX_ADDR_LEN];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* skb control-block accessors with a little extra debugging for initial
 | 
					/* skb control-block accessors with a little extra debugging for initial
 | 
				
			||||||
| 
						 | 
					@ -177,6 +184,7 @@ static inline struct mctp_skb_cb *mctp_cb(struct sk_buff *skb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mctp_skb_cb *cb = (void *)skb->cb;
 | 
						struct mctp_skb_cb *cb = (void *)skb->cb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BUILD_BUG_ON(sizeof(struct mctp_skb_cb) > sizeof(skb->cb));
 | 
				
			||||||
	WARN_ON(cb->magic != 0x4d435450);
 | 
						WARN_ON(cb->magic != 0x4d435450);
 | 
				
			||||||
	return (void *)(skb->cb);
 | 
						return (void *)(skb->cb);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
					 * 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
 | 
					 * so routes cannot be referenced over a RCU grace period. Specifically: A
 | 
				
			||||||
 * caller cannot block between mctp_route_lookup and passing the route to
 | 
					 * caller cannot block between mctp_route_lookup and mctp_route_release()
 | 
				
			||||||
 * mctp_do_route.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct mctp_route {
 | 
					struct mctp_route {
 | 
				
			||||||
	mctp_eid_t		min, max;
 | 
						mctp_eid_t		min, max;
 | 
				
			||||||
| 
						 | 
					@ -210,8 +217,6 @@ struct mctp_route {
 | 
				
			||||||
struct mctp_route *mctp_route_lookup(struct net *net, unsigned int dnet,
 | 
					struct mctp_route *mctp_route_lookup(struct net *net, unsigned int dnet,
 | 
				
			||||||
				     mctp_eid_t daddr);
 | 
									     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,
 | 
					int mctp_local_output(struct sock *sk, struct mctp_route *rt,
 | 
				
			||||||
		      struct sk_buff *skb, mctp_eid_t daddr, u8 req_tag);
 | 
							      struct sk_buff *skb, mctp_eid_t daddr, u8 req_tag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/types.h>
 | 
					#include <linux/types.h>
 | 
				
			||||||
#include <linux/socket.h>
 | 
					#include <linux/socket.h>
 | 
				
			||||||
 | 
					#include <linux/netdevice.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef __u8			mctp_eid_t;
 | 
					typedef __u8			mctp_eid_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,6 +29,14 @@ struct sockaddr_mctp {
 | 
				
			||||||
	__u8			__smctp_pad1;
 | 
						__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_NET_ANY		0x0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MCTP_ADDR_NULL		0x00
 | 
					#define MCTP_ADDR_NULL		0x00
 | 
				
			||||||
| 
						 | 
					@ -36,4 +45,6 @@ struct sockaddr_mctp {
 | 
				
			||||||
#define MCTP_TAG_MASK		0x07
 | 
					#define MCTP_TAG_MASK		0x07
 | 
				
			||||||
#define MCTP_TAG_OWNER		0x08
 | 
					#define MCTP_TAG_OWNER		0x08
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MCTP_OPT_ADDR_EXT	1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __UAPI_MCTP_H */
 | 
					#endif /* __UAPI_MCTP_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
						const int hlen = MCTP_HEADER_MAXLEN + sizeof(struct mctp_hdr);
 | 
				
			||||||
	int rc, addrlen = msg->msg_namelen;
 | 
						int rc, addrlen = msg->msg_namelen;
 | 
				
			||||||
	struct sock *sk = sock->sk;
 | 
						struct sock *sk = sock->sk;
 | 
				
			||||||
 | 
						struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
 | 
				
			||||||
	struct mctp_skb_cb *cb;
 | 
						struct mctp_skb_cb *cb;
 | 
				
			||||||
	struct mctp_route *rt;
 | 
						struct mctp_route *rt;
 | 
				
			||||||
	struct sk_buff *skb;
 | 
						struct sk_buff *skb;
 | 
				
			||||||
| 
						 | 
					@ -100,11 +101,6 @@ static int mctp_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
 | 
				
			||||||
	if (addr->smctp_network == MCTP_NET_ANY)
 | 
						if (addr->smctp_network == MCTP_NET_ANY)
 | 
				
			||||||
		addr->smctp_network = mctp_default_net(sock_net(sk));
 | 
							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,
 | 
						skb = sock_alloc_send_skb(sk, hlen + 1 + len,
 | 
				
			||||||
				  msg->msg_flags & MSG_DONTWAIT, &rc);
 | 
									  msg->msg_flags & MSG_DONTWAIT, &rc);
 | 
				
			||||||
	if (!skb)
 | 
						if (!skb)
 | 
				
			||||||
| 
						 | 
					@ -116,19 +112,45 @@ static int mctp_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
 | 
				
			||||||
	*(u8 *)skb_put(skb, 1) = addr->smctp_type;
 | 
						*(u8 *)skb_put(skb, 1) = addr->smctp_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = memcpy_from_msg((void *)skb_put(skb, len), msg, len);
 | 
						rc = memcpy_from_msg((void *)skb_put(skb, len), msg, len);
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0)
 | 
				
			||||||
		kfree_skb(skb);
 | 
							goto err_free;
 | 
				
			||||||
		return rc;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* set up cb */
 | 
						/* set up cb */
 | 
				
			||||||
	cb = __mctp_cb(skb);
 | 
						cb = __mctp_cb(skb);
 | 
				
			||||||
	cb->net = addr->smctp_network;
 | 
						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,
 | 
						rc = mctp_local_output(sk, rt, skb, addr->smctp_addr.s_addr,
 | 
				
			||||||
			       addr->smctp_tag);
 | 
								       addr->smctp_tag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return rc ? : len;
 | 
						return rc ? : len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err_free:
 | 
				
			||||||
 | 
						kfree_skb(skb);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int mctp_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 | 
					static int mctp_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 | 
				
			||||||
| 
						 | 
					@ -136,6 +158,7 @@ static int mctp_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	DECLARE_SOCKADDR(struct sockaddr_mctp *, addr, msg->msg_name);
 | 
						DECLARE_SOCKADDR(struct sockaddr_mctp *, addr, msg->msg_name);
 | 
				
			||||||
	struct sock *sk = sock->sk;
 | 
						struct sock *sk = sock->sk;
 | 
				
			||||||
 | 
						struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
 | 
				
			||||||
	struct sk_buff *skb;
 | 
						struct sk_buff *skb;
 | 
				
			||||||
	size_t msglen;
 | 
						size_t msglen;
 | 
				
			||||||
	u8 type;
 | 
						u8 type;
 | 
				
			||||||
| 
						 | 
					@ -181,6 +204,16 @@ static int mctp_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 | 
				
			||||||
		addr->smctp_tag = hdr->flags_seq_tag &
 | 
							addr->smctp_tag = hdr->flags_seq_tag &
 | 
				
			||||||
					(MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO);
 | 
										(MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO);
 | 
				
			||||||
		msg->msg_namelen = sizeof(*addr);
 | 
							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;
 | 
						rc = len;
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
					static int mctp_setsockopt(struct socket *sock, int level, int optname,
 | 
				
			||||||
			   sockptr_t optval, unsigned int optlen)
 | 
								   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,
 | 
					static int mctp_getsockopt(struct socket *sock, int level, int optname,
 | 
				
			||||||
			   char __user *optval, int __user *optlen)
 | 
								   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;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -434,6 +434,7 @@ static unsigned int mctp_route_mtu(struct mctp_route *rt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int mctp_route_output(struct mctp_route *route, struct sk_buff *skb)
 | 
					static int mctp_route_output(struct mctp_route *route, struct sk_buff *skb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct mctp_skb_cb *cb = mctp_cb(skb);
 | 
				
			||||||
	struct mctp_hdr *hdr = mctp_hdr(skb);
 | 
						struct mctp_hdr *hdr = mctp_hdr(skb);
 | 
				
			||||||
	char daddr_buf[MAX_ADDR_LEN];
 | 
						char daddr_buf[MAX_ADDR_LEN];
 | 
				
			||||||
	char *daddr = NULL;
 | 
						char *daddr = NULL;
 | 
				
			||||||
| 
						 | 
					@ -448,9 +449,14 @@ static int mctp_route_output(struct mctp_route *route, struct sk_buff *skb)
 | 
				
			||||||
		return -EMSGSIZE;
 | 
							return -EMSGSIZE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If lookup fails let the device handle daddr==NULL */
 | 
						if (cb->ifindex) {
 | 
				
			||||||
	if (mctp_neigh_lookup(route->dev, hdr->dest, daddr_buf) == 0)
 | 
							/* direct route; use the hwaddr we stashed in sendmsg */
 | 
				
			||||||
		daddr = daddr_buf;
 | 
							daddr = cb->haddr;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/* If lookup fails let the device handle daddr==NULL */
 | 
				
			||||||
 | 
							if (mctp_neigh_lookup(route->dev, hdr->dest, daddr_buf) == 0)
 | 
				
			||||||
 | 
								daddr = daddr_buf;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = dev_hard_header(skb, skb->dev, ntohs(skb->protocol),
 | 
						rc = dev_hard_header(skb, skb->dev, ntohs(skb->protocol),
 | 
				
			||||||
			     daddr, skb->dev->dev_addr, skb->len);
 | 
								     daddr, skb->dev->dev_addr, skb->len);
 | 
				
			||||||
| 
						 | 
					@ -649,16 +655,6 @@ static struct mctp_route *mctp_route_lookup_null(struct net *net,
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* sends a skb to rt and releases the route. */
 | 
					 | 
				
			||||||
int mctp_do_route(struct mctp_route *rt, struct sk_buff *skb)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rc = rt->output(rt, skb);
 | 
					 | 
				
			||||||
	mctp_route_release(rt);
 | 
					 | 
				
			||||||
	return rc;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int mctp_do_fragment_route(struct mctp_route *rt, struct sk_buff *skb,
 | 
					static int mctp_do_fragment_route(struct mctp_route *rt, struct sk_buff *skb,
 | 
				
			||||||
				  unsigned int mtu, u8 tag)
 | 
									  unsigned int mtu, u8 tag)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -725,7 +721,7 @@ static int mctp_do_fragment_route(struct mctp_route *rt, struct sk_buff *skb,
 | 
				
			||||||
		/* copy message payload */
 | 
							/* copy message payload */
 | 
				
			||||||
		skb_copy_bits(skb, pos, skb_transport_header(skb2), size);
 | 
							skb_copy_bits(skb, pos, skb_transport_header(skb2), size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* do route, but don't drop the rt reference */
 | 
							/* do route */
 | 
				
			||||||
		rc = rt->output(rt, skb2);
 | 
							rc = rt->output(rt, skb2);
 | 
				
			||||||
		if (rc)
 | 
							if (rc)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
| 
						 | 
					@ -734,7 +730,6 @@ static int mctp_do_fragment_route(struct mctp_route *rt, struct sk_buff *skb,
 | 
				
			||||||
		pos += size;
 | 
							pos += size;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mctp_route_release(rt);
 | 
					 | 
				
			||||||
	consume_skb(skb);
 | 
						consume_skb(skb);
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -744,15 +739,51 @@ int mctp_local_output(struct sock *sk, struct mctp_route *rt,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
 | 
						struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
 | 
				
			||||||
	struct mctp_skb_cb *cb = mctp_cb(skb);
 | 
						struct mctp_skb_cb *cb = mctp_cb(skb);
 | 
				
			||||||
 | 
						struct mctp_route tmp_rt;
 | 
				
			||||||
 | 
						struct net_device *dev;
 | 
				
			||||||
	struct mctp_hdr *hdr;
 | 
						struct mctp_hdr *hdr;
 | 
				
			||||||
	unsigned long flags;
 | 
						unsigned long flags;
 | 
				
			||||||
	unsigned int mtu;
 | 
						unsigned int mtu;
 | 
				
			||||||
	mctp_eid_t saddr;
 | 
						mctp_eid_t saddr;
 | 
				
			||||||
 | 
						bool ext_rt;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	u8 tag;
 | 
						u8 tag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (WARN_ON(!rt->dev))
 | 
						rc = -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rt) {
 | 
				
			||||||
 | 
							ext_rt = false;
 | 
				
			||||||
 | 
							dev = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (WARN_ON(!rt->dev))
 | 
				
			||||||
 | 
								goto out_release;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						} else if (cb->ifindex) {
 | 
				
			||||||
 | 
							ext_rt = true;
 | 
				
			||||||
 | 
							rt = &tmp_rt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rcu_read_lock();
 | 
				
			||||||
 | 
							dev = dev_get_by_index_rcu(sock_net(sk), cb->ifindex);
 | 
				
			||||||
 | 
							if (!dev) {
 | 
				
			||||||
 | 
								rcu_read_unlock();
 | 
				
			||||||
 | 
								return rc;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rt->dev = __mctp_dev_get(dev);
 | 
				
			||||||
 | 
							rcu_read_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!rt->dev)
 | 
				
			||||||
 | 
								goto out_release;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* establish temporary route - we set up enough to keep
 | 
				
			||||||
 | 
							 * mctp_route_output happy
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							rt->output = mctp_route_output;
 | 
				
			||||||
 | 
							rt->mtu = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock_irqsave(&rt->dev->addrs_lock, flags);
 | 
						spin_lock_irqsave(&rt->dev->addrs_lock, flags);
 | 
				
			||||||
	if (rt->dev->num_addrs == 0) {
 | 
						if (rt->dev->num_addrs == 0) {
 | 
				
			||||||
| 
						 | 
					@ -765,18 +796,17 @@ int mctp_local_output(struct sock *sk, struct mctp_route *rt,
 | 
				
			||||||
	spin_unlock_irqrestore(&rt->dev->addrs_lock, flags);
 | 
						spin_unlock_irqrestore(&rt->dev->addrs_lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		return rc;
 | 
							goto out_release;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (req_tag & MCTP_HDR_FLAG_TO) {
 | 
						if (req_tag & MCTP_HDR_FLAG_TO) {
 | 
				
			||||||
		rc = mctp_alloc_local_tag(msk, saddr, daddr, &tag);
 | 
							rc = mctp_alloc_local_tag(msk, saddr, daddr, &tag);
 | 
				
			||||||
		if (rc)
 | 
							if (rc)
 | 
				
			||||||
			return rc;
 | 
								goto out_release;
 | 
				
			||||||
		tag |= MCTP_HDR_FLAG_TO;
 | 
							tag |= MCTP_HDR_FLAG_TO;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		tag = req_tag;
 | 
							tag = req_tag;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
	skb->protocol = htons(ETH_P_MCTP);
 | 
						skb->protocol = htons(ETH_P_MCTP);
 | 
				
			||||||
	skb->priority = 0;
 | 
						skb->priority = 0;
 | 
				
			||||||
	skb_reset_transport_header(skb);
 | 
						skb_reset_transport_header(skb);
 | 
				
			||||||
| 
						 | 
					@ -796,12 +826,22 @@ int mctp_local_output(struct sock *sk, struct mctp_route *rt,
 | 
				
			||||||
	mtu = mctp_route_mtu(rt);
 | 
						mtu = mctp_route_mtu(rt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (skb->len + sizeof(struct mctp_hdr) <= mtu) {
 | 
						if (skb->len + sizeof(struct mctp_hdr) <= mtu) {
 | 
				
			||||||
		hdr->flags_seq_tag = MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM |
 | 
							hdr->flags_seq_tag = MCTP_HDR_FLAG_SOM |
 | 
				
			||||||
			tag;
 | 
								MCTP_HDR_FLAG_EOM | tag;
 | 
				
			||||||
		return mctp_do_route(rt, skb);
 | 
							rc = rt->output(rt, skb);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		return mctp_do_fragment_route(rt, skb, mtu, tag);
 | 
							rc = mctp_do_fragment_route(rt, skb, mtu, tag);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_release:
 | 
				
			||||||
 | 
						if (!ext_rt)
 | 
				
			||||||
 | 
							mctp_route_release(rt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dev)
 | 
				
			||||||
 | 
							dev_put(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* route management */
 | 
					/* route management */
 | 
				
			||||||
| 
						 | 
					@ -942,8 +982,15 @@ static int mctp_pkttype_receive(struct sk_buff *skb, struct net_device *dev,
 | 
				
			||||||
	if (mh->ver < MCTP_VER_MIN || mh->ver > MCTP_VER_MAX)
 | 
						if (mh->ver < MCTP_VER_MIN || mh->ver > MCTP_VER_MAX)
 | 
				
			||||||
		goto err_drop;
 | 
							goto err_drop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cb = __mctp_cb(skb);
 | 
						/* MCTP drivers must populate halen/haddr */
 | 
				
			||||||
 | 
						if (dev->type == ARPHRD_MCTP) {
 | 
				
			||||||
 | 
							cb = mctp_cb(skb);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							cb = __mctp_cb(skb);
 | 
				
			||||||
 | 
							cb->halen = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	cb->net = READ_ONCE(mdev->net);
 | 
						cb->net = READ_ONCE(mdev->net);
 | 
				
			||||||
 | 
						cb->ifindex = dev->ifindex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rt = mctp_route_lookup(net, cb->net, mh->dest);
 | 
						rt = mctp_route_lookup(net, cb->net, mh->dest);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -954,7 +1001,8 @@ static int mctp_pkttype_receive(struct sk_buff *skb, struct net_device *dev,
 | 
				
			||||||
	if (!rt)
 | 
						if (!rt)
 | 
				
			||||||
		goto err_drop;
 | 
							goto err_drop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mctp_do_route(rt, skb);
 | 
						rt->output(rt, skb);
 | 
				
			||||||
 | 
						mctp_route_release(rt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return NET_RX_SUCCESS;
 | 
						return NET_RX_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue