// 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;
}
+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)
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
static struct odhcpd_event router_event = {{.fd = -1}, handle_icmpv6};
static FILE *fp_route = NULL;
+#define RA_IOV_LEN 6
int init_router(void)
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)
.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)},
odhcpd_send(router_event.uloop.fd,
&dest, iov, ARRAY_SIZE(iov), iface);
+ odhcpd_iterate_interface_neighbors(iface, send_neigh_ra, iov);
return msecs;
}