aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErich E. Hoover <ehoover@mines.edu>2012-02-08 04:11:08 -0500
committerDavid S. Miller <davem@davemloft.net>2012-02-08 15:52:45 -0500
commitc4062dfc425e94290ac427a98d6b4721dd2bc91f (patch)
tree30180df3e11ded7ed8ea2c3c4525092d0711f1af
parent76e21053b5bf33a07c76f99d27a74238310e3c71 (diff)
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>
-rw-r--r--include/linux/in6.h1
-rw-r--r--include/linux/ipv6.h1
-rw-r--r--net/ipv6/icmp.c4
-rw-r--r--net/ipv6/ipv6_sockglue.c34
-rw-r--r--net/ipv6/raw.c2
-rw-r--r--net/ipv6/udp.c3
6 files changed, 44 insertions, 1 deletions
diff --git a/include/linux/in6.h b/include/linux/in6.h
index 097a34b55560..5c83d9e3eb8f 100644
--- a/include/linux/in6.h
+++ b/include/linux/in6.h
@@ -271,6 +271,7 @@ struct in6_flowlabel_req {
271#define IPV6_ORIGDSTADDR 74 271#define IPV6_ORIGDSTADDR 74
272#define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR 272#define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR
273#define IPV6_TRANSPARENT 75 273#define IPV6_TRANSPARENT 75
274#define IPV6_UNICAST_IF 76
274 275
275/* 276/*
276 * Multicast Routing: 277 * Multicast Routing:
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 6318268dcaf5..743a16a41040 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -324,6 +324,7 @@ struct ipv6_pinfo {
324 __unused_2:6; 324 __unused_2:6;
325 __s16 mcast_hops:9; 325 __s16 mcast_hops:9;
326#endif 326#endif
327 int ucast_oif;
327 int mcast_oif; 328 int mcast_oif;
328 329
329 /* pktoption flags */ 330 /* pktoption flags */
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 01d46bff63c3..af88934e4d79 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -468,6 +468,8 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
468 468
469 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) 469 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
470 fl6.flowi6_oif = np->mcast_oif; 470 fl6.flowi6_oif = np->mcast_oif;
471 else if (!fl6.flowi6_oif)
472 fl6.flowi6_oif = np->ucast_oif;
471 473
472 dst = icmpv6_route_lookup(net, skb, sk, &fl6); 474 dst = icmpv6_route_lookup(net, skb, sk, &fl6);
473 if (IS_ERR(dst)) 475 if (IS_ERR(dst))
@@ -553,6 +555,8 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
553 555
554 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) 556 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
555 fl6.flowi6_oif = np->mcast_oif; 557 fl6.flowi6_oif = np->mcast_oif;
558 else if (!fl6.flowi6_oif)
559 fl6.flowi6_oif = np->ucast_oif;
556 560
557 err = ip6_dst_lookup(sk, &dst, &fl6); 561 err = ip6_dst_lookup(sk, &dst, &fl6);
558 if (err) 562 if (err)
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 18a2719003c3..6d6b65fdaa1a 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -516,6 +516,36 @@ done:
516 retv = 0; 516 retv = 0;
517 break; 517 break;
518 518
519 case IPV6_UNICAST_IF:
520 {
521 struct net_device *dev = NULL;
522 int ifindex;
523
524 if (optlen != sizeof(int))
525 goto e_inval;
526
527 ifindex = (__force int)ntohl((__force __be32)val);
528 if (ifindex == 0) {
529 np->ucast_oif = 0;
530 retv = 0;
531 break;
532 }
533
534 dev = dev_get_by_index(net, ifindex);
535 retv = -EADDRNOTAVAIL;
536 if (!dev)
537 break;
538 dev_put(dev);
539
540 retv = -EINVAL;
541 if (sk->sk_bound_dev_if)
542 break;
543
544 np->ucast_oif = ifindex;
545 retv = 0;
546 break;
547 }
548
519 case IPV6_MULTICAST_IF: 549 case IPV6_MULTICAST_IF:
520 if (sk->sk_type == SOCK_STREAM) 550 if (sk->sk_type == SOCK_STREAM)
521 break; 551 break;
@@ -1160,6 +1190,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
1160 val = np->mcast_oif; 1190 val = np->mcast_oif;
1161 break; 1191 break;
1162 1192
1193 case IPV6_UNICAST_IF:
1194 val = (__force int)htonl((__u32) np->ucast_oif);
1195 break;
1196
1163 case IPV6_MTU_DISCOVER: 1197 case IPV6_MTU_DISCOVER:
1164 val = np->pmtudisc; 1198 val = np->pmtudisc;
1165 break; 1199 break;
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index d02f7e4dd611..5bddea778840 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -856,6 +856,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
856 856
857 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) 857 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
858 fl6.flowi6_oif = np->mcast_oif; 858 fl6.flowi6_oif = np->mcast_oif;
859 else if (!fl6.flowi6_oif)
860 fl6.flowi6_oif = np->ucast_oif;
859 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); 861 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
860 862
861 dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); 863 dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 4f96b5c63685..8aebf8f90436 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1130,7 +1130,8 @@ do_udp_sendmsg:
1130 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) { 1130 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) {
1131 fl6.flowi6_oif = np->mcast_oif; 1131 fl6.flowi6_oif = np->mcast_oif;
1132 connected = 0; 1132 connected = 0;
1133 } 1133 } else if (!fl6.flowi6_oif)
1134 fl6.flowi6_oif = np->ucast_oif;
1134 1135
1135 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); 1136 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
1136 1137