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];
|