diff options
Diffstat (limited to 'sys/net/if_ethersubr.c')
-rw-r--r-- | sys/net/if_ethersubr.c | 47 |
1 files changed, 40 insertions, 7 deletions
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 6f0e6e3cc1776..9346aecb9f827 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -199,7 +199,7 @@ ether_requestencap(struct ifnet *ifp, struct if_encap_req *req) static int ether_resolve_addr(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, struct route *ro, u_char *phdr, - uint32_t *pflags) + uint32_t *pflags, struct llentry **plle) { struct ether_header *eh; uint32_t lleflags = 0; @@ -208,13 +208,16 @@ ether_resolve_addr(struct ifnet *ifp, struct mbuf *m, uint16_t etype; #endif + if (plle) + *plle = NULL; eh = (struct ether_header *)phdr; switch (dst->sa_family) { #ifdef INET case AF_INET: if ((m->m_flags & (M_BCAST | M_MCAST)) == 0) - error = arpresolve(ifp, 0, m, dst, phdr, &lleflags); + error = arpresolve(ifp, 0, m, dst, phdr, &lleflags, + plle); else { if (m->m_flags & M_BCAST) memcpy(eh->ether_dhost, ifp->if_broadcastaddr, @@ -233,7 +236,8 @@ ether_resolve_addr(struct ifnet *ifp, struct mbuf *m, #ifdef INET6 case AF_INET6: if ((m->m_flags & M_MCAST) == 0) - error = nd6_resolve(ifp, 0, m, dst, phdr, &lleflags); + error = nd6_resolve(ifp, 0, m, dst, phdr, &lleflags, + plle); else { const struct in6_addr *a6; a6 = &(((const struct sockaddr_in6 *)dst)->sin6_addr); @@ -283,14 +287,40 @@ ether_output(struct ifnet *ifp, struct mbuf *m, int loop_copy = 1; int hlen; /* link layer header length */ uint32_t pflags; + struct llentry *lle = NULL; + struct rtentry *rt0 = NULL; + int addref = 0; phdr = NULL; pflags = 0; if (ro != NULL) { - phdr = ro->ro_prepend; - hlen = ro->ro_plen; - pflags = ro->ro_flags; + /* XXX BPF uses ro_prepend */ + if (ro->ro_prepend != NULL) { + phdr = ro->ro_prepend; + hlen = ro->ro_plen; + } else if (!(m->m_flags & (M_BCAST | M_MCAST))) { + if ((ro->ro_flags & RT_LLE_CACHE) != 0) { + lle = ro->ro_lle; + if (lle != NULL && + (lle->la_flags & LLE_VALID) == 0) { + LLE_FREE(lle); + lle = NULL; /* redundant */ + ro->ro_lle = NULL; + } + if (lle == NULL) { + /* if we lookup, keep cache */ + addref = 1; + } + } + if (lle != NULL) { + phdr = lle->r_linkdata; + hlen = lle->r_hdrlen; + pflags = lle->r_flags; + } + } + rt0 = ro->ro_rt; } + #ifdef MAC error = mac_ifnet_check_transmit(ifp, m); if (error) @@ -308,7 +338,10 @@ ether_output(struct ifnet *ifp, struct mbuf *m, /* No prepend data supplied. Try to calculate ourselves. */ phdr = linkhdr; hlen = ETHER_HDR_LEN; - error = ether_resolve_addr(ifp, m, dst, ro, phdr, &pflags); + error = ether_resolve_addr(ifp, m, dst, ro, phdr, &pflags, + addref ? &lle : NULL); + if (addref && lle != NULL) + ro->ro_lle = lle; if (error != 0) return (error == EWOULDBLOCK ? 0 : error); } |