diff options
author | George V. Neville-Neil <gnn@FreeBSD.org> | 2016-06-02 17:51:29 +0000 |
---|---|---|
committer | George V. Neville-Neil <gnn@FreeBSD.org> | 2016-06-02 17:51:29 +0000 |
commit | 6d7682268826ca15ed86237eb25286740b952f1c (patch) | |
tree | 35865ebb972dd3afe8974183497a1af7a56b33fc | |
parent | 55a87f85cfe1614b1745392afa56177e063eabb5 (diff) |
Notes
-rw-r--r-- | sys/net/flowtable.c | 9 | ||||
-rw-r--r-- | sys/net/if_arcsubr.c | 6 | ||||
-rw-r--r-- | sys/net/if_ethersubr.c | 47 | ||||
-rw-r--r-- | sys/net/if_fddisubr.c | 4 | ||||
-rw-r--r-- | sys/net/if_fwsubr.c | 5 | ||||
-rw-r--r-- | sys/net/if_iso88025subr.c | 4 | ||||
-rw-r--r-- | sys/net/if_llatbl.h | 1 | ||||
-rw-r--r-- | sys/net/route.c | 2 | ||||
-rw-r--r-- | sys/net/route.h | 15 | ||||
-rw-r--r-- | sys/netinet/if_ether.c | 20 | ||||
-rw-r--r-- | sys/netinet/if_ether.h | 7 | ||||
-rw-r--r-- | sys/netinet/in_pcb.c | 5 | ||||
-rw-r--r-- | sys/netinet/ip_output.c | 6 | ||||
-rw-r--r-- | sys/netinet/toecore.c | 4 | ||||
-rw-r--r-- | sys/netinet6/in6.h | 5 | ||||
-rw-r--r-- | sys/netinet6/in6_pcb.c | 5 | ||||
-rw-r--r-- | sys/netinet6/ip6_output.c | 3 | ||||
-rw-r--r-- | sys/netinet6/nd6.c | 16 | ||||
-rw-r--r-- | sys/netinet6/nd6.h | 2 |
19 files changed, 123 insertions, 43 deletions
diff --git a/sys/net/flowtable.c b/sys/net/flowtable.c index 895b233ab1a3c..35aff00a5ab39 100644 --- a/sys/net/flowtable.c +++ b/sys/net/flowtable.c @@ -696,13 +696,8 @@ flowtable_lookup(sa_family_t sa, struct mbuf *m, struct route *ro) ro->ro_rt = fle->f_rt; ro->ro_flags |= RT_NORTREF; lle = fle->f_lle; - if (lle != NULL && (lle->la_flags & LLE_VALID)) { - ro->ro_prepend = lle->r_linkdata; - ro->ro_plen = lle->r_hdrlen; - ro->ro_flags |= RT_MAY_LOOP; - if (lle->la_flags & LLE_IFADDR) - ro->ro_flags |= RT_L2_ME; - } + if (lle != NULL && (lle->la_flags & LLE_VALID)) + ro->ro_lle = lle; /* share ref with fle->f_lle */ return (0); } diff --git a/sys/net/if_arcsubr.c b/sys/net/if_arcsubr.c index ff38b68f5dc2a..3bf372baba6c9 100644 --- a/sys/net/if_arcsubr.c +++ b/sys/net/if_arcsubr.c @@ -129,7 +129,8 @@ arc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, else if (ifp->if_flags & IFF_NOARP) adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF; else { - error = arpresolve(ifp, is_gw, m, dst, &adst, NULL); + error = arpresolve(ifp, is_gw, m, dst, &adst, NULL, + NULL); if (error) return (error == EWOULDBLOCK ? 0 : error); } @@ -170,7 +171,8 @@ arc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, if ((m->m_flags & M_MCAST) != 0) adst = arcbroadcastaddr; /* ARCnet broadcast address */ else { - error = nd6_resolve(ifp, is_gw, m, dst, &adst, NULL); + error = nd6_resolve(ifp, is_gw, m, dst, &adst, NULL, + NULL); if (error != 0) return (error == EWOULDBLOCK ? 0 : error); } 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); } diff --git a/sys/net/if_fddisubr.c b/sys/net/if_fddisubr.c index 1ebd4da44d6f2..b02901ffab8e8 100644 --- a/sys/net/if_fddisubr.c +++ b/sys/net/if_fddisubr.c @@ -126,7 +126,7 @@ fddi_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, switch (dst->sa_family) { #ifdef INET case AF_INET: { - error = arpresolve(ifp, is_gw, m, dst, edst, NULL); + error = arpresolve(ifp, is_gw, m, dst, edst, NULL, NULL); if (error) return (error == EWOULDBLOCK ? 0 : error); type = htons(ETHERTYPE_IP); @@ -162,7 +162,7 @@ fddi_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, #endif /* INET */ #ifdef INET6 case AF_INET6: - error = nd6_resolve(ifp, is_gw, m, dst, edst, NULL); + error = nd6_resolve(ifp, is_gw, m, dst, edst, NULL, NULL); if (error) return (error == EWOULDBLOCK ? 0 : error); type = htons(ETHERTYPE_IPV6); diff --git a/sys/net/if_fwsubr.c b/sys/net/if_fwsubr.c index c2253d4ef0ae9..57f42567128fd 100644 --- a/sys/net/if_fwsubr.c +++ b/sys/net/if_fwsubr.c @@ -144,7 +144,8 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, * doesn't fit into the arp model. */ if (unicast) { - error = arpresolve(ifp, is_gw, m, dst, (u_char *) destfw, NULL); + error = arpresolve(ifp, is_gw, m, dst, + (u_char *) destfw, NULL, NULL); if (error) return (error == EWOULDBLOCK ? 0 : error); } @@ -174,7 +175,7 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, case AF_INET6: if (unicast) { error = nd6_resolve(fc->fc_ifp, is_gw, m, dst, - (u_char *) destfw, NULL); + (u_char *) destfw, NULL, NULL); if (error) return (error == EWOULDBLOCK ? 0 : error); } diff --git a/sys/net/if_iso88025subr.c b/sys/net/if_iso88025subr.c index a96e2b9c69463..8306154e56756 100644 --- a/sys/net/if_iso88025subr.c +++ b/sys/net/if_iso88025subr.c @@ -254,7 +254,7 @@ iso88025_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, switch (dst->sa_family) { #ifdef INET case AF_INET: - error = arpresolve(ifp, is_gw, m, dst, edst, NULL); + error = arpresolve(ifp, is_gw, m, dst, edst, NULL, NULL); if (error) return (error == EWOULDBLOCK ? 0 : error); snap_type = ETHERTYPE_IP; @@ -289,7 +289,7 @@ iso88025_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, #endif /* INET */ #ifdef INET6 case AF_INET6: - error = nd6_resolve(ifp, is_gw, m, dst, edst, NULL); + error = nd6_resolve(ifp, is_gw, m, dst, edst, NULL, NULL); if (error) return (error == EWOULDBLOCK ? 0 : error); snap_type = ETHERTYPE_IPV6; diff --git a/sys/net/if_llatbl.h b/sys/net/if_llatbl.h index b6111c65cc9f8..51de726a621ec 100644 --- a/sys/net/if_llatbl.h +++ b/sys/net/if_llatbl.h @@ -138,7 +138,6 @@ struct llentry { LLE_FREE_LOCKED(lle); \ } while (0) - typedef struct llentry *(llt_lookup_t)(struct lltable *, u_int flags, const struct sockaddr *l3addr); typedef struct llentry *(llt_alloc_t)(struct lltable *, u_int flags, diff --git a/sys/net/route.c b/sys/net/route.c index 4b191d00d4e04..26e3b851c15a3 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -207,6 +207,8 @@ rt_tables_get_gen(int table, int fam) struct rib_head *rnh; rnh = *rt_tables_get_rnh_ptr(table, fam); + KASSERT(rnh != NULL, ("%s: NULL rib_head pointer table %d fam %d", + __func__, table, fam)); return (rnh->rnh_gen); } diff --git a/sys/net/route.h b/sys/net/route.h index e0ff6b4081a6e..46e2ace15f903 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -50,6 +50,11 @@ */ struct route { struct rtentry *ro_rt; + struct llentry *ro_lle; + /* + * ro_prepend and ro_plen are only used for bpf to pass in a + * preformed header. They are not cacheable. + */ char *ro_prepend; uint16_t ro_plen; uint16_t ro_flags; @@ -71,6 +76,7 @@ struct route { #define RT_REJECT 0x0020 /* Destination is reject */ #define RT_BLACKHOLE 0x0040 /* Destination is blackhole */ #define RT_HAS_GW 0x0080 /* Destination has GW */ +#define RT_LLE_CACHE 0x0100 /* Cache link layer */ struct rt_metrics { u_long rmx_locks; /* Kernel must leave these values alone */ @@ -399,6 +405,7 @@ struct rt_addrinfo { if ((_ro)->ro_flags & RT_NORTREF) { \ (_ro)->ro_flags &= ~RT_NORTREF; \ (_ro)->ro_rt = NULL; \ + (_ro)->ro_lle = NULL; \ } else { \ RT_LOCK((_ro)->ro_rt); \ RTFREE_LOCKED((_ro)->ro_rt); \ @@ -413,9 +420,11 @@ struct rt_addrinfo { */ #define RT_VALIDATE(ro, cookiep, fibnum) do { \ rt_gen_t cookie = RT_GEN(fibnum, (ro)->ro_dst.sa_family); \ - if (*(cookiep) != cookie && (ro)->ro_rt != NULL) { \ - RTFREE((ro)->ro_rt); \ - (ro)->ro_rt = NULL; \ + if (*(cookiep) != cookie) { \ + if ((ro)->ro_rt != NULL) { \ + RTFREE((ro)->ro_rt); \ + (ro)->ro_rt = NULL; \ + } \ *(cookiep) = cookie; \ } \ } while (0) diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index eac3c1d247824..48fae92ae5fed 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -420,7 +420,8 @@ arprequest(struct ifnet *ifp, const struct in_addr *sip, */ static int arpresolve_full(struct ifnet *ifp, int is_gw, int flags, struct mbuf *m, - const struct sockaddr *dst, u_char *desten, uint32_t *pflags) + const struct sockaddr *dst, u_char *desten, uint32_t *pflags, + struct llentry **plle) { struct llentry *la = NULL, *la_tmp; struct mbuf *curr = NULL; @@ -431,6 +432,8 @@ arpresolve_full(struct ifnet *ifp, int is_gw, int flags, struct mbuf *m, if (pflags != NULL) *pflags = 0; + if (plle != NULL) + *plle = NULL; if ((flags & LLE_CREATE) == 0) { IF_AFDATA_RLOCK(ifp); @@ -483,6 +486,10 @@ arpresolve_full(struct ifnet *ifp, int is_gw, int flags, struct mbuf *m, } if (pflags != NULL) *pflags = la->la_flags & (LLE_VALID|LLE_IFADDR); + if (plle) { + LLE_ADDREF(la); + *plle = la; + } LLE_WUNLOCK(la); return (0); } @@ -548,12 +555,12 @@ arpresolve_full(struct ifnet *ifp, int is_gw, int flags, struct mbuf *m, */ int arpresolve_addr(struct ifnet *ifp, int flags, const struct sockaddr *dst, - char *desten, uint32_t *pflags) + char *desten, uint32_t *pflags, struct llentry **plle) { int error; flags |= LLE_ADDRONLY; - error = arpresolve_full(ifp, 0, flags, NULL, dst, desten, pflags); + error = arpresolve_full(ifp, 0, flags, NULL, dst, desten, pflags, plle); return (error); } @@ -576,12 +583,15 @@ arpresolve_addr(struct ifnet *ifp, int flags, const struct sockaddr *dst, */ int arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m, - const struct sockaddr *dst, u_char *desten, uint32_t *pflags) + const struct sockaddr *dst, u_char *desten, uint32_t *pflags, + struct llentry **plle) { struct llentry *la = NULL; if (pflags != NULL) *pflags = 0; + if (plle != NULL) + *plle = NULL; if (m != NULL) { if (m->m_flags & M_BCAST) { @@ -616,7 +626,7 @@ arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m, IF_AFDATA_RUNLOCK(ifp); return (arpresolve_full(ifp, is_gw, la == NULL ? LLE_CREATE : 0, m, dst, - desten, pflags)); + desten, pflags, plle)); } /* diff --git a/sys/netinet/if_ether.h b/sys/netinet/if_ether.h index 06ec210c07fba..27e51f78b69c3 100644 --- a/sys/netinet/if_ether.h +++ b/sys/netinet/if_ether.h @@ -113,11 +113,14 @@ extern u_char ether_ipmulticast_min[ETHER_ADDR_LEN]; extern u_char ether_ipmulticast_max[ETHER_ADDR_LEN]; struct ifaddr; +struct llentry; int arpresolve_addr(struct ifnet *ifp, int flags, - const struct sockaddr *dst, char *desten, uint32_t *pflags); + const struct sockaddr *dst, char *desten, uint32_t *pflags, + struct llentry **plle); int arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m, - const struct sockaddr *dst, u_char *desten, uint32_t *pflags); + const struct sockaddr *dst, u_char *desten, uint32_t *pflags, + struct llentry **plle); void arprequest(struct ifnet *, const struct in_addr *, const struct in_addr *, u_char *); void arp_ifinit(struct ifnet *, struct ifaddr *); diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 50e5d6e45d211..7d5da0e8e0eba 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$"); #include <net/if.h> #include <net/if_var.h> #include <net/if_types.h> +#include <net/if_llatbl.h> #include <net/route.h> #include <net/rss_config.h> #include <net/vnet.h> @@ -1302,6 +1303,8 @@ in_pcbfree(struct inpcb *inp) RTFREE(inp->inp_route.ro_rt); inp->inp_route.ro_rt = (struct rtentry *)NULL; } + if (inp->inp_route.ro_lle) + LLE_FREE(inp->inp_route.ro_lle); /* zeros ro_lle */ inp->inp_vflag = 0; inp->inp_flags2 |= INP_FREED; @@ -2243,6 +2246,8 @@ in_losing(struct inpcb *inp) RTFREE(inp->inp_route.ro_rt); inp->inp_route.ro_rt = (struct rtentry *)NULL; } + if (inp->inp_route.ro_lle) + LLE_FREE(inp->inp_route.ro_lle); /* zeros ro_lle */ return; } diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index ec1996078d1d2..27363a096eb3f 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -245,7 +245,8 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags, if (ro == NULL) { ro = &iproute; bzero(ro, sizeof (*ro)); - } + } else + ro->ro_flags |= RT_LLE_CACHE; #ifdef FLOWTABLE if (ro->ro_rt == NULL) @@ -311,6 +312,9 @@ again: dst->sin_addr.s_addr != ip->ip_dst.s_addr)) { RTFREE(rte); rte = ro->ro_rt = (struct rtentry *)NULL; + if (ro->ro_lle) + LLE_FREE(ro->ro_lle); /* zeros ro_lle */ + ro->ro_lle = (struct llentry *)NULL; } ia = NULL; have_ia_ref = 0; diff --git a/sys/netinet/toecore.c b/sys/netinet/toecore.c index 4bca16c09120b..3354b01794af9 100644 --- a/sys/netinet/toecore.c +++ b/sys/netinet/toecore.c @@ -451,12 +451,12 @@ toe_l2_resolve(struct toedev *tod, struct ifnet *ifp, struct sockaddr *sa, switch (sa->sa_family) { #ifdef INET case AF_INET: - rc = arpresolve(ifp, 0, NULL, sa, lladdr, NULL); + rc = arpresolve(ifp, 0, NULL, sa, lladdr, NULL, NULL); break; #endif #ifdef INET6 case AF_INET6: - rc = nd6_resolve(ifp, 0, NULL, sa, lladdr, NULL); + rc = nd6_resolve(ifp, 0, NULL, sa, lladdr, NULL, NULL); break; #endif default: diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h index ae049f0d11066..c84881e404274 100644 --- a/sys/netinet6/in6.h +++ b/sys/netinet6/in6.h @@ -375,6 +375,11 @@ extern const struct in6_addr in6addr_linklocal_allv2routers; #if __BSD_VISIBLE struct route_in6 { struct rtentry *ro_rt; + struct llentry *ro_lle; + /* + * ro_prepend and ro_plen are only used for bpf to pass in a + * preformed header. They are not cacheable. + */ char *ro_prepend; uint16_t ro_plen; uint16_t ro_flags; diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index 98f4cd3c1cdd9..ff8813b143475 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -92,6 +92,7 @@ __FBSDID("$FreeBSD$"); #include <net/if.h> #include <net/if_var.h> +#include <net/if_llatbl.h> #include <net/if_types.h> #include <net/route.h> @@ -831,6 +832,8 @@ in6_losing(struct inpcb *in6p) RTFREE(in6p->inp_route6.ro_rt); in6p->inp_route6.ro_rt = (struct rtentry *)NULL; } + if (in6p->inp_route.ro_lle) + LLE_FREE(in6p->inp_route.ro_lle); /* zeros ro_lle */ return; } @@ -846,6 +849,8 @@ in6_rtchange(struct inpcb *inp, int errno) RTFREE(inp->inp_route6.ro_rt); inp->inp_route6.ro_rt = (struct rtentry *)NULL; } + if (inp->inp_route.ro_lle) + LLE_FREE(inp->inp_route.ro_lle); /* zeros ro_lle */ return inp; } diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index e12aee44e6352..fde6710e225f9 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -500,7 +500,8 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, if (ro == NULL) { ro = &ip6route; bzero((caddr_t)ro, sizeof(*ro)); - } + } else + ro->ro_flags |= RT_LLE_CACHE; ro_pmtu = ro; if (opt && opt->ip6po_rthdr) ro = &opt->ip6po_route; diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 6db94fd0eddb9..0585cd714e04f 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -136,7 +136,7 @@ static void nd6_llinfo_settimer_locked(struct llentry *, long); static void clear_llinfo_pqueue(struct llentry *); static void nd6_rtrequest(int, struct rtentry *, struct rt_addrinfo *); static int nd6_resolve_slow(struct ifnet *, int, struct mbuf *, - const struct sockaddr_in6 *, u_char *, uint32_t *); + const struct sockaddr_in6 *, u_char *, uint32_t *, struct llentry **); static int nd6_need_cache(struct ifnet *); @@ -2175,7 +2175,8 @@ nd6_output_ifp(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m, */ int nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m, - const struct sockaddr *sa_dst, u_char *desten, uint32_t *pflags) + const struct sockaddr *sa_dst, u_char *desten, uint32_t *pflags, + struct llentry **plle) { struct llentry *ln = NULL; const struct sockaddr_in6 *dst6; @@ -2227,7 +2228,7 @@ nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m, } IF_AFDATA_RUNLOCK(ifp); - return (nd6_resolve_slow(ifp, 0, m, dst6, desten, pflags)); + return (nd6_resolve_slow(ifp, 0, m, dst6, desten, pflags, plle)); } @@ -2244,7 +2245,8 @@ nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m, */ static __noinline int nd6_resolve_slow(struct ifnet *ifp, int flags, struct mbuf *m, - const struct sockaddr_in6 *dst, u_char *desten, uint32_t *pflags) + const struct sockaddr_in6 *dst, u_char *desten, uint32_t *pflags, + struct llentry **plle) { struct llentry *lle = NULL, *lle_tmp; struct in6_addr *psrc, src; @@ -2331,6 +2333,10 @@ nd6_resolve_slow(struct ifnet *ifp, int flags, struct mbuf *m, bcopy(lladdr, desten, ll_len); if (pflags != NULL) *pflags = lle->la_flags; + if (plle) { + LLE_ADDREF(lle); + *plle = lle; + } LLE_WUNLOCK(lle); return (0); } @@ -2405,7 +2411,7 @@ nd6_resolve_addr(struct ifnet *ifp, int flags, const struct sockaddr *dst, flags |= LLE_ADDRONLY; error = nd6_resolve_slow(ifp, flags, NULL, - (const struct sockaddr_in6 *)dst, desten, pflags); + (const struct sockaddr_in6 *)dst, desten, pflags, NULL); return (error); } diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index 0978f0d2e9663..ce98975d3792e 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -428,7 +428,7 @@ void nd6_purge(struct ifnet *); int nd6_resolve_addr(struct ifnet *ifp, int flags, const struct sockaddr *dst, char *desten, uint32_t *pflags); int nd6_resolve(struct ifnet *, int, struct mbuf *, - const struct sockaddr *, u_char *, uint32_t *); + const struct sockaddr *, u_char *, uint32_t *, struct llentry **); int nd6_ioctl(u_long, caddr_t, struct ifnet *); void nd6_cache_lladdr(struct ifnet *, struct in6_addr *, char *, int, int, int); |