Page MenuHomeFreeBSD

D35307.id106314.diff
No OneTemporary

D35307.id106314.diff

Index: sys/net/if_llatbl.c
===================================================================
--- sys/net/if_llatbl.c
+++ sys/net/if_llatbl.c
@@ -708,6 +708,13 @@
lltable_unlink_entry(llt, lle);
IF_AFDATA_WUNLOCK(ifp);
+#ifdef INET6
+ /* Leave the solicited multicast group for dst. */
+ if ((lle->la_flags & (LLE_PUB | LLE_STATIC | LLE_IFADDR)) ==
+ (LLE_PUB | LLE_STATIC)
+ && l3addr->sa_family == AF_INET6)
+ in6_handle_proxy_ndp_mc(RTM_DELETE, ifp, l3addr);
+#endif
llt->llt_delete_entry(llt, lle);
@@ -978,6 +985,12 @@
&((struct sockaddr_in *)dst)->sin_addr,
(u_char *)LLADDR(dl));
#endif
+#ifdef INET6
+ /* Join the solicited multicast group for dst. */
+ if ((laflags & (LLE_PUB | LLE_STATIC)) == (LLE_PUB | LLE_STATIC)
+ && dst->sa_family == AF_INET6)
+ in6_handle_proxy_ndp_mc(rtm->rtm_type, ifp, dst);
+#endif
break;
Index: sys/netinet6/in6.c
===================================================================
--- sys/netinet6/in6.c
+++ sys/netinet6/in6.c
@@ -2614,3 +2614,116 @@
free(*nam, M_SONAME);
*nam = (struct sockaddr *)sin6_p;
}
+
+/*
+ * Join/leave the solicited multicast groups for proxy NDP entries.
+ */
+static struct mtx pndp_mc_list_mtx;
+MTX_SYSINIT(pndp_mc_list_mtx, &pndp_mc_list_mtx, "pndp_mc_listmtx", MTX_DEF);
+#define PNDP_MC_LIST_LOCK() mtx_lock(&pndp_mc_list_mtx)
+#define PNDP_MC_LIST_UNLOCK() mtx_unlock(&pndp_mc_list_mtx)
+
+static LIST_HEAD(in6_pndp_mc_list, in6_multi_mship) pndp_mc_list;
+
+static void in6_pndp_mc_list_add(struct in6_multi_mship *imm);
+static void in6_pndp_mc_list_delete(struct in6_multi *inm);
+
+void
+in6_handle_proxy_ndp_mc(int cmd, struct ifnet *ifp, const struct sockaddr *sa)
+{
+ const struct sockaddr_in6 *sin6;
+ struct in6_multi_mship *imm;
+ struct in6_multi *inm;
+ struct in6_addr mltaddr;
+ struct epoch_tracker et;
+ char ip6buf[INET6_ADDRSTRLEN];
+ int error;
+
+ sin6 = (const struct sockaddr_in6 *)sa;
+ bzero(&mltaddr, sizeof(struct in6_addr));
+ mltaddr.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
+ mltaddr.s6_addr32[2] = htonl(1);
+ mltaddr.s6_addr32[3] = sin6->sin6_addr.s6_addr32[3];
+ mltaddr.s6_addr8[12] = 0xff;
+ if ((error = in6_setscope(&mltaddr, ifp, NULL)) != 0) {
+ nd6log((LOG_ERR, "%s: in6_setscope failed\n", __func__));
+ return;
+ }
+ if (cmd == RTM_ADD) {
+ imm = in6_joingroup_legacy(ifp, &mltaddr, &error, 0);
+ if (imm != NULL)
+ in6_pndp_mc_list_add(imm);
+ else {
+ nd6log((LOG_WARNING,
+ "%s: in6_joingroup_legacy failed for %s on %s "
+ "(errno=%d)\n", __func__,
+ ip6_sprintf(ip6buf, &mltaddr), if_name(ifp),
+ error));
+ return;
+ }
+ } else {
+ NET_EPOCH_ENTER(et);
+ inm = in6m_lookup(ifp, &mltaddr);
+ NET_EPOCH_EXIT(et);
+ if (inm != NULL) {
+ in6_pndp_mc_list_delete(inm);
+ in6_leavegroup(inm, NULL);
+ } else {
+ nd6log((LOG_WARNING,
+ "%s: in6_lookup failed for %s on %s\n",
+ __func__, ip6_sprintf(ip6buf, &mltaddr),
+ if_name(ifp)));
+ }
+ }
+}
+
+void
+in6_purge_proxy_ndp_mc(struct ifnet *ifp)
+{
+ struct in6_pndp_mc_list removed;
+ struct in6_multi_mship *imm;
+
+ LIST_INIT(&removed);
+ PNDP_MC_LIST_LOCK();
+ LIST_FOREACH(imm, &pndp_mc_list, i6mm_chain) {
+ if (imm->i6mm_maddr->in6m_ifp == ifp) {
+ LIST_REMOVE(imm, i6mm_chain);
+ LIST_INSERT_HEAD(&removed, imm, i6mm_chain);
+ }
+ }
+ PNDP_MC_LIST_UNLOCK();
+
+ while ((imm = LIST_FIRST(&removed)) != NULL) {
+ LIST_REMOVE(imm, i6mm_chain);
+ in6_leavegroup(imm->i6mm_maddr, NULL);
+ free(imm, M_IP6MADDR);
+ }
+}
+
+static void
+in6_pndp_mc_list_add(struct in6_multi_mship *imm)
+{
+ PNDP_MC_LIST_LOCK();
+ LIST_INSERT_HEAD(&pndp_mc_list, imm, i6mm_chain);
+ PNDP_MC_LIST_UNLOCK();
+}
+
+static void
+in6_pndp_mc_list_delete(struct in6_multi *inm)
+{
+ struct in6_multi_mship *imm;
+
+ PNDP_MC_LIST_LOCK();
+ LIST_FOREACH(imm, &pndp_mc_list, i6mm_chain) {
+ if (imm->i6mm_maddr == inm) {
+ LIST_REMOVE(imm, i6mm_chain);
+ break;
+ }
+ }
+ PNDP_MC_LIST_UNLOCK();
+ if (imm != NULL)
+ free(imm, M_IP6MADDR);
+ else
+ nd6log((LOG_WARNING,
+ "in6_multi %p not found on proxy ndp list.\n", inm));
+}
Index: sys/netinet6/in6_ifattach.c
===================================================================
--- sys/netinet6/in6_ifattach.c
+++ sys/netinet6/in6_ifattach.c
@@ -861,6 +861,7 @@
{
struct in6_multi_head inmh;
+ in6_purge_proxy_ndp_mc(ifp);
SLIST_INIT(&inmh);
IN6_MULTI_LOCK();
IN6_MULTI_LIST_LOCK();
Index: sys/netinet6/in6_var.h
===================================================================
--- sys/netinet6/in6_var.h
+++ sys/netinet6/in6_var.h
@@ -916,6 +916,9 @@
int in6_src_ioctl(u_long, caddr_t);
void in6_newaddrmsg(struct in6_ifaddr *, int);
+
+void in6_handle_proxy_ndp_mc(int, struct ifnet *, const struct sockaddr *);
+void in6_purge_proxy_ndp_mc(struct ifnet *);
/*
* Extended API for IPv6 FIB support.
*/
Index: sys/netinet6/nd6_nbr.c
===================================================================
--- sys/netinet6/nd6_nbr.c
+++ sys/netinet6/nd6_nbr.c
@@ -255,33 +255,29 @@
/* (2) check. */
proxy = 0;
if (ifa == NULL) {
- struct sockaddr_dl rt_gateway;
- struct rt_addrinfo info;
- struct sockaddr_in6 dst6;
-
- bzero(&dst6, sizeof(dst6));
- dst6.sin6_len = sizeof(struct sockaddr_in6);
- dst6.sin6_family = AF_INET6;
- dst6.sin6_addr = taddr6;
-
- bzero(&rt_gateway, sizeof(rt_gateway));
- rt_gateway.sdl_len = sizeof(rt_gateway);
- bzero(&info, sizeof(info));
- info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&rt_gateway;
-
- if (rib_lookup_info(ifp->if_fib, (struct sockaddr *)&dst6,
- 0, 0, &info) == 0) {
- if ((info.rti_flags & RTF_ANNOUNCE) != 0 &&
- rt_gateway.sdl_family == AF_LINK) {
- /*
- * proxy NDP for single entry
- */
- proxydl = *SDL(&rt_gateway);
+ struct llentry *ln;
+
+ ln = nd6_lookup(&taddr6, LLE_SF(AF_INET6, 0), ifp);
+ if (ln != NULL) {
+#define LLE_PROXY_ND (LLE_PUB | LLE_STATIC | LLE_VALID)
+ /*
+ * ifa == NULL here should be sufficient for proxy,
+ * but we can check by !LLE_IFADDR also.
+ */
+ if ((ln->la_flags & (LLE_PROXY_ND | LLE_IFADDR))
+ == LLE_PROXY_ND) {
+ link_init_sdl(ifp, (struct sockaddr *)&proxydl,
+ ifp->if_type);
+ proxydl.sdl_alen = ifp->if_addrlen;
+ bcopy(ln->ll_addr, &proxydl.sdl_data,
+ ifp->if_addrlen);
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(
ifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
if (ifa)
proxy = 1;
+#undef LLE_PROXY_ND
}
+ LLE_RUNLOCK(ln);
}
}
if (ifa == NULL) {

File Metadata

Mime Type
text/plain
Expires
Tue, May 19, 10:38 AM (22 h, 52 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33308098
Default Alt Text
D35307.id106314.diff (6 KB)

Event Timeline