+ return (flags == 0x0) ? 512 : (flags == 0x1) ? 384 :
+ (flags == 0x3) ? 640 : -1;
+}
+
+
+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;
+
+ ssize_t alen = NLMSG_PAYLOAD(&resp.hdr, sizeof(resp.msg));
+ for (struct rtattr *rta = (struct rtattr*)(resp.pad);
+ RTA_OK(rta, alen); rta = RTA_NEXT(rta, alen)) {
+ if (rta->rta_type == IFLA_ADDRESS &&
+ RTA_PAYLOAD(rta) >= sizeof(rs.lladdr.data))
+ memcpy(rs.lladdr.data, RTA_DATA(rta), sizeof(rs.lladdr.data));
+ }
+
+ 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;