Index: sys/net/flowtable.c =================================================================== --- sys/net/flowtable.c +++ sys/net/flowtable.c @@ -504,7 +504,7 @@ struct rtentry *rt; struct lltable *lt = NULL; struct llentry *lle; - struct sockaddr_storage *l3addr; + void *l3addr; struct ifnet *ifp; struct flist *flist; struct flentry *fle, *iter; @@ -581,11 +581,16 @@ lt = LLTABLE6(ifp); #endif - if (rt->rt_flags & RTF_GATEWAY) - l3addr = (struct sockaddr_storage *)rt->rt_gateway; - else - l3addr = (struct sockaddr_storage *)&ro->ro_dst; - lle = llentry_alloc(ifp, lt, l3addr); + l3addr = (void *)key; +#ifdef INET + if (rt->rt_flags & RTF_GATEWAY && ft == &V_ip4_ft) + l3addr = &((struct sockaddr_in *)rt->rt_gateway)->sin_addr; +#endif +#ifdef INET6 + if (rt->rt_flags & RTF_GATEWAY && ft == &V_ip6_ft) + l3addr = &((struct sockaddr_in6 *)rt->rt_gateway)->sin6_addr; +#endif + lle = llentry_request(ifp, lt, l3addr); if (lle == NULL) { RTFREE(rt); Index: sys/net/if_ethersubr.c =================================================================== --- sys/net/if_ethersubr.c +++ sys/net/if_ethersubr.c @@ -204,6 +204,12 @@ struct ether_header *eh; uint32_t lleflags = 0; int error = 0; +#ifdef INET + const struct in_addr *a; +#endif +#ifdef INET6 + const struct in6_addr *a6; +#endif #if defined(INET) || defined(INET6) uint16_t etype; #endif @@ -213,17 +219,15 @@ switch (dst->sa_family) { #ifdef INET case AF_INET: + a = &(((const struct sockaddr_in *)dst)->sin_addr); if ((m->m_flags & (M_BCAST | M_MCAST)) == 0) - error = arpresolve(ifp, 0, m, dst, phdr, &lleflags); + error = in_resolve_lla(ifp, m, a, phdr, &lleflags); else { if (m->m_flags & M_BCAST) memcpy(eh->ether_dhost, ifp->if_broadcastaddr, ETHER_ADDR_LEN); - else { - const struct in_addr *a; - a = &(((const struct sockaddr_in *)dst)->sin_addr); + else ETHER_MAP_IP_MULTICAST(a, eh->ether_dhost); - } etype = htons(ETHERTYPE_IP); memcpy(&eh->ether_type, &etype, sizeof(etype)); memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN); @@ -232,11 +236,10 @@ #endif #ifdef INET6 case AF_INET6: + a6 = &(((const struct sockaddr_in6 *)dst)->sin6_addr); if ((m->m_flags & M_MCAST) == 0) - error = nd6_resolve(ifp, 0, m, dst, phdr, &lleflags); + error = in6_resolve_lla(ifp, m, a6, phdr, &lleflags); else { - const struct in6_addr *a6; - a6 = &(((const struct sockaddr_in6 *)dst)->sin6_addr); ETHER_MAP_IPV6_MULTICAST(a6, eh->ether_dhost); etype = htons(ETHERTYPE_IPV6); memcpy(&eh->ether_type, &etype, sizeof(etype)); Index: sys/net/if_llatbl.h =================================================================== --- sys/net/if_llatbl.h +++ sys/net/if_llatbl.h @@ -140,9 +140,9 @@ typedef struct llentry *(llt_lookup_t)(struct lltable *, u_int flags, - const struct sockaddr *l3addr); + const void *l3addr); typedef struct llentry *(llt_alloc_t)(struct lltable *, u_int flags, - const struct sockaddr *l3addr); + const void *l3addr); typedef void (llt_delete_t)(struct lltable *, struct llentry *); typedef void (llt_prefix_free_t)(struct lltable *, const struct sockaddr *addr, const struct sockaddr *mask, u_int flags); @@ -218,8 +218,8 @@ int lltable_sysctl_dumparp(int, struct sysctl_req *); size_t llentry_free(struct llentry *); -struct llentry *llentry_alloc(struct ifnet *, struct lltable *, - struct sockaddr_storage *); +struct llentry *llentry_request(struct ifnet *, struct lltable *, + const void *); /* helper functions */ size_t lltable_drop_entry_queue(struct llentry *); @@ -232,7 +232,7 @@ char *buf, size_t *bufsize, int *lladdr_off); void lltable_update_ifaddr(struct lltable *llt); struct llentry *lltable_alloc_entry(struct lltable *llt, u_int flags, - const struct sockaddr *l4addr); + const void *l3addr); void lltable_free_entry(struct lltable *llt, struct llentry *lle); int lltable_delete_addr(struct lltable *llt, u_int flags, const struct sockaddr *l3addr); @@ -248,7 +248,7 @@ * Generic link layer address lookup function. */ static __inline struct llentry * -lla_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) +lla_lookup(struct lltable *llt, u_int flags, const void *l3addr) { return (llt->llt_lookup(llt, flags, l3addr)); Index: sys/net/if_llatbl.c =================================================================== --- sys/net/if_llatbl.c +++ sys/net/if_llatbl.c @@ -440,13 +440,13 @@ * If found the llentry * is returned referenced and unlocked. */ struct llentry * -llentry_alloc(struct ifnet *ifp, struct lltable *lt, - struct sockaddr_storage *dst) +llentry_request(struct ifnet *ifp, struct lltable *lt, + const void *dst) { struct llentry *la, *la_tmp; IF_AFDATA_RLOCK(ifp); - la = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst); + la = lla_lookup(lt, LLE_EXCLUSIVE, dst); IF_AFDATA_RUNLOCK(ifp); if (la != NULL) { @@ -456,13 +456,13 @@ } if ((ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) { - la = lltable_alloc_entry(lt, 0, (struct sockaddr *)dst); + la = lltable_alloc_entry(lt, 0, dst); if (la == NULL) return (NULL); IF_AFDATA_WLOCK(ifp); LLE_WLOCK(la); /* Prefer any existing LLE over newly-created one */ - la_tmp = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst); + la_tmp = lla_lookup(lt, LLE_EXCLUSIVE, dst); if (la_tmp == NULL) lltable_link_entry(lt, la); IF_AFDATA_WUNLOCK(ifp); @@ -660,7 +660,7 @@ struct llentry * lltable_alloc_entry(struct lltable *llt, u_int flags, - const struct sockaddr *l3addr) + const void *l3addr) { return (llt->llt_alloc_entry(llt, flags, l3addr)); @@ -756,7 +756,7 @@ laflags = 0; if (rtm->rtm_rmx.rmx_expire == 0) laflags = LLE_STATIC; - lle = lltable_alloc_entry(llt, laflags, dst); + lle = lltable_alloc_entry(llt, laflags, dst); /* XXX dst SA */ if (lle == NULL) return (ENOMEM); Index: sys/netinet/if_ether.h =================================================================== --- sys/netinet/if_ether.h +++ sys/netinet/if_ether.h @@ -114,6 +114,17 @@ struct ifaddr; +static inline const void * +_check_in_addr_type(const struct in_addr *paddr) +{ + + return ((const void *)paddr); +} +#define arp_lookup(_l, _f, _a) \ + lla_lookup(_l, _f, _check_in_addr_type(_a)) +#define arp_alloc(_l, _f, _a) \ + lltable_alloc_entry(_l, _f, _check_in_addr_type(_a)) + int arpresolve_addr(struct ifnet *ifp, int flags, const struct sockaddr *dst, char *desten, uint32_t *pflags); int arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m, @@ -122,6 +133,8 @@ const struct in_addr *, u_char *); void arp_ifinit(struct ifnet *, struct ifaddr *); void arp_announce_ifaddr(struct ifnet *, struct in_addr addr, u_char *); +int in_resolve_lla(struct ifnet *ifp, struct mbuf *m, + const struct in_addr *dst, u_char *desten, uint32_t *pflags); #endif #endif Index: sys/netinet/if_ether.c =================================================================== --- sys/netinet/if_ether.c +++ sys/netinet/if_ether.c @@ -419,8 +419,8 @@ * Note that m_freem() handles NULL. */ 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) +arpresolve_full(struct ifnet *ifp, int flags, struct mbuf *m, + const struct in_addr *dst, u_char *desten, uint32_t *pflags) { struct llentry *la = NULL, *la_tmp; struct mbuf *curr = NULL; @@ -434,11 +434,11 @@ if ((flags & LLE_CREATE) == 0) { IF_AFDATA_RLOCK(ifp); - la = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst); + la = arp_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst); IF_AFDATA_RUNLOCK(ifp); } if (la == NULL && (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) { - la = lltable_alloc_entry(LLTABLE(ifp), 0, dst); + la = arp_alloc(LLTABLE(ifp), 0, dst); if (la == NULL) { log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s on %s\n", @@ -449,7 +449,7 @@ IF_AFDATA_WLOCK(ifp); LLE_WLOCK(la); - la_tmp = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst); + la_tmp = arp_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst); /* Prefer ANY existing lle over newly-created one */ if (la_tmp == NULL) lltable_link_entry(LLTABLE(ifp), la); @@ -522,7 +522,7 @@ if (la->la_asked < V_arp_maxtries) error = EWOULDBLOCK; /* First request. */ else - error = is_gw != 0 ? EHOSTUNREACH : EHOSTDOWN; + error = EHOSTDOWN; if (renew) { int canceled; @@ -535,7 +535,7 @@ LLE_REMREF(la); la->la_asked++; LLE_WUNLOCK(la); - arprequest(ifp, NULL, &SIN(dst)->sin_addr, NULL); + arprequest(ifp, NULL, dst, NULL); return (error); } @@ -550,14 +550,16 @@ arpresolve_addr(struct ifnet *ifp, int flags, const struct sockaddr *dst, char *desten, uint32_t *pflags) { + const struct sockaddr_in *dst4; int error; flags |= LLE_ADDRONLY; - error = arpresolve_full(ifp, 0, flags, NULL, dst, desten, pflags); + dst4 = (const struct sockaddr_in *)dst; + error = arpresolve_full(ifp, flags, NULL, &dst4->sin_addr, desten, + pflags); return (error); } - /* * Lookups link header based on an IP address. * On input: @@ -578,7 +580,8 @@ arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m, const struct sockaddr *dst, u_char *desten, uint32_t *pflags) { - struct llentry *la = 0; + const struct sockaddr_in *dst4; + int error; if (pflags != NULL) *pflags = 0; @@ -597,8 +600,36 @@ } } + dst4 = (const struct sockaddr_in *)dst; + error = in_resolve_lla(ifp, m, &dst4->sin_addr, desten, pflags); + if (error == EHOSTDOWN && is_gw != 0) + error = EHOSTUNREACH; + return (error); +} + +/* + * Lookups link header based on an IP address. + * On input: + * ifp is the interface we use + * m is the mbuf. May be NULL if we don't have a packet. + * dst is the next hop, + * desten is the storage to put LL header. + * flags returns subset of lle flags: LLE_VALID | LLE_IFADDR + * + * On success, full/partial link header and flags are filled in and + * the function returns 0. + * If the packet must be held pending resolution, we return EWOULDBLOCK + * On other errors, we return the corresponding error code. + * Note that m_freem() handles NULL. + */ +int +in_resolve_lla(struct ifnet *ifp, struct mbuf *m, const struct in_addr *dst, + u_char *desten, uint32_t *pflags) +{ + struct llentry *la = 0; + IF_AFDATA_RLOCK(ifp); - la = lla_lookup(LLTABLE(ifp), LLE_UNLOCKED, dst); + la = arp_lookup(LLTABLE(ifp), LLE_UNLOCKED, dst); if (la != NULL && (la->r_flags & RLLE_VALID) != 0) { /* Entry found, let's copy lle info */ bcopy(la->r_linkdata, desten, la->r_hdrlen); @@ -615,7 +646,7 @@ } IF_AFDATA_RUNLOCK(ifp); - return (arpresolve_full(ifp, is_gw, la == NULL ? LLE_CREATE : 0, m, dst, + return (arpresolve_full(ifp, la == NULL ? LLE_CREATE : 0, m, dst, desten, pflags)); } @@ -757,8 +788,6 @@ int op; int bridged = 0, is_bridge = 0; int carped; - struct sockaddr_in sin; - struct sockaddr *dst; struct nhop4_basic nh4; uint8_t linkhdr[LLE_MAX_LINKHDR]; struct route ro; @@ -766,10 +795,6 @@ int lladdr_off; int error; - sin.sin_len = sizeof(struct sockaddr_in); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = 0; - if (ifp->if_bridge) bridged = 1; if (ifp->if_type == IFT_BRIDGE) @@ -919,13 +944,8 @@ if (ifp->if_flags & IFF_STATICARP) goto reply; - bzero(&sin, sizeof(sin)); - sin.sin_len = sizeof(struct sockaddr_in); - sin.sin_family = AF_INET; - sin.sin_addr = isaddr; - dst = (struct sockaddr *)&sin; IF_AFDATA_RLOCK(ifp); - la = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst); + la = arp_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, &isaddr); IF_AFDATA_RUNLOCK(ifp); if (la != NULL) arp_check_update_lle(ah, isaddr, ifp, bridged, la); @@ -940,7 +960,7 @@ goto reply; /* Allocate new entry */ - la = lltable_alloc_entry(LLTABLE(ifp), 0, dst); + la = arp_alloc(LLTABLE(ifp), 0, &isaddr); if (la == NULL) { /* @@ -956,7 +976,7 @@ IF_AFDATA_WLOCK(ifp); LLE_WLOCK(la); - la_tmp = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst); + la_tmp = arp_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, &isaddr); /* * Check if lle still does not exists. @@ -1003,9 +1023,8 @@ } else { struct llentry *lle = NULL; - sin.sin_addr = itaddr; IF_AFDATA_RLOCK(ifp); - lle = lla_lookup(LLTABLE(ifp), 0, (struct sockaddr *)&sin); + lle = arp_lookup(LLTABLE(ifp), 0, &itaddr); IF_AFDATA_RUNLOCK(ifp); if ((lle != NULL) && (lle->la_flags & LLE_PUB)) { @@ -1239,13 +1258,15 @@ arp_add_ifa_lle(struct ifnet *ifp, const struct sockaddr *dst) { struct llentry *lle, *lle_tmp; + struct in_addr in; /* * Interface address LLE record is considered static * because kernel code relies on LLE_STATIC flag to check * if these entries can be rewriten by arp updates. */ - lle = lltable_alloc_entry(LLTABLE(ifp), LLE_IFADDR | LLE_STATIC, dst); + in = ((const struct sockaddr_in *)dst)->sin_addr; + lle = arp_alloc(LLTABLE(ifp), LLE_IFADDR | LLE_STATIC, &in); if (lle == NULL) { log(LOG_INFO, "arp_ifinit: cannot create arp " "entry for interface address\n"); @@ -1255,7 +1276,7 @@ IF_AFDATA_WLOCK(ifp); LLE_WLOCK(lle); /* Unlink any entry if exists */ - lle_tmp = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst); + lle_tmp = arp_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, &in); if (lle_tmp != NULL) lltable_unlink_entry(LLTABLE(ifp), lle_tmp); Index: sys/netinet/in.c =================================================================== --- sys/netinet/in.c +++ sys/netinet/in.c @@ -1104,15 +1104,19 @@ } static int -in_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr *l3addr) +in_lltable_rtcheck(struct ifnet *ifp, u_int flags, struct in_addr l3addr) { struct rt_addrinfo info; - struct sockaddr_in rt_key, rt_mask; + struct sockaddr_in rt_key, rt_mask, sin; struct sockaddr rt_gateway; + struct sockaddr *sa; int rt_flags; - KASSERT(l3addr->sa_family == AF_INET, - ("sin_family %d", l3addr->sa_family)); + bzero(&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_len = sizeof(sin); + sin.sin_addr = l3addr; + sa = (struct sockaddr *)&sin; bzero(&rt_key, sizeof(rt_key)); rt_key.sin_len = sizeof(rt_key); @@ -1126,7 +1130,7 @@ info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&rt_mask; info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&rt_gateway; - if (rib_lookup_info(ifp->if_fib, l3addr, NHR_REF, 0, &info) != 0) + if (rib_lookup_info(ifp->if_fib, sa, NHR_REF, 0, &info) != 0) return (EINVAL); rt_flags = info.rti_flags; @@ -1141,7 +1145,7 @@ if (!(rt_flags & RTF_HOST) || !info.rti_ifp || info.rti_ifp->if_type != IFT_ETHER || (info.rti_ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) != 0 || - memcmp(rt_gateway.sa_data, l3addr->sa_data, + memcmp(rt_gateway.sa_data, sa->sa_data, sizeof(in_addr_t)) != 0) { rib_free_info(&info); return (EINVAL); @@ -1169,15 +1173,15 @@ return (EINVAL); sa = (const char *)&rt_key; - addr = (const char *)l3addr; - len = ((const struct sockaddr_in *)l3addr)->sin_len; + addr = (const char *)&sin; + len = ((const struct sockaddr_in *)&sin)->sin_len; lim = addr + len; for ( ; addr < lim; sa++, mask++, addr++) { if ((*sa ^ *addr) & *mask) { #ifdef DIAGNOSTIC log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n", - inet_ntoa(((const struct sockaddr_in *)l3addr)->sin_addr)); + inet_ntoa(l3addr)); #endif return (EINVAL); } @@ -1245,17 +1249,16 @@ } static struct llentry * -in_lltable_alloc(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) +in_lltable_alloc_entry(struct lltable *llt, u_int flags, const void *l3addr) { - const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr; + struct in_addr in; struct ifnet *ifp = llt->llt_ifp; struct llentry *lle; char linkhdr[LLE_MAX_LINKHDR]; size_t linkhdrsize; int lladdr_off; - KASSERT(l3addr->sa_family == AF_INET, - ("sin_family %d", l3addr->sa_family)); + in = *(const struct in_addr *)l3addr; /* * A route that covers the given address must have @@ -1263,12 +1266,12 @@ * verify this. */ if (!(flags & LLE_IFADDR) && - in_lltable_rtcheck(ifp, flags, l3addr) != 0) + in_lltable_rtcheck(ifp, flags, in) != 0) return (NULL); - lle = in_lltable_new(sin->sin_addr, flags); + lle = in_lltable_new(in, flags); if (lle == NULL) { - log(LOG_INFO, "lla_lookup: new lle malloc failed\n"); + log(LOG_INFO, "%s: new lle malloc failed\n", __FUNCTION__); return (NULL); } lle->la_flags = flags; @@ -1293,15 +1296,13 @@ * If found return lle read locked. */ static struct llentry * -in_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) +in_lltable_lookup_entry(struct lltable *llt, u_int flags, const void *l3addr) { - const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr; + struct in_addr in = *((const struct in_addr *)l3addr); struct llentry *lle; IF_AFDATA_LOCK_ASSERT(llt->llt_ifp); - KASSERT(l3addr->sa_family == AF_INET, - ("sin_family %d", l3addr->sa_family)); - lle = in_lltable_find_dst(llt, sin->sin_addr); + lle = in_lltable_find_dst(llt, in); if (lle == NULL) return (NULL); @@ -1395,8 +1396,8 @@ llt->llt_af = AF_INET; llt->llt_ifp = ifp; - llt->llt_lookup = in_lltable_lookup; - llt->llt_alloc_entry = in_lltable_alloc; + llt->llt_lookup = in_lltable_lookup_entry; + llt->llt_alloc_entry = in_lltable_alloc_entry; llt->llt_delete_entry = in_lltable_delete_entry; llt->llt_dump_entry = in_lltable_dump_entry; llt->llt_hash = in_lltable_hash; Index: sys/netinet6/icmp6.c =================================================================== --- sys/netinet6/icmp6.c +++ sys/netinet6/icmp6.c @@ -2491,7 +2491,6 @@ size_t maxlen; u_char *p; struct ifnet *outif = NULL; - struct sockaddr_in6 src_sa; icmp6_errcount(ND_REDIRECT, 0); @@ -2510,11 +2509,7 @@ * [RFC 2461, sec 8.2] */ sip6 = mtod(m0, struct ip6_hdr *); - bzero(&src_sa, sizeof(src_sa)); - src_sa.sin6_family = AF_INET6; - src_sa.sin6_len = sizeof(src_sa); - src_sa.sin6_addr = sip6->ip6_src; - if (nd6_is_addr_neighbor(&src_sa, ifp) == 0) + if (nd6_is_addr_neighbor(&sip6->ip6_src, ifp) == 0) goto fail; if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst)) goto fail; /* what should we do here? */ Index: sys/netinet6/in6.c =================================================================== --- sys/netinet6/in6.c +++ sys/netinet6/in6.c @@ -2146,22 +2146,18 @@ static int in6_lltable_rtcheck(struct ifnet *ifp, u_int flags, - const struct sockaddr *l3addr) + const struct in6_addr *l3addr) { - const struct sockaddr_in6 *sin6; struct nhop6_basic nh6; struct in6_addr dst; uint32_t scopeid; int error; + struct sockaddr_in6 sin6; char ip6buf[INET6_ADDRSTRLEN]; - KASSERT(l3addr->sa_family == AF_INET6, - ("sin_family %d", l3addr->sa_family)); - /* Our local addresses are always only installed on the default FIB. */ - sin6 = (const struct sockaddr_in6 *)l3addr; - in6_splitscope(&sin6->sin6_addr, &dst, &scopeid); + in6_splitscope(l3addr, &dst, &scopeid); error = fib6_lookup_nh_basic(RT_DEFAULT_FIB, &dst, scopeid, 0, 0, &nh6); if (error != 0 || (nh6.nh_flags & NHF_GATEWAY) || nh6.nh_ifp != ifp) { struct ifaddr *ifa; @@ -2169,13 +2165,18 @@ * Create an ND6 cache for an IPv6 neighbor * that is not covered by our own prefix. */ - ifa = ifaof_ifpforaddr(l3addr, ifp); + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(sin6); + sin6.sin6_addr = *l3addr; + + ifa = ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); if (ifa != NULL) { ifa_free(ifa); return 0; } log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n", - ip6_sprintf(ip6buf, &sin6->sin6_addr)); + ip6_sprintf(ip6buf, l3addr)); return EINVAL; } return 0; @@ -2240,18 +2241,15 @@ static struct llentry * in6_lltable_alloc(struct lltable *llt, u_int flags, - const struct sockaddr *l3addr) + const void *l3addr) { - const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr; + const struct in6_addr *in6 = (const struct in6_addr *)l3addr; struct ifnet *ifp = llt->llt_ifp; struct llentry *lle; char linkhdr[LLE_MAX_LINKHDR]; size_t linkhdrsize; int lladdr_off; - KASSERT(l3addr->sa_family == AF_INET6, - ("sin_family %d", l3addr->sa_family)); - /* * A route that covers the given address must have * been installed 1st because we are doing a resolution, @@ -2261,9 +2259,9 @@ in6_lltable_rtcheck(ifp, flags, l3addr) != 0) return (NULL); - lle = in6_lltable_new(&sin6->sin6_addr, flags); + lle = in6_lltable_new(in6, flags); if (lle == NULL) { - log(LOG_INFO, "lla_lookup: new lle malloc failed\n"); + log(LOG_INFO, "%s: new lle malloc failed\n", __FUNCTION__); return (NULL); } lle->la_flags = flags; @@ -2279,22 +2277,22 @@ if ((lle->la_flags & LLE_STATIC) != 0) lle->ln_state = ND6_LLINFO_REACHABLE; + else + lle->ln_state = ND6_LLINFO_NOSTATE; return (lle); } static struct llentry * in6_lltable_lookup(struct lltable *llt, u_int flags, - const struct sockaddr *l3addr) + const void *l3addr) { - const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr; + const struct in6_addr *in6 = (const struct in6_addr *)l3addr; struct llentry *lle; IF_AFDATA_LOCK_ASSERT(llt->llt_ifp); - KASSERT(l3addr->sa_family == AF_INET6, - ("sin_family %d", l3addr->sa_family)); - lle = in6_lltable_find_dst(llt, &sin6->sin6_addr); + lle = in6_lltable_find_dst(llt, in6); if (lle == NULL) return (NULL); Index: sys/netinet6/nd6.h =================================================================== --- sys/netinet6/nd6.h +++ sys/netinet6/nd6.h @@ -400,12 +400,10 @@ #endif struct nd_ifinfo *nd6_ifattach(struct ifnet *); void nd6_ifdetach(struct nd_ifinfo *); -int nd6_is_addr_neighbor(const struct sockaddr_in6 *, struct ifnet *); +int nd6_is_addr_neighbor(const struct in6_addr *, struct ifnet *); void nd6_option_init(void *, int, union nd_opts *); struct nd_opt_hdr *nd6_option(union nd_opts *); int nd6_options(union nd_opts *); -struct llentry *nd6_lookup(const struct in6_addr *, int, struct ifnet *); -struct llentry *nd6_alloc(const struct in6_addr *, int, struct ifnet *); void nd6_setmtu(struct ifnet *); void nd6_llinfo_setstate(struct llentry *lle, int newstate); void nd6_timer(void *); @@ -414,6 +412,8 @@ char *desten, uint32_t *pflags); int nd6_resolve(struct ifnet *, int, struct mbuf *, const struct sockaddr *, u_char *, uint32_t *); +int in6_resolve_lla(struct ifnet *, struct mbuf *, const struct in6_addr *, + u_char *, uint32_t *); int nd6_ioctl(u_long, caddr_t, struct ifnet *); void nd6_cache_lladdr(struct ifnet *, struct in6_addr *, char *, int, int, int); @@ -426,6 +426,17 @@ int nd6_output_ifp(struct ifnet *, struct ifnet *, struct mbuf *, struct sockaddr_in6 *, struct route *); +static inline const void * +_check_in6_addr_type(const struct in6_addr *paddr) +{ + + return ((const void *)paddr); +} +#define nd6_lookup(a, f, i) \ + lla_lookup(LLTABLE6(i), f, _check_in6_addr_type(a)) +#define nd6_alloc(a, f, i) \ + lltable_alloc_entry(LLTABLE6(i), f, _check_in6_addr_type(a)) + /* nd6_nbr.c */ void nd6_na_input(struct mbuf *, int, int); void nd6_na_output(struct ifnet *, const struct in6_addr *, Index: sys/netinet6/nd6.c =================================================================== --- sys/netinet6/nd6.c +++ sys/netinet6/nd6.c @@ -126,8 +126,7 @@ int (*send_sendso_input_hook)(struct mbuf *, struct ifnet *, int, int); -static int nd6_is_new_addr_neighbor(const struct sockaddr_in6 *, - struct ifnet *); +static int nd6_is_new_addr_neighbor(const struct in6_addr *, struct ifnet *); static void nd6_setmtu0(struct ifnet *, struct nd_ifinfo *); static void nd6_slowtimo(void *); static int regen_tmpaddr(struct in6_ifaddr *); @@ -138,7 +137,7 @@ 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 in6_addr *, u_char *, uint32_t *); static int nd6_need_cache(struct ifnet *); @@ -1160,53 +1159,13 @@ */ } -/* - * the caller acquires and releases the lock on the lltbls - * Returns the llentry locked - */ -struct llentry * -nd6_lookup(const struct in6_addr *addr6, int flags, struct ifnet *ifp) -{ - struct sockaddr_in6 sin6; - struct llentry *ln; - - bzero(&sin6, sizeof(sin6)); - sin6.sin6_len = sizeof(struct sockaddr_in6); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = *addr6; - - IF_AFDATA_LOCK_ASSERT(ifp); - - ln = lla_lookup(LLTABLE6(ifp), flags, (struct sockaddr *)&sin6); - - return (ln); -} - -struct llentry * -nd6_alloc(const struct in6_addr *addr6, int flags, struct ifnet *ifp) -{ - struct sockaddr_in6 sin6; - struct llentry *ln; - - bzero(&sin6, sizeof(sin6)); - sin6.sin6_len = sizeof(struct sockaddr_in6); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = *addr6; - - ln = lltable_alloc_entry(LLTABLE6(ifp), 0, (struct sockaddr *)&sin6); - if (ln != NULL) - ln->ln_state = ND6_LLINFO_NOSTATE; - - return (ln); -} - /* * Test whether a given IPv6 address is a neighbor or not, ignoring * the actual neighbor cache. The neighbor cache is ignored in order * to not reenter the routing code from within itself. */ static int -nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) +nd6_is_new_addr_neighbor(const struct in6_addr *addr, struct ifnet *ifp) { struct nd_prefix *pr; struct ifaddr *dstaddr; @@ -1214,12 +1173,18 @@ struct sockaddr_in6 rt_key; struct sockaddr *dst6; int fibnum; + struct sockaddr_in6 sin6; + + bzero(&sin6, sizeof(sin6)); + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_family = AF_INET6; + sin6.sin6_addr = *addr; /* * A link-local address is always a neighbor. * XXX: a link does not necessarily specify a single interface. */ - if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { + if (IN6_IS_ADDR_LINKLOCAL(addr)) { struct sockaddr_in6 sin6_copy; u_int32_t zone; @@ -1227,7 +1192,7 @@ * We need sin6_copy since sa6_recoverscope() may modify the * content (XXX). */ - sin6_copy = *addr; + sin6_copy = sin6; if (sa6_recoverscope(&sin6_copy)) return (0); /* XXX: should be impossible */ if (in6_setscope(&sin6_copy.sin6_addr, ifp, &zone)) @@ -1280,7 +1245,7 @@ } if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, - &addr->sin6_addr, &pr->ndpr_mask)) + addr, &pr->ndpr_mask)) return (1); } @@ -1288,7 +1253,7 @@ * If the address is assigned on the node of the other side of * a p2p interface, the address should be a neighbor. */ - dstaddr = ifa_ifwithdstaddr((const struct sockaddr *)addr, RT_ALL_FIBS); + dstaddr = ifa_ifwithdstaddr((const struct sockaddr *)&sin6, RT_ALL_FIBS); if (dstaddr != NULL) { if (dstaddr->ifa_ifp == ifp) { ifa_free(dstaddr); @@ -1316,7 +1281,7 @@ * XXX: should take care of the destination of a p2p link? */ int -nd6_is_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) +nd6_is_addr_neighbor(const struct in6_addr *addr, struct ifnet *ifp) { struct llentry *lle; int rc = 0; @@ -1330,7 +1295,7 @@ * in the neighbor cache. */ IF_AFDATA_RLOCK(ifp); - if ((lle = nd6_lookup(&addr->sin6_addr, 0, ifp)) != NULL) { + if ((lle = nd6_lookup(addr, 0, ifp)) != NULL) { LLE_RUNLOCK(lle); rc = 1; } @@ -2149,8 +2114,8 @@ nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m, const struct sockaddr *sa_dst, u_char *desten, uint32_t *pflags) { - struct llentry *ln = NULL; const struct sockaddr_in6 *dst6; + int error; if (pflags != NULL) *pflags = 0; @@ -2180,8 +2145,33 @@ } } + error = in6_resolve_lla(ifp, m, &dst6->sin6_addr, desten, pflags); + if (error == EHOSTDOWN && is_gw != 0) + error = EHOSTUNREACH; + return (error); +} + +/* + * Lookup link headerfor @sa_dst address. Stores found + * data in @desten buffer. Copy of lle ln_flags can be also + * saved in @pflags if @pflags is non-NULL. + * + * If destination LLE does not exists or lle state modification + * is required, call "slow" version. + * + * Return values: + * - 0 on success (address copied to buffer). + * - EWOULDBLOCK (no local error, but address is still unresolved) + * - other errors (alloc failure, etc) + */ +int +in6_resolve_lla(struct ifnet *ifp, struct mbuf *m, const struct in6_addr *dst, + u_char *desten, uint32_t *pflags) +{ + struct llentry *ln = NULL; + IF_AFDATA_RLOCK(ifp); - ln = nd6_lookup(&dst6->sin6_addr, LLE_UNLOCKED, ifp); + ln = nd6_lookup(dst, LLE_UNLOCKED, ifp); if (ln != NULL && (ln->r_flags & RLLE_VALID) != 0) { /* Entry found, let's copy lle info */ bcopy(ln->r_linkdata, desten, ln->r_hdrlen); @@ -2199,7 +2189,7 @@ } IF_AFDATA_RUNLOCK(ifp); - return (nd6_resolve_slow(ifp, 0, m, dst6, desten, pflags)); + return (nd6_resolve_slow(ifp, 0, m, dst, desten, pflags)); } @@ -2216,7 +2206,7 @@ */ 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 in6_addr *dst, u_char *desten, uint32_t *pflags) { struct llentry *lle = NULL, *lle_tmp; struct in6_addr *psrc, src; @@ -2231,7 +2221,7 @@ */ if (lle == NULL) { IF_AFDATA_RLOCK(ifp); - lle = nd6_lookup(&dst->sin6_addr, LLE_EXCLUSIVE, ifp); + lle = nd6_lookup(dst, LLE_EXCLUSIVE, ifp); IF_AFDATA_RUNLOCK(ifp); if ((lle == NULL) && nd6_is_addr_neighbor(dst, ifp)) { /* @@ -2239,13 +2229,13 @@ * the condition below is not very efficient. But we believe * it is tolerable, because this should be a rare case. */ - lle = nd6_alloc(&dst->sin6_addr, 0, ifp); + lle = nd6_alloc(dst, 0, ifp); if (lle == NULL) { char ip6buf[INET6_ADDRSTRLEN]; log(LOG_DEBUG, "nd6_output: can't allocate llinfo for %s " "(ln=%p)\n", - ip6_sprintf(ip6buf, &dst->sin6_addr), lle); + ip6_sprintf(ip6buf, dst), lle); m_freem(m); return (ENOBUFS); } @@ -2253,7 +2243,7 @@ IF_AFDATA_WLOCK(ifp); LLE_WLOCK(lle); /* Prefer any existing entry over newly-created one */ - lle_tmp = nd6_lookup(&dst->sin6_addr, LLE_EXCLUSIVE, ifp); + lle_tmp = nd6_lookup(dst, LLE_EXCLUSIVE, ifp); if (lle_tmp == NULL) lltable_link_entry(LLTABLE6(ifp), lle); IF_AFDATA_WUNLOCK(ifp); @@ -2355,7 +2345,7 @@ } LLE_WUNLOCK(lle); if (send_ns != 0) - nd6_ns_output(ifp, psrc, NULL, &dst->sin6_addr, NULL); + nd6_ns_output(ifp, psrc, NULL, dst, NULL); return (EWOULDBLOCK); } @@ -2375,10 +2365,12 @@ char *desten, uint32_t *pflags) { int error; + const struct sockaddr_in6 *dst6; flags |= LLE_ADDRONLY; - error = nd6_resolve_slow(ifp, flags, NULL, - (const struct sockaddr_in6 *)dst, desten, pflags); + dst6 = (const struct sockaddr_in6 *)dst; + error = nd6_resolve_slow(ifp, flags, NULL, &dst6->sin6_addr, + desten, pflags); return (error); } @@ -2451,22 +2443,20 @@ { struct ifnet *ifp; struct llentry *ln, *ln_tmp; - struct sockaddr *dst; ifp = ia->ia_ifa.ifa_ifp; if (nd6_need_cache(ifp) == 0) return (0); ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; - dst = (struct sockaddr *)&ia->ia_addr; - ln = lltable_alloc_entry(LLTABLE6(ifp), LLE_IFADDR, dst); + ln = nd6_alloc(&ia->ia_addr.sin6_addr, LLE_IFADDR, ifp); if (ln == NULL) return (ENOBUFS); IF_AFDATA_WLOCK(ifp); LLE_WLOCK(ln); /* Unlink any entry if exists */ - ln_tmp = lla_lookup(LLTABLE6(ifp), LLE_EXCLUSIVE, dst); + ln_tmp = nd6_lookup(&ia->ia_addr.sin6_addr, LLE_EXCLUSIVE, ifp); if (ln_tmp != NULL) lltable_unlink_entry(LLTABLE6(ifp), ln_tmp); lltable_link_entry(LLTABLE6(ifp), ln); Index: sys/netinet6/nd6_nbr.c =================================================================== --- sys/netinet6/nd6_nbr.c +++ sys/netinet6/nd6_nbr.c @@ -175,7 +175,6 @@ goto bad; } } else if (!V_nd6_onlink_ns_rfc4861) { - struct sockaddr_in6 src_sa6; /* * According to recent IETF discussions, it is not a good idea @@ -183,11 +182,7 @@ * to be a neighbor otherwise. This point is expected to be * clarified in future revisions of the specification. */ - bzero(&src_sa6, sizeof(src_sa6)); - src_sa6.sin6_family = AF_INET6; - src_sa6.sin6_len = sizeof(src_sa6); - src_sa6.sin6_addr = saddr6; - if (nd6_is_addr_neighbor(&src_sa6, ifp) == 0) { + if (nd6_is_addr_neighbor(&saddr6, ifp) == 0) { nd6log((LOG_INFO, "nd6_ns_input: " "NS packet from non-neighbor\n")); goto bad;