forked from mirrors/linux
		
	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
	
	 Jeremy Kerr
						Jeremy Kerr