X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0b4e3aa066abc0728aacb4bbeb86f53f9737156e..0b4c1975fb5e4eccf1012a35081f7e7799b81046:/bsd/netinet6/in6_prefix.c diff --git a/bsd/netinet6/in6_prefix.c b/bsd/netinet6/in6_prefix.c index a1afb0124..891917965 100644 --- a/bsd/netinet6/in6_prefix.c +++ b/bsd/netinet6/in6_prefix.c @@ -1,3 +1,31 @@ +/* + * Copyright (c) 2008 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + /* $KAME: in6_prefix.c,v 1.27 2000/03/29 23:13:13 itojun Exp $ */ /* @@ -65,9 +93,6 @@ */ #include -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) -#include -#endif #include #include #include @@ -75,9 +100,7 @@ #include #include #include -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) #include -#endif #include @@ -87,22 +110,26 @@ #include #include -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 -static MALLOC_DEFINE(M_IPFW, "ip6rr", "IPv6 Router Renumbering Prefix"); -static MALLOC_DEFINE(M_IPFW, "rp_addr", "IPv6 Router Renumbering Ifid"); +#ifdef __APPLE__ +#define M_IP6RR M_IP6MISC +#define M_RR_ADDR M_IP6MISC +#else +static MALLOC_DEFINE(M_IP6RR, "ip6rr", "IPv6 Router Renumbering Prefix"); +static MALLOC_DEFINE(M_RR_ADDR, "rp_addr", "IPv6 Router Renumbering Ifid"); #endif struct rr_prhead rr_prefix; #include -static void add_each_addr __P((struct socket *so, struct rr_prefix *rpp, - struct rp_addr *rap)); -static int create_ra_entry __P((struct rp_addr **rapp)); -static int add_each_prefix __P((struct socket *so, struct rr_prefix *rpp)); -static void free_rp_entries __P((struct rr_prefix *rpp)); -static int link_stray_ia6s __P((struct rr_prefix *rpp)); -static void rp_remove __P((struct rr_prefix *rpp)); +static void add_each_addr(struct socket *so, struct rr_prefix *rpp, + struct rp_addr *rap); +static int create_ra_entry(struct rp_addr **rapp); +static int add_each_prefix(struct socket *so, struct rr_prefix *rpp); +static void free_rp_entries(struct rr_prefix *rpp); +static int link_stray_ia6s(struct rr_prefix *rpp); +static void rp_remove(struct rr_prefix *rpp); +extern lck_mtx_t *prefix6_mutex; /* * Copy bits from src to tgt, from off bit for len bits. @@ -160,16 +187,21 @@ in6_prefixwithifp(struct ifnet *ifp, int plen, struct in6_addr *dst) struct ifprefix *ifpr; /* search matched prefix */ - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { + ifnet_lock_shared(ifp); + for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; + ifpr = TAILQ_NEXT(ifpr, ifpr_list)) + { if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; if (plen <= in6_matchlen(dst, IFPR_IN6(ifpr))) break; } + ifnet_lock_done(ifp); return (ifpr); } +#if 0 /* * Search prefix which matches arg prefix as specified in * draft-ietf-ipngwg-router-renum-08.txt @@ -192,11 +224,8 @@ search_matched_prefix(struct ifnet *ifp, struct in6_prefixreq *ipr) * which matches the addr */ -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif + ifnet_lock_shared(ifp); + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -204,14 +233,20 @@ search_matched_prefix(struct ifnet *ifp, struct in6_prefixreq *ipr) in6_matchlen(&ipr->ipr_prefix.sin6_addr, IFA_IN6(ifa))) break; } - if (ifa == NULL) + if (ifa == NULL) { + ifnet_lock_done(ifp); return NULL; + } rpp = ifpr2rp(((struct in6_ifaddr *)ifa)->ia6_ifpr); - if (rpp != 0) + if (rpp != 0) { + ifnet_lock_done(ifp); return rpp; - - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { + } + + for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; + ifpr = TAILQ_NEXT(ifpr, ifpr_list)) + { if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; @@ -219,6 +254,7 @@ search_matched_prefix(struct ifnet *ifp, struct in6_prefixreq *ipr) IFPR_IN6(ifpr))) break; } + ifnet_lock_done(ifp); if (ifpr != NULL) log(LOG_ERR, "in6_prefix.c: search_matched_prefix: addr %s" "has no pointer to prefix %s\n", ip6_sprintf(IFA_IN6(ifa)), @@ -232,14 +268,17 @@ search_matched_prefix(struct ifnet *ifp, struct in6_prefixreq *ipr) * Return 1 if anything matched, and 0 if nothing matched. */ static int -mark_matched_prefixes(u_long cmd, struct ifnet *ifp, struct in6_rrenumreq *irr) +mark_matched_prefixes(u_int32_t cmd, struct ifnet *ifp, struct in6_rrenumreq *irr) { struct ifprefix *ifpr; struct ifaddr *ifa; int matchlen, matched = 0; /* search matched prefixes */ - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { + ifnet_lock_exclusive(ifp); /* Should if_prefixhead be protected by IPv6?? */ + for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; + ifpr = TAILQ_NEXT(ifpr, ifpr_list)) + { if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; @@ -259,11 +298,7 @@ mark_matched_prefixes(u_long cmd, struct ifnet *ifp, struct in6_rrenumreq *irr) * search matched addr, and then search prefixes * which matche the addr */ -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { struct rr_prefix *rpp; @@ -286,6 +321,7 @@ mark_matched_prefixes(u_long cmd, struct ifnet *ifp, struct in6_rrenumreq *irr) "ND autoconfigured addr?\n", ip6_sprintf(IFA_IN6(ifa))); } + ifnet_lock_done(ifp); return matched; } @@ -293,12 +329,15 @@ mark_matched_prefixes(u_long cmd, struct ifnet *ifp, struct in6_rrenumreq *irr) * Mark global prefixes as to be deleted. */ static void -delmark_global_prefixes(struct ifnet *ifp, struct in6_rrenumreq *irr) +delmark_global_prefixes(struct ifnet *ifp, __unused struct in6_rrenumreq *irr) { struct ifprefix *ifpr; /* search matched prefixes */ - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { + ifnet_lock_exclusive(ifp); + for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; + ifpr = TAILQ_NEXT(ifpr, ifpr_list)) + { if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; @@ -307,6 +346,7 @@ delmark_global_prefixes(struct ifnet *ifp, struct in6_rrenumreq *irr) IPV6_ADDR_SCOPE_GLOBAL) ifpr2rp(ifpr)->rp_statef_delmark = 1; } + ifnet_lock_done(ifp); } /* Unmark prefixes */ @@ -316,7 +356,10 @@ unmark_prefixes(struct ifnet *ifp) struct ifprefix *ifpr; /* unmark all prefix */ - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { + ifnet_lock_exclusive(ifp); + for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; + ifpr = TAILQ_NEXT(ifpr, ifpr_list)) + { if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; @@ -324,25 +367,27 @@ unmark_prefixes(struct ifnet *ifp) ifpr2rp(ifpr)->rp_statef_addmark = 0; ifpr2rp(ifpr)->rp_statef_delmark = 0; } + ifnet_lock_done(ifp); } +#endif static void init_prefix_ltimes(struct rr_prefix *rpp) { -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__) - long time_second = time.tv_sec; -#endif + struct timeval timenow; + + getmicrotime(&timenow); if (rpp->rp_pltime == RR_INFINITE_LIFETIME || rpp->rp_rrf_decrprefd == 0) rpp->rp_preferred = 0; else - rpp->rp_preferred = time_second + rpp->rp_pltime; + rpp->rp_preferred = timenow.tv_sec + rpp->rp_pltime; if (rpp->rp_vltime == RR_INFINITE_LIFETIME || rpp->rp_rrf_decrvalid == 0) rpp->rp_expire = 0; else - rpp->rp_expire = time_second + rpp->rp_vltime; + rpp->rp_expire = timenow.tv_sec + rpp->rp_vltime; } static int @@ -380,21 +425,23 @@ search_ifidwithprefix(struct rr_prefix *rpp, struct in6_addr *ifid) { struct rp_addr *rap; - for (rap = rpp->rp_addrhead.lh_first; rap != NULL; - rap = rap->ra_entry.le_next) + lck_mtx_lock(prefix6_mutex); + LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry) + { if (rr_are_ifid_equal(ifid, &rap->ra_ifid, (sizeof(struct in6_addr) << 3) - rpp->rp_plen)) break; + } + lck_mtx_unlock(prefix6_mutex); return rap; } static int -assigne_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia) +assign_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia) { int error = 0; struct rp_addr *rap; - int s; if ((error = create_ra_entry(&rap)) != 0) return error; @@ -405,24 +452,28 @@ assigne_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia) sizeof(*IA6_IN6(ia)) << 3, rpp->rp_plen, iilen); /* link to ia, and put into list */ rap->ra_addr = ia; - rap->ra_addr->ia_ifa.ifa_refcnt++; + ifaref(&rap->ra_addr->ia_ifa); #if 0 /* Can't do this now, because rpp may be on th stack. should fix it? */ ia->ia6_ifpr = rp2ifpr(rpp); #endif - s = splnet(); + lck_mtx_lock(prefix6_mutex); LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry); - splx(s); + lck_mtx_unlock(prefix6_mutex); return 0; } +/* + * add a link-local address to an interface. we will add new interface address + * (prefix database + new interface id). + */ static int -in6_prefix_add_llifid(int iilen, struct in6_ifaddr *ia) +in6_prefix_add_llifid(__unused int iilen, struct in6_ifaddr *ia) { struct rr_prefix *rpp; struct rp_addr *rap; struct socket so; - int error, s; + int error; if ((error = create_ra_entry(&rap)) != 0) return(error); @@ -433,21 +484,26 @@ in6_prefix_add_llifid(int iilen, struct in6_ifaddr *ia) /* XXX: init dummy so */ bzero(&so, sizeof(so)); /* insert into list */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) + lck_mtx_lock(prefix6_mutex); LIST_FOREACH(rpp, &rr_prefix, rp_entry) -#else - for (rpp = LIST_FIRST(&rr_prefix); rpp; rpp = LIST_NEXT(rpp, rp_entry)) -#endif { - s = splnet(); + /* + * do not attempt to add an address, if ifp does not match + */ + if (rpp->rp_ifp != ia->ia_ifp) + continue; + LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry); - splx(s); add_each_addr(&so, rpp, rap); } + lck_mtx_unlock(prefix6_mutex); return 0; } - +/* + * add an address to an interface. if the interface id portion is new, + * we will add new interface address (prefix database + new interface id). + */ int in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia) { @@ -462,7 +518,7 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia) if (ifpr == NULL) { struct rr_prefix rp; struct socket so; - int pplen = (plen == 128) ? 64 : plen; + int pplen = (plen == 128) ? 64 : plen; /* XXX hardcoded 64 is bad */ /* allocate a prefix for ia, with default properties */ @@ -493,9 +549,6 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia) /* XXX: init dummy so */ bzero(&so, sizeof(so)); -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__NetBSD__) - so.so_state |= SS_PRIV; -#endif error = add_each_prefix(&so, &rp); @@ -514,11 +567,11 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia) if (rap != NULL) { if (rap->ra_addr == NULL) { rap->ra_addr = ia; - rap->ra_addr->ia_ifa.ifa_refcnt++; + ifaref(&rap->ra_addr->ia_ifa); } else if (rap->ra_addr != ia) { /* There may be some inconsistencies between addrs. */ log(LOG_ERR, "ip6_prefix.c: addr %s/%d matched prefix" - "has already another ia %x(%s) on its ifid list\n", + " already has another ia %p(%s) on its ifid list\n", ip6_sprintf(IA6_IN6(ia)), plen, rap->ra_addr, ip6_sprintf(IA6_IN6(rap->ra_addr))); @@ -527,14 +580,14 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia) ia->ia6_ifpr = ifpr; return 0; } - error = assigne_ra_entry(ifpr2rp(ifpr), iilen, ia); + error = assign_ra_entry(ifpr2rp(ifpr), iilen, ia); if (error == 0) ia->ia6_ifpr = ifpr; return (error); } void -in6_prefix_remove_ifid(int iilen, struct in6_ifaddr *ia) +in6_prefix_remove_ifid(__unused int iilen, struct in6_ifaddr *ia) { struct rp_addr *rap; @@ -542,46 +595,36 @@ in6_prefix_remove_ifid(int iilen, struct in6_ifaddr *ia) return; rap = search_ifidwithprefix(ifpr2rp(ia->ia6_ifpr), IA6_IN6(ia)); if (rap != NULL) { - int s = splnet(); + lck_mtx_lock(prefix6_mutex); LIST_REMOVE(rap, ra_entry); - splx(s); + lck_mtx_unlock(prefix6_mutex); if (rap->ra_addr) - IFAFREE(&rap->ra_addr->ia_ifa); - _FREE(rap, M_IPFW); + ifafree(&rap->ra_addr->ia_ifa); + FREE(rap, M_RR_ADDR); } -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) if (LIST_EMPTY(&ifpr2rp(ia->ia6_ifpr)->rp_addrhead)) -#else - if (LIST_FIRST(&ifpr2rp(ia->ia6_ifpr)->rp_addrhead) == NULL) -#endif rp_remove(ifpr2rp(ia->ia6_ifpr)); } void -in6_purgeprefix(ifp) - struct ifnet *ifp; +in6_purgeprefix( + struct ifnet *ifp) { struct ifprefix *ifpr, *nextifpr; /* delete prefixes before ifnet goes away */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 4 + ifnet_lock_exclusive(ifp); for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; ifpr = nextifpr) -#else - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = nextifpr) -#endif { -#if defined(__FreeBSD__) && __FreeBSD__ >= 4 nextifpr = TAILQ_NEXT(ifpr, ifpr_list); -#else - nextifpr = ifpr->ifpr_next; -#endif if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; (void)delete_each_prefix(ifpr2rp(ifpr), PR_ORIG_KERNEL); } + ifnet_lock_done(ifp); } static void @@ -589,7 +632,8 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap) { struct in6_ifaddr *ia6; struct in6_aliasreq ifra; - int error; + struct proc *p = current_proc(); + int error, p64 = proc_is64bit(p); /* init ifra */ bzero(&ifra, sizeof(ifra)); @@ -611,20 +655,30 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap) in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, rpp->rp_plen); /* don't care ifra_flags for now */ + /* + * XXX: if we did this with finite lifetime values, the lifetimes would + * decrese in time and never incremented. + * we should need more clarifications on the prefix mechanism... + */ + ifra.ifra_lifetime.ia6t_vltime = rpp->rp_vltime; + ifra.ifra_lifetime.ia6t_pltime = rpp->rp_pltime; + ia6 = in6ifa_ifpwithaddr(rpp->rp_ifp, &ifra.ifra_addr.sin6_addr); if (ia6 != NULL) { if (ia6->ia6_ifpr == NULL) { /* link this addr and the prefix each other */ - IFAFREE(&rap->ra_addr->ia_ifa); + if (rap->ra_addr) + ifafree(&rap->ra_addr->ia_ifa); + /* Reference held in in6ifa_ifpwithaddr() */ rap->ra_addr = ia6; - rap->ra_addr->ia_ifa.ifa_refcnt++; ia6->ia6_ifpr = rp2ifpr(rpp); return; } if (ia6->ia6_ifpr == rp2ifpr(rpp)) { - IFAFREE(&rap->ra_addr->ia_ifa); + if (rap->ra_addr) + ifafree(&rap->ra_addr->ia_ifa); + /* Reference held in in6ifa_ifpwithaddr() */ rap->ra_addr = ia6; - rap->ra_addr->ia_ifa.ifa_refcnt++; return; } /* @@ -637,27 +691,56 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap) * Or, completely duplicated prefixes? * log it and return. */ - log(LOG_ERR, "in6_prefix.c: add_each_addr: addition of an addr" - "%s/%d failed because there is already another addr %s/%d\n", + log(LOG_ERR, + "in6_prefix.c: add_each_addr: addition of an addr %s/%d " + "failed because there is already another addr %s/%d\n", ip6_sprintf(&ifra.ifra_addr.sin6_addr), rpp->rp_plen, ip6_sprintf(IA6_IN6(ia6)), - in6_mask2len(&ia6->ia_prefixmask.sin6_addr)); + in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL)); + ifafree(&ia6->ia_ifa); return; } /* propagate ANYCAST flag if it is set for ancestor addr */ if (rap->ra_flags.anycast != 0) ifra.ifra_flags |= IN6_IFF_ANYCAST; - error = in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, rpp->rp_ifp -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !defined(__APPLE__) - , current_proc() -#endif - ); - if (error != 0) + + if (!p64) { +#if defined(__LP64__) + struct in6_aliasreq_32 ifra_32; + /* + * Use 32-bit ioctl and structure for 32-bit process. + */ + in6_aliasreq_64_to_32((struct in6_aliasreq_64 *)&ifra, + &ifra_32); + error = in6_control(so, SIOCAIFADDR_IN6_32, (caddr_t)&ifra_32, + rpp->rp_ifp, p); +#else + error = in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, + rpp->rp_ifp, p); +#endif /* __LP64__ */ + } else { +#if defined(__LP64__) + error = in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, + rpp->rp_ifp, p); +#else + struct in6_aliasreq_64 ifra_64; + /* + * Use 32-bit ioctl and structure for 32-bit process. + */ + in6_aliasreq_32_to_64((struct in6_aliasreq_32 *)&ifra, + &ifra_64); + error = in6_control(so, SIOCAIFADDR_IN6_64, (caddr_t)&ifra_64, + rpp->rp_ifp, p); +#endif /* __LP64__ */ + } + + if (error != 0) { log(LOG_ERR, "in6_prefix.c: add_each_addr: addition of an addr" "%s/%d failed because in6_control failed for error %d\n", ip6_sprintf(&ifra.ifra_addr.sin6_addr), rpp->rp_plen, error); return; + } /* * link beween this addr and the prefix will be done @@ -671,10 +754,12 @@ rrpr_update(struct socket *so, struct rr_prefix *new) struct rr_prefix *rpp; struct ifprefix *ifpr; struct rp_addr *rap; - int s; /* search existing prefix */ - for (ifpr = new->rp_ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) { + ifnet_lock_exclusive(new->rp_ifp); + for (ifpr = TAILQ_FIRST(&new->rp_ifp->if_prefixhead); ifpr; + ifpr = TAILQ_NEXT(ifpr, ifpr_list)) + { if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; @@ -692,8 +777,10 @@ rrpr_update(struct socket *so, struct rr_prefix *new) * If the origin of the already-installed prefix is more * preferable than the new one, ignore installation request. */ - if (rpp->rp_origin > new->rp_origin) + if (rpp->rp_origin > new->rp_origin) { + ifnet_lock_done(new->rp_ifp); return(EPERM); + } /* update prefix information */ rpp->rp_flags.prf_ra = new->rp_flags.prf_ra; @@ -709,73 +796,70 @@ rrpr_update(struct socket *so, struct rr_prefix *new) * add rp_addr entries in new into rpp, if they have not * been already included in rpp. */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined(__APPLE__) + lck_mtx_lock(prefix6_mutex); while (!LIST_EMPTY(&new->rp_addrhead)) -#else - while (new->rp_addrhead.lh_first != NULL) -#endif { rap = LIST_FIRST(&new->rp_addrhead); LIST_REMOVE(rap, ra_entry); if (search_ifidwithprefix(rpp, &rap->ra_ifid) != NULL) { if (rap->ra_addr) - IFAFREE(&rap->ra_addr->ia_ifa); - _FREE(rap, M_IPFW); + ifafree(&rap->ra_addr->ia_ifa); + FREE(rap, M_RR_ADDR); continue; } - s = splnet(); LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry); - splx(s); } + lck_mtx_unlock(prefix6_mutex); } else { /* * We got a fresh prefix. */ /* create new prefix */ - rpp = (struct rr_prefix *)_MALLOC(sizeof(*rpp), M_IPFW, + rpp = (struct rr_prefix *)_MALLOC(sizeof(*rpp), M_IP6RR, M_NOWAIT); if (rpp == NULL) { log(LOG_ERR, "in6_prefix.c: rrpr_update:%d" ": ENOBUFS for rr_prefix\n", __LINE__); + ifnet_lock_done(new->rp_ifp); return(ENOBUFS); } /* initilization */ + lck_mtx_lock(prefix6_mutex); *rpp = *new; LIST_INIT(&rpp->rp_addrhead); /* move rp_addr entries of new to rpp */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined(__APPLE__) while (!LIST_EMPTY(&new->rp_addrhead)) -#else - while (new->rp_addrhead.lh_first != NULL) -#endif { rap = LIST_FIRST(&new->rp_addrhead); LIST_REMOVE(rap, ra_entry); LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry); } + lck_mtx_unlock(prefix6_mutex); /* let rp_ifpr.ifpr_prefix point rr_prefix. */ rpp->rp_ifpr.ifpr_prefix = (struct sockaddr *)&rpp->rp_prefix; /* link rr_prefix entry to if_prefixlist */ { struct ifnet *ifp = rpp->rp_ifp; - struct ifprefix *ifpr; - if ((ifpr = ifp->if_prefixlist) != NULL) { - for ( ; ifpr->ifpr_next; - ifpr = ifpr->ifpr_next) + if ((ifpr = TAILQ_FIRST(&ifp->if_prefixhead)) + != NULL) { + for ( ; TAILQ_NEXT(ifpr, ifpr_list); + ifpr = TAILQ_NEXT(ifpr, ifpr_list)) continue; - ifpr->ifpr_next = rp2ifpr(rpp); + TAILQ_NEXT(ifpr, ifpr_list) = rp2ifpr(rpp); } else - ifp->if_prefixlist = rp2ifpr(rpp); + TAILQ_FIRST(&ifp->if_prefixhead) = + rp2ifpr(rpp); rp2ifpr(rpp)->ifpr_type = IN6_PREFIX_RR; } /* link rr_prefix entry to rr_prefix list */ - s = splnet(); + lck_mtx_lock(prefix6_mutex); LIST_INSERT_HEAD(&rr_prefix, rpp, rp_entry); - splx(s); + lck_mtx_unlock(prefix6_mutex); } + ifnet_lock_done(new->rp_ifp); if (!new->rp_raf_auto) return 0; @@ -785,8 +869,9 @@ rrpr_update(struct socket *so, struct rr_prefix *new) * If it existed but not pointing to the prefix yet, * init the prefix pointer. */ - for (rap = rpp->rp_addrhead.lh_first; rap != NULL; - rap = rap->ra_entry.le_next) { + lck_mtx_lock(prefix6_mutex); + LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry) + { if (rap->ra_addr != NULL) { if (rap->ra_addr->ia6_ifpr == NULL) rap->ra_addr->ia6_ifpr = rp2ifpr(rpp); @@ -794,6 +879,7 @@ rrpr_update(struct socket *so, struct rr_prefix *new) } add_each_addr(so, rpp, rap); } + lck_mtx_unlock(prefix6_mutex); return 0; } @@ -807,39 +893,42 @@ add_each_prefix(struct socket *so, struct rr_prefix *rpp) static void rp_remove(struct rr_prefix *rpp) { - int s; - s = splnet(); /* unlink rp_entry from if_prefixlist */ + lck_mtx_lock(prefix6_mutex); { struct ifnet *ifp = rpp->rp_ifp; struct ifprefix *ifpr; - if ((ifpr = ifp->if_prefixlist) == rp2ifpr(rpp)) - ifp->if_prefixlist = ifpr->ifpr_next; + ifnet_lock_exclusive(ifp); + if ((ifpr = TAILQ_FIRST(&ifp->if_prefixhead)) == rp2ifpr(rpp)) + TAILQ_FIRST(&ifp->if_prefixhead) = + TAILQ_NEXT(ifpr, ifpr_list); else { - while (ifpr->ifpr_next && - (ifpr->ifpr_next != rp2ifpr(rpp))) - ifpr = ifpr->ifpr_next; - if (ifpr->ifpr_next) - ifpr->ifpr_next = rp2ifpr(rpp)->ifpr_next; - else - printf("Couldn't unlink rr_prefix from ifp\n"); + while (TAILQ_NEXT(ifpr, ifpr_list) != NULL && + (TAILQ_NEXT(ifpr, ifpr_list) != rp2ifpr(rpp))) + ifpr = TAILQ_NEXT(ifpr, ifpr_list); + if (TAILQ_NEXT(ifpr, ifpr_list)) + TAILQ_NEXT(ifpr, ifpr_list) = + TAILQ_NEXT(rp2ifpr(rpp), ifpr_list); + else + printf("Couldn't unlink rr_prefix from ifp\n"); } + ifnet_lock_done(ifp); } /* unlink rp_entry from rr_prefix list */ LIST_REMOVE(rpp, rp_entry); - splx(s); - _FREE(rpp, M_IPFW); + lck_mtx_unlock(prefix6_mutex); + FREE(rpp, M_IP6RR); } static int create_ra_entry(struct rp_addr **rapp) { - *rapp = (struct rp_addr *)_MALLOC(sizeof(struct rp_addr), M_IPFW, + *rapp = (struct rp_addr *)_MALLOC(sizeof(struct rp_addr), M_RR_ADDR, M_NOWAIT); if (*rapp == NULL) { - log(LOG_ERR, "in6_prefix.c: init_newprefix:%d: ENOBUFS" + log(LOG_ERR, "in6_prefix.c:%d: ENOBUFS" "for rp_addr\n", __LINE__); return ENOBUFS; } @@ -848,6 +937,7 @@ create_ra_entry(struct rp_addr **rapp) return 0; } +#if 0 static int init_newprefix(struct in6_rrenumreq *irr, struct ifprefix *ifpr, struct rr_prefix *rpp) @@ -872,8 +962,9 @@ init_newprefix(struct in6_rrenumreq *irr, struct ifprefix *ifpr, irr->irr_u_uselen, min(ifpr->ifpr_plen - irr->irr_u_uselen, irr->irr_u_keeplen)); - for (orap = (ifpr2rp(ifpr)->rp_addrhead).lh_first; orap != NULL; - orap = orap->ra_entry.le_next) { + lck_mtx_lock(prefix6_mutex); + LIST_FOREACH(orap, &(ifpr2rp(ifpr)->rp_addrhead), ra_entry) + { struct rp_addr *rap; int error = 0; @@ -894,9 +985,11 @@ init_newprefix(struct in6_rrenumreq *irr, struct ifprefix *ifpr, /* Is some FlagMasks for rrf necessary? */ rpp->rp_rrf = irr->irr_rrf; rpp->rp_origin = irr->irr_origin; + lck_mtx_unlock(prefix6_mutex); return 0; } +#endif static void free_rp_entries(struct rr_prefix *rpp) @@ -905,22 +998,21 @@ free_rp_entries(struct rr_prefix *rpp) * This func is only called with rpp on stack(not on list). * So no splnet() here */ -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined(__APPLE__) + lck_mtx_lock(prefix6_mutex); while (!LIST_EMPTY(&rpp->rp_addrhead)) -#else - while (rpp->rp_addrhead.lh_first != NULL) -#endif { struct rp_addr *rap; rap = LIST_FIRST(&rpp->rp_addrhead); LIST_REMOVE(rap, ra_entry); if (rap->ra_addr) - IFAFREE(&rap->ra_addr->ia_ifa); - _FREE(rap, M_IPFW); + ifafree(&rap->ra_addr->ia_ifa); + FREE(rap, M_RR_ADDR); } + lck_mtx_unlock(prefix6_mutex); } +#if 0 static int add_useprefixes(struct socket *so, struct ifnet *ifp, struct in6_rrenumreq *irr) @@ -930,8 +1022,10 @@ add_useprefixes(struct socket *so, struct ifnet *ifp, int error = 0; /* add prefixes to each of marked prefix */ - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = nextifpr) { - nextifpr = ifpr->ifpr_next; + ifnet_lock_exclusive(ifp); + for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; ifpr = nextifpr) + { + nextifpr = TAILQ_NEXT(ifpr, ifpr_list); if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; @@ -941,27 +1035,32 @@ add_useprefixes(struct socket *so, struct ifnet *ifp, error = add_each_prefix(so, &rp); } } + ifnet_lock_done(ifp); /* free each rp_addr entry */ free_rp_entries(&rp); return error; } +#endif static void unprefer_prefix(struct rr_prefix *rpp) { struct rp_addr *rap; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) - long time_second = time.tv_sec; -#endif + struct timeval timenow; + + getmicrotime(&timenow); + lck_mtx_lock(prefix6_mutex); for (rap = rpp->rp_addrhead.lh_first; rap != NULL; rap = rap->ra_entry.le_next) { if (rap->ra_addr == NULL) continue; - rap->ra_addr->ia6_lifetime.ia6t_preferred = time_second; + rap->ra_addr->ia6_lifetime.ia6t_preferred = timenow.tv_sec; rap->ra_addr->ia6_lifetime.ia6t_pltime = 0; } + lck_mtx_unlock(prefix6_mutex); + } int @@ -972,58 +1071,59 @@ delete_each_prefix(struct rr_prefix *rpp, u_char origin) if (rpp->rp_origin > origin) return(EPERM); + lck_mtx_lock(prefix6_mutex); while (rpp->rp_addrhead.lh_first != NULL) { struct rp_addr *rap; - int s; - s = splnet(); rap = LIST_FIRST(&rpp->rp_addrhead); - if (rap == NULL) + if (rap == NULL) { break; + } LIST_REMOVE(rap, ra_entry); - splx(s); if (rap->ra_addr == NULL) { - _FREE(rap, M_IPFW); + FREE(rap, M_RR_ADDR); continue; } rap->ra_addr->ia6_ifpr = NULL; - in6_purgeaddr(&rap->ra_addr->ia_ifa, rpp->rp_ifp); - IFAFREE(&rap->ra_addr->ia_ifa); - _FREE(rap, M_IPFW); + in6_purgeaddr(&rap->ra_addr->ia_ifa, 0); + ifafree(&rap->ra_addr->ia_ifa); + FREE(rap, M_RR_ADDR); } rp_remove(rpp); + lck_mtx_unlock(prefix6_mutex); return error; } +#if 0 static void delete_prefixes(struct ifnet *ifp, u_char origin) { struct ifprefix *ifpr, *nextifpr; /* delete prefixes marked as tobe deleted */ - for (ifpr = ifp->if_prefixlist; ifpr; ifpr = nextifpr) { - nextifpr = ifpr->ifpr_next; + ifnet_lock_exclusive(ifp); + for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; ifpr = nextifpr) + { + nextifpr = TAILQ_NEXT(ifpr, ifpr_list); if (ifpr->ifpr_prefix->sa_family != AF_INET6 || ifpr->ifpr_type != IN6_PREFIX_RR) continue; if (ifpr2rp(ifpr)->rp_statef_delmark) (void)delete_each_prefix(ifpr2rp(ifpr), origin); } + ifnet_lock_done(ifp); } +#endif static int link_stray_ia6s(struct rr_prefix *rpp) { struct ifaddr *ifa; -#if (defined(__FreeBSD__) && __FreeBSD__ < 3) || defined(__bsdi__) - for (ifa = rpp->rp_ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else for (ifa = rpp->rp_ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif { struct rp_addr *rap; struct rr_prefix *orpp; @@ -1046,7 +1146,7 @@ link_stray_ia6s(struct rr_prefix *rpp) rpp->rp_plen); continue; } - if ((error = assigne_ra_entry(rpp, + if ((error = assign_ra_entry(rpp, (sizeof(rap->ra_ifid) << 3) - rpp->rp_plen, (struct in6_ifaddr *)ifa)) != 0) @@ -1055,6 +1155,7 @@ link_stray_ia6s(struct rr_prefix *rpp) return 0; } +#if 0 /* XXX assumes that permission is already checked by the caller */ int in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data, @@ -1068,7 +1169,7 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data, int error = 0; /* - * Failsafe for errneous address config program. + * Failsafe for erroneous address config program. * Let's hope rrenumd don't make a mistakes. */ if (ipr->ipr_origin <= PR_ORIG_RA) @@ -1085,7 +1186,7 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data, log(LOG_NOTICE, "in6_prefix_ioctl: preferred lifetime" "(%ld) is greater than valid lifetime(%ld)\n", - (u_long)irr->irr_pltime, (u_long)irr->irr_vltime); + (u_int32_t)irr->irr_pltime, (u_int32_t)irr->irr_vltime); error = EINVAL; break; } @@ -1120,7 +1221,7 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data, log(LOG_NOTICE, "in6_prefix_ioctl: preferred lifetime" "(%ld) is greater than valid lifetime(%ld)\n", - (u_long)ipr->ipr_pltime, (u_long)ipr->ipr_vltime); + (u_int32_t)ipr->ipr_pltime, (u_int32_t)ipr->ipr_vltime); error = EINVAL; break; } @@ -1140,13 +1241,10 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data, free_rp_entries(&rp_tmp); break; } -#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) -#else + ifnet_lock_exclusive(ifp); for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) -#endif { if (ifa->ifa_addr == NULL) continue; /* just for safety */ @@ -1167,8 +1265,11 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data, rp_tmp.rp_plen, (sizeof(rap->ra_ifid) << 3) - rp_tmp.rp_plen); /* insert into list */ + lck_mtx_lock(prefix6_mutex); LIST_INSERT_HEAD(&rp_tmp.rp_addrhead, rap, ra_entry); + lck_mtx_unlock(prefix6_mutex); } + ifnet_lock_done(ifp); error = add_each_prefix(so, &rp_tmp); @@ -1181,42 +1282,29 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data, if (rpp == NULL || ifp != rpp->rp_ifp) return (EADDRNOTAVAIL); + ifnet_lock_exclusive(ifp); error = delete_each_prefix(rpp, ipr->ipr_origin); + ifnet_lock_done(ifp); break; } bad: return error; } - -void -in6_rr_timer_funneled(void *ignored_arg) -{ -#ifdef __APPLE__ - boolean_t funnel_state; - funnel_state = thread_funnel_set(network_flock, TRUE); -#endif - in6_rr_timer(ignored_arg); -#ifdef __APPLE__ - (void) thread_funnel_set(network_flock, FALSE); #endif -} void -in6_rr_timer(void *ignored_arg) +in6_rr_timer(__unused void *ignored_arg) { - int s; struct rr_prefix *rpp; -#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__) - long time_second = time.tv_sec; -#endif + struct timeval timenow; - timeout(in6_rr_timer_funneled, (caddr_t)0, ip6_rr_prune * hz); + getmicrotime(&timenow); - s = splnet(); /* expire */ + lck_mtx_lock(prefix6_mutex); rpp = LIST_FIRST(&rr_prefix); while (rpp) { - if (rpp->rp_expire && rpp->rp_expire < time_second) { + if (rpp->rp_expire && rpp->rp_expire < timenow.tv_sec) { struct rr_prefix *next_rpp; next_rpp = LIST_NEXT(rpp, rp_entry); @@ -1224,9 +1312,10 @@ in6_rr_timer(void *ignored_arg) rpp = next_rpp; continue; } - if (rpp->rp_preferred && rpp->rp_preferred < time_second) + if (rpp->rp_preferred && rpp->rp_preferred < timenow.tv_sec) unprefer_prefix(rpp); rpp = LIST_NEXT(rpp, rp_entry); } - splx(s); + lck_mtx_unlock(prefix6_mutex); + timeout(in6_rr_timer, (caddr_t)0, ip6_rr_prune * hz); }