+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;
+}
+
+int ra_conf_hoplimit(int newvalue)
+{
+ static int value = 0;
+ if (newvalue > value)
+ value = newvalue;
+ return value;
+}
+
+int ra_conf_mtu(int newvalue)
+{
+ static int value = 0;
+ if (newvalue >= 1280 && newvalue <= 65535)
+ value = newvalue;
+ return value;
+}
+
+int ra_conf_reachable(int newvalue)
+{
+ static int value = 0;
+ if (newvalue > 0 && newvalue <= 3600000)
+ value = newvalue;
+ return value;
+}
+
+int ra_conf_retransmit(int newvalue)
+{
+ static int value = 0;
+ if (newvalue > 0 && newvalue <= 60000)
+ value = newvalue;
+ return value;
+}
+