Index: sys/netinet/if_ether.c =================================================================== --- sys/netinet/if_ether.c +++ sys/netinet/if_ether.c @@ -1149,6 +1149,39 @@ } #endif +static void +arp_grab_holdchain(struct llentry *la, struct mbuf **chain, + struct sockaddr_in *sin) +{ + LLE_WLOCK_ASSERT(la); + + *chain = la->la_hold; + la->la_hold = NULL; + la->la_numheld = 0; + lltable_fill_sa_entry(la, (struct sockaddr *)&sin); +} + + +static void +arp_flush_holdchain(struct ifnet *ifp, struct llentry *la, struct mbuf *chain, + struct sockaddr_in *dst) +{ + struct mbuf *m_hold, *m_hold_next; + + struct route ro = { + .ro_prepend = la->r_linkdata, + .ro_plen = la->r_hdrlen, + }; + + for (m_hold = chain; m_hold != NULL; m_hold = m_hold_next) { + m_hold_next = m_hold->m_nextpkt; + m_hold->m_nextpkt = NULL; + /* Avoid confusing lower layers. */ + m_clrprotoflags(m_hold); + (*ifp->if_output)(ifp, m_hold, (struct sockaddr *)dst, &ro); + } +} + /* * Checks received arp data against existing @la. * Updates lle state/performs notification if necessary. @@ -1157,8 +1190,6 @@ arp_check_update_lle(struct arphdr *ah, struct in_addr isaddr, struct ifnet *ifp, int bridged, struct llentry *la) { - struct sockaddr sa; - struct mbuf *m_hold, *m_hold_next; uint8_t linkhdr[LLE_MAX_LINKHDR]; size_t linkhdrsize; int lladdr_off; @@ -1231,18 +1262,12 @@ * output routine. */ if (la->la_hold != NULL) { - m_hold = la->la_hold; - la->la_hold = NULL; - la->la_numheld = 0; - lltable_fill_sa_entry(la, &sa); + struct sockaddr_in sin; + struct mbuf *chain; + + arp_grab_holdchain(la, &chain, &sin); LLE_WUNLOCK(la); - for (; m_hold != NULL; m_hold = m_hold_next) { - m_hold_next = m_hold->m_nextpkt; - m_hold->m_nextpkt = NULL; - /* Avoid confusing lower layers. */ - m_clrprotoflags(m_hold); - (*ifp->if_output)(ifp, m_hold, &sa, NULL); - } + arp_flush_holdchain(ifp, la, chain, &sin); } else LLE_WUNLOCK(la); } Index: sys/netinet6/nd6.h =================================================================== --- sys/netinet6/nd6.h +++ sys/netinet6/nd6.h @@ -378,7 +378,7 @@ char *, int, int, int); void nd6_grab_holdchain(struct llentry *, struct mbuf **, struct sockaddr_in6 *); -int nd6_flush_holdchain(struct ifnet *, struct mbuf *, +int nd6_flush_holdchain(struct ifnet *, struct llentry *, struct mbuf *, struct sockaddr_in6 *); int nd6_add_ifa_lle(struct in6_ifaddr *); void nd6_rem_ifa_lle(struct in6_ifaddr *, int); Index: sys/netinet6/nd6.c =================================================================== --- sys/netinet6/nd6.c +++ sys/netinet6/nd6.c @@ -2067,7 +2067,7 @@ LLE_RUNLOCK(ln); if (chain != NULL) - nd6_flush_holdchain(ifp, chain, &sin6); + nd6_flush_holdchain(ifp, ln, chain, &sin6); /* * When the link-layer address of a router changes, select the @@ -2446,19 +2446,24 @@ } int -nd6_flush_holdchain(struct ifnet *ifp, struct mbuf *chain, +nd6_flush_holdchain(struct ifnet *ifp, struct llentry *lle, struct mbuf *chain, struct sockaddr_in6 *dst) { struct mbuf *m, *m_head; int error = 0; + struct route_in6 ro = { + .ro_prepend = lle->r_linkdata, + .ro_plen = lle->r_hdrlen, + }; + m_head = chain; while (m_head) { m = m_head; m_head = m_head->m_nextpkt; m->m_nextpkt = NULL; - error = nd6_output_ifp(ifp, ifp, m, dst, NULL); + error = nd6_output_ifp(ifp, ifp, m, dst, (struct route *)&ro); } /* Index: sys/netinet6/nd6_nbr.c =================================================================== --- sys/netinet6/nd6_nbr.c +++ sys/netinet6/nd6_nbr.c @@ -908,7 +908,7 @@ LLE_WUNLOCK(ln); if (chain != NULL) - nd6_flush_holdchain(ifp, chain, &sin6); + nd6_flush_holdchain(ifp, ln, chain, &sin6); if (checklink) pfxlist_onlink_check();