summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Barth <steven@midlink.org>2015-07-07 16:01:13 +0200
committerSteven Barth <steven@midlink.org>2015-07-07 16:01:13 +0200
commitfd3e3bbc461fcbbaefff9339da2e9b6c85a5b4a1 (patch)
tree3895bd2f9a9ab585fb30cfd32d9dd9c4709f968b
parentfb47b59a249adaff373aefe1bf09e635082ee0b3 (diff)
downloadodhcpd-fd3e3bbc461fcbbaefff9339da2e9b6c85a5b4a1.tar.gz
router: also send RAs to every known neighbor
-rw-r--r--src/ndp.c2
-rw-r--r--src/odhcpd.c55
-rw-r--r--src/odhcpd.h4
-rw-r--r--src/router.c17
4 files changed, 76 insertions, 2 deletions
diff --git a/src/ndp.c b/src/ndp.c
index 027e9ab..a6f8427 100644
--- a/src/ndp.c
+++ b/src/ndp.c
@@ -356,7 +356,7 @@ static void handle_rtnetlink(_unused void *addr, void *data, size_t len,
// Data to retrieve
size_t rta_offset = (is_route) ? sizeof(*rtm) : (is_addr) ?
- sizeof(*ifa) : sizeof(*ndm);
+ sizeof(struct ifaddrmsg) : sizeof(*ndm);
uint16_t atype = (is_route) ? RTA_DST : (is_addr) ? IFA_ADDRESS : NDA_DST;
ssize_t alen = NLMSG_PAYLOAD(nh, rta_offset);
struct in6_addr *addr = NULL;
diff --git a/src/odhcpd.c b/src/odhcpd.c
index aad5b37..3fb3009 100644
--- a/src/odhcpd.c
+++ b/src/odhcpd.c
@@ -194,6 +194,61 @@ ssize_t odhcpd_send(int socket, struct sockaddr_in6 *dest,
}
+int odhcpd_iterate_interface_neighbors(const struct interface *iface,
+ void(*cb_neigh)(const struct in6_addr *addr,
+ const struct interface *iface, void *data), void *data)
+{
+ struct {
+ struct nlmsghdr nhm;
+ struct ndmsg ndm;
+ } req = {{sizeof(req), RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_DUMP,
+ ++rtnl_seq, 0}, {AF_INET6, 0, 0, iface->ifindex, 0, 0, 0}};
+
+ if (send(rtnl_socket, &req, sizeof(req), 0) < (ssize_t)sizeof(req))
+ return -1;
+
+ uint8_t buf[8192];
+ ssize_t len = 0;
+
+ for (struct nlmsghdr *nhm = NULL; ; nhm = NLMSG_NEXT(nhm, len)) {
+ while (len < 0 || !NLMSG_OK(nhm, (size_t)len)) {
+ len = recv(rtnl_socket, buf, sizeof(buf), 0);
+ nhm = (struct nlmsghdr*)buf;
+ if (len < 0 || !NLMSG_OK(nhm, (size_t)len)) {
+ if (errno == EINTR)
+ continue;
+ else
+ return -1;
+ }
+ }
+
+ if (nhm->nlmsg_type != RTM_NEWNEIGH)
+ break;
+
+ struct ndmsg *ndm = NLMSG_DATA(nhm);
+ if (ndm->ndm_ifindex != iface->ifindex ||
+ (ndm->ndm_state & NUD_FAILED))
+ continue;
+
+ struct rtattr *rta = (struct rtattr*)&ndm[1];
+ size_t alen = NLMSG_PAYLOAD(nhm, sizeof(*ndm));
+
+ while (RTA_OK(rta, alen)) {
+ if (rta->rta_type == NDA_DST) {
+ // TODO
+ cb_neigh(NULL, iface, data);
+ break;
+ } else {
+ rta = RTA_NEXT(rta, alen);
+ }
+ }
+
+ }
+
+ return 0;
+}
+
+
// Detect an IPV6-address currently assigned to the given interface
ssize_t odhcpd_get_interface_addresses(int ifindex,
struct odhcpd_ipaddr *addrs, size_t cnt)
diff --git a/src/odhcpd.h b/src/odhcpd.h
index 5944661..dcd2d14 100644
--- a/src/odhcpd.h
+++ b/src/odhcpd.h
@@ -202,6 +202,10 @@ void odhcpd_hexlify(char *dst, const uint8_t *src, size_t len);
int odhcpd_bmemcmp(const void *av, const void *bv, size_t bits);
void odhcpd_bmemcpy(void *av, const void *bv, size_t bits);
+int odhcpd_iterate_interface_neighbors(const struct interface *iface,
+ void(*cb_neigh)(const struct in6_addr *addr,
+ const struct interface *iface, void *data), void *data);
+
int config_parse_interface(void *data, size_t len, const char *iname, bool overwrite);
#ifdef WITH_UBUS
diff --git a/src/router.c b/src/router.c
index f942d8f..718f170 100644
--- a/src/router.c
+++ b/src/router.c
@@ -37,6 +37,7 @@ static void sigusr1_refresh(int signal);
static struct odhcpd_event router_event = {{.fd = -1}, handle_icmpv6};
static FILE *fp_route = NULL;
+#define RA_IOV_LEN 6
int init_router(void)
@@ -205,6 +206,18 @@ static bool parse_routes(struct odhcpd_ipaddr *n, ssize_t len)
return found_default;
}
+// Unicsat RAs
+static void send_neigh_ra(const struct in6_addr *addr,
+ const struct interface *iface, void *data)
+{
+ struct sockaddr_in6 dest = {
+ .sin6_family = AF_INET6,
+ .sin6_addr = *addr,
+ .sin6_scope_id = iface->ifindex,
+ };
+ odhcpd_send(router_event.uloop.fd, &dest, data, RA_IOV_LEN, iface);
+}
+
// Router Advert server mode
static uint64_t send_router_advert(struct interface *iface, const struct in6_addr *from)
@@ -443,7 +456,8 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add
.data = {0, 0, maxival >> 24, maxival >> 16, maxival >> 8, maxival}
};
- struct iovec iov[] = {{&adv, (uint8_t*)&adv.prefix[cnt] - (uint8_t*)&adv},
+ struct iovec iov[RA_IOV_LEN] = {
+ {&adv, (uint8_t*)&adv.prefix[cnt] - (uint8_t*)&adv},
{&routes, routes_cnt * sizeof(*routes)},
{&dns, (dns_cnt) ? sizeof(dns) : 0},
{dns_addr, dns_cnt * sizeof(*dns_addr)},
@@ -457,6 +471,7 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add
odhcpd_send(router_event.uloop.fd,
&dest, iov, ARRAY_SIZE(iov), iface);
+ odhcpd_iterate_interface_neighbors(iface, send_neigh_ra, iov);
return msecs;
}