Upgrade tcpdump to tcpdump-4.99.1

Test: make
Change-Id: I052ed8f5279c806e4d2ff925f581b71db3ac03c0
diff --git a/print-ip6.c b/print-ip6.c
index a634d7b..525a284 100644
--- a/print-ip6.c
+++ b/print-ip6.c
@@ -22,10 +22,10 @@
 /* \summary: IPv6 printer */
 
 #ifdef HAVE_CONFIG_H
-#include "config.h"
+#include <config.h>
 #endif
 
-#include <netdissect-stdinc.h>
+#include "netdissect-stdinc.h"
 
 #include <string.h>
 
@@ -44,22 +44,23 @@
  * calculation.
  */
 static void
-ip6_finddst(netdissect_options *ndo, struct in6_addr *dst,
+ip6_finddst(netdissect_options *ndo, nd_ipv6 *dst,
             const struct ip6_hdr *ip6)
 {
 	const u_char *cp;
-	int advance;
+	u_int advance;
 	u_int nh;
-	const struct in6_addr *dst_addr;
+	const void *dst_addr;
 	const struct ip6_rthdr *dp;
 	const struct ip6_rthdr0 *dp0;
-	const struct in6_addr *addr;
+	const struct ip6_srh *srh;
+	const u_char *p;
 	int i, len;
 
 	cp = (const u_char *)ip6;
 	advance = sizeof(struct ip6_hdr);
-	nh = ip6->ip6_nxt;
-	dst_addr = &ip6->ip6_dst;
+	nh = GET_U_1(ip6->ip6_nxt);
+	dst_addr = (const void *)ip6->ip6_dst;
 
 	while (cp < ndo->ndo_snapend) {
 		cp += advance;
@@ -76,9 +77,8 @@
 			 * the header, in units of 8 octets, excluding
 			 * the first 8 octets.
 			 */
-			ND_TCHECK2(*cp, 2);
-			advance = (int)((*(cp + 1) + 1) << 3);
-			nh = *cp;
+			advance = (GET_U_1(cp + 1) + 1) << 3;
+			nh = GET_U_1(cp);
 			break;
 
 		case IPPROTO_FRAGMENT:
@@ -87,9 +87,8 @@
 			 * marked as reserved, and the header is always
 			 * the same size.
 			 */
-			ND_TCHECK2(*cp, 1);
 			advance = sizeof(struct ip6_frag);
-			nh = *cp;
+			nh = GET_U_1(cp);
 			break;
 
 		case IPPROTO_ROUTING:
@@ -97,9 +96,9 @@
 			 * OK, we found it.
 			 */
 			dp = (const struct ip6_rthdr *)cp;
-			ND_TCHECK(*dp);
-			len = dp->ip6r_len;
-			switch (dp->ip6r_type) {
+			ND_TCHECK_SIZE(dp);
+			len = GET_U_1(dp->ip6r_len);
+			switch (GET_U_1(dp->ip6r_type)) {
 
 			case IPV6_RTHDR_TYPE_0:
 			case IPV6_RTHDR_TYPE_2:		/* Mobile IPv6 ID-20 */
@@ -107,15 +106,26 @@
 				if (len % 2 == 1)
 					goto trunc;
 				len >>= 1;
-				addr = &dp0->ip6r0_addr[0];
+				p = (const u_char *) dp0->ip6r0_addr;
 				for (i = 0; i < len; i++) {
-					if ((const u_char *)(addr + 1) > ndo->ndo_snapend)
-						goto trunc;
-
-					dst_addr = addr;
-					addr++;
+					ND_TCHECK_16(p);
+					dst_addr = (const void *)p;
+					p += 16;
 				}
 				break;
+			case IPV6_RTHDR_TYPE_4:
+				/* IPv6 Segment Routing Header (SRH) */
+				srh = (const struct ip6_srh *)dp;
+				if (len % 2 == 1)
+					goto trunc;
+				p = (const u_char *) srh->srh_segments;
+				/*
+				 * The list of segments are encoded in the reverse order.
+				 * Accordingly, the final DA is encoded in srh_segments[0]
+				 */
+				ND_TCHECK_16(p);
+				dst_addr = (const void *)p;
+				break;
 
 			default:
 				break;
@@ -153,30 +163,32 @@
 
 done:
 trunc:
-	UNALIGNED_MEMCPY(dst, dst_addr, sizeof(struct in6_addr));
+	GET_CPY_BYTES(dst, dst_addr, sizeof(nd_ipv6));
 }
 
 /*
  * Compute a V6-style checksum by building a pseudoheader.
  */
-int
+uint16_t
 nextproto6_cksum(netdissect_options *ndo,
                  const struct ip6_hdr *ip6, const uint8_t *data,
-		 u_int len, u_int covlen, u_int next_proto)
+		 u_int len, u_int covlen, uint8_t next_proto)
 {
         struct {
-                struct in6_addr ph_src;
-                struct in6_addr ph_dst;
+                nd_ipv6 ph_src;
+                nd_ipv6 ph_dst;
                 uint32_t       ph_len;
                 uint8_t        ph_zero[3];
                 uint8_t        ph_nxt;
         } ph;
         struct cksum_vec vec[2];
+        u_int nh;
 
         /* pseudo-header */
         memset(&ph, 0, sizeof(ph));
-        UNALIGNED_MEMCPY(&ph.ph_src, &ip6->ip6_src, sizeof (struct in6_addr));
-        switch (ip6->ip6_nxt) {
+        GET_CPY_BYTES(&ph.ph_src, ip6->ip6_src, sizeof(nd_ipv6));
+        nh = GET_U_1(ip6->ip6_nxt);
+        switch (nh) {
 
         case IPPROTO_HOPOPTS:
         case IPPROTO_DSTOPTS:
@@ -193,7 +205,7 @@
                 break;
 
         default:
-                UNALIGNED_MEMCPY(&ph.ph_dst, &ip6->ip6_dst, sizeof (struct in6_addr));
+                GET_CPY_BYTES(&ph.ph_dst, ip6->ip6_dst, sizeof(nd_ipv6));
                 break;
         }
         ph.ph_len = htonl(len);
@@ -213,103 +225,146 @@
 void
 ip6_print(netdissect_options *ndo, const u_char *bp, u_int length)
 {
-	register const struct ip6_hdr *ip6;
-	register int advance;
+	const struct ip6_hdr *ip6;
+	int advance;
 	u_int len;
-	const u_char *ipend;
-	register const u_char *cp;
-	register u_int payload_len;
-	int nh;
+	u_int total_advance;
+	const u_char *cp;
+	uint32_t payload_len;
+	uint8_t nh;
 	int fragmented = 0;
 	u_int flow;
+	int found_extension_header;
+	int found_jumbo;
 
+	ndo->ndo_protocol = "ip6";
 	ip6 = (const struct ip6_hdr *)bp;
 
-	ND_TCHECK(*ip6);
+	ND_TCHECK_SIZE(ip6);
 	if (length < sizeof (struct ip6_hdr)) {
-		ND_PRINT((ndo, "truncated-ip6 %u", length));
+		ND_PRINT("truncated-ip6 %u", length);
 		return;
 	}
 
         if (!ndo->ndo_eflag)
-            ND_PRINT((ndo, "IP6 "));
+            ND_PRINT("IP6 ");
 
 	if (IP6_VERSION(ip6) != 6) {
-          ND_PRINT((ndo,"version error: %u != 6", IP6_VERSION(ip6)));
+          ND_PRINT("version error: %u != 6", IP6_VERSION(ip6));
           return;
 	}
 
-	payload_len = EXTRACT_16BITS(&ip6->ip6_plen);
-	len = payload_len + sizeof(struct ip6_hdr);
-	if (length < len)
-		ND_PRINT((ndo, "truncated-ip6 - %u bytes missing!",
-			len - length));
+	payload_len = GET_BE_U_2(ip6->ip6_plen);
+	/*
+	 * RFC 1883 says:
+	 *
+	 * The Payload Length field in the IPv6 header must be set to zero
+	 * in every packet that carries the Jumbo Payload option.  If a
+	 * packet is received with a valid Jumbo Payload option present and
+	 * a non-zero IPv6 Payload Length field, an ICMP Parameter Problem
+	 * message, Code 0, should be sent to the packet's source, pointing
+	 * to the Option Type field of the Jumbo Payload option.
+	 *
+	 * Later versions of the IPv6 spec don't discuss the Jumbo Payload
+	 * option.
+	 *
+	 * If the payload length is 0, we temporarily just set the total
+	 * length to the remaining data in the packet (which, for Ethernet,
+	 * could include frame padding, but if it's a Jumbo Payload frame,
+	 * it shouldn't even be sendable over Ethernet, so we don't worry
+	 * about that), so we can process the extension headers in order
+	 * to *find* a Jumbo Payload hop-by-hop option and, when we've
+	 * processed all the extension headers, check whether we found
+	 * a Jumbo Payload option, and fail if we haven't.
+	 */
+	if (payload_len != 0) {
+		len = payload_len + sizeof(struct ip6_hdr);
+		if (length < len)
+			ND_PRINT("truncated-ip6 - %u bytes missing!",
+				len - length);
+	} else
+		len = length + sizeof(struct ip6_hdr);
 
+        nh = GET_U_1(ip6->ip6_nxt);
         if (ndo->ndo_vflag) {
-            flow = EXTRACT_32BITS(&ip6->ip6_flow);
-            ND_PRINT((ndo, "("));
+            flow = GET_BE_U_4(ip6->ip6_flow);
+            ND_PRINT("(");
 #if 0
             /* rfc1883 */
             if (flow & 0x0f000000)
-		ND_PRINT((ndo, "pri 0x%02x, ", (flow & 0x0f000000) >> 24));
+		ND_PRINT("pri 0x%02x, ", (flow & 0x0f000000) >> 24);
             if (flow & 0x00ffffff)
-		ND_PRINT((ndo, "flowlabel 0x%06x, ", flow & 0x00ffffff));
+		ND_PRINT("flowlabel 0x%06x, ", flow & 0x00ffffff);
 #else
             /* RFC 2460 */
             if (flow & 0x0ff00000)
-		ND_PRINT((ndo, "class 0x%02x, ", (flow & 0x0ff00000) >> 20));
+		ND_PRINT("class 0x%02x, ", (flow & 0x0ff00000) >> 20);
             if (flow & 0x000fffff)
-		ND_PRINT((ndo, "flowlabel 0x%05x, ", flow & 0x000fffff));
+		ND_PRINT("flowlabel 0x%05x, ", flow & 0x000fffff);
 #endif
 
-            ND_PRINT((ndo, "hlim %u, next-header %s (%u) payload length: %u) ",
-                         ip6->ip6_hlim,
-                         tok2str(ipproto_values,"unknown",ip6->ip6_nxt),
-                         ip6->ip6_nxt,
-                         payload_len));
+            ND_PRINT("hlim %u, next-header %s (%u) payload length: %u) ",
+                         GET_U_1(ip6->ip6_hlim),
+                         tok2str(ipproto_values,"unknown",nh),
+                         nh,
+                         payload_len);
         }
 
 	/*
 	 * Cut off the snapshot length to the end of the IP payload.
 	 */
-	ipend = bp + len;
-	if (ipend < ndo->ndo_snapend)
-		ndo->ndo_snapend = ipend;
+	nd_push_snapend(ndo, bp + len);
 
 	cp = (const u_char *)ip6;
 	advance = sizeof(struct ip6_hdr);
-	nh = ip6->ip6_nxt;
+	total_advance = 0;
+	/* Process extension headers */
+	found_extension_header = 0;
+	found_jumbo = 0;
 	while (cp < ndo->ndo_snapend && advance > 0) {
 		if (len < (u_int)advance)
 			goto trunc;
 		cp += advance;
 		len -= advance;
+		total_advance += advance;
 
 		if (cp == (const u_char *)(ip6 + 1) &&
 		    nh != IPPROTO_TCP && nh != IPPROTO_UDP &&
 		    nh != IPPROTO_DCCP && nh != IPPROTO_SCTP) {
-			ND_PRINT((ndo, "%s > %s: ", ip6addr_string(ndo, &ip6->ip6_src),
-				     ip6addr_string(ndo, &ip6->ip6_dst)));
+			ND_PRINT("%s > %s: ", GET_IP6ADDR_STRING(ip6->ip6_src),
+				     GET_IP6ADDR_STRING(ip6->ip6_dst));
 		}
 
 		switch (nh) {
+
 		case IPPROTO_HOPOPTS:
-			advance = hbhopt_print(ndo, cp);
-			if (advance < 0)
+			advance = hbhopt_process(ndo, cp, &found_jumbo, &payload_len);
+			if (advance < 0) {
+				nd_pop_packet_info(ndo);
 				return;
-			nh = *cp;
+			}
+			found_extension_header = 1;
+			nh = GET_U_1(cp);
 			break;
+
 		case IPPROTO_DSTOPTS:
-			advance = dstopt_print(ndo, cp);
-			if (advance < 0)
+			advance = dstopt_process(ndo, cp);
+			if (advance < 0) {
+				nd_pop_packet_info(ndo);
 				return;
-			nh = *cp;
+			}
+			found_extension_header = 1;
+			nh = GET_U_1(cp);
 			break;
+
 		case IPPROTO_FRAGMENT:
 			advance = frag6_print(ndo, cp, (const u_char *)ip6);
-			if (advance < 0 || ndo->ndo_snapend <= cp + advance)
+			if (advance < 0 || ndo->ndo_snapend <= cp + advance) {
+				nd_pop_packet_info(ndo);
 				return;
-			nh = *cp;
+			}
+			found_extension_header = 1;
+			nh = GET_U_1(cp);
 			fragmented = 1;
 			break;
 
@@ -319,105 +374,110 @@
 			 * XXX - we don't use "advance"; RFC 3775 says that
 			 * the next header field in a mobility header
 			 * should be IPPROTO_NONE, but speaks of
-			 * the possiblity of a future extension in
+			 * the possibility of a future extension in
 			 * which payload can be piggybacked atop a
 			 * mobility header.
 			 */
 			advance = mobility_print(ndo, cp, (const u_char *)ip6);
-			if (advance < 0)
+			if (advance < 0) {
+				nd_pop_packet_info(ndo);
 				return;
-			nh = *cp;
+			}
+			found_extension_header = 1;
+			nh = GET_U_1(cp);
+			nd_pop_packet_info(ndo);
 			return;
+
 		case IPPROTO_ROUTING:
-			ND_TCHECK(*cp);
+			ND_TCHECK_1(cp);
 			advance = rt6_print(ndo, cp, (const u_char *)ip6);
-			if (advance < 0)
+			if (advance < 0) {
+				nd_pop_packet_info(ndo);
 				return;
-			nh = *cp;
+			}
+			found_extension_header = 1;
+			nh = GET_U_1(cp);
 			break;
-		case IPPROTO_SCTP:
-			sctp_print(ndo, cp, (const u_char *)ip6, len);
-			return;
-		case IPPROTO_DCCP:
-			dccp_print(ndo, cp, (const u_char *)ip6, len);
-			return;
-		case IPPROTO_TCP:
-			tcp_print(ndo, cp, len, (const u_char *)ip6, fragmented);
-			return;
-		case IPPROTO_UDP:
-			udp_print(ndo, cp, len, (const u_char *)ip6, fragmented);
-			return;
-		case IPPROTO_ICMPV6:
-			icmp6_print(ndo, cp, len, (const u_char *)ip6, fragmented);
-			return;
-		case IPPROTO_AH:
-			advance = ah_print(ndo, cp);
-			if (advance < 0)
-				return;
-			nh = *cp;
-			break;
-		case IPPROTO_ESP:
-		    {
-			int enh, padlen;
-			advance = esp_print(ndo, cp, len, (const u_char *)ip6, &enh, &padlen);
-			if (advance < 0)
-				return;
-			nh = enh & 0xff;
-			len -= padlen;
-			break;
-		    }
-		case IPPROTO_IPCOMP:
-		    {
-			ipcomp_print(ndo, cp);
-			/*
-			 * Either this has decompressed the payload and
-			 * printed it, in which case there's nothing more
-			 * to do, or it hasn't, in which case there's
-			 * nothing more to do.
-			 */
-			advance = -1;
-			break;
-		    }
-
-		case IPPROTO_PIM:
-			pim_print(ndo, cp, len, (const u_char *)ip6);
-			return;
-
-		case IPPROTO_OSPF:
-			ospf6_print(ndo, cp, len);
-			return;
-
-		case IPPROTO_IPV6:
-			ip6_print(ndo, cp, len);
-			return;
-
-		case IPPROTO_IPV4:
-		        ip_print(ndo, cp, len);
-			return;
-
-                case IPPROTO_PGM:
-                        pgm_print(ndo, cp, len, (const u_char *)ip6);
-                        return;
-
-		case IPPROTO_GRE:
-			gre_print(ndo, cp, len);
-			return;
-
-		case IPPROTO_RSVP:
-			rsvp_print(ndo, cp, len);
-			return;
-
-		case IPPROTO_NONE:
-			ND_PRINT((ndo, "no next header"));
-			return;
 
 		default:
-			ND_PRINT((ndo, "ip-proto-%d %d", nh, len));
+			/*
+			 * Not an extension header; hand off to the
+			 * IP protocol demuxer.
+			 */
+			if (found_jumbo) {
+				/*
+				 * We saw a Jumbo Payload option.
+				 * Set the length to the payload length
+				 * plus the IPv6 header length, and
+				 * change the snapshot length accordingly.
+				 *
+				 * But make sure it's not shorter than
+				 * the total number of bytes we've
+				 * processed so far.
+				 */
+				len = payload_len + sizeof(struct ip6_hdr);
+				if (len < total_advance)
+					goto trunc;
+				if (length < len)
+					ND_PRINT("truncated-ip6 - %u bytes missing!",
+						len - length);
+				nd_change_snapend(ndo, bp + len);
+
+				/*
+				 * Now subtract the length of the IPv6
+				 * header plus extension headers to get
+				 * the payload length.
+				 */
+				len -= total_advance;
+			} else {
+				/*
+				 * We didn't see a Jumbo Payload option;
+				 * was the payload length zero?
+				 */
+				if (payload_len == 0) {
+					/*
+					 * Yes.  If we found an extension
+					 * header, treat that as a truncated
+					 * packet header, as there was
+					 * no payload to contain an
+					 * extension header.
+					 */
+					if (found_extension_header)
+						goto trunc;
+
+					/*
+					 * OK, we didn't see any extnesion
+					 * header, but that means we have
+					 * no payload, so set the length
+					 * to the IPv6 header length,
+					 * and change the snapshot length
+					 * accordingly.
+					 */
+					len = sizeof(struct ip6_hdr);
+					nd_change_snapend(ndo, bp + len);
+
+					/*
+					 * Now subtract the length of
+					 * the IPv6 header plus extension
+					 * headers (there weren't any, so
+					 * that's just the IPv6 header
+					 * length) to get the payload length.
+					 */
+					len -= total_advance;
+				}
+			}
+			ip_demux_print(ndo, cp, len, 6, fragmented,
+				       GET_U_1(ip6->ip6_hlim), nh, bp);
+			nd_pop_packet_info(ndo);
 			return;
 		}
+
+		/* ndo_protocol reassignment after xxx_print() calls */
+		ndo->ndo_protocol = "ip6";
 	}
 
+	nd_pop_packet_info(ndo);
 	return;
 trunc:
-	ND_PRINT((ndo, "[|ip6]"));
+	nd_print_trunc(ndo);
 }