Do not pass lle to nd6_ns_output(). Use newly-added
nd6_llinfo_get_holdsrc() to extract desired IPv6 source from holdchain and pass it to the nd6_ns_output().
This commit is contained in:
parent
7a82f35c9d
commit
26deb8826c
@ -482,7 +482,7 @@ restart:
|
||||
(long)ND_IFINFO(ifp)->retrans * hz / 1000);
|
||||
LLE_WUNLOCK(lle);
|
||||
|
||||
nd6_ns_output(ifp, NULL, &sin6->sin6_addr, NULL, 0);
|
||||
nd6_ns_output(ifp, NULL, NULL, &sin6->sin6_addr, 0);
|
||||
|
||||
return (EWOULDBLOCK);
|
||||
} else {
|
||||
|
@ -510,6 +510,34 @@ nd6_llinfo_settimer_locked(struct llentry *ln, long tick)
|
||||
LLE_REMREF(ln);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets source address of the first packet in hold queue
|
||||
* and stores it in @src.
|
||||
* Returns pointer to @src (if hold queue is not empty) or NULL.
|
||||
*
|
||||
*/
|
||||
static struct in6_addr *
|
||||
nd6_llinfo_get_holdsrc(struct llentry *ln, struct in6_addr *src)
|
||||
{
|
||||
struct ip6_hdr hdr;
|
||||
struct mbuf *m;
|
||||
|
||||
if (ln->la_hold == NULL)
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* assume every packet in la_hold has the same IP header
|
||||
*/
|
||||
m = ln->la_hold;
|
||||
if (sizeof(hdr) < m->m_len)
|
||||
return (NULL);
|
||||
|
||||
m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr);
|
||||
*src = hdr.ip6_src;
|
||||
|
||||
return (src);
|
||||
}
|
||||
|
||||
void
|
||||
nd6_llinfo_settimer(struct llentry *ln, long tick)
|
||||
{
|
||||
@ -523,9 +551,10 @@ static void
|
||||
nd6_llinfo_timer(void *arg)
|
||||
{
|
||||
struct llentry *ln;
|
||||
struct in6_addr *dst;
|
||||
struct in6_addr *dst, *pdst, *psrc, src;
|
||||
struct ifnet *ifp;
|
||||
struct nd_ifinfo *ndi = NULL;
|
||||
int send_ns;
|
||||
|
||||
KASSERT(arg != NULL, ("%s: arg NULL", __func__));
|
||||
ln = (struct llentry *)arg;
|
||||
@ -552,6 +581,10 @@ nd6_llinfo_timer(void *arg)
|
||||
}
|
||||
ifp = ln->lle_tbl->llt_ifp;
|
||||
CURVNET_SET(ifp->if_vnet);
|
||||
ndi = ND_IFINFO(ifp);
|
||||
send_ns = 0;
|
||||
dst = &ln->r_l3addr.addr6;
|
||||
pdst = dst;
|
||||
|
||||
if (ln->ln_ntick > 0) {
|
||||
if (ln->ln_ntick > INT_MAX) {
|
||||
@ -564,8 +597,6 @@ nd6_llinfo_timer(void *arg)
|
||||
goto done;
|
||||
}
|
||||
|
||||
ndi = ND_IFINFO(ifp);
|
||||
dst = &ln->r_l3addr.addr6;
|
||||
if (ln->la_flags & LLE_STATIC) {
|
||||
goto done;
|
||||
}
|
||||
@ -580,10 +611,9 @@ nd6_llinfo_timer(void *arg)
|
||||
case ND6_LLINFO_INCOMPLETE:
|
||||
if (ln->la_asked < V_nd6_mmaxtries) {
|
||||
ln->la_asked++;
|
||||
nd6_llinfo_settimer_locked(ln, (long)ndi->retrans * hz / 1000);
|
||||
LLE_WUNLOCK(ln);
|
||||
nd6_ns_output(ifp, NULL, dst, ln, NULL);
|
||||
LLE_WLOCK(ln);
|
||||
send_ns = 1;
|
||||
/* Send NS to multicast address */
|
||||
pdst = NULL;
|
||||
} else {
|
||||
struct mbuf *m = ln->la_hold;
|
||||
if (m) {
|
||||
@ -627,10 +657,7 @@ nd6_llinfo_timer(void *arg)
|
||||
/* We need NUD */
|
||||
ln->la_asked = 1;
|
||||
ln->ln_state = ND6_LLINFO_PROBE;
|
||||
nd6_llinfo_settimer_locked(ln, (long)ndi->retrans * hz / 1000);
|
||||
LLE_WUNLOCK(ln);
|
||||
nd6_ns_output(ifp, dst, dst, ln, NULL);
|
||||
LLE_WLOCK(ln);
|
||||
send_ns = 1;
|
||||
} else {
|
||||
ln->ln_state = ND6_LLINFO_STALE; /* XXX */
|
||||
nd6_llinfo_settimer_locked(ln, (long)V_nd6_gctimer * hz);
|
||||
@ -639,10 +666,7 @@ nd6_llinfo_timer(void *arg)
|
||||
case ND6_LLINFO_PROBE:
|
||||
if (ln->la_asked < V_nd6_umaxtries) {
|
||||
ln->la_asked++;
|
||||
nd6_llinfo_settimer_locked(ln, (long)ndi->retrans * hz / 1000);
|
||||
LLE_WUNLOCK(ln);
|
||||
nd6_ns_output(ifp, dst, dst, ln, NULL);
|
||||
LLE_WLOCK(ln);
|
||||
send_ns = 1;
|
||||
} else {
|
||||
EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_EXPIRED);
|
||||
(void)nd6_free(ln, 0);
|
||||
@ -654,6 +678,14 @@ nd6_llinfo_timer(void *arg)
|
||||
__func__, ln->ln_state);
|
||||
}
|
||||
done:
|
||||
if (send_ns != 0) {
|
||||
nd6_llinfo_settimer_locked(ln, (long)ndi->retrans * hz / 1000);
|
||||
psrc = nd6_llinfo_get_holdsrc(ln, &src);
|
||||
LLE_FREE_LOCKED(ln);
|
||||
ln = NULL;
|
||||
nd6_ns_output(ifp, psrc, pdst, dst, NULL);
|
||||
}
|
||||
|
||||
if (ln != NULL)
|
||||
LLE_FREE_LOCKED(ln);
|
||||
CURVNET_RESTORE();
|
||||
@ -2170,12 +2202,14 @@ nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
|
||||
* INCOMPLETE state, send the first solicitation.
|
||||
*/
|
||||
if (!ND6_LLINFO_PERMANENT(lle) && lle->la_asked == 0) {
|
||||
struct in6_addr src, *psrc;
|
||||
lle->la_asked++;
|
||||
|
||||
nd6_llinfo_settimer_locked(lle,
|
||||
(long)ND_IFINFO(ifp)->retrans * hz / 1000);
|
||||
psrc = nd6_llinfo_get_holdsrc(lle, &src);
|
||||
LLE_WUNLOCK(lle);
|
||||
nd6_ns_output(ifp, NULL, &dst->sin6_addr, lle, NULL);
|
||||
nd6_ns_output(ifp, psrc, NULL, &dst->sin6_addr, NULL);
|
||||
} else {
|
||||
/* We did the lookup so we need to do the unlock here. */
|
||||
LLE_WUNLOCK(lle);
|
||||
|
@ -437,7 +437,7 @@ void nd6_na_output(struct ifnet *, const struct in6_addr *,
|
||||
const struct in6_addr *, u_long, int, struct sockaddr *);
|
||||
void nd6_ns_input(struct mbuf *, int, int);
|
||||
void nd6_ns_output(struct ifnet *, const struct in6_addr *,
|
||||
const struct in6_addr *, struct llentry *, uint8_t *);
|
||||
const struct in6_addr *, const struct in6_addr *, uint8_t *);
|
||||
caddr_t nd6_ifptomac(struct ifnet *);
|
||||
void nd6_dad_init(void);
|
||||
void nd6_dad_start(struct ifaddr *, int);
|
||||
|
@ -95,7 +95,7 @@ static void nd6_dad_na_input(struct ifaddr *);
|
||||
static void nd6_na_output_fib(struct ifnet *, const struct in6_addr *,
|
||||
const struct in6_addr *, u_long, int, struct sockaddr *, u_int);
|
||||
static void nd6_ns_output_fib(struct ifnet *, const struct in6_addr *,
|
||||
const struct in6_addr *, struct llentry *, uint8_t *, u_int);
|
||||
const struct in6_addr *, const struct in6_addr *, uint8_t *, u_int);
|
||||
|
||||
static VNET_DEFINE(int, dad_enhanced) = 1;
|
||||
#define V_dad_enhanced VNET(dad_enhanced)
|
||||
@ -396,9 +396,9 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
|
||||
* the value (length is ND_OPT_NONCE_LEN) is used as a random nonce.
|
||||
*/
|
||||
static void
|
||||
nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6,
|
||||
const struct in6_addr *taddr6, struct llentry *ln, uint8_t *nonce,
|
||||
u_int fibnum)
|
||||
nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6,
|
||||
const struct in6_addr *daddr6, const struct in6_addr *taddr6,
|
||||
uint8_t *nonce, u_int fibnum)
|
||||
{
|
||||
struct mbuf *m;
|
||||
struct m_tag *mtag;
|
||||
@ -462,7 +462,7 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6,
|
||||
goto bad;
|
||||
}
|
||||
if (nonce == NULL) {
|
||||
struct ifaddr *ifa;
|
||||
struct ifaddr *ifa = NULL;
|
||||
|
||||
/*
|
||||
* RFC2461 7.2.2:
|
||||
@ -474,35 +474,15 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6,
|
||||
* interface should be used."
|
||||
*
|
||||
* We use the source address for the prompting packet
|
||||
* (saddr6), if:
|
||||
* - saddr6 is given from the caller (by giving "ln"), and
|
||||
* - saddr6 belongs to the outgoing interface.
|
||||
* (saddr6), if saddr6 belongs to the outgoing interface.
|
||||
* Otherwise, we perform the source address selection as usual.
|
||||
*/
|
||||
struct in6_addr *hsrc;
|
||||
|
||||
hsrc = NULL;
|
||||
if (ln != NULL) {
|
||||
LLE_RLOCK(ln);
|
||||
if (ln->la_hold != NULL) {
|
||||
struct ip6_hdr *hip6; /* hold ip6 */
|
||||
|
||||
/*
|
||||
* assuming every packet in la_hold has the same IP
|
||||
* header
|
||||
*/
|
||||
hip6 = mtod(ln->la_hold, struct ip6_hdr *);
|
||||
/* XXX pullup? */
|
||||
if (sizeof(*hip6) < ln->la_hold->m_len) {
|
||||
ip6->ip6_src = hip6->ip6_src;
|
||||
hsrc = &hip6->ip6_src;
|
||||
}
|
||||
}
|
||||
LLE_RUNLOCK(ln);
|
||||
}
|
||||
if (hsrc && (ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp,
|
||||
hsrc)) != NULL) {
|
||||
if (saddr6 != NULL)
|
||||
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, saddr6);
|
||||
if (ifa != NULL) {
|
||||
/* ip6_src set already. */
|
||||
ip6->ip6_src = *saddr6;
|
||||
ifa_free(ifa);
|
||||
} else {
|
||||
int error;
|
||||
@ -626,11 +606,11 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6,
|
||||
|
||||
#ifndef BURN_BRIDGES
|
||||
void
|
||||
nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
|
||||
const struct in6_addr *taddr6, struct llentry *ln, uint8_t *nonce)
|
||||
nd6_ns_output(struct ifnet *ifp, const struct in6_addr *saddr6,
|
||||
const struct in6_addr *daddr6, const struct in6_addr *taddr6,uint8_t *nonce)
|
||||
{
|
||||
|
||||
nd6_ns_output_fib(ifp, daddr6, taddr6, ln, nonce, RT_DEFAULT_FIB);
|
||||
nd6_ns_output_fib(ifp, saddr6, daddr6, taddr6, nonce, RT_DEFAULT_FIB);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
@ -1581,7 +1561,7 @@ nd6_dad_ns_output(struct dadq *dp, struct ifaddr *ifa)
|
||||
* should work well in almost all cases.
|
||||
*/
|
||||
}
|
||||
nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL,
|
||||
nd6_ns_output(ifp, NULL, NULL, &ia->ia_addr.sin6_addr,
|
||||
(uint8_t *)&dp->dad_nonce[0]);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user