processing of router advertisements was already in the kernel.
With this rtsol{,d}(8) is no longer necessary.
The kernel starts sending solicitations with
# ifconfig $IF inet6 autoconf
or
inet6 autoconf
in /etc/hostname.$IF.
input stsp@
much help & OK mpi@
tweaks & OK bluhm@
-/* $OpenBSD: if.c,v 1.299 2014/08/14 11:38:14 mikeb Exp $ */
+/* $OpenBSD: if.c,v 1.300 2014/08/25 14:00:34 florian Exp $ */
/* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */
/*
splx(s);
}
}
+
+ if (ifr->ifr_flags & IFXF_AUTOCONF6)
+ nd6_rs_output_set_timo(ND6_RS_OUTPUT_QUICK_INTERVAL);
+
+ if ((ifr->ifr_flags & IFXF_AUTOCONF6) &&
+ !(ifp->if_xflags & IFXF_AUTOCONF6)) {
+ nd6_rs_timeout_count++;
+ RS_LHCOOKIE(ifp) = hook_establish(
+ ifp->if_linkstatehooks, 1, nd6_rs_dev_state, ifp);
+ if (!timeout_pending(&nd6_rs_output_timer))
+ nd6_rs_output_set_timo(nd6_rs_output_timeout);
+ }
+ if ((ifp->if_xflags & IFXF_AUTOCONF6) &&
+ !(ifr->ifr_flags & IFXF_AUTOCONF6)) {
+ hook_disestablish(ifp->if_linkstatehooks,
+ RS_LHCOOKIE(ifp));
+ nd6_rs_timeout_count--;
+ if (nd6_rs_timeout_count == 0)
+ timeout_del(&nd6_rs_output_timer);
+ }
#endif
#ifdef MPLS
-/* $OpenBSD: in6.c,v 1.138 2014/07/12 18:44:23 tedu Exp $ */
+/* $OpenBSD: in6.c,v 1.139 2014/08/25 14:00:34 florian Exp $ */
/* $KAME: in6.c,v 1.372 2004/06/14 08:14:21 itojun Exp $ */
/*
if (ia6->ia6_flags & IN6_IFF_TENTATIVE)
nd6_dad_start(ifa, &dad_delay);
}
+
+ if (ifp->if_xflags & IFXF_AUTOCONF6)
+ nd6_rs_output_set_timo(ND6_RS_OUTPUT_QUICK_INTERVAL);
}
int
-/* $OpenBSD: in6_ifattach.c,v 1.72 2014/07/01 19:37:07 benno Exp $ */
+/* $OpenBSD: in6_ifattach.c,v 1.73 2014/08/25 14:00:34 florian Exp $ */
/* $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei Exp $ */
/*
ifp->if_rdomain);
rtfree(rt);
}
+
+ if (ifp->if_xflags & IFXF_AUTOCONF6) {
+ nd6_rs_timeout_count--;
+ if (nd6_rs_timeout_count == 0)
+ timeout_del(&nd6_rs_output_timer);
+ if (RS_LHCOOKIE(ifp) != NULL)
+ hook_disestablish(ifp->if_linkstatehooks,
+ RS_LHCOOKIE(ifp));
+ }
}
-/* $OpenBSD: in6_var.h,v 1.49 2014/04/03 08:22:10 mpi Exp $ */
+/* $OpenBSD: in6_var.h,v 1.50 2014/08/25 14:00:34 florian Exp $ */
/* $KAME: in6_var.h,v 1.55 2001/02/16 12:49:45 itojun Exp $ */
/*
struct in6_ifstat *in6_ifstat;
struct icmp6_ifstat *icmp6_ifstat;
struct nd_ifinfo *nd_ifinfo;
+ void *rs_lhcookie;
int nprefixes;
int ndefrouters;
};
-/* $OpenBSD: nd6.c,v 1.121 2014/08/11 13:51:07 mpi Exp $ */
+/* $OpenBSD: nd6.c,v 1.122 2014/08/25 14:00:34 florian Exp $ */
/* $KAME: nd6.c,v 1.280 2002/06/08 19:52:07 itojun Exp $ */
/*
struct task nd6_timer_task;
void nd6_timer_work(void *, void *);
+struct timeout nd6_rs_output_timer;
+int nd6_rs_output_timeout = ND6_RS_OUTPUT_INTERVAL;
+int nd6_rs_timeout_count = 0;
+void nd6_rs_output_timo(void *);
+
int fill_drlist(void *, size_t *, size_t);
int fill_prlist(void *, size_t *, size_t);
/* start timer */
timeout_set(&nd6_slowtimo_ch, nd6_slowtimo, NULL);
timeout_add_sec(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL);
+
+ timeout_set(&nd6_rs_output_timer, nd6_rs_output_timo, NULL);
}
struct nd_ifinfo *
splx(s);
}
+void
+nd6_rs_output_set_timo(int timeout)
+{
+ nd6_rs_output_timeout = timeout;
+ timeout_add_sec(&nd6_rs_output_timer, nd6_rs_output_timeout);
+}
+
+void
+nd6_rs_output_timo(void *ignored_arg)
+{
+ struct ifnet *ifp;
+ struct in6_ifaddr *ia6;
+
+ if (nd6_rs_timeout_count == 0)
+ return;
+
+ if (nd6_rs_output_timeout < ND6_RS_OUTPUT_INTERVAL)
+ /* exponential backoff if running quick timeouts */
+ nd6_rs_output_timeout *= 2;
+ if (nd6_rs_output_timeout > ND6_RS_OUTPUT_INTERVAL)
+ nd6_rs_output_timeout = ND6_RS_OUTPUT_INTERVAL;
+
+ TAILQ_FOREACH(ifp, &ifnet, if_list) {
+ if (ISSET(ifp->if_flags, IFF_RUNNING) &&
+ ISSET(ifp->if_xflags, IFXF_AUTOCONF6)) {
+ ia6 = in6ifa_ifpforlinklocal(ifp, IN6_IFF_TENTATIVE);
+ if (ia6 != NULL)
+ nd6_rs_output(ifp, ia6);
+ }
+ }
+ timeout_add_sec(&nd6_rs_output_timer, nd6_rs_output_timeout);
+}
+
#define senderr(e) { error = (e); goto bad;}
int
nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0,
-/* $OpenBSD: nd6.h,v 1.38 2014/07/11 15:03:17 blambert Exp $ */
+/* $OpenBSD: nd6.h,v 1.39 2014/08/25 14:00:34 florian Exp $ */
/* $KAME: nd6.h,v 1.95 2002/06/08 11:31:06 itojun Exp $ */
/*
#define ND_IFINFO(ifp) \
(((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->nd_ifinfo)
+#define RS_LHCOOKIE(ifp) \
+ ((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->rs_lhcookie
+
#define IN6_LINKMTU(ifp) \
((ND_IFINFO(ifp)->linkmtu && ND_IFINFO(ifp)->linkmtu < (ifp)->if_mtu) \
? ND_IFINFO(ifp)->linkmtu \
extern struct timeout nd6_timer_ch;
+#define ND6_RS_OUTPUT_INTERVAL 60
+#define ND6_RS_OUTPUT_QUICK_INTERVAL 1
+extern struct timeout nd6_rs_output_timer;
+extern int nd6_rs_output_timeout;
+extern int nd6_rs_timeout_count;
+
union nd_opts {
struct nd_opt_hdr *nd_opt_array[9];
struct {
void nd6_rs_input(struct mbuf *, int, int);
void nd6_ra_input(struct mbuf *, int, int);
+void nd6_rs_output_set_timo(int);
+void nd6_rs_output(struct ifnet *, struct in6_ifaddr *);
+void nd6_rs_dev_state(void *);
void prelist_del(struct nd_prefix *);
void defrouter_addreq(struct nd_defrouter *);
void defrouter_reset(void);
-/* $OpenBSD: nd6_rtr.c,v 1.83 2014/07/12 18:44:23 tedu Exp $ */
+/* $OpenBSD: nd6_rtr.c,v 1.84 2014/08/25 14:00:34 florian Exp $ */
/* $KAME: nd6_rtr.c,v 1.97 2001/02/07 11:09:13 itojun Exp $ */
/*
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/timeout.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
m_freem(m);
}
+void
+nd6_rs_output(struct ifnet* ifp, struct in6_ifaddr *ia6)
+{
+ struct mbuf *m;
+ struct ip6_hdr *ip6;
+ struct nd_router_solicit *rs;
+ struct ip6_moptions im6o;
+ caddr_t mac;
+ int icmp6len, maxlen, s;
+
+ KASSERT(ia6 != NULL);
+ KASSERT(ifp->if_flags & IFF_RUNNING);
+ KASSERT(ifp->if_xflags & IFXF_AUTOCONF6);
+ KASSERT(!(ia6->ia6_flags & IN6_IFF_TENTATIVE));
+
+ maxlen = sizeof(*ip6) + sizeof(*rs);
+ maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m && max_linkhdr + maxlen >= MHLEN) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_free(m);
+ m = NULL;
+ }
+ }
+ if (m == NULL)
+ return;
+
+ m->m_pkthdr.rcvif = NULL;
+ m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
+ m->m_flags |= M_MCAST;
+ m->m_pkthdr.csum_flags |= M_ICMP_CSUM_OUT;
+
+ im6o.im6o_multicast_ifp = ifp;
+ im6o.im6o_multicast_hlim = 255;
+ im6o.im6o_multicast_loop = 0;
+
+ icmp6len = sizeof(*rs);
+ m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len;
+ m->m_data += max_linkhdr; /* or MH_ALIGN() equivalent? */
+
+ /* fill neighbor solicitation packet */
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6->ip6_flow = 0;
+ ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
+ ip6->ip6_vfc |= IPV6_VERSION;
+ /* ip6->ip6_plen will be set later */
+ ip6->ip6_nxt = IPPROTO_ICMPV6;
+ ip6->ip6_hlim = 255;
+ bzero(&ip6->ip6_dst, sizeof(struct in6_addr));
+
+ ip6->ip6_dst.s6_addr16[0] = htons(0xff02);
+ ip6->ip6_dst.s6_addr8[15] = 0x02;
+
+ ip6->ip6_src = ia6->ia_addr.sin6_addr;
+
+ rs = (struct nd_router_solicit *)(ip6 + 1);
+ rs->nd_rs_type = ND_ROUTER_SOLICIT;
+ rs->nd_rs_code = 0;
+ rs->nd_rs_cksum = 0;
+ rs->nd_rs_reserved = 0;
+
+ if ((mac = nd6_ifptomac(ifp))) {
+ int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
+ struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(rs + 1);
+ /* 8 byte alignments... */
+ optlen = (optlen + 7) & ~7;
+
+ m->m_pkthdr.len += optlen;
+ m->m_len += optlen;
+ icmp6len += optlen;
+ bzero((caddr_t)nd_opt, optlen);
+ nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
+ nd_opt->nd_opt_len = optlen >> 3;
+ bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen);
+ }
+
+ ip6->ip6_plen = htons((u_short)icmp6len);
+
+ s = splsoftnet();
+ ip6_output(m, NULL, NULL, 0, &im6o, NULL, NULL);
+ splx(s);
+
+ icmp6_ifstat_inc(ifp, ifs6_out_msg);
+ icmp6_ifstat_inc(ifp, ifs6_out_routersolicit);
+ icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT]++;
+}
+
+void
+nd6_rs_dev_state(void *arg)
+{
+ struct ifnet *ifp;
+
+ ifp = (struct ifnet *) arg;
+
+ if (LINK_STATE_IS_UP(ifp->if_link_state) &&
+ ifp->if_flags & IFF_RUNNING)
+ /* start quick timer, will exponentially back off */
+ nd6_rs_output_set_timo(ND6_RS_OUTPUT_QUICK_INTERVAL);
+}
+
/*
* Receive Router Advertisement Message.
*
if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV))
goto freeit;
+ if (nd6_rs_output_timeout != ND6_RS_OUTPUT_INTERVAL)
+ /* we saw a RA, stop quick timer */
+ nd6_rs_output_set_timo(ND6_RS_OUTPUT_INTERVAL);
+
if (ip6->ip6_hlim != 255) {
nd6log((LOG_ERR,
"nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n",