Update from 4.99.0 to 4.99.1

Bug: 90184

Change-Id: I0d2773f607c727c47fde4064d6ca78779aea6dca
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/github.com/the-tcpdump-group/tcpdump/+/617081
Fuchsia-Auto-Submit: Ghanan Gowripalan <ghanan@google.com>
Reviewed-by: Adam Perry <adamperry@google.com>
Commit-Queue: Auto-Submit <auto-submit@fuchsia-infra.iam.gserviceaccount.com>
Commit-Queue: Ghanan Gowripalan <ghanan@google.com>
diff --git a/README.md b/README.md
index 7e381e1..48445ae 100644
--- a/README.md
+++ b/README.md
@@ -1,80 +1,78 @@
-# tcpdump
+# TCPDUMP 4.x.y by [The Tcpdump Group](https://www.tcpdump.org/)
 
-[![Build Status](https://travis-ci.org/the-tcpdump-group/tcpdump.svg?branch=master)](https://travis-ci.org/the-tcpdump-group/tcpdump)
-
-[![Build Status](https://ci.appveyor.com/api/projects/status/github/the-tcpdump-group/tcpdump?branch=master&svg=true)](https://ci.appveyor.com/project/guyharris/tcpdump)
-
-To report a security issue please send an e-mail to security@tcpdump.org.
+**To report a security issue please send an e-mail to security@tcpdump.org.**
 
 To report bugs and other problems, contribute patches, request a
-feature, provide generic feedback etc please see the file
-CONTRIBUTING in the tcpdump source tree root.
+feature, provide generic feedback etc please see the
+[guidelines for contributing](CONTRIBUTING) in the tcpdump source tree root.
 
-TCPDUMP 4.x.y
-Now maintained by "The Tcpdump Group"
-See 		https://www.tcpdump.org
+Anonymous Git is available via
 
-Anonymous Git is available via:
-
-	git clone git://bpf.tcpdump.org/tcpdump
-
-formerly from 	Lawrence Berkeley National Laboratory
-		Network Research Group <tcpdump@ee.lbl.gov>
-		ftp://ftp.ee.lbl.gov/old/tcpdump.tar.Z (3.4)
+	https://github.com/the-tcpdump-group/tcpdump.git
 
 This directory contains source code for tcpdump, a tool for network
-monitoring and data acquisition.  This software was originally
-developed by the Network Research Group at the Lawrence Berkeley
-National Laboratory.  The original distribution is available via
-anonymous ftp to `ftp.ee.lbl.gov`, in `tcpdump.tar.Z`.  More recent
-development is performed at tcpdump.org, https://www.tcpdump.org/.
+monitoring and data acquisition.
 
+Over the past few years, tcpdump has been steadily improved by the
+excellent contributions from the Internet community (just browse
+through the [change log](CHANGES)).  We are grateful for all the input.
+
+### Supported platforms
+In many operating systems tcpdump is available as a native package or port,
+which simplifies installation of updates and long-term maintenance. However,
+the native packages are sometimes a few versions behind and to try a more
+recent snapshot it will take to compile tcpdump from the source code.
+
+tcpdump compiles and works on at least the following platforms:
+
+* AIX
+* DragonFly BSD
+* FreeBSD
+* Haiku
+* HP-UX 11i
+* GNU/Linux
+* {Mac} OS X / macOS
+* NetBSD
+* OpenBSD
+* OpenWrt
+* Solaris
+* Windows (requires WinPcap or Npcap, and Visual Studio with CMake)
+
+### Dependency on libpcap
 Tcpdump uses libpcap, a system-independent interface for user-level
 packet capture.  Before building tcpdump, you must first retrieve and
-build libpcap, also originally from LBL and now being maintained by
-tcpdump.org; see https://www.tcpdump.org/.
+build libpcap.
 
 Once libpcap is built (either install it or make sure it's in
-`../libpcap`), you can build tcpdump using the procedure in the `INSTALL.txt`
-file.
+`../libpcap`), you can build tcpdump using the procedure in the
+[installation guide](INSTALL.txt).
 
+### Origins of tcpdump
 The program is loosely based on SMI's "etherfind" although none of the
 etherfind code remains.  It was originally written by Van Jacobson as
-part of an ongoing research project to investigate and improve tcp and
-internet gateway performance.  The parts of the program originally
+part of an ongoing research project to investigate and improve TCP and
+Internet gateway performance.  The parts of the program originally
 taken from Sun's etherfind were later re-written by Steven McCanne of
 LBL.  To insure that there would be no vestige of proprietary code in
 tcpdump, Steve wrote these pieces from the specification given by the
 manual entry, with no access to the source of tcpdump or etherfind.
+```text
+formerly from 	Lawrence Berkeley National Laboratory
+		Network Research Group <tcpdump@ee.lbl.gov>
+		ftp://ftp.ee.lbl.gov/old/tcpdump.tar.Z (3.4)
+```
 
-Over the past few years, tcpdump has been steadily improved by the
-excellent contributions from the Internet community (just browse
-through the `CHANGES` file).  We are grateful for all the input.
-
+### See also
 Richard Stevens gives an excellent treatment of the Internet protocols
 in his book *"TCP/IP Illustrated, Volume 1"*. If you want to learn more
 about tcpdump and how to interpret its output, pick up this book.
 
-Some tools for viewing and analyzing tcpdump trace files are available
-from the Internet Traffic Archive:
-
-* http://ita.ee.lbl.gov/
-
-Another tool that tcpdump users might find useful is tcpslice:
-
-* https://github.com/the-tcpdump-group/tcpslice
-
+Another tool that tcpdump users might find useful is
+[tcpslice](https://github.com/the-tcpdump-group/tcpslice).
 It is a program that can be used to extract portions of tcpdump binary
-trace files. See the above distribution for further details and
-documentation.
+trace files.
 
-Current versions can be found at https://www.tcpdump.org.
-
- - The TCPdump group
-
-original text by: Steve McCanne, Craig Leres, Van Jacobson
-
--------------------------------------
+### The original LBL README by Steve McCanne, Craig Leres and Van Jacobson
 ```
 This directory also contains some short awk programs intended as
 examples of ways to reduce tcpdump data when you're tracking
diff --git a/VERSION b/VERSION
index 60f4637..6cda521 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-4.99.0
+4.99.1
diff --git a/addrtoname.c b/addrtoname.c
index 33b9378..58ced4f 100644
--- a/addrtoname.c
+++ b/addrtoname.c
@@ -77,6 +77,7 @@
         #define NEED_NETINET_IF_ETHER_H
       #else /* HAVE_STRUCT_ETHER_ADDR */
 	struct ether_addr {
+		/* Beware FreeBSD calls this "octet". */
 		unsigned char ether_addr_octet[MAC_ADDR_LEN];
 	};
       #endif /* HAVE_STRUCT_ETHER_ADDR */
@@ -601,8 +602,15 @@
 #ifdef USE_ETHER_NTOHOST
 	if (!ndo->ndo_nflag) {
 		char buf2[BUFSIZE];
+		/*
+		 * This is a non-const copy of ep for ether_ntohost(), which
+		 * has its second argument non-const in OpenBSD. Also saves a
+		 * type cast.
+		 */
+		struct ether_addr ea;
 
-		if (ether_ntohost(buf2, (const struct ether_addr *)ep) == 0) {
+		memcpy (&ea, ep, MAC_ADDR_LEN);
+		if (ether_ntohost(buf2, &ea) == 0) {
 			tp->e_name = strdup(buf2);
 			if (tp->e_name == NULL)
 				(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
@@ -977,7 +985,10 @@
 		/*
 		 * Use YP/NIS version of name if available.
 		 */
-		if (ether_ntohost(name, (const struct ether_addr *)el->addr) == 0) {
+		/* Same workaround as in etheraddr_string(). */
+		struct ether_addr ea;
+		memcpy (&ea, el->addr, MAC_ADDR_LEN);
+		if (ether_ntohost(name, &ea) == 0) {
 			tp->e_name = strdup(name);
 			if (tp->e_name == NULL)
 				(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
diff --git a/bpf_dump.c b/bpf_dump.c
index 7cfe49a..1ac74a2 100644
--- a/bpf_dump.c
+++ b/bpf_dump.c
@@ -28,6 +28,7 @@
 #include <stdio.h>
 
 #include "netdissect.h"
+#include "interface.h"
 
 void
 bpf_dump(const struct bpf_program *p, int option)
diff --git a/netdissect-stdinc.h b/netdissect-stdinc.h
index 0639b88..0523620 100644
--- a/netdissect-stdinc.h
+++ b/netdissect-stdinc.h
@@ -39,6 +39,8 @@
 #ifndef netdissect_stdinc_h
 #define netdissect_stdinc_h
 
+#include "ftmacros.h"
+
 #include <errno.h>
 
 #include "compiler-tests.h"
diff --git a/netdissect.h b/netdissect.h
index 8595287..0e6557f 100644
--- a/netdissect.h
+++ b/netdissect.h
@@ -99,7 +99,7 @@
 /*
  * Use this for MAC addresses.
  */
-#define MAC_ADDR_LEN	6		/* length of MAC addresses */
+#define MAC_ADDR_LEN	6U		/* length of MAC addresses */
 typedef unsigned char nd_mac_addr[MAC_ADDR_LEN];
 
 /*
@@ -391,7 +391,6 @@
 
 extern void fn_print_char(netdissect_options *, u_char);
 extern void fn_print_str(netdissect_options *, const u_char *);
-extern int nd_print(netdissect_options *, const u_char *, const u_char *);
 extern u_int nd_printztn(netdissect_options *, const u_char *, u_int, const u_char *);
 extern int nd_printn(netdissect_options *, const u_char *, u_int, const u_char *);
 extern void nd_printjnp(netdissect_options *, const u_char *, u_int);
@@ -704,12 +703,12 @@
 extern int vjc_print(netdissect_options *, const u_char *, u_short);
 extern void vqp_print(netdissect_options *, const u_char *, u_int);
 extern void vrrp_print(netdissect_options *, const u_char *, u_int, const u_char *, int);
-extern void vtp_print(netdissect_options *, const u_char *, u_int);
+extern void vtp_print(netdissect_options *, const u_char *, const u_int);
 extern void vxlan_gpe_print(netdissect_options *, const u_char *, u_int);
 extern void vxlan_print(netdissect_options *, const u_char *, u_int);
 extern void wb_print(netdissect_options *, const u_char *, u_int);
 extern void zep_print(netdissect_options *, const u_char *, u_int);
-extern void zephyr_print(netdissect_options *, const u_char *, int);
+extern void zephyr_print(netdissect_options *, const u_char *, u_int);
 extern void zmtp1_print(netdissect_options *, const u_char *, u_int);
 extern void zmtp1_datagram_print(netdissect_options *, const u_char *, const u_int);
 extern void someip_print(netdissect_options *, const u_char *, const u_int);
diff --git a/print-802_15_4.c b/print-802_15_4.c
index d337164..5687d45 100644
--- a/print-802_15_4.c
+++ b/print-802_15_4.c
@@ -28,6 +28,7 @@
 
 #include "netdissect-stdinc.h"
 
+#define ND_LONGJMP_FROM_TCHECK
 #include "netdissect.h"
 #include "addrtoname.h"
 
@@ -2020,6 +2021,7 @@
 		if (len < 0) {
 			return 0;
 		}
+		ND_TCHECK_LEN(p, len);
 		p += len;
 		caplen -= len;
 	} else {
@@ -2138,6 +2140,7 @@
 				if (len < 0) {
 					break;
 				}
+				ND_TCHECK_LEN(p, len);
 				p += len;
 				caplen -= len;
 			}
@@ -2331,6 +2334,7 @@
 		if (len < 0) {
 			return 0;
 		}
+		ND_TCHECK_LEN(p, len);
 		p += len;
 		caplen -= len;
 	} else {
diff --git a/print-aoe.c b/print-aoe.c
index c4f3758..0cd4299 100644
--- a/print-aoe.c
+++ b/print-aoe.c
@@ -270,7 +270,7 @@
 	cp += 1;
 	len -= 1;
 	ND_PRINT(", Dir Count: %u", dircount);
-	if (dircount * 8 > len)
+	if (dircount * 8U > len)
 		goto invalid;
 	/* directives */
 	for (i = 0; i < dircount; i++) {
diff --git a/print-arp.c b/print-arp.c
index 4855332..7d3efe7 100644
--- a/print-arp.c
+++ b/print-arp.c
@@ -424,8 +424,16 @@
 		break;
 
 	case ARPOP_REVREQUEST:
-		ND_PRINT("who-is %s tell %s",
-			  GET_LINKADDR_STRING(THA(ap), linkaddr, HRD_LEN(ap)),
+		/*
+		 * XXX - GET_LINKADDR_STRING() may return a pointer to
+		 * a static buffer, so we only have one call to it per
+		 * ND_PRINT() call.
+		 *
+		 * This should be done in a cleaner fashion.
+		 */
+		ND_PRINT("who-is %s",
+			  GET_LINKADDR_STRING(THA(ap), linkaddr, HRD_LEN(ap)));
+		ND_PRINT(" tell %s",
 			  GET_LINKADDR_STRING(SHA(ap), linkaddr, HRD_LEN(ap)));
 		break;
 
@@ -436,8 +444,16 @@
 		break;
 
 	case ARPOP_INVREQUEST:
-		ND_PRINT("who-is %s tell %s",
-			  GET_LINKADDR_STRING(THA(ap), linkaddr, HRD_LEN(ap)),
+		/*
+		 * XXX - GET_LINKADDR_STRING() may return a pointer to
+		 * a static buffer, so we only have one call to it per
+		 * ND_PRINT() call.
+		 *
+		 * This should be done in a cleaner fashion.
+		 */
+		ND_PRINT("who-is %s",
+			  GET_LINKADDR_STRING(THA(ap), linkaddr, HRD_LEN(ap)));
+		ND_PRINT(" tell %s",
 			  GET_LINKADDR_STRING(SHA(ap), linkaddr, HRD_LEN(ap)));
 		break;
 
diff --git a/print-ascii.c b/print-ascii.c
index e5b7a58..2f5fe85 100644
--- a/print-ascii.c
+++ b/print-ascii.c
@@ -64,11 +64,14 @@
 {
 	u_int caplength;
 	u_char s;
+	int truncated = FALSE;
 
 	ndo->ndo_protocol = "ascii";
 	caplength = (ndo->ndo_snapend > cp) ? ND_BYTES_AVAILABLE_AFTER(cp) : 0;
-	if (length > caplength)
+	if (length > caplength) {
 		length = caplength;
+		truncated = TRUE;
+	}
 	ND_PRINT("\n");
 	while (length > 0) {
 		s = GET_U_1(cp);
@@ -94,6 +97,8 @@
 				ND_PRINT("%c", s);
 		}
 	}
+	if (truncated)
+		nd_trunc_longjmp(ndo);
 }
 
 static void
@@ -104,12 +109,15 @@
 	u_int i;
 	u_int s1, s2;
 	u_int nshorts;
+	int truncated = FALSE;
 	char hexstuff[HEXDUMP_SHORTS_PER_LINE*HEXDUMP_HEXSTUFF_PER_SHORT+1], *hsp;
 	char asciistuff[ASCII_LINELENGTH+1], *asp;
 
 	caplength = (ndo->ndo_snapend > cp) ? ND_BYTES_AVAILABLE_AFTER(cp) : 0;
-	if (length > caplength)
+	if (length > caplength) {
 		length = caplength;
+		truncated = TRUE;
+	}
 	nshorts = length / sizeof(u_short);
 	i = 0;
 	hsp = hexstuff; asp = asciistuff;
@@ -149,6 +157,8 @@
 		     ident, oset, HEXDUMP_HEXSTUFF_PER_LINE,
 		     hexstuff, asciistuff);
 	}
+	if (truncated)
+		nd_trunc_longjmp(ndo);
 }
 
 void
@@ -169,10 +179,13 @@
 	u_int caplength;
 	u_int i, s;
 	u_int nshorts;
+	int truncated = FALSE;
 
 	caplength = (ndo->ndo_snapend > cp) ? ND_BYTES_AVAILABLE_AFTER(cp) : 0;
-	if (length > caplength)
+	if (length > caplength) {
 		length = caplength;
+		truncated = TRUE;
+	}
 	nshorts = length / sizeof(u_short);
 	i = 0;
 	while (nshorts != 0) {
@@ -191,15 +204,15 @@
 			ND_PRINT("%s0x%04x: ", ident, oset);
 		ND_PRINT(" %02x", GET_U_1(cp));
 	}
+	if (truncated)
+		nd_trunc_longjmp(ndo);
 }
 
-/*
- * just for completeness
- */
 void
-hex_print(netdissect_options *ndo,const char *ident, const u_char *cp, u_int length)
+hex_print(netdissect_options *ndo,
+	  const char *ident, const u_char *cp, u_int length)
 {
-  hex_print_with_offset(ndo, ident, cp, length, 0);
+	hex_print_with_offset(ndo, ident, cp, length, 0);
 }
 
 #ifdef MAIN
diff --git a/print-bgp.c b/print-bgp.c
index 5de1003..c905107 100644
--- a/print-bgp.c
+++ b/print-bgp.c
@@ -557,8 +557,7 @@
     { 0, NULL },
 };
 
-/* allocate space for the largest possible string */
-static char astostr[sizeof("xxxxx.xxxxx")];
+#define AS_STR_SIZE sizeof("xxxxx.xxxxx")
 
 /*
  * as_printf
@@ -598,20 +597,16 @@
 
     memset(&addr, 0, sizeof(addr));
     plenbytes = (plen + 7) / 8;
-    ND_TCHECK_LEN(pptr + 1, plenbytes);
     ITEMCHECK(plenbytes);
-    memcpy(&addr, pptr + 1, plenbytes);
+    GET_CPY_BYTES(&addr, pptr + 1, plenbytes);
     if (plen % 8) {
         ((u_char *)&addr)[plenbytes - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
     }
     snprintf(buf, buflen, "%s/%u", ipaddr_string(ndo, (const u_char *)&addr), plen);
     return 1 + plenbytes;
 
-trunc:
-    return -2;
-
 badtlv:
-    return -3;
+    return -2;
 }
 
 static int
@@ -646,9 +641,8 @@
 
     memset(&addr, 0, sizeof(addr));
     plenbytes = (plen + 7) / 8;
-    ND_TCHECK_LEN(pptr + 4, plenbytes);
     ITEMCHECK(plenbytes);
-    memcpy(&addr, pptr + 4, plenbytes);
+    GET_CPY_BYTES(&addr, pptr + 4, plenbytes);
     if (plen % 8) {
         ((u_char *)&addr)[plenbytes - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
     }
@@ -766,6 +760,8 @@
     /* allocate space for the largest possible string */
     static char rd[sizeof("xxxxx.xxxxx:xxxxx (xxx.xxx.xxx.xxx:xxxxx)")];
     char *pos = rd;
+    /* allocate space for the largest possible string */
+    char astostr[AS_STR_SIZE];
 
     /* ok lets load the RD format */
     switch (GET_BE_U_2(pptr)) {
@@ -815,6 +811,8 @@
         float f;
         uint32_t i;
     } bw;
+    /* allocate space for the largest possible string */
+    char astostr[AS_STR_SIZE];
 
     switch (GET_BE_U_2(pptr)) {
 
@@ -920,6 +918,8 @@
     char rtc_prefix_in_hex[20] = "";
     u_int rtc_prefix_in_hex_len = 0;
     static char output[61]; /* max response string */
+    /* allocate space for the largest possible string */
+    char astostr[AS_STR_SIZE];
     uint16_t ec_type = 0;
     u_int octet_count;
     u_int i;
@@ -993,7 +993,8 @@
 {
     uint8_t route_target[8];
     u_int plen;
-    char asbuf[sizeof(astostr)]; /* bgp_vpn_rd_print() overwrites astostr */
+    /* allocate space for the largest possible string */
+    char astostr[AS_STR_SIZE];
     u_int num_octets;
 
     /* NLRI "prefix length" from RFC 2858 Section 4. */
@@ -1015,7 +1016,7 @@
     }
 
     /* With at least "origin AS", possibly with "route target". */
-    as_printf(ndo, asbuf, sizeof(asbuf), GET_BE_U_4(pptr + 1));
+    as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_4(pptr + 1));
 
     plen -= 32; /* adjust prefix length */
 
@@ -1030,20 +1031,17 @@
      */
     memset(&route_target, 0, sizeof(route_target));
     num_octets = (plen + 7) / 8;
-    ND_TCHECK_LEN(pptr + 5, num_octets);
-    memcpy(&route_target, pptr + 5, num_octets);
+    GET_CPY_BYTES(&route_target, pptr + 5, num_octets);
     /* If mask-len is not on octet boundary, ensure all extra bits are 0 */
     if (plen % 8) {
         ((u_char *)&route_target)[num_octets - 1] &=
             ((0xff00 >> (plen % 8)) & 0xff);
     }
     ND_PRINT("\n\t      origin AS: %s, %s",
-             asbuf,
+             astostr,
              bgp_rt_prefix_print(ndo, (u_char *)&route_target, plen));
 
     return 5 + num_octets;
-trunc:
-    return -2;
 }
 
 static int
@@ -1064,8 +1062,7 @@
         return -1;
 
     memset(&addr, 0, sizeof(addr));
-    ND_TCHECK_LEN(pptr + 12, (plen + 7) / 8);
-    memcpy(&addr, pptr + 12, (plen + 7) / 8);
+    GET_CPY_BYTES(&addr, pptr + 12, (plen + 7) / 8);
     if (plen % 8) {
         ((u_char *)&addr)[(plen + 7) / 8 - 1] &=
             ((0xff00 >> (plen % 8)) & 0xff);
@@ -1079,9 +1076,6 @@
                 ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
 
     return 12 + (plen + 7) / 8;
-
-trunc:
-    return -2;
 }
 
 /*
@@ -1150,6 +1144,8 @@
 decode_multicast_vpn(netdissect_options *ndo,
                      const u_char *pptr, char *buf, size_t buflen)
 {
+    /* allocate space for the largest possible string */
+    char astostr[AS_STR_SIZE];
     uint8_t route_type, route_length;
     u_int addr_length, sg_length;
     u_int offset;
@@ -1381,9 +1377,8 @@
 
     memset(&addr, 0, sizeof(addr));
     plenbytes = (plen + 7) / 8;
-    ND_TCHECK_LEN(pd + 1, plenbytes);
     ITEMCHECK(plenbytes);
-    memcpy(&addr, pd + 1, plenbytes);
+    GET_CPY_BYTES(&addr, pd + 1, plenbytes);
     if (plen % 8) {
         addr[plenbytes - 1] &=
             ((0xff00 >> (plen % 8)) & 0xff);
@@ -1391,11 +1386,8 @@
     snprintf(buf, buflen, "%s/%u", ip6addr_string(ndo, (const u_char *)&addr), plen);
     return 1 + plenbytes;
 
-trunc:
-    return -2;
-
 badtlv:
-    return -3;
+    return -2;
 }
 
 static int
@@ -1421,8 +1413,7 @@
 
     memset(&addr, 0, sizeof(addr));
     plenbytes = (plen + 7) / 8;
-    ND_TCHECK_LEN(pptr + 4, plenbytes);
-    memcpy(&addr, pptr + 4, plenbytes);
+    GET_CPY_BYTES(&addr, pptr + 4, plenbytes);
     if (plen % 8) {
         addr[plenbytes - 1] &=
             ((0xff00 >> (plen % 8)) & 0xff);
@@ -1461,8 +1452,7 @@
         return -1;
 
     memset(&addr, 0, sizeof(addr));
-    ND_TCHECK_LEN(pptr + 12, (plen + 7) / 8);
-    memcpy(&addr, pptr + 12, (plen + 7) / 8);
+    GET_CPY_BYTES(&addr, pptr + 12, (plen + 7) / 8);
     if (plen % 8) {
         addr[(plen + 7) / 8 - 1] &=
             ((0xff00 >> (plen % 8)) & 0xff);
@@ -1476,9 +1466,6 @@
                 ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
 
     return 12 + (plen + 7) / 8;
-
-trunc:
-    return -2;
 }
 
 static int
@@ -1494,8 +1481,7 @@
         return -1;
 
     memset(&addr, 0, sizeof(addr));
-    ND_TCHECK_LEN(pptr + 4, (plen + 7) / 8);
-    memcpy(&addr, pptr + 4, (plen + 7) / 8);
+    GET_CPY_BYTES(&addr, pptr + 4, (plen + 7) / 8);
     if (plen % 8) {
         addr[(plen + 7) / 8 - 1] &=
             ((0xff00 >> (plen % 8)) & 0xff);
@@ -1506,9 +1492,6 @@
                 plen);
 
     return 1 + (plen + 7) / 8;
-
-trunc:
-    return -2;
 }
 
 static int
@@ -1529,8 +1512,7 @@
         return -1;
 
     memset(&addr, 0, sizeof(addr));
-    ND_TCHECK_LEN(pptr + 12, (plen + 7) / 8);
-    memcpy(&addr, pptr + 12, (plen + 7) / 8);
+    GET_CPY_BYTES(&addr, pptr + 12, (plen + 7) / 8);
     if (plen % 8) {
         addr[(plen + 7) / 8 - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
     }
@@ -1544,9 +1526,6 @@
                 ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
 
     return 12 + (plen + 7) / 8;
-
-trunc:
-    return -2;
 }
 
 /*
@@ -1753,8 +1732,6 @@
                 if (advance == -1)
                     ND_PRINT("\n\t    (illegal prefix length)");
                 else if (advance == -2)
-                    goto trunc;
-                else if (advance == -3)
                     break; /* bytes left, but not enough */
                 else
                     ND_PRINT("\n\t      %s", buf);
@@ -1780,15 +1757,11 @@
                 advance = decode_labeled_vpn_prefix4(ndo, tptr, buf, buflen);
                 if (advance == -1)
                     ND_PRINT("\n\t    (illegal prefix length)");
-                else if (advance == -2)
-                    goto trunc;
                 else
                     ND_PRINT("\n\t      %s", buf);
                 break;
             case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO):
                 advance = decode_rt_routing_info(ndo, tptr);
-                if (advance == -2)
-                    goto trunc;
                 break;
             case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN): /* fall through */
             case (AFNUM_INET6<<8 | SAFNUM_MULTICAST_VPN):
@@ -1821,8 +1794,6 @@
                 if (advance == -1)
                     ND_PRINT("\n\t    (illegal prefix length)");
                 else if (advance == -2)
-                    goto trunc;
-                else if (advance == -3)
                     break; /* bytes left, but not enough */
                 else
                     ND_PRINT("\n\t      %s", buf);
@@ -1848,8 +1819,6 @@
                 advance = decode_labeled_vpn_prefix6(ndo, tptr, buf, buflen);
                 if (advance == -1)
                     ND_PRINT("\n\t    (illegal prefix length)");
-                else if (advance == -2)
-                    goto trunc;
                 else
                     ND_PRINT("\n\t      %s", buf);
                 break;
@@ -1871,8 +1840,6 @@
                 advance = decode_clnp_prefix(ndo, tptr, buf, buflen);
                 if (advance == -1)
                     ND_PRINT("\n\t    (illegal prefix length)");
-                else if (advance == -2)
-                    goto trunc;
                 else
                     ND_PRINT("\n\t      %s", buf);
                 break;
@@ -1882,8 +1849,6 @@
                 advance = decode_labeled_vpn_clnp_prefix(ndo, tptr, buf, buflen);
                 if (advance == -1)
                     ND_PRINT("\n\t    (illegal prefix length)");
-                else if (advance == -2)
-                    goto trunc;
                 else
                     ND_PRINT("\n\t      %s", buf);
                 break;
@@ -1906,6 +1871,8 @@
                uint8_t atype, const u_char *pptr, u_int len,
                const unsigned attr_set_level)
 {
+    /* allocate space for the largest possible string */
+    char astostr[AS_STR_SIZE];
     u_int i;
     uint16_t af;
     uint8_t safi, snpa, nhlen;
@@ -2551,6 +2518,8 @@
 bgp_capabilities_print(netdissect_options *ndo,
                        const u_char *opt, u_int caps_len)
 {
+    /* allocate space for the largest possible string */
+    char astostr[AS_STR_SIZE];
     u_int cap_type, cap_len, tcap_len, cap_offset;
     u_int i = 0;
 
@@ -2679,6 +2648,8 @@
 bgp_open_print(netdissect_options *ndo,
                const u_char *dat, u_int length)
 {
+    /* allocate space for the largest possible string */
+    char astostr[AS_STR_SIZE];
     const struct bgp_open *bgp_open_header;
     u_int optslen;
     const struct bgp_opt *bgpopt;
@@ -2800,8 +2771,6 @@
                 ND_PRINT("\n\t    (illegal prefix length)");
                 break;
             } else if (wpfx == -2)
-                goto trunc;
-            else if (wpfx == -3)
                 goto trunc; /* bytes left, but not enough */
             else {
                 ND_PRINT("\n\t    %s", buf);
@@ -2917,8 +2886,6 @@
                 ND_PRINT("\n\t    (illegal prefix length)");
                 break;
             } else if (i == -2)
-                goto trunc;
-            else if (i == -3)
                 goto trunc; /* bytes left, but not enough */
             else {
                 ND_PRINT("\n\t    %s", buf);
diff --git a/print-dhcp6.c b/print-dhcp6.c
index dba13e9..6b0dc21 100644
--- a/print-dhcp6.c
+++ b/print-dhcp6.c
@@ -408,11 +408,26 @@
 			ND_PRINT(" %u)", GET_BE_U_2(tp));
 			break;
 		case DH6OPT_RELAY_MSG:
+		    {
+			const u_char *snapend_save;
+
 			ND_PRINT(" (");
 			tp = (const u_char *)(dh6o + 1);
+			/*
+			 * Update the snapend to the end of the option before
+			 * calling recursively dhcp6_print() for the nested
+			 * packet. Other options may be present after the
+			 * nested DHCPv6 packet. This prevents that, in
+			 * dhcp6_print(), for the nested DHCPv6 packet, the
+			 * remaining length < remaining caplen.
+			 */
+			snapend_save = ndo->ndo_snapend;
+			ndo->ndo_snapend = ND_MIN(tp + optlen, ndo->ndo_snapend);
 			dhcp6_print(ndo, tp, optlen);
+			ndo->ndo_snapend = snapend_save;
 			ND_PRINT(")");
 			break;
+		    }
 		case DH6OPT_AUTH:
 			if (optlen < 11) {
 				ND_PRINT(" ?)");
diff --git a/print-domain.c b/print-domain.c
index 74c71db..c3c6fd8 100644
--- a/print-domain.c
+++ b/print-domain.c
@@ -796,10 +796,8 @@
 			ND_PRINT(" %u(bad plen)", pbit);
 			break;
 		} else if (pbit < 128) {
-			if (!ND_TTEST_LEN(cp + 1, sizeof(a) - pbyte))
-				return(NULL);
 			memset(a, 0, sizeof(a));
-			memcpy(a + pbyte, cp + 1, sizeof(a) - pbyte);
+			GET_CPY_BYTES(a + pbyte, cp + 1, sizeof(a) - pbyte);
 			ND_PRINT(" %u %s", pbit,
 			    addrtostr6(&a, ntop_buf, sizeof(ntop_buf)));
 		}
diff --git a/print-eigrp.c b/print-eigrp.c
index 136efd0..1bcdf17 100644
--- a/print-eigrp.c
+++ b/print-eigrp.c
@@ -43,7 +43,8 @@
     nd_uint32_t flags;
     nd_uint32_t seq;
     nd_uint32_t ack;
-    nd_uint32_t asn;
+    nd_uint16_t vrid;
+    nd_uint16_t asn;
 };
 
 #define	EIGRP_VERSION                        2
@@ -68,6 +69,8 @@
 static const struct tok eigrp_common_header_flag_values[] = {
     { 0x01, "Init" },
     { 0x02, "Conditionally Received" },
+    { 0x04, "Restart" },
+    { 0x08, "End-of-Table" },
     { 0, NULL}
 };
 
@@ -259,18 +262,19 @@
     }
     tlen=len-sizeof(struct eigrp_common_header);
 
-    /* FIXME print other header info */
-    ND_PRINT("\n\tEIGRP v%u, opcode: %s (%u), chksum: 0x%04x, Flags: [%s]\n\tseq: 0x%08x, ack: 0x%08x, AS: %u, length: %u",
+    ND_PRINT("\n\tEIGRP v%u, opcode: %s (%u), chksum: 0x%04x, Flags: [%s]"
+             "\n\tseq: 0x%08x, ack: 0x%08x, VRID: %u, AS: %u, length: %u",
            GET_U_1(eigrp_com_header->version),
            tok2str(eigrp_opcode_values, "unknown, type: %u",GET_U_1(eigrp_com_header->opcode)),
            GET_U_1(eigrp_com_header->opcode),
            GET_BE_U_2(eigrp_com_header->checksum),
-           tok2str(eigrp_common_header_flag_values,
+           bittok2str(eigrp_common_header_flag_values,
                    "none",
                    GET_BE_U_4(eigrp_com_header->flags)),
            GET_BE_U_4(eigrp_com_header->seq),
            GET_BE_U_4(eigrp_com_header->ack),
-           GET_BE_U_4(eigrp_com_header->asn),
+           GET_BE_U_2(eigrp_com_header->vrid),
+           GET_BE_U_2(eigrp_com_header->asn),
            tlen);
 
     tptr+=sizeof(struct eigrp_common_header);
diff --git a/print-esp.c b/print-esp.c
index 8b664b6..61c3e13 100644
--- a/print-esp.c
+++ b/print-esp.c
@@ -903,12 +903,20 @@
 
 	ND_PRINT(": ");
 
+	/*
+	 * Don't put padding + padding length(1 byte) + next header(1 byte)
+	 * in the buffer because they are not part of the plaintext to decode.
+	 */
+	nd_push_snapend(ndo, ep - (padlen + 2));
+
 	/* Now dissect the plaintext. */
 	ip_demux_print(ndo, pt, payloadlen - (padlen + 2), ver, fragmented,
-	    ttl_hl, nh, bp2);
+		       ttl_hl, nh, bp2);
 
 	/* Pop the buffer, freeing it. */
 	nd_pop_packet_info(ndo);
+	/* Pop the nd_push_snapend */
+	nd_pop_packet_info(ndo);
 #endif
 }
 #ifdef HAVE_LIBCRYPTO
diff --git a/print-ether.c b/print-ether.c
index 2596cd6..da95862 100644
--- a/print-ether.c
+++ b/print-ether.c
@@ -564,6 +564,9 @@
 			nd_print_trunc(ndo);
 			return (1);
 		}
+		/* At least one byte is required */
+		/* FIXME: Reference for this byte? */
+		ND_TCHECK_LEN(p, 1);
 		isoclns_print(ndo, p + 1, length - 1);
 		return(1);
 
diff --git a/print-forces.c b/print-forces.c
index b95eab7..e6b52d6 100644
--- a/print-forces.c
+++ b/print-forces.c
@@ -743,9 +743,8 @@
 		const u_char *tdp = (const u_char *) ILV_DATA(ilv);
 		invilv = ilv_valid(ndo, ilv, rlen);
 		if (invilv) {
-			ND_PRINT("%s[", ib + 1);
-			hex_print(ndo, ib, tdp, rlen);
-			ND_PRINT("\n%s]\n", ib + 1);
+			ND_PRINT("Error: %s, rlen %u\n",
+			         tok2str(ForCES_TLV_err, NULL, invilv), rlen);
 			return -1;
 		}
 		if (ndo->ndo_vflag >= 3) {
diff --git a/print-fr.c b/print-fr.c
index 98f436f..f0d7fbe 100644
--- a/print-fr.c
+++ b/print-fr.c
@@ -147,14 +147,22 @@
 
     static u_int dlci, addr_len;
     static uint32_t flags;
-    static char buffer[sizeof("DLCI xxxxxxxxxx")];
+    static char buffer[sizeof("parse_q922_header() returned XXXXXXXXXXX")];
+    int ret;
     memset(buffer, 0, sizeof(buffer));
 
-    if (parse_q922_header(ndo, p, &dlci, &addr_len, &flags, length) == 1){
+    ret = parse_q922_header(ndo, p, &dlci, &addr_len, &flags, length);
+    if (ret == 1) {
         snprintf(buffer, sizeof(buffer), "DLCI %u", dlci);
+        return buffer;
+    } else if (ret == 0) {
+        return "<Invalid DLCI>";
+    } else if (ret == -1) {
+        return "<Truncated>";
+    } else {
+        snprintf(buffer, sizeof(buffer), "parse_q922_header() returned %d", ret);
+        return buffer;
     }
-
-    return buffer;
 }
 
 
diff --git a/print-geonet.c b/print-geonet.c
index dfb19db..2f8046e 100644
--- a/print-geonet.c
+++ b/print-geonet.c
@@ -169,6 +169,7 @@
 	print_long_pos_vector(ndo, bp + 8);
 
 	/* Skip Common Header */
+	ND_TCHECK_LEN(bp, 36);
 	length -= 36;
 	bp += 36;
 
diff --git a/print-icmp.c b/print-icmp.c
index eebb6e3..7753922 100644
--- a/print-icmp.c
+++ b/print-icmp.c
@@ -226,7 +226,7 @@
  * The Destination Unreachable, Time Exceeded
  * and Parameter Problem messages are slightly changed as per
  * the above draft. A new Length field gets added to give
- * the caller an idea about the length of the piggypacked
+ * the caller an idea about the length of the piggybacked
  * IP packet before the MPLS extension header starts.
  *
  * The Length field represents length of the padded "original datagram"
@@ -305,7 +305,6 @@
 	const struct udphdr *ouh;
         const uint8_t *obj_tptr;
         uint32_t raw_label;
-        const u_char *snapend_save;
 	const struct icmp_mpls_ext_object_header_t *icmp_mpls_ext_object_header;
 	u_int hlen, mtu, obj_tlen, obj_class_num, obj_ctype;
 	uint16_t dport;
@@ -651,12 +650,25 @@
          * save the snaplength as this may get overridden in the IP printer.
          */
 	if (ndo->ndo_vflag >= 1 && ICMP_ERRTYPE(icmp_type)) {
+		const u_char *snapend_save;
+
 		bp += 8;
 		ND_PRINT("\n\t");
 		ip = (const struct ip *)bp;
-                snapend_save = ndo->ndo_snapend;
+		snapend_save = ndo->ndo_snapend;
+		/*
+		 * Update the snapend because extensions (MPLS, ...) may be
+		 * present after the IP packet. In this case the current
+		 * (outer) packet's snapend is not what ip_print() needs to
+		 * decode an IP packet nested in the middle of an ICMP payload.
+		 *
+		 * This prevents that, in ip_print(), for the nested IP packet,
+		 * the remaining length < remaining caplen.
+		 */
+		ndo->ndo_snapend = ND_MIN(bp + GET_BE_U_2(ip->ip_len),
+					  ndo->ndo_snapend);
 		ip_print(ndo, bp, GET_BE_U_2(ip->ip_len));
-                ndo->ndo_snapend = snapend_save;
+		ndo->ndo_snapend = snapend_save;
 	}
 
 	/* ndo_protocol reassignment after ip_print() call */
diff --git a/print-icmp6.c b/print-icmp6.c
index ba1f6e6..f16c1fa 100644
--- a/print-icmp6.c
+++ b/print-icmp6.c
@@ -1514,12 +1514,10 @@
 			case 1:
 				break;
 			case 2:
-				ND_TCHECK_8(opri + 1);
-				memcpy(&in6, opri + 1, 8);
+				GET_CPY_BYTES(&in6, opri + 1, 8);
 				break;
 			case 3:
-				ND_TCHECK_16(opri + 1);
-				memcpy(&in6, opri + 1, 16);
+				GET_CPY_BYTES(&in6, opri + 1, 16);
 				break;
 			default:
 				goto trunc;
diff --git a/print-ip.c b/print-ip.c
index 7cec640..a0df959 100644
--- a/print-ip.c
+++ b/print-ip.c
@@ -471,8 +471,18 @@
 				     GET_IPADDR_STRING(ip->ip_src),
 				     GET_IPADDR_STRING(ip->ip_dst));
 		}
+		/*
+		 * Do a bounds check before calling ip_demux_print().
+		 * At least the header data is required.
+		 */
+		if (!ND_TTEST_LEN((const u_char *)ip, hlen)) {
+			ND_PRINT(" [remaining caplen(%u) < header length(%u)]",
+				 ND_BYTES_AVAILABLE_AFTER((const u_char *)ip),
+				 hlen);
+			nd_trunc_longjmp(ndo);
+		}
 		ip_demux_print(ndo, (const u_char *)ip + hlen, len, 4,
-		    off & IP_MF, GET_U_1(ip->ip_ttl), nh, bp);
+			       off & IP_MF, GET_U_1(ip->ip_ttl), nh, bp);
 	} else {
 		/*
 		 * Ultra quiet now means that all this stuff should be
diff --git a/print-isoclns.c b/print-isoclns.c
index 3b4a150..ddd5595 100644
--- a/print-isoclns.c
+++ b/print-isoclns.c
@@ -2307,9 +2307,8 @@
 
     byte_length = (bit_length + 7) / 8; /* prefix has variable length encoding */
 
-    ND_TCHECK_LEN(tptr, byte_length);
     memset(prefix, 0, sizeof(prefix));   /* clear the copy buffer */
-    memcpy(prefix,tptr,byte_length);    /* copy as much as is stored in the TLV */
+    GET_CPY_BYTES(prefix,tptr,byte_length);    /* copy as much as is stored in the TLV */
     tptr+=byte_length;
     processed+=byte_length;
 
@@ -2360,8 +2359,6 @@
         }
     }
     return (processed);
-trunc:
-    return 0;
 }
 
 static void
diff --git a/print-l2tp.c b/print-l2tp.c
index 8377d3a..940aa2b 100644
--- a/print-l2tp.c
+++ b/print-l2tp.c
@@ -806,6 +806,8 @@
 
 	if (flag_o) {	/* Offset Size */
 		pad =  GET_BE_U_2(ptr);
+		/* Offset padding octets in packet buffer? */
+		ND_TCHECK_LEN(ptr + 2, pad);
 		ptr += (2 + pad);
 		cnt += (2 + pad);
 	}
@@ -851,4 +853,7 @@
 		ppp_print(ndo, ptr, length - cnt);
 		ND_PRINT("}");
 	}
+	return;
+trunc:
+	nd_print_trunc(ndo);
 }
diff --git a/print-macsec.c b/print-macsec.c
index 0cf8cd6..607f696 100644
--- a/print-macsec.c
+++ b/print-macsec.c
@@ -25,7 +25,7 @@
 #include <config.h>
 #endif
 
-#include <netdissect-stdinc.h>
+#include "netdissect-stdinc.h"
 
 #include "netdissect.h"
 #include "addrtoname.h"
@@ -217,6 +217,13 @@
 	}
 	*lengthp -= MACSEC_DEFAULT_ICV_LEN;
 	*caplenp -= MACSEC_DEFAULT_ICV_LEN;
+	/*
+	 * Update the snapend thus the ICV field is not in the payload for
+	 * the caller.
+	 * The ICV (Integrity Check Value) is at the end of the frame, after
+	 * the secure data.
+	 */
+	ndo->ndo_snapend -= MACSEC_DEFAULT_ICV_LEN;
 
 	/*
 	 * If the SL field is non-zero, then it's the length of the
diff --git a/print-msdp.c b/print-msdp.c
index 545f452..7845116 100644
--- a/print-msdp.c
+++ b/print-msdp.c
@@ -36,12 +36,13 @@
 	unsigned int type, len;
 
 	ndo->ndo_protocol = "msdp";
+	ND_PRINT(": ");
+	nd_print_protocol(ndo);
 	/* See if we think we're at the beginning of a compound packet */
 	type = GET_U_1(sp);
 	len = GET_BE_U_2(sp + 1);
 	if (len > 1500 || len < 3 || type == 0 || type > MSDP_TYPE_MAX)
 		goto trunc;	/* not really truncated, but still not decodable */
-	ND_PRINT(" msdp:");
 	while (length != 0) {
 		type = GET_U_1(sp);
 		len = GET_BE_U_2(sp + 1);
diff --git a/print-olsr.c b/print-olsr.c
index 2b85d67..8f04923 100644
--- a/print-olsr.c
+++ b/print-olsr.c
@@ -328,6 +328,9 @@
     ndo->ndo_protocol = "olsr";
     tptr = pptr;
 
+    nd_print_protocol_caps(ndo);
+    ND_PRINT("v%u", (is_ipv6) ? 6 : 4);
+
     if (length < sizeof(struct olsr_common)) {
         goto trunc;
     }
@@ -337,8 +340,7 @@
     ptr.common = (const struct olsr_common *)tptr;
     length = ND_MIN(length, GET_BE_U_2(ptr.common->packet_len));
 
-    ND_PRINT("OLSRv%i, seq 0x%04x, length %u",
-            (is_ipv6 == 0) ? 4 : 6,
+    ND_PRINT(", seq 0x%04x, length %u",
             GET_BE_U_2(ptr.common->packet_seq),
             length);
 
diff --git a/print-openflow-1.0.c b/print-openflow-1.0.c
index d2cc5b9..1d7f247 100644
--- a/print-openflow-1.0.c
+++ b/print-openflow-1.0.c
@@ -1018,7 +1018,18 @@
 	}
 	ndo->ndo_vflag -= 3;
 	ND_PRINT(", frame decoding below\n");
+	/*
+	 * The encapsulated Ethernet frame is not necessarily the last
+	 * data of this packet (i.e. there may be more OpenFlow messages
+	 * after the current OFPT_PACKET_IN/OFPT_PACKET_OUT message, in
+	 * which case the current (outer) packet's snapshot end is not
+	 * what ether_print() needs to decode an Ethernet frame nested in
+	 * the middle of a TCP payload.
+	 */
+	const u_char *snapend_save = ndo->ndo_snapend;
+	ndo->ndo_snapend = ND_MIN(cp + len, ndo->ndo_snapend);
 	ether_print(ndo, cp, len, ND_BYTES_AVAILABLE_AFTER(cp), NULL, NULL);
+	ndo->ndo_snapend = snapend_save;
 	ndo->ndo_vflag += 3;
 }
 
diff --git a/print-ospf6.c b/print-ospf6.c
index 1b862b3..1bdcd68 100644
--- a/print-ospf6.c
+++ b/print-ospf6.c
@@ -425,9 +425,8 @@
 	if (lsa_length < wordlen * 4)
 		goto trunc;
 	lsa_length -= wordlen * 4;
-	ND_TCHECK_LEN(lsapp->lsa_p_prefix, wordlen * 4);
 	memset(prefix, 0, sizeof(prefix));
-	memcpy(prefix, lsapp->lsa_p_prefix, wordlen * 4);
+	GET_CPY_BYTES(prefix, lsapp->lsa_p_prefix, wordlen * 4);
 	ND_PRINT("\n\t\t%s/%u", ip6addr_string(ndo, prefix), /* local buffer, not packet data; don't use GET_IP6ADDR_STRING() */
 		 GET_U_1(lsapp->lsa_p_len));
         if (GET_U_1(lsapp->lsa_p_opt)) {
diff --git a/print-tcp.c b/print-tcp.c
index 68ef3f2..5e6240f 100644
--- a/print-tcp.c
+++ b/print-tcp.c
@@ -170,6 +170,7 @@
         uint16_t magic;
         int rev;
         const struct ip6_hdr *ip6;
+        u_int header_len;	/* Header length in bytes */
 
         ndo->ndo_protocol = "tcp";
         tp = (const struct tcphdr *)bp;
@@ -610,11 +611,28 @@
                                 break;
 
                         case TCPOPT_MPTCP:
+                            {
+                                const u_char *snapend_save;
+                                int ret;
+
                                 datalen = len - 2;
                                 LENCHECK(datalen);
-                                if (!mptcp_print(ndo, cp-2, len, flags))
+                                /* Update the snapend to the end of the option
+                                 * before calling mptcp_print(). Some options
+                                 * (MPTCP or others) may be present after a
+                                 * MPTCP option. This prevents that, in
+                                 * mptcp_print(), the remaining length < the
+                                 * remaining caplen.
+                                 */
+                                snapend_save = ndo->ndo_snapend;
+                                ndo->ndo_snapend = ND_MIN(cp - 2 + len,
+                                                          ndo->ndo_snapend);
+                                ret = mptcp_print(ndo, cp - 2, len, flags);
+                                ndo->ndo_snapend = snapend_save;
+                                if (!ret)
                                         goto bad;
                                 break;
+                            }
 
                         case TCPOPT_FASTOPEN:
                                 datalen = len - 2;
@@ -684,7 +702,17 @@
         /*
          * Decode payload if necessary.
          */
-        bp += TH_OFF(tp) * 4;
+        header_len = TH_OFF(tp) * 4;
+        /*
+         * Do a bounds check before decoding the payload.
+         * At least the header data is required.
+         */
+        if (!ND_TTEST_LEN(bp, header_len)) {
+                ND_PRINT(" [remaining caplen(%u) < header length(%u)]",
+                         ND_BYTES_AVAILABLE_AFTER(bp), header_len);
+                nd_trunc_longjmp(ndo);
+        }
+        bp += header_len;
         if ((flags & TH_RST) && ndo->ndo_vflag) {
                 print_tcp_rst_data(ndo, bp, length);
                 return;
diff --git a/print-zep.c b/print-zep.c
index ac4e017..e10ecb3 100644
--- a/print-zep.c
+++ b/print-zep.c
@@ -27,6 +27,7 @@
 
 #include "netdissect-stdinc.h"
 
+#define ND_LONGJMP_FROM_TCHECK
 #include "netdissect.h"
 
 #include "extract.h"
@@ -166,6 +167,7 @@
 		/* Call 802.15.4 dissector. */
 		ND_PRINT("\n\t");
 		if (ieee802_15_4_print(ndo, bp, inner_len)) {
+			ND_TCHECK_LEN(bp, len);
 			bp += len;
 			len = 0;
 		}
diff --git a/print-zephyr.c b/print-zephyr.c
index 7f60f1f..aa552aa 100644
--- a/print-zephyr.c
+++ b/print-zephyr.c
@@ -140,7 +140,7 @@
 }
 
 void
-zephyr_print(netdissect_options *ndo, const u_char *cp, int length)
+zephyr_print(netdissect_options *ndo, const u_char *cp, u_int length)
 {
     struct z_packet z = {
         NULL,	/* version */
diff --git a/print.c b/print.c
index 823cea6..bfc35d9 100644
--- a/print.c
+++ b/print.c
@@ -386,7 +386,16 @@
 	 * bigger lengths.
 	 */
 
-	ts_print(ndo, &h->ts);
+	/*
+	 * The header /usr/include/pcap/pcap.h in OpenBSD declares h->ts as
+	 * struct bpf_timeval, not struct timeval. The former comes from
+	 * /usr/include/net/bpf.h and uses 32-bit unsigned types instead of
+	 * the types used in struct timeval.
+	 */
+	struct timeval tvbuf;
+	tvbuf.tv_sec = h->ts.tv_sec;
+	tvbuf.tv_usec = h->ts.tv_usec;
+	ts_print(ndo, &tvbuf);
 
 	/*
 	 * Printers must check that they're not walking off the end of
diff --git a/util-print.c b/util-print.c
index f9ea618..6f8f61d 100644
--- a/util-print.c
+++ b/util-print.c
@@ -95,33 +95,6 @@
 }
 
 /*
- * Print out a null-terminated filename (or other ASCII string), part of
- * the packet buffer.
- * If ep is NULL, assume no truncation check is needed.
- * Return true if truncated.
- * Stop at ep (if given) or before the null char, whichever is first.
- */
-int
-nd_print(netdissect_options *ndo,
-         const u_char *s, const u_char *ep)
-{
-	int ret;
-	u_char c;
-
-	ret = 1;			/* assume truncated */
-	while (ep == NULL || s < ep) {
-		c = GET_U_1(s);
-		s++;
-		if (c == '\0') {
-			ret = 0;
-			break;
-		}
-		fn_print_char(ndo, c);
-	}
-	return(ret);
-}
-
-/*
  * Print out a null-terminated filename (or other ASCII string) from
  * a fixed-length field in the packet buffer, or from what remains of
  * the packet.