From nobody Fri Oct 3 08:02:25 2025 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4cdLjs659nz69rH8; Fri, 03 Oct 2025 08:02:25 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4cdLjs5spkz3y5y; Fri, 03 Oct 2025 08:02:25 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1759478545; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=PbzeEbcPfHAYybP7nA2POl7yIrz2RZ4qXdWSEQ4Wgio=; b=P8ER5fMz+YoguzkCuUyGZlLphhRS8PXoIKYnWA6GL00FC+OUnkHQxTTlG0Rs4CHZ+a1lyd tzTmQm6x9eExvZIYJbmIAdEkFegUZzkVAtrA2xELKXUSjyP4Zjs0pAht4Xq5x4jkDb4qyK T5j5NdVm1WXjOSO1Xxp/xMrUBJNLGbOpw+cWesNtB26K8ZizfCUsAoy4t5b6Scwzz+Uy6F BpvXz5ZkTNHEcFXxCx5tYtB7HBWd6+kcdRQNfltmkD2eAFP1W8a+qQQWeFYbd714/uRu8P lqPDvvltosHQWrzXxOnTzjY++4tQN4VeyTTeuF3ck3nJ9bJj9jQDiNBCpTQdIg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1759478545; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=PbzeEbcPfHAYybP7nA2POl7yIrz2RZ4qXdWSEQ4Wgio=; b=wMELnCd4G6uTU9PvjzClbkXNa05SPzHiZEkoQ36R4gboIEMzDLQtJ6Ou1/RJ1hB4CakbQP S2ASeGGxkIJv3+2bqkHGeYbY8sl4MAdGBIBe3pPzJ0vaFxw0eqAzfQI1ZpyXMvPPk4wu8Q JAYRrUaSmcJU5JKIBMudnYCKEv6jB6Vh6UntCfXUjTvrolsJ+UewS0/N8Vidb1Da+FlE7x UVTlvwEQvz/Z05hB2T/BKiiso1swwI71i8w5na23P+mr8+v3hb/VRtzYmSfV2Y97rV/WUv 6A3wjG8eA0Karr77Is8PKCh0OokDL9RQ+etfbJUtap8u9WUpbAhPTV5K3oTPIA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1759478545; a=rsa-sha256; cv=none; b=Bju30VKySkLOezD4VegyoKPxvbPiMJqB47miqRL0u4Zf6mA/fmf7IS+8XiR4+v0ptCzoh2 KBIhHMGp2jQM+AWHjkQlxKjuwb7GVJxy7vyiNL9+mgPw0VY9SZ07tOy/z8HWoxQxw8Sdky 2d+/n1T+2STOxrt9wUplCL4ier5DVnoqq8ArD0h5/WpfKE0ko09HrSdIjqD3A5NyomByeD gXC9RlipDRU1H1uGsMSSzX9g4h9YWGd8Kfp7nCYm7uXt/4xRS6IXFvYqtI9sXYNvedeNzC 6fwuN5tw4Q6hn2THrzY6Ic8YDWgAiNoBQfpnS9t8ZEj6dw4jiaFYTRIu6Gfigg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4cdLjs5Db4zmb7; Fri, 03 Oct 2025 08:02:25 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 59382PXO063852; Fri, 3 Oct 2025 08:02:25 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 59382PmL063849; Fri, 3 Oct 2025 08:02:25 GMT (envelope-from git) Date: Fri, 3 Oct 2025 08:02:25 GMT Message-Id: <202510030802.59382PmL063849@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: "Andrey V. Elsukov" Subject: git: 716acd9367df - main - carp6: revise the generation of ND6 NA List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: ae X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 716acd9367df49d44f29eeb783706025f3a04c65 Auto-Submitted: auto-generated The branch main has been updated by ae: URL: https://cgit.FreeBSD.org/src/commit/?id=716acd9367df49d44f29eeb783706025f3a04c65 commit 716acd9367df49d44f29eeb783706025f3a04c65 Author: Andrey V. Elsukov AuthorDate: 2025-10-03 07:57:44 +0000 Commit: Andrey V. Elsukov CommitDate: 2025-10-03 07:57:44 +0000 carp6: revise the generation of ND6 NA * use ND_NA_FLAG_ROUTER flag in carp_send_na() when we work as router. * use in6addr_any as destination address for nd6_na_output(), then it will use ipv6-all-nodes multicast address. * add in6_selectsrc_nbr() function that accepts additional argument ip6_moptions. Use this function from ND6 code to avoid cases when nd6_na_output/nd6_ns_output can not find source address for multicast destinations. * add some comments from RFC2461 for better understanding. * use tlladdr argument as flags and use ND6_NA_OPT_LLA when we need to add target link-layer address option, and ND6_NA_CARP_MASTER when we know that target address is CARP master. Then we can prepare correct CARP's mac address if target address is CARP master. * move blocks of code where multicast options is initialized and use it when destination address is multicast. Reviewed by: kp Obtained from: Yandex LLC MFC after: 2 weeks Sponsored by: Yandex LLC Differential Revision: https://reviews.freebsd.org/D52825 --- sys/netinet/ip_carp.c | 27 ++++++++--- sys/netinet6/in6_src.c | 54 ++++++++++++++++------ sys/netinet6/ip6_var.h | 2 + sys/netinet6/nd6.h | 4 ++ sys/netinet6/nd6_nbr.c | 121 ++++++++++++++++++++++--------------------------- 5 files changed, 119 insertions(+), 89 deletions(-) diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index d3d7957cf087..4f553b9aac5e 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -1640,18 +1640,31 @@ carp_iamatch(struct ifaddr *ifa, uint8_t **enaddr) static void carp_send_na(struct carp_softc *sc) { - static struct in6_addr mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT; struct ifaddr *ifa; - struct in6_addr *in6; + int flags; + /* + * Sending Unsolicited Neighbor Advertisements + * + * If the node is a router, we MUST set the Router flag to one. + * We set Override flag to one and send link-layer address option, + * thus neighboring nodes will install the new link-layer address. + */ + flags = ND_NA_FLAG_OVERRIDE; + if (V_ip6_forwarding) + flags |= ND_NA_FLAG_ROUTER; CARP_FOREACH_IFA(sc, ifa) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; - - in6 = IFA_IN6(ifa); - nd6_na_output(sc->sc_carpdev, &mcast, in6, - ND_NA_FLAG_OVERRIDE, 1, NULL); - DELAY(1000); /* XXX */ + /* + * We use unspecified address as destination here to avoid + * scope initialization for each call. + * nd6_na_output() will use all nodes multicast address if + * destinaion address is unspecified. + */ + nd6_na_output(sc->sc_carpdev, &in6addr_any, IFA_IN6(ifa), + flags, ND6_NA_OPT_LLA | ND6_NA_CARP_MASTER, NULL); + DELAY(1000); /* RetransTimer */ } } diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c index dd6864482b3c..3e55c6e5fc05 100644 --- a/sys/netinet6/in6_src.c +++ b/sys/netinet6/in6_src.c @@ -132,8 +132,8 @@ static int in6_selectif(struct sockaddr_in6 *, struct ip6_pktopts *, struct ip6_moptions *, struct ifnet **, struct ifnet *, u_int); static int in6_selectsrc(uint32_t, struct sockaddr_in6 *, - struct ip6_pktopts *, struct inpcb *, struct ucred *, - struct ifnet **, struct in6_addr *); + struct ip6_pktopts *, struct ip6_moptions *, struct inpcb *, + struct ucred *, struct ifnet **, struct in6_addr *); static struct in6_addrpolicy *lookup_addrsel_policy(struct sockaddr_in6 *); @@ -173,8 +173,8 @@ static struct in6_addrpolicy *match_addrsel_policy(struct sockaddr_in6 *); static int in6_selectsrc(uint32_t fibnum, struct sockaddr_in6 *dstsock, - struct ip6_pktopts *opts, struct inpcb *inp, struct ucred *cred, - struct ifnet **ifpp, struct in6_addr *srcp) + struct ip6_pktopts *opts, struct ip6_moptions *mopts, struct inpcb *inp, + struct ucred *cred, struct ifnet **ifpp, struct in6_addr *srcp) { struct rm_priotracker in6_ifa_tracker; struct in6_addr dst, tmp; @@ -186,7 +186,6 @@ in6_selectsrc(uint32_t fibnum, struct sockaddr_in6 *dstsock, u_int32_t odstzone; int prefer_tempaddr; int error; - struct ip6_moptions *mopts; NET_EPOCH_ASSERT(); KASSERT(srcp != NULL, ("%s: srcp is NULL", __func__)); @@ -205,13 +204,6 @@ in6_selectsrc(uint32_t fibnum, struct sockaddr_in6 *dstsock, *ifpp = NULL; } - if (inp != NULL) { - INP_LOCK_ASSERT(inp); - mopts = inp->in6p_moptions; - } else { - mopts = NULL; - } - /* * If the source address is explicitly specified by the caller, * check if the requested source address is indeed a unicast address @@ -552,10 +544,13 @@ in6_selectsrc_socket(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, uint32_t fibnum; int error; + INP_LOCK_ASSERT(inp); + fibnum = inp->inp_inc.inc_fibnum; retifp = NULL; - error = in6_selectsrc(fibnum, dstsock, opts, inp, cred, &retifp, srcp); + error = in6_selectsrc(fibnum, dstsock, opts, inp->in6p_moptions, + inp, cred, &retifp, srcp); if (error != 0) return (error); @@ -583,7 +578,7 @@ in6_selectsrc_socket(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, * Stores selected address to @srcp. * Returns 0 on success. * - * Used by non-socket based consumers (ND code mostly) + * Used by non-socket based consumers */ int in6_selectsrc_addr(uint32_t fibnum, const struct in6_addr *dst, @@ -602,13 +597,42 @@ in6_selectsrc_addr(uint32_t fibnum, const struct in6_addr *dst, dst_sa.sin6_scope_id = scopeid; sa6_embedscope(&dst_sa, 0); - error = in6_selectsrc(fibnum, &dst_sa, NULL, NULL, NULL, &retifp, srcp); + error = in6_selectsrc(fibnum, &dst_sa, NULL, NULL, + NULL, NULL, &retifp, srcp); if (hlim != NULL) *hlim = in6_selecthlim(NULL, retifp); return (error); } +/* + * Select source address based on @fibnum, @dst and @mopts. + * Stores selected address to @srcp. + * Returns 0 on success. + * + * Used by non-socket based consumers (ND code mostly) + */ +int +in6_selectsrc_nbr(uint32_t fibnum, const struct in6_addr *dst, + struct ip6_moptions *mopts, struct ifnet *ifp, struct in6_addr *srcp) +{ + struct sockaddr_in6 dst_sa; + struct ifnet *retifp; + int error; + + retifp = ifp; + bzero(&dst_sa, sizeof(dst_sa)); + dst_sa.sin6_family = AF_INET6; + dst_sa.sin6_len = sizeof(dst_sa); + dst_sa.sin6_addr = *dst; + dst_sa.sin6_scope_id = ntohs(in6_getscope(dst)); + sa6_embedscope(&dst_sa, 0); + + error = in6_selectsrc(fibnum, &dst_sa, NULL, mopts, + NULL, NULL, &retifp, srcp); + return (error); +} + static struct nhop_object * cache_route(uint32_t fibnum, const struct sockaddr_in6 *dst, struct route_in6 *ro, uint32_t flowid) diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index e1a4e8678ebb..c28bfa5a9d08 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -440,6 +440,8 @@ int in6_selectsrc_socket(struct sockaddr_in6 *, struct ip6_pktopts *, struct inpcb *, struct ucred *, int, struct in6_addr *, int *); int in6_selectsrc_addr(uint32_t, const struct in6_addr *, uint32_t, struct ifnet *, struct in6_addr *, int *); +int in6_selectsrc_nbr(uint32_t, const struct in6_addr *, + struct ip6_moptions *, struct ifnet *, struct in6_addr *); int in6_selectroute(struct sockaddr_in6 *, struct ip6_pktopts *, struct ip6_moptions *, struct route_in6 *, struct ifnet **, struct nhop_object **, u_int, uint32_t); diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index 5fe027ac5e7c..e484c709e29a 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -171,6 +171,10 @@ struct in6_ndifreq { #define NDPRF_ONLINK 0x1 #define NDPRF_DETACHED 0x2 +/* ND6 NA output flags */ +#define ND6_NA_OPT_LLA 0x01 +#define ND6_NA_CARP_MASTER 0x02 + /* protocol constants */ #define MAX_RTR_SOLICITATION_DELAY 1 /* 1sec */ #define RTR_SOLICITATION_INTERVAL 4 /* 4sec */ diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index cc17b4e1a402..e2db192bca15 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -245,10 +245,9 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) * In implementation, we add target link-layer address by default. * We do not add one in MUST NOT cases. */ - if (!IN6_IS_ADDR_MULTICAST(&daddr6)) - tlladdr = 0; - else - tlladdr = 1; + tlladdr = 0; + if (IN6_IS_ADDR_MULTICAST(&daddr6)) + tlladdr |= ND6_NA_OPT_LLA; /* * Target address (taddr6) must be either: @@ -257,9 +256,11 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) * (3) "tentative" address on which DAD is being performed. */ /* (1) and (3) check. */ - if (ifp->if_carp) + if (ifp->if_carp) { ifa = (*carp_iamatch6_p)(ifp, &taddr6); - else + if (ifa != NULL) + tlladdr |= ND6_NA_CARP_MASTER; + } else ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); /* (2) check. */ @@ -322,33 +323,29 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) goto freeit; } + /* + * If the Target Address is either an anycast address or a unicast + * address for which the node is providing proxy service, or the Target + * Link-Layer Address option is not included, the Override flag SHOULD + * be set to zero. Otherwise, the Override flag SHOULD be set to one. + */ + if (anycast == 0 && proxy == 0 && (tlladdr & ND6_NA_OPT_LLA) != 0) + rflag |= ND_NA_FLAG_OVERRIDE; /* * If the source address is unspecified address, entries must not * be created or updated. - * It looks that sender is performing DAD. Output NA toward - * all-node multicast address, to tell the sender that I'm using - * the address. + * It looks that sender is performing DAD. nd6_na_output() will + * send NA toward all-node multicast address, to tell the sender + * that I'm using the address. * S bit ("solicited") must be zero. */ - if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { - struct in6_addr in6_all; - - in6_all = in6addr_linklocal_allnodes; - if (in6_setscope(&in6_all, ifp, NULL) != 0) - goto bad; - nd6_na_output_fib(ifp, &in6_all, &taddr6, - ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) | - rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL, - M_GETFIB(m)); - goto freeit; + if (!IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { + nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, + ND_NEIGHBOR_SOLICIT, 0); + rflag |= ND_NA_FLAG_SOLICITED; } - nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, - ND_NEIGHBOR_SOLICIT, 0); - - nd6_na_output_fib(ifp, &saddr6, &taddr6, - ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) | - rflag | ND_NA_FLAG_SOLICITED, tlladdr, + nd6_na_output_fib(ifp, &saddr6, &taddr6, rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m)); freeit: if (ifa != NULL) @@ -440,13 +437,6 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6, return; M_SETFIB(m, fibnum); - if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) { - m->m_flags |= M_MCAST; - im6o.im6o_multicast_ifp = ifp; - im6o.im6o_multicast_hlim = 255; - im6o.im6o_multicast_loop = 0; - } - icmp6len = sizeof(*nd_ns); m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len; m->m_data += max_linkhdr; /* or M_ALIGN() equivalent? */ @@ -471,6 +461,12 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6, if (in6_setscope(&ip6->ip6_dst, ifp, NULL) != 0) goto bad; } + if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { + m->m_flags |= M_MCAST; + im6o.im6o_multicast_ifp = ifp; + im6o.im6o_multicast_hlim = 255; + im6o.im6o_multicast_loop = 0; + } if (nonce == NULL) { char ip6buf[INET6_ADDRSTRLEN]; struct ifaddr *ifa = NULL; @@ -492,20 +488,16 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6, ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, saddr6); if (ifa == NULL) { int error; - struct in6_addr dst6, src6; - uint32_t scopeid; - in6_splitscope(&ip6->ip6_dst, &dst6, &scopeid); - error = in6_selectsrc_addr(fibnum, &dst6, - scopeid, ifp, &src6, NULL); + error = in6_selectsrc_nbr(fibnum, &ip6->ip6_dst, &im6o, + ifp, &ip6->ip6_src); if (error) { nd6log((LOG_DEBUG, "%s: source can't be " "determined: dst=%s, error=%d\n", __func__, - ip6_sprintf(ip6buf, &dst6), + ip6_sprintf(ip6buf, &ip6->ip6_dst), error)); goto bad; } - ip6->ip6_src = src6; } else ip6->ip6_src = *saddr6; @@ -968,7 +960,9 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD) * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD) * - * tlladdr - 1 if include target link-layer address + * tlladdr: + * - 0x01 if include target link-layer address + * - 0x02 if target address is CARP MASTER * sdl0 - sockaddr_dl (= proxy NA) or NULL */ static void @@ -981,8 +975,7 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0, struct ip6_hdr *ip6; struct nd_neighbor_advert *nd_na; struct ip6_moptions im6o; - struct in6_addr daddr6, dst6, src6; - uint32_t scopeid; + struct in6_addr daddr6; NET_EPOCH_ASSERT(); @@ -1006,13 +999,6 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0, return; M_SETFIB(m, fibnum); - if (IN6_IS_ADDR_MULTICAST(&daddr6)) { - m->m_flags |= M_MCAST; - im6o.im6o_multicast_ifp = ifp; - im6o.im6o_multicast_hlim = 255; - im6o.im6o_multicast_loop = 0; - } - icmp6len = sizeof(*nd_na); m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + icmp6len; m->m_data += max_linkhdr; /* or M_ALIGN() equivalent? */ @@ -1024,26 +1010,24 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0, ip6->ip6_vfc |= IPV6_VERSION; ip6->ip6_nxt = IPPROTO_ICMPV6; ip6->ip6_hlim = 255; + if (IN6_IS_ADDR_UNSPECIFIED(&daddr6)) { /* reply to DAD */ - daddr6.s6_addr16[0] = IPV6_ADDR_INT16_MLL; - daddr6.s6_addr16[1] = 0; - daddr6.s6_addr32[1] = 0; - daddr6.s6_addr32[2] = 0; - daddr6.s6_addr32[3] = IPV6_ADDR_INT32_ONE; + daddr6 = in6addr_linklocal_allnodes; if (in6_setscope(&daddr6, ifp, NULL)) goto bad; flags &= ~ND_NA_FLAG_SOLICITED; } - ip6->ip6_dst = daddr6; + if (IN6_IS_ADDR_MULTICAST(&daddr6)) { + m->m_flags |= M_MCAST; + im6o.im6o_multicast_ifp = ifp; + im6o.im6o_multicast_hlim = 255; + im6o.im6o_multicast_loop = 0; + } - /* - * Select a source whose scope is the same as that of the dest. - */ - in6_splitscope(&daddr6, &dst6, &scopeid); - error = in6_selectsrc_addr(fibnum, &dst6, - scopeid, ifp, &src6, NULL); + ip6->ip6_dst = daddr6; + error = in6_selectsrc_nbr(fibnum, &daddr6, &im6o, ifp, &ip6->ip6_src); if (error) { char ip6buf[INET6_ADDRSTRLEN]; nd6log((LOG_DEBUG, "nd6_na_output: source can't be " @@ -1051,28 +1035,31 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0, ip6_sprintf(ip6buf, &daddr6), error)); goto bad; } - ip6->ip6_src = src6; nd_na = (struct nd_neighbor_advert *)(ip6 + 1); nd_na->nd_na_type = ND_NEIGHBOR_ADVERT; nd_na->nd_na_code = 0; nd_na->nd_na_target = *taddr6; in6_clearscope(&nd_na->nd_na_target); /* XXX */ + /* + * If we respond from CARP address, we need to prepare mac address + * for carp_output(). + */ + if (ifp->if_carp && (tlladdr & ND6_NA_CARP_MASTER)) + mac = (*carp_macmatch6_p)(ifp, m, taddr6); /* * "tlladdr" indicates NS's condition for adding tlladdr or not. * see nd6_ns_input() for details. * Basically, if NS packet is sent to unicast/anycast addr, * target lladdr option SHOULD NOT be included. */ - if (tlladdr) { + if (tlladdr & ND6_NA_OPT_LLA) { /* * sdl0 != NULL indicates proxy NA. If we do proxy, use * lladdr in sdl0. If we are not proxying (sending NA for * my address) use lladdr configured for the interface. */ if (sdl0 == NULL) { - if (ifp->if_carp) - mac = (*carp_macmatch6_p)(ifp, m, taddr6); if (mac == NULL) mac = nd6_ifptomac(ifp); } else if (sdl0->sa_family == AF_LINK) { @@ -1082,7 +1069,7 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0, mac = LLADDR(sdl); } } - if (tlladdr && mac) { + if ((tlladdr & ND6_NA_OPT_LLA) && mac != NULL) { int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen; struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1);