forked from Minki/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
@ -111,6 +111,7 @@ struct in_addr {
|
||||
#define MCAST_LEAVE_SOURCE_GROUP 47
|
||||
#define MCAST_MSFILTER 48
|
||||
#define IP_MULTICAST_ALL 49
|
||||
#define IP_UNICAST_IF 50
|
||||
|
||||
#define MCAST_EXCLUDE 0
|
||||
#define MCAST_INCLUDE 1
|
||||
|
@ -132,6 +132,7 @@ struct rtable;
|
||||
* @tos - TOS
|
||||
* @mc_ttl - Multicasting TTL
|
||||
* @is_icsk - is this an inet_connection_sock?
|
||||
* @uc_index - Unicast outgoing device index
|
||||
* @mc_index - Multicast device index
|
||||
* @mc_list - Group array
|
||||
* @cork - info to build ip hdr on each ip frag while socket is corked
|
||||
@ -167,6 +168,7 @@ struct inet_sock {
|
||||
transparent:1,
|
||||
mc_all:1,
|
||||
nodefrag:1;
|
||||
int uc_index;
|
||||
int mc_index;
|
||||
__be32 mc_addr;
|
||||
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_PASSSEC) | (1<<IP_TRANSPARENT) |
|
||||
(1<<IP_MINTTL) | (1<<IP_NODEFRAG))) ||
|
||||
optname == IP_UNICAST_IF ||
|
||||
optname == IP_MULTICAST_TTL ||
|
||||
optname == IP_MULTICAST_ALL ||
|
||||
optname == IP_MULTICAST_LOOP ||
|
||||
@ -628,6 +629,35 @@ static int do_ip_setsockopt(struct sock *sk, int level,
|
||||
goto e_inval;
|
||||
inet->mc_loop = !!val;
|
||||
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:
|
||||
{
|
||||
struct ip_mreqn mreq;
|
||||
@ -1178,6 +1208,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
|
||||
case IP_MULTICAST_LOOP:
|
||||
val = inet->mc_loop;
|
||||
break;
|
||||
case IP_UNICAST_IF:
|
||||
val = (__force int)htonl((__u32) inet->uc_index);
|
||||
break;
|
||||
case IP_MULTICAST_IF:
|
||||
{
|
||||
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;
|
||||
if (!saddr)
|
||||
saddr = inet->mc_addr;
|
||||
}
|
||||
} else if (!ipc.oif)
|
||||
ipc.oif = inet->uc_index;
|
||||
|
||||
flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
|
||||
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;
|
||||
if (!saddr)
|
||||
saddr = inet->mc_addr;
|
||||
}
|
||||
} else if (!ipc.oif)
|
||||
ipc.oif = inet->uc_index;
|
||||
|
||||
flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
|
||||
RT_SCOPE_UNIVERSE,
|
||||
|
@ -917,7 +917,8 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
||||
if (!saddr)
|
||||
saddr = inet->mc_addr;
|
||||
connected = 0;
|
||||
}
|
||||
} else if (!ipc.oif)
|
||||
ipc.oif = inet->uc_index;
|
||||
|
||||
if (connected)
|
||||
rt = (struct rtable *)sk_dst_check(sk, 0);
|
||||
|
Loading…
Reference in New Issue
Block a user