+bool ra_link_up(void)
+{
+ static bool firstcall = true;
+ struct {
+ struct nlmsghdr hdr;
+ struct ifinfomsg msg;
+ uint8_t pad[4000];
+ } resp;
+
+ bool ret = false;
+ ssize_t read;
+
+ do {
+ read = recv(rtnl, &resp, sizeof(resp), MSG_DONTWAIT);
+ if (read < 0 || !NLMSG_OK(&resp.hdr, (size_t)read) ||
+ resp.hdr.nlmsg_type != RTM_NEWLINK ||
+ resp.msg.ifi_index != if_index)
+ continue;
+
+ bool hascarrier = resp.msg.ifi_flags & IFF_LOWER_UP;
+ if (!firstcall && nocarrier != !hascarrier)
+ ret = true;
+
+ nocarrier = !hascarrier;
+ firstcall = false;
+ } while (read > 0);
+
+ if (ret) {
+ syslog(LOG_NOTICE, "carrier => %i event on %s", (int)!nocarrier, if_name);
+
+ rs_attempt = 0;
+ ra_send_rs(SIGALRM);
+ }
+
+ return ret;
+}
+
+static bool ra_icmpv6_valid(struct sockaddr_in6 *source, int hlim, uint8_t *data, size_t len)
+{
+ struct icmp6_hdr *hdr = (struct icmp6_hdr*)data;
+ struct icmpv6_opt *opt, *end = (struct icmpv6_opt*)&data[len];
+
+ if (hlim != 255 || len < sizeof(*hdr) || hdr->icmp6_code)
+ return false;
+
+ switch (hdr->icmp6_type) {
+ case ND_ROUTER_ADVERT:
+ if (!IN6_IS_ADDR_LINKLOCAL(&source->sin6_addr))
+ return false;
+
+ opt = (struct icmpv6_opt*)((struct nd_router_advert*)data + 1);
+ break;
+
+ default:
+ return false;
+ }
+
+ icmpv6_for_each_option(opt, opt, end)
+ ;
+
+ return opt == end;
+}
+