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:
committed by
David S. Miller
parent
43480aecb1
commit
76e21053b5
@@ -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;
|
||||
|
Reference in New Issue
Block a user