+static struct tok icmp6_type_values[] = {
+ { ICMP6_DST_UNREACH, "destination unreachable"},
+ { ICMP6_PACKET_TOO_BIG, "packet too big"},
+ { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"},
+ { ICMP6_PARAM_PROB, "parameter problem"},
+ { ICMP6_ECHO_REQUEST, "echo request"},
+ { ICMP6_ECHO_REPLY, "echo reply"},
+ { MLD6_LISTENER_QUERY, "multicast listener query"},
+ { MLD6_LISTENER_REPORT, "multicast listener report"},
+ { MLD6_LISTENER_DONE, "multicast listener done"},
+ { ND_ROUTER_SOLICIT, "router solicitation"},
+ { ND_ROUTER_ADVERT, "router advertisement"},
+ { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"},
+ { ND_NEIGHBOR_ADVERT, "neighbor advertisement"},
+ { ND_REDIRECT, "redirect"},
+ { ICMP6_ROUTER_RENUMBERING, "router renumbering"},
+ { IND_SOLICIT, "inverse neighbor solicitation"},
+ { IND_ADVERT, "inverse neighbor advertisement"},
+ { MLDV2_LISTENER_REPORT, "multicast listener report v2"},
+ { ICMP6_HADISCOV_REQUEST, "ha discovery request"},
+ { ICMP6_HADISCOV_REPLY, "ha discovery reply"},
+ { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"},
+ { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"},
+ { ICMP6_WRUREQUEST, "who-are-you request"},
+ { ICMP6_WRUREPLY, "who-are-you reply"},
+ { ICMP6_NI_QUERY, "node information query"},
+ { ICMP6_NI_REPLY, "node information reply"},
+ { MLD6_MTRACE, "mtrace message"},
+ { MLD6_MTRACE_RESP, "mtrace response"},
+ { 0, NULL }
+};
+
+static struct tok icmp6_dst_unreach_code_values[] = {
+ { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" },
+ { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"},
+ { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"},
+ { ICMP6_DST_UNREACH_ADDR, "unreachable address"},
+ { ICMP6_DST_UNREACH_NOPORT, "unreachable port"},
+ { 0, NULL }
+};
+
+static struct tok icmp6_opt_pi_flag_values[] = {
+ { ND_OPT_PI_FLAG_ONLINK, "onlink" },
+ { ND_OPT_PI_FLAG_AUTO, "auto" },
+ { ND_OPT_PI_FLAG_ROUTER, "router" },
+ { 0, NULL }
+};
+
+static struct tok icmp6_opt_ra_flag_values[] = {
+ { ND_RA_FLAG_MANAGED, "managed" },
+ { ND_RA_FLAG_OTHER, "other stateful"},
+ { ND_RA_FLAG_HOME_AGENT, "home agent"},
+ { 0, NULL }
+};
+
+static struct tok icmp6_nd_na_flag_values[] = {
+ { ND_NA_FLAG_ROUTER, "router" },
+ { ND_NA_FLAG_SOLICITED, "solicited" },
+ { ND_NA_FLAG_OVERRIDE, "override" },
+ { 0, NULL }
+};
+
+
+static struct tok icmp6_opt_values[] = {
+ { ND_OPT_SOURCE_LINKADDR, "source link-address"},
+ { ND_OPT_TARGET_LINKADDR, "destination link-address"},
+ { ND_OPT_PREFIX_INFORMATION, "prefix info"},
+ { ND_OPT_REDIRECTED_HEADER, "redirected header"},
+ { ND_OPT_MTU, "mtu"},
+ { ND_OPT_ADVINTERVAL, "advertisement interval"},
+ { ND_OPT_HOMEAGENT_INFO, "homeagent information"},
+ { ND_OPT_ROUTE_INFO, "route info"},
+ { 0, NULL }
+};
+
+/* mldv2 report types */
+static struct tok mldv2report2str[] = {
+ { 1, "is_in" },
+ { 2, "is_ex" },
+ { 3, "to_in" },
+ { 4, "to_ex" },
+ { 5, "allow" },
+ { 6, "block" },
+ { 0, NULL }
+};
+
+static const char *
+get_rtpref(u_int v)
+{
+ static const char *rtpref_str[] = {
+ "medium", /* 00 */
+ "high", /* 01 */
+ "rsv", /* 10 */
+ "low" /* 11 */
+ };
+
+ return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff];
+}
+
+static const char *
+get_lifetime(u_int32_t v)
+{
+ static char buf[20];
+
+ if (v == (u_int32_t)~0UL)
+ return "infinity";
+ else {
+ snprintf(buf, sizeof(buf), "%u", v);
+ return buf;
+ }
+}
+
+static void
+print_lladdr(const u_int8_t *p, size_t l)
+{
+ const u_int8_t *ep, *q;
+
+ q = p;
+ ep = p + l;
+ while (l > 0 && q < ep) {
+ if (q > p)
+ printf(":");
+ printf("%02x", *q++);
+ l--;
+ }
+}
+
+static int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp,
+ u_int len)
+{
+ size_t i;
+ register const u_int16_t *sp;
+ u_int32_t sum;
+ union {
+ struct {
+ struct in6_addr ph_src;
+ struct in6_addr ph_dst;
+ u_int32_t ph_len;
+ u_int8_t ph_zero[3];
+ u_int8_t ph_nxt;
+ } ph;
+ u_int16_t pa[20];
+ } phu;
+
+ /* pseudo-header */
+ memset(&phu, 0, sizeof(phu));
+ phu.ph.ph_src = ip6->ip6_src;
+ phu.ph.ph_dst = ip6->ip6_dst;
+ phu.ph.ph_len = htonl(len);
+ phu.ph.ph_nxt = IPPROTO_ICMPV6;
+
+ sum = 0;
+ for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
+ sum += phu.pa[i];
+
+ sp = (const u_int16_t *)icp;
+
+ for (i = 0; i < (len & ~1); i += 2)
+ sum += *sp++;
+
+ if (len & 1)
+ sum += htons((*(const u_int8_t *)sp) << 8);
+
+ while (sum > 0xffff)
+ sum = (sum & 0xffff) + (sum >> 16);
+ sum = ~sum & 0xffff;
+
+ return (sum);
+}
+