#define ND_OPT_MTU 5
#define ND_OPT_ADVINTERVAL 7
#define ND_OPT_HOMEAGENT_INFO 8
+#define ND_OPT_NONCE 14
#define ND_OPT_ROUTE_INFO 24 /* RFC4191 */
#define ND_OPT_RDNSS 25
#define ND_OPT_DNSSL 31
+#define ND_OPT_PREF64_INFORMATION 38 /* RFC8781 */
struct nd_opt_prefix_info { /* prefix information */
nd_uint8_t nd_opt_pi_type;
/* prefix follows */
};
+struct nd_opt_pref64 { /* PREF64 option */
+ nd_uint8_t nd_opt_pref64_type;
+ nd_uint8_t nd_opt_pref64_len;
+ nd_uint16_t nd_opt_pref64_slplc; /* 13bit lft + 3bit PLC */
+ nd_uint32_t nd_opt_pref64_words[3]; /* highest 96 bits of prefix */
+};
+
/*
* icmp6 namelookup
*/
#define NI_NODEADDR_FLAG_LINKLOCAL 0x0008
#define NI_NODEADDR_FLAG_SITELOCAL 0x0010
#define NI_NODEADDR_FLAG_GLOBAL 0x0020
-#define NI_NODEADDR_FLAG_ANYCAST 0x0040 /* just experimental. not in spec */
+
+static const struct tok ni_nodeaddr_flag_values[] = {
+ { NI_NODEADDR_FLAG_TRUNCATE, "T" },
+ { NI_NODEADDR_FLAG_ALL, "A" },
+ { NI_NODEADDR_FLAG_COMPAT, "C" },
+ { NI_NODEADDR_FLAG_LINKLOCAL, "L" },
+ { NI_NODEADDR_FLAG_SITELOCAL, "S" },
+ { NI_NODEADDR_FLAG_GLOBAL, "G" },
+ { 0, NULL }
+};
+
+static const struct tok ni_ipv4addr_flag_values[] = {
+ { NI_NODEADDR_FLAG_TRUNCATE, "T" },
+ { NI_NODEADDR_FLAG_ALL, "A" },
+ { 0, NULL }
+};
struct ni_reply_fqdn {
nd_uint32_t ni_fqdn_ttl; /* TTL */
#define ICMP6_RR_FLAGS_SPECSITE 0x10
#define ICMP6_RR_FLAGS_PREVDONE 0x08
+static const struct tok router_renum_flag_values[] = {
+ { ICMP6_RR_FLAGS_TEST, "T" },
+ { ICMP6_RR_FLAGS_REQRESULT, "R" },
+ { ICMP6_RR_FLAGS_FORCEAPPLY, "A" },
+ { ICMP6_RR_FLAGS_SPECSITE, "S" },
+ { ICMP6_RR_FLAGS_PREVDONE, "P" },
+ { 0, NULL },
+};
+
#define rr_type rr_hdr.icmp6_type
#define rr_code rr_hdr.icmp6_code
#define rr_cksum rr_hdr.icmp6_cksum
static const char *get_rtpref(u_int);
static const char *get_lifetime(uint32_t);
+static const char *get_pref64_len_repr(uint16_t);
static void print_lladdr(netdissect_options *ndo, const u_char *, size_t);
static int icmp6_opt_print(netdissect_options *ndo, const u_char *, int);
static void mld6_print(netdissect_options *ndo, const u_char *);
{ ND_OPT_DNSSL, "dnssl"},
{ ND_OPT_ADVINTERVAL, "advertisement interval"},
{ ND_OPT_HOMEAGENT_INFO, "homeagent information"},
+ { ND_OPT_NONCE, "nonce"},
{ ND_OPT_ROUTE_INFO, "route info"},
+ { ND_OPT_PREF64_INFORMATION, "pref64"},
{ 0, NULL }
};
}
}
+static const char *
+get_pref64_len_repr(uint16_t v)
+{
+ static const char *prefixlen_str[] = {
+ "96", "64", "56", "48", "40", "32"
+ };
+
+ v = v & 0x0007;
+ if (v < 6)
+ return prefixlen_str[v];
+ else
+ return "??";
+}
+
static void
print_lladdr(netdissect_options *ndo, const uint8_t *p, size_t l)
{
const struct nd_opt_advinterval *opa;
const struct nd_opt_homeagent_info *oph;
const struct nd_opt_route_info *opri;
+ const struct nd_opt_pref64 *op64;
const u_char *cp, *ep, *domp;
nd_ipv6 in6;
size_t l;
u_int i;
+ uint16_t w;
cp = bp;
/* 'ep' points to the end of available data. */
GET_BE_U_2(oph->nd_opt_hai_preference),
GET_BE_U_2(oph->nd_opt_hai_lifetime));
break;
+ case ND_OPT_NONCE:
+ l = (opt_len << 3) - 2;
+ nd_print_bytes_hex(ndo, cp + 2, l);
+ break;
case ND_OPT_ROUTE_INFO:
opri = (const struct nd_opt_route_info *)op;
ND_TCHECK_4(opri->nd_opt_rti_lifetime);
ND_PRINT(", lifetime=%s",
get_lifetime(GET_BE_U_4(opri->nd_opt_rti_lifetime)));
break;
+ case ND_OPT_PREF64_INFORMATION:
+ op64 = (const struct nd_opt_pref64 *)op;
+ if (opt_len != 2)
+ ND_PRINT("%s", "bad option length! ");
+ w = GET_BE_U_2(op64->nd_opt_pref64_slplc);
+ memset(&in6, 0, sizeof(in6));
+ GET_CPY_BYTES(&in6, op64->nd_opt_pref64_words,
+ sizeof(op64->nd_opt_pref64_words));
+ ND_PRINT("%s/%s (plc %u), lifetime %us",
+ ip6addr_string(ndo, (const u_char *)&in6),
+ get_pref64_len_repr(w),
+ w & 0x0007,
+ w & 0xfff8);
+ break;
default:
if (ndo->ndo_vflag <= 1) {
print_unknown_data(ndo,cp+2,"\n\t ", (opt_len << 3) - 2); /* skip option header */
const struct icmp6_hdr *dp;
const u_char *cp;
size_t siz, i;
+ uint16_t flags;
int needcomma;
if (ep < bp)
break;
case NI_QTYPE_NODEADDR:
ND_PRINT("node addresses");
- i = GET_BE_U_2(ni6->ni_flags);
- if (!i)
- break;
- /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
- ND_PRINT(" [%s%s%s%s%s%s]",
- (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
- (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
- (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
- (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
- (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
- (i & NI_NODEADDR_FLAG_ALL) ? "A" : "");
+ flags = GET_BE_U_2(ni6->ni_flags);
+ if (flags)
+ ND_PRINT(" [%s]",
+ bittok2str_nosep(ni_nodeaddr_flag_values,
+ "none", flags));
+ if (flags & NI_NODEADDR_FLAG_TRUNCATE)
+ ND_PRINT(" [invalid flag Truncate present]");
+ break;
+ case NI_QTYPE_IPV4ADDR:
+ ND_PRINT("ipv4 addresses");
+ flags = GET_BE_U_2(ni6->ni_flags);
+ if (flags)
+ ND_PRINT(" [%s]",
+ bittok2str_nosep(ni_ipv4addr_flag_values,
+ "none", flags));
+ if (flags & NI_NODEADDR_FLAG_TRUNCATE)
+ ND_PRINT(" [invalid flag Truncate present]");
break;
default:
ND_PRINT("unknown");
if (needcomma)
ND_PRINT(", ");
ND_PRINT("node addresses");
+ flags = GET_BE_U_2(ni6->ni_flags);
+ if (flags)
+ ND_PRINT(" [%s]",
+ bittok2str_nosep(ni_nodeaddr_flag_values,
+ "none", flags));
i = sizeof(*ni6);
while (i < siz) {
if (i + sizeof(uint32_t) + sizeof(nd_ipv6) > siz)
GET_BE_U_4(bp + i));
i += sizeof(uint32_t) + sizeof(nd_ipv6);
}
- i = GET_BE_U_2(ni6->ni_flags);
- if (!i)
- break;
- ND_PRINT(" [%s%s%s%s%s%s%s]",
- (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
- (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
- (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
- (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
- (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
- (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
- (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
+ break;
+ case NI_QTYPE_IPV4ADDR:
+ if (needcomma)
+ ND_PRINT(", ");
+ ND_PRINT("ipv4 addresses");
+ flags = GET_BE_U_2(ni6->ni_flags);
+ if (flags)
+ ND_PRINT(" [%s]",
+ bittok2str_nosep(ni_nodeaddr_flag_values,
+ "none", flags));
+ cp = (const u_char *)(ni6 + 1);
+ while (cp < ep) {
+ uint32_t ttl;
+
+ ttl = GET_BE_U_4(cp);
+ cp += 4;
+ ND_PRINT(" %s(%u)", GET_IPADDR_STRING(cp), ttl);
+ cp += 4;
+ }
break;
default:
if (needcomma)
if (ndo->ndo_vflag) {
uint8_t rr_flags = GET_U_1(rr6->rr_flags);
-#define F(x, y) (rr_flags & (x) ? (y) : "")
ND_PRINT("["); /*]*/
if (rr_flags) {
- ND_PRINT("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
- F(ICMP6_RR_FLAGS_REQRESULT, "R"),
- F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
- F(ICMP6_RR_FLAGS_SPECSITE, "S"),
- F(ICMP6_RR_FLAGS_PREVDONE, "P"));
+ ND_PRINT("%s,",
+ bittok2str_nosep(router_renum_flag_values,
+ "none", rr_flags));
}
ND_PRINT("seg=%u,", GET_U_1(rr6->rr_segnum));
ND_PRINT("maxdelay=%u", GET_BE_U_2(rr6->rr_maxdelay));
ND_PRINT("rsvd=0x%x", GET_BE_U_4(rr6->rr_reserved));
/*[*/
ND_PRINT("]");
-#undef F
}
if (GET_U_1(rr6->rr_code) == ICMP6_ROUTER_RENUMBERING_COMMAND) {