netdev
[Top] [All Lists]

[PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 an

To: kuznet@xxxxxxxxxxxxx
Subject: [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port)
From: YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@xxxxxxxxxxxxxx>
Date: Wed, 23 Oct 2002 16:24:39 +0900 (JST)
Cc: davem@xxxxxxxxxx, netdev@xxxxxxxxxxx, usagi@xxxxxxxxxxxxxx
In-reply-to: <200210031552.TAA29921@sex.inr.ac.ru>
Organization: USAGI Project
References: <20021004.001929.03389091.yoshfuji@linux-ipv6.org> <200210031552.TAA29921@sex.inr.ac.ru>
Sender: netdev-bounce@xxxxxxxxxxx
In article <200210031552.TAA29921@xxxxxxxxxxxxx> (at Thu, 3 Oct 2002 19:52:40 
+0400 (MSD)), kuznet@xxxxxxxxxxxxx says:

> Actually, it would be great if you said what is wrong in that my patch?
> It looks so simple that I am not ready to agree that real one should be
> so complicated. :-)

Well, I've refered alexey's patch and simplified many if-clauses.
Here's the new patch and test results.  seems ok.

--------------------
Linux IPv6 stack provides the ability for IPv6 applications to
interoperate with IPv4 applications.  Port space for TCP (or UDP) is
shared by IPv6 and IPv4.  This conforms to RFC2553.
However, some kind of applications may want to restrict their use of
an IPv6 socket to IPv6 communication only.  IPV6_V6ONLY socket option is
defined for such applications in RFC2553bis, which is successor of RFC2553.  
This patch allows to bind both IPv6 and IPv4 sockets with the single
port number at the same time if IPV6_V6ONLY socket options is set to
the IPv6 socket.

Packet delivery strategy is similar to one before, but we prefer
IPv4 a bit.

Test results and patch against 2.4.20-pre11 follows.

*** Test for bind(2) ***

[SOCK_DGRAM w/o IPV6_V6ONLY]
        0       ::      127.1   ::1
0       x       x       x       x
::      x       x       x       x
127.1   x       x       x       o
::1     x       x       o       x

==> OK

[SOCK_DGRAM w/ IPV6_V6ONLY]
        0       ::      127.1   ::1
0       x       o       x       o
::      o       x       o       x
127.1   x       o       x       o
::1     o       x       o       x

==> OK

[SOCK_DGRAM w/ SO_REUSEADDR w/o IPV6_V6ONLY]
        0       ::      127.1   ::1
0       o       o       o       o
::      o       o       o       o
127.1   o       o       o       o
::1     o       o       o       o

==> OK

[SOCK_DGRAM w/ SO_REUSEADDR w IPV6_V6ONLY]
        0       ::      127.1   ::1
0       o       o       o       o
::      o       o       o       o
127.1   o       o       o       o
::1     o       o       o       o

==> OK

[SOCK_STREAM w/o IPV6_V6ONLY]
        0       ::      127.1   ::1
0       x       x       x       x
::      x       x       x       x
127.1   x       x       x       o
::1     x       x       o       x

==> OK

[SOCK_STREAM w/ IPV6_V6ONLY]
        0       ::      127.1   ::1
0       x       o       x       o
::      o       x       o       x
127.1   x       o       x       o
::1     o       x       o       x

==> OK

[SOCK_STREAM w/ SO_REUSEADDR w/o IPV6_V6ONLY]
        0       ::      127.1   ::1
0       o       o       o       o
::      o       o       o       o
127.1   o       o       o       o
::1     o       o       o       o

==> OK

[SOCK_STREAM w/ SO_REUSEADDR w IPV6_V6ONLY]
        0       ::      127.1   ::1
0       o       o       o       o
::      o       o       o       o
127.1   o       o       o       o
::1     o       o       o       o

==> OK

*** Test for Receiver ***

[IPv6]
1a. :: <- ::1
        received from ::1

1b. :: w/IPV6_V6ONLY <- ::1
        received from ::1

2a. :: <- 127.0.0.1
        received from ::1

2b. :: w/IPV6_V6ONLY <- 127.0.0.1
        none received

3a. :: <- ff02::1
        received from fe80::EUI64

3b. :: w/IPV6_V6ONLY <- ff02::1
        received from fe80::EUI64

4a. :: <- 224.0.0.1
        received from ::ffff:ipv4addr

4b. :: w/IPV6_V6ONLY <- 224.0.0.1
        none received

==> OK

[IPv4]
1. 0.0.0.0 <- ::1
        none received

2. 0.0.0.0 <- 127.0.0.1
        received from 127.0.0.1

3. 0.0.0.0 <- ff02::1
        none received

4. 0.0.0.0 <- 224.0.0.1
        received from ipv4addr

==> OK

[IPv6 vs IPv4]
5. :: w/IPV6_V6ONLY vs 0.0.0.0 <- ::1
        ipv6 received from ::1

6. :: w/IPV6_V6ONLY vs 0.0.0.0 <- 127.0.0.1
        ipv4 received from 127.0.0.1

7. :: w/IPV6_V6ONLY vs 0.0.0.0 <- ff02::1
        ipv6 received from fe80::EUI64

8. :: w/IPV6_V6ONLY vs 0.0.0.0 <- 224.0.0.1
        ipv4 received from ipv4addra

==> OK

-------------------------------------------------------------------
Patch-Name: Allow Both IPv6 and IPv4 Sockets on the Same Port Number 
(IPV6_V6ONLY Support) - Rev.2
Patch-Id: FIX_2_4_20_pre11_DOUBLEBIND-20021023
Patch-Author: YOSHIFUJI Hideaki / USAGI Project <yoshfuji@xxxxxxxxxxxxxx>
Credit: YOSHIFUJI Hideaki / USAGI Project <yoshfuji@xxxxxxxxxxxxxx>
Reference: RFC2553bis
-------------------------------------------------------------------
Index: Documentation/networking/ip-sysctl.txt
===================================================================
RCS file: 
/cvsroot/usagi/usagi-backport/linux24/Documentation/networking/ip-sysctl.txt,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.42.1
diff -u -r1.1.1.1 -r1.1.1.1.42.1
--- Documentation/networking/ip-sysctl.txt      20 Aug 2002 09:48:10 -0000      
1.1.1.1
+++ Documentation/networking/ip-sysctl.txt      22 Oct 2002 19:19:48 -0000      
1.1.1.1.42.1
@@ -462,6 +462,15 @@
 IPv6 has no global variables such as tcp_*.  tcp_* settings under ipv4/ also
 apply to IPv6 [XXX?].
 
+bindv6only - BOOLEAN
+       Default value for IPV6_V6ONLY socket option,
+       which restricts use of the IPv6 socket to IPv6 communication 
+       only.
+               TRUE: disable IPv4-mapped address feature
+               FALSE: enable IPv4-mapped address feature
+
+       Default: FALSE (as specified in RFC2553bis)
+
 conf/default/*:
        Change the interface-specific default settings.
 
Index: include/linux/in6.h
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/include/linux/in6.h,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.40.1
diff -u -r1.1.1.1 -r1.1.1.1.40.1
--- include/linux/in6.h 20 Aug 2002 09:46:34 -0000      1.1.1.1
+++ include/linux/in6.h 22 Oct 2002 19:19:48 -0000      1.1.1.1.40.1
@@ -156,6 +156,7 @@
 #define IPV6_MTU_DISCOVER      23
 #define IPV6_MTU               24
 #define IPV6_RECVERR           25
+#define IPV6_V6ONLY            26
 
 /* IPV6_MTU_DISCOVER values */
 #define IPV6_PMTUDISC_DONT             0
Index: include/linux/sysctl.h
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/include/linux/sysctl.h,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.16.1
diff -u -r1.1.1.2 -r1.1.1.2.16.1
--- include/linux/sysctl.h      9 Oct 2002 01:35:37 -0000       1.1.1.2
+++ include/linux/sysctl.h      22 Oct 2002 19:19:48 -0000      1.1.1.2.16.1
@@ -345,7 +345,8 @@
 enum {
        NET_IPV6_CONF=16,
        NET_IPV6_NEIGH=17,
-       NET_IPV6_ROUTE=18
+       NET_IPV6_ROUTE=18,
+       NET_IPV6_BINDV6ONLY=20,
 };
 
 enum {
Index: include/net/ipv6.h
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/include/net/ipv6.h,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.38.1
diff -u -r1.1.1.1 -r1.1.1.1.38.1
--- include/net/ipv6.h  20 Aug 2002 09:46:45 -0000      1.1.1.1
+++ include/net/ipv6.h  22 Oct 2002 19:19:48 -0000      1.1.1.1.38.1
@@ -88,6 +88,9 @@
 
 #include <net/sock.h>
 
+/* sysctls */
+extern int sysctl_ipv6_bindv6only;
+
 extern struct ipv6_mib         ipv6_statistics[NR_CPUS*2];
 #define IP6_INC_STATS(field)           SNMP_INC_STATS(ipv6_statistics, field)
 #define IP6_INC_STATS_BH(field)                
SNMP_INC_STATS_BH(ipv6_statistics, field)
Index: include/net/sock.h
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/include/net/sock.h,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.40.1
diff -u -r1.1.1.1 -r1.1.1.1.40.1
--- include/net/sock.h  20 Aug 2002 09:46:45 -0000      1.1.1.1
+++ include/net/sock.h  22 Oct 2002 19:19:48 -0000      1.1.1.1.40.1
@@ -171,7 +171,8 @@
        __u8                    mc_loop:1,
                                recverr:1,
                                sndflow:1,
-                               pmtudisc:2;
+                               pmtudisc:2,
+                               ipv6only:1;
 
        struct ipv6_mc_socklist *ipv6_mc_list;
        struct ipv6_fl_socklist *ipv6_fl_list;
@@ -188,6 +189,12 @@
        struct icmp6_filter     filter;
 };
 
+#define __ipv6_only_sock(sk)   ((sk)->net_pinfo.af_inet6.ipv6only)
+#define ipv6_only_sock(sk)     ((sk)->family == PF_INET6 && \
+                                (sk)->net_pinfo.af_inet6.ipv6only)
+#else
+#define __ipv6_only_sock(sk)   0
+#define ipv6_only_sock(sk)     0
 #endif /* IPV6 */
 
 #if defined(CONFIG_INET) || defined(CONFIG_INET_MODULE)
Index: net/ipv4/tcp_ipv4.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv4/tcp_ipv4.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.16.2
diff -u -r1.1.1.2 -r1.1.1.2.16.2
--- net/ipv4/tcp_ipv4.c 9 Oct 2002 01:35:52 -0000       1.1.1.2
+++ net/ipv4/tcp_ipv4.c 22 Oct 2002 19:40:48 -0000      1.1.1.2.16.2
@@ -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:       Support IPV6_V6ONLY socket option, which
+ *                                     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>
@@ -182,6 +186,7 @@
        for( ; sk2 != NULL; sk2 = sk2->bind_next) {
                if (sk != sk2 &&
                    sk2->reuse <= 1 &&
+                   !ipv6_only_sock(sk2) &&
                    sk->bound_dev_if == sk2->bound_dev_if) {
                        if (!sk_reuse   ||
                            !sk2->reuse ||
@@ -418,23 +423,27 @@
        struct sock *result = NULL;
        int score, hiscore;
 
-       hiscore=0;
+       hiscore=-1;
        for(; sk; sk = sk->next) {
-               if(sk->num == hnum) {
+               if(sk->num == hnum && !ipv6_only_sock(sk)) {
                        __u32 rcv_saddr = sk->rcv_saddr;
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+                       score = sk->family == PF_INET ? 1 : 0;
+#else
                        score = 1;
+#endif
                        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;
@@ -456,6 +465,7 @@
                if (sk->num == hnum &&
                    sk->next == NULL &&
                    (!sk->rcv_saddr || sk->rcv_saddr == daddr) &&
+                   (sk->family == PF_INET || !ipv6_only_sock(sk)) &&
                    !sk->bound_dev_if)
                        goto sherry_cache;
                sk = __tcp_v4_lookup_listener(sk, daddr, hnum, dif);
Index: net/ipv4/udp.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv4/udp.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.40.1
diff -u -r1.1.1.1 -r1.1.1.1.40.1
--- net/ipv4/udp.c      20 Aug 2002 09:47:02 -0000      1.1.1.1
+++ net/ipv4/udp.c      22 Oct 2002 19:19:48 -0000      1.1.1.1.40.1
@@ -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:       Support IPV6_V6ONLY socket option, which
+ *                                     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
@@ -85,6 +88,7 @@
 #include <linux/netdevice.h>
 #include <net/snmp.h>
 #include <net/ip.h>
+#include <net/ipv6.h>
 #include <net/protocol.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
@@ -159,6 +163,7 @@
                     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 ||
@@ -215,29 +220,34 @@
        int badness = -1;
 
        for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = 
sk->next) {
-               if(sk->num == hnum) {
-                       int score = 0;
+               if(sk->num == hnum && !ipv6_only_sock(sk)) {
+                       int score;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+                       score = sk->family == PF_INET ? 1 : 0;
+#else
+                       score = 1;
+#endif
                        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) {
@@ -273,6 +283,7 @@
                    (s->daddr && s->daddr!=rmt_addr)                    ||
                    (s->dport != rmt_port && s->dport != 0)                     
||
                    (s->rcv_saddr  && s->rcv_saddr != loc_addr)         ||
+                   ipv6_only_sock(s)                                   ||
                    (s->bound_dev_if && s->bound_dev_if != dif))
                        continue;
                break;
Index: net/ipv6/af_inet6.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv6/af_inet6.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.36.1
diff -u -r1.1.1.1 -r1.1.1.1.36.1
--- net/ipv6/af_inet6.c 20 Aug 2002 09:47:02 -0000      1.1.1.1
+++ net/ipv6/af_inet6.c 22 Oct 2002 19:19:48 -0000      1.1.1.1.36.1
@@ -88,6 +88,8 @@
 extern void ipv6_sysctl_unregister(void);
 #endif
 
+int sysctl_ipv6_bindv6only;
+
 #ifdef INET_REFCNT_DEBUG
 atomic_t inet6_sock_nr;
 #endif
@@ -173,6 +175,8 @@
        sk->net_pinfo.af_inet6.mc_loop    = 1;
        sk->net_pinfo.af_inet6.pmtudisc   = IPV6_PMTUDISC_WANT;
 
+       sk->net_pinfo.af_inet6.ipv6only = sysctl_ipv6_bindv6only;
+       
        /* Init the ipv4 part of the socket since we can have sockets
         * using v6 API for ipv4.
         */
Index: net/ipv6/ipv6_sockglue.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv6/ipv6_sockglue.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.36.1
diff -u -r1.1.1.1 -r1.1.1.1.36.1
--- net/ipv6/ipv6_sockglue.c    20 Aug 2002 09:47:02 -0000      1.1.1.1
+++ net/ipv6/ipv6_sockglue.c    22 Oct 2002 19:19:48 -0000      1.1.1.1.36.1
@@ -157,7 +157,8 @@
                                break;
                        }
 
-                       if (!(ipv6_addr_type(&np->daddr) & IPV6_ADDR_MAPPED)) {
+                       if (ipv6_only_sock(sk) ||
+                           !(ipv6_addr_type(&np->daddr) & IPV6_ADDR_MAPPED)) {
                                retv = -EADDRNOTAVAIL;
                                break;
                        }
@@ -203,6 +204,13 @@
                }
                goto e_inval;
 
+       case IPV6_V6ONLY:
+               if (sk->num)
+                       goto e_inval;
+               np->ipv6only = valbool;
+               retv = 0;
+               break;
+
        case IPV6_PKTINFO:
                np->rxopt.bits.rxinfo = valbool;
                retv = 0;
@@ -465,6 +473,10 @@
                        return -ENOTCONN;
                break;
        }
+
+       case IPV6_V6ONLY:
+               val = np->ipv6only;
+               break;
 
        case IPV6_PKTINFO:
                val = np->rxopt.bits.rxinfo;
Index: net/ipv6/sysctl_net_ipv6.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv6/sysctl_net_ipv6.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.40.1
diff -u -r1.1.1.1 -r1.1.1.1.40.1
--- net/ipv6/sysctl_net_ipv6.c  20 Aug 2002 09:47:02 -0000      1.1.1.1
+++ net/ipv6/sysctl_net_ipv6.c  22 Oct 2002 19:19:48 -0000      1.1.1.1.40.1
@@ -17,6 +17,8 @@
 
 ctl_table ipv6_table[] = {
        {NET_IPV6_ROUTE, "route", NULL, 0, 0555, ipv6_route_table},
+       {NET_IPV6_BINDV6ONLY, "bindv6only",
+        &sysctl_ipv6_bindv6only, sizeof(int), 0644, NULL, &proc_dointvec},
        {0}
 };
 
Index: net/ipv6/tcp_ipv6.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv6/tcp_ipv6.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.16.1
diff -u -r1.1.1.2 -r1.1.1.2.16.1
--- net/ipv6/tcp_ipv6.c 9 Oct 2002 01:35:53 -0000       1.1.1.2
+++ net/ipv6/tcp_ipv6.c 22 Oct 2002 19:19:48 -0000      1.1.1.2.16.1
@@ -14,6 +14,9 @@
  *
  *     Fixes:
  *     Hideaki YOSHIFUJI       :       sin6_scope_id support
+ *     YOSHIFUJI Hideaki @USAGI:       Support IPV6_V6ONLY socket option, which
+ *                                     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
  *      modify it under the terms of the GNU General Public License
@@ -148,14 +151,23 @@
                                            !sk2->reuse ||
                                            sk2->state == TCP_LISTEN) {
                                                /* NOTE: IPv6 tw bucket have 
different format */
-                                               if (!sk2->rcv_saddr     ||
-                                                   addr_type == IPV6_ADDR_ANY 
||
-                                                   
!ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
-                                                                  sk2->state 
!= TCP_TIME_WAIT ?
-                                                                  
&sk2->net_pinfo.af_inet6.rcv_saddr :
-                                                                  &((struct 
tcp_tw_bucket*)sk)->v6_rcv_saddr) ||
-                                                   
(addr_type==IPV6_ADDR_MAPPED && sk2->family==AF_INET &&
-                                                    
sk->rcv_saddr==sk2->rcv_saddr))
+                                               if ((!sk2->rcv_saddr && 
!ipv6_only_sock(sk)) ||
+                                                   (sk2->family == AF_INET6 &&
+                                                    
ipv6_addr_any(&sk2->net_pinfo.af_inet6.rcv_saddr) &&
+                                                    !(ipv6_only_sock(sk2) && 
addr_type == IPV6_ADDR_MAPPED)) ||
+                                                   (addr_type == IPV6_ADDR_ANY 
&&
+                                                    (!ipv6_only_sock(sk) ||
+                                                     !(sk2->family == AF_INET6 
? ipv6_addr_type(&sk2->net_pinfo.af_inet6.rcv_saddr) == IPV6_ADDR_MAPPED : 1))) 
||
+                                                   (sk2->family == AF_INET6 &&
+                                                    
!ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
+                                                                   sk2->state 
!= TCP_TIME_WAIT ?
+                                                                   
&sk2->net_pinfo.af_inet6.rcv_saddr :
+                                                                   &((struct 
tcp_tw_bucket*)sk)->v6_rcv_saddr)) ||
+                                                   (addr_type == 
IPV6_ADDR_MAPPED && 
+                                                    !ipv6_only_sock(sk2) &&
+                                                    (!sk2->rcv_saddr ||
+                                                     !sk->rcv_saddr ||
+                                                     sk->rcv_saddr == 
sk2->rcv_saddr)))
                                                        break;
                                        }
                                }
@@ -601,6 +613,9 @@
                struct sockaddr_in sin;
 
                SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
+
+               if (__ipv6_only_sock(sk))
+                       return -ENETUNREACH;
 
                sin.sin_family = AF_INET;
                sin.sin_port = usin->sin6_port;
Index: net/ipv6/udp.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv6/udp.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.16.1
diff -u -r1.1.1.2 -r1.1.1.2.16.1
--- net/ipv6/udp.c      9 Oct 2002 01:35:53 -0000       1.1.1.2
+++ net/ipv6/udp.c      22 Oct 2002 19:19:48 -0000      1.1.1.2.16.1
@@ -11,6 +11,9 @@
  *
  *     Fixes:
  *     Hideaki YOSHIFUJI       :       sin6_scope_id support
+ *     YOSHIFUJI Hideaki @USAGI:       Support IPV6_V6ONLY socket option, which
+ *                                     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
  *      modify it under the terms of the GNU General Public License
@@ -106,13 +109,21 @@
                        if (sk2->num == snum &&
                            sk2 != sk &&
                            sk2->bound_dev_if == sk->bound_dev_if &&
-                           (!sk2->rcv_saddr ||
-                            addr_type == IPV6_ADDR_ANY ||
-                            !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
-                                           &sk2->net_pinfo.af_inet6.rcv_saddr) 
||
+                           ((!sk2->rcv_saddr && !ipv6_only_sock(sk)) ||
+                            (sk2->family == AF_INET6 && 
+                             ipv6_addr_any(&sk2->net_pinfo.af_inet6.rcv_saddr) 
&&
+                             !(ipv6_only_sock(sk2) && addr_type == 
IPV6_ADDR_MAPPED)) ||
+                            (addr_type == IPV6_ADDR_ANY && 
+                             (!ipv6_only_sock(sk) || 
+                              !(sk2->family == AF_INET6 ? 
(ipv6_addr_type(&sk2->net_pinfo.af_inet6.rcv_saddr) == IPV6_ADDR_MAPPED) : 1))) 
||
+                            (sk2->family == AF_INET6 && 
+                             !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
+                                            
&sk2->net_pinfo.af_inet6.rcv_saddr)) ||
                             (addr_type == IPV6_ADDR_MAPPED &&
-                             sk2->family == AF_INET &&
-                             sk->rcv_saddr == sk2->rcv_saddr)) &&
+                             !ipv6_only_sock(sk2) &&
+                             (!sk2->rcv_saddr || 
+                              !sk->rcv_saddr ||
+                              sk->rcv_saddr == sk2->rcv_saddr))) &&
                            (!sk2->reuse || !sk->reuse))
                                goto fail;
                }
@@ -221,6 +232,8 @@
        int                     err;
 
        if (usin->sin6_family == AF_INET) {
+               if (__ipv6_only_sock(sk))
+                       return -EAFNOSUPPORT;
                err = udp_connect(sk, uaddr, addr_len);
                goto ipv4_connected;
        }
@@ -256,6 +269,9 @@
        if (addr_type == IPV6_ADDR_MAPPED) {
                struct sockaddr_in sin;
 
+               if (__ipv6_only_sock(sk))
+                       return -ENETUNREACH;
+
                sin.sin_family = AF_INET;
                sin.sin_addr.s_addr = daddr->s6_addr32[3];
                sin.sin_port = usin->sin6_port;
@@ -783,8 +799,11 @@
        fl.oif = 0;
 
        if (sin6) {
-               if (sin6->sin6_family == AF_INET)
+               if (sin6->sin6_family == AF_INET) {
+                       if (__ipv6_only_sock(sk))
+                               return -ENETUNREACH;
                        return udp_sendmsg(sk, msg, ulen);
+               }
 
                if (addr_len < SIN6_LEN_RFC2133)
                        return -EINVAL;
@@ -830,6 +849,9 @@
 
        if (addr_type == IPV6_ADDR_MAPPED) {
                struct sockaddr_in sin;
+
+               if (__ipv6_only_sock(sk))
+                       return -ENETUNREACH;
 
                sin.sin_family = AF_INET;
                sin.sin_addr.s_addr = daddr->s6_addr32[3];


<Prev in Thread] Current Thread [Next in Thread>