summaryrefslogtreecommitdiff
path: root/sys/netinet6
diff options
context:
space:
mode:
authorFlorian Obser <florian@cvs.openbsd.org>2014-08-25 14:00:35 +0000
committerFlorian Obser <florian@cvs.openbsd.org>2014-08-25 14:00:35 +0000
commit970b26ec4389cce4f07f4d0afcdfda199a9118be (patch)
tree957d4a6f7d0b5d0af482bcf1a4687ab0af5f785b /sys/netinet6
parent1910644611fb8118754549f7bd25101f9d025b6c (diff)
Move sending of router solicitations to the kernel; receiving and
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@
Diffstat (limited to 'sys/netinet6')
-rw-r--r--sys/netinet6/in6.c5
-rw-r--r--sys/netinet6/in6_ifattach.c11
-rw-r--r--sys/netinet6/in6_var.h3
-rw-r--r--sys/netinet6/nd6.c42
-rw-r--r--sys/netinet6/nd6.h14
-rw-r--r--sys/netinet6/nd6_rtr.c109
6 files changed, 178 insertions, 6 deletions
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index e9670897dda..1a9dc206158 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -1,4 +1,4 @@
-/* $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 $ */
/*
@@ -2087,6 +2087,9 @@ in6_if_up(struct ifnet *ifp)
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
diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c
index 93620c48377..7f812902a6b 100644
--- a/sys/netinet6/in6_ifattach.c
+++ b/sys/netinet6/in6_ifattach.c
@@ -1,4 +1,4 @@
-/* $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 $ */
/*
@@ -689,4 +689,13 @@ in6_ifdetach(struct ifnet *ifp)
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));
+ }
}
diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h
index ed1786b466c..d2c444617d9 100644
--- a/sys/netinet6/in6_var.h
+++ b/sys/netinet6/in6_var.h
@@ -1,4 +1,4 @@
-/* $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 $ */
/*
@@ -92,6 +92,7 @@ struct in6_ifextra {
struct in6_ifstat *in6_ifstat;
struct icmp6_ifstat *icmp6_ifstat;
struct nd_ifinfo *nd_ifinfo;
+ void *rs_lhcookie;
int nprefixes;
int ndefrouters;
};
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index d5c48f669b8..e2d018fc4c9 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -1,4 +1,4 @@
-/* $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 $ */
/*
@@ -103,6 +103,11 @@ struct timeout nd6_timer_ch;
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);
@@ -137,6 +142,8 @@ nd6_init(void)
/* 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 *
@@ -1607,6 +1614,39 @@ nd6_slowtimo(void *ignored_arg)
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,
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h
index f17e69535f5..e5ca468ed28 100644
--- a/sys/netinet6/nd6.h
+++ b/sys/netinet6/nd6.h
@@ -1,4 +1,4 @@
-/* $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 $ */
/*
@@ -134,6 +134,9 @@ struct in6_ndifreq {
#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 \
@@ -230,6 +233,12 @@ extern int nd6_debug;
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 {
@@ -294,6 +303,9 @@ void nd6_dad_duplicated(struct ifaddr *);
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);
diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c
index e8a7b10d487..a50dbf7c080 100644
--- a/sys/netinet6/nd6_rtr.c
+++ b/sys/netinet6/nd6_rtr.c
@@ -1,4 +1,4 @@
-/* $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 $ */
/*
@@ -32,6 +32,7 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/timeout.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
@@ -170,6 +171,108 @@ nd6_rs_input(struct mbuf *m, int off, int icmp6len)
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.
*
@@ -201,6 +304,10 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len)
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",