ipv6: Implement IPV6_UNICAST_IF socket option.

The IPV6_UNICAST_IF feature is the IPv6 compliment to IP_UNICAST_IF.

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:
Erich E. Hoover 2012-02-08 09:11:08 +00:00 committed by David S. Miller
parent 76e21053b5
commit c4062dfc42
6 changed files with 44 additions and 1 deletions

View File

@ -271,6 +271,7 @@ struct in6_flowlabel_req {
#define IPV6_ORIGDSTADDR 74 #define IPV6_ORIGDSTADDR 74
#define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR #define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR
#define IPV6_TRANSPARENT 75 #define IPV6_TRANSPARENT 75
#define IPV6_UNICAST_IF 76
/* /*
* Multicast Routing: * Multicast Routing:

View File

@ -324,6 +324,7 @@ struct ipv6_pinfo {
__unused_2:6; __unused_2:6;
__s16 mcast_hops:9; __s16 mcast_hops:9;
#endif #endif
int ucast_oif;
int mcast_oif; int mcast_oif;
/* pktoption flags */ /* pktoption flags */

View File

@ -468,6 +468,8 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
fl6.flowi6_oif = np->mcast_oif; fl6.flowi6_oif = np->mcast_oif;
else if (!fl6.flowi6_oif)
fl6.flowi6_oif = np->ucast_oif;
dst = icmpv6_route_lookup(net, skb, sk, &fl6); dst = icmpv6_route_lookup(net, skb, sk, &fl6);
if (IS_ERR(dst)) if (IS_ERR(dst))
@ -553,6 +555,8 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
fl6.flowi6_oif = np->mcast_oif; fl6.flowi6_oif = np->mcast_oif;
else if (!fl6.flowi6_oif)
fl6.flowi6_oif = np->ucast_oif;
err = ip6_dst_lookup(sk, &dst, &fl6); err = ip6_dst_lookup(sk, &dst, &fl6);
if (err) if (err)

View File

@ -516,6 +516,36 @@ done:
retv = 0; retv = 0;
break; break;
case IPV6_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) {
np->ucast_oif = 0;
retv = 0;
break;
}
dev = dev_get_by_index(net, ifindex);
retv = -EADDRNOTAVAIL;
if (!dev)
break;
dev_put(dev);
retv = -EINVAL;
if (sk->sk_bound_dev_if)
break;
np->ucast_oif = ifindex;
retv = 0;
break;
}
case IPV6_MULTICAST_IF: case IPV6_MULTICAST_IF:
if (sk->sk_type == SOCK_STREAM) if (sk->sk_type == SOCK_STREAM)
break; break;
@ -1160,6 +1190,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
val = np->mcast_oif; val = np->mcast_oif;
break; break;
case IPV6_UNICAST_IF:
val = (__force int)htonl((__u32) np->ucast_oif);
break;
case IPV6_MTU_DISCOVER: case IPV6_MTU_DISCOVER:
val = np->pmtudisc; val = np->pmtudisc;
break; break;

View File

@ -856,6 +856,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
fl6.flowi6_oif = np->mcast_oif; fl6.flowi6_oif = np->mcast_oif;
else if (!fl6.flowi6_oif)
fl6.flowi6_oif = np->ucast_oif;
security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true);

View File

@ -1130,7 +1130,8 @@ do_udp_sendmsg:
if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) { if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) {
fl6.flowi6_oif = np->mcast_oif; fl6.flowi6_oif = np->mcast_oif;
connected = 0; connected = 0;
} } else if (!fl6.flowi6_oif)
fl6.flowi6_oif = np->ucast_oif;
security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));