/*
- * Copyright (c) 2003-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2003-2018 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <sys/syslog.h>
#include <libkern/crypto/sha1.h>
#include <libkern/OSAtomic.h>
-#include <kern/lock.h>
+#include <kern/locks.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/route.h>
#include <net/kpi_protocol.h>
+#include <net/if_llatbl.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
/* XXX assumption on the size of IFID */
bcopy(seed1, &seed[8], 8);
- if (0) { /* for debugging purposes only */
+ if ((0)) { /* for debugging purposes only */
int i;
printf("%s: new randomized ID from: ", __func__);
*/
bcopy(&digest[8], seed0, 8);
- if (0) { /* for debugging purposes only */
+ if ((0)) { /* for debugging purposes only */
int i;
printf("to: ");
* address, and then reconfigure another one, the prefix is still
* valid with referring to the old link-local address.
*/
- if ((pr = nd6_prefix_lookup(&pr0)) == NULL) {
+ if ((pr = nd6_prefix_lookup(&pr0, ND6_PREFIX_EXPIRY_UNSPEC)) == NULL) {
if ((error = nd6_prelist_add(&pr0, NULL, &pr, TRUE)) != 0) {
IFA_REMREF(&ia->ia_ifa);
lck_mtx_destroy(&pr0.ndpr_lock, ifa_mtx_grp);
}
}
- in6_post_msg(ifp, KEV_INET6_NEW_LL_ADDR, ia);
+ in6_post_msg(ifp, KEV_INET6_NEW_LL_ADDR, ia, NULL);
IFA_REMREF(&ia->ia_ifa);
/* Drop use count held above during lookup/add */
* in6_update_ifa() does not use ifra_name, but we accurately set it
* for safety.
*/
- strncpy(ifra.ifra_name, if_name(ifp), sizeof (ifra.ifra_name));
+ strlcpy(ifra.ifra_name, if_name(ifp), sizeof (ifra.ifra_name));
ifra.ifra_prefixmask.sin6_len = sizeof (struct sockaddr_in6);
ifra.ifra_prefixmask.sin6_family = AF_INET6;
/* we don't need to perform DAD on loopback interfaces. */
ifra.ifra_flags |= IN6_IFF_NODAD;
- /* skip registration to the prefix list. XXX should be temporary. */
- ifra.ifra_flags |= IN6_IFF_NOPFX;
-
/* add the new interface address */
error = in6_update_ifa(ifp, &ifra, 0, &ia);
if (error != 0) {
if (p - name > sizeof (n) - 1)
return (-1); /* label too long */
l = p - name;
- strncpy(n, name, l);
+ strlcpy(n, name, l);
n[(int)l] = '\0';
for (q = (u_char *) n; *q; q++) {
if ('A' <= *q && *q <= 'Z')
struct in6_ifextra *ext;
void **pbuf, *base;
int error = 0;
+ struct in6_ifaddr *ia6 = NULL;
VERIFY(ifp != NULL);
* (previously, this was a silent error.)
*/
if ((ifp->if_flags & IFF_MULTICAST) == 0) {
- nd6log((LOG_INFO, "in6_ifattach: ",
+ nd6log0((LOG_INFO, "in6_ifattach: ",
"%s is not multicast capable, IPv6 not enabled\n",
if_name(ifp)));
return (EINVAL);
#endif
if (ifp->if_inet6data == NULL) {
- ext = (struct in6_ifextra *)_MALLOC(in6_extra_size, M_IFADDR,
+ ext = (struct in6_ifextra *)_MALLOC(in6_extra_bufsize, M_IFADDR,
M_WAITOK|M_ZERO);
if (!ext)
return (ENOMEM);
base = (void *)P2ROUNDUP((intptr_t)ext + sizeof(uint64_t),
sizeof(uint64_t));
- VERIFY(((intptr_t)base + in6_extra_size) <=
+ VERIFY(((intptr_t)base + in6_extra_size) <=
((intptr_t)ext + in6_extra_bufsize));
pbuf = (void **)((intptr_t)base - sizeof(void *));
*pbuf = ext;
ifp->if_inet6data = base;
+ IN6_IFEXTRA(ifp)->ii_llt = in6_lltattach(ifp);
VERIFY(IS_P2ALIGNED(ifp->if_inet6data, sizeof(uint64_t)));
} else {
/*
- * Since the structure is never freed, we need to zero out
+ * Since the structure is never freed, we need to zero out
* some of its members. We avoid zeroing out the scope6
* structure on purpose because other threads might be
* using its contents.
sizeof(IN6_IFEXTRA(ifp)->icmp6_ifstat));
bzero(&IN6_IFEXTRA(ifp)->in6_ifstat,
sizeof(IN6_IFEXTRA(ifp)->in6_ifstat));
+ /* XXX TBD Purge the layer two table */
+ /*
+ * XXX When recycling, nd_ifinfo gets initialized, other
+ * than the lock, inside nd6_ifattach
+ */
}
- /* initialize NDP variables */
- if ((error = nd6_ifattach(ifp)) != 0)
- return (error);
-
+ /*
+ * XXX Only initialize IPv6 configuration for the interface
+ * if interface has not yet been configured with
+ * link local IPv6 address.
+ * Could possibly be optimized with an interface flag if need
+ * be. For now using in6ifa_ifpforlinklocal.
+ */
+ ia6 = in6ifa_ifpforlinklocal(ifp, 0);
+ if (ia6 == NULL) {
+ IN6_IFEXTRA(ifp)->netsig_len = 0;
+ bzero(&IN6_IFEXTRA(ifp)->netsig,
+ sizeof(IN6_IFEXTRA(ifp)->netsig));
+ bzero(IN6_IFEXTRA(ifp)->nat64_prefixes,
+ sizeof(IN6_IFEXTRA(ifp)->nat64_prefixes));
+ /* initialize NDP variables */
+ nd6_ifattach(ifp);
+ } else {
+ VERIFY(ND_IFINFO(ifp)->initialized);
+ IFA_REMREF(&ia6->ia_ifa);
+ ia6 = NULL;
+ }
scope6_ifattach(ifp);
/* initialize loopback interface address */
return (0);
}
+/*
+ * This routine is only meant to configure IPv6 Link Local
+ * addresses.
+ */
int
in6_ifattach_aliasreq(struct ifnet *ifp, struct ifnet *altifp,
struct in6_aliasreq *ifra0)
if (!ip6_auto_linklocal)
return (0);
- /* assign a link-local address, only if there isn't one here already. */
+ /*
+ * Assign a link-local address, only if there isn't one here already.
+ * XXX If we ever allow more than one LLA on the interface
+ * make sure that the corresponding prefix on the prefixlist
+ * is reference counted and the address's prefix pointer
+ * points to the prefix.
+ */
ia6 = in6ifa_ifpforlinklocal(ifp, 0);
if (ia6 != NULL) {
IFA_REMREF(&ia6->ia_ifa);
* in6_update_ifa() does not use ifra_name, but we accurately set it
* for safety.
*/
- strncpy(ifra.ifra_name, if_name(ifp), sizeof (ifra.ifra_name));
+ strlcpy(ifra.ifra_name, if_name(ifp), sizeof (ifra.ifra_name));
/* Initialize the IPv6 interface address in our in6_aliasreq block */
- if ((ifp->if_eflags & IFEF_NOAUTOIPV6LL) != 0 && ifra0 != NULL) {
+ if (ifra0 != NULL) {
/* interface provided both addresses for us */
struct sockaddr_in6 *sin6 = &ifra.ifra_addr;
struct in6_addr *in6 = &sin6->sin6_addr;
}
int
-in6_ifattach_llstartreq(struct ifnet *ifp, struct in6_llstartreq *llsr)
+in6_ifattach_llcgareq(struct ifnet *ifp, struct in6_cgareq *llcgasr)
{
struct in6_aliasreq ifra;
- struct in6_ifaddr *ia6;
- struct nd_ifinfo *ndi;
+ struct in6_ifaddr *ia6 = NULL;
+ struct nd_ifinfo *ndi = NULL;
int error;
- VERIFY(llsr != NULL);
+ VERIFY(llcgasr != NULL);
error = in6_ifattach_prelim(ifp);
if (error != 0)
return (error);
- if (!ip6_auto_linklocal || (ifp->if_eflags & IFEF_NOAUTOIPV6LL) != 0)
+ if (!ip6_auto_linklocal)
return (0);
if (nd6_send_opstate == ND6_SEND_OPMODE_DISABLED)
return (ENXIO);
- lck_rw_lock_shared(nd_if_rwlock);
ndi = ND_IFINFO(ifp);
VERIFY(ndi != NULL && ndi->initialized);
if ((ndi->flags & ND6_IFF_INSECURE) != 0) {
- lck_rw_done(nd_if_rwlock);
return (ENXIO);
}
- lck_rw_done(nd_if_rwlock);
- /* assign a link-local address, only if there isn't one here already. */
+ /*
+ * Assign a link-local address, only if there isn't one here already.
+ * XXX If we ever allow more than one LLA on the interface
+ * make sure that the corresponding prefix on the prefixlist
+ * is reference counted and the address's prefix pointer
+ * points to the prefix.
+ */
ia6 = in6ifa_ifpforlinklocal(ifp, 0);
if (ia6 != NULL) {
IFA_REMREF(&ia6->ia_ifa);
}
bzero(&ifra, sizeof (ifra));
- strncpy(ifra.ifra_name, if_name(ifp), sizeof (ifra.ifra_name));
+ strlcpy(ifra.ifra_name, if_name(ifp), sizeof (ifra.ifra_name));
ifra.ifra_addr.sin6_family = AF_INET6;
ifra.ifra_addr.sin6_len = sizeof (struct sockaddr_in6);
ifra.ifra_flags = IN6_IFF_SECURED;
in6_cga_node_lock();
- if (in6_cga_generate(&llsr->llsr_cgaprep, 0,
+ if (in6_cga_generate(&llcgasr->cgar_cgaprep, 0,
&ifra.ifra_addr.sin6_addr)) {
in6_cga_node_unlock();
return (EADDRNOTAVAIL);
* identifiers].
*/
ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
- ifra.ifra_lifetime.ia6t_pltime = llsr->llsr_lifetime.ia6t_pltime;
+ ifra.ifra_lifetime.ia6t_pltime = llcgasr->cgar_lifetime.ia6t_pltime;
/* Attach the link-local address */
if (in6_ifattach_linklocal(ifp, &ifra) != 0) {
struct in6_multi_mship *imm;
int unlinked;
- lck_mtx_assert(nd6_mutex, LCK_MTX_ASSERT_NOTOWNED);
+ LCK_MTX_ASSERT(nd6_mutex, LCK_MTX_ASSERT_NOTOWNED);
/* remove neighbor management table */
nd6_purge(ifp);
+ if (LLTABLE6(ifp))
+ lltable_free(LLTABLE6(ifp));
+
/* nuke any of IPv6 addresses we have */
lck_rw_lock_exclusive(&in6_ifaddr_rwlock);
ia = in6_ifaddrs;
int generate)
{
u_int8_t nullbuf[8];
- struct nd_ifinfo *ndi;
+ struct nd_ifinfo *ndi = ND_IFINFO(ifp);
- lck_rw_lock_shared(nd_if_rwlock);
- ndi = ND_IFINFO(ifp);
VERIFY(ndi != NULL && ndi->initialized);
lck_mtx_lock(&ndi->lock);
bzero(nullbuf, sizeof (nullbuf));
bcopy(ndi->randomid, retbuf, 8);
lck_mtx_unlock(&ndi->lock);
- lck_rw_done(nd_if_rwlock);
}
void
in6_tmpaddrtimer(void *arg)
{
#pragma unused(arg)
- int i;
- struct nd_ifinfo *ndi;
+ struct ifnet *ifp = NULL;
+ struct nd_ifinfo *ndi = NULL;
u_int8_t nullbuf[8];
timeout(in6_tmpaddrtimer, (caddr_t)0, (ip6_temp_preferred_lifetime -
ip6_desync_factor - ip6_temp_regen_advance) * hz);
- lck_rw_lock_shared(nd_if_rwlock);
bzero(nullbuf, sizeof (nullbuf));
- for (i = 1; i < if_index + 1; i++) {
- if (!nd_ifinfo || i >= nd_ifinfo_indexlim)
- break;
- ndi = &nd_ifinfo[i];
- if (!ndi->initialized)
+ ifnet_head_lock_shared();
+ for (ifp = ifnet_head.tqh_first; ifp;
+ ifp = ifp->if_link.tqe_next) {
+ ndi = ND_IFINFO(ifp);
+ if ((NULL == ndi) || (FALSE == ndi->initialized)) {
continue;
+ }
lck_mtx_lock(&ndi->lock);
if (bcmp(ndi->randomid, nullbuf, sizeof (nullbuf)) != 0) {
/*
}
lck_mtx_unlock(&ndi->lock);
}
- lck_rw_done(nd_if_rwlock);
+ ifnet_head_done();
}