All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port Number (IPV6_V6ONLY Support)
@ 2002-10-03  3:13 YOSHIFUJI Hideaki / 吉藤英明
  2002-10-03  3:53 ` acme
                   ` (4 more replies)
  0 siblings, 5 replies; 33+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2002-10-03  3:13 UTC (permalink / raw)
  To: linux-kernel, netdev; +Cc: usagi

Hello!

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.

We also prohibit a completely duplicate set of (local-addr, local-port,
remote-addr, remote-port) set even if SO_REUSEADDR is set unless
the local address is a multicast address; it is ambiguous and it may 
steal packets from others; i.e. a kind of DoS.

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

Following patch is against linux-2.4.19.

Thank you in advance.

-------------------------------------------------------------------
Patch-Name: Allow Both IPv6 and IPv4 Sockets on the Same Port Number (IPV6_V6ONLY Support)
Patch-Id: FIX_2_4_19_DOUBLEBIND-20020909
Patch-Author: YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
Credit: YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
Reference: RFC2553bis
-------------------------------------------------------------------
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.8.1
diff -u -r1.1.1.1 -r1.1.1.1.8.1
--- include/linux/in6.h	2002/08/20 09:46:34	1.1.1.1
+++ include/linux/in6.h	2002/09/11 03:30:27	1.1.1.1.8.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
@@ -167,4 +168,19 @@
 #define IPV6_FLOWINFO_SEND	33
 
 
+#ifdef __KERNEL__
+#ifndef IN6_IS_ADDR_UNSPECIFIED
+#define IN6_IS_ADDR_UNSPECIFIED(a)			\
+	((((a)->s6_addr32[0]) == 0) &&			\
+	 (((a)->s6_addr32[1]) == 0) &&			\
+	 (((a)->s6_addr32[2]) == 0) &&			\
+	 (((a)->s6_addr32[3]) == 0))
+#endif
+#ifndef IN6_IS_ADDR_V4MAPPED
+#define IN6_IS_ADDR_V4MAPPED(a)				\
+	((((a)->s6_addr32[0]) == 0) &&			\
+	 (((a)->s6_addr32[1]) == 0) &&			\
+	 (((a)->s6_addr32[2]) == __constant_htonl(0x0000ffff)))
+#endif
+#endif
 #endif
Index: include/linux/sysctl.h
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/include/linux/sysctl.h,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.8.1
diff -u -r1.1.1.1 -r1.1.1.1.8.1
--- include/linux/sysctl.h	2002/08/20 09:46:34	1.1.1.1
+++ include/linux/sysctl.h	2002/09/11 03:30:27	1.1.1.1.8.1
@@ -369,7 +369,8 @@
 	NET_IPV6_DAD_TRANSMITS=7,
 	NET_IPV6_RTR_SOLICITS=8,
 	NET_IPV6_RTR_SOLICIT_INTERVAL=9,
-	NET_IPV6_RTR_SOLICIT_DELAY=10
+	NET_IPV6_RTR_SOLICIT_DELAY=10,
+	NET_IPV6_BINDV6ONLY=11
 };
 
 /* /proc/sys/net/<protocol>/neigh/<dev> */
Index: include/net/if_inet6.h
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/include/net/if_inet6.h,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.8.1
diff -u -r1.1.1.1 -r1.1.1.1.8.1
--- include/net/if_inet6.h	2002/08/20 09:46:45	1.1.1.1
+++ include/net/if_inet6.h	2002/09/11 03:30:27	1.1.1.1.8.1
@@ -86,6 +86,7 @@
 	int		rtr_solicits;
 	int		rtr_solicit_interval;
 	int		rtr_solicit_delay;
+	int		bindv6only;
 
 	void		*sysctl;
 };
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.8.1
diff -u -r1.1.1.1 -r1.1.1.1.8.1
--- include/net/sock.h	2002/08/20 09:46:45	1.1.1.1
+++ include/net/sock.h	2002/09/11 03:30:27	1.1.1.1.8.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;
Index: net/ipv4/tcp_ipv4.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv4/tcp_ipv4.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.8.1
diff -u -r1.1.1.1 -r1.1.1.1.8.1
--- net/ipv4/tcp_ipv4.c	2002/08/20 09:47:02	1.1.1.1
+++ net/ipv4/tcp_ipv4.c	2002/09/11 03:30:27	1.1.1.1.8.1
@@ -45,6 +45,14 @@
  *	Vitaly E. Lavrov	:	Transparent proxy revived after year coma.
  *	Andi Kleen		:	Fix new listen.
  *	Andi Kleen		:	Fix accept error reporting.
+ *	YOSHIFUJI Hideaki @USAGI:	Reworked bind(2) behavior including:
+ *					- Allow ipv6 and ipv4 bind(2) to the
+ *					  same port if IPV6_V6ONLY socket option
+ *					  is set.
+ *					- Don't allow binding to the same
+ *					  address unless it is one of multi-
+ *					  cast address even if SO_REUSEADDR 
+ *					  is set.
  */
 
 #include <linux/config.h>
@@ -177,23 +185,92 @@
 static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb)
 {
 	struct sock *sk2 = tb->owners;
-	int sk_reuse = sk->reuse;
+	int sk_reuse, sk2_reuse;
+	int addr_type2;
+	int ret;
+
+	sk_reuse = 0;
+	if (sk->reuse)
+		sk_reuse |= 1;
 	
 	for( ; sk2 != NULL; sk2 = sk2->bind_next) {
-		if (sk != sk2 &&
-		    sk2->reuse <= 1 &&
-		    sk->bound_dev_if == sk2->bound_dev_if) {
-			if (!sk_reuse	||
-			    !sk2->reuse	||
-			    sk2->state == TCP_LISTEN) {
-				if (!sk2->rcv_saddr	||
-				    !sk->rcv_saddr	||
-				    (sk2->rcv_saddr == sk->rcv_saddr))
-					break;
+		int both_specified = 0;
+
+		if (sk2 == sk ||
+		    (sk2->bound_dev_if && sk->bound_dev_if &&
+		     sk2->bound_dev_if != sk->bound_dev_if))
+			continue;
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		if (sk2->family == AF_INET6) {
+			struct in6_addr *sk2_rcv_saddr6 = sk2->state != TCP_TIME_WAIT ?
+				&sk2->net_pinfo.af_inet6.rcv_saddr :
+				&((struct tcp_tw_bucket*)sk2)->v6_rcv_saddr;
+			if (IN6_IS_ADDR_UNSPECIFIED(sk2_rcv_saddr6))
+				addr_type2 = IPV6_ADDR_ANY;
+			else if (IN6_IS_ADDR_V4MAPPED(sk2_rcv_saddr6))
+				addr_type2 = IPV6_ADDR_MAPPED;
+			else
+				addr_type2 = IPV6_ADDR_UNICAST;	/*XXX*/
+		} else
+			addr_type2 = IPV6_ADDR_MAPPED;
+#else
+		addr_type2 = IPV6_ADDR_MAPPED;
+#endif
+		if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) &&
+		    sk->rcv_saddr) {
+			if (sk2->rcv_saddr != sk->rcv_saddr)
+				continue;
+			both_specified = 1;
+		}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		if (addr_type2 != IPV6_ADDR_MAPPED && sk2->net_pinfo.af_inet6.ipv6only) {
+			continue;
+		}
+#endif
+
+		sk2_reuse = 0;
+		if (sk2->reuse)
+			sk2_reuse |= 1;
+
+		if (sk2_reuse & sk_reuse & 3) {	/* NOT && */
+			ret = 1;
+			if (both_specified) {
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+				struct in6_addr *sk2_daddr6 = sk2->state != TCP_TIME_WAIT ?
+								&sk2->net_pinfo.af_inet6.daddr :
+								&((struct tcp_tw_bucket*)sk2)->v6_daddr;
+#endif
+				int addr_type2d;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+				if (sk2->family == AF_INET6) {
+					if (IN6_IS_ADDR_UNSPECIFIED(sk2_daddr6))
+						addr_type2d = IPV6_ADDR_ANY;
+					else if (IN6_IS_ADDR_V4MAPPED(sk2_daddr6))
+						addr_type2d = IPV6_ADDR_MAPPED;
+					else
+						addr_type2d = IPV6_ADDR_UNICAST; /*XXX*/
+				} else
+					addr_type2d = IPV6_ADDR_MAPPED;
+#else
+				addr_type2d = IPV6_ADDR_MAPPED;
+#endif
+				if (addr_type2d != IPV6_ADDR_MAPPED ? addr_type2d != IPV6_ADDR_ANY : sk2->daddr)
+					continue;
+			} else {
+				if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) ||
+				     sk->rcv_saddr)
+					continue;
 			}
 		}
+		ret = 1;
+		goto failed;
 	}
-	return sk2 != NULL;
+	/* If we found a conflict, fail. */
+	ret = sk2 != NULL;
+failed:
+	return ret;
 }
 
 /* Obtain a reference to a local port for the given sock,
@@ -247,10 +324,11 @@
 				break;
 	}
 	if (tb != NULL && tb->owners != NULL) {
-		if (sk->reuse > 1)
+		ret = 1; 
+		if (tb->fastreuse > 0 && 
+		    sk->reuse != 0 &&
+		    sk->state != TCP_LISTEN) {
 			goto success;
-		if (tb->fastreuse > 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
-			goto success;
 		} else {
 			ret = 1;
 			if (tcp_bind_conflict(sk, tb))
@@ -418,23 +496,31 @@
 	struct sock *result = NULL;
 	int score, hiscore;
 
-	hiscore=0;
+	hiscore = -1;
 	for(; sk; sk = sk->next) {
 		if(sk->num == hnum) {
 			__u32 rcv_saddr = sk->rcv_saddr;
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+			score = 0;
+			if (sk->family == PF_INET)
+				score++;
+			else if (sk->net_pinfo.af_inet6.ipv6only)
+				continue;
+#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 +542,10 @@
 		if (sk->num == hnum &&
 		    sk->next == NULL &&
 		    (!sk->rcv_saddr || sk->rcv_saddr == daddr) &&
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		    (sk->family == PF_INET ||
+		     (sk->family == PF_INET6 && !sk->net_pinfo.af_inet6.ipv6only)) &&
+#endif
 		    !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.8.1
diff -u -r1.1.1.1 -r1.1.1.1.8.1
--- net/ipv4/udp.c	2002/08/20 09:47:02	1.1.1.1
+++ net/ipv4/udp.c	2002/09/11 03:30:27	1.1.1.1.8.1
@@ -61,6 +61,14 @@
  *					return ENOTCONN for unconnected sockets (POSIX)
  *		Janos Farkas	:	don't deliver multi/broadcasts to a different
  *					bound-to-device socket
+ *	YOSHIFUJI Hideaki @USAGI:	Reworked bind(2) behavior, including:
+ *					- Allow ipv6 and ipv4 bind(2) to the
+ *					  same port if IPV6_V6ONLY socket opttion is
+ *					  is set.
+ *					- Don't allow binding to the same
+ *					  address unless it is one of multi-
+ *					  cast address even if SO_REUSEADDR 
+ *					  is set.
  *
  *
  *		This program is free software; you can redistribute it and/or
@@ -85,6 +93,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>
@@ -153,18 +162,88 @@
 		udp_port_rover = snum = result;
 	} else {
 		struct sock *sk2;
+		int sk_reuse, sk2_reuse;
+		int addr_type2;
 
+		sk_reuse = 0;
+		if (sk->reuse)
+			sk_reuse |= 1;
+		if (sk_reuse &&
+		    MULTICAST(sk->rcv_saddr))
+			sk_reuse |= 4;
+
 		for (sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
 		     sk2 != NULL;
 		     sk2 = sk2->next) {
-			if (sk2->num == snum &&
-			    sk2 != sk &&
-			    sk2->bound_dev_if == sk->bound_dev_if &&
-			    (!sk2->rcv_saddr ||
-			     !sk->rcv_saddr ||
-			     sk2->rcv_saddr == sk->rcv_saddr) &&
-			    (!sk2->reuse || !sk->reuse))
-				goto fail;
+			int both_specified = 0;
+
+			if (sk2->num != snum ||
+			    sk2 == sk ||
+			    (sk2->bound_dev_if && sk->bound_dev_if &&
+			     sk2->bound_dev_if != sk->bound_dev_if))
+				continue;
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+			if (sk2->family == AF_INET6) {
+				if (IN6_IS_ADDR_UNSPECIFIED(&sk2->net_pinfo.af_inet6.rcv_saddr))
+					addr_type2 = IPV6_ADDR_ANY;
+				else if (IN6_IS_ADDR_V4MAPPED(&sk2->net_pinfo.af_inet6.rcv_saddr))
+					addr_type2 = IPV6_ADDR_MAPPED;
+				else
+					addr_type2 = IPV6_ADDR_UNICAST;	/*XXX*/
+			} else
+				addr_type2 = IPV6_ADDR_MAPPED;
+#else
+			addr_type2 = IPV6_ADDR_MAPPED;
+#endif
+
+			if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) &&
+			    sk->rcv_saddr) {
+				if (sk2->rcv_saddr != sk->rcv_saddr)
+					continue;
+				both_specified = 1;
+			}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+			if (addr_type2 != IPV6_ADDR_MAPPED && sk2->net_pinfo.af_inet6.ipv6only) {
+				continue;
+			}
+#endif
+
+			sk2_reuse = 0;
+			if (sk2->reuse)
+				sk2_reuse |= 1;
+			if (sk2_reuse &&
+			    (addr_type2 != IPV6_ADDR_MAPPED ? (addr_type2 & IPV6_ADDR_MULTICAST) : MULTICAST(sk2->rcv_saddr)))
+				sk2_reuse |= 4;
+
+			if (sk2_reuse & sk_reuse & 3) {	/* NOT && */
+				if (sk2_reuse & sk_reuse & 4)
+					continue;
+				if (both_specified) {
+					int addr_type2d;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+					if (sk2->family == AF_INET6) {
+						if (IN6_IS_ADDR_UNSPECIFIED(&sk2->net_pinfo.af_inet6.daddr))
+							addr_type2d = IPV6_ADDR_ANY;
+						else if (IN6_IS_ADDR_V4MAPPED(&sk2->net_pinfo.af_inet6.daddr))
+							addr_type2d = IPV6_ADDR_MAPPED;
+						else
+							addr_type2d = IPV6_ADDR_UNICAST; /*XXX*/
+					} else
+						addr_type2d = IPV6_ADDR_MAPPED;
+#else
+					addr_type2d = IPV6_ADDR_MAPPED;
+#endif
+					if (addr_type2d != IPV6_ADDR_MAPPED ? addr_type2d != IPV6_ADDR_ANY : sk2->daddr)
+						continue;
+				} else {
+					if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) ||
+					    sk->rcv_saddr)
+						continue;
+				}
+			}
+			goto fail;
 		}
 	}
 	sk->num = snum;
@@ -216,28 +295,37 @@
 
 	for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) {
 		if(sk->num == hnum) {
-			int score = 0;
+			int score;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+			score = 0;
+			if(sk->family == PF_INET)
+				score++;
+			else if (sk->net_pinfo.af_inet6.ipv6only)
+				continue;
+#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 +361,9 @@
 		    (s->daddr && s->daddr!=rmt_addr)			||
 		    (s->dport != rmt_port && s->dport != 0)			||
 		    (s->rcv_saddr  && s->rcv_saddr != loc_addr)		||
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		    (s->family != PF_INET && s->net_pinfo.af_inet6.ipv6only)	||
+#endif
 		    (s->bound_dev_if && s->bound_dev_if != dif))
 			continue;
 		break;
Index: net/ipv6/addrconf.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv6/addrconf.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.8.1
diff -u -r1.1.1.1 -r1.1.1.1.8.1
--- net/ipv6/addrconf.c	2002/08/20 09:47:02	1.1.1.1
+++ net/ipv6/addrconf.c	2002/09/11 03:30:27	1.1.1.1.8.1
@@ -116,6 +116,7 @@
 	MAX_RTR_SOLICITATIONS,		/* router solicits	*/
 	RTR_SOLICITATION_INTERVAL,	/* rtr solicit interval	*/
 	MAX_RTR_SOLICITATION_DELAY,	/* rtr solicit delay	*/
+	bindv6only:		0,
 };
 
 static struct ipv6_devconf ipv6_devconf_dflt =
@@ -130,6 +131,7 @@
 	MAX_RTR_SOLICITATIONS,		/* router solicits	*/
 	RTR_SOLICITATION_INTERVAL,	/* rtr solicit interval	*/
 	MAX_RTR_SOLICITATION_DELAY,	/* rtr solicit delay	*/
+	bindv6only:		0,
 };
 
 int ipv6_addr_type(struct in6_addr *addr)
@@ -1879,7 +1881,7 @@
 static struct addrconf_sysctl_table
 {
 	struct ctl_table_header *sysctl_header;
-	ctl_table addrconf_vars[11];
+	ctl_table addrconf_vars[12];
 	ctl_table addrconf_dev[2];
 	ctl_table addrconf_conf_dir[2];
 	ctl_table addrconf_proto_dir[2];
@@ -1925,6 +1927,10 @@
 	{NET_IPV6_RTR_SOLICIT_DELAY, "router_solicitation_delay",
          &ipv6_devconf.rtr_solicit_delay, sizeof(int), 0644, NULL,
          &proc_dointvec_jiffies},
+
+	{NET_IPV6_BINDV6ONLY, "bindv6only",
+	 &ipv6_devconf.bindv6only, sizeof(int), 0644, NULL,
+	 &proc_dointvec},
 
 	{0}},
 
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.8.1
diff -u -r1.1.1.1 -r1.1.1.1.8.1
--- net/ipv6/af_inet6.c	2002/08/20 09:47:02	1.1.1.1
+++ net/ipv6/af_inet6.c	2002/09/11 03:30:27	1.1.1.1.8.1
@@ -173,6 +173,8 @@
 	sk->net_pinfo.af_inet6.mc_loop	  = 1;
 	sk->net_pinfo.af_inet6.pmtudisc	  = IPV6_PMTUDISC_WANT;
 
+	sk->net_pinfo.af_inet6.ipv6only   = ipv6_devconf.bindv6only;
+
 	/* Init the ipv4 part of the socket since we can have sockets
 	 * using v6 API for ipv4.
 	 */
@@ -248,6 +250,8 @@
 
 	/* Check if the address belongs to the host. */
 	if (addr_type == IPV6_ADDR_MAPPED) {
+		if (sk->net_pinfo.af_inet6.ipv6only)
+			return -EADDRNOTAVAIL;
 		v4addr = addr->sin6_addr.s6_addr32[3];
 		if (inet_addr_type(v4addr) != RTN_LOCAL)
 			return -EADDRNOTAVAIL;
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.8.1
diff -u -r1.1.1.1 -r1.1.1.1.8.1
--- net/ipv6/ipv6_sockglue.c	2002/08/20 09:47:02	1.1.1.1
+++ net/ipv6/ipv6_sockglue.c	2002/09/11 03:30:27	1.1.1.1.8.1
@@ -380,6 +380,15 @@
 		retv = ipv6_flowlabel_opt(sk, optval, optlen);
 		break;
 
+	case IPV6_V6ONLY:
+		if (optlen != sizeof(int))
+			goto e_inval;
+		if (sk->userlocks&SOCK_BINDADDR_LOCK)
+			goto e_inval;
+		np->ipv6only = valbool;
+		retv = 0;
+		break;
+
 #ifdef CONFIG_NETFILTER
 	default:
 		retv = nf_setsockopt(sk, PF_INET6, optname, optval, 
@@ -520,6 +529,10 @@
 
 	case IPV6_FLOWINFO_SEND:
 		val = np->sndflow;
+		break;
+
+	case IPV6_V6ONLY:
+		val = np->ipv6only;
 		break;
 
 	default:
Index: net/ipv6/tcp_ipv6.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv6/tcp_ipv6.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.8.1
diff -u -r1.1.1.1 -r1.1.1.1.8.1
--- net/ipv6/tcp_ipv6.c	2002/08/20 09:47:02	1.1.1.1
+++ net/ipv6/tcp_ipv6.c	2002/09/11 03:30:27	1.1.1.1.8.1
@@ -14,6 +14,14 @@
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
+ *	YOSHIFUJI Hideaki @USAGI:	Reworked bind(2) behavior, including:
+ *					- Allow ipv6 and ipv4 bind(2) to the
+ *					  same port if IPV6_V6ONLY socket
+ *					  option is set.
+ *					- Don't allow binding to the same
+ *					  address unless it is one of multi-
+ *					  cast address even if SO_REUSEADDR 
+ *					  is set.
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -137,28 +145,70 @@
 			goto success;
 		} else {
 			struct sock *sk2 = tb->owners;
-			int sk_reuse = sk->reuse;
-			int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr);
+			int sk_reuse, sk2_reuse;
+			struct in6_addr *sk_rcv_saddr6 = sk->state != TCP_TIME_WAIT ? 
+								&sk->net_pinfo.af_inet6.rcv_saddr:
+								&((struct tcp_tw_bucket*)sk)->v6_rcv_saddr;
+			int addr_type = ipv6_addr_type(sk_rcv_saddr6),
+			    addr_type2;
+
+			sk_reuse = 0;
+			if (sk->reuse)
+				sk_reuse |= 1;
 
 			/* We must walk the whole port owner list in this case. -DaveM */
 			for( ; sk2 != NULL; sk2 = sk2->bind_next) {
-				if (sk != sk2 &&
-				    sk->bound_dev_if == sk2->bound_dev_if) {
-					if (!sk_reuse	||
-					    !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))
-							break;
+				int both_specified = 0;
+				struct in6_addr *sk2_rcv_saddr6;
+				if (sk2 == sk ||
+				    (sk2->bound_dev_if && sk->bound_dev_if &&
+				     sk2->bound_dev_if != sk->bound_dev_if))
+					continue;
+				sk2_rcv_saddr6 = sk2->state != TCP_TIME_WAIT ?
+							&sk2->net_pinfo.af_inet6.rcv_saddr :
+							&((struct tcp_tw_bucket*)sk2)->v6_rcv_saddr;
+
+				if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) &&
+				    (addr_type != IPV6_ADDR_MAPPED ? addr_type != IPV6_ADDR_ANY : sk->rcv_saddr)) {
+					if (addr_type2 == IPV6_ADDR_MAPPED || addr_type == IPV6_ADDR_MAPPED) {
+						if (addr_type2 != addr_type ||
+						    sk2->rcv_saddr != sk->rcv_saddr)
+							continue;
+					} else {
+						if (ipv6_addr_cmp(sk2_rcv_saddr6, sk_rcv_saddr6))
+							continue;
 					}
+					both_specified = 1;
 				}
+
+				if ((addr_type2 == IPV6_ADDR_MAPPED &&
+				     addr_type != IPV6_ADDR_MAPPED && sk->net_pinfo.af_inet6.ipv6only) ||
+				    (addr_type == IPV6_ADDR_MAPPED &&
+				     addr_type2 != IPV6_ADDR_MAPPED && sk2->net_pinfo.af_inet6.ipv6only)) {
+					continue;
+				}
+
+				sk2_reuse = 0;
+				if (sk2->reuse)
+					sk2_reuse |= 1;
+
+				if (sk2_reuse & sk_reuse & 3) { /* NOT && */
+					ret = 1;
+					if (both_specified) {
+						struct in6_addr *sk2_daddr6 = sk2->state != TCP_TIME_WAIT ?
+										&sk2->net_pinfo.af_inet6.daddr :
+										&((struct tcp_tw_bucket*)sk2)->v6_daddr;
+						int addr_type2d = sk2->family == AF_INET6 ? ipv6_addr_type(sk2_daddr6) : IPV6_ADDR_MAPPED;
+						if (addr_type2d != IPV6_ADDR_MAPPED ? addr_type2d != IPV6_ADDR_ANY : sk2->daddr)
+							continue;
+					} else {
+						if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) || 
+						    (addr_type != IPV6_ADDR_MAPPED ? addr_type != IPV6_ADDR_ANY : sk->rcv_saddr))
+							continue;
+					}
+				}
+				ret = 1;
+				goto fail_unlock;
 			}
 			/* If we found a conflict, fail. */
 			ret = 1;
@@ -601,6 +651,9 @@
 		struct sockaddr_in sin;
 
 		SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
+
+		if (sk->net_pinfo.af_inet6.ipv6only)
+			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.1
retrieving revision 1.1.1.1.8.1
diff -u -r1.1.1.1 -r1.1.1.1.8.1
--- net/ipv6/udp.c	2002/08/20 09:47:02	1.1.1.1
+++ net/ipv6/udp.c	2002/09/11 03:30:27	1.1.1.1.8.1
@@ -11,7 +11,16 @@
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
+ *	YOSHIFUJI Hideaki @USAGI:	Reworked bind(2) behavior, including:
+ *					- Allow ipv6 and ipv4 bind(2) to the
+ *					  same port if IPV6_V6ONLY socket
+ *					  option is set.
+ *					- Don't allow binding to the same
+ *					  address unless it is one of multi-
+ *					  cast address even if SO_REUSEADDR 
+ *					  is set.
  *
+ *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
  *      as published by the Free Software Foundation; either version
@@ -98,23 +107,72 @@
 		udp_port_rover = snum = result;
 	} else {
 		struct sock *sk2;
-		int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr);
+		int sk_reuse, sk2_reuse;
+		int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr),
+		    addr_type2;
+
+		sk_reuse = 0;
+		if (sk->reuse)
+			sk_reuse |= 1;
+		if (sk_reuse &&
+		    (addr_type != IPV6_ADDR_MAPPED ? (addr_type & IPV6_ADDR_MULTICAST) : MULTICAST(sk->rcv_saddr)))
+			sk_reuse |= 4;
 
 		for (sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
 		     sk2 != NULL;
 		     sk2 = sk2->next) {
-			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) ||
-			     (addr_type == IPV6_ADDR_MAPPED &&
-			      sk2->family == AF_INET &&
-			      sk->rcv_saddr == sk2->rcv_saddr)) &&
-			    (!sk2->reuse || !sk->reuse))
-				goto fail;
+			int both_specified = 0;
+
+			if (sk2->num != snum ||
+			    sk2 == sk ||
+			    (sk2->bound_dev_if && sk->bound_dev_if &&
+			     sk2->bound_dev_if != sk->bound_dev_if))
+				continue;
+
+			addr_type2 = sk2->family == AF_INET6 ? ipv6_addr_type(&sk2->net_pinfo.af_inet6.rcv_saddr) : IPV6_ADDR_MAPPED;
+
+			if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) &&
+			    (addr_type != IPV6_ADDR_MAPPED ? addr_type != IPV6_ADDR_ANY : sk->rcv_saddr)) {
+				if (addr_type2 == IPV6_ADDR_MAPPED || addr_type == IPV6_ADDR_MAPPED) {
+					if (addr_type2 != addr_type ||
+					    sk2->rcv_saddr != sk->rcv_saddr)
+						continue;
+				} else {
+					if (ipv6_addr_cmp(&sk2->net_pinfo.af_inet6.rcv_saddr,
+							  &sk->net_pinfo.af_inet6.rcv_saddr))
+						continue;
+				}
+				both_specified = 1;
+			}
+
+			if ((addr_type2 == IPV6_ADDR_MAPPED && 
+			     addr_type != IPV6_ADDR_MAPPED && sk->net_pinfo.af_inet6.ipv6only) ||
+			    (addr_type == IPV6_ADDR_MAPPED &&
+			     addr_type2 != IPV6_ADDR_MAPPED && sk2->net_pinfo.af_inet6.ipv6only)) {
+				continue;
+			}
+
+			sk2_reuse = 0;
+			if (sk2->reuse)
+				sk2_reuse |= 1;
+			if (sk2_reuse &&
+			    (addr_type2 != IPV6_ADDR_MAPPED ? (addr_type2 & IPV6_ADDR_MULTICAST) : MULTICAST(sk2->rcv_saddr)))
+				sk2_reuse |= 4;
+
+			if (sk2_reuse & sk_reuse & 3) {	/* NOT && */
+				if (sk2_reuse & sk_reuse & 4)
+					continue;
+				if (both_specified) {
+					int addr_type2d = sk2->family == AF_INET6 ? ipv6_addr_type(&sk2->net_pinfo.af_inet6.daddr) : IPV6_ADDR_MAPPED;
+					if (addr_type2d != IPV6_ADDR_MAPPED ? addr_type2d != IPV6_ADDR_ANY : sk2->daddr)
+						continue;
+				} else {
+					if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) || 
+					    (addr_type != IPV6_ADDR_MAPPED ? addr_type != IPV6_ADDR_ANY : sk->rcv_saddr))
+						continue;
+				}
+			}
+			goto fail;
 		}
 	}
 
@@ -221,6 +279,8 @@
 	int			err;
 
 	if (usin->sin6_family == AF_INET) {
+		if (sk->net_pinfo.af_inet6.ipv6only)
+			return -EAFNOSUPPORT;
 		err = udp_connect(sk, uaddr, addr_len);
 		goto ipv4_connected;
 	}
@@ -256,6 +316,9 @@
 	if (addr_type == IPV6_ADDR_MAPPED) {
 		struct sockaddr_in sin;
 
+		if (sk->net_pinfo.af_inet6.ipv6only)
+			return -ENETUNREACH;
+
 		sin.sin_family = AF_INET;
 		sin.sin_addr.s_addr = daddr->s6_addr32[3];
 		sin.sin_port = usin->sin6_port;
@@ -783,8 +846,11 @@
 	fl.oif = 0;
 
 	if (sin6) {
-		if (sin6->sin6_family == AF_INET)
+		if (sin6->sin6_family == AF_INET) {
+			if (sk->net_pinfo.af_inet6.ipv6only)
+				return -EAFNOSUPPORT;
 			return udp_sendmsg(sk, msg, ulen);
+		}
 
 		if (addr_len < SIN6_LEN_RFC2133)
 			return -EINVAL;
@@ -830,6 +896,9 @@
 
 	if (addr_type == IPV6_ADDR_MAPPED) {
 		struct sockaddr_in sin;
+
+		if (sk->net_pinfo.af_inet6.ipv6only)
+			return -ENETUNREACH;
 
 		sin.sin_family = AF_INET;
 		sin.sin_addr.s_addr = daddr->s6_addr32[3];

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port Number (IPV6_V6ONLY Support)
  2002-10-03  3:13 [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port Number (IPV6_V6ONLY Support) YOSHIFUJI Hideaki / 吉藤英明
@ 2002-10-03  3:53 ` acme
  2002-10-03  3:55 ` acme
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 33+ messages in thread
From: acme @ 2002-10-03  3:53 UTC (permalink / raw)
  To: YOSHIFUJI, UNEXPECTED_DATA_AFTER_ADDRESS; +Cc: linux-kernel, netdev, usagi


Quoting YOSHIFUJI Hideaki / ^[$B5HF#1QL@^[(B <yoshfuji@linux-ipv6.org>: 
 
> +#define IN6_IS_ADDR_V4MAPPED(a)				\ 
> +	((((a)->s6_addr32[0]) == 0) &&			\ 
> +	 (((a)->s6_addr32[1]) == 0) &&			\ 
> +	 (((a)->s6_addr32[2]) == __constant_htonl(0x0000ffff))) 
 
Please use plain htonl, __constant_htonl is only needed in static 
initializations, in all other cases with constants as a parameter it 
generates the same code as htonl, so lets prefer using the shorter, 
more readable format. 
 
- Arnaldo 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port Number (IPV6_V6ONLY Support)
  2002-10-03  3:13 [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port Number (IPV6_V6ONLY Support) YOSHIFUJI Hideaki / 吉藤英明
  2002-10-03  3:53 ` acme
@ 2002-10-03  3:55 ` acme
  2002-10-03  7:00 ` Pekka Savola
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 33+ messages in thread
From: acme @ 2002-10-03  3:55 UTC (permalink / raw)
  To: yoshfuji; +Cc: linux-kernel, netdev, usagi

Quoting YOSHIFUJI Hideaki / ^[$B5HF#1QL@^[(B <yoshfuji@linux-ipv6.org>: 
 
 
> +	 (((a)->s6_addr32[2]) == __constant_htonl(0x0000ffff))) 
 
Please use plain htonl, __constant_htonl is only needed in static 
initializations, in all other cases with constants as a parameter it 
generates the same code as htonl, so lets prefer using the shorter, 
more readable format. 
 
- Arnaldo 
 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port Number (IPV6_V6ONLY Support)
  2002-10-03  3:13 [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port Number (IPV6_V6ONLY Support) YOSHIFUJI Hideaki / 吉藤英明
  2002-10-03  3:53 ` acme
  2002-10-03  3:55 ` acme
@ 2002-10-03  7:00 ` Pekka Savola
  2002-10-03  8:29 ` David S. Miller
  2002-10-03 13:01 ` [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port kuznet
  4 siblings, 0 replies; 33+ messages in thread
From: Pekka Savola @ 2002-10-03  7:00 UTC (permalink / raw)
  To: YOSHIFUJI Hideaki / 吉藤英明
  Cc: linux-kernel, netdev, usagi

Please add a short description of 'bindv6only' in 
Documentation/networking/ip-sysctl.txt.

This toggle seems usable only in interface "all" context.

Didn't really look at the rest of the patch.

On Thu, 3 Oct 2002, YOSHIFUJI Hideaki / [iso-2022-jp] ^[$B5HF#1QL@^[(B wrote:
> Hello!
> 
> 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.
> 
> We also prohibit a completely duplicate set of (local-addr, local-port,
> remote-addr, remote-port) set even if SO_REUSEADDR is set unless
> the local address is a multicast address; it is ambiguous and it may 
> steal packets from others; i.e. a kind of DoS.
> 
> Packet delivery strategy is similar to one before, but we prefer
> IPv4 a bit.
> 
> Following patch is against linux-2.4.19.
> 
> Thank you in advance.
> 
> -------------------------------------------------------------------
> Patch-Name: Allow Both IPv6 and IPv4 Sockets on the Same Port Number (IPV6_V6ONLY Support)
> Patch-Id: FIX_2_4_19_DOUBLEBIND-20020909
> Patch-Author: YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
> Credit: YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
> Reference: RFC2553bis
> -------------------------------------------------------------------
> 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.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- include/linux/in6.h	2002/08/20 09:46:34	1.1.1.1
> +++ include/linux/in6.h	2002/09/11 03:30:27	1.1.1.1.8.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
> @@ -167,4 +168,19 @@
>  #define IPV6_FLOWINFO_SEND	33
>  
>  
> +#ifdef __KERNEL__
> +#ifndef IN6_IS_ADDR_UNSPECIFIED
> +#define IN6_IS_ADDR_UNSPECIFIED(a)			\
> +	((((a)->s6_addr32[0]) == 0) &&			\
> +	 (((a)->s6_addr32[1]) == 0) &&			\
> +	 (((a)->s6_addr32[2]) == 0) &&			\
> +	 (((a)->s6_addr32[3]) == 0))
> +#endif
> +#ifndef IN6_IS_ADDR_V4MAPPED
> +#define IN6_IS_ADDR_V4MAPPED(a)				\
> +	((((a)->s6_addr32[0]) == 0) &&			\
> +	 (((a)->s6_addr32[1]) == 0) &&			\
> +	 (((a)->s6_addr32[2]) == __constant_htonl(0x0000ffff)))
> +#endif
> +#endif
>  #endif
> Index: include/linux/sysctl.h
> ===================================================================
> RCS file: /cvsroot/usagi/usagi-backport/linux24/include/linux/sysctl.h,v
> retrieving revision 1.1.1.1
> retrieving revision 1.1.1.1.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- include/linux/sysctl.h	2002/08/20 09:46:34	1.1.1.1
> +++ include/linux/sysctl.h	2002/09/11 03:30:27	1.1.1.1.8.1
> @@ -369,7 +369,8 @@
>  	NET_IPV6_DAD_TRANSMITS=7,
>  	NET_IPV6_RTR_SOLICITS=8,
>  	NET_IPV6_RTR_SOLICIT_INTERVAL=9,
> -	NET_IPV6_RTR_SOLICIT_DELAY=10
> +	NET_IPV6_RTR_SOLICIT_DELAY=10,
> +	NET_IPV6_BINDV6ONLY=11
>  };
>  
>  /* /proc/sys/net/<protocol>/neigh/<dev> */
> Index: include/net/if_inet6.h
> ===================================================================
> RCS file: /cvsroot/usagi/usagi-backport/linux24/include/net/if_inet6.h,v
> retrieving revision 1.1.1.1
> retrieving revision 1.1.1.1.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- include/net/if_inet6.h	2002/08/20 09:46:45	1.1.1.1
> +++ include/net/if_inet6.h	2002/09/11 03:30:27	1.1.1.1.8.1
> @@ -86,6 +86,7 @@
>  	int		rtr_solicits;
>  	int		rtr_solicit_interval;
>  	int		rtr_solicit_delay;
> +	int		bindv6only;
>  
>  	void		*sysctl;
>  };
> 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.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- include/net/sock.h	2002/08/20 09:46:45	1.1.1.1
> +++ include/net/sock.h	2002/09/11 03:30:27	1.1.1.1.8.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;
> Index: net/ipv4/tcp_ipv4.c
> ===================================================================
> RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv4/tcp_ipv4.c,v
> retrieving revision 1.1.1.1
> retrieving revision 1.1.1.1.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- net/ipv4/tcp_ipv4.c	2002/08/20 09:47:02	1.1.1.1
> +++ net/ipv4/tcp_ipv4.c	2002/09/11 03:30:27	1.1.1.1.8.1
> @@ -45,6 +45,14 @@
>   *	Vitaly E. Lavrov	:	Transparent proxy revived after year coma.
>   *	Andi Kleen		:	Fix new listen.
>   *	Andi Kleen		:	Fix accept error reporting.
> + *	YOSHIFUJI Hideaki @USAGI:	Reworked bind(2) behavior including:
> + *					- Allow ipv6 and ipv4 bind(2) to the
> + *					  same port if IPV6_V6ONLY socket option
> + *					  is set.
> + *					- Don't allow binding to the same
> + *					  address unless it is one of multi-
> + *					  cast address even if SO_REUSEADDR 
> + *					  is set.
>   */
>  
>  #include <linux/config.h>
> @@ -177,23 +185,92 @@
>  static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb)
>  {
>  	struct sock *sk2 = tb->owners;
> -	int sk_reuse = sk->reuse;
> +	int sk_reuse, sk2_reuse;
> +	int addr_type2;
> +	int ret;
> +
> +	sk_reuse = 0;
> +	if (sk->reuse)
> +		sk_reuse |= 1;
>  	
>  	for( ; sk2 != NULL; sk2 = sk2->bind_next) {
> -		if (sk != sk2 &&
> -		    sk2->reuse <= 1 &&
> -		    sk->bound_dev_if == sk2->bound_dev_if) {
> -			if (!sk_reuse	||
> -			    !sk2->reuse	||
> -			    sk2->state == TCP_LISTEN) {
> -				if (!sk2->rcv_saddr	||
> -				    !sk->rcv_saddr	||
> -				    (sk2->rcv_saddr == sk->rcv_saddr))
> -					break;
> +		int both_specified = 0;
> +
> +		if (sk2 == sk ||
> +		    (sk2->bound_dev_if && sk->bound_dev_if &&
> +		     sk2->bound_dev_if != sk->bound_dev_if))
> +			continue;
> +
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +		if (sk2->family == AF_INET6) {
> +			struct in6_addr *sk2_rcv_saddr6 = sk2->state != TCP_TIME_WAIT ?
> +				&sk2->net_pinfo.af_inet6.rcv_saddr :
> +				&((struct tcp_tw_bucket*)sk2)->v6_rcv_saddr;
> +			if (IN6_IS_ADDR_UNSPECIFIED(sk2_rcv_saddr6))
> +				addr_type2 = IPV6_ADDR_ANY;
> +			else if (IN6_IS_ADDR_V4MAPPED(sk2_rcv_saddr6))
> +				addr_type2 = IPV6_ADDR_MAPPED;
> +			else
> +				addr_type2 = IPV6_ADDR_UNICAST;	/*XXX*/
> +		} else
> +			addr_type2 = IPV6_ADDR_MAPPED;
> +#else
> +		addr_type2 = IPV6_ADDR_MAPPED;
> +#endif
> +		if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) &&
> +		    sk->rcv_saddr) {
> +			if (sk2->rcv_saddr != sk->rcv_saddr)
> +				continue;
> +			both_specified = 1;
> +		}
> +
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +		if (addr_type2 != IPV6_ADDR_MAPPED && sk2->net_pinfo.af_inet6.ipv6only) {
> +			continue;
> +		}
> +#endif
> +
> +		sk2_reuse = 0;
> +		if (sk2->reuse)
> +			sk2_reuse |= 1;
> +
> +		if (sk2_reuse & sk_reuse & 3) {	/* NOT && */
> +			ret = 1;
> +			if (both_specified) {
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +				struct in6_addr *sk2_daddr6 = sk2->state != TCP_TIME_WAIT ?
> +								&sk2->net_pinfo.af_inet6.daddr :
> +								&((struct tcp_tw_bucket*)sk2)->v6_daddr;
> +#endif
> +				int addr_type2d;
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +				if (sk2->family == AF_INET6) {
> +					if (IN6_IS_ADDR_UNSPECIFIED(sk2_daddr6))
> +						addr_type2d = IPV6_ADDR_ANY;
> +					else if (IN6_IS_ADDR_V4MAPPED(sk2_daddr6))
> +						addr_type2d = IPV6_ADDR_MAPPED;
> +					else
> +						addr_type2d = IPV6_ADDR_UNICAST; /*XXX*/
> +				} else
> +					addr_type2d = IPV6_ADDR_MAPPED;
> +#else
> +				addr_type2d = IPV6_ADDR_MAPPED;
> +#endif
> +				if (addr_type2d != IPV6_ADDR_MAPPED ? addr_type2d != IPV6_ADDR_ANY : sk2->daddr)
> +					continue;
> +			} else {
> +				if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) ||
> +				     sk->rcv_saddr)
> +					continue;
>  			}
>  		}
> +		ret = 1;
> +		goto failed;
>  	}
> -	return sk2 != NULL;
> +	/* If we found a conflict, fail. */
> +	ret = sk2 != NULL;
> +failed:
> +	return ret;
>  }
>  
>  /* Obtain a reference to a local port for the given sock,
> @@ -247,10 +324,11 @@
>  				break;
>  	}
>  	if (tb != NULL && tb->owners != NULL) {
> -		if (sk->reuse > 1)
> +		ret = 1; 
> +		if (tb->fastreuse > 0 && 
> +		    sk->reuse != 0 &&
> +		    sk->state != TCP_LISTEN) {
>  			goto success;
> -		if (tb->fastreuse > 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
> -			goto success;
>  		} else {
>  			ret = 1;
>  			if (tcp_bind_conflict(sk, tb))
> @@ -418,23 +496,31 @@
>  	struct sock *result = NULL;
>  	int score, hiscore;
>  
> -	hiscore=0;
> +	hiscore = -1;
>  	for(; sk; sk = sk->next) {
>  		if(sk->num == hnum) {
>  			__u32 rcv_saddr = sk->rcv_saddr;
>  
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +			score = 0;
> +			if (sk->family == PF_INET)
> +				score++;
> +			else if (sk->net_pinfo.af_inet6.ipv6only)
> +				continue;
> +#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 +542,10 @@
>  		if (sk->num == hnum &&
>  		    sk->next == NULL &&
>  		    (!sk->rcv_saddr || sk->rcv_saddr == daddr) &&
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +		    (sk->family == PF_INET ||
> +		     (sk->family == PF_INET6 && !sk->net_pinfo.af_inet6.ipv6only)) &&
> +#endif
>  		    !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.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- net/ipv4/udp.c	2002/08/20 09:47:02	1.1.1.1
> +++ net/ipv4/udp.c	2002/09/11 03:30:27	1.1.1.1.8.1
> @@ -61,6 +61,14 @@
>   *					return ENOTCONN for unconnected sockets (POSIX)
>   *		Janos Farkas	:	don't deliver multi/broadcasts to a different
>   *					bound-to-device socket
> + *	YOSHIFUJI Hideaki @USAGI:	Reworked bind(2) behavior, including:
> + *					- Allow ipv6 and ipv4 bind(2) to the
> + *					  same port if IPV6_V6ONLY socket opttion is
> + *					  is set.
> + *					- Don't allow binding to the same
> + *					  address unless it is one of multi-
> + *					  cast address even if SO_REUSEADDR 
> + *					  is set.
>   *
>   *
>   *		This program is free software; you can redistribute it and/or
> @@ -85,6 +93,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>
> @@ -153,18 +162,88 @@
>  		udp_port_rover = snum = result;
>  	} else {
>  		struct sock *sk2;
> +		int sk_reuse, sk2_reuse;
> +		int addr_type2;
>  
> +		sk_reuse = 0;
> +		if (sk->reuse)
> +			sk_reuse |= 1;
> +		if (sk_reuse &&
> +		    MULTICAST(sk->rcv_saddr))
> +			sk_reuse |= 4;
> +
>  		for (sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
>  		     sk2 != NULL;
>  		     sk2 = sk2->next) {
> -			if (sk2->num == snum &&
> -			    sk2 != sk &&
> -			    sk2->bound_dev_if == sk->bound_dev_if &&
> -			    (!sk2->rcv_saddr ||
> -			     !sk->rcv_saddr ||
> -			     sk2->rcv_saddr == sk->rcv_saddr) &&
> -			    (!sk2->reuse || !sk->reuse))
> -				goto fail;
> +			int both_specified = 0;
> +
> +			if (sk2->num != snum ||
> +			    sk2 == sk ||
> +			    (sk2->bound_dev_if && sk->bound_dev_if &&
> +			     sk2->bound_dev_if != sk->bound_dev_if))
> +				continue;
> +
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +			if (sk2->family == AF_INET6) {
> +				if (IN6_IS_ADDR_UNSPECIFIED(&sk2->net_pinfo.af_inet6.rcv_saddr))
> +					addr_type2 = IPV6_ADDR_ANY;
> +				else if (IN6_IS_ADDR_V4MAPPED(&sk2->net_pinfo.af_inet6.rcv_saddr))
> +					addr_type2 = IPV6_ADDR_MAPPED;
> +				else
> +					addr_type2 = IPV6_ADDR_UNICAST;	/*XXX*/
> +			} else
> +				addr_type2 = IPV6_ADDR_MAPPED;
> +#else
> +			addr_type2 = IPV6_ADDR_MAPPED;
> +#endif
> +
> +			if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) &&
> +			    sk->rcv_saddr) {
> +				if (sk2->rcv_saddr != sk->rcv_saddr)
> +					continue;
> +				both_specified = 1;
> +			}
> +
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +			if (addr_type2 != IPV6_ADDR_MAPPED && sk2->net_pinfo.af_inet6.ipv6only) {
> +				continue;
> +			}
> +#endif
> +
> +			sk2_reuse = 0;
> +			if (sk2->reuse)
> +				sk2_reuse |= 1;
> +			if (sk2_reuse &&
> +			    (addr_type2 != IPV6_ADDR_MAPPED ? (addr_type2 & IPV6_ADDR_MULTICAST) : MULTICAST(sk2->rcv_saddr)))
> +				sk2_reuse |= 4;
> +
> +			if (sk2_reuse & sk_reuse & 3) {	/* NOT && */
> +				if (sk2_reuse & sk_reuse & 4)
> +					continue;
> +				if (both_specified) {
> +					int addr_type2d;
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +					if (sk2->family == AF_INET6) {
> +						if (IN6_IS_ADDR_UNSPECIFIED(&sk2->net_pinfo.af_inet6.daddr))
> +							addr_type2d = IPV6_ADDR_ANY;
> +						else if (IN6_IS_ADDR_V4MAPPED(&sk2->net_pinfo.af_inet6.daddr))
> +							addr_type2d = IPV6_ADDR_MAPPED;
> +						else
> +							addr_type2d = IPV6_ADDR_UNICAST; /*XXX*/
> +					} else
> +						addr_type2d = IPV6_ADDR_MAPPED;
> +#else
> +					addr_type2d = IPV6_ADDR_MAPPED;
> +#endif
> +					if (addr_type2d != IPV6_ADDR_MAPPED ? addr_type2d != IPV6_ADDR_ANY : sk2->daddr)
> +						continue;
> +				} else {
> +					if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) ||
> +					    sk->rcv_saddr)
> +						continue;
> +				}
> +			}
> +			goto fail;
>  		}
>  	}
>  	sk->num = snum;
> @@ -216,28 +295,37 @@
>  
>  	for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) {
>  		if(sk->num == hnum) {
> -			int score = 0;
> +			int score;
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +			score = 0;
> +			if(sk->family == PF_INET)
> +				score++;
> +			else if (sk->net_pinfo.af_inet6.ipv6only)
> +				continue;
> +#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 +361,9 @@
>  		    (s->daddr && s->daddr!=rmt_addr)			||
>  		    (s->dport != rmt_port && s->dport != 0)			||
>  		    (s->rcv_saddr  && s->rcv_saddr != loc_addr)		||
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +		    (s->family != PF_INET && s->net_pinfo.af_inet6.ipv6only)	||
> +#endif
>  		    (s->bound_dev_if && s->bound_dev_if != dif))
>  			continue;
>  		break;
> Index: net/ipv6/addrconf.c
> ===================================================================
> RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv6/addrconf.c,v
> retrieving revision 1.1.1.1
> retrieving revision 1.1.1.1.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- net/ipv6/addrconf.c	2002/08/20 09:47:02	1.1.1.1
> +++ net/ipv6/addrconf.c	2002/09/11 03:30:27	1.1.1.1.8.1
> @@ -116,6 +116,7 @@
>  	MAX_RTR_SOLICITATIONS,		/* router solicits	*/
>  	RTR_SOLICITATION_INTERVAL,	/* rtr solicit interval	*/
>  	MAX_RTR_SOLICITATION_DELAY,	/* rtr solicit delay	*/
> +	bindv6only:		0,
>  };
>  
>  static struct ipv6_devconf ipv6_devconf_dflt =
> @@ -130,6 +131,7 @@
>  	MAX_RTR_SOLICITATIONS,		/* router solicits	*/
>  	RTR_SOLICITATION_INTERVAL,	/* rtr solicit interval	*/
>  	MAX_RTR_SOLICITATION_DELAY,	/* rtr solicit delay	*/
> +	bindv6only:		0,
>  };
>  
>  int ipv6_addr_type(struct in6_addr *addr)
> @@ -1879,7 +1881,7 @@
>  static struct addrconf_sysctl_table
>  {
>  	struct ctl_table_header *sysctl_header;
> -	ctl_table addrconf_vars[11];
> +	ctl_table addrconf_vars[12];
>  	ctl_table addrconf_dev[2];
>  	ctl_table addrconf_conf_dir[2];
>  	ctl_table addrconf_proto_dir[2];
> @@ -1925,6 +1927,10 @@
>  	{NET_IPV6_RTR_SOLICIT_DELAY, "router_solicitation_delay",
>           &ipv6_devconf.rtr_solicit_delay, sizeof(int), 0644, NULL,
>           &proc_dointvec_jiffies},
> +
> +	{NET_IPV6_BINDV6ONLY, "bindv6only",
> +	 &ipv6_devconf.bindv6only, sizeof(int), 0644, NULL,
> +	 &proc_dointvec},
>  
>  	{0}},
>  
> 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.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- net/ipv6/af_inet6.c	2002/08/20 09:47:02	1.1.1.1
> +++ net/ipv6/af_inet6.c	2002/09/11 03:30:27	1.1.1.1.8.1
> @@ -173,6 +173,8 @@
>  	sk->net_pinfo.af_inet6.mc_loop	  = 1;
>  	sk->net_pinfo.af_inet6.pmtudisc	  = IPV6_PMTUDISC_WANT;
>  
> +	sk->net_pinfo.af_inet6.ipv6only   = ipv6_devconf.bindv6only;
> +
>  	/* Init the ipv4 part of the socket since we can have sockets
>  	 * using v6 API for ipv4.
>  	 */
> @@ -248,6 +250,8 @@
>  
>  	/* Check if the address belongs to the host. */
>  	if (addr_type == IPV6_ADDR_MAPPED) {
> +		if (sk->net_pinfo.af_inet6.ipv6only)
> +			return -EADDRNOTAVAIL;
>  		v4addr = addr->sin6_addr.s6_addr32[3];
>  		if (inet_addr_type(v4addr) != RTN_LOCAL)
>  			return -EADDRNOTAVAIL;
> 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.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- net/ipv6/ipv6_sockglue.c	2002/08/20 09:47:02	1.1.1.1
> +++ net/ipv6/ipv6_sockglue.c	2002/09/11 03:30:27	1.1.1.1.8.1
> @@ -380,6 +380,15 @@
>  		retv = ipv6_flowlabel_opt(sk, optval, optlen);
>  		break;
>  
> +	case IPV6_V6ONLY:
> +		if (optlen != sizeof(int))
> +			goto e_inval;
> +		if (sk->userlocks&SOCK_BINDADDR_LOCK)
> +			goto e_inval;
> +		np->ipv6only = valbool;
> +		retv = 0;
> +		break;
> +
>  #ifdef CONFIG_NETFILTER
>  	default:
>  		retv = nf_setsockopt(sk, PF_INET6, optname, optval, 
> @@ -520,6 +529,10 @@
>  
>  	case IPV6_FLOWINFO_SEND:
>  		val = np->sndflow;
> +		break;
> +
> +	case IPV6_V6ONLY:
> +		val = np->ipv6only;
>  		break;
>  
>  	default:
> Index: net/ipv6/tcp_ipv6.c
> ===================================================================
> RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv6/tcp_ipv6.c,v
> retrieving revision 1.1.1.1
> retrieving revision 1.1.1.1.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- net/ipv6/tcp_ipv6.c	2002/08/20 09:47:02	1.1.1.1
> +++ net/ipv6/tcp_ipv6.c	2002/09/11 03:30:27	1.1.1.1.8.1
> @@ -14,6 +14,14 @@
>   *
>   *	Fixes:
>   *	Hideaki YOSHIFUJI	:	sin6_scope_id support
> + *	YOSHIFUJI Hideaki @USAGI:	Reworked bind(2) behavior, including:
> + *					- Allow ipv6 and ipv4 bind(2) to the
> + *					  same port if IPV6_V6ONLY socket
> + *					  option is set.
> + *					- Don't allow binding to the same
> + *					  address unless it is one of multi-
> + *					  cast address even if SO_REUSEADDR 
> + *					  is set.
>   *
>   *	This program is free software; you can redistribute it and/or
>   *      modify it under the terms of the GNU General Public License
> @@ -137,28 +145,70 @@
>  			goto success;
>  		} else {
>  			struct sock *sk2 = tb->owners;
> -			int sk_reuse = sk->reuse;
> -			int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr);
> +			int sk_reuse, sk2_reuse;
> +			struct in6_addr *sk_rcv_saddr6 = sk->state != TCP_TIME_WAIT ? 
> +								&sk->net_pinfo.af_inet6.rcv_saddr:
> +								&((struct tcp_tw_bucket*)sk)->v6_rcv_saddr;
> +			int addr_type = ipv6_addr_type(sk_rcv_saddr6),
> +			    addr_type2;
> +
> +			sk_reuse = 0;
> +			if (sk->reuse)
> +				sk_reuse |= 1;
>  
>  			/* We must walk the whole port owner list in this case. -DaveM */
>  			for( ; sk2 != NULL; sk2 = sk2->bind_next) {
> -				if (sk != sk2 &&
> -				    sk->bound_dev_if == sk2->bound_dev_if) {
> -					if (!sk_reuse	||
> -					    !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))
> -							break;
> +				int both_specified = 0;
> +				struct in6_addr *sk2_rcv_saddr6;
> +				if (sk2 == sk ||
> +				    (sk2->bound_dev_if && sk->bound_dev_if &&
> +				     sk2->bound_dev_if != sk->bound_dev_if))
> +					continue;
> +				sk2_rcv_saddr6 = sk2->state != TCP_TIME_WAIT ?
> +							&sk2->net_pinfo.af_inet6.rcv_saddr :
> +							&((struct tcp_tw_bucket*)sk2)->v6_rcv_saddr;
> +
> +				if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) &&
> +				    (addr_type != IPV6_ADDR_MAPPED ? addr_type != IPV6_ADDR_ANY : sk->rcv_saddr)) {
> +					if (addr_type2 == IPV6_ADDR_MAPPED || addr_type == IPV6_ADDR_MAPPED) {
> +						if (addr_type2 != addr_type ||
> +						    sk2->rcv_saddr != sk->rcv_saddr)
> +							continue;
> +					} else {
> +						if (ipv6_addr_cmp(sk2_rcv_saddr6, sk_rcv_saddr6))
> +							continue;
>  					}
> +					both_specified = 1;
>  				}
> +
> +				if ((addr_type2 == IPV6_ADDR_MAPPED &&
> +				     addr_type != IPV6_ADDR_MAPPED && sk->net_pinfo.af_inet6.ipv6only) ||
> +				    (addr_type == IPV6_ADDR_MAPPED &&
> +				     addr_type2 != IPV6_ADDR_MAPPED && sk2->net_pinfo.af_inet6.ipv6only)) {
> +					continue;
> +				}
> +
> +				sk2_reuse = 0;
> +				if (sk2->reuse)
> +					sk2_reuse |= 1;
> +
> +				if (sk2_reuse & sk_reuse & 3) { /* NOT && */
> +					ret = 1;
> +					if (both_specified) {
> +						struct in6_addr *sk2_daddr6 = sk2->state != TCP_TIME_WAIT ?
> +										&sk2->net_pinfo.af_inet6.daddr :
> +										&((struct tcp_tw_bucket*)sk2)->v6_daddr;
> +						int addr_type2d = sk2->family == AF_INET6 ? ipv6_addr_type(sk2_daddr6) : IPV6_ADDR_MAPPED;
> +						if (addr_type2d != IPV6_ADDR_MAPPED ? addr_type2d != IPV6_ADDR_ANY : sk2->daddr)
> +							continue;
> +					} else {
> +						if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) || 
> +						    (addr_type != IPV6_ADDR_MAPPED ? addr_type != IPV6_ADDR_ANY : sk->rcv_saddr))
> +							continue;
> +					}
> +				}
> +				ret = 1;
> +				goto fail_unlock;
>  			}
>  			/* If we found a conflict, fail. */
>  			ret = 1;
> @@ -601,6 +651,9 @@
>  		struct sockaddr_in sin;
>  
>  		SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
> +
> +		if (sk->net_pinfo.af_inet6.ipv6only)
> +			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.1
> retrieving revision 1.1.1.1.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- net/ipv6/udp.c	2002/08/20 09:47:02	1.1.1.1
> +++ net/ipv6/udp.c	2002/09/11 03:30:27	1.1.1.1.8.1
> @@ -11,7 +11,16 @@
>   *
>   *	Fixes:
>   *	Hideaki YOSHIFUJI	:	sin6_scope_id support
> + *	YOSHIFUJI Hideaki @USAGI:	Reworked bind(2) behavior, including:
> + *					- Allow ipv6 and ipv4 bind(2) to the
> + *					  same port if IPV6_V6ONLY socket
> + *					  option is set.
> + *					- Don't allow binding to the same
> + *					  address unless it is one of multi-
> + *					  cast address even if SO_REUSEADDR 
> + *					  is set.
>   *
> + *
>   *	This program is free software; you can redistribute it and/or
>   *      modify it under the terms of the GNU General Public License
>   *      as published by the Free Software Foundation; either version
> @@ -98,23 +107,72 @@
>  		udp_port_rover = snum = result;
>  	} else {
>  		struct sock *sk2;
> -		int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr);
> +		int sk_reuse, sk2_reuse;
> +		int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr),
> +		    addr_type2;
> +
> +		sk_reuse = 0;
> +		if (sk->reuse)
> +			sk_reuse |= 1;
> +		if (sk_reuse &&
> +		    (addr_type != IPV6_ADDR_MAPPED ? (addr_type & IPV6_ADDR_MULTICAST) : MULTICAST(sk->rcv_saddr)))
> +			sk_reuse |= 4;
>  
>  		for (sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
>  		     sk2 != NULL;
>  		     sk2 = sk2->next) {
> -			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) ||
> -			     (addr_type == IPV6_ADDR_MAPPED &&
> -			      sk2->family == AF_INET &&
> -			      sk->rcv_saddr == sk2->rcv_saddr)) &&
> -			    (!sk2->reuse || !sk->reuse))
> -				goto fail;
> +			int both_specified = 0;
> +
> +			if (sk2->num != snum ||
> +			    sk2 == sk ||
> +			    (sk2->bound_dev_if && sk->bound_dev_if &&
> +			     sk2->bound_dev_if != sk->bound_dev_if))
> +				continue;
> +
> +			addr_type2 = sk2->family == AF_INET6 ? ipv6_addr_type(&sk2->net_pinfo.af_inet6.rcv_saddr) : IPV6_ADDR_MAPPED;
> +
> +			if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) &&
> +			    (addr_type != IPV6_ADDR_MAPPED ? addr_type != IPV6_ADDR_ANY : sk->rcv_saddr)) {
> +				if (addr_type2 == IPV6_ADDR_MAPPED || addr_type == IPV6_ADDR_MAPPED) {
> +					if (addr_type2 != addr_type ||
> +					    sk2->rcv_saddr != sk->rcv_saddr)
> +						continue;
> +				} else {
> +					if (ipv6_addr_cmp(&sk2->net_pinfo.af_inet6.rcv_saddr,
> +							  &sk->net_pinfo.af_inet6.rcv_saddr))
> +						continue;
> +				}
> +				both_specified = 1;
> +			}
> +
> +			if ((addr_type2 == IPV6_ADDR_MAPPED && 
> +			     addr_type != IPV6_ADDR_MAPPED && sk->net_pinfo.af_inet6.ipv6only) ||
> +			    (addr_type == IPV6_ADDR_MAPPED &&
> +			     addr_type2 != IPV6_ADDR_MAPPED && sk2->net_pinfo.af_inet6.ipv6only)) {
> +				continue;
> +			}
> +
> +			sk2_reuse = 0;
> +			if (sk2->reuse)
> +				sk2_reuse |= 1;
> +			if (sk2_reuse &&
> +			    (addr_type2 != IPV6_ADDR_MAPPED ? (addr_type2 & IPV6_ADDR_MULTICAST) : MULTICAST(sk2->rcv_saddr)))
> +				sk2_reuse |= 4;
> +
> +			if (sk2_reuse & sk_reuse & 3) {	/* NOT && */
> +				if (sk2_reuse & sk_reuse & 4)
> +					continue;
> +				if (both_specified) {
> +					int addr_type2d = sk2->family == AF_INET6 ? ipv6_addr_type(&sk2->net_pinfo.af_inet6.daddr) : IPV6_ADDR_MAPPED;
> +					if (addr_type2d != IPV6_ADDR_MAPPED ? addr_type2d != IPV6_ADDR_ANY : sk2->daddr)
> +						continue;
> +				} else {
> +					if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) || 
> +					    (addr_type != IPV6_ADDR_MAPPED ? addr_type != IPV6_ADDR_ANY : sk->rcv_saddr))
> +						continue;
> +				}
> +			}
> +			goto fail;
>  		}
>  	}
>  
> @@ -221,6 +279,8 @@
>  	int			err;
>  
>  	if (usin->sin6_family == AF_INET) {
> +		if (sk->net_pinfo.af_inet6.ipv6only)
> +			return -EAFNOSUPPORT;
>  		err = udp_connect(sk, uaddr, addr_len);
>  		goto ipv4_connected;
>  	}
> @@ -256,6 +316,9 @@
>  	if (addr_type == IPV6_ADDR_MAPPED) {
>  		struct sockaddr_in sin;
>  
> +		if (sk->net_pinfo.af_inet6.ipv6only)
> +			return -ENETUNREACH;
> +
>  		sin.sin_family = AF_INET;
>  		sin.sin_addr.s_addr = daddr->s6_addr32[3];
>  		sin.sin_port = usin->sin6_port;
> @@ -783,8 +846,11 @@
>  	fl.oif = 0;
>  
>  	if (sin6) {
> -		if (sin6->sin6_family == AF_INET)
> +		if (sin6->sin6_family == AF_INET) {
> +			if (sk->net_pinfo.af_inet6.ipv6only)
> +				return -EAFNOSUPPORT;
>  			return udp_sendmsg(sk, msg, ulen);
> +		}
>  
>  		if (addr_len < SIN6_LEN_RFC2133)
>  			return -EINVAL;
> @@ -830,6 +896,9 @@
>  
>  	if (addr_type == IPV6_ADDR_MAPPED) {
>  		struct sockaddr_in sin;
> +
> +		if (sk->net_pinfo.af_inet6.ipv6only)
> +			return -ENETUNREACH;
>  
>  		sin.sin_family = AF_INET;
>  		sin.sin_addr.s_addr = daddr->s6_addr32[3];
> 
> 

-- 
Pekka Savola                 "Tell me of difficulties surmounted,
Netcore Oy                   not those you stumble over and fall"
Systems. Networks. Security.  -- Robert Jordan: A Crown of Swords


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port Number (IPV6_V6ONLY Support)
  2002-10-03  3:13 [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port Number (IPV6_V6ONLY Support) YOSHIFUJI Hideaki / 吉藤英明
                   ` (2 preceding siblings ...)
  2002-10-03  7:00 ` Pekka Savola
@ 2002-10-03  8:29 ` David S. Miller
  2002-10-03  8:55   ` Brad Hards
  2002-10-03 13:06   ` [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same kuznet
  2002-10-03 13:01 ` [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port kuznet
  4 siblings, 2 replies; 33+ messages in thread
From: David S. Miller @ 2002-10-03  8:29 UTC (permalink / raw)
  To: yoshfuji; +Cc: linux-kernel, netdev, usagi

   From: YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org>
   Date: Thu, 03 Oct 2002 12:13:50 +0900 (JST)

   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.  

I really wish BSD socket features did not get standardized
in RFC's, we must live with their mistakes.

For example, this IPV6_V6ONLY socket option is flawed.  What we
really need is a generic socket option which says "my family only"

There is nothing ipv6 specific about such a socket attribute.

So please, create instead "SO_ONEFAMILY" or similar generic
socket option.

I still need to review the rest of the patch for functional
correctness.  This is probably the most complex area of the
socket identity code in TCP/UDP :-)

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port Number (IPV6_V6ONLY Support)
  2002-10-03  8:29 ` David S. Miller
@ 2002-10-03  8:55   ` Brad Hards
  2002-10-03  8:58     ` David S. Miller
  2002-10-03 13:06   ` [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same kuznet
  1 sibling, 1 reply; 33+ messages in thread
From: Brad Hards @ 2002-10-03  8:55 UTC (permalink / raw)
  To: David S. Miller, yoshfuji; +Cc: linux-kernel, netdev, usagi

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Thu, 3 Oct 2002 18:29, David S. Miller wrote:
> For example, this IPV6_V6ONLY socket option is flawed.  What we
> really need is a generic socket option which says "my family only"
>
> There is nothing ipv6 specific about such a socket attribute.
>
> So please, create instead "SO_ONEFAMILY" or similar generic
> socket option.
>
> I still need to review the rest of the patch for functional
> correctness.  This is probably the most complex area of the
> socket identity code in TCP/UDP :-)
While you are grotting aroung in this area - a thought / request.

When we get IPv4 link-local autoconf addressing in widespread use, there is a 
problem on multi-homed machines.

Assume B has two network interfaces (B1 and B2) on seperate IPv4 links (net1 
and net2). Host A is on net1 and Host C is on net2. Assume that both Host A 
and Host C have the same autoconf address. So IP address is not enough 
information for Host B to use to determine which interface to use in order to 
contact Host A (instead of Host C).

If host B has socket binding on IP+port+local interface, it all works out.

Is this going to work?

Brad

- -- 
http://conf.linux.org.au. 22-25Jan2003. Perth, Aust. Tickets booked.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQE9nAXwW6pHgIdAuOMRAscOAKC/TyYdV1IOjDMlYZghhLf1mYtrKgCfbDEh
VJAdPL1Rc1Z2uM6RCIgSYOE=
=JZGw
-----END PGP SIGNATURE-----


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port Number (IPV6_V6ONLY Support)
  2002-10-03  8:55   ` Brad Hards
@ 2002-10-03  8:58     ` David S. Miller
  0 siblings, 0 replies; 33+ messages in thread
From: David S. Miller @ 2002-10-03  8:58 UTC (permalink / raw)
  To: bhards; +Cc: yoshfuji, linux-kernel, netdev, usagi

   From: Brad Hards <bhards@bigpond.net.au>
   Date: Thu, 3 Oct 2002 18:55:11 +1000

   Assume B has two network interfaces (B1 and B2) on seperate IPv4 links (net1 
   and net2). Host A is on net1 and Host C is on net2. Assume that both Host A 
   and Host C have the same autoconf address. So IP address is not enough 
   information for Host B to use to determine which interface to use in order to 
   contact Host A (instead of Host C).
   
   If host B has socket binding on IP+port+local interface, it all works out.
   
You want SO_BINDTODEVICE, which we have.

   

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port
  2002-10-03  3:13 [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port Number (IPV6_V6ONLY Support) YOSHIFUJI Hideaki / 吉藤英明
                   ` (3 preceding siblings ...)
  2002-10-03  8:29 ` David S. Miller
@ 2002-10-03 13:01 ` kuznet
  2002-10-03 14:15   ` YOSHIFUJI Hideaki / 吉藤英明
  4 siblings, 1 reply; 33+ messages in thread
From: kuznet @ 2002-10-03 13:01 UTC (permalink / raw)
  To: YOSHIFUJI Hideaki / 吉藤英明; +Cc: netdev, Dave Miller

Hello!

> We also prohibit a completely duplicate set of (local-addr, local-port,
> remote-addr, remote-port) set even if SO_REUSEADDR is set unless
> the local address is a multicast address; it is ambiguous and it may 
> steal packets from others; i.e. a kind of DoS.

This part of the patch is noop.

While doing *_get_port() daddr/dport are _unknown_ and always zero,
so it never works.

Please, remove these bits, the patch will become simpler.

What's about the problem, it cannot be a problem for TCP, connection
uniqueness is verified by tcp_*_check_established() not depending
on value of SO_REUSEADDR. What's about UDP, the problem really might
be a real problem, let's defer the issue, it looks absoluteky unrelated.


BTW the question: why is bindv6only in device configuration directory?

Alexey




> ===================================================================
> RCS file: /cvsroot/usagi/usagi-backport/linux24/include/net/if_inet6.h,v
> retrieving revision 1.1.1.1
> retrieving revision 1.1.1.1.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- include/net/if_inet6.h	2002/08/20 09:46:45	1.1.1.1
> +++ include/net/if_inet6.h	2002/09/11 03:30:27	1.1.1.1.8.1
> @@ -86,6 +86,7 @@
>  	int		rtr_solicits;
>  	int		rtr_solicit_interval;
>  	int		rtr_solicit_delay;
> +	int		bindv6only;
>  
>  	void		*sysctl;
>  };
> 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.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- include/net/sock.h	2002/08/20 09:46:45	1.1.1.1
> +++ include/net/sock.h	2002/09/11 03:30:27	1.1.1.1.8.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;
> Index: net/ipv4/tcp_ipv4.c
> ===================================================================
> RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv4/tcp_ipv4.c,v
> retrieving revision 1.1.1.1
> retrieving revision 1.1.1.1.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- net/ipv4/tcp_ipv4.c	2002/08/20 09:47:02	1.1.1.1
> +++ net/ipv4/tcp_ipv4.c	2002/09/11 03:30:27	1.1.1.1.8.1
> @@ -45,6 +45,14 @@
>   *	Vitaly E. Lavrov	:	Transparent proxy revived after year coma.
>   *	Andi Kleen		:	Fix new listen.
>   *	Andi Kleen		:	Fix accept error reporting.
> + *	YOSHIFUJI Hideaki @USAGI:	Reworked bind(2) behavior including:
> + *					- Allow ipv6 and ipv4 bind(2) to the
> + *					  same port if IPV6_V6ONLY socket option
> + *					  is set.
> + *					- Don't allow binding to the same
> + *					  address unless it is one of multi-
> + *					  cast address even if SO_REUSEADDR 
> + *					  is set.
>   */
>  
>  #include <linux/config.h>
> @@ -177,23 +185,92 @@
>  static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb)
>  {
>  	struct sock *sk2 = tb->owners;
> -	int sk_reuse = sk->reuse;
> +	int sk_reuse, sk2_reuse;
> +	int addr_type2;
> +	int ret;
> +
> +	sk_reuse = 0;
> +	if (sk->reuse)
> +		sk_reuse |= 1;
>  	
>  	for( ; sk2 != NULL; sk2 = sk2->bind_next) {
> -		if (sk != sk2 &&
> -		    sk2->reuse <= 1 &&
> -		    sk->bound_dev_if == sk2->bound_dev_if) {
> -			if (!sk_reuse	||
> -			    !sk2->reuse	||
> -			    sk2->state == TCP_LISTEN) {
> -				if (!sk2->rcv_saddr	||
> -				    !sk->rcv_saddr	||
> -				    (sk2->rcv_saddr == sk->rcv_saddr))
> -					break;
> +		int both_specified = 0;
> +
> +		if (sk2 == sk ||
> +		    (sk2->bound_dev_if && sk->bound_dev_if &&
> +		     sk2->bound_dev_if != sk->bound_dev_if))
> +			continue;
> +
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +		if (sk2->family == AF_INET6) {
> +			struct in6_addr *sk2_rcv_saddr6 = sk2->state != TCP_TIME_WAIT ?
> +				&sk2->net_pinfo.af_inet6.rcv_saddr :
> +				&((struct tcp_tw_bucket*)sk2)->v6_rcv_saddr;
> +			if (IN6_IS_ADDR_UNSPECIFIED(sk2_rcv_saddr6))
> +				addr_type2 = IPV6_ADDR_ANY;
> +			else if (IN6_IS_ADDR_V4MAPPED(sk2_rcv_saddr6))
> +				addr_type2 = IPV6_ADDR_MAPPED;
> +			else
> +				addr_type2 = IPV6_ADDR_UNICAST;	/*XXX*/
> +		} else
> +			addr_type2 = IPV6_ADDR_MAPPED;
> +#else
> +		addr_type2 = IPV6_ADDR_MAPPED;
> +#endif
> +		if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) &&
> +		    sk->rcv_saddr) {
> +			if (sk2->rcv_saddr != sk->rcv_saddr)
> +				continue;
> +			both_specified = 1;
> +		}
> +
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +		if (addr_type2 != IPV6_ADDR_MAPPED && sk2->net_pinfo.af_inet6.ipv6only) {
> +			continue;
> +		}
> +#endif
> +
> +		sk2_reuse = 0;
> +		if (sk2->reuse)
> +			sk2_reuse |= 1;
> +
> +		if (sk2_reuse & sk_reuse & 3) {	/* NOT && */
> +			ret = 1;
> +			if (both_specified) {
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +				struct in6_addr *sk2_daddr6 = sk2->state != TCP_TIME_WAIT ?
> +								&sk2->net_pinfo.af_inet6.daddr :
> +								&((struct tcp_tw_bucket*)sk2)->v6_daddr;
> +#endif
> +				int addr_type2d;
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +				if (sk2->family == AF_INET6) {
> +					if (IN6_IS_ADDR_UNSPECIFIED(sk2_daddr6))
> +						addr_type2d = IPV6_ADDR_ANY;
> +					else if (IN6_IS_ADDR_V4MAPPED(sk2_daddr6))
> +						addr_type2d = IPV6_ADDR_MAPPED;
> +					else
> +						addr_type2d = IPV6_ADDR_UNICAST; /*XXX*/
> +				} else
> +					addr_type2d = IPV6_ADDR_MAPPED;
> +#else
> +				addr_type2d = IPV6_ADDR_MAPPED;
> +#endif
> +				if (addr_type2d != IPV6_ADDR_MAPPED ? addr_type2d != IPV6_ADDR_ANY : sk2->daddr)
> +					continue;
> +			} else {
> +				if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) ||
> +				     sk->rcv_saddr)
> +					continue;
>  			}
>  		}
> +		ret = 1;
> +		goto failed;
>  	}
> -	return sk2 != NULL;
> +	/* If we found a conflict, fail. */
> +	ret = sk2 != NULL;
> +failed:
> +	return ret;
>  }
>  
>  /* Obtain a reference to a local port for the given sock,
> @@ -247,10 +324,11 @@
>  				break;
>  	}
>  	if (tb != NULL && tb->owners != NULL) {
> -		if (sk->reuse > 1)
> +		ret = 1; 
> +		if (tb->fastreuse > 0 && 
> +		    sk->reuse != 0 &&
> +		    sk->state != TCP_LISTEN) {
>  			goto success;
> -		if (tb->fastreuse > 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
> -			goto success;
>  		} else {
>  			ret = 1;
>  			if (tcp_bind_conflict(sk, tb))
> @@ -418,23 +496,31 @@
>  	struct sock *result = NULL;
>  	int score, hiscore;
>  
> -	hiscore=0;
> +	hiscore = -1;
>  	for(; sk; sk = sk->next) {
>  		if(sk->num == hnum) {
>  			__u32 rcv_saddr = sk->rcv_saddr;
>  
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +			score = 0;
> +			if (sk->family == PF_INET)
> +				score++;
> +			else if (sk->net_pinfo.af_inet6.ipv6only)
> +				continue;
> +#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 +542,10 @@
>  		if (sk->num == hnum &&
>  		    sk->next == NULL &&
>  		    (!sk->rcv_saddr || sk->rcv_saddr == daddr) &&
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +		    (sk->family == PF_INET ||
> +		     (sk->family == PF_INET6 && !sk->net_pinfo.af_inet6.ipv6only)) &&
> +#endif
>  		    !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.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- net/ipv4/udp.c	2002/08/20 09:47:02	1.1.1.1
> +++ net/ipv4/udp.c	2002/09/11 03:30:27	1.1.1.1.8.1
> @@ -61,6 +61,14 @@
>   *					return ENOTCONN for unconnected sockets (POSIX)
>   *		Janos Farkas	:	don't deliver multi/broadcasts to a different
>   *					bound-to-device socket
> + *	YOSHIFUJI Hideaki @USAGI:	Reworked bind(2) behavior, including:
> + *					- Allow ipv6 and ipv4 bind(2) to the
> + *					  same port if IPV6_V6ONLY socket opttion is
> + *					  is set.
> + *					- Don't allow binding to the same
> + *					  address unless it is one of multi-
> + *					  cast address even if SO_REUSEADDR 
> + *					  is set.
>   *
>   *
>   *		This program is free software; you can redistribute it and/or
> @@ -85,6 +93,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>
> @@ -153,18 +162,88 @@
>  		udp_port_rover = snum = result;
>  	} else {
>  		struct sock *sk2;
> +		int sk_reuse, sk2_reuse;
> +		int addr_type2;
>  
> +		sk_reuse = 0;
> +		if (sk->reuse)
> +			sk_reuse |= 1;
> +		if (sk_reuse &&
> +		    MULTICAST(sk->rcv_saddr))
> +			sk_reuse |= 4;
> +
>  		for (sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
>  		     sk2 != NULL;
>  		     sk2 = sk2->next) {
> -			if (sk2->num == snum &&
> -			    sk2 != sk &&
> -			    sk2->bound_dev_if == sk->bound_dev_if &&
> -			    (!sk2->rcv_saddr ||
> -			     !sk->rcv_saddr ||
> -			     sk2->rcv_saddr == sk->rcv_saddr) &&
> -			    (!sk2->reuse || !sk->reuse))
> -				goto fail;
> +			int both_specified = 0;
> +
> +			if (sk2->num != snum ||
> +			    sk2 == sk ||
> +			    (sk2->bound_dev_if && sk->bound_dev_if &&
> +			     sk2->bound_dev_if != sk->bound_dev_if))
> +				continue;
> +
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +			if (sk2->family == AF_INET6) {
> +				if (IN6_IS_ADDR_UNSPECIFIED(&sk2->net_pinfo.af_inet6.rcv_saddr))
> +					addr_type2 = IPV6_ADDR_ANY;
> +				else if (IN6_IS_ADDR_V4MAPPED(&sk2->net_pinfo.af_inet6.rcv_saddr))
> +					addr_type2 = IPV6_ADDR_MAPPED;
> +				else
> +					addr_type2 = IPV6_ADDR_UNICAST;	/*XXX*/
> +			} else
> +				addr_type2 = IPV6_ADDR_MAPPED;
> +#else
> +			addr_type2 = IPV6_ADDR_MAPPED;
> +#endif
> +
> +			if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) &&
> +			    sk->rcv_saddr) {
> +				if (sk2->rcv_saddr != sk->rcv_saddr)
> +					continue;
> +				both_specified = 1;
> +			}
> +
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +			if (addr_type2 != IPV6_ADDR_MAPPED && sk2->net_pinfo.af_inet6.ipv6only) {
> +				continue;
> +			}
> +#endif
> +
> +			sk2_reuse = 0;
> +			if (sk2->reuse)
> +				sk2_reuse |= 1;
> +			if (sk2_reuse &&
> +			    (addr_type2 != IPV6_ADDR_MAPPED ? (addr_type2 & IPV6_ADDR_MULTICAST) : MULTICAST(sk2->rcv_saddr)))
> +				sk2_reuse |= 4;
> +
> +			if (sk2_reuse & sk_reuse & 3) {	/* NOT && */
> +				if (sk2_reuse & sk_reuse & 4)
> +					continue;
> +				if (both_specified) {
> +					int addr_type2d;
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +					if (sk2->family == AF_INET6) {
> +						if (IN6_IS_ADDR_UNSPECIFIED(&sk2->net_pinfo.af_inet6.daddr))
> +							addr_type2d = IPV6_ADDR_ANY;
> +						else if (IN6_IS_ADDR_V4MAPPED(&sk2->net_pinfo.af_inet6.daddr))
> +							addr_type2d = IPV6_ADDR_MAPPED;
> +						else
> +							addr_type2d = IPV6_ADDR_UNICAST; /*XXX*/
> +					} else
> +						addr_type2d = IPV6_ADDR_MAPPED;
> +#else
> +					addr_type2d = IPV6_ADDR_MAPPED;
> +#endif
> +					if (addr_type2d != IPV6_ADDR_MAPPED ? addr_type2d != IPV6_ADDR_ANY : sk2->daddr)
> +						continue;
> +				} else {
> +					if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) ||
> +					    sk->rcv_saddr)
> +						continue;
> +				}
> +			}
> +			goto fail;
>  		}
>  	}
>  	sk->num = snum;
> @@ -216,28 +295,37 @@
>  
>  	for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) {
>  		if(sk->num == hnum) {
> -			int score = 0;
> +			int score;
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +			score = 0;
> +			if(sk->family == PF_INET)
> +				score++;
> +			else if (sk->net_pinfo.af_inet6.ipv6only)
> +				continue;
> +#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 +361,9 @@
>  		    (s->daddr && s->daddr!=rmt_addr)			||
>  		    (s->dport != rmt_port && s->dport != 0)			||
>  		    (s->rcv_saddr  && s->rcv_saddr != loc_addr)		||
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +		    (s->family != PF_INET && s->net_pinfo.af_inet6.ipv6only)	||
> +#endif
>  		    (s->bound_dev_if && s->bound_dev_if != dif))
>  			continue;
>  		break;
> Index: net/ipv6/addrconf.c
> ===================================================================
> RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv6/addrconf.c,v
> retrieving revision 1.1.1.1
> retrieving revision 1.1.1.1.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- net/ipv6/addrconf.c	2002/08/20 09:47:02	1.1.1.1
> +++ net/ipv6/addrconf.c	2002/09/11 03:30:27	1.1.1.1.8.1
> @@ -116,6 +116,7 @@
>  	MAX_RTR_SOLICITATIONS,		/* router solicits	*/
>  	RTR_SOLICITATION_INTERVAL,	/* rtr solicit interval	*/
>  	MAX_RTR_SOLICITATION_DELAY,	/* rtr solicit delay	*/
> +	bindv6only:		0,
>  };
>  
>  static struct ipv6_devconf ipv6_devconf_dflt =
> @@ -130,6 +131,7 @@
>  	MAX_RTR_SOLICITATIONS,		/* router solicits	*/
>  	RTR_SOLICITATION_INTERVAL,	/* rtr solicit interval	*/
>  	MAX_RTR_SOLICITATION_DELAY,	/* rtr solicit delay	*/
> +	bindv6only:		0,
>  };
>  
>  int ipv6_addr_type(struct in6_addr *addr)
> @@ -1879,7 +1881,7 @@
>  static struct addrconf_sysctl_table
>  {
>  	struct ctl_table_header *sysctl_header;
> -	ctl_table addrconf_vars[11];
> +	ctl_table addrconf_vars[12];
>  	ctl_table addrconf_dev[2];
>  	ctl_table addrconf_conf_dir[2];
>  	ctl_table addrconf_proto_dir[2];
> @@ -1925,6 +1927,10 @@
>  	{NET_IPV6_RTR_SOLICIT_DELAY, "router_solicitation_delay",
>           &ipv6_devconf.rtr_solicit_delay, sizeof(int), 0644, NULL,
>           &proc_dointvec_jiffies},
> +
> +	{NET_IPV6_BINDV6ONLY, "bindv6only",
> +	 &ipv6_devconf.bindv6only, sizeof(int), 0644, NULL,
> +	 &proc_dointvec},
>  
>  	{0}},
>  
> 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.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- net/ipv6/af_inet6.c	2002/08/20 09:47:02	1.1.1.1
> +++ net/ipv6/af_inet6.c	2002/09/11 03:30:27	1.1.1.1.8.1
> @@ -173,6 +173,8 @@
>  	sk->net_pinfo.af_inet6.mc_loop	  = 1;
>  	sk->net_pinfo.af_inet6.pmtudisc	  = IPV6_PMTUDISC_WANT;
>  
> +	sk->net_pinfo.af_inet6.ipv6only   = ipv6_devconf.bindv6only;
> +
>  	/* Init the ipv4 part of the socket since we can have sockets
>  	 * using v6 API for ipv4.
>  	 */
> @@ -248,6 +250,8 @@
>  
>  	/* Check if the address belongs to the host. */
>  	if (addr_type == IPV6_ADDR_MAPPED) {
> +		if (sk->net_pinfo.af_inet6.ipv6only)
> +			return -EADDRNOTAVAIL;
>  		v4addr = addr->sin6_addr.s6_addr32[3];
>  		if (inet_addr_type(v4addr) != RTN_LOCAL)
>  			return -EADDRNOTAVAIL;
> 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.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- net/ipv6/ipv6_sockglue.c	2002/08/20 09:47:02	1.1.1.1
> +++ net/ipv6/ipv6_sockglue.c	2002/09/11 03:30:27	1.1.1.1.8.1
> @@ -380,6 +380,15 @@
>  		retv = ipv6_flowlabel_opt(sk, optval, optlen);
>  		break;
>  
> +	case IPV6_V6ONLY:
> +		if (optlen != sizeof(int))
> +			goto e_inval;
> +		if (sk->userlocks&SOCK_BINDADDR_LOCK)
> +			goto e_inval;
> +		np->ipv6only = valbool;
> +		retv = 0;
> +		break;
> +
>  #ifdef CONFIG_NETFILTER
>  	default:
>  		retv = nf_setsockopt(sk, PF_INET6, optname, optval, 
> @@ -520,6 +529,10 @@
>  
>  	case IPV6_FLOWINFO_SEND:
>  		val = np->sndflow;
> +		break;
> +
> +	case IPV6_V6ONLY:
> +		val = np->ipv6only;
>  		break;
>  
>  	default:
> Index: net/ipv6/tcp_ipv6.c
> ===================================================================
> RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv6/tcp_ipv6.c,v
> retrieving revision 1.1.1.1
> retrieving revision 1.1.1.1.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- net/ipv6/tcp_ipv6.c	2002/08/20 09:47:02	1.1.1.1
> +++ net/ipv6/tcp_ipv6.c	2002/09/11 03:30:27	1.1.1.1.8.1
> @@ -14,6 +14,14 @@
>   *
>   *	Fixes:
>   *	Hideaki YOSHIFUJI	:	sin6_scope_id support
> + *	YOSHIFUJI Hideaki @USAGI:	Reworked bind(2) behavior, including:
> + *					- Allow ipv6 and ipv4 bind(2) to the
> + *					  same port if IPV6_V6ONLY socket
> + *					  option is set.
> + *					- Don't allow binding to the same
> + *					  address unless it is one of multi-
> + *					  cast address even if SO_REUSEADDR 
> + *					  is set.
>   *
>   *	This program is free software; you can redistribute it and/or
>   *      modify it under the terms of the GNU General Public License
> @@ -137,28 +145,70 @@
>  			goto success;
>  		} else {
>  			struct sock *sk2 = tb->owners;
> -			int sk_reuse = sk->reuse;
> -			int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr);
> +			int sk_reuse, sk2_reuse;
> +			struct in6_addr *sk_rcv_saddr6 = sk->state != TCP_TIME_WAIT ? 
> +								&sk->net_pinfo.af_inet6.rcv_saddr:
> +								&((struct tcp_tw_bucket*)sk)->v6_rcv_saddr;
> +			int addr_type = ipv6_addr_type(sk_rcv_saddr6),
> +			    addr_type2;
> +
> +			sk_reuse = 0;
> +			if (sk->reuse)
> +				sk_reuse |= 1;
>  
>  			/* We must walk the whole port owner list in this case. -DaveM */
>  			for( ; sk2 != NULL; sk2 = sk2->bind_next) {
> -				if (sk != sk2 &&
> -				    sk->bound_dev_if == sk2->bound_dev_if) {
> -					if (!sk_reuse	||
> -					    !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))
> -							break;
> +				int both_specified = 0;
> +				struct in6_addr *sk2_rcv_saddr6;
> +				if (sk2 == sk ||
> +				    (sk2->bound_dev_if && sk->bound_dev_if &&
> +				     sk2->bound_dev_if != sk->bound_dev_if))
> +					continue;
> +				sk2_rcv_saddr6 = sk2->state != TCP_TIME_WAIT ?
> +							&sk2->net_pinfo.af_inet6.rcv_saddr :
> +							&((struct tcp_tw_bucket*)sk2)->v6_rcv_saddr;
> +
> +				if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) &&
> +				    (addr_type != IPV6_ADDR_MAPPED ? addr_type != IPV6_ADDR_ANY : sk->rcv_saddr)) {
> +					if (addr_type2 == IPV6_ADDR_MAPPED || addr_type == IPV6_ADDR_MAPPED) {
> +						if (addr_type2 != addr_type ||
> +						    sk2->rcv_saddr != sk->rcv_saddr)
> +							continue;
> +					} else {
> +						if (ipv6_addr_cmp(sk2_rcv_saddr6, sk_rcv_saddr6))
> +							continue;
>  					}
> +					both_specified = 1;
>  				}
> +
> +				if ((addr_type2 == IPV6_ADDR_MAPPED &&
> +				     addr_type != IPV6_ADDR_MAPPED && sk->net_pinfo.af_inet6.ipv6only) ||
> +				    (addr_type == IPV6_ADDR_MAPPED &&
> +				     addr_type2 != IPV6_ADDR_MAPPED && sk2->net_pinfo.af_inet6.ipv6only)) {
> +					continue;
> +				}
> +
> +				sk2_reuse = 0;
> +				if (sk2->reuse)
> +					sk2_reuse |= 1;
> +
> +				if (sk2_reuse & sk_reuse & 3) { /* NOT && */
> +					ret = 1;
> +					if (both_specified) {
> +						struct in6_addr *sk2_daddr6 = sk2->state != TCP_TIME_WAIT ?
> +										&sk2->net_pinfo.af_inet6.daddr :
> +										&((struct tcp_tw_bucket*)sk2)->v6_daddr;
> +						int addr_type2d = sk2->family == AF_INET6 ? ipv6_addr_type(sk2_daddr6) : IPV6_ADDR_MAPPED;
> +						if (addr_type2d != IPV6_ADDR_MAPPED ? addr_type2d != IPV6_ADDR_ANY : sk2->daddr)
> +							continue;
> +					} else {
> +						if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) || 
> +						    (addr_type != IPV6_ADDR_MAPPED ? addr_type != IPV6_ADDR_ANY : sk->rcv_saddr))
> +							continue;
> +					}
> +				}
> +				ret = 1;
> +				goto fail_unlock;
>  			}
>  			/* If we found a conflict, fail. */
>  			ret = 1;
> @@ -601,6 +651,9 @@
>  		struct sockaddr_in sin;
>  
>  		SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
> +
> +		if (sk->net_pinfo.af_inet6.ipv6only)
> +			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.1
> retrieving revision 1.1.1.1.8.1
> diff -u -r1.1.1.1 -r1.1.1.1.8.1
> --- net/ipv6/udp.c	2002/08/20 09:47:02	1.1.1.1
> +++ net/ipv6/udp.c	2002/09/11 03:30:27	1.1.1.1.8.1
> @@ -11,7 +11,16 @@
>   *
>   *	Fixes:
>   *	Hideaki YOSHIFUJI	:	sin6_scope_id support
> + *	YOSHIFUJI Hideaki @USAGI:	Reworked bind(2) behavior, including:
> + *					- Allow ipv6 and ipv4 bind(2) to the
> + *					  same port if IPV6_V6ONLY socket
> + *					  option is set.
> + *					- Don't allow binding to the same
> + *					  address unless it is one of multi-
> + *					  cast address even if SO_REUSEADDR 
> + *					  is set.
>   *
> + *
>   *	This program is free software; you can redistribute it and/or
>   *      modify it under the terms of the GNU General Public License
>   *      as published by the Free Software Foundation; either version
> @@ -98,23 +107,72 @@
>  		udp_port_rover = snum = result;
>  	} else {
>  		struct sock *sk2;
> -		int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr);
> +		int sk_reuse, sk2_reuse;
> +		int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr),
> +		    addr_type2;
> +
> +		sk_reuse = 0;
> +		if (sk->reuse)
> +			sk_reuse |= 1;
> +		if (sk_reuse &&
> +		    (addr_type != IPV6_ADDR_MAPPED ? (addr_type & IPV6_ADDR_MULTICAST) : MULTICAST(sk->rcv_saddr)))
> +			sk_reuse |= 4;
>  
>  		for (sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
>  		     sk2 != NULL;
>  		     sk2 = sk2->next) {
> -			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) ||
> -			     (addr_type == IPV6_ADDR_MAPPED &&
> -			      sk2->family == AF_INET &&
> -			      sk->rcv_saddr == sk2->rcv_saddr)) &&
> -			    (!sk2->reuse || !sk->reuse))
> -				goto fail;
> +			int both_specified = 0;
> +
> +			if (sk2->num != snum ||
> +			    sk2 == sk ||
> +			    (sk2->bound_dev_if && sk->bound_dev_if &&
> +			     sk2->bound_dev_if != sk->bound_dev_if))
> +				continue;
> +
> +			addr_type2 = sk2->family == AF_INET6 ? ipv6_addr_type(&sk2->net_pinfo.af_inet6.rcv_saddr) : IPV6_ADDR_MAPPED;
> +
> +			if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) &&
> +			    (addr_type != IPV6_ADDR_MAPPED ? addr_type != IPV6_ADDR_ANY : sk->rcv_saddr)) {
> +				if (addr_type2 == IPV6_ADDR_MAPPED || addr_type == IPV6_ADDR_MAPPED) {
> +					if (addr_type2 != addr_type ||
> +					    sk2->rcv_saddr != sk->rcv_saddr)
> +						continue;
> +				} else {
> +					if (ipv6_addr_cmp(&sk2->net_pinfo.af_inet6.rcv_saddr,
> +							  &sk->net_pinfo.af_inet6.rcv_saddr))
> +						continue;
> +				}
> +				both_specified = 1;
> +			}
> +
> +			if ((addr_type2 == IPV6_ADDR_MAPPED && 
> +			     addr_type != IPV6_ADDR_MAPPED && sk->net_pinfo.af_inet6.ipv6only) ||
> +			    (addr_type == IPV6_ADDR_MAPPED &&
> +			     addr_type2 != IPV6_ADDR_MAPPED && sk2->net_pinfo.af_inet6.ipv6only)) {
> +				continue;
> +			}
> +
> +			sk2_reuse = 0;
> +			if (sk2->reuse)
> +				sk2_reuse |= 1;
> +			if (sk2_reuse &&
> +			    (addr_type2 != IPV6_ADDR_MAPPED ? (addr_type2 & IPV6_ADDR_MULTICAST) : MULTICAST(sk2->rcv_saddr)))
> +				sk2_reuse |= 4;
> +
> +			if (sk2_reuse & sk_reuse & 3) {	/* NOT && */
> +				if (sk2_reuse & sk_reuse & 4)
> +					continue;
> +				if (both_specified) {
> +					int addr_type2d = sk2->family == AF_INET6 ? ipv6_addr_type(&sk2->net_pinfo.af_inet6.daddr) : IPV6_ADDR_MAPPED;
> +					if (addr_type2d != IPV6_ADDR_MAPPED ? addr_type2d != IPV6_ADDR_ANY : sk2->daddr)
> +						continue;
> +				} else {
> +					if ((addr_type2 != IPV6_ADDR_MAPPED ? addr_type2 != IPV6_ADDR_ANY : sk2->rcv_saddr) || 
> +					    (addr_type != IPV6_ADDR_MAPPED ? addr_type != IPV6_ADDR_ANY : sk->rcv_saddr))
> +						continue;
> +				}
> +			}
> +			goto fail;
>  		}
>  	}
>  
> @@ -221,6 +279,8 @@
>  	int			err;
>  
>  	if (usin->sin6_family == AF_INET) {
> +		if (sk->net_pinfo.af_inet6.ipv6only)
> +			return -EAFNOSUPPORT;
>  		err = udp_connect(sk, uaddr, addr_len);
>  		goto ipv4_connected;
>  	}
> @@ -256,6 +316,9 @@
>  	if (addr_type == IPV6_ADDR_MAPPED) {
>  		struct sockaddr_in sin;
>  
> +		if (sk->net_pinfo.af_inet6.ipv6only)
> +			return -ENETUNREACH;
> +
>  		sin.sin_family = AF_INET;
>  		sin.sin_addr.s_addr = daddr->s6_addr32[3];
>  		sin.sin_port = usin->sin6_port;
> @@ -783,8 +846,11 @@
>  	fl.oif = 0;
>  
>  	if (sin6) {
> -		if (sin6->sin6_family == AF_INET)
> +		if (sin6->sin6_family == AF_INET) {
> +			if (sk->net_pinfo.af_inet6.ipv6only)
> +				return -EAFNOSUPPORT;
>  			return udp_sendmsg(sk, msg, ulen);
> +		}
>  
>  		if (addr_len < SIN6_LEN_RFC2133)
>  			return -EINVAL;
> @@ -830,6 +896,9 @@
>  
>  	if (addr_type == IPV6_ADDR_MAPPED) {
>  		struct sockaddr_in sin;
> +
> +		if (sk->net_pinfo.af_inet6.ipv6only)
> +			return -ENETUNREACH;
>  
>  		sin.sin_family = AF_INET;
>  		sin.sin_addr.s_addr = daddr->s6_addr32[3];
> 
> 
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same
  2002-10-03 13:06   ` [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same kuznet
@ 2002-10-03 13:02     ` David S. Miller
  2002-10-03 13:18       ` Pekka Savola
  0 siblings, 1 reply; 33+ messages in thread
From: David S. Miller @ 2002-10-03 13:02 UTC (permalink / raw)
  To: kuznet; +Cc: netdev

   From: kuznet@ms2.inr.ac.ru
   Date: Thu, 3 Oct 2002 17:06:48 +0400 (MSD)

   No, really! __Sharing__ of port space between IPv4 and IPv6 was mad
   idea. It cannot generalized to other protocol families.
   
   So, IPV6_V6ONLY is really unique for IPv6. Well, actually, it could
   be negated: be default and the option would be called
   IPV6_SHARE_THIS_PORT_TO_IPV4.

I think what I want to really say is that I want to provide
way for ipv4 application to say "no ipv6 connections on this
listening socket please".

So does it make no sense at all to have IP_V4ONLY?

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same
  2002-10-03  8:29 ` David S. Miller
  2002-10-03  8:55   ` Brad Hards
@ 2002-10-03 13:06   ` kuznet
  2002-10-03 13:02     ` David S. Miller
  1 sibling, 1 reply; 33+ messages in thread
From: kuznet @ 2002-10-03 13:06 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev

Hello!

> For example, this IPV6_V6ONLY socket option is flawed.  What we
> really need is a generic socket option which says "my family only"
> 
> There is nothing ipv6 specific about such a socket attribute.
> 
> So please, create instead "SO_ONEFAMILY" or similar generic
> socket option.

No, really! __Sharing__ of port space between IPv4 and IPv6 was mad
idea. It cannot generalized to other protocol families.

So, IPV6_V6ONLY is really unique for IPv6. Well, actually, it could
be negated: be default and the option would be called
IPV6_SHARE_THIS_PORT_TO_IPV4.

Alexey

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same
  2002-10-03 13:18       ` Pekka Savola
@ 2002-10-03 13:13         ` David S. Miller
  0 siblings, 0 replies; 33+ messages in thread
From: David S. Miller @ 2002-10-03 13:13 UTC (permalink / raw)
  To: pekkas; +Cc: kuznet, netdev

   From: Pekka Savola <pekkas@netcore.fi>
   Date: Thu, 3 Oct 2002 16:18:53 +0300 (EEST)

   On Thu, 3 Oct 2002, David S. Miller wrote:
   > So does it make no sense at all to have IP_V4ONLY?
   
   Umm, I think an app guy can do that with creating an AF_INET socket; there 
   will not be IPv6 there.  Folks Who Think They Know Best decided that dual 
   use for AF_INET6 would be best, and IPV6_V6ONLY was invented (note: it'd 
   already implemented by some others) to repair that.

Ok, ignore my silly idea then.

Let us continue with verifying correctness of the USAGI
patch.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same
  2002-10-03 13:02     ` David S. Miller
@ 2002-10-03 13:18       ` Pekka Savola
  2002-10-03 13:13         ` David S. Miller
  0 siblings, 1 reply; 33+ messages in thread
From: Pekka Savola @ 2002-10-03 13:18 UTC (permalink / raw)
  To: David S. Miller; +Cc: kuznet, netdev

On Thu, 3 Oct 2002, David S. Miller wrote:
>    From: kuznet@ms2.inr.ac.ru
>    Date: Thu, 3 Oct 2002 17:06:48 +0400 (MSD)
> 
>    No, really! __Sharing__ of port space between IPv4 and IPv6 was mad
>    idea. It cannot generalized to other protocol families.
>    
>    So, IPV6_V6ONLY is really unique for IPv6. Well, actually, it could
>    be negated: be default and the option would be called
>    IPV6_SHARE_THIS_PORT_TO_IPV4.
> 
> I think what I want to really say is that I want to provide
> way for ipv4 application to say "no ipv6 connections on this
> listening socket please".
> 
> So does it make no sense at all to have IP_V4ONLY?

Umm, I think an app guy can do that with creating an AF_INET socket; there 
will not be IPv6 there.  Folks Who Think They Know Best decided that dual 
use for AF_INET6 would be best, and IPV6_V6ONLY was invented (note: it'd 
already implemented by some others) to repair that.

-- 
Pekka Savola                 "Tell me of difficulties surmounted,
Netcore Oy                   not those you stumble over and fall"
Systems. Networks. Security.  -- Robert Jordan: A Crown of Swords

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port
  2002-10-03 14:15   ` YOSHIFUJI Hideaki / 吉藤英明
@ 2002-10-03 14:10     ` David S. Miller
  2002-10-03 15:06     ` YOSHIFUJI Hideaki / 吉藤英明
  1 sibling, 0 replies; 33+ messages in thread
From: David S. Miller @ 2002-10-03 14:10 UTC (permalink / raw)
  To: yoshfuji; +Cc: kuznet, netdev, usagi

   From: YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org>
   Date: Thu, 03 Oct 2002 23:15:34 +0900 (JST)

   In article <200210031301.RAA29267@sex.inr.ac.ru> (at Thu, 3 Oct 2002 17:01:11 +0400 (MSD)), kuznet@ms2.inr.ac.ru says:
   
   > What's about the problem, it cannot be a problem for TCP, connection
   > uniqueness is verified by tcp_*_check_established() not depending
   > on value of SO_REUSEADDR. What's about UDP, the problem really might
   > be a real problem, let's defer the issue, it looks absoluteky unrelated.
   
   Hmm, but I'm afraid that different behavior between TCP and UDP would
   confuse users.
   
He is saying we should do the TCP part first to make the patch simpler
and easier to verify.

Then we can investigate the UDP side seperately.
   
   > BTW the question: why is bindv6only in device configuration directory?
   
   Because I thought that net.ipv6.conf is the place for all 
   configuration...

It is for interface level configuration.
   
   Do you propose to move it to parent directory (net.ipv6.bindv6only),
   and put other general settings there?
   
Yes.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port
  2002-10-03 13:01 ` [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port kuznet
@ 2002-10-03 14:15   ` YOSHIFUJI Hideaki / 吉藤英明
  2002-10-03 14:10     ` David S. Miller
  2002-10-03 15:06     ` YOSHIFUJI Hideaki / 吉藤英明
  0 siblings, 2 replies; 33+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2002-10-03 14:15 UTC (permalink / raw)
  To: kuznet; +Cc: netdev, davem, usagi

In article <200210031301.RAA29267@sex.inr.ac.ru> (at Thu, 3 Oct 2002 17:01:11 +0400 (MSD)), kuznet@ms2.inr.ac.ru says:

> While doing *_get_port() daddr/dport are _unknown_ and always zero,
> so it never works.
> 
> Please, remove these bits, the patch will become simpler.

Ok, I'll do that.


> What's about the problem, it cannot be a problem for TCP, connection
> uniqueness is verified by tcp_*_check_established() not depending
> on value of SO_REUSEADDR. What's about UDP, the problem really might
> be a real problem, let's defer the issue, it looks absoluteky unrelated.

Hmm, but I'm afraid that different behavior between TCP and UDP would
confuse users.


> BTW the question: why is bindv6only in device configuration directory?

Because I thought that net.ipv6.conf is the place for all 
configuration...

Do you propose to move it to parent directory (net.ipv6.bindv6only),
and put other general settings there?

--yoshfuji

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port
  2002-10-03 15:06     ` YOSHIFUJI Hideaki / 吉藤英明
@ 2002-10-03 15:04       ` David S. Miller
  2002-10-03 15:19         ` YOSHIFUJI Hideaki / 吉藤英明
  0 siblings, 1 reply; 33+ messages in thread
From: David S. Miller @ 2002-10-03 15:04 UTC (permalink / raw)
  To: yoshfuji; +Cc: kuznet, netdev, usagi

   From: YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org>
   Date: Fri, 04 Oct 2002 00:06:31 +0900 (JST)

   In article <20021003.231534.83777766.yoshfuji@linux-ipv6.org> (at Thu, 03 Oct 2002 23:15:34 +0900 (JST)), YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org> says:
   
   > In article <200210031301.RAA29267@sex.inr.ac.ru> (at Thu, 3 Oct 2002 17:01:11 +0400 (MSD)), kuznet@ms2.inr.ac.ru says:
   > 
   > > While doing *_get_port() daddr/dport are _unknown_ and always zero,
   > > so it never works.
   > > 
   > > Please, remove these bits, the patch will become simpler.
   > 
   > Ok, I'll do that.
   
   I remember that test for daddr is for existing sockets, 
   not for socket doing XXX_get_port().
   So, I think I don't need to remove that.

Where can daddr/dport be non-zero during get_port()?

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port
  2002-10-03 14:15   ` YOSHIFUJI Hideaki / 吉藤英明
  2002-10-03 14:10     ` David S. Miller
@ 2002-10-03 15:06     ` YOSHIFUJI Hideaki / 吉藤英明
  2002-10-03 15:04       ` David S. Miller
  1 sibling, 1 reply; 33+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2002-10-03 15:06 UTC (permalink / raw)
  To: kuznet; +Cc: netdev, davem, usagi

In article <20021003.231534.83777766.yoshfuji@linux-ipv6.org> (at Thu, 03 Oct 2002 23:15:34 +0900 (JST)), YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org> says:

> In article <200210031301.RAA29267@sex.inr.ac.ru> (at Thu, 3 Oct 2002 17:01:11 +0400 (MSD)), kuznet@ms2.inr.ac.ru says:
> 
> > While doing *_get_port() daddr/dport are _unknown_ and always zero,
> > so it never works.
> > 
> > Please, remove these bits, the patch will become simpler.
> 
> Ok, I'll do that.

I remember that test for daddr is for existing sockets, 
not for socket doing XXX_get_port().
So, I think I don't need to remove that.

--yoshfuji

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port
  2002-10-03 15:04       ` David S. Miller
@ 2002-10-03 15:19         ` YOSHIFUJI Hideaki / 吉藤英明
  2002-10-03 15:52           ` kuznet
  0 siblings, 1 reply; 33+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2002-10-03 15:19 UTC (permalink / raw)
  To: davem; +Cc: kuznet, netdev, usagi

In article <20021003.080408.78030688.davem@redhat.com> (at Thu, 03 Oct 2002 08:04:08 -0700 (PDT)), "David S. Miller" <davem@redhat.com> says:

>    I remember that test for daddr is for existing sockets, 
>    not for socket doing XXX_get_port().
>    So, I think I don't need to remove that.
> 
> Where can daddr/dport be non-zero during get_port()?

test for daddr if for sk2.
sk2 is iterator for existing sockets, which can be "connected."
daddr can be non-zero, can't it?
Am I wrong???

--yoshfuji

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port
  2002-10-03 15:19         ` YOSHIFUJI Hideaki / 吉藤英明
@ 2002-10-03 15:52           ` kuznet
  2002-10-23  7:24             ` [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port) YOSHIFUJI Hideaki / 吉藤英明
  0 siblings, 1 reply; 33+ messages in thread
From: kuznet @ 2002-10-03 15:52 UTC (permalink / raw)
  To: YOSHIFUJI Hideaki / 吉藤英明; +Cc: davem, netdev, usagi

Hello!

> test for daddr if for sk2.
> sk2 is iterator for existing sockets, which can be "connected."
> daddr can be non-zero, can't it?
> Am I wrong???

You are absolutely right.

But then I am put to coma. Now I do not understand the goal of the check.
Can you give a simple example showing what illegal case this check is supposed
to eliminate?

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. :-)

Alexey

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port)
  2002-10-23  7:24             ` [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port) YOSHIFUJI Hideaki / 吉藤英明
@ 2002-10-23  7:23               ` David S. Miller
  2002-10-23  7:58                 ` YOSHIFUJI Hideaki / 吉藤英明
  2002-10-23  7:36               ` Pekka Savola
                                 ` (2 subsequent siblings)
  3 siblings, 1 reply; 33+ messages in thread
From: David S. Miller @ 2002-10-23  7:23 UTC (permalink / raw)
  To: yoshfuji; +Cc: kuznet, netdev, usagi

   From: YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org>
   Date: Wed, 23 Oct 2002 16:24:39 +0900 (JST)
   
   Well, I've refered alexey's patch and simplified many if-clauses.
   Here's the new patch and test results.  seems ok.

So, because you simplified some if clauses in Alexey's patch, USAGI is
the only entity who deserves credit for the work in the comments?

That's dishonest.  Please fix this.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port)
  2002-10-03 15:52           ` kuznet
@ 2002-10-23  7:24             ` YOSHIFUJI Hideaki / 吉藤英明
  2002-10-23  7:23               ` David S. Miller
                                 ` (3 more replies)
  0 siblings, 4 replies; 33+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2002-10-23  7:24 UTC (permalink / raw)
  To: kuznet; +Cc: davem, netdev, usagi

In article <200210031552.TAA29921@sex.inr.ac.ru> (at Thu, 3 Oct 2002 19:52:40 +0400 (MSD)), kuznet@ms2.inr.ac.ru 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@linux-ipv6.org>
Credit: YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
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];

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port)
  2002-10-23  7:24             ` [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port) YOSHIFUJI Hideaki / 吉藤英明
  2002-10-23  7:23               ` David S. Miller
@ 2002-10-23  7:36               ` Pekka Savola
  2002-10-23 10:01                 ` YOSHIFUJI Hideaki / 吉藤英明
  2002-10-23 15:53               ` [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port) Kyle C Quest
  2002-10-24 10:24               ` David S. Miller
  3 siblings, 1 reply; 33+ messages in thread
From: Pekka Savola @ 2002-10-23  7:36 UTC (permalink / raw)
  To: YOSHIFUJI Hideaki / 吉藤英明
  Cc: kuznet, davem, netdev, usagi

Overview looks good.

Does Bind 9.2.1 work this so that it can receive packets, when IPv6 is
also enabled, from IPv4 addresses using TCP without
'match-mapped-addresses yes', or is that a separate problem?

(with IPV6_V6ONLY if supported that would work all right.)

On Wed, 23 Oct 2002, YOSHIFUJI Hideaki / [iso-2022-jp] ^[$B5HF#1QL@^[(B wrote:

> In article <200210031552.TAA29921@sex.inr.ac.ru> (at Thu, 3 Oct 2002 19:52:40 +0400 (MSD)), kuznet@ms2.inr.ac.ru 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@linux-ipv6.org>
> Credit: YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
> 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];
> 
> 

-- 
Pekka Savola                 "Tell me of difficulties surmounted,
Netcore Oy                   not those you stumble over and fall"
Systems. Networks. Security.  -- Robert Jordan: A Crown of Swords

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port)
  2002-10-23  7:23               ` David S. Miller
@ 2002-10-23  7:58                 ` YOSHIFUJI Hideaki / 吉藤英明
  2002-10-23  8:06                   ` YOSHIFUJI Hideaki / 吉藤英明
  0 siblings, 1 reply; 33+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2002-10-23  7:58 UTC (permalink / raw)
  To: davem; +Cc: kuznet, netdev, usagi

In article <20021023.002303.67097780.davem@redhat.com> (at Wed, 23 Oct 2002 00:23:03 -0700 (PDT)), "David S. Miller" <davem@redhat.com> says:

> So, because you simplified some if clauses in Alexey's patch, USAGI is
> the only entity who deserves credit for the work in the comments?
> 
> That's dishonest.  Please fix this.

Hmm, we simplified our patch based on original linux kernel.
In fact, I use ipv6_only_sock() from his patch.
Sorry about that, apply this agaist that patch:

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.16.2
diff -u -r1.1.1.2.16.2 tcp_ipv4.c
--- net/ipv4/tcp_ipv4.c	22 Oct 2002 19:40:48 -0000	1.1.1.2.16.2
+++ net/ipv4/tcp_ipv4.c	23 Oct 2002 07:46:23 -0000
@@ -45,8 +45,8 @@
  *	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
+ *	YOSHIFUJI Hideaki @USAGI and:	Support IPV6_V6ONLY socket option, which
+ *	and Alexey Kuznetsov		allow both IPv4 and IPv6 sockets to bind
  *					a single port at the same time.
  */
 
Index: net/ipv4/udp.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv4/udp.c,v
retrieving revision 1.1.1.1.40.1
diff -u -r1.1.1.1.40.1 udp.c
--- net/ipv4/udp.c	22 Oct 2002 19:19:48 -0000	1.1.1.1.40.1
+++ net/ipv4/udp.c	23 Oct 2002 07:46:23 -0000
@@ -61,8 +61,8 @@
  *					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
+ *	YOSHIFUJI Hideaki @USAGI and:	Support IPV6_V6ONLY socket option, which
+ *	and Alexey Kuznetsov:		allow both IPv4 and IPv6 sockets to bind
  *					a single port at the same time.
  *
  *
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.16.1
diff -u -r1.1.1.2.16.1 tcp_ipv6.c
--- net/ipv6/tcp_ipv6.c	22 Oct 2002 19:19:48 -0000	1.1.1.2.16.1
+++ net/ipv6/tcp_ipv6.c	23 Oct 2002 07:46:23 -0000
@@ -14,8 +14,8 @@
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
- *	YOSHIFUJI Hideaki @USAGI:	Support IPV6_V6ONLY socket option, which
- *					allow both IPv4 and IPv6 sockets to bind
+ *	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
Index: net/ipv6/udp.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv6/udp.c,v
retrieving revision 1.1.1.2.16.1
diff -u -r1.1.1.2.16.1 udp.c
--- net/ipv6/udp.c	22 Oct 2002 19:19:48 -0000	1.1.1.2.16.1
+++ net/ipv6/udp.c	23 Oct 2002 07:46:23 -0000
@@ -11,8 +11,8 @@
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
- *	YOSHIFUJI Hideaki @USAGI:	Support IPV6_V6ONLY socket option, which
- *					allow both IPv4 and IPv6 sockets to bind
+ *	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

-- 
Hideaki YOSHIFUJI @ USAGI Project <yoshfuji@linux-ipv6.org>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF  80D8 4807 F894 E062 0EEA

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port)
  2002-10-23  8:06                   ` YOSHIFUJI Hideaki / 吉藤英明
@ 2002-10-23  8:02                     ` David S. Miller
  0 siblings, 0 replies; 33+ messages in thread
From: David S. Miller @ 2002-10-23  8:02 UTC (permalink / raw)
  To: yoshfuji; +Cc: kuznet, netdev, usagi

   From: YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org>
   Date: Wed, 23 Oct 2002 17:06:00 +0900 (JST)

   oops, typo.  please use this instead:
   
Thank you.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port)
  2002-10-23  7:58                 ` YOSHIFUJI Hideaki / 吉藤英明
@ 2002-10-23  8:06                   ` YOSHIFUJI Hideaki / 吉藤英明
  2002-10-23  8:02                     ` David S. Miller
  0 siblings, 1 reply; 33+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2002-10-23  8:06 UTC (permalink / raw)
  To: davem; +Cc: kuznet, netdev, usagi

In article <20021023.165832.11432472.yoshfuji@linux-ipv6.org> (at Wed, 23 Oct 2002 16:58:32 +0900 (JST)), YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org> says:

> Sorry about that, apply this agaist that patch:

oops, typo.  please use this instead:

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.16.2
diff -u -r1.1.1.2.16.2 tcp_ipv4.c
--- net/ipv4/tcp_ipv4.c	22 Oct 2002 19:40:48 -0000	1.1.1.2.16.2
+++ net/ipv4/tcp_ipv4.c	23 Oct 2002 08:03:09 -0000
@@ -45,8 +45,8 @@
  *	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
+ *	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.
  */
 
Index: net/ipv4/udp.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv4/udp.c,v
retrieving revision 1.1.1.1.40.1
diff -u -r1.1.1.1.40.1 udp.c
--- net/ipv4/udp.c	22 Oct 2002 19:19:48 -0000	1.1.1.1.40.1
+++ net/ipv4/udp.c	23 Oct 2002 08:03:09 -0000
@@ -61,8 +61,8 @@
  *					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
+ *	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.
  *
  *
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.16.1
diff -u -r1.1.1.2.16.1 tcp_ipv6.c
--- net/ipv6/tcp_ipv6.c	22 Oct 2002 19:19:48 -0000	1.1.1.2.16.1
+++ net/ipv6/tcp_ipv6.c	23 Oct 2002 08:03:09 -0000
@@ -14,8 +14,8 @@
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
- *	YOSHIFUJI Hideaki @USAGI:	Support IPV6_V6ONLY socket option, which
- *					allow both IPv4 and IPv6 sockets to bind
+ *	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
Index: net/ipv6/udp.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv6/udp.c,v
retrieving revision 1.1.1.2.16.1
diff -u -r1.1.1.2.16.1 udp.c
--- net/ipv6/udp.c	22 Oct 2002 19:19:48 -0000	1.1.1.2.16.1
+++ net/ipv6/udp.c	23 Oct 2002 08:03:09 -0000
@@ -11,8 +11,8 @@
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
- *	YOSHIFUJI Hideaki @USAGI:	Support IPV6_V6ONLY socket option, which
- *					allow both IPv4 and IPv6 sockets to bind
+ *	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

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port)
  2002-10-23  7:36               ` Pekka Savola
@ 2002-10-23 10:01                 ` YOSHIFUJI Hideaki / 吉藤英明
  2002-10-23 10:15                   ` Pekka Savola
  0 siblings, 1 reply; 33+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2002-10-23 10:01 UTC (permalink / raw)
  To: pekkas; +Cc: kuznet, davem, netdev, usagi

In article <Pine.LNX.4.44.0210231031540.26788-100000@netcore.fi> (at Wed, 23 Oct 2002 10:36:19 +0300 (EEST)), Pekka Savola <pekkas@netcore.fi> says:

> Does Bind 9.2.1 work this so that it can receive packets, when IPv6 is
> also enabled, from IPv4 addresses using TCP without
> 'match-mapped-addresses yes', or is that a separate problem?

Bind9 trys to bind :: and all ipv4 addresses on the node.

-- 
Hideaki YOSHIFUJI @ USAGI Project <yoshfuji@linux-ipv6.org>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF  80D8 4807 F894 E062 0EEA

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port)
  2002-10-23 10:15                   ` Pekka Savola
@ 2002-10-23 10:12                     ` David S. Miller
  2002-10-24 16:24                     ` [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both kuznet
  1 sibling, 0 replies; 33+ messages in thread
From: David S. Miller @ 2002-10-23 10:12 UTC (permalink / raw)
  To: pekkas; +Cc: yoshfuji, kuznet, netdev, usagi

   From: Pekka Savola <pekkas@netcore.fi>
   Date: Wed, 23 Oct 2002 13:15:26 +0300 (EEST)
   
   Will this work too?
   
It should work as a side effect of the USAGI patch.

Because when bind9 does ipv6only bind on wildcarded ipv6,
the ipv4 specific IP binds will then be allowed.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port)
  2002-10-23 10:01                 ` YOSHIFUJI Hideaki / 吉藤英明
@ 2002-10-23 10:15                   ` Pekka Savola
  2002-10-23 10:12                     ` David S. Miller
  2002-10-24 16:24                     ` [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both kuznet
  0 siblings, 2 replies; 33+ messages in thread
From: Pekka Savola @ 2002-10-23 10:15 UTC (permalink / raw)
  To: YOSHIFUJI Hideaki / 吉藤英明
  Cc: kuznet, davem, netdev, usagi

On Wed, 23 Oct 2002, YOSHIFUJI Hideaki / [iso-2022-jp] ^[$B5HF#1QL@^[(B wrote:
> In article <Pine.LNX.4.44.0210231031540.26788-100000@netcore.fi> (at Wed, 23 Oct 2002 10:36:19 +0300 (EEST)), Pekka Savola <pekkas@netcore.fi> says:
> 
> > Does Bind 9.2.1 work this so that it can receive packets, when IPv6 is
> > also enabled, from IPv4 addresses using TCP without
> > 'match-mapped-addresses yes', or is that a separate problem?
> 
> Bind9 trys to bind :: and all ipv4 addresses on the node.

Yes, but binding those IPv4 addresses _for TCP_ failed after binding to 
::, at least previously.  That worked e.g. on BSD.  Does that work now, 
too?

I.e. I have two boxes, both running Bind 9.2.1.  Linux gives:

$ netstat -an | grep :53
tcp        0      0 :::53                   :::*                    LISTEN      
udp        0      0 193.94.160.1:53         0.0.0.0:*                           
udp        0      0 127.0.0.1:53            0.0.0.0:*                           
udp        0      0 :::53                   :::*    

and BSD gives:

# netstat -an | grep .53
tcp6       0      0  ::1.953                *.*                    LISTEN
tcp4       0      0  127.0.0.1.953          *.*                    LISTEN
tcp4       0      0  127.0.0.1.53           *.*                    LISTEN
tcp4       0      0  193.166.4.206.53       *.*                    LISTEN
tcp4       0      0  193.166.187.10.53      *.*                    LISTEN
tcp6       0      0  *.53                   *.*                    LISTEN
udp4       0      0  127.0.0.1.53           *.*                    
udp4       0      0  193.166.4.206.53       *.*                    
udp4       0      0  193.166.187.10.53      *.*                    
udp6       0      0  *.53                   *.*

Will this work too?

-- 
Pekka Savola                 "Tell me of difficulties surmounted,
Netcore Oy                   not those you stumble over and fall"
Systems. Networks. Security.  -- Robert Jordan: A Crown of Swords

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port)
  2002-10-23  7:24             ` [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port) YOSHIFUJI Hideaki / 吉藤英明
  2002-10-23  7:23               ` David S. Miller
  2002-10-23  7:36               ` Pekka Savola
@ 2002-10-23 15:53               ` Kyle C Quest
  2002-10-23 16:06                 ` Pekka Savola
  2002-10-24 10:24               ` David S. Miller
  3 siblings, 1 reply; 33+ messages in thread
From: Kyle C Quest @ 2002-10-23 15:53 UTC (permalink / raw)
  To: yoshfuji; +Cc: netdev


I'm just curious... what happened to the generic option, SO_ONEFAMILY, that
would replace
the need for IPV6_V6ONLY?



> In article <200210031552.TAA29921@sex.inr.ac.ru> (at Thu, 3 Oct 2002
19:52:40 +0400 (MSD)), kuznet@ms2.inr.ac.ru 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@linux-ipv6.org>
> Credit: YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
> 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];
>
>

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port)
  2002-10-23 15:53               ` [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port) Kyle C Quest
@ 2002-10-23 16:06                 ` Pekka Savola
  2002-10-23 16:09                   ` Kyle C Quest
  0 siblings, 1 reply; 33+ messages in thread
From: Pekka Savola @ 2002-10-23 16:06 UTC (permalink / raw)
  To: Kyle C Quest; +Cc: yoshfuji, netdev

On Wed, 23 Oct 2002, Kyle C Quest wrote:
> I'm just curious... what happened to the generic option, SO_ONEFAMILY, that
> would replace
> the need for IPV6_V6ONLY?

This kind of thing is only applicable to IPv4 and IPv6 (and badly even 
there), there is no use trying to generalize it -- the idea was discarded.

> > In article <200210031552.TAA29921@sex.inr.ac.ru> (at Thu, 3 Oct 2002
> 19:52:40 +0400 (MSD)), kuznet@ms2.inr.ac.ru 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@linux-ipv6.org>
> > Credit: YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
> > 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];
> >
> >
> 
> 

-- 
Pekka Savola                 "Tell me of difficulties surmounted,
Netcore Oy                   not those you stumble over and fall"
Systems. Networks. Security.  -- Robert Jordan: A Crown of Swords

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port)
  2002-10-23 16:06                 ` Pekka Savola
@ 2002-10-23 16:09                   ` Kyle C Quest
  0 siblings, 0 replies; 33+ messages in thread
From: Kyle C Quest @ 2002-10-23 16:09 UTC (permalink / raw)
  To: Pekka Savola; +Cc: yoshfuji, netdev


> > I'm just curious... what happened to the generic option, SO_ONEFAMILY,
that
> > would replace
> > the need for IPV6_V6ONLY?
>
> This kind of thing is only applicable to IPv4 and IPv6 (and badly even
> there), there is no use trying to generalize it -- the idea was discarded.
>

I see...
Thanks for the info

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port)
  2002-10-23  7:24             ` [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port) YOSHIFUJI Hideaki / 吉藤英明
                                 ` (2 preceding siblings ...)
  2002-10-23 15:53               ` [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port) Kyle C Quest
@ 2002-10-24 10:24               ` David S. Miller
  3 siblings, 0 replies; 33+ messages in thread
From: David S. Miller @ 2002-10-24 10:24 UTC (permalink / raw)
  To: yoshfuji; +Cc: kuznet, netdev, usagi


I've added this patch to both of my trees.
Thank you.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both
  2002-10-23 10:15                   ` Pekka Savola
  2002-10-23 10:12                     ` David S. Miller
@ 2002-10-24 16:24                     ` kuznet
  2002-10-25  7:46                       ` Pekka Savola
  1 sibling, 1 reply; 33+ messages in thread
From: kuznet @ 2002-10-24 16:24 UTC (permalink / raw)
  To: Pekka Savola; +Cc: yoshfuji, davem, netdev, usagi

Hello!

Late question:

> ::, at least previously.  That worked e.g. on BSD.  Does that work now, 
> too?

Provided it uses IPV6_V6ONLY.


> tcp4       0      0  127.0.0.1.53           *.*                    LISTEN
> tcp4       0      0  193.166.4.206.53       *.*                    LISTEN
> tcp4       0      0  193.166.187.10.53      *.*                    LISTEN
> tcp6       0      0  *.53                   *.*                    LISTEN
...
> Will this work too?

No.

The question follows: what the hell does it make this? What is special
in ipv4 that it needs to bind to its addresses? With IPV6_V6ONLY connections
to all the IPv4 addresses but listed ones will be refused. I guess it is
not _that_ thing which bind expects.

Alexey

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both
  2002-10-24 16:24                     ` [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both kuznet
@ 2002-10-25  7:46                       ` Pekka Savola
  0 siblings, 0 replies; 33+ messages in thread
From: Pekka Savola @ 2002-10-25  7:46 UTC (permalink / raw)
  To: kuznet; +Cc: yoshfuji, davem, netdev, usagi

On Thu, 24 Oct 2002 kuznet@ms2.inr.ac.ru wrote:
> > tcp4       0      0  127.0.0.1.53           *.*                    LISTEN
> > tcp4       0      0  193.166.4.206.53       *.*                    LISTEN
> > tcp4       0      0  193.166.187.10.53      *.*                    LISTEN
> > tcp6       0      0  *.53                   *.*                    LISTEN
> ...
> > Will this work too?
> 
> No.
> 
> The question follows: what the hell does it make this? What is special
> in ipv4 that it needs to bind to its addresses? With IPV6_V6ONLY connections
> to all the IPv4 addresses but listed ones will be refused. I guess it is
> not _that_ thing which bind expects.

I'm not sure I understand what you mean.  Note that the last line is 
_tcp6_:

tcp6       0      0  *.53                   *.*                    LISTEN

So, I belive using IPV6_V6ONLY it should indeed work.

(The reasoning in Bind is that you can bind to addresses _only_ in IPv4 
but you don't have to.  It's done in these cases.  For IPv6, it's 
all-or-nothing.)

-- 
Pekka Savola                 "Tell me of difficulties surmounted,
Netcore Oy                   not those you stumble over and fall"
Systems. Networks. Security.  -- Robert Jordan: A Crown of Swords

^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2002-10-25  7:46 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-10-03  3:13 [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port Number (IPV6_V6ONLY Support) YOSHIFUJI Hideaki / 吉藤英明
2002-10-03  3:53 ` acme
2002-10-03  3:55 ` acme
2002-10-03  7:00 ` Pekka Savola
2002-10-03  8:29 ` David S. Miller
2002-10-03  8:55   ` Brad Hards
2002-10-03  8:58     ` David S. Miller
2002-10-03 13:06   ` [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same kuznet
2002-10-03 13:02     ` David S. Miller
2002-10-03 13:18       ` Pekka Savola
2002-10-03 13:13         ` David S. Miller
2002-10-03 13:01 ` [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port kuznet
2002-10-03 14:15   ` YOSHIFUJI Hideaki / 吉藤英明
2002-10-03 14:10     ` David S. Miller
2002-10-03 15:06     ` YOSHIFUJI Hideaki / 吉藤英明
2002-10-03 15:04       ` David S. Miller
2002-10-03 15:19         ` YOSHIFUJI Hideaki / 吉藤英明
2002-10-03 15:52           ` kuznet
2002-10-23  7:24             ` [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port) YOSHIFUJI Hideaki / 吉藤英明
2002-10-23  7:23               ` David S. Miller
2002-10-23  7:58                 ` YOSHIFUJI Hideaki / 吉藤英明
2002-10-23  8:06                   ` YOSHIFUJI Hideaki / 吉藤英明
2002-10-23  8:02                     ` David S. Miller
2002-10-23  7:36               ` Pekka Savola
2002-10-23 10:01                 ` YOSHIFUJI Hideaki / 吉藤英明
2002-10-23 10:15                   ` Pekka Savola
2002-10-23 10:12                     ` David S. Miller
2002-10-24 16:24                     ` [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both kuznet
2002-10-25  7:46                       ` Pekka Savola
2002-10-23 15:53               ` [PATCH] IPV6_V6ONLY Support, v2 (is Re: [PATCH] IPv6: Allow Both IPv6 and IPv4 Sockets on the Same Port) Kyle C Quest
2002-10-23 16:06                 ` Pekka Savola
2002-10-23 16:09                   ` Kyle C Quest
2002-10-24 10:24               ` David S. Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.