Module Name:    src
Committed By:   dyoung
Date:           Fri Sep 11 22:06:29 UTC 2009

Modified Files:
        src/sbin/ifconfig: af_inet.c af_inet6.c util.c util.h
        src/sys/kern: uipc_domain.c uipc_socket.c
        src/sys/net: if.c if.h
        src/sys/netinet: in.c
        src/sys/netinet6: in6.c in6.h in6_proto.c scope6.c
        src/sys/sys: domain.h socket.h socketvar.h

Log Message:
Make ifconfig(8) set and display preference numbers for IPv6
addresses.  Make the kernel support SIOC[SG]IFADDRPREF for IPv6
interface addresses.

In in6ifa_ifpforlinklocal(), consult preference numbers before
making an otherwise arbitrary choice of in6_ifaddr.  Otherwise,
preference numbers are *not* consulted by the kernel, but that will
be rather easy for somebody with a little bit of free time to fix.

Please note that setting the preference number for a link-local
IPv6 address does not work right, yet, but that ought to be fixed
soon.

In support of the changes above,

1 Add a method to struct domain for "externalizing" a sockaddr, and
  provide an implementation for IPv6.  Expect more work in this area: it
  may be more proper to say that the IPv6 implementation "internalizes"
  a sockaddr.  Add sockaddr_externalize().

2 Add a subroutine, sofamily(), that returns a struct socket's address
  family or AF_UNSPEC.

3 Make a lot of IPv4-specific code generic, and move it from
  sys/netinet/ to sys/net/ for re-use by IPv6 parts of the kernel and
  ifconfig(8).


To generate a diff of this commit:
cvs rdiff -u -r1.13 -r1.14 src/sbin/ifconfig/af_inet.c
cvs rdiff -u -r1.24 -r1.25 src/sbin/ifconfig/af_inet6.c
cvs rdiff -u -r1.12 -r1.13 src/sbin/ifconfig/util.c
cvs rdiff -u -r1.7 -r1.8 src/sbin/ifconfig/util.h
cvs rdiff -u -r1.83 -r1.84 src/sys/kern/uipc_domain.c
cvs rdiff -u -r1.189 -r1.190 src/sys/kern/uipc_socket.c
cvs rdiff -u -r1.234 -r1.235 src/sys/net/if.c
cvs rdiff -u -r1.143 -r1.144 src/sys/net/if.h
cvs rdiff -u -r1.134 -r1.135 src/sys/netinet/in.c
cvs rdiff -u -r1.152 -r1.153 src/sys/netinet6/in6.c
cvs rdiff -u -r1.67 -r1.68 src/sys/netinet6/in6.h
cvs rdiff -u -r1.86 -r1.87 src/sys/netinet6/in6_proto.c
cvs rdiff -u -r1.7 -r1.8 src/sys/netinet6/scope6.c
cvs rdiff -u -r1.28 -r1.29 src/sys/sys/domain.h
cvs rdiff -u -r1.95 -r1.96 src/sys/sys/socket.h
cvs rdiff -u -r1.120 -r1.121 src/sys/sys/socketvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sbin/ifconfig/af_inet.c
diff -u src/sbin/ifconfig/af_inet.c:1.13 src/sbin/ifconfig/af_inet.c:1.14
--- src/sbin/ifconfig/af_inet.c:1.13	Fri Aug  7 19:35:55 2009
+++ src/sbin/ifconfig/af_inet.c	Fri Sep 11 22:06:29 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: af_inet.c,v 1.13 2009/08/07 19:35:55 dyoung Exp $	*/
+/*	$NetBSD: af_inet.c,v 1.14 2009/09/11 22:06:29 dyoung Exp $	*/
 
 /*
  * Copyright (c) 1983, 1993
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: af_inet.c,v 1.13 2009/08/07 19:35:55 dyoung Exp $");
+__RCSID("$NetBSD: af_inet.c,v 1.14 2009/09/11 22:06:29 dyoung Exp $");
 #endif /* not lint */
 
 #include <sys/param.h> 
@@ -63,7 +63,6 @@
 static void in_commit_address(prop_dictionary_t, prop_dictionary_t);
 static void in_alias(const char *, prop_dictionary_t, prop_dictionary_t,
     struct in_aliasreq *);
-static void in_preference(const char *, const struct sockaddr *);
 
 static struct afswtch af = {
 	.af_name = "inet", .af_af = AF_INET, .af_status = in_status,
@@ -139,46 +138,12 @@
 	}
 }
 
-static int16_t
-in_get_preference(const char *ifname, const struct sockaddr *sa)
-{
-	struct if_addrprefreq ifap;
-	int s;
-
-	if ((s = getsock(AF_INET)) == -1) {
-		if (errno == EPROTONOSUPPORT)
-			return 0;
-		err(EXIT_FAILURE, "socket");
-	}
-	memset(&ifap, 0, sizeof(ifap));
-	estrlcpy(ifap.ifap_name, ifname, sizeof(ifap.ifap_name));
-	memcpy(&ifap.ifap_addr, sa, MIN(sizeof(ifap.ifap_addr), sa->sa_len));
-	if (ioctl(s, SIOCGIFADDRPREF, &ifap) == -1) {
-		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT)
-			return 0;
-		warn("SIOCGIFADDRPREF");
-	}
-	return ifap.ifap_preference;
-}
-
-static void
-in_preference(const char *ifname, const struct sockaddr *sa)
-{
-	int16_t preference;
-
-	if (lflag)
-		return;
-
-	preference = in_get_preference(ifname, sa);
-	printf(" preference %" PRId16, preference);
-}
-
 static void
 in_status(prop_dictionary_t env, prop_dictionary_t oenv, bool force)
 {
 	struct ifaddrs *ifap, *ifa;
 	struct in_aliasreq ifra;
-	int printprefs = 0;
+	bool printprefs = false;
 	const char *ifname;
 
 	if ((ifname = getifname(env)) == NULL)
@@ -187,19 +152,8 @@
 	if (getifaddrs(&ifap) != 0)
 		err(EXIT_FAILURE, "getifaddrs");
 
-	/* Print address preference numbers if any address has a non-zero
-	 * preference assigned.
-	 */
-	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
-		if (strcmp(ifname, ifa->ifa_name) != 0)
-			continue;
-		if (ifa->ifa_addr->sa_family != AF_INET)
-			continue;
-		if (in_get_preference(ifa->ifa_name, ifa->ifa_addr) != 0) {
-			printprefs = 1;
-			break;
-		}
-	}
+	printprefs = ifa_any_preferences(ifname, ifap, AF_INET);
+
 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
 		if (strcmp(ifname, ifa->ifa_name) != 0)
 			continue;
@@ -213,7 +167,7 @@
 		memcpy(&ifra.ifra_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
 		in_alias(ifa->ifa_name, env, oenv, &ifra);
 		if (printprefs)
-			in_preference(ifa->ifa_name, ifa->ifa_addr);
+			ifa_print_preference(ifa->ifa_name, ifa->ifa_addr);
 		printf("\n");
 	}
 	freeifaddrs(ifap);

Index: src/sbin/ifconfig/af_inet6.c
diff -u src/sbin/ifconfig/af_inet6.c:1.24 src/sbin/ifconfig/af_inet6.c:1.25
--- src/sbin/ifconfig/af_inet6.c:1.24	Fri Aug  7 18:53:37 2009
+++ src/sbin/ifconfig/af_inet6.c	Fri Sep 11 22:06:29 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: af_inet6.c,v 1.24 2009/08/07 18:53:37 dyoung Exp $	*/
+/*	$NetBSD: af_inet6.c,v 1.25 2009/09/11 22:06:29 dyoung Exp $	*/
 
 /*
  * Copyright (c) 1983, 1993
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: af_inet6.c,v 1.24 2009/08/07 18:53:37 dyoung Exp $");
+__RCSID("$NetBSD: af_inet6.c,v 1.25 2009/09/11 22:06:29 dyoung Exp $");
 #endif /* not lint */
 
 #include <sys/param.h> 
@@ -374,8 +374,6 @@
 				printf("infty");
 		}
 	}
-
-	printf("\n");
 }
 
 static void
@@ -384,12 +382,14 @@
 	struct ifaddrs *ifap, *ifa;
 	struct in6_ifreq ifr;
 	const char *ifname;
+	bool printprefs = false;
 
 	if ((ifname = getifname(env)) == NULL)
 		err(EXIT_FAILURE, "%s: getifname", __func__);
 
 	if (getifaddrs(&ifap) != 0)
 		err(EXIT_FAILURE, "getifaddrs");
+	printprefs = ifa_any_preferences(ifname, ifap, AF_INET6);
 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
 		if (strcmp(ifname, ifa->ifa_name) != 0)
 			continue;
@@ -402,6 +402,9 @@
 		estrlcpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
 		memcpy(&ifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
 		in6_alias(ifname, env, oenv, &ifr);
+		if (printprefs)
+			ifa_print_preference(ifa->ifa_name, ifa->ifa_addr);
+		printf("\n");
 	}
 	freeifaddrs(ifap);
 }

Index: src/sbin/ifconfig/util.c
diff -u src/sbin/ifconfig/util.c:1.12 src/sbin/ifconfig/util.c:1.13
--- src/sbin/ifconfig/util.c:1.12	Fri Aug  7 18:53:37 2009
+++ src/sbin/ifconfig/util.c	Fri Sep 11 22:06:29 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: util.c,v 1.12 2009/08/07 18:53:37 dyoung Exp $	*/
+/*	$NetBSD: util.c,v 1.13 2009/09/11 22:06:29 dyoung Exp $	*/
 
 /*-
  * Copyright (c) 2008 David Young.  All rights reserved.
@@ -27,7 +27,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: util.c,v 1.12 2009/08/07 18:53:37 dyoung Exp $");
+__RCSID("$NetBSD: util.c,v 1.13 2009/09/11 22:06:29 dyoung Exp $");
 #endif /* not lint */
 
 #include <ctype.h>
@@ -290,6 +290,60 @@
 	freeifaddrs(ifap);
 }
 
+int16_t
+ifa_get_preference(const char *ifname, const struct sockaddr *sa)
+{
+	struct if_addrprefreq ifap;
+	int s;
+
+	if ((s = getsock(sa->sa_family)) == -1) {
+		if (errno == EPROTONOSUPPORT)
+			return 0;
+		err(EXIT_FAILURE, "socket");
+	}
+	memset(&ifap, 0, sizeof(ifap));
+	estrlcpy(ifap.ifap_name, ifname, sizeof(ifap.ifap_name));
+	memcpy(&ifap.ifap_addr, sa, MIN(sizeof(ifap.ifap_addr), sa->sa_len));
+	if (ioctl(s, SIOCGIFADDRPREF, &ifap) == -1) {
+		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT)
+			return 0;
+		warn("SIOCGIFADDRPREF");
+	}
+	return ifap.ifap_preference;
+}
+
+void
+ifa_print_preference(const char *ifname, const struct sockaddr *sa)
+{
+	int16_t preference;
+
+	if (lflag)
+		return;
+
+	preference = ifa_get_preference(ifname, sa);
+	printf(" preference %" PRId16, preference);
+}
+
+bool
+ifa_any_preferences(const char *ifname, struct ifaddrs *ifap, int family)
+{
+	struct ifaddrs *ifa;
+
+	/* Print address preference numbers if any address has a non-zero
+	 * preference assigned.
+	 */
+	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+		if (strcmp(ifname, ifa->ifa_name) != 0)
+			continue;
+		if (ifa->ifa_addr->sa_family != family)
+			continue;
+		if (ifa_get_preference(ifa->ifa_name, ifa->ifa_addr) != 0)
+			return true;
+	}
+	return false;
+}
+
+
 #ifdef INET6
 /* KAME idiosyncrasy */
 void

Index: src/sbin/ifconfig/util.h
diff -u src/sbin/ifconfig/util.h:1.7 src/sbin/ifconfig/util.h:1.8
--- src/sbin/ifconfig/util.h:1.7	Tue Apr 21 22:46:39 2009
+++ src/sbin/ifconfig/util.h	Fri Sep 11 22:06:29 2009
@@ -2,6 +2,9 @@
 #define _IFCONFIG_UTIL_H
 
 #include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <ifaddrs.h>
 
 #include "parse.h"
 
@@ -25,5 +28,8 @@
 #ifdef INET6
 void in6_fillscopeid(struct sockaddr_in6 *sin6);
 #endif /* INET6	*/
+bool ifa_any_preferences(const char *, struct ifaddrs *, int);
+void ifa_print_preference(const char *, const struct sockaddr *);
+int16_t ifa_get_preference(const char *, const struct sockaddr *);
 
 #endif /* _IFCONFIG_UTIL_H */

Index: src/sys/kern/uipc_domain.c
diff -u src/sys/kern/uipc_domain.c:1.83 src/sys/kern/uipc_domain.c:1.84
--- src/sys/kern/uipc_domain.c:1.83	Tue Sep  8 18:01:34 2009
+++ src/sys/kern/uipc_domain.c	Fri Sep 11 22:06:29 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: uipc_domain.c,v 1.83 2009/09/08 18:01:34 dyoung Exp $	*/
+/*	$NetBSD: uipc_domain.c,v 1.84 2009/09/11 22:06:29 dyoung Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1993
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_domain.c,v 1.83 2009/09/08 18:01:34 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_domain.c,v 1.84 2009/09/11 22:06:29 dyoung Exp $");
 
 #include <sys/param.h>
 #include <sys/socket.h>
@@ -268,6 +268,20 @@
 	return memcpy(dst, src, src->sa_len);
 }
 
+struct sockaddr *
+sockaddr_externalize(struct sockaddr *dst, socklen_t socklen,
+    const struct sockaddr *src)
+{
+	struct domain *dom;
+
+	dom = pffinddomain(src->sa_family);
+
+	if (dom != NULL && dom->dom_sockaddr_externalize != NULL)
+		return (*dom->dom_sockaddr_externalize)(dst, socklen, src);
+
+	return sockaddr_copy(dst, socklen, src);
+}
+
 int
 sockaddr_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
 {

Index: src/sys/kern/uipc_socket.c
diff -u src/sys/kern/uipc_socket.c:1.189 src/sys/kern/uipc_socket.c:1.190
--- src/sys/kern/uipc_socket.c:1.189	Thu Apr 30 20:41:33 2009
+++ src/sys/kern/uipc_socket.c	Fri Sep 11 22:06:29 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: uipc_socket.c,v 1.189 2009/04/30 20:41:33 ad Exp $	*/
+/*	$NetBSD: uipc_socket.c,v 1.190 2009/09/11 22:06:29 dyoung Exp $	*/
 
 /*-
  * Copyright (c) 2002, 2007, 2008, 2009 The NetBSD Foundation, Inc.
@@ -63,7 +63,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.189 2009/04/30 20:41:33 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.190 2009/09/11 22:06:29 dyoung Exp $");
 
 #include "opt_compat_netbsd.h"
 #include "opt_sock_counters.h"
@@ -555,6 +555,19 @@
 }
 
 int
+sofamily(const struct socket *so)
+{
+	const struct protosw *pr;
+	const struct domain *dom;
+
+	if ((pr = so->so_proto) == NULL)
+		return AF_UNSPEC;
+	if ((dom = pr->pr_domain) == NULL)
+		return AF_UNSPEC;
+	return dom->dom_family;
+}
+
+int
 sobind(struct socket *so, struct mbuf *nam, struct lwp *l)
 {
 	int	error;

Index: src/sys/net/if.c
diff -u src/sys/net/if.c:1.234 src/sys/net/if.c:1.235
--- src/sys/net/if.c:1.234	Thu Aug 13 00:23:31 2009
+++ src/sys/net/if.c	Fri Sep 11 22:06:29 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: if.c,v 1.234 2009/08/13 00:23:31 dyoung Exp $	*/
+/*	$NetBSD: if.c,v 1.235 2009/09/11 22:06:29 dyoung Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -90,7 +90,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.234 2009/08/13 00:23:31 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.235 2009/09/11 22:06:29 dyoung Exp $");
 
 #include "opt_inet.h"
 
@@ -1573,6 +1573,68 @@
 	return 0;
 }
 
+int
+ifaddrpref_ioctl(struct socket *so, u_long cmd, void *data, struct ifnet *ifp,
+    lwp_t *l)
+{
+	struct if_addrprefreq *ifap = (struct if_addrprefreq *)data;
+	struct ifaddr *ifa;
+	const struct sockaddr *any, *sa;
+	union {
+		struct sockaddr sa;
+		struct sockaddr_storage ss;
+	} u;
+
+	switch (cmd) {
+	case SIOCSIFADDRPREF:
+		if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_INTERFACE,
+		    KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
+		    NULL) != 0)
+			return EPERM;
+	case SIOCGIFADDRPREF:
+		break;
+	default:
+		return EOPNOTSUPP;
+	}
+
+	/* sanity checks */
+	if (data == NULL || ifp == NULL) {
+		panic("invalid argument to %s", __func__);
+		/*NOTREACHED*/
+	}
+
+	/* address must be specified on ADD and DELETE */
+	sa = sstocsa(&ifap->ifap_addr);
+	if (sa->sa_family != sofamily(so))
+		return EINVAL;
+	if ((any = sockaddr_any(sa)) == NULL || sa->sa_len != any->sa_len)
+		return EINVAL;
+
+	IFADDR_FOREACH(ifa, ifp) {
+		if (ifa->ifa_addr->sa_family != sa->sa_family)
+			continue;
+		sockaddr_externalize(&u.sa, sizeof(u.ss), ifa->ifa_addr);
+		if (sockaddr_cmp(&u.sa, sa) == 0)
+			break;
+	}
+	if (ifa == NULL)
+		return EADDRNOTAVAIL;
+
+	switch (cmd) {
+	case SIOCSIFADDRPREF:
+		ifa->ifa_preference = ifap->ifap_preference;
+		return 0;
+	case SIOCGIFADDRPREF:
+		/* fill in the if_laddrreq structure */
+		(void)sockaddr_copy(sstosa(&ifap->ifap_addr),
+		    sizeof(ifap->ifap_addr), ifa->ifa_addr);
+		ifap->ifap_preference = ifa->ifa_preference;
+		return 0;
+	default:
+		return EOPNOTSUPP;
+	}
+}
+
 /*
  * Interface ioctls.
  */

Index: src/sys/net/if.h
diff -u src/sys/net/if.h:1.143 src/sys/net/if.h:1.144
--- src/sys/net/if.h:1.143	Thu Aug 13 00:23:32 2009
+++ src/sys/net/if.h	Fri Sep 11 22:06:29 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: if.h,v 1.143 2009/08/13 00:23:32 dyoung Exp $	*/
+/*	$NetBSD: if.h,v 1.144 2009/09/11 22:06:29 dyoung Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -829,6 +829,8 @@
 int	ifconf(u_long, void *);
 void	ifinit(void);
 void	ifinit1(void);
+int	ifaddrpref_ioctl(struct socket *, u_long, void *, struct ifnet *,
+    lwp_t *);
 int	ifioctl(struct socket *, u_long, void *, struct lwp *);
 int	ifioctl_common(struct ifnet *, u_long, void *);
 int	ifpromisc(struct ifnet *, int);

Index: src/sys/netinet/in.c
diff -u src/sys/netinet/in.c:1.134 src/sys/netinet/in.c:1.135
--- src/sys/netinet/in.c:1.134	Sat Apr 18 14:58:05 2009
+++ src/sys/netinet/in.c	Fri Sep 11 22:06:29 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: in.c,v 1.134 2009/04/18 14:58:05 tsutsui Exp $	*/
+/*	$NetBSD: in.c,v 1.135 2009/09/11 22:06:29 dyoung Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,7 +91,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.134 2009/04/18 14:58:05 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.135 2009/09/11 22:06:29 dyoung Exp $");
 
 #include "opt_inet.h"
 #include "opt_inet_conf.h"
@@ -139,8 +139,6 @@
 static int in_lifaddr_ioctl(struct socket *, u_long, void *,
 	struct ifnet *, struct lwp *);
 
-static int in_ifaddrpref_ioctl(struct socket *, u_long, void *,
-	struct ifnet *);
 static int in_addprefix(struct in_ifaddr *, int);
 static int in_scrubprefix(struct in_ifaddr *);
 
@@ -321,15 +319,15 @@
 	switch (cmd) {
 	case SIOCALIFADDR:
 	case SIOCDLIFADDR:
-	case SIOCSIFADDRPREF:
-	case SIOCGIFADDRPREF:
 	case SIOCGLIFADDR:
 		if (ifp == NULL)
 			return EINVAL;
-		if (cmd == SIOCGIFADDRPREF || cmd == SIOCSIFADDRPREF)
-			return in_ifaddrpref_ioctl(so, cmd, data, ifp);
-		else
-			return in_lifaddr_ioctl(so, cmd, data, ifp, l);
+		return in_lifaddr_ioctl(so, cmd, data, ifp, l);
+	case SIOCGIFADDRPREF:
+	case SIOCSIFADDRPREF:
+		if (ifp == NULL)
+			return EINVAL;
+		return ifaddrpref_ioctl(so, cmd, data, ifp, l);
 	}
 
 	/*
@@ -339,7 +337,6 @@
 		IFP_TO_IA(ifp, ia);
 
 	switch (cmd) {
-
 	case SIOCAIFADDR:
 	case SIOCDIFADDR:
 	case SIOCGIFALIAS:
@@ -777,66 +774,6 @@
 	return EOPNOTSUPP;	/*just for safety*/
 }
 
-static int
-in_ifaddrpref_ioctl(struct socket *so, u_long cmd, void *data,
-    struct ifnet *ifp)
-{
-	struct if_addrprefreq *ifap = (struct if_addrprefreq *)data;
-	struct ifaddr *ifa;
-	struct sockaddr *sa;
-	struct in_ifaddr *ia = NULL; /* appease gcc -Wuninitialized */
-	struct in_addr match;
-	struct sockaddr_in *sin;
-
-	/* sanity checks */
-	if (data == NULL || ifp == NULL) {
-		panic("invalid argument to %s", __func__);
-		/*NOTREACHED*/
-	}
-
-	/* address must be specified on ADD and DELETE */
-	sa = (struct sockaddr *)&ifap->ifap_addr;
-	if (sa->sa_family != AF_INET)
-		return EINVAL;
-	if (sa->sa_len != sizeof(struct sockaddr_in))
-		return EINVAL;
-
-	switch (cmd) {
-	case SIOCSIFADDRPREF:
-	case SIOCGIFADDRPREF:
-		break;
-	default:
-		return EOPNOTSUPP;
-	}
-
-	sin = (struct sockaddr_in *)&ifap->ifap_addr;
-	match.s_addr = sin->sin_addr.s_addr;
-
-	IFADDR_FOREACH(ifa, ifp) {
-		ia = (struct in_ifaddr *)ifa;
-		if (ia->ia_addr.sin_family != AF_INET)
-			continue;
-		if (ia->ia_addr.sin_addr.s_addr == match.s_addr)
-			break;
-	}
-	if (ifa == NULL)
-		return EADDRNOTAVAIL;
-
-	switch (cmd) {
-	case SIOCSIFADDRPREF:
-		ifa->ifa_preference = ifap->ifap_preference;
-		return 0;
-	case SIOCGIFADDRPREF:
-		/* fill in the if_laddrreq structure */
-		(void)memcpy(&ifap->ifap_addr, &ia->ia_addr,
-		    ia->ia_addr.sin_len);
-		ifap->ifap_preference = ifa->ifa_preference;
-		return 0;
-	default:
-		return EOPNOTSUPP;
-	}
-}
-
 /*
  * Delete any existing route for an interface.
  */

Index: src/sys/netinet6/in6.c
diff -u src/sys/netinet6/in6.c:1.152 src/sys/netinet6/in6.c:1.153
--- src/sys/netinet6/in6.c:1.152	Thu Aug 13 00:34:04 2009
+++ src/sys/netinet6/in6.c	Fri Sep 11 22:06:29 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6.c,v 1.152 2009/08/13 00:34:04 dyoung Exp $	*/
+/*	$NetBSD: in6.c,v 1.153 2009/09/11 22:06:29 dyoung Exp $	*/
 /*	$KAME: in6.c,v 1.198 2001/07/18 09:12:38 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.152 2009/08/13 00:34:04 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.153 2009/09/11 22:06:29 dyoung Exp $");
 
 #include "opt_inet.h"
 #include "opt_pfil_hooks.h"
@@ -350,13 +350,14 @@
 
 static int
 in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp,
-    struct lwp *l)
+    lwp_t *l)
 {
 	struct	in6_ifreq *ifr = (struct in6_ifreq *)data;
 	struct	in6_ifaddr *ia = NULL;
 	struct	in6_aliasreq *ifra = (struct in6_aliasreq *)data;
 	struct sockaddr_in6 *sa6;
 	int error;
+
 	switch (cmd) {
 	/*
 	 * XXX: Fix me, once we fix SIOCSIFADDR, SIOCIFDSTADDR, etc.
@@ -370,6 +371,11 @@
 	case SIOCGETSGCNT_IN6:
 	case SIOCGETMIFCNT_IN6:
 		return mrt6_ioctl(cmd, data);
+	case SIOCGIFADDRPREF:
+	case SIOCSIFADDRPREF:
+		if (ifp == NULL)
+			return EINVAL;
+		return ifaddrpref_ioctl(so, cmd, data, ifp, l);
 	}
 
 	if (ifp == NULL)
@@ -1793,22 +1799,24 @@
 struct in6_ifaddr *
 in6ifa_ifpforlinklocal(const struct ifnet *ifp, const int ignoreflags)
 {
-	struct ifaddr *ifa;
+	struct ifaddr *best_ifa = NULL, *ifa;
 
 	IFADDR_FOREACH(ifa, ifp) {
 		if (ifa->ifa_addr == NULL)
 			continue;	/* just for safety */
 		if (ifa->ifa_addr->sa_family != AF_INET6)
 			continue;
-		if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) {
-			if ((((struct in6_ifaddr *)ifa)->ia6_flags &
-			     ignoreflags) != 0)
-				continue;
-			break;
-		}
+		if (!IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa)))
+			continue;
+		if ((((struct in6_ifaddr *)ifa)->ia6_flags & ignoreflags) != 0)
+			continue;
+		if (best_ifa == NULL)
+			best_ifa = ifa;
+		else if (best_ifa->ifa_preference < ifa->ifa_preference)
+			best_ifa = ifa;
 	}
 
-	return (struct in6_ifaddr *)ifa;
+	return (struct in6_ifaddr *)best_ifa;
 }
 
 

Index: src/sys/netinet6/in6.h
diff -u src/sys/netinet6/in6.h:1.67 src/sys/netinet6/in6.h:1.68
--- src/sys/netinet6/in6.h:1.67	Wed Aug 19 18:52:48 2009
+++ src/sys/netinet6/in6.h	Fri Sep 11 22:06:29 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6.h,v 1.67 2009/08/19 18:52:48 seanb Exp $	*/
+/*	$NetBSD: in6.h,v 1.68 2009/09/11 22:06:29 dyoung Exp $	*/
 /*	$KAME: in6.h,v 1.83 2001/03/29 02:55:07 jinmei Exp $	*/
 
 /*
@@ -684,6 +684,8 @@
 struct mbuf;
 struct ifnet;
 int sockaddr_in6_cmp(const struct sockaddr *, const struct sockaddr *);
+struct sockaddr *sockaddr_in6_externalize(struct sockaddr *, socklen_t,
+    const struct sockaddr *);
 int	in6_cksum(struct mbuf *, u_int8_t, u_int32_t, u_int32_t);
 void	in6_delayed_cksum(struct mbuf *);
 int	in6_localaddr(const struct in6_addr *);

Index: src/sys/netinet6/in6_proto.c
diff -u src/sys/netinet6/in6_proto.c:1.86 src/sys/netinet6/in6_proto.c:1.87
--- src/sys/netinet6/in6_proto.c:1.86	Fri Sep 11 20:10:06 2009
+++ src/sys/netinet6/in6_proto.c	Fri Sep 11 22:06:29 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6_proto.c,v 1.86 2009/09/11 20:10:06 dyoung Exp $	*/
+/*	$NetBSD: in6_proto.c,v 1.87 2009/09/11 22:06:29 dyoung Exp $	*/
 /*	$KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6_proto.c,v 1.86 2009/09/11 20:10:06 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6_proto.c,v 1.87 2009/09/11 22:06:29 dyoung Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -421,6 +421,7 @@
 	.dom_sa_cmpofs = offsetof(struct sockaddr_in6, sin6_addr),
 	.dom_sa_cmplen = sizeof(struct in6_addr),
 	.dom_sa_any = (const struct sockaddr *)&in6_any,
+	.dom_sockaddr_externalize = sockaddr_in6_externalize,
 	.dom_rtcache = LIST_HEAD_INITIALIZER(inet6domain.dom_rtcache)
 };
 

Index: src/sys/netinet6/scope6.c
diff -u src/sys/netinet6/scope6.c:1.7 src/sys/netinet6/scope6.c:1.8
--- src/sys/netinet6/scope6.c:1.7	Sun Mar 15 21:26:09 2009
+++ src/sys/netinet6/scope6.c	Fri Sep 11 22:06:29 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: scope6.c,v 1.7 2009/03/15 21:26:09 cegger Exp $	*/
+/*	$NetBSD: scope6.c,v 1.8 2009/09/11 22:06:29 dyoung Exp $	*/
 /*	$KAME$	*/
 
 /*-
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: scope6.c,v 1.7 2009/03/15 21:26:09 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: scope6.c,v 1.8 2009/09/11 22:06:29 dyoung Exp $");
 
 #include <sys/param.h>
 #include <sys/malloc.h>
@@ -328,6 +328,20 @@
 	return 0;
 }
 
+struct sockaddr *
+sockaddr_in6_externalize(struct sockaddr *dst, socklen_t socklen,
+    const struct sockaddr *src)
+{
+	struct sockaddr_in6 *sin6;
+
+	sin6 = satosin6(sockaddr_copy(dst, socklen, src));
+
+	if (sin6 == NULL || sa6_recoverscope(sin6) != 0)
+		return NULL;
+
+	return dst;
+}
+
 /*
  * generate standard sockaddr_in6 from embedded form.
  */

Index: src/sys/sys/domain.h
diff -u src/sys/sys/domain.h:1.28 src/sys/sys/domain.h:1.29
--- src/sys/sys/domain.h:1.28	Wed May 27 23:44:35 2009
+++ src/sys/sys/domain.h	Fri Sep 11 22:06:29 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: domain.h,v 1.28 2009/05/27 23:44:35 pooka Exp $	*/
+/*	$NetBSD: domain.h,v 1.29 2009/09/11 22:06:29 dyoung Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1993
@@ -75,6 +75,9 @@
 	void	*(*dom_sockaddr_addr)(struct sockaddr *, socklen_t *);
 	int	(*dom_sockaddr_cmp)(const struct sockaddr *,
 	                            const struct sockaddr *);
+	struct sockaddr *(*dom_sockaddr_externalize)(struct sockaddr *,
+	                                             socklen_t,
+						     const struct sockaddr *);
 	const struct sockaddr *dom_sa_any;
 	struct ifqueue *dom_ifqueues[2]; /* ifqueue for domain */
 	STAILQ_ENTRY(domain) dom_link;

Index: src/sys/sys/socket.h
diff -u src/sys/sys/socket.h:1.95 src/sys/sys/socket.h:1.96
--- src/sys/sys/socket.h:1.95	Tue Apr 28 20:54:50 2009
+++ src/sys/sys/socket.h	Fri Sep 11 22:06:29 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: socket.h,v 1.95 2009/04/28 20:54:50 dyoung Exp $	*/
+/*	$NetBSD: socket.h,v 1.96 2009/09/11 22:06:29 dyoung Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -573,6 +573,8 @@
 __BEGIN_DECLS
 struct sockaddr *sockaddr_copy(struct sockaddr *, socklen_t,
     const struct sockaddr *);
+struct sockaddr *sockaddr_externalize(struct sockaddr *, socklen_t,
+    const struct sockaddr *);
 struct sockaddr *sockaddr_alloc(sa_family_t, socklen_t, int);
 const void *sockaddr_const_addr(const struct sockaddr *, socklen_t *);
 void *sockaddr_addr(struct sockaddr *, socklen_t *);

Index: src/sys/sys/socketvar.h
diff -u src/sys/sys/socketvar.h:1.120 src/sys/sys/socketvar.h:1.121
--- src/sys/sys/socketvar.h:1.120	Wed Sep  2 14:56:57 2009
+++ src/sys/sys/socketvar.h	Fri Sep 11 22:06:29 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: socketvar.h,v 1.120 2009/09/02 14:56:57 tls Exp $	*/
+/*	$NetBSD: socketvar.h,v 1.121 2009/09/11 22:06:29 dyoung Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -281,6 +281,7 @@
 void	soinit2(void);
 int	soabort(struct socket *);
 int	soaccept(struct socket *, struct mbuf *);
+int	sofamily(const struct socket *);
 int	sobind(struct socket *, struct mbuf *, struct lwp *);
 void	socantrcvmore(struct socket *);
 void	socantsendmore(struct socket *);

Reply via email to