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 *);