patch-2.4.21 linux-2.4.21/net/ipv6/udp.c

Next file: linux-2.4.21/net/irda/ircomm/ircomm_core.c
Previous file: linux-2.4.21/net/ipv6/tcp_ipv6.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.20/net/ipv6/udp.c linux-2.4.21/net/ipv6/udp.c
@@ -11,6 +11,9 @@
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
+ *	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
  *      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;
@@ -831,6 +850,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 = udh.uh.dest;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)