forked from mirrors/linux
		
	ipv4: Implement IP_UNICAST_IF socket option.
The IP_UNICAST_IF feature is needed by the Wine project. This patch implements the feature by setting the outgoing interface in a similar fashion to that of IP_MULTICAST_IF. A separate option is needed to handle this feature since the existing options do not provide all of the characteristics required by IP_UNICAST_IF, a summary is provided below. SO_BINDTODEVICE: * SO_BINDTODEVICE requires administrative privileges, IP_UNICAST_IF does not. From reading some old mailing list articles my understanding is that SO_BINDTODEVICE requires administrative privileges because it can override the administrator's routing settings. * The SO_BINDTODEVICE option restricts both outbound and inbound traffic, IP_UNICAST_IF only impacts outbound traffic. IP_PKTINFO: * Since IP_PKTINFO and IP_UNICAST_IF are independent options, implementing IP_UNICAST_IF with IP_PKTINFO will likely break some applications. * Implementing IP_UNICAST_IF on top of IP_PKTINFO significantly complicates the Wine codebase and reduces the socket performance (doing this requires a lot of extra communication between the "server" and "user" layers). bind(): * bind() does not work on broadcast packets, IP_UNICAST_IF is specifically intended to work with broadcast packets. * Like SO_BINDTODEVICE, bind() restricts both outbound and inbound traffic. Signed-off-by: Erich E. Hoover <ehoover@mines.edu> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									43480aecb1
								
							
						
					
					
						commit
						76e21053b5
					
				
					 6 changed files with 42 additions and 3 deletions
				
			
		|  | @ -111,6 +111,7 @@ struct in_addr { | ||||||
| #define MCAST_LEAVE_SOURCE_GROUP	47 | #define MCAST_LEAVE_SOURCE_GROUP	47 | ||||||
| #define MCAST_MSFILTER			48 | #define MCAST_MSFILTER			48 | ||||||
| #define IP_MULTICAST_ALL		49 | #define IP_MULTICAST_ALL		49 | ||||||
|  | #define IP_UNICAST_IF			50 | ||||||
| 
 | 
 | ||||||
| #define MCAST_EXCLUDE	0 | #define MCAST_EXCLUDE	0 | ||||||
| #define MCAST_INCLUDE	1 | #define MCAST_INCLUDE	1 | ||||||
|  |  | ||||||
|  | @ -132,6 +132,7 @@ struct rtable; | ||||||
|  * @tos - TOS |  * @tos - TOS | ||||||
|  * @mc_ttl - Multicasting TTL |  * @mc_ttl - Multicasting TTL | ||||||
|  * @is_icsk - is this an inet_connection_sock? |  * @is_icsk - is this an inet_connection_sock? | ||||||
|  |  * @uc_index - Unicast outgoing device index | ||||||
|  * @mc_index - Multicast device index |  * @mc_index - Multicast device index | ||||||
|  * @mc_list - Group array |  * @mc_list - Group array | ||||||
|  * @cork - info to build ip hdr on each ip frag while socket is corked |  * @cork - info to build ip hdr on each ip frag while socket is corked | ||||||
|  | @ -167,6 +168,7 @@ struct inet_sock { | ||||||
| 				transparent:1, | 				transparent:1, | ||||||
| 				mc_all:1, | 				mc_all:1, | ||||||
| 				nodefrag:1; | 				nodefrag:1; | ||||||
|  | 	int			uc_index; | ||||||
| 	int			mc_index; | 	int			mc_index; | ||||||
| 	__be32			mc_addr; | 	__be32			mc_addr; | ||||||
| 	struct ip_mc_socklist __rcu	*mc_list; | 	struct ip_mc_socklist __rcu	*mc_list; | ||||||
|  |  | ||||||
|  | @ -469,6 +469,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, | ||||||
| 			     (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) | | 			     (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) | | ||||||
| 			     (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT) | | 			     (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT) | | ||||||
| 			     (1<<IP_MINTTL) | (1<<IP_NODEFRAG))) || | 			     (1<<IP_MINTTL) | (1<<IP_NODEFRAG))) || | ||||||
|  | 	    optname == IP_UNICAST_IF || | ||||||
| 	    optname == IP_MULTICAST_TTL || | 	    optname == IP_MULTICAST_TTL || | ||||||
| 	    optname == IP_MULTICAST_ALL || | 	    optname == IP_MULTICAST_ALL || | ||||||
| 	    optname == IP_MULTICAST_LOOP || | 	    optname == IP_MULTICAST_LOOP || | ||||||
|  | @ -628,6 +629,35 @@ static int do_ip_setsockopt(struct sock *sk, int level, | ||||||
| 			goto e_inval; | 			goto e_inval; | ||||||
| 		inet->mc_loop = !!val; | 		inet->mc_loop = !!val; | ||||||
| 		break; | 		break; | ||||||
|  | 	case IP_UNICAST_IF: | ||||||
|  | 	{ | ||||||
|  | 		struct net_device *dev = NULL; | ||||||
|  | 		int ifindex; | ||||||
|  | 
 | ||||||
|  | 		if (optlen != sizeof(int)) | ||||||
|  | 			goto e_inval; | ||||||
|  | 
 | ||||||
|  | 		ifindex = (__force int)ntohl((__force __be32)val); | ||||||
|  | 		if (ifindex == 0) { | ||||||
|  | 			inet->uc_index = 0; | ||||||
|  | 			err = 0; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		dev = dev_get_by_index(sock_net(sk), ifindex); | ||||||
|  | 		err = -EADDRNOTAVAIL; | ||||||
|  | 		if (!dev) | ||||||
|  | 			break; | ||||||
|  | 		dev_put(dev); | ||||||
|  | 
 | ||||||
|  | 		err = -EINVAL; | ||||||
|  | 		if (sk->sk_bound_dev_if) | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
|  | 		inet->uc_index = ifindex; | ||||||
|  | 		err = 0; | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
| 	case IP_MULTICAST_IF: | 	case IP_MULTICAST_IF: | ||||||
| 	{ | 	{ | ||||||
| 		struct ip_mreqn mreq; | 		struct ip_mreqn mreq; | ||||||
|  | @ -1178,6 +1208,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, | ||||||
| 	case IP_MULTICAST_LOOP: | 	case IP_MULTICAST_LOOP: | ||||||
| 		val = inet->mc_loop; | 		val = inet->mc_loop; | ||||||
| 		break; | 		break; | ||||||
|  | 	case IP_UNICAST_IF: | ||||||
|  | 		val = (__force int)htonl((__u32) inet->uc_index); | ||||||
|  | 		break; | ||||||
| 	case IP_MULTICAST_IF: | 	case IP_MULTICAST_IF: | ||||||
| 	{ | 	{ | ||||||
| 		struct in_addr addr; | 		struct in_addr addr; | ||||||
|  |  | ||||||
|  | @ -556,7 +556,8 @@ static int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | ||||||
| 			ipc.oif = inet->mc_index; | 			ipc.oif = inet->mc_index; | ||||||
| 		if (!saddr) | 		if (!saddr) | ||||||
| 			saddr = inet->mc_addr; | 			saddr = inet->mc_addr; | ||||||
| 	} | 	} else if (!ipc.oif) | ||||||
|  | 		ipc.oif = inet->uc_index; | ||||||
| 
 | 
 | ||||||
| 	flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, | 	flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, | ||||||
| 			   RT_SCOPE_UNIVERSE, sk->sk_protocol, | 			   RT_SCOPE_UNIVERSE, sk->sk_protocol, | ||||||
|  |  | ||||||
|  | @ -563,7 +563,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | ||||||
| 			ipc.oif = inet->mc_index; | 			ipc.oif = inet->mc_index; | ||||||
| 		if (!saddr) | 		if (!saddr) | ||||||
| 			saddr = inet->mc_addr; | 			saddr = inet->mc_addr; | ||||||
| 	} | 	} else if (!ipc.oif) | ||||||
|  | 		ipc.oif = inet->uc_index; | ||||||
| 
 | 
 | ||||||
| 	flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, | 	flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, | ||||||
| 			   RT_SCOPE_UNIVERSE, | 			   RT_SCOPE_UNIVERSE, | ||||||
|  |  | ||||||
|  | @ -917,7 +917,8 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | ||||||
| 		if (!saddr) | 		if (!saddr) | ||||||
| 			saddr = inet->mc_addr; | 			saddr = inet->mc_addr; | ||||||
| 		connected = 0; | 		connected = 0; | ||||||
| 	} | 	} else if (!ipc.oif) | ||||||
|  | 		ipc.oif = inet->uc_index; | ||||||
| 
 | 
 | ||||||
| 	if (connected) | 	if (connected) | ||||||
| 		rt = (struct rtable *)sk_dst_check(sk, 0); | 		rt = (struct rtable *)sk_dst_check(sk, 0); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Erich E. Hoover
						Erich E. Hoover