+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 int 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;
+ size_t optlen;
+
+ if (hlim != 255)
+ return 0;
+
+ if (len < sizeof(*hdr))
+ return 0;
+
+ if (hdr->icmp6_code)
+ return 0;
+
+ switch (hdr->icmp6_type) {
+ case ND_ROUTER_ADVERT:
+ if (!IN6_IS_ADDR_LINKLOCAL(&source->sin6_addr))
+ return 0;
+
+ opt = (struct icmpv6_opt *)((struct nd_router_advert *)data + 1);
+ optlen = len - sizeof(struct nd_router_advert);
+ break;
+
+ default:
+ return 0;
+ }
+
+ while (optlen > 0) {
+ size_t l = opt->len << 3;
+
+ if (optlen < sizeof(*opt))
+ return 0;
+
+ if (l > optlen || l == 0)
+ return 0;
+
+ opt = (struct icmpv6_opt *)(((uint8_t *)opt) + l);
+
+ optlen -= l;
+ }
+
+ return 1;
+}
+