-/* $OpenBSD: engine.c,v 1.3 2018/07/10 22:14:19 florian Exp $ */
+/* $OpenBSD: engine.c,v 1.4 2018/07/11 14:03:13 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
#include "rad.h"
#include "engine.h"
-__dead void engine_shutdown(void);
-void engine_sig_handler(int sig, short, void *);
-void engine_dispatch_frontend(int, short, void *);
-void engine_dispatch_main(int, short, void *);
-void parse_ra_rs(struct imsg_ra_rs *);
-void parse_ra(struct imsg_ra_rs *);
-void parse_rs(struct imsg_ra_rs *);
+#define MAX_RTR_ADV_INTERVAL 600
+#define MIN_RTR_ADV_INTERVAL 200
+
+struct engine_iface {
+ TAILQ_ENTRY(engine_iface) entry;
+ struct event timer;
+ uint32_t if_index;
+};
+
+TAILQ_HEAD(, engine_iface) engine_interfaces;
+
+
+__dead void engine_shutdown(void);
+void engine_sig_handler(int sig, short, void *);
+void engine_dispatch_frontend(int, short, void *);
+void engine_dispatch_main(int, short, void *);
+void parse_ra_rs(struct imsg_ra_rs *);
+void parse_ra(struct imsg_ra_rs *);
+void parse_rs(struct imsg_ra_rs *);
+void update_iface(uint32_t);
+struct engine_iface *find_engine_iface_by_id(uint32_t);
+void iface_timeout(int, short, void *);
struct rad_conf *engine_conf;
struct imsgev *iev_frontend;
struct imsg imsg;
struct imsg_ra_rs ra_rs;
ssize_t n;
+ uint32_t if_index;
int shut = 0, verbose;
ibuf = &iev->ibuf;
memcpy(&ra_rs, imsg.data, sizeof(ra_rs));
parse_ra_rs(&ra_rs);
break;
+ case IMSG_UPDATE_IF:
+ if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(if_index))
+ fatal("%s: IMSG_UPDATE_IF wrong length: %d",
+ __func__, imsg.hdr.len);
+ memcpy(&if_index, imsg.data, sizeof(if_index));
+ update_iface(if_index);
+ break;
case IMSG_CTL_LOG_VERBOSE:
/* Already checked by frontend. */
memcpy(&verbose, imsg.data, sizeof(verbose));
engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra,
sizeof(send_ra));
}
+
+struct engine_iface*
+find_engine_iface_by_id(uint32_t if_index)
+{
+ struct engine_iface *engine_iface;
+
+ TAILQ_FOREACH(engine_iface, &engine_interfaces, entry) {
+ if (engine_iface->if_index == if_index)
+ return engine_iface;
+ }
+ return (NULL);
+}
+
+void
+update_iface(uint32_t if_index)
+{
+ struct engine_iface *engine_iface;
+ struct timeval tv;
+
+ if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL) {
+ engine_iface = calloc(1, sizeof(*engine_iface));
+ engine_iface->if_index = if_index;
+ evtimer_set(&engine_iface->timer, iface_timeout, engine_iface);
+ }
+
+ tv.tv_sec = 0;
+ tv.tv_usec = arc4random_uniform(1000000);
+ evtimer_add(&engine_iface->timer, &tv);
+}
+
+void
+iface_timeout(int fd, short events, void *arg)
+{
+ struct engine_iface *engine_iface = (struct engine_iface *)arg;
+ struct imsg_send_ra send_ra;
+ struct timeval tv;
+
+
+ tv.tv_sec = MIN_RTR_ADV_INTERVAL +
+ arc4random_uniform(MAX_RTR_ADV_INTERVAL - MIN_RTR_ADV_INTERVAL);
+ tv.tv_usec = arc4random_uniform(1000000);
+
+ log_debug("%s new timeout in %lld", __func__, tv.tv_sec);
+
+ evtimer_add(&engine_iface->timer, &tv);
+
+ send_ra.if_index = engine_iface->if_index;
+ memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to));
+ engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra,
+ sizeof(send_ra));
+}
-/* $OpenBSD: frontend.c,v 1.2 2018/07/10 22:14:19 florian Exp $ */
+/* $OpenBSD: frontend.c,v 1.3 2018/07/11 14:03:13 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
#include "frontend.h"
#include "control.h"
+#define RA_MAX_SIZE 1500
+
struct icmp6_ev {
struct event ev;
uint8_t answer[1500];
int removed;
int prefix_count;
size_t datalen;
- uint8_t data[1500];
+ uint8_t data[RA_MAX_SIZE];
};
TAILQ_HEAD(, ra_iface) ra_interfaces;
struct ra_iface_conf *ra_iface_conf;
struct ra_options_conf *ra_options_conf;
struct ra_prefix_conf *ra_prefix_conf;
- uint8_t *buf;
+ size_t len;
+ uint8_t *p, buf[RA_MAX_SIZE];
ra_iface_conf = find_ra_iface_conf(&frontend_conf->ra_iface_list,
ra_iface->name);
ra_options_conf = &ra_iface_conf->ra_options;
- ra_iface->datalen = sizeof(*ra);
- ra_iface->datalen += sizeof(*ndopt_pi) * ra_iface->prefix_count;
+ len = sizeof(*ra);
+ len += sizeof(*ndopt_pi) * ra_iface->prefix_count;
- if (ra_iface->datalen > sizeof(ra_iface->data))
+ if (len > sizeof(ra_iface->data))
fatal("%s: packet too big", __func__); /* XXX send multiple */
- buf = ra_iface->data;
+ p = buf;
- ra = (struct nd_router_advert *)buf;
+ ra = (struct nd_router_advert *)p;
memset(ra, 0, sizeof(*ra));
ra->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
if (ra_options_conf->o_flag)
ra->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
- if (ra_options_conf->dfr)
+ if (ra_iface->removed)
+ /* tell clients that we are no longer a default router */
+ ra->nd_ra_router_lifetime = 0;
+ else if (ra_options_conf->dfr) {
ra->nd_ra_router_lifetime =
htons(ra_options_conf->router_lifetime);
+ }
ra->nd_ra_reachable = htonl(ra_options_conf->reachable_time);
ra->nd_ra_retransmit = htonl(ra_options_conf->retrans_timer);
- buf += sizeof(*ra);
+ p += sizeof(*ra);
SIMPLEQ_FOREACH(ra_prefix_conf, &ra_iface->prefixes, entry) {
- ndopt_pi = (struct nd_opt_prefix_info *)buf;
+ ndopt_pi = (struct nd_opt_prefix_info *)p;
memset(ndopt_pi, 0, sizeof(*ndopt_pi));
ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
ndopt_pi->nd_opt_pi_len = 4;
htonl(ra_prefix_conf->pltime);
ndopt_pi->nd_opt_pi_prefix = ra_prefix_conf->prefix;
- buf += sizeof(*ndopt_pi);
+ p += sizeof(*ndopt_pi);
+ }
+
+ if (len != ra_iface->datalen || memcmp(buf, ra_iface->data, len)
+ != 0) {
+ memcpy(ra_iface->data, buf, len);
+ ra_iface->datalen = len;
+ /* packet changed; tell engine to send new advertisments */
+ frontend_imsg_compose_engine(IMSG_UPDATE_IF, 0,
+ &ra_iface->if_index, sizeof(ra_iface->if_index));
}
}