*/
#ifndef lint
-static const char rcsid[] =
- "@(#) /master/usr.sbin/tcpdump/tcpdump/print-icmp.c,v 2.1 1995/02/03 18:14:42 polk Exp (LBL)";
+static const char rcsid[] _U_ =
+ "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.77 2004-06-16 00:06:28 guy Exp $";
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
#endif
#ifdef INET6
-#include <ctype.h>
+#include <tcpdump-stdinc.h>
-#include <sys/param.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+#include <stdio.h>
+#include <string.h>
-#include <net/if.h>
+#include "ip6.h"
+#include "icmp6.h"
+#include "ipproto.h"
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
-#include <netinet/ip_var.h>
-#include <netinet/udp.h>
-#include <netinet/udp_var.h>
-#include <netinet/tcp.h>
+#include "interface.h"
+#include "addrtoname.h"
+#include "extract.h"
-#include <arpa/inet.h>
+#include "udp.h"
+#include "ah.h"
-#include <stdio.h>
+static const char *get_rtpref(u_int);
+static const char *get_lifetime(u_int32_t);
+static void print_lladdr(const u_char *, size_t);
+static void icmp6_opt_print(const u_char *, int);
+static void mld6_print(const u_char *);
+static void mldv2_report_print(const u_char *, u_int);
+static void mldv2_query_print(const u_char *, u_int);
+static struct udphdr *get_upperlayer(u_char *, u_int *);
+static void dnsname_print(const u_char *, const u_char *);
+static void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *);
+static void icmp6_rrenum_print(const u_char *, const u_char *);
-#include <netinet/ip6.h>
-#include <netinet/icmp6.h>
+#ifndef abs
+#define abs(a) ((0 < (a)) ? (a) : -(a))
+#endif
-#include "interface.h"
-#include "addrtoname.h"
+/* 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;
+ }
+}
-void icmp6_opt_print(const u_char *, int);
-void mld6_print(const u_char *);
+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);
+}
void
-icmp6_print(register const u_char *bp, register const u_char *bp2)
+icmp6_print(const u_char *bp, u_int length, const u_char *bp2, int fragmented)
{
- register const struct icmp6_hdr *dp;
- register const struct ip6_hdr *ip;
- register const char *str;
- register const struct ip6_hdr *oip;
- register const struct udphdr *ouh;
- register int hlen, dport;
- register const u_char *ep;
+ const struct icmp6_hdr *dp;
+ const struct ip6_hdr *ip;
+ const char *str;
+ const struct ip6_hdr *oip;
+ const struct udphdr *ouh;
+ int dport;
+ const u_char *ep;
char buf[256];
- int icmp6len;
-
-#if 0
-#define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc
-#endif
+ u_int prot;
dp = (struct icmp6_hdr *)bp;
ip = (struct ip6_hdr *)bp2;
oip = (struct ip6_hdr *)(dp + 1);
str = buf;
- /* 'ep' points to the end of avaible data. */
+ /* 'ep' points to the end of available data. */
ep = snapend;
- if (ip->ip6_plen)
- icmp6len = (ntohs(ip->ip6_plen) + sizeof(struct ip6_hdr) -
- (bp - bp2));
- else /* XXX: jumbo payload case... */
- icmp6len = snapend - bp;
-
-#if 0
- (void)printf("%s > %s: ",
- ip6addr_string(&ip->ip6_src),
- ip6addr_string(&ip->ip6_dst));
-#endif
- TCHECK(dp->icmp6_code);
- switch(dp->icmp6_type) {
+ TCHECK(dp->icmp6_cksum);
+
+ if (vflag && !fragmented) {
+ int sum = dp->icmp6_cksum;
+
+ if (TTEST2(bp[0], length)) {
+ sum = icmp6_cksum(ip, dp, length);
+ if (sum != 0)
+ (void)printf("[bad icmp6 cksum %x!] ", sum);
+ else
+ (void)printf("[icmp6 sum ok] ");
+ }
+ }
+
+ switch (dp->icmp6_type) {
case ICMP6_DST_UNREACH:
TCHECK(oip->ip6_dst);
switch (dp->icmp6_code) {
printf("icmp6: %s unreachable prohibited",
ip6addr_string(&oip->ip6_dst));
break;
-#ifdef ICMP6_DST_UNREACH_BEYONDSCOPE
case ICMP6_DST_UNREACH_BEYONDSCOPE:
-#else
- case ICMP6_DST_UNREACH_NOTNEIGHBOR:
-#endif
printf("icmp6: %s beyond scope of source address %s",
ip6addr_string(&oip->ip6_dst),
ip6addr_string(&oip->ip6_src));
ip6addr_string(&oip->ip6_dst));
break;
case ICMP6_DST_UNREACH_NOPORT:
- TCHECK(oip->ip6_nxt);
- hlen = sizeof(struct ip6_hdr);
- ouh = (struct udphdr *)(((u_char *)oip) + hlen);
- dport = ntohs(ouh->uh_dport);
- switch (oip->ip6_nxt) {
+ if ((ouh = get_upperlayer((u_char *)oip, &prot))
+ == NULL)
+ goto trunc;
+
+ dport = EXTRACT_16BITS(&ouh->uh_dport);
+ switch (prot) {
case IPPROTO_TCP:
printf("icmp6: %s tcp port %s unreachable",
ip6addr_string(&oip->ip6_dst),
break;
case ICMP6_PACKET_TOO_BIG:
TCHECK(dp->icmp6_mtu);
- printf("icmp6: too big %u\n", (u_int32_t)ntohl(dp->icmp6_mtu));
+ printf("icmp6: too big %u", EXTRACT_32BITS(&dp->icmp6_mtu));
break;
case ICMP6_TIME_EXCEEDED:
TCHECK(oip->ip6_dst);
TCHECK(oip->ip6_dst);
switch (dp->icmp6_code) {
case ICMP6_PARAMPROB_HEADER:
- printf("icmp6: parameter problem errorneous - octet %u\n",
- (u_int32_t)ntohl(dp->icmp6_pptr));
+ printf("icmp6: parameter problem errorneous - octet %u",
+ EXTRACT_32BITS(&dp->icmp6_pptr));
break;
case ICMP6_PARAMPROB_NEXTHEADER:
- printf("icmp6: parameter problem next header - octet %u\n",
- (u_int32_t)ntohl(dp->icmp6_pptr));
+ printf("icmp6: parameter problem next header - octet %u",
+ EXTRACT_32BITS(&dp->icmp6_pptr));
break;
case ICMP6_PARAMPROB_OPTION:
- printf("icmp6: parameter problem option - octet %u\n",
- (u_int32_t)ntohl(dp->icmp6_pptr));
+ printf("icmp6: parameter problem option - octet %u",
+ EXTRACT_32BITS(&dp->icmp6_pptr));
break;
default:
printf("icmp6: parameter problem code-#%d",
}
break;
case ICMP6_ECHO_REQUEST:
- printf("icmp6: echo request");
- break;
case ICMP6_ECHO_REPLY:
- printf("icmp6: echo reply");
+ TCHECK(dp->icmp6_seq);
+ printf("icmp6: echo %s seq %u",
+ dp->icmp6_type == ICMP6_ECHO_REQUEST ?
+ "request" : "reply",
+ EXTRACT_16BITS(&dp->icmp6_seq));
break;
case ICMP6_MEMBERSHIP_QUERY:
printf("icmp6: multicast listener query ");
- mld6_print((const u_char *)dp);
+ if (length == MLD_MINLEN) {
+ mld6_print((const u_char *)dp);
+ } else if (length >= MLDV2_MINLEN) {
+ printf("v2 ");
+ mldv2_query_print((const u_char *)dp, length);
+ } else {
+ printf(" unknown-version(len=%d) ", length);
+ }
break;
case ICMP6_MEMBERSHIP_REPORT:
printf("icmp6: multicast listener report ");
printf("icmp6: router solicitation ");
if (vflag) {
#define RTSOLLEN 8
- icmp6_opt_print((const u_char *)dp + RTSOLLEN,
- icmp6len - RTSOLLEN);
+ icmp6_opt_print((const u_char *)dp + RTSOLLEN,
+ length - RTSOLLEN);
}
break;
case ND_ROUTER_ADVERT:
printf("M");
if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
printf("O");
- if (p->nd_ra_flags_reserved != 0)
+ if (p->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT)
+ printf("H");
+
+ if ((p->nd_ra_flags_reserved & ~ND_RA_FLAG_RTPREF_MASK)
+ != 0)
printf(" ");
- printf("router_ltime=%d, ", ntohs(p->nd_ra_router_lifetime));
+
+ printf("pref=%s, ",
+ get_rtpref(p->nd_ra_flags_reserved));
+
+ printf("router_ltime=%d, ", EXTRACT_16BITS(&p->nd_ra_router_lifetime));
printf("reachable_time=%u, ",
- (u_int32_t)ntohl(p->nd_ra_reachable));
+ EXTRACT_32BITS(&p->nd_ra_reachable));
printf("retrans_time=%u)",
- (u_int32_t)ntohl(p->nd_ra_retransmit));
+ EXTRACT_32BITS(&p->nd_ra_retransmit));
#define RTADVLEN 16
- icmp6_opt_print((const u_char *)dp + RTADVLEN,
- icmp6len - RTADVLEN);
+ icmp6_opt_print((const u_char *)dp + RTADVLEN,
+ length - RTADVLEN);
}
break;
case ND_NEIGHBOR_SOLICIT:
ip6addr_string(&p->nd_ns_target));
if (vflag) {
#define NDSOLLEN 24
- icmp6_opt_print((const u_char *)dp + NDSOLLEN,
- icmp6len - NDSOLLEN);
+ icmp6_opt_print((const u_char *)dp + NDSOLLEN,
+ length - NDSOLLEN);
}
}
break;
TCHECK(p->nd_na_target);
printf("icmp6: neighbor adv: tgt is %s",
ip6addr_string(&p->nd_na_target));
- if (vflag) {
+ if (vflag) {
#define ND_NA_FLAG_ALL \
(ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE)
/* we don't need ntohl() here. see advanced-api-04. */
printf(")");
}
#define NDADVLEN 24
- icmp6_opt_print((const u_char *)dp + NDADVLEN,
- icmp6len - NDADVLEN);
+ icmp6_opt_print((const u_char *)dp + NDADVLEN,
+ length - NDADVLEN);
+#undef NDADVLEN
}
}
break;
case ND_REDIRECT:
- {
#define RDR(i) ((struct nd_redirect *)(i))
- char tgtbuf[INET6_ADDRSTRLEN], dstbuf[INET6_ADDRSTRLEN];
-
TCHECK(RDR(dp)->nd_rd_dst);
- inet_ntop(AF_INET6, &RDR(dp)->nd_rd_target,
- tgtbuf, INET6_ADDRSTRLEN);
- inet_ntop(AF_INET6, &RDR(dp)->nd_rd_dst,
- dstbuf, INET6_ADDRSTRLEN);
- printf("icmp6: redirect %s to %s", dstbuf, tgtbuf);
+ printf("icmp6: redirect %s",
+ getname6((const u_char *)&RDR(dp)->nd_rd_dst));
+ TCHECK(RDR(dp)->nd_rd_target);
+ printf(" to %s",
+ getname6((const u_char*)&RDR(dp)->nd_rd_target));
#define REDIRECTLEN 40
if (vflag) {
icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
- icmp6len - REDIRECTLEN);
+ length - REDIRECTLEN);
}
break;
- }
+#undef REDIRECTLEN
+#undef RDR
case ICMP6_ROUTER_RENUMBERING:
- switch (dp->icmp6_code) {
- case ICMP6_ROUTER_RENUMBERING_COMMAND:
- printf("icmp6: router renum command");
- break;
- case ICMP6_ROUTER_RENUMBERING_RESULT:
- printf("icmp6: router renum result");
- break;
- default:
- printf("icmp6: router renum code-#%d", dp->icmp6_code);
- break;
- }
+ icmp6_rrenum_print(bp, ep);
break;
-#ifdef ICMP6_WRUREQUEST
- case ICMP6_WRUREQUEST: /*ICMP6_FQDN_QUERY*/
- {
- int siz;
- siz = ep - (u_char *)(dp + 1);
- if (siz == 4)
- printf("icmp6: who-are-you request");
- else {
- printf("icmp6: FQDN request");
- if (vflag) {
- if (siz < 8)
- printf("?(icmp6_data %d bytes)", siz);
- else if (8 < siz)
- printf("?(extra %d bytes)", siz - 8);
- }
+ case ICMP6_NI_QUERY:
+ case ICMP6_NI_REPLY:
+ icmp6_nodeinfo_print(length, bp, ep);
+ break;
+ case IND_SOLICIT:
+ printf("icmp6: inverse neighbor solicitation");
+ break;
+ case IND_ADVERT:
+ printf("icmp6: inverse neighbor advertisement");
+ break;
+ case ICMP6_V2_MEMBERSHIP_REPORT:
+ printf("icmp6: multicast listener report v2 ");
+ mldv2_report_print((const u_char *) dp, length);
+ break;
+ case ICMP6_HADISCOV_REQUEST:
+ printf("icmp6: ha discovery request");
+ if (vflag) {
+ TCHECK(dp->icmp6_data16[0]);
+ printf("(id=%d)", EXTRACT_16BITS(&dp->icmp6_data16[0]));
}
break;
- }
-#endif /*ICMP6_WRUREQUEST*/
-#ifdef ICMP6_WRUREPLY
- case ICMP6_WRUREPLY: /*ICMP6_FQDN_REPLY*/
- {
- enum { UNKNOWN, WRU, FQDN } mode = UNKNOWN;
- u_char const *buf;
- u_char const *cp = NULL;
-
- buf = (u_char *)(dp + 1);
-
- /* fair guess */
- if (buf[12] == ep - buf - 13)
- mode = FQDN;
- else if (dp->icmp6_code == 1)
- mode = FQDN;
-
- /* wild guess */
- if (mode == UNKNOWN) {
- cp = buf + 4;
- while (cp < ep) {
- if (!isprint(*cp++))
- mode = FQDN;
+ case ICMP6_HADISCOV_REPLY:
+ printf("icmp6: ha discovery reply");
+ if (vflag) {
+ struct in6_addr *in6;
+ u_char *cp;
+
+ TCHECK(dp->icmp6_data16[0]);
+ printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0]));
+ cp = (u_char *)dp + length;
+ in6 = (struct in6_addr *)(dp + 1);
+ for (; (u_char *)in6 < cp; in6++) {
+ TCHECK(*in6);
+ printf(", %s", ip6addr_string(in6));
}
+ printf(")");
}
-#ifndef abs
-#define abs(a) ((0 < (a)) ? (a) : -(a))
-#endif
- if (mode == UNKNOWN && 2 < abs(buf[12] - (ep - buf - 13)))
- mode = WRU;
- if (mode == UNKNOWN)
- mode = FQDN;
-
- if (mode == WRU) {
- cp = buf + 4;
- printf("icmp6: who-are-you reply(\"");
- } else if (mode == FQDN) {
- cp = buf + 13;
- printf("icmp6: FQDN reply(\"");
+ break;
+ case ICMP6_MOBILEPREFIX_SOLICIT:
+ printf("icmp6: mobile router solicitation");
+ if (vflag) {
+ TCHECK(dp->icmp6_data16[0]);
+ printf("(id=%d)", EXTRACT_16BITS(&dp->icmp6_data16[0]));
}
- for (; cp < ep; cp++)
- printf((isprint(*cp) ? "%c" : "\\%03o"), *cp);
- printf("\"");
+ break;
+ case ICMP6_MOBILEPREFIX_ADVERT:
+ printf("icmp6: mobile router advertisement");
if (vflag) {
- printf(",%s", mode == FQDN ? "FQDN" : "WRU");
- if (mode == FQDN) {
- long ttl;
- ttl = (long)ntohl(*(u_long *)&buf[8]);
- if (dp->icmp6_code == 1)
- printf(",TTL=unknown");
- else if (ttl < 0)
- printf(",TTL=%ld:invalid", ttl);
- else
- printf(",TTL=%ld", ttl);
- if (buf[12] != ep - buf - 13) {
- (void)printf(",invalid namelen:%d/%u",
- buf[12],
- (unsigned int)(ep - buf - 13));
- }
- }
+ TCHECK(dp->icmp6_data16[0]);
+ printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0]));
+ if (dp->icmp6_data16[1] & 0xc0)
+ printf(" ");
+ if (dp->icmp6_data16[1] & 0x80)
+ printf("M");
+ if (dp->icmp6_data16[1] & 0x40)
+ printf("O");
+ printf(")");
+#define MPADVLEN 8
+ icmp6_opt_print((const u_char *)dp + MPADVLEN,
+ length - MPADVLEN);
}
- printf(")");
break;
- }
-#endif /*ICMP6_WRUREPLY*/
default:
printf("icmp6: type-#%d", dp->icmp6_type);
break;
return;
trunc:
fputs("[|icmp6]", stdout);
-#if 0
-#undef TCHECK
-#endif
}
-void
-icmp6_opt_print(register const u_char *bp, int resid)
+static struct udphdr *
+get_upperlayer(u_char *bp, u_int *prot)
{
- register const struct nd_opt_hdr *op;
- register const struct nd_opt_hdr *opl; /* why there's no struct? */
- register const struct nd_opt_prefix_info *opp;
- register const struct icmp6_opts_redirect *opr;
- register const struct nd_opt_mtu *opm;
- register const u_char *ep;
- int opts_len;
-#if 0
- register const struct ip6_hdr *ip;
- register const char *str;
- register const struct ip6_hdr *oip;
- register const struct udphdr *ouh;
- register int hlen, dport;
- char buf[256];
-#endif
+ const u_char *ep;
+ struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
+ struct udphdr *uh;
+ struct ip6_hbh *hbh;
+ struct ip6_frag *fragh;
+ struct ah *ah;
+ u_int nh;
+ int hlen;
+
+ /* 'ep' points to the end of available data. */
+ ep = snapend;
+
+ if (!TTEST(ip6->ip6_nxt))
+ return NULL;
+
+ nh = ip6->ip6_nxt;
+ hlen = sizeof(struct ip6_hdr);
+
+ while (bp < snapend) {
+ bp += hlen;
+
+ switch(nh) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ uh = (struct udphdr *)bp;
+ if (TTEST(uh->uh_dport)) {
+ *prot = nh;
+ return(uh);
+ }
+ else
+ return(NULL);
+ /* NOTREACHED */
+
+ case IPPROTO_HOPOPTS:
+ case IPPROTO_DSTOPTS:
+ case IPPROTO_ROUTING:
+ hbh = (struct ip6_hbh *)bp;
+ if (!TTEST(hbh->ip6h_len))
+ return(NULL);
+ nh = hbh->ip6h_nxt;
+ hlen = (hbh->ip6h_len + 1) << 3;
+ break;
+
+ case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
+ fragh = (struct ip6_frag *)bp;
+ if (!TTEST(fragh->ip6f_offlg))
+ return(NULL);
+ /* fragments with non-zero offset are meaningless */
+ if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0)
+ return(NULL);
+ nh = fragh->ip6f_nxt;
+ hlen = sizeof(struct ip6_frag);
+ break;
+
+ case IPPROTO_AH:
+ ah = (struct ah *)bp;
+ if (!TTEST(ah->ah_len))
+ return(NULL);
+ nh = ah->ah_nxt;
+ hlen = (ah->ah_len + 2) << 2;
+ break;
+
+ default: /* unknown or undecodable header */
+ *prot = nh; /* meaningless, but set here anyway */
+ return(NULL);
+ }
+ }
+
+ return(NULL); /* should be notreached, though */
+}
+
+static void
+icmp6_opt_print(const u_char *bp, int resid)
+{
+ const struct nd_opt_hdr *op;
+ const struct nd_opt_hdr *opl; /* why there's no struct? */
+ const struct nd_opt_prefix_info *opp;
+ const struct icmp6_opts_redirect *opr;
+ const struct nd_opt_mtu *opm;
+ const struct nd_opt_advinterval *opa;
+ const struct nd_opt_homeagent_info *oph;
+ const struct nd_opt_route_info *opri;
+ const u_char *cp, *ep;
+ struct in6_addr in6, *in6p;
+ size_t l;
-#if 0
-#define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc
-#endif
#define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
- op = (struct nd_opt_hdr *)bp;
-#if 0
- ip = (struct ip6_hdr *)bp2;
- oip = &dp->icmp6_ip6;
- str = buf;
-#endif
- /* 'ep' points to the end of avaible data. */
+ cp = bp;
+ /* 'ep' points to the end of available data. */
ep = snapend;
- ECHECK(op->nd_opt_len);
- if (resid <= 0)
- return;
- switch(op->nd_opt_type) {
- case ND_OPT_SOURCE_LINKADDR:
- opl = (struct nd_opt_hdr *)op;
-#if 1
- if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
+ while (cp < ep) {
+ op = (struct nd_opt_hdr *)cp;
+
+ ECHECK(op->nd_opt_len);
+ if (resid <= 0)
+ return;
+ if (op->nd_opt_len == 0)
goto trunc;
-#else
- TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
-#endif
- printf("(src lladdr: %s",
- etheraddr_string((u_char *)(opl + 1)));
- if (opl->nd_opt_len != 1)
- printf("!");
- printf(")");
- icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
- resid - (op->nd_opt_len << 3));
- break;
- case ND_OPT_TARGET_LINKADDR:
- opl = (struct nd_opt_hdr *)op;
-#if 1
- if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
+ if (cp + (op->nd_opt_len << 3) > ep)
goto trunc;
-#else
- TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
-#endif
- printf("(tgt lladdr: %s",
- etheraddr_string((u_char *)(opl + 1)));
- if (opl->nd_opt_len != 1)
- printf("!");
- printf(")");
- icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
- resid - (op->nd_opt_len << 3));
- break;
- case ND_OPT_PREFIX_INFORMATION:
- opp = (struct nd_opt_prefix_info *)op;
- TCHECK(opp->nd_opt_pi_prefix);
- printf("(prefix info: ");
- if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
- printf("L");
- if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)
- printf("A");
- if (opp->nd_opt_pi_flags_reserved)
- printf(" ");
- printf("valid_ltime=");
- if ((u_int32_t)ntohl(opp->nd_opt_pi_valid_time) == ~0U)
- printf("infinity");
- else {
- printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_valid_time));
- }
- printf(", ");
- printf("preffered_ltime=");
- if ((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time) == ~0U)
- printf("infinity");
- else {
- printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_preferred_time));
+
+ switch (op->nd_opt_type) {
+ case ND_OPT_SOURCE_LINKADDR:
+ opl = (struct nd_opt_hdr *)op;
+ printf("(src lladdr: ");
+ l = (op->nd_opt_len << 3) - 2;
+ print_lladdr(cp + 2, l);
+ /*(*/
+ printf(")");
+ break;
+ case ND_OPT_TARGET_LINKADDR:
+ opl = (struct nd_opt_hdr *)op;
+ printf("(tgt lladdr: ");
+ l = (op->nd_opt_len << 3) - 2;
+ print_lladdr(cp + 2, l);
+ /*(*/
+ printf(")");
+ break;
+ case ND_OPT_PREFIX_INFORMATION:
+ opp = (struct nd_opt_prefix_info *)op;
+ TCHECK(opp->nd_opt_pi_prefix);
+ printf("(prefix info: "); /*)*/
+ if (op->nd_opt_len != 4) {
+ printf("badlen");
+ /*(*/
+ printf(")");
+ break;
+ }
+ if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
+ printf("L");
+ if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)
+ printf("A");
+ if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ROUTER)
+ printf("R");
+ if (opp->nd_opt_pi_flags_reserved)
+ printf(" ");
+ printf("valid_ltime=%s,",
+ get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time)));
+ printf("preferred_ltime=%s,",
+ get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time)));
+ printf("prefix=%s/%d",
+ ip6addr_string(&opp->nd_opt_pi_prefix),
+ opp->nd_opt_pi_prefix_len);
+ if (opp->nd_opt_pi_len != 4)
+ printf("!");
+ /*(*/
+ printf(")");
+ break;
+ case ND_OPT_REDIRECTED_HEADER:
+ opr = (struct icmp6_opts_redirect *)op;
+ printf("(redirect)");
+ /* xxx */
+ break;
+ case ND_OPT_MTU:
+ opm = (struct nd_opt_mtu *)op;
+ TCHECK(opm->nd_opt_mtu_mtu);
+ printf("(mtu:"); /*)*/
+ if (op->nd_opt_len != 1) {
+ printf("badlen");
+ /*(*/
+ printf(")");
+ break;
+ }
+ printf(" mtu=%u", EXTRACT_32BITS(&opm->nd_opt_mtu_mtu));
+ if (opm->nd_opt_mtu_len != 1)
+ printf("!");
+ printf(")");
+ break;
+ case ND_OPT_ADVINTERVAL:
+ opa = (struct nd_opt_advinterval *)op;
+ TCHECK(opa->nd_opt_adv_interval);
+ printf("(advint:"); /*)*/
+ printf(" advint=%u",
+ EXTRACT_32BITS(&opa->nd_opt_adv_interval));
+ /*(*/
+ printf(")");
+ break;
+ case ND_OPT_HOMEAGENT_INFO:
+ oph = (struct nd_opt_homeagent_info *)op;
+ TCHECK(oph->nd_opt_hai_lifetime);
+ printf("(ha info:"); /*)*/
+ printf(" pref=%d", EXTRACT_16BITS(&oph->nd_opt_hai_preference));
+ printf(", lifetime=%u", EXTRACT_16BITS(&oph->nd_opt_hai_lifetime));
+ printf(")");
+ break;
+ case ND_OPT_ROUTE_INFO:
+ opri = (struct nd_opt_route_info *)op;
+ TCHECK(opri->nd_opt_rti_lifetime);
+ memset(&in6, 0, sizeof(in6));
+ in6p = (struct in6_addr *)(opri + 1);
+ switch (op->nd_opt_len) {
+ case 1:
+ break;
+ case 2:
+ TCHECK2(*in6p, 8);
+ memcpy(&in6, opri + 1, 8);
+ break;
+ case 3:
+ TCHECK(*in6p);
+ memcpy(&in6, opri + 1, sizeof(in6));
+ break;
+ default:
+ goto trunc;
+ }
+ printf("(rtinfo:"); /*)*/
+ printf(" %s/%u", ip6addr_string(&in6),
+ opri->nd_opt_rti_prefixlen);
+ printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags));
+ printf(", lifetime=%s",
+ get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime)));
+ /*(*/
+ printf(")");
+ break;
+ default:
+ printf("(unknown opt_type=%d, opt_len=%d)",
+ op->nd_opt_type, op->nd_opt_len);
+ break;
}
- printf(", ");
- printf("prefix=%s/%d", ip6addr_string(&opp->nd_opt_pi_prefix),
- opp->nd_opt_pi_prefix_len);
- if (opp->nd_opt_pi_len != 4)
- printf("!");
- printf(")");
- icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
- resid - (op->nd_opt_len << 3));
- break;
- case ND_OPT_REDIRECTED_HEADER:
- opr = (struct icmp6_opts_redirect *)op;
- printf("(redirect)");
- /* xxx */
- icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
- resid - (op->nd_opt_len << 3));
- break;
- case ND_OPT_MTU:
- opm = (struct nd_opt_mtu *)op;
- TCHECK(opm->nd_opt_mtu_mtu);
- printf("(mtu: ");
- printf("mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu));
- if (opm->nd_opt_mtu_len != 1)
- printf("!");
- printf(")");
- icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
- resid - (op->nd_opt_len << 3));
- break;
- default:
- opts_len = op->nd_opt_len;
- printf("(unknwon opt_type=%d, opt_len=%d)",
- op->nd_opt_type, opts_len);
- if (opts_len == 0)
- opts_len = 1; /* XXX */
- icmp6_opt_print((const u_char *)op + (opts_len << 3),
- resid - (opts_len << 3));
- break;
+
+ cp += op->nd_opt_len << 3;
+ resid -= op->nd_opt_len << 3;
}
return;
+
trunc:
fputs("[ndp opt]", stdout);
return;
-#if 0
-#undef TCHECK
-#endif
#undef ECHECK
}
-void
-mld6_print(register const u_char *bp)
+static void
+mld6_print(const u_char *bp)
{
- register struct mld6_hdr *mp = (struct mld6_hdr *)bp;
- register const u_char *ep;
+ struct mld6_hdr *mp = (struct mld6_hdr *)bp;
+ const u_char *ep;
- /* 'ep' points to the end of avaible data. */
+ /* 'ep' points to the end of available data. */
ep = snapend;
if ((u_char *)mp + sizeof(*mp) > ep)
return;
- printf("max resp delay: %d ", ntohs(mp->mld6_maxdelay));
+ printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay));
printf("addr: %s", ip6addr_string(&mp->mld6_addr));
+}
+
+static void
+mldv2_report_print(const u_char *bp, u_int len)
+{
+ struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
+ u_int group, nsrcs, ngroups;
+ u_int i, j;
+
+ /* Minimum len is 8 */
+ if (len < 8) {
+ printf(" [invalid len %d]", len);
+ return;
+ }
+
+ TCHECK(icp->icmp6_data16[1]);
+ ngroups = ntohs(icp->icmp6_data16[1]);
+ printf(", %d group record(s)", ngroups);
+ if (vflag > 0) {
+ /* Print the group records */
+ group = 8;
+ for (i = 0; i < ngroups; i++) {
+ /* type(1) + auxlen(1) + numsrc(2) + grp(16) */
+ if (len < group + 20) {
+ printf(" [invalid number of groups]");
+ return;
+ }
+ TCHECK(bp[group + 4]);
+ printf(" [gaddr %s", ip6addr_string(&bp[group + 4]));
+ printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]",
+ bp[group]));
+ nsrcs = (bp[group + 2] << 8) + bp[group + 3];
+ /* Check the number of sources and print them */
+ if (len < group + 20 + (nsrcs * 16)) {
+ printf(" [invalid number of sources %d]", nsrcs);
+ return;
+ }
+ if (vflag == 1)
+ printf(", %d source(s)", nsrcs);
+ else {
+ /* Print the sources */
+ (void)printf(" {");
+ for (j = 0; j < nsrcs; j++) {
+ TCHECK2(bp[group + 20 + j * 16], 16);
+ printf(" %s", ip6addr_string(&bp[group + 20 + j * 16]));
+ }
+ (void)printf(" }");
+ }
+ /* Next group record */
+ group += 20 + nsrcs * 16;
+ printf("]");
+ }
+ }
+ return;
+trunc:
+ (void)printf("[|icmp6]");
+ return;
+}
+
+static void
+mldv2_query_print(const u_char *bp, u_int len)
+{
+ struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
+ u_int mrc;
+ int mrt, qqi;
+ u_int nsrcs;
+ register u_int i;
+
+ /* Minimum len is 28 */
+ if (len < 28) {
+ printf(" [invalid len %d]", len);
+ return;
+ }
+ TCHECK(icp->icmp6_data16[0]);
+ mrc = ntohs(icp->icmp6_data16[0]);
+ if (mrc < 32768) {
+ mrt = mrc;
+ } else {
+ mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3);
+ }
+ if (vflag) {
+ (void)printf(" [max resp delay=%d]", mrt);
+ }
+ printf(" [gaddr %s", ip6addr_string(&bp[8]));
+
+ if (vflag) {
+ TCHECK(bp[25]);
+ if (bp[24] & 0x08) {
+ printf(" sflag");
+ }
+ if (bp[24] & 0x07) {
+ printf(" robustness=%d", bp[24] & 0x07);
+ }
+ if (bp[25] < 128) {
+ qqi = bp[25];
+ } else {
+ qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3);
+ }
+ printf(" qqi=%d", qqi);
+ }
+
+ nsrcs = ntohs(*(u_short *)&bp[26]);
+ if (nsrcs > 0) {
+ if (len < 28 + nsrcs * 16)
+ printf(" [invalid number of sources]");
+ else if (vflag > 1) {
+ printf(" {");
+ for (i = 0; i < nsrcs; i++) {
+ TCHECK2(bp[28 + i * 16], 16);
+ printf(" %s", ip6addr_string(&bp[28 + i * 16]));
+ }
+ printf(" }");
+ } else
+ printf(", %d source(s)", nsrcs);
+ }
+ printf("]");
+ return;
+trunc:
+ (void)printf("[|icmp6]");
+ return;
+}
+
+void
+dnsname_print(const u_char *cp, const u_char *ep)
+{
+ int i;
+
+ /* DNS name decoding - no decompression */
+ printf(", \"");
+ while (cp < ep) {
+ i = *cp++;
+ if (i) {
+ if (i > ep - cp) {
+ printf("???");
+ break;
+ }
+ while (i-- && cp < ep) {
+ safeputchar(*cp);
+ cp++;
+ }
+ if (cp + 1 < ep && *cp)
+ printf(".");
+ } else {
+ if (cp == ep) {
+ /* FQDN */
+ printf(".");
+ } else if (cp + 1 == ep && *cp == '\0') {
+ /* truncated */
+ } else {
+ /* invalid */
+ printf("???");
+ }
+ break;
+ }
+ }
+ printf("\"");
+}
+
+static void
+icmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep)
+{
+ struct icmp6_nodeinfo *ni6;
+ struct icmp6_hdr *dp;
+ const u_char *cp;
+ size_t siz, i;
+ int needcomma;
+
+ if (ep < bp)
+ return;
+ dp = (struct icmp6_hdr *)bp;
+ ni6 = (struct icmp6_nodeinfo *)bp;
+ siz = ep - bp;
+
+ switch (ni6->ni_type) {
+ case ICMP6_NI_QUERY:
+ if (siz == sizeof(*dp) + 4) {
+ /* KAME who-are-you */
+ printf("icmp6: who-are-you request");
+ break;
+ }
+ printf("icmp6: node information query");
+
+ TCHECK2(*dp, sizeof(*ni6));
+ ni6 = (struct icmp6_nodeinfo *)dp;
+ printf(" ("); /*)*/
+ switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
+ case NI_QTYPE_NOOP:
+ printf("noop");
+ break;
+ case NI_QTYPE_SUPTYPES:
+ printf("supported qtypes");
+ i = EXTRACT_16BITS(&ni6->ni_flags);
+ if (i)
+ printf(" [%s]", (i & 0x01) ? "C" : "");
+ break;
+ break;
+ case NI_QTYPE_FQDN:
+ printf("DNS name");
+ break;
+ case NI_QTYPE_NODEADDR:
+ printf("node addresses");
+ i = ni6->ni_flags;
+ if (!i)
+ break;
+ /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
+ printf(" [%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" : "");
+ break;
+ default:
+ printf("unknown");
+ break;
+ }
+
+ if (ni6->ni_qtype == NI_QTYPE_NOOP ||
+ ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
+ if (siz != sizeof(*ni6))
+ if (vflag)
+ printf(", invalid len");
+ /*(*/
+ printf(")");
+ break;
+ }
+
+
+ /* XXX backward compat, icmp-name-lookup-03 */
+ if (siz == sizeof(*ni6)) {
+ printf(", 03 draft");
+ /*(*/
+ printf(")");
+ break;
+ }
+
+ switch (ni6->ni_code) {
+ case ICMP6_NI_SUBJ_IPV6:
+ if (!TTEST2(*dp,
+ sizeof(*ni6) + sizeof(struct in6_addr)))
+ break;
+ if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
+ if (vflag)
+ printf(", invalid subject len");
+ break;
+ }
+ printf(", subject=%s",
+ getname6((const u_char *)(ni6 + 1)));
+ break;
+ case ICMP6_NI_SUBJ_FQDN:
+ printf(", subject=DNS name");
+ cp = (const u_char *)(ni6 + 1);
+ if (cp[0] == ep - cp - 1) {
+ /* icmp-name-lookup-03, pascal string */
+ if (vflag)
+ printf(", 03 draft");
+ cp++;
+ printf(", \"");
+ while (cp < ep) {
+ safeputchar(*cp);
+ cp++;
+ }
+ printf("\"");
+ } else
+ dnsname_print(cp, ep);
+ break;
+ case ICMP6_NI_SUBJ_IPV4:
+ if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
+ break;
+ if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
+ if (vflag)
+ printf(", invalid subject len");
+ break;
+ }
+ printf(", subject=%s",
+ getname((const u_char *)(ni6 + 1)));
+ break;
+ default:
+ printf(", unknown subject");
+ break;
+ }
+
+ /*(*/
+ printf(")");
+ break;
+
+ case ICMP6_NI_REPLY:
+ if (icmp6len > siz) {
+ printf("[|icmp6: node information reply]");
+ break;
+ }
+
+ needcomma = 0;
+
+ ni6 = (struct icmp6_nodeinfo *)dp;
+ printf("icmp6: node information reply");
+ printf(" ("); /*)*/
+ switch (ni6->ni_code) {
+ case ICMP6_NI_SUCCESS:
+ if (vflag) {
+ printf("success");
+ needcomma++;
+ }
+ break;
+ case ICMP6_NI_REFUSED:
+ printf("refused");
+ needcomma++;
+ if (siz != sizeof(*ni6))
+ if (vflag)
+ printf(", invalid length");
+ break;
+ case ICMP6_NI_UNKNOWN:
+ printf("unknown");
+ needcomma++;
+ if (siz != sizeof(*ni6))
+ if (vflag)
+ printf(", invalid length");
+ break;
+ }
+
+ if (ni6->ni_code != ICMP6_NI_SUCCESS) {
+ /*(*/
+ printf(")");
+ break;
+ }
+
+ switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
+ case NI_QTYPE_NOOP:
+ if (needcomma)
+ printf(", ");
+ printf("noop");
+ if (siz != sizeof(*ni6))
+ if (vflag)
+ printf(", invalid length");
+ break;
+ case NI_QTYPE_SUPTYPES:
+ if (needcomma)
+ printf(", ");
+ printf("supported qtypes");
+ i = EXTRACT_16BITS(&ni6->ni_flags);
+ if (i)
+ printf(" [%s]", (i & 0x01) ? "C" : "");
+ break;
+ case NI_QTYPE_FQDN:
+ if (needcomma)
+ printf(", ");
+ printf("DNS name");
+ cp = (const u_char *)(ni6 + 1) + 4;
+ if (cp[0] == ep - cp - 1) {
+ /* icmp-name-lookup-03, pascal string */
+ if (vflag)
+ printf(", 03 draft");
+ cp++;
+ printf(", \"");
+ while (cp < ep) {
+ safeputchar(*cp);
+ cp++;
+ }
+ printf("\"");
+ } else
+ dnsname_print(cp, ep);
+ if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0)
+ printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
+ break;
+ case NI_QTYPE_NODEADDR:
+ if (needcomma)
+ printf(", ");
+ printf("node addresses");
+ i = sizeof(*ni6);
+ while (i < siz) {
+ if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
+ break;
+ printf(" %s", getname6(bp + i));
+ i += sizeof(struct in6_addr);
+ printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i));
+ i += sizeof(int32_t);
+ }
+ i = ni6->ni_flags;
+ if (!i)
+ break;
+ printf(" [%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;
+ default:
+ if (needcomma)
+ printf(", ");
+ printf("unknown");
+ break;
+ }
+
+ /*(*/
+ printf(")");
+ break;
+ }
+ return;
+
+trunc:
+ fputs("[|icmp6]", stdout);
+}
+
+static void
+icmp6_rrenum_print(const u_char *bp, const u_char *ep)
+{
+ struct icmp6_router_renum *rr6;
+ struct icmp6_hdr *dp;
+ size_t siz;
+ const char *cp;
+ struct rr_pco_match *match;
+ struct rr_pco_use *use;
+ char hbuf[NI_MAXHOST];
+ int n;
+
+ if (ep < bp)
+ return;
+ dp = (struct icmp6_hdr *)bp;
+ rr6 = (struct icmp6_router_renum *)bp;
+ siz = ep - bp;
+ cp = (const char *)(rr6 + 1);
+
+ TCHECK(rr6->rr_reserved);
+ switch (rr6->rr_code) {
+ case ICMP6_ROUTER_RENUMBERING_COMMAND:
+ printf("router renum: command");
+ break;
+ case ICMP6_ROUTER_RENUMBERING_RESULT:
+ printf("router renum: result");
+ break;
+ case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
+ printf("router renum: sequence number reset");
+ break;
+ default:
+ printf("router renum: code-#%d", rr6->rr_code);
+ break;
+ }
+
+ printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum));
+
+ if (vflag) {
+#define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "")
+ printf("["); /*]*/
+ if (rr6->rr_flags) {
+ printf("%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"));
+ }
+ printf("seg=%u,", rr6->rr_segnum);
+ printf("maxdelay=%u", rr6->rr_maxdelay);
+ if (rr6->rr_reserved)
+ printf("rsvd=0x%x", EXTRACT_16BITS(&rr6->rr_reserved));
+ /*[*/
+ printf("]");
+#undef F
+ }
+
+ if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
+ match = (struct rr_pco_match *)cp;
+ cp = (const char *)(match + 1);
+
+ TCHECK(match->rpm_prefix);
+
+ if (vflag > 1)
+ printf("\n\t");
+ else
+ printf(" ");
+ printf("match("); /*)*/
+ switch (match->rpm_code) {
+ case RPM_PCO_ADD: printf("add"); break;
+ case RPM_PCO_CHANGE: printf("change"); break;
+ case RPM_PCO_SETGLOBAL: printf("setglobal"); break;
+ default: printf("#%u", match->rpm_code); break;
+ }
+
+ if (vflag) {
+ printf(",ord=%u", match->rpm_ordinal);
+ printf(",min=%u", match->rpm_minlen);
+ printf(",max=%u", match->rpm_maxlen);
+ }
+ if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf)))
+ printf(",%s/%u", hbuf, match->rpm_matchlen);
+ else
+ printf(",?/%u", match->rpm_matchlen);
+ /*(*/
+ printf(")");
+
+ n = match->rpm_len - 3;
+ if (n % 4)
+ goto trunc;
+ n /= 4;
+ while (n-- > 0) {
+ use = (struct rr_pco_use *)cp;
+ cp = (const char *)(use + 1);
+
+ TCHECK(use->rpu_prefix);
+
+ if (vflag > 1)
+ printf("\n\t");
+ else
+ printf(" ");
+ printf("use("); /*)*/
+ if (use->rpu_flags) {
+#define F(x, y) ((use->rpu_flags) & (x) ? (y) : "")
+ printf("%s%s,",
+ F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
+ F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
+#undef F
+ }
+ if (vflag) {
+ printf("mask=0x%x,", use->rpu_ramask);
+ printf("raflags=0x%x,", use->rpu_raflags);
+ if (~use->rpu_vltime == 0)
+ printf("vltime=infty,");
+ else
+ printf("vltime=%u,",
+ EXTRACT_32BITS(&use->rpu_vltime));
+ if (~use->rpu_pltime == 0)
+ printf("pltime=infty,");
+ else
+ printf("pltime=%u,",
+ EXTRACT_32BITS(&use->rpu_pltime));
+ }
+ if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
+ sizeof(hbuf)))
+ printf("%s/%u/%u", hbuf, use->rpu_uselen,
+ use->rpu_keeplen);
+ else
+ printf("?/%u/%u", use->rpu_uselen,
+ use->rpu_keeplen);
+ /*(*/
+ printf(")");
+ }
+ }
return;
+
+trunc:
+ fputs("[|icmp6]", stdout);
}
+
#endif /* INET6 */