The patches attached to this email are required to get a fully working tcpdump
on OpenSolaris, or Solaris Express Community Edition, build 125 and later.

The attached patch introduces support for printing out the IPNET headers used
for packet capture inside of zones that share their networking with the global
zone and for packets "transmitted" between zones.

tcpdump 4.0.0 will ship with builds 129 and later of OpenSolaris/SXCE and
when run as root with the '-L' option, should behave as below to indicate that
the system is fully functional:

Data link types (use option -y to set):
 DOCSIS (DOCSIS) (printing not supported)
 IPNET (Solaris IPNET)
 EN10MB (Ethernet)

Cheers,
Darren
diff --git a/Makefile.in b/Makefile.in
index 04efdcd..ca29ce8 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -77,7 +77,7 @@
 	print-eap.c print-eigrp.c\
 	print-esp.c print-ether.c print-fddi.c print-fr.c \
 	print-gre.c print-hsrp.c print-icmp.c print-igmp.c \
-	print-igrp.c print-ip.c print-ipcomp.c print-ipfc.c \
+	print-igrp.c print-ip.c print-ipcomp.c print-ipfc.c print-ipnet.c \
 	print-ipx.c print-isoclns.c print-juniper.c print-krb.c \
 	print-l2tp.c print-lane.c print-ldp.c print-lldp.c print-llc.c \
         print-lmp.c print-lspping.c print-lwapp.c \
diff --git a/interface.h b/interface.h
index 9038b43..4296823 100644
--- a/interface.h
+++ b/interface.h
@@ -322,6 +322,10 @@
 extern void sip_print(const u_char *, u_int);
 extern void syslog_print(const u_char *, u_int);
 extern u_int bt_if_print(const struct pcap_pkthdr *, const u_char *);
+extern void ipnet_print(const u_char *, u_int, u_int);
+extern u_int ipnet_if_print(const struct pcap_pkthdr *, const u_char *);
+extern int ipnet_encap_print(u_short, const u_char *, u_int, u_int);
+
 extern u_int usb_linux_print(const struct pcap_pkthdr *, const u_char *);
 
 #ifdef INET6
diff --git a/ipnet.h b/ipnet.h
new file mode 100644
index 0000000..ae69284
--- /dev/null
+++ b/ipnet.h
@@ -0,0 +1,13 @@
+typedef struct ipnet_hdr {
+	uint8_t		iph_version;
+	uint8_t		iph_family;
+	uint16_t	iph_htype;
+	uint32_t	iph_pktlen;
+	uint32_t	iph_ifindex;
+	uint32_t	iph_grifindex;
+	uint32_t	iph_zsrc;
+	uint32_t	iph_zdst;
+} ipnet_hdr_t;
+
+#define	IPH_AF_INET	2		/* Matches Solaris's AF_INET */
+#define	IPH_AF_INET6	26		/* Matches Solaris's AF_INET6 */
diff --git a/print-ipnet.c b/print-ipnet.c
new file mode 100644
index 0000000..56b4978
--- /dev/null
+++ b/print-ipnet.c
@@ -0,0 +1,132 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <tcpdump-stdinc.h>
+
+#include <stdio.h>
+#include <pcap.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "ipnet.h"
+
+#ifdef DLT_IPNET
+
+int ipnet_encap_print(u_short, const u_char *, u_int, u_int);
+
+const struct tok ipnet_values[] = {
+	{ IPH_AF_INET,		"IPv4" },
+	{ IPH_AF_INET6,		"IPv6" },
+	{ 0,			NULL }
+};
+
+static inline void
+ipnet_hdr_print(register const u_char *bp, u_int length)
+{
+	const ipnet_hdr_t *hdr;
+	hdr = (const ipnet_hdr_t *)bp;
+
+	(void)printf("%d > %d", hdr->iph_zsrc, hdr->iph_zdst);
+
+	if (!qflag) {
+		(void)printf(", family %s (%d)",
+			     tok2str(ipnet_values, "Unknown",
+				     hdr->iph_family),
+			      hdr->iph_family);
+        } else {
+		(void)printf(", %s",
+			     tok2str(ipnet_values,
+				     "Unknown Ethertype (0x%04x)",
+				     hdr->iph_family));
+        }
+
+	(void)printf(", length %u: ", length);
+}
+
+void
+ipnet_print(const u_char *p, u_int length, u_int caplen)
+{
+	ipnet_hdr_t *hdr;
+
+	if (caplen < sizeof(ipnet_hdr_t)) {
+		printf("[|ipnet]");
+		return;
+	}
+
+	if (eflag)
+		ipnet_hdr_print(p, length);
+
+	length -= sizeof(ipnet_hdr_t);
+	caplen -= sizeof(ipnet_hdr_t);
+	hdr = (ipnet_hdr_t *)p;
+	p += sizeof(ipnet_hdr_t);
+
+	if (ipnet_encap_print(hdr->iph_family, p, length, caplen) == 0) {
+		if (!eflag)
+			ipnet_hdr_print((u_char *)hdr,
+					length + sizeof(ipnet_hdr_t));
+
+		if (!suppress_default_print)
+			default_print(p, caplen);
+	} 
+}
+
+/*
+ * This is the top level routine of the printer.  'p' points
+ * to the ether header of the packet, 'h->ts' is the timestamp,
+ * 'h->len' is the length of the packet off the wire, and 'h->caplen'
+ * is the number of bytes actually captured.
+ */
+u_int
+ipnet_if_print(const struct pcap_pkthdr *h, const u_char *p)
+{
+	ipnet_print(p, h->len, h->caplen);
+
+	return (sizeof(ipnet_hdr_t));
+}
+
+/*
+ * Prints the packet encapsulated in an Ethernet data segment
+ * (or an equivalent encapsulation), given the Ethernet type code.
+ *
+ * Returns non-zero if it can do so, zero if the ethertype is unknown.
+ *
+ * The Ethernet type code is passed through a pointer; if it was
+ * ETHERTYPE_8021Q, it gets updated to be the Ethernet type of
+ * the 802.1Q payload, for the benefit of lower layers that might
+ * want to know what it is.
+ */
+
+int
+ipnet_encap_print(u_short family, const u_char *p,
+    u_int length, u_int caplen)
+{
+ recurse:
+
+	switch (family) {
+
+	case IPH_AF_INET:
+	        ip_print(gndo, p, length);
+		return (1);
+
+#ifdef INET6
+	case IPH_AF_INET6:
+		ip6_print(p, length);
+		return (1);
+#endif /*INET6*/
+
+	default:
+		return(0);
+	}
+}
+
+
+/*
+ * Local Variables:
+ * c-style: whitesmith
+ * c-basic-offset: 8
+ * End:
+ */
+
+#endif /* DLT_IPNET */
diff --git a/tcpdump.c b/tcpdump.c
index 18c7af4..25feb7a 100644
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -282,6 +282,9 @@
 #if defined(HAVE_PCAP_USB_H) && defined(DLT_USB_LINUX_MMAPPED)
 	{ usb_linux_print, DLT_USB_LINUX_MMAPPED},
 #endif
+#ifdef DLT_IPNET
+	{ ipnet_if_print, DLT_IPNET },
+#endif
 	{ NULL,			0 },
 };