Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 4 Feb 2014 09:30:42 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r261480 - in user/ae/inet6: gnu/lib/libgcc sys/amd64/vmm/intel sys/ia64/conf sys/net sys/netinet sys/netinet6 sys/ofed/drivers/infiniband/ulp/ipoib sys/powerpc/powermac usr.sbin/bsdinst...
Message-ID:  <201402040930.s149Ugwr078172@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Tue Feb  4 09:30:42 2014
New Revision: 261480
URL: http://svnweb.freebsd.org/changeset/base/261480

Log:
  Merge from head/ up to r260882.

Modified:
  user/ae/inet6/gnu/lib/libgcc/Makefile
  user/ae/inet6/sys/amd64/vmm/intel/vmx.c
  user/ae/inet6/sys/ia64/conf/GENERIC
  user/ae/inet6/sys/net/ieee8023ad_lacp.c
  user/ae/inet6/sys/net/if.c
  user/ae/inet6/sys/net/if_arcsubr.c
  user/ae/inet6/sys/net/if_dl.h
  user/ae/inet6/sys/net/if_ethersubr.c
  user/ae/inet6/sys/net/if_fddisubr.c
  user/ae/inet6/sys/net/if_iso88025subr.c
  user/ae/inet6/sys/net/if_lagg.c
  user/ae/inet6/sys/netinet/ip_carp.c
  user/ae/inet6/sys/netinet/tcp_syncache.c
  user/ae/inet6/sys/netinet6/in6.c
  user/ae/inet6/sys/netinet6/in6_var.h
  user/ae/inet6/sys/netinet6/nd6.c
  user/ae/inet6/sys/netinet6/nd6.h
  user/ae/inet6/sys/netinet6/nd6_rtr.c
  user/ae/inet6/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c
  user/ae/inet6/sys/powerpc/powermac/pmu.c
  user/ae/inet6/usr.sbin/bsdinstall/scripts/services
Directory Properties:
  user/ae/inet6/   (props changed)
  user/ae/inet6/gnu/lib/   (props changed)
  user/ae/inet6/sys/   (props changed)
  user/ae/inet6/sys/amd64/vmm/   (props changed)

Modified: user/ae/inet6/gnu/lib/libgcc/Makefile
==============================================================================
--- user/ae/inet6/gnu/lib/libgcc/Makefile	Tue Feb  4 09:11:50 2014	(r261479)
+++ user/ae/inet6/gnu/lib/libgcc/Makefile	Tue Feb  4 09:30:42 2014	(r261480)
@@ -34,9 +34,9 @@ OBJS=		# added to below in various ways 
 
 #---------------------------------------------------------------------------
 #
-# When upgrading GCC, get the following defintions straight from Makefile.in
-#
 # Library members defined in libgcc2.c.
+# When upgrading GCC, obtain the following list from mklibgcc.in
+#
 LIB2FUNCS= _muldi3 _negdi2 _lshrdi3 _ashldi3 _ashrdi3 \
 	_cmpdi2 _ucmpdi2 \
 	_enable_execute_stack _trampoline __main _absvsi2 _absvdi2 _addvsi3 \
@@ -44,7 +44,7 @@ LIB2FUNCS= _muldi3 _negdi2 _lshrdi3 _ash
 	_ffssi2 _ffsdi2 _clz _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _popcount_tab \
 	_popcountsi2 _popcountdi2 _paritysi2 _paritydi2 _powisf2 _powidf2 \
 	_powixf2 _powitf2 _mulsc3 _muldc3 _mulxc3 _multc3 _divsc3 _divdc3 \
-	_divxc3 _divtc3
+	_divxc3 _divtc3 _bswapsi2 _bswapdi2
 .if ${COMPILER_TYPE} != "clang" || ${TARGET_CPUARCH} != "arm"
 LIB2FUNCS+= _clear_cache
 .endif
@@ -145,7 +145,6 @@ LIB1ASMFUNCS = __divxf3 __divdf3 __divsf
 	__divsi3 __modsi3 __udivsi3 __umodsi3 __save_stack_nonlocal \
 	__nonlocal_goto __restore_stack_nonlocal __trampoline \
 	_fixtfdi _fixunstfdi _floatditf
-LIB2FUNCS += _bswapsi2 _bswapdi2
 LIB2ADDEH = unwind-ia64.c unwind-sjlj.c unwind-c.c
 .endif
 

Modified: user/ae/inet6/sys/amd64/vmm/intel/vmx.c
==============================================================================
--- user/ae/inet6/sys/amd64/vmm/intel/vmx.c	Tue Feb  4 09:11:50 2014	(r261479)
+++ user/ae/inet6/sys/amd64/vmm/intel/vmx.c	Tue Feb  4 09:30:42 2014	(r261480)
@@ -147,21 +147,6 @@ SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, initia
 	   &vmx_initialized, 0, "Intel VMX initialized");
 
 /*
- * Virtual NMI blocking conditions.
- *
- * Some processor implementations also require NMI to be blocked if
- * the STI_BLOCKING bit is set. It is possible to detect this at runtime
- * based on the (exit_reason,exit_qual) tuple being set to 
- * (EXIT_REASON_INVAL_VMCS, EXIT_QUAL_NMI_WHILE_STI_BLOCKING).
- *
- * We take the easy way out and also include STI_BLOCKING as one of the
- * gating items for vNMI injection.
- */
-static uint64_t nmi_blocking_bits = VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING |
-				    VMCS_INTERRUPTIBILITY_NMI_BLOCKING |
-				    VMCS_INTERRUPTIBILITY_STI_BLOCKING;
-
-/*
  * Optional capabilities
  */
 static int cap_halt_exit;
@@ -1020,117 +1005,145 @@ static void __inline
 vmx_set_int_window_exiting(struct vmx *vmx, int vcpu)
 {
 
-	vmx->cap[vcpu].proc_ctls |= PROCBASED_INT_WINDOW_EXITING;
-	vmcs_write(VMCS_PRI_PROC_BASED_CTLS, vmx->cap[vcpu].proc_ctls);
+	if ((vmx->cap[vcpu].proc_ctls & PROCBASED_INT_WINDOW_EXITING) == 0) {
+		vmx->cap[vcpu].proc_ctls |= PROCBASED_INT_WINDOW_EXITING;
+		vmcs_write(VMCS_PRI_PROC_BASED_CTLS, vmx->cap[vcpu].proc_ctls);
+		VCPU_CTR0(vmx->vm, vcpu, "Enabling interrupt window exiting");
+	}
 }
 
 static void __inline
 vmx_clear_int_window_exiting(struct vmx *vmx, int vcpu)
 {
 
+	KASSERT((vmx->cap[vcpu].proc_ctls & PROCBASED_INT_WINDOW_EXITING) != 0,
+	    ("intr_window_exiting not set: %#x", vmx->cap[vcpu].proc_ctls));
 	vmx->cap[vcpu].proc_ctls &= ~PROCBASED_INT_WINDOW_EXITING;
 	vmcs_write(VMCS_PRI_PROC_BASED_CTLS, vmx->cap[vcpu].proc_ctls);
+	VCPU_CTR0(vmx->vm, vcpu, "Disabling interrupt window exiting");
 }
 
 static void __inline
 vmx_set_nmi_window_exiting(struct vmx *vmx, int vcpu)
 {
 
-	vmx->cap[vcpu].proc_ctls |= PROCBASED_NMI_WINDOW_EXITING;
-	vmcs_write(VMCS_PRI_PROC_BASED_CTLS, vmx->cap[vcpu].proc_ctls);
+	if ((vmx->cap[vcpu].proc_ctls & PROCBASED_NMI_WINDOW_EXITING) == 0) {
+		vmx->cap[vcpu].proc_ctls |= PROCBASED_NMI_WINDOW_EXITING;
+		vmcs_write(VMCS_PRI_PROC_BASED_CTLS, vmx->cap[vcpu].proc_ctls);
+		VCPU_CTR0(vmx->vm, vcpu, "Enabling NMI window exiting");
+	}
 }
 
 static void __inline
 vmx_clear_nmi_window_exiting(struct vmx *vmx, int vcpu)
 {
 
+	KASSERT((vmx->cap[vcpu].proc_ctls & PROCBASED_NMI_WINDOW_EXITING) != 0,
+	    ("nmi_window_exiting not set %#x", vmx->cap[vcpu].proc_ctls));
 	vmx->cap[vcpu].proc_ctls &= ~PROCBASED_NMI_WINDOW_EXITING;
 	vmcs_write(VMCS_PRI_PROC_BASED_CTLS, vmx->cap[vcpu].proc_ctls);
+	VCPU_CTR0(vmx->vm, vcpu, "Disabling NMI window exiting");
 }
 
-static int
+#define	NMI_BLOCKING	(VMCS_INTERRUPTIBILITY_NMI_BLOCKING |		\
+			 VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING)
+#define	HWINTR_BLOCKING	(VMCS_INTERRUPTIBILITY_STI_BLOCKING |		\
+			 VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING)
+
+static void
 vmx_inject_nmi(struct vmx *vmx, int vcpu)
 {
-	uint64_t info, interruptibility;
+	uint32_t gi, info;
 
-	/* Bail out if no NMI requested */
-	if (!vm_nmi_pending(vmx->vm, vcpu))
-		return (0);
+	gi = vmcs_read(VMCS_GUEST_INTERRUPTIBILITY);
+	KASSERT((gi & NMI_BLOCKING) == 0, ("vmx_inject_nmi: invalid guest "
+	    "interruptibility-state %#x", gi));
 
-	interruptibility = vmcs_read(VMCS_GUEST_INTERRUPTIBILITY);
-	if (interruptibility & nmi_blocking_bits)
-		goto nmiblocked;
+	info = vmcs_read(VMCS_ENTRY_INTR_INFO);
+	KASSERT((info & VMCS_INTR_VALID) == 0, ("vmx_inject_nmi: invalid "
+	    "VM-entry interruption information %#x", info));
 
 	/*
 	 * Inject the virtual NMI. The vector must be the NMI IDT entry
 	 * or the VMCS entry check will fail.
 	 */
-	info = VMCS_INTR_T_NMI | VMCS_INTR_VALID;
-	info |= IDT_NMI;
+	info = IDT_NMI | VMCS_INTR_T_NMI | VMCS_INTR_VALID;
 	vmcs_write(VMCS_ENTRY_INTR_INFO, info);
 
 	VCPU_CTR0(vmx->vm, vcpu, "Injecting vNMI");
 
 	/* Clear the request */
 	vm_nmi_clear(vmx->vm, vcpu);
-	return (1);
-
-nmiblocked:
-	/*
-	 * Set the NMI Window Exiting execution control so we can inject
-	 * the virtual NMI as soon as blocking condition goes away.
-	 */
-	vmx_set_nmi_window_exiting(vmx, vcpu);
-
-	VCPU_CTR0(vmx->vm, vcpu, "Enabling NMI window exiting");
-	return (1);
 }
 
 static void
 vmx_inject_interrupts(struct vmx *vmx, int vcpu, struct vlapic *vlapic)
 {
-	int vector;
-	uint64_t info, rflags, interruptibility;
-
-	const int HWINTR_BLOCKED = VMCS_INTERRUPTIBILITY_STI_BLOCKING |
-				   VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING;
+	int vector, need_nmi_exiting;
+	uint64_t rflags;
+	uint32_t gi, info;
 
-	/*
-	 * If there is already an interrupt pending then just return.
-	 *
-	 * This could happen if an interrupt was injected on a prior
-	 * VM entry but the actual entry into guest mode was aborted
-	 * because of a pending AST.
-	 */
-	info = vmcs_read(VMCS_ENTRY_INTR_INFO);
-	if (info & VMCS_INTR_VALID)
-		return;
+	if (vm_nmi_pending(vmx->vm, vcpu)) {
+		/*
+		 * If there are no conditions blocking NMI injection then
+		 * inject it directly here otherwise enable "NMI window
+		 * exiting" to inject it as soon as we can.
+		 *
+		 * We also check for STI_BLOCKING because some implementations
+		 * don't allow NMI injection in this case. If we are running
+		 * on a processor that doesn't have this restriction it will
+		 * immediately exit and the NMI will be injected in the
+		 * "NMI window exiting" handler.
+		 */
+		need_nmi_exiting = 1;
+		gi = vmcs_read(VMCS_GUEST_INTERRUPTIBILITY);
+		if ((gi & (HWINTR_BLOCKING | NMI_BLOCKING)) == 0) {
+			info = vmcs_read(VMCS_ENTRY_INTR_INFO);
+			if ((info & VMCS_INTR_VALID) == 0) {
+				vmx_inject_nmi(vmx, vcpu);
+				need_nmi_exiting = 0;
+			} else {
+				VCPU_CTR1(vmx->vm, vcpu, "Cannot inject NMI "
+				    "due to VM-entry intr info %#x", info);
+			}
+		} else {
+			VCPU_CTR1(vmx->vm, vcpu, "Cannot inject NMI due to "
+			    "Guest Interruptibility-state %#x", gi);
+		}
 
-	/*
-	 * NMI injection has priority so deal with those first
-	 */
-	if (vmx_inject_nmi(vmx, vcpu))
-		return;
+		if (need_nmi_exiting)
+			vmx_set_nmi_window_exiting(vmx, vcpu);
+	}
 
 	if (virtual_interrupt_delivery) {
 		vmx_inject_pir(vlapic);
 		return;
 	}
 
+	/*
+	 * If there is already an interrupt pending then just return. This
+	 * could happen for multiple reasons:
+	 * - A vectoring VM-entry was aborted due to astpending or rendezvous.
+	 * - A VM-exit happened during event injection.
+	 * - A NMI was injected above or after "NMI window exiting" VM-exit.
+	 */
+	info = vmcs_read(VMCS_ENTRY_INTR_INFO);
+	if (info & VMCS_INTR_VALID)
+		return;
+
 	/* Ask the local apic for a vector to inject */
 	if (!vlapic_pending_intr(vlapic, &vector))
 		return;
 
-	if (vector < 32 || vector > 255)
-		panic("vmx_inject_interrupts: invalid vector %d\n", vector);
+	KASSERT(vector >= 32 && vector <= 255, ("invalid vector %d", vector));
 
 	/* Check RFLAGS.IF and the interruptibility state of the guest */
 	rflags = vmcs_read(VMCS_GUEST_RFLAGS);
 	if ((rflags & PSL_I) == 0)
 		goto cantinject;
 
-	interruptibility = vmcs_read(VMCS_GUEST_INTERRUPTIBILITY);
-	if (interruptibility & HWINTR_BLOCKED)
+	gi = vmcs_read(VMCS_GUEST_INTERRUPTIBILITY);
+	if (gi & HWINTR_BLOCKING)
 		goto cantinject;
 
 	/* Inject the interrupt */
@@ -1151,8 +1164,6 @@ cantinject:
 	 * the interrupt as soon as blocking condition goes away.
 	 */
 	vmx_set_int_window_exiting(vmx, vcpu);
-
-	VCPU_CTR0(vmx->vm, vcpu, "Enabling interrupt window exiting");
 }
 
 /*
@@ -1587,7 +1598,6 @@ vmx_exit_process(struct vmx *vmx, int vc
 	case EXIT_REASON_INTR_WINDOW:
 		vmm_stat_incr(vmx->vm, vcpu, VMEXIT_INTR_WINDOW, 1);
 		vmx_clear_int_window_exiting(vmx, vcpu);
-		VCPU_CTR0(vmx->vm, vcpu, "Disabling interrupt window exiting");
 		return (1);
 	case EXIT_REASON_EXT_INTR:
 		/*
@@ -1613,9 +1623,10 @@ vmx_exit_process(struct vmx *vmx, int vc
 		return (1);
 	case EXIT_REASON_NMI_WINDOW:
 		/* Exit to allow the pending virtual NMI to be injected */
-		vmm_stat_incr(vmx->vm, vcpu, VMEXIT_NMI_WINDOW, 1);
+		if (vm_nmi_pending(vmx->vm, vcpu))
+			vmx_inject_nmi(vmx, vcpu);
 		vmx_clear_nmi_window_exiting(vmx, vcpu);
-		VCPU_CTR0(vmx->vm, vcpu, "Disabling NMI window exiting");
+		vmm_stat_incr(vmx->vm, vcpu, VMEXIT_NMI_WINDOW, 1);
 		return (1);
 	case EXIT_REASON_INOUT:
 		vmm_stat_incr(vmx->vm, vcpu, VMEXIT_INOUT, 1);

Modified: user/ae/inet6/sys/ia64/conf/GENERIC
==============================================================================
--- user/ae/inet6/sys/ia64/conf/GENERIC	Tue Feb  4 09:11:50 2014	(r261479)
+++ user/ae/inet6/sys/ia64/conf/GENERIC	Tue Feb  4 09:30:42 2014	(r261480)
@@ -192,7 +192,9 @@ options		AH_SUPPORT_AR5416
 # Various (pseudo) devices
 device		ether		# Ethernet support
 device		faith		# IPv6-to-IPv4 relaying (translation)
+device		firmware	# firmware assist module
 device		gif		# IPv6 and IPv4 tunneling
+device		kbdmux		# keyboard multiplexer
 device		loop		# Network loopback
 device		md		# Memory "disks"
 device		puc		# Multi I/O cards and multi-channel UARTs
@@ -200,7 +202,8 @@ device		random		# Entropy device
 device		tun		# Packet tunnel.
 device		uart		# Serial port (UART)
 device		vlan		# 802.1Q VLAN support
-device		firmware	# firmware assist module
+device		vt		# Virtual terminals
+device		vt_vga		# VGA terminal device
 
 # The `bpf' device enables the Berkeley Packet Filter.
 # Be aware of the administrative consequences of enabling this!

Modified: user/ae/inet6/sys/net/ieee8023ad_lacp.c
==============================================================================
--- user/ae/inet6/sys/net/ieee8023ad_lacp.c	Tue Feb  4 09:11:50 2014	(r261479)
+++ user/ae/inet6/sys/net/ieee8023ad_lacp.c	Tue Feb  4 09:30:42 2014	(r261480)
@@ -522,11 +522,7 @@ lacp_port_create(struct lagg_port *lgp)
 	boolean_t active = TRUE; /* XXX should be configurable */
 	boolean_t fast = FALSE; /* XXX should be configurable */
 
-	bzero((char *)&sdl, sizeof(sdl));
-	sdl.sdl_len = sizeof(sdl);
-	sdl.sdl_family = AF_LINK;
-	sdl.sdl_index = ifp->if_index;
-	sdl.sdl_type = IFT_ETHER;
+	link_init_sdl(ifp, (struct sockaddr *)&sdl, IFT_ETHER);
 	sdl.sdl_alen = ETHER_ADDR_LEN;
 
 	bcopy(&ethermulticastaddr_slowprotocols,

Modified: user/ae/inet6/sys/net/if.c
==============================================================================
--- user/ae/inet6/sys/net/if.c	Tue Feb  4 09:11:50 2014	(r261479)
+++ user/ae/inet6/sys/net/if.c	Tue Feb  4 09:30:42 2014	(r261480)
@@ -1902,6 +1902,38 @@ link_rtrequest(int cmd, struct rtentry *
 	}
 }
 
+struct sockaddr_dl *
+link_alloc_sdl(size_t size, int flags)
+{
+
+	return (malloc(size, M_TEMP, flags));
+}
+
+void
+link_free_sdl(struct sockaddr *sa)
+{
+	free(sa, M_TEMP);
+}
+
+/*
+ * Fills in given sdl with interface basic info.
+ * Returns pointer to filled sdl.
+ */
+struct sockaddr_dl *
+link_init_sdl(struct ifnet *ifp, struct sockaddr *paddr, u_char iftype)
+{
+	struct sockaddr_dl *sdl;
+
+	sdl = (struct sockaddr_dl *)paddr;
+	memset(sdl, 0, sizeof(struct sockaddr_dl));
+	sdl->sdl_len = sizeof(struct sockaddr_dl);
+	sdl->sdl_family = AF_LINK;
+	sdl->sdl_index = ifp->if_index;
+	sdl->sdl_type = iftype;
+
+	return (sdl);
+}
+
 /*
  * Mark an interface down and notify protocols of
  * the transition.
@@ -2952,6 +2984,7 @@ if_addmulti(struct ifnet *ifp, struct so
 {
 	struct ifmultiaddr *ifma, *ll_ifma;
 	struct sockaddr *llsa;
+	struct sockaddr_dl sdl;
 	int error;
 
 	/*
@@ -2971,12 +3004,18 @@ if_addmulti(struct ifnet *ifp, struct so
 	/*
 	 * The address isn't already present; resolve the protocol address
 	 * into a link layer address, and then look that up, bump its
-	 * refcount or allocate an ifma for that also.  If 'llsa' was
-	 * returned, we will need to free it later.
+	 * refcount or allocate an ifma for that also.
+	 * Most link layer resolving functions returns address data which
+	 * fits inside default sockaddr_dl structure. However callback
+	 * can allocate another sockaddr structure, in that case we need to
+	 * free it later.
 	 */
 	llsa = NULL;
 	ll_ifma = NULL;
 	if (ifp->if_resolvemulti != NULL) {
+		/* Provide called function with buffer size information */
+		sdl.sdl_len = sizeof(sdl);
+		llsa = (struct sockaddr *)&sdl;
 		error = ifp->if_resolvemulti(ifp, &llsa, sa);
 		if (error)
 			goto unlock_out;
@@ -3040,14 +3079,14 @@ if_addmulti(struct ifnet *ifp, struct so
 		(void) (*ifp->if_ioctl)(ifp, SIOCADDMULTI, 0);
 	}
 
-	if (llsa != NULL)
-		free(llsa, M_IFMADDR);
+	if ((llsa != NULL) && (llsa != (struct sockaddr *)&sdl))
+		link_free_sdl(llsa);
 
 	return (0);
 
 free_llsa_out:
-	if (llsa != NULL)
-		free(llsa, M_IFMADDR);
+	if ((llsa != NULL) && (llsa != (struct sockaddr *)&sdl))
+		link_free_sdl(llsa);
 
 unlock_out:
 	IF_ADDR_WUNLOCK(ifp);

Modified: user/ae/inet6/sys/net/if_arcsubr.c
==============================================================================
--- user/ae/inet6/sys/net/if_arcsubr.c	Tue Feb  4 09:11:50 2014	(r261479)
+++ user/ae/inet6/sys/net/if_arcsubr.c	Tue Feb  4 09:30:42 2014	(r261480)
@@ -786,14 +786,7 @@ arc_resolvemulti(struct ifnet *ifp, stru
 		sin = (struct sockaddr_in *)sa;
 		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
 			return EADDRNOTAVAIL;
-		sdl = malloc(sizeof *sdl, M_IFMADDR,
-		       M_NOWAIT | M_ZERO);
-		if (sdl == NULL)
-			return ENOMEM;
-		sdl->sdl_len = sizeof *sdl;
-		sdl->sdl_family = AF_LINK;
-		sdl->sdl_index = ifp->if_index;
-		sdl->sdl_type = IFT_ARCNET;
+		sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
 		sdl->sdl_alen = ARC_ADDR_LEN;
 		*LLADDR(sdl) = 0;
 		*llsa = (struct sockaddr *)sdl;
@@ -814,14 +807,7 @@ arc_resolvemulti(struct ifnet *ifp, stru
 		}
 		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
 			return EADDRNOTAVAIL;
-		sdl = malloc(sizeof *sdl, M_IFMADDR,
-		       M_NOWAIT | M_ZERO);
-		if (sdl == NULL)
-			return ENOMEM;
-		sdl->sdl_len = sizeof *sdl;
-		sdl->sdl_family = AF_LINK;
-		sdl->sdl_index = ifp->if_index;
-		sdl->sdl_type = IFT_ARCNET;
+		sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
 		sdl->sdl_alen = ARC_ADDR_LEN;
 		*LLADDR(sdl) = 0;
 		*llsa = (struct sockaddr *)sdl;

Modified: user/ae/inet6/sys/net/if_dl.h
==============================================================================
--- user/ae/inet6/sys/net/if_dl.h	Tue Feb  4 09:11:50 2014	(r261479)
+++ user/ae/inet6/sys/net/if_dl.h	Tue Feb  4 09:30:42 2014	(r261480)
@@ -69,6 +69,12 @@ struct sockaddr_dl {
 #define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen))
 #define LLINDEX(s) ((s)->sdl_index)
 
+
+struct ifnet;
+struct sockaddr_dl *link_alloc_sdl(size_t, int);
+void link_free_sdl(struct sockaddr *sa);
+struct sockaddr_dl *link_init_sdl(struct ifnet *, struct sockaddr *, u_char);
+
 #ifndef _KERNEL
 
 #include <sys/cdefs.h>

Modified: user/ae/inet6/sys/net/if_ethersubr.c
==============================================================================
--- user/ae/inet6/sys/net/if_ethersubr.c	Tue Feb  4 09:11:50 2014	(r261479)
+++ user/ae/inet6/sys/net/if_ethersubr.c	Tue Feb  4 09:30:42 2014	(r261480)
@@ -1171,14 +1171,7 @@ ether_resolvemulti(struct ifnet *ifp, st
 		sin = (struct sockaddr_in *)sa;
 		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
 			return EADDRNOTAVAIL;
-		sdl = malloc(sizeof *sdl, M_IFMADDR,
-		       M_NOWAIT|M_ZERO);
-		if (sdl == NULL)
-			return ENOMEM;
-		sdl->sdl_len = sizeof *sdl;
-		sdl->sdl_family = AF_LINK;
-		sdl->sdl_index = ifp->if_index;
-		sdl->sdl_type = IFT_ETHER;
+		sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
 		sdl->sdl_alen = ETHER_ADDR_LEN;
 		e_addr = LLADDR(sdl);
 		ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
@@ -1200,14 +1193,7 @@ ether_resolvemulti(struct ifnet *ifp, st
 		}
 		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
 			return EADDRNOTAVAIL;
-		sdl = malloc(sizeof *sdl, M_IFMADDR,
-		       M_NOWAIT|M_ZERO);
-		if (sdl == NULL)
-			return (ENOMEM);
-		sdl->sdl_len = sizeof *sdl;
-		sdl->sdl_family = AF_LINK;
-		sdl->sdl_index = ifp->if_index;
-		sdl->sdl_type = IFT_ETHER;
+		sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
 		sdl->sdl_alen = ETHER_ADDR_LEN;
 		e_addr = LLADDR(sdl);
 		ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);

Modified: user/ae/inet6/sys/net/if_fddisubr.c
==============================================================================
--- user/ae/inet6/sys/net/if_fddisubr.c	Tue Feb  4 09:11:50 2014	(r261479)
+++ user/ae/inet6/sys/net/if_fddisubr.c	Tue Feb  4 09:30:42 2014	(r261480)
@@ -729,14 +729,7 @@ fddi_resolvemulti(ifp, llsa, sa)
 		sin = (struct sockaddr_in *)sa;
 		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
 			return (EADDRNOTAVAIL);
-		sdl = malloc(sizeof *sdl, M_IFMADDR,
-		       M_NOWAIT | M_ZERO);
-		if (sdl == NULL)
-			return (ENOMEM);
-		sdl->sdl_len = sizeof *sdl;
-		sdl->sdl_family = AF_LINK;
-		sdl->sdl_index = ifp->if_index;
-		sdl->sdl_type = IFT_FDDI;
+		sdl = link_init_sdl(ifp, *llsa, IFT_FDDI);
 		sdl->sdl_nlen = 0;
 		sdl->sdl_alen = FDDI_ADDR_LEN;
 		sdl->sdl_slen = 0;
@@ -760,14 +753,7 @@ fddi_resolvemulti(ifp, llsa, sa)
 		}
 		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
 			return (EADDRNOTAVAIL);
-		sdl = malloc(sizeof *sdl, M_IFMADDR,
-		       M_NOWAIT | M_ZERO);
-		if (sdl == NULL)
-			return (ENOMEM);
-		sdl->sdl_len = sizeof *sdl;
-		sdl->sdl_family = AF_LINK;
-		sdl->sdl_index = ifp->if_index;
-		sdl->sdl_type = IFT_FDDI;
+		sdl = link_init_sdl(ifp, *llsa, IFT_FDDI);
 		sdl->sdl_nlen = 0;
 		sdl->sdl_alen = FDDI_ADDR_LEN;
 		sdl->sdl_slen = 0;

Modified: user/ae/inet6/sys/net/if_iso88025subr.c
==============================================================================
--- user/ae/inet6/sys/net/if_iso88025subr.c	Tue Feb  4 09:11:50 2014	(r261479)
+++ user/ae/inet6/sys/net/if_iso88025subr.c	Tue Feb  4 09:30:42 2014	(r261480)
@@ -721,14 +721,7 @@ iso88025_resolvemulti (ifp, llsa, sa)
 		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
 			return (EADDRNOTAVAIL);
 		}
-		sdl = malloc(sizeof *sdl, M_IFMADDR,
-		       M_NOWAIT|M_ZERO);
-		if (sdl == NULL)
-			return (ENOMEM);
-		sdl->sdl_len = sizeof *sdl;
-		sdl->sdl_family = AF_LINK;
-		sdl->sdl_index = ifp->if_index;
-		sdl->sdl_type = IFT_ISO88025;
+		sdl = link_init_sdl(ifp, *llsa, IFT_ISO88025);
 		sdl->sdl_alen = ISO88025_ADDR_LEN;
 		e_addr = LLADDR(sdl);
 		ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
@@ -751,14 +744,7 @@ iso88025_resolvemulti (ifp, llsa, sa)
 		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
 			return (EADDRNOTAVAIL);
 		}
-		sdl = malloc(sizeof *sdl, M_IFMADDR,
-		       M_NOWAIT|M_ZERO);
-		if (sdl == NULL)
-			return (ENOMEM);
-		sdl->sdl_len = sizeof *sdl;
-		sdl->sdl_family = AF_LINK;
-		sdl->sdl_index = ifp->if_index;
-		sdl->sdl_type = IFT_ISO88025;
+		sdl = link_init_sdl(ifp, *llsa, IFT_ISO88025);
 		sdl->sdl_alen = ISO88025_ADDR_LEN;
 		e_addr = LLADDR(sdl);
 		ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);

Modified: user/ae/inet6/sys/net/if_lagg.c
==============================================================================
--- user/ae/inet6/sys/net/if_lagg.c	Tue Feb  4 09:11:50 2014	(r261479)
+++ user/ae/inet6/sys/net/if_lagg.c	Tue Feb  4 09:30:42 2014	(r261480)
@@ -1214,12 +1214,8 @@ lagg_ether_cmdmulti(struct lagg_port *lp
 
 	LAGG_WLOCK_ASSERT(sc);
 
-	bzero((char *)&sdl, sizeof(sdl));
-	sdl.sdl_len = sizeof(sdl);
-	sdl.sdl_family = AF_LINK;
-	sdl.sdl_type = IFT_ETHER;
+	link_init_sdl(ifp, (struct sockaddr *)&sdl, IFT_ETHER);
 	sdl.sdl_alen = ETHER_ADDR_LEN;
-	sdl.sdl_index = ifp->if_index;
 
 	if (set) {
 		TAILQ_FOREACH(ifma, &scifp->if_multiaddrs, ifma_link) {

Modified: user/ae/inet6/sys/netinet/ip_carp.c
==============================================================================
--- user/ae/inet6/sys/netinet/ip_carp.c	Tue Feb  4 09:11:50 2014	(r261479)
+++ user/ae/inet6/sys/netinet/ip_carp.c	Tue Feb  4 09:30:42 2014	(r261480)
@@ -956,7 +956,7 @@ carp_ifa_addroute(struct ifaddr *ifa)
 	case AF_INET6:
 		ifa_add_loopback_route(ifa,
 		    (struct sockaddr *)&ifatoia6(ifa)->ia_addr);
-		in6_ifaddloop(ifa);
+		nd6_add_ifa_lle(ifatoia6(ifa));
 		break;
 #endif
 	}
@@ -987,7 +987,7 @@ carp_ifa_delroute(struct ifaddr *ifa)
 	case AF_INET6:
 		ifa_del_loopback_route(ifa,
 		    (struct sockaddr *)&ifatoia6(ifa)->ia_addr);
-		in6_ifremloop(ifa);
+		nd6_rem_ifa_lle(ifatoia6(ifa));
 		break;
 #endif
 	}

Modified: user/ae/inet6/sys/netinet/tcp_syncache.c
==============================================================================
--- user/ae/inet6/sys/netinet/tcp_syncache.c	Tue Feb  4 09:11:50 2014	(r261479)
+++ user/ae/inet6/sys/netinet/tcp_syncache.c	Tue Feb  4 09:30:42 2014	(r261480)
@@ -724,6 +724,16 @@ syncache_socket(struct syncache *sc, str
 #endif
 
 	/*
+	 * If there's an mbuf and it has a flowid, then let's initialise the
+	 * inp with that particular flowid.
+	 */
+	if (m != NULL && m->m_flags & M_FLOWID) {
+		inp->inp_flags |= INP_HW_FLOWID;
+		inp->inp_flags &= ~INP_SW_FLOWID;
+		inp->inp_flowid = m->m_pkthdr.flowid;
+	}
+
+	/*
 	 * Install in the reservation hash table for now, but don't yet
 	 * install a connection group since the full 4-tuple isn't yet
 	 * configured.

Modified: user/ae/inet6/sys/netinet6/in6.c
==============================================================================
--- user/ae/inet6/sys/netinet6/in6.c	Tue Feb  4 09:11:50 2014	(r261479)
+++ user/ae/inet6/sys/netinet6/in6.c	Tue Feb  4 09:30:42 2014	(r261480)
@@ -133,8 +133,8 @@ const struct in6_addr in6mask128 = IN6MA
 const struct sockaddr_in6 sa6_any =
 	{ sizeof(sa6_any), AF_INET6, 0, 0, IN6ADDR_ANY_INIT, 0 };
 
-static int in6_ifinit(struct ifnet *, struct in6_ifaddr *,
-	struct sockaddr_in6 *, int);
+static int in6_notify_ifa(struct ifnet *, struct in6_ifaddr *,
+	struct in6_aliasreq *, int);
 static void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *);
 
 int	(*faithprefix_p)(struct in6_addr *);
@@ -145,44 +145,26 @@ static struct in6_ifaddr *in6_alloc_ifa(
     struct in6_aliasreq *, int flags);
 static int in6_update_ifa_internal(struct ifnet *, struct in6_aliasreq *,
     struct in6_ifaddr *, int, int);
-static int in6_setup_ifa(struct ifnet *, struct in6_aliasreq *,
+static int in6_broadcast_ifa(struct ifnet *, struct in6_aliasreq *,
     struct in6_ifaddr *, int);
 
 #define ifa2ia6(ifa)	((struct in6_ifaddr *)(ifa))
 #define ia62ifa(ia6)	(&((ia6)->ia_ifa))
 
+
 void
-in6_ifaddloop(struct ifaddr *ifa)
+in6_newaddrmsg(struct in6_ifaddr *ia, int cmd)
 {
 	struct sockaddr_dl gateway;
 	struct sockaddr_in6 mask, addr;
 	struct rtentry rt;
-	struct in6_ifaddr *ia;
-	struct ifnet *ifp;
-	struct llentry *ln;
 
-	ia = ifa2ia6(ifa);
-	ifp = ifa->ifa_ifp;
-	IF_AFDATA_LOCK(ifp);
-	ifa->ifa_rtrequest = nd6_rtrequest;
-	ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR |
-	    LLE_EXCLUSIVE), (struct sockaddr *)&ia->ia_addr);
-	IF_AFDATA_UNLOCK(ifp);
-	if (ln != NULL) {
-		ln->la_expire = 0;  /* for IPv6 this means permanent */
-		ln->ln_state = ND6_LLINFO_REACHABLE;
-		/*
-		 * initialize for rtmsg generation
-		 */
-		bzero(&gateway, sizeof(gateway));
-		gateway.sdl_len = sizeof(gateway);
-		gateway.sdl_family = AF_LINK;
-		gateway.sdl_nlen = 0;
-		gateway.sdl_alen = 6;
-		memcpy(gateway.sdl_data, &ln->ll_addr.mac_aligned,
-		    sizeof(ln->ll_addr));
-		LLE_WUNLOCK(ln);
-	}
+	/*
+	 * initialize for rtmsg generation
+	 */
+	bzero(&gateway, sizeof(gateway));
+	gateway.sdl_len = sizeof(gateway);
+	gateway.sdl_family = AF_LINK;
 
 	bzero(&rt, sizeof(rt));
 	rt.rt_gateway = (struct sockaddr *)&gateway;
@@ -190,42 +172,11 @@ in6_ifaddloop(struct ifaddr *ifa)
 	memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr));
 	rt_mask(&rt) = (struct sockaddr *)&mask;
 	rt_key(&rt) = (struct sockaddr *)&addr;
-	rt.rt_flags = RTF_UP | RTF_HOST | RTF_STATIC;
+	rt.rt_flags = RTF_HOST | RTF_STATIC;
+	if (cmd == RTM_ADD)
+		rt.rt_flags |= RTF_UP;
 	/* Announce arrival of local address to all FIBs. */
-	rt_newaddrmsg(RTM_ADD, ifa, 0, &rt);
-}
-
-void
-in6_ifremloop(struct ifaddr *ifa)
-{
-	struct sockaddr_dl gateway;
-	struct sockaddr_in6 mask, addr;
-	struct rtentry rt0;
-	struct in6_ifaddr *ia;
-	struct ifnet *ifp;
-
-	ia = ifa2ia6(ifa);
-	ifp = ifa->ifa_ifp;
-	memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr));
-	memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
-	lltable_prefix_free(AF_INET6, (struct sockaddr *)&addr,
-	            (struct sockaddr *)&mask, LLE_STATIC);
-
-	/*
-	 * initialize for rtmsg generation
-	 */
-	bzero(&gateway, sizeof(gateway));
-	gateway.sdl_len = sizeof(gateway);
-	gateway.sdl_family = AF_LINK;
-	gateway.sdl_nlen = 0;
-	gateway.sdl_alen = ifp->if_addrlen;
-	bzero(&rt0, sizeof(rt0));
-	rt0.rt_gateway = (struct sockaddr *)&gateway;
-	rt_mask(&rt0) = (struct sockaddr *)&mask;
-	rt_key(&rt0) = (struct sockaddr *)&addr;
-	rt0.rt_flags = RTF_HOST | RTF_STATIC;
-	/* Announce removal of local address to all FIBs. */
-	rt_newaddrmsg(RTM_DELETE, ifa, 0, &rt0);
+	rt_newaddrmsg(cmd, &ia->ia_ifa, 0, &rt);
 }
 
 int
@@ -962,13 +913,13 @@ in6_update_ifa(struct ifnet *ifp, struct
 	}
 
 	if (hostIsNew)
-		error = in6_setup_ifa(ifp, ifra, ia, flags);
+		error = in6_broadcast_ifa(ifp, ifra, ia, flags);
 
 	return (error);
 }
 
 /*
- * Fill in basic IPv6 address request info
+ * Fill in basic IPv6 address request info.
  */
 void
 in6_prepare_ifra(struct in6_aliasreq *ifra, const struct in6_addr *addr,
@@ -992,9 +943,9 @@ static int
 in6_validate_ifra(struct ifnet *ifp, struct in6_aliasreq *ifra,
     struct in6_ifaddr *ia, int flags)
 {
-	int plen = -1;
 	struct sockaddr_in6 dst6;
 	struct in6_addrlifetime *lt;
+	int plen;
 	char ip6buf[INET6_ADDRSTRLEN];
 
 	/* Validate parameters */
@@ -1009,6 +960,19 @@ in6_validate_ifra(struct ifnet *ifp, str
 	    ifra->ifra_dstaddr.sin6_family != AF_INET6 &&
 	    ifra->ifra_dstaddr.sin6_family != AF_UNSPEC)
 		return (EAFNOSUPPORT);
+
+	/*
+	 * Validate address
+	 */
+	if (ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6) ||
+	    ifra->ifra_addr.sin6_family != AF_INET6)
+		return (EINVAL);
+	/*
+	 * Check and automatically fill scope zone index.
+	 */
+	plen = sa6_checkzone_ifp(ifp, &ifra->ifra_addr);
+	if (plen != 0)
+		return (plen);
 	/*
 	 * validate ifra_prefixmask.  don't check sin6_family, netmask
 	 * does not carry fields other than sin6_len.
@@ -1126,12 +1090,11 @@ in6_alloc_ifa(struct ifnet *ifp, struct 
 	LIST_INIT(&ia->ia6_memberships);
 	/* Initialize the address and masks, and put time stamp */
 	ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
-	ia->ia_addr.sin6_family = AF_INET6;
-	ia->ia_addr.sin6_len = sizeof(ia->ia_addr);
+	ia->ia_addr = ifra->ifra_addr;
 	ia->ia6_createtime = time_uptime;
 	if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) {
 		/*
-		 * XXX: some functions expect that ifa_dstaddr is not
+		 * Some functions expect that ifa_dstaddr is not
 		 * NULL for p2p interfaces.
 		 */
 		ia->ia_ifa.ifa_dstaddr =
@@ -1139,7 +1102,15 @@ in6_alloc_ifa(struct ifnet *ifp, struct 
 	} else {
 		ia->ia_ifa.ifa_dstaddr = NULL;
 	}
+
+	/* set prefix mask if any */
 	ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
+	if (ifra->ifra_prefixmask.sin6_len != 0) {
+		ia->ia_prefixmask.sin6_family = AF_INET6;
+		ia->ia_prefixmask.sin6_len = ifra->ifra_prefixmask.sin6_len;
+		ia->ia_prefixmask.sin6_addr = ifra->ifra_prefixmask.sin6_addr;
+	}
+
 	ia->ia_ifp = ifp;
 	ifa_ref(&ia->ia_ifa);			/* if_addrhead */
 	IF_ADDR_WLOCK(ifp);
@@ -1149,30 +1120,28 @@ in6_alloc_ifa(struct ifnet *ifp, struct 
 	ifa_ref(&ia->ia_ifa);			/* in6_ifaddrhead */
 	IN6_IFADDR_WLOCK();
 	TAILQ_INSERT_TAIL(&V_in6_ifaddrhead, ia, ia_link);
-	LIST_INSERT_HEAD(IN6ADDR_HASH(&ifra->ifra_addr.sin6_addr),
-	    ia, ia6_hash);
+	LIST_INSERT_HEAD(IN6ADDR_HASH(&ia->ia_addr.sin6_addr), ia, ia6_hash);
 	IN6_IFADDR_WUNLOCK();
 
 	return (ia);
 }
 
+/*
+ * Update/configure interface address parameters:
+ *
+ * 1) Update lifetime
+ * 2) Update interface metric ad flags
+ * 3) Notify other subsystems
+ */
 static int
 in6_update_ifa_internal(struct ifnet *ifp, struct in6_aliasreq *ifra,
     struct in6_ifaddr *ia, int hostIsNew, int flags)
 {
-	struct sockaddr_in6 *pdst;
 	int error;
-	char ip6buf[INET6_ADDRSTRLEN];
 
 	/* update timestamp */
 	ia->ia6_updatetime = time_uptime;
 
-	/* set prefix mask */
-	if (ifra->ifra_prefixmask.sin6_len != 0) {
-		ia->ia_prefixmask = ifra->ifra_prefixmask;
-		ia->ia_prefixmask.sin6_family = AF_INET6;
-	}
-
 	/*
 	 * Set lifetimes.  We do not refer to ia6t_expire and ia6t_preferred
 	 * to see if the address is deprecated or invalidated, but initialize
@@ -1199,6 +1168,9 @@ in6_update_ifa_internal(struct ifnet *if
 		ia->ia6_lifetime.ia6t_preferred = time_uptime;
 	}
 
+	/* Update metric */
+	ia->ia_ifa.ifa_metric = ifp->if_metric;
+
 	/*
 	 * configure address flags.
 	 */
@@ -1217,53 +1189,40 @@ in6_update_ifa_internal(struct ifnet *if
 	if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)
 		ia->ia6_flags |= IN6_IFF_TENTATIVE;
 
-	/*
-	 * If a new destination address is specified, scrub the old one and
-	 * install the new destination.  Note that the interface must be
-	 * p2p or loopback (see the check above.)
-	 */
-	pdst = &ifra->ifra_dstaddr;
-	if (pdst->sin6_family == AF_INET6 &&
-	    !IN6_ARE_ADDR_EQUAL(&pdst->sin6_addr, &ia->ia_dstaddr.sin6_addr)) {
-		if ((ia->ia_flags & IFA_ROUTE) != 0 &&
-		    (rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST) != 0)) {
-			nd6log((LOG_ERR, "in6_update_ifa_internal: failed to "
-			    "remove a route to the old destination: %s\n",
-			    ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)));
-			/* proceed anyway... */
-		} else
-			ia->ia_flags &= ~IFA_ROUTE;
-		ia->ia_dstaddr = *pdst;
-	}
-
-	/* reset the interface and routing table appropriately. */
-	if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0) {
-	/*
-	 * XXX: if a change of an existing address failed, keep the entry
-	 * anyway.
-	 */
-	}
+	/* notify other subsystems */
+	error = in6_notify_ifa(ifp, ia, ifra, hostIsNew);
 
 	return (error);
 }
 
+/*
+ * Do link-level ifa job:
+ * 1) Add lle entry for added address
+ * 2) Notifies routing socket users about new address
+ * 3) join appropriate multicast group
+ * 4) start DAD if enabled
+ */
 static int
-in6_setup_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
+in6_broadcast_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
     struct in6_ifaddr *ia, int flags)
 {
 	struct in6_multi *in6m_sol;
 	int error = 0;
 
 	/* Add local address to lltable, if necessary (ex. on p2p link). */
-	in6_ifaddloop(&(ia->ia_ifa));
+	if ((error = nd6_add_ifa_lle(ia)) != 0) {
+		in6_purgeaddr(&ia->ia_ifa);
+		ifa_free(&ia->ia_ifa);
+		return (error);
+	}
 
 	/* Join necessary multicast groups. */
 	in6m_sol = NULL;
 	if ((ifp->if_flags & IFF_MULTICAST) != 0) {
 		error = in6_update_ifa_join_mc(ifp, ifra, ia, flags, &in6m_sol);
 		if (error != 0) {
-			ifa_free(&ia->ia_ifa);
 			in6_purgeaddr(&ia->ia_ifa);
+			ifa_free(&ia->ia_ifa);
 			return (error);
 		}
 	}
@@ -1370,7 +1329,7 @@ in6_purgeaddr(struct ifaddr *ifa)
 	nd6_dad_stop(ifa);
 
 	/* Remove local address entry from lltable. */
-	in6_ifremloop(ifa);
+	nd6_rem_ifa_lle(ia);
 
 	/* Leave multicast groups. */
 	error = in6_purgeaddr_mc(ifp, ia, ifa0);
@@ -1435,46 +1394,60 @@ in6_unlink_ifa(struct in6_ifaddr *ia, st
 }
 
 /*
- * Initialize an interface's IPv6 address and routing table entry.
+ * Notifies other other subsystems about address change/arrival:
+ * 1) Notifies device handler on first IPv6 address assignment
+ * 2) Handle routing table changes for P2P links and route
+ * 3) Handle routing table changes for address host route
  */
 static int
-in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia,
-    struct sockaddr_in6 *sin6, int newhost)
+in6_notify_ifa(struct ifnet *ifp, struct in6_ifaddr *ia,
+    struct in6_aliasreq *ifra, int hostIsNew)
 {
 	int	error = 0, plen, ifacount = 0;
 	struct ifaddr *ifa;
+	struct sockaddr_in6 *pdst;
+	char ip6buf[INET6_ADDRSTRLEN];
 
 	/*
 	 * Give the interface a chance to initialize
 	 * if this is its first address,
-	 * and to validate the address if necessary.
 	 */
-	IF_ADDR_RLOCK(ifp);
-	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
-		if (ifa->ifa_addr->sa_family != AF_INET6)
-			continue;
-		ifacount++;
+	if (hostIsNew != 0) {
+		IF_ADDR_RLOCK(ifp);
+		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+			if (ifa->ifa_addr->sa_family != AF_INET6)
+				continue;
+			ifacount++;
+		}
+		IF_ADDR_RUNLOCK(ifp);
 	}
-	IF_ADDR_RUNLOCK(ifp);
 
-	ia->ia_addr = *sin6;
-	/*
-	 * Initialize sin6_scope_id using specified ifnet.
-	 */
-	ia->ia_addr.sin6_scope_id = in6_getscopezone(ifp,
-	    in6_addrscope(&sin6->sin6_addr));
 	if (ifacount <= 1 && ifp->if_ioctl) {
 		error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
 		if (error)
 			return (error);
 	}
 
-	ia->ia_ifa.ifa_metric = ifp->if_metric;
-
-	/* we could do in(6)_socktrim here, but just omit it at this moment. */
+	/*
+	 * If a new destination address is specified, scrub the old one and
+	 * install the new destination.  Note that the interface must be
+	 * p2p or loopback.
+	 */
+	pdst = &ifra->ifra_dstaddr;
+	if (pdst->sin6_family == AF_INET6 &&
+	    !IN6_ARE_ADDR_EQUAL(&pdst->sin6_addr, &ia->ia_dstaddr.sin6_addr)) {
+		if ((ia->ia_flags & IFA_ROUTE) != 0 &&
+		    (rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST) != 0)) {
+			nd6log((LOG_ERR, "in6_update_ifa_internal: failed to "

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201402040930.s149Ugwr078172>