mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 14:42:24 +00:00
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_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 New Issue
Block a user