diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2013-01-13 16:23:35 +0100 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2013-01-13 16:26:51 +0100 |
commit | 2b2d7fdc42475019e5ce3eabc9c9673e3c13d89f (patch) | |
tree | e7409c870c39a10241875454e345d5ec16517738 /pfinet/linux-src/net/ipv4 | |
parent | 03be85eb11f756414aafedca22f93a3351b727b8 (diff) | |
download | hurd-2b2d7fdc42475019e5ce3eabc9c9673e3c13d89f.tar.gz hurd-2b2d7fdc42475019e5ce3eabc9c9673e3c13d89f.tar.bz2 hurd-2b2d7fdc42475019e5ce3eabc9c9673e3c13d89f.zip |
[IPV6]: Add IPV6_V6ONLY socket option support.
Cherry-picked from Linux 524354b4d086a4f013343d727eaccb7b4c39eb25
* pfinet/glue-include/linux/ipv6.h: Include linux/config.h>
(__ipv6_only_sock, ipv6_only_sock): New macros
* pfinet/linux-src/include/linux/ipv6.h: Likewise.
* pfinet/linux-src/include/linux/in6.h (IPV6_V6ONLY): New macro.
* pfinet/linux-src/include/linux/sysctl.h (NET_IPV6_BINDV6ONLY): New macro.
* pfinet/linux-src/include/net/ipv6.h (sysctl_ipv6_bindv6only): Declare
variable.
* pfinet/linux-src/include/net/sock.h (ipv6_pinfo): Add ipv6only field.
* pfinet/linux-src/net/ipv4/tcp_ipv4.c: Include linux/ipv6.h.
(tcp_v4_get_port, tcp_v4_lookup_listener): Test for ipv6_only_sock.
* pfinet/linux-src/net/ipv4/udp.c: Include linux/ipv6.h.
(udp_v4_get_port, udp_v4_lookup_longway, udp_v4_mcast_next): Test for
ipv6_only_sock.
* pfinet/linux-src/net/ipv6/af_inet6.c (sysctl_ipv6_bindv6only): New
variable.
(inet6_create): Initialize ipv6only field to sysctl_ipv6_bindv6only.
* pfinet/linux-src/net/ipv6/ipv6_sockglue.c (ipv6_setsockopt): Test for
ipv6_only_sock.
(ipv6_setsockopt, ipv6_getsockopt): Support IPV6_V6ONLY case.
* pfinet/linux-src/net/ipv6/tcp_ipv6.c (ipv6_rcv_saddr_equal): New inline
function.
(tcp_v6_get_port): Replace old tests with ipv6_rcv_saddr_equal.
(tcp_v6_connect): Test for __ipv6_only_sock.
* pfinet/linux-src/net/ipv6/udp_ipv6.c (udv6_rcv_saddr_equal): New inline
function.
(udp_v6_get_port): Replace old tests with udv6_rcv_saddr_equal.
(udpv6_connect, udpv6_sendmsg): Test for __ipv6_only_sock.
Diffstat (limited to 'pfinet/linux-src/net/ipv4')
-rw-r--r-- | pfinet/linux-src/net/ipv4/tcp_ipv4.c | 20 | ||||
-rw-r--r-- | pfinet/linux-src/net/ipv4/udp.c | 21 |
2 files changed, 27 insertions, 14 deletions
diff --git a/pfinet/linux-src/net/ipv4/tcp_ipv4.c b/pfinet/linux-src/net/ipv4/tcp_ipv4.c index 60d2bdb4..df2c8b7c 100644 --- a/pfinet/linux-src/net/ipv4/tcp_ipv4.c +++ b/pfinet/linux-src/net/ipv4/tcp_ipv4.c @@ -45,9 +45,13 @@ * Vitaly E. Lavrov : Transparent proxy revived after year coma. * Andi Kleen : Fix new listen. * Andi Kleen : Fix accept error reporting. + * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which + * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind + * a single port at the same time. */ #include <linux/config.h> + #include <linux/types.h> #include <linux/fcntl.h> #include <linux/random.h> @@ -61,6 +65,7 @@ #include <asm/segment.h> #include <linux/inet.h> +#include <linux/ipv6.h> #include <linux/stddef.h> extern int sysctl_tcp_timestamps; @@ -258,7 +263,8 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum) int sk_reuse = sk->reuse; for( ; sk2 != NULL; sk2 = sk2->bind_next) { - if (sk->bound_dev_if == sk2->bound_dev_if) { + if (!ipv6_only_sock(sk2) && + sk->bound_dev_if == sk2->bound_dev_if) { if (!sk_reuse || !sk2->reuse || sk2->state == TCP_LISTEN) { @@ -378,23 +384,23 @@ static struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum, int d struct sock *result = NULL; int score, hiscore; - hiscore=0; + hiscore=-1; for(sk = tcp_listening_hash[tcp_lhashfn(hnum)]; sk; sk = sk->next) { - if(sk->num == hnum) { + if(sk->num == hnum && !ipv6_only_sock(sk)) { __u32 rcv_saddr = sk->rcv_saddr; - score = 1; + score = (sk->family == PF_INET ? 1 : 0); if(rcv_saddr) { if (rcv_saddr != daddr) continue; - score++; + score+=2; } if (sk->bound_dev_if) { if (sk->bound_dev_if != dif) continue; - score++; + score+=2; } - if (score == 3) + if (score == 5) return sk; if (score > hiscore) { hiscore = score; diff --git a/pfinet/linux-src/net/ipv4/udp.c b/pfinet/linux-src/net/ipv4/udp.c index 1ceb43e4..f9be2e04 100644 --- a/pfinet/linux-src/net/ipv4/udp.c +++ b/pfinet/linux-src/net/ipv4/udp.c @@ -61,6 +61,9 @@ * return ENOTCONN for unconnected sockets (POSIX) * Janos Farkas : don't deliver multi/broadcasts to a different * bound-to-device socket + * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which + * Alexey Kuznetsov: allow both IPv4 and IPv6 sockets to bind + * a single port at the same time. * * * This program is free software; you can redistribute it and/or @@ -104,6 +107,7 @@ #include <linux/mm.h> #include <linux/config.h> #include <linux/inet.h> +#include <linux/ipv6.h> #include <linux/netdevice.h> #include <net/snmp.h> #include <net/ip.h> @@ -178,6 +182,7 @@ gotit: sk2 = sk2->next) { if (sk2->num == snum && sk2 != sk && + !ipv6_only_sock(sk2) && sk2->bound_dev_if == sk->bound_dev_if && (!sk2->rcv_saddr || !sk->rcv_saddr || @@ -236,29 +241,30 @@ struct sock *udp_v4_lookup_longway(u32 saddr, u16 sport, u32 daddr, u16 dport, i int badness = -1; for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) { - if((sk->num == hnum) && !(sk->dead && (sk->state == TCP_CLOSE))) { - int score = 0; + if((sk->num == hnum) && !ipv6_only_sock(sk) + && !(sk->dead && (sk->state == TCP_CLOSE))) { + int score = (sk->family == PF_INET ? 1 : 0); if(sk->rcv_saddr) { if(sk->rcv_saddr != daddr) continue; - score++; + score+=2; } if(sk->daddr) { if(sk->daddr != saddr) continue; - score++; + score+=2; } if(sk->dport) { if(sk->dport != sport) continue; - score++; + score+=2; } if(sk->bound_dev_if) { if(sk->bound_dev_if != dif) continue; - score++; + score+=2; } - if(score == 4) { + if(score == 9) { result = sk; break; } else if(score > badness) { @@ -389,6 +395,7 @@ static inline struct sock *udp_v4_mcast_next(struct sock *sk, (s->daddr && s->daddr!=raddr) || (s->dport != rnum && s->dport != 0) || (s->rcv_saddr && s->rcv_saddr != laddr) || + ipv6_only_sock(s) || (s->bound_dev_if && s->bound_dev_if != dif)) continue; break; |