Module Name:    src
Committed By:   msaitoh
Date:           Tue Jul 17 05:52:07 UTC 2018

Modified Files:
        src/share/man/man4: ddb.4
        src/sys/kern: files.kern uipc_mbuf.c
        src/sys/sys: mbuf.h socket.h
Added Files:
        src/sys/kern: uipc_mbufdebug.c

Log Message:
 Add /d(dump) and /v(verbose) modifiers to DDB's "show mbuf" command. Mainly
written by Hiroki SUENAGA. Currently, /v supports Ethernet, PPP, PPPoE, ARP,
IPv4, ICMP, IPv6, ICMPv6, TCP and UDP.


To generate a diff of this commit:
cvs rdiff -u -r1.178 -r1.179 src/share/man/man4/ddb.4
cvs rdiff -u -r1.18 -r1.19 src/sys/kern/files.kern
cvs rdiff -u -r1.215 -r1.216 src/sys/kern/uipc_mbuf.c
cvs rdiff -u -r0 -r1.1 src/sys/kern/uipc_mbufdebug.c
cvs rdiff -u -r1.207 -r1.208 src/sys/sys/mbuf.h
cvs rdiff -u -r1.124 -r1.125 src/sys/sys/socket.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/share/man/man4/ddb.4
diff -u src/share/man/man4/ddb.4:1.178 src/share/man/man4/ddb.4:1.179
--- src/share/man/man4/ddb.4:1.178	Mon Mar 19 08:41:21 2018
+++ src/share/man/man4/ddb.4	Tue Jul 17 05:52:07 2018
@@ -1,4 +1,4 @@
-.\"	$NetBSD: ddb.4,v 1.178 2018/03/19 08:41:21 ozaki-r Exp $
+.\"	$NetBSD: ddb.4,v 1.179 2018/07/17 05:52:07 msaitoh Exp $
 .\"
 .\" Copyright (c) 1997 - 2009 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -56,7 +56,7 @@
 .\" any improvements or extensions that they make and grant Carnegie Mellon
 .\" the rights to redistribute these changes.
 .\"
-.Dd March 19, 2018
+.Dd July 17, 2018
 .Dt DDB 4
 .Os
 .Sh NAME
@@ -673,12 +673,20 @@ Print the mount structure at
 If
 .Cm /f
 is specified, the complete vnode list is printed.
-.It Ic show mbuf Ns Oo Cm /c Oc Ar address
+.It Ic show mbuf Ns Oo Cm /cdv Oc Ar address
 Print the mbuf structure at
 .Ar address .
-If
-.Cm /c
-is specified, the mbufs in the chain are followed.
+Valid modifiers:
+.Bl -tag -width 4n -compact
+.It Cm /c
+The mbufs in the chain are followed.
+.It Cm /d
+The data is dumped.
+.It Cm /v
+Decode the mbuf chain as a packet.
+It currently supports Ethernet, PPP, PPPoE, ARP, IPv4, ICMP, IPv6, ICMP6, TCP
+and UDP.
+.El
 .It Ic show ncache Ar address
 Dump the namecache list associated with vnode at
 .Ar address .

Index: src/sys/kern/files.kern
diff -u src/sys/kern/files.kern:1.18 src/sys/kern/files.kern:1.19
--- src/sys/kern/files.kern:1.18	Thu Jul 12 10:46:48 2018
+++ src/sys/kern/files.kern	Tue Jul 17 05:52:07 2018
@@ -1,4 +1,4 @@
-#	$NetBSD: files.kern,v 1.18 2018/07/12 10:46:48 maxv Exp $
+#	$NetBSD: files.kern,v 1.19 2018/07/17 05:52:07 msaitoh Exp $
 
 #
 # kernel sources
@@ -175,6 +175,7 @@ file	kern/uipc_accf.c		kern
 file	kern/uipc_domain.c		kern
 file	kern/uipc_mbuf.c		kern
 file	kern/uipc_mbuf2.c		kern
+file	kern/uipc_mbufdebug.c		kern
 file	net/link_proto.c		kern	# XXX
 file	kern/uipc_proto.c		kern
 file	kern/uipc_sem.c			kern

Index: src/sys/kern/uipc_mbuf.c
diff -u src/sys/kern/uipc_mbuf.c:1.215 src/sys/kern/uipc_mbuf.c:1.216
--- src/sys/kern/uipc_mbuf.c:1.215	Mon May  7 09:57:37 2018
+++ src/sys/kern/uipc_mbuf.c	Tue Jul 17 05:52:07 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: uipc_mbuf.c,v 1.215 2018/05/07 09:57:37 maxv Exp $	*/
+/*	$NetBSD: uipc_mbuf.c,v 1.216 2018/07/17 05:52:07 msaitoh Exp $	*/
 
 /*
  * Copyright (c) 1999, 2001 The NetBSD Foundation, Inc.
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_mbuf.c,v 1.215 2018/05/07 09:57:37 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_mbuf.c,v 1.216 2018/07/17 05:52:07 msaitoh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_mbuftrace.h"
@@ -1646,7 +1646,11 @@ void
 m_print(const struct mbuf *m, const char *modif, void (*pr)(const char *, ...))
 {
 	char ch;
+	const struct mbuf *m0 = NULL;
 	bool opt_c = false;
+	bool opt_d = false;
+	bool opt_v = false;
+	int no = 0;
 	char buf[512];
 
 	while ((ch = *(modif++)) != '\0') {
@@ -1654,14 +1658,35 @@ m_print(const struct mbuf *m, const char
 		case 'c':
 			opt_c = true;
 			break;
+		case 'd':
+			opt_d = true;
+			break;
+		case 'v':
+			opt_v = true;
+			m0 = m;
+			break;
 		}
 	}
 
 nextchain:
-	(*pr)("MBUF %p\n", m);
+	(*pr)("MBUF(%d) %p\n", no, m);
 	snprintb(buf, sizeof(buf), M_FLAGS_BITS, (u_int)m->m_flags);
 	(*pr)("  data=%p, len=%d, type=%d, flags=%s\n",
 	    m->m_data, m->m_len, m->m_type, buf);
+	if (opt_d) {
+		int i;
+		unsigned char *p = m->m_data;
+
+		(*pr)("  data:");
+
+		for (i = 0; i < m->m_len; i++) {
+			if (i % 16 == 0)
+				(*pr)("\n");
+			(*pr)(" %02x", p[i]);
+		}
+
+		(*pr)("\n");
+	}
 	(*pr)("  owner=%p, next=%p, nextpkt=%p\n", m->m_owner, m->m_next,
 	    m->m_nextpkt);
 	(*pr)("  leadingspace=%u, trailingspace=%u, readonly=%u\n",
@@ -1697,9 +1722,14 @@ nextchain:
 	if (opt_c) {
 		m = m->m_next;
 		if (m != NULL) {
+			no++;
 			goto nextchain;
 		}
 	}
+
+	if (opt_v && m0) {
+		m_examine(m0, AF_ETHER, modif, pr);
+	}
 }
 #endif /* defined(DDB) */
 

Index: src/sys/sys/mbuf.h
diff -u src/sys/sys/mbuf.h:1.207 src/sys/sys/mbuf.h:1.208
--- src/sys/sys/mbuf.h:1.207	Fri Jun  1 08:56:00 2018
+++ src/sys/sys/mbuf.h	Tue Jul 17 05:52:07 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: mbuf.h,v 1.207 2018/06/01 08:56:00 maxv Exp $	*/
+/*	$NetBSD: mbuf.h,v 1.208 2018/07/17 05:52:07 msaitoh Exp $	*/
 
 /*
  * Copyright (c) 1996, 1997, 1999, 2001, 2007 The NetBSD Foundation, Inc.
@@ -900,6 +900,10 @@ m_copy_rcvif(struct mbuf *m, const struc
 void m_print(const struct mbuf *, const char *, void (*)(const char *, ...)
     __printflike(1, 2));
 
+/* from uipc_mbufdebug.c */
+void	m_examine(const struct mbuf *, int, const char *, void (*)(const char *, ...)
+    __printflike(1, 2));
+
 /*
  * Get rcvif of a mbuf.
  *

Index: src/sys/sys/socket.h
diff -u src/sys/sys/socket.h:1.124 src/sys/sys/socket.h:1.125
--- src/sys/sys/socket.h:1.124	Thu Apr 19 21:19:07 2018
+++ src/sys/sys/socket.h	Tue Jul 17 05:52:07 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: socket.h,v 1.124 2018/04/19 21:19:07 christos Exp $	*/
+/*	$NetBSD: socket.h,v 1.125 2018/07/17 05:52:07 msaitoh Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -222,7 +222,8 @@ struct	accept_filter_arg {
 #define	AF_MPLS		33		/* MultiProtocol Label Switching */
 #define	AF_ROUTE	34		/* Internal Routing Protocol */
 #define	AF_CAN		35
-#define	AF_MAX		36
+#define	AF_ETHER	36
+#define	AF_MAX		37
 
 /*
  * Structure used by kernel to store most
@@ -332,6 +333,7 @@ struct sockaddr_storage {
 #define	PF_MPLS		AF_MPLS
 #define	PF_ROUTE	AF_ROUTE
 #define	PF_CAN		AF_CAN
+#define	PF_ETHER	AF_ETHER
 
 #define	PF_MAX		AF_MAX
 

Added files:

Index: src/sys/kern/uipc_mbufdebug.c
diff -u /dev/null src/sys/kern/uipc_mbufdebug.c:1.1
--- /dev/null	Tue Jul 17 05:52:07 2018
+++ src/sys/kern/uipc_mbufdebug.c	Tue Jul 17 05:52:07 2018
@@ -0,0 +1,959 @@
+/*	$NetBSD: uipc_mbufdebug.c,v 1.1 2018/07/17 05:52:07 msaitoh Exp $	*/
+
+/*
+ * Copyright (C) 2017 Internet Initiative Japan Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$SEIL: uipc_mbufseil.c$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+
+#include <net/if.h>
+#include <net/if_ether.h>
+#include <net/ppp_defs.h>
+#include <net/if_arp.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <netinet/if_inarp.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+
+#define EXAMINE_HEX_LIMIT 128
+#define EXAMINE_HEX_COL 4
+
+/* mbuf operations without change of mbuf chain */
+static int m_peek_data(const struct mbuf *, int, int, void *);
+static unsigned int m_peek_len(const struct mbuf *, const char *);
+
+/* utility */
+static char *str_ethaddr(const uint8_t *);
+static char *str_ipaddr(const struct in_addr *);
+static char *str_ip6addr(const struct in6_addr *);
+static const char *str_ipproto(const uint8_t);
+
+/* parsers for m_examine() */
+static void m_examine_ether(const struct mbuf *, int, const char *,
+    void (*)(const char *, ...));
+static void m_examine_pppoe(const struct mbuf *, int, const char *,
+    void (*)(const char *, ...));
+static void m_examine_ppp(const struct mbuf *, int, const char *,
+    void (*)(const char *, ...));
+static void m_examine_arp(const struct mbuf *, int, const char *,
+    void (*)(const char *, ...));
+static void m_examine_ip(const struct mbuf *, int, const char *,
+    void (*)(const char *, ...));
+static void m_examine_icmp(const struct mbuf *, int, const char *,
+    void (*)(const char *, ...));
+static void m_examine_ip6(const struct mbuf *, int, const char *,
+    void (*)(const char *, ...));
+static void m_examine_icmp6(const struct mbuf *, int, const char *,
+    void (*)(const char *, ...));
+static void m_examine_tcp(const struct mbuf *, int, const char *,
+    void (*)(const char *, ...));
+static void m_examine_udp(const struct mbuf *, int, const char *,
+    void (*)(const char *, ...));
+static void m_examine_hex(const struct mbuf *, int, const char *,
+    void (*)(const char *, ...));
+
+/* header structure for some protocol */
+struct pppoehdr {
+	uint8_t vertype;
+	uint8_t code;
+	uint16_t session;
+	uint16_t plen;
+} __attribute__((__packed__));
+
+struct pppoetag {
+	uint16_t tag;
+	uint16_t len;
+} __attribute__((__packed__));
+
+#define PPPOE_TAG_EOL 0x0000
+#define PPPOE_CODE_PADI		0x09	/* Active Discovery Initiation */
+#define	PPPOE_CODE_PADO		0x07	/* Active Discovery Offer */
+#define	PPPOE_CODE_PADR		0x19	/* Active Discovery Request */
+#define	PPPOE_CODE_PADS		0x65	/* Active Discovery Session confirmation */
+#define	PPPOE_CODE_PADT		0xA7	/* Active Discovery Terminate */
+
+struct ppp_header {
+	uint8_t address;
+	uint8_t control;
+	uint16_t protocol;
+} __attribute__((__packed__));
+
+#define CISCO_MULTICAST		0x8f	/* Cisco multicast address */
+#define CISCO_UNICAST		0x0f	/* Cisco unicast address */
+#define CISCO_KEEPALIVE		0x8035	/* Cisco keepalive protocol */
+
+#ifndef NELEMS
+#define NELEMS(elem) ((sizeof(elem))/(sizeof((elem)[0])))
+#endif
+
+static int
+m_peek_data(const struct mbuf *m, int off, int len, void *vp)
+{
+	unsigned int count;
+	char *cp = vp;
+
+	if (off < 0 || len < 0)
+		return -1;
+
+	while (off > 0) {
+		if (m == 0)
+			return -1;
+		if (off < m->m_len)
+			break;
+		off -= m->m_len;
+		m = m->m_next;
+	}
+	while (len > 0) {
+		if (m == 0)
+			return -1;
+		count = min(m->m_len - off, len);
+		memcpy(cp, mtod(m, char *) + off, count);
+		len -= count;
+		cp += count;
+		off = 0;
+		m = m->m_next;
+	}
+
+	return 0;
+}
+
+static unsigned int
+m_peek_len(const struct mbuf *m, const char *modif)
+{
+	const struct mbuf *m0;
+	unsigned int pktlen;
+	boolean_t opt_c = FALSE;
+	unsigned char ch;
+
+	while ( modif && (ch = *(modif++)) != '\0') {
+		switch (ch) {
+		case 'c':
+			opt_c = TRUE;
+			break;
+		}
+	}
+
+	if (opt_c == TRUE) {
+		return m->m_len;
+	}
+
+	if ((m->m_flags & M_PKTHDR) != 0)
+		return m->m_pkthdr.len;
+
+	pktlen = 0;
+	for (m0 = m; m0 != NULL; m0 = m0->m_next)
+		pktlen += m0->m_len;
+
+	return pktlen;
+}
+
+static char *
+str_ethaddr(const uint8_t *ap)
+{
+	static char buf[3 * ETHER_ADDR_LEN];
+
+	return ether_snprintf(buf, sizeof(buf), ap);
+}
+
+static char *
+str_ipaddr(const struct in_addr *ap)
+{
+	static char buf[INET_ADDRSTRLEN];
+
+	return IN_PRINT(buf, ap);
+}
+
+static char *
+str_ip6addr(const struct in6_addr *ap)
+{
+	static char buf[INET6_ADDRSTRLEN];
+
+	return IN6_PRINT(buf, ap);
+}
+
+static const char *
+str_ipproto(const uint8_t proto)
+{
+	switch (proto) {
+	case IPPROTO_HOPOPTS:
+		return ("IPv6 Hop-by-Hop");
+		break;
+	case IPPROTO_TCP:
+		return("TCP");
+		break;
+	case IPPROTO_UDP:
+		return("UDP");
+		break;
+	case IPPROTO_ICMP:
+		return("ICMP");
+		break;
+	case IPPROTO_IGMP:
+		return("IGMP");
+		break;
+	case IPPROTO_ESP:
+		return("ESP");
+		break;
+	case IPPROTO_AH:
+		return("AH");
+		break;
+	case IPPROTO_IPV6_ICMP:
+		return("ICMP6");
+	default:
+		return("unknown");
+		break;
+	}
+
+	/* not reached */
+	return NULL;
+}
+
+static void
+m_examine_ether(const struct mbuf *m, int off, const char *modif,
+    void (*pr)(const char *, ...))
+{
+	struct ether_header eh;
+	unsigned int pktlen;
+
+	pktlen = m_peek_len(m, modif) - off;
+	if (pktlen < sizeof(eh)) {
+		(*pr)("%s: too short mbuf chain\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+
+	if (m_peek_data(m, off, sizeof(eh), (void *)(&eh)) < 0) {
+		(*pr)("%s: cannot read header\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+	off += sizeof(eh);
+
+	(*pr)("ETHER: DST = %s\n", str_ethaddr(eh.ether_dhost));
+	(*pr)("ETHER: SRC = %s\n", str_ethaddr(eh.ether_shost));
+
+	(*pr)("ETHER: TYPE = 0x%04x(", ntohs(eh.ether_type));
+	switch (ntohs(eh.ether_type)) {
+	case ETHERTYPE_PPPOE:
+		(*pr)("PPPoE)\n");
+		return m_examine_pppoe(m, off, modif, pr);
+		break;
+	case ETHERTYPE_ARP:
+		(*pr)("ARP)\n");
+		return m_examine_arp(m, off, modif, pr);
+		break;
+	case ETHERTYPE_IP:
+		(*pr)("IPv4)\n");
+		return m_examine_ip(m, off, modif, pr);
+		break;
+	case ETHERTYPE_IPV6:
+		(*pr)("IPv6)\n");
+		return m_examine_ip6(m, off, modif, pr);
+		break;
+	default:
+		(*pr)("unknown)\n");
+		break;
+	}
+
+	return m_examine_hex(m, off, modif, pr);
+}
+
+static void
+m_examine_pppoe(const struct mbuf *m, int off, const char *modif,
+    void (*pr)(const char *, ...))
+{
+	struct pppoehdr ph;
+	struct pppoetag pt;
+	unsigned int pktlen;
+	uint8_t vt;
+
+	pktlen = m_peek_len(m, modif) - off;
+	if (pktlen < sizeof(ph)) {
+		(*pr)("%s: too short mbuf chain\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+
+	if (m_peek_data(m, off, sizeof(ph), (void *)(&ph)) < 0) {
+		(*pr)("%s: cannot read header\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+	off += sizeof(ph);
+
+	while (off + sizeof(pt) > pktlen) {
+		if (m_peek_data(m, off, sizeof(pt), (void *)(&pt)) < 0) {
+			(*pr)("%s: cannot read header\n", __func__);
+			return m_examine_hex(m, off, modif, pr);
+		}
+		off += sizeof(pt);
+
+		if (ntohs(pt.tag) == PPPOE_TAG_EOL)
+			break;
+		off += ntohs(pt.len);
+	}
+
+	vt = ph.vertype;
+
+	(*pr)("PPPoE: Version = %u\n", ((vt >> 4) & 0xff));
+	(*pr)("PPPoE: Type = %u\n", (vt & 0xff));
+	(*pr)("PPPoE: Code = %u(", ph.code);
+	switch (ph.code) {
+	case 0:
+		(*pr)("DATA");
+		break;
+	case PPPOE_CODE_PADI:
+		(*pr)("PADI");
+		break;
+	case PPPOE_CODE_PADO:
+		(*pr)("PADO");
+		break;
+	case PPPOE_CODE_PADS:
+		(*pr)("PADS");
+		break;
+	case PPPOE_CODE_PADT:
+		(*pr)("PADT");
+		break;
+	default:
+		(*pr)("unknown");
+		break;
+	}
+	(*pr)(")\n");
+
+	(*pr)("PPPoE: Session = 0x%04x\n", ntohs(ph.session));
+	(*pr)("PPPoE: Payload Length = %u\n", ntohs(ph.plen));
+
+	switch (ph.code) {
+	case PPPOE_CODE_PADI:
+	case PPPOE_CODE_PADO:
+	case PPPOE_CODE_PADS:
+	case PPPOE_CODE_PADT:
+		(*pr)("No parser for PPPoE control frame.\n");
+		return m_examine_hex(m, off, modif, pr);
+		break;
+	}
+
+	if (ph.code != 0) {
+		(*pr)("Unknown PPPoE code.\n");
+		return m_examine_hex(m, off, modif, pr);
+	}
+
+	return m_examine_ppp(m, off, modif, pr);
+}
+
+static void
+m_examine_ppp(const struct mbuf *m, int off, const char *modif,
+    void (*pr)(const char *, ...))
+{
+	struct ppp_header h;
+	unsigned int pktlen;
+	uint16_t protocol;
+
+	pktlen = m_peek_len(m, modif) - off;
+	if (pktlen < sizeof(h)) {
+		(*pr)("%s: too short mbuf chain\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+
+	if (m_peek_data(m, off, sizeof(h), (void *)(&h)) < 0) {
+		(*pr)("%s: cannot read header\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+	off += sizeof(h);
+
+	protocol = ntohs(h.protocol);
+
+	(*pr)("SPPP: Address = %d(", h.address);
+	switch (h.address) {
+	case PPP_ALLSTATIONS:
+		(*pr)("ALLSTATIONS)\n");
+		(*pr)("SPPP: Protocol = %d(", protocol);
+		switch (protocol) {
+		case PPP_LCP:
+			(*pr)("LCP)\n");
+			break;
+		case PPP_PAP:
+			(*pr)("PAP)\n");
+			break;
+		case PPP_CHAP:
+			(*pr)("CHAP)\n");
+			break;
+		case PPP_IPCP:
+			(*pr)("IPCP)\n");
+			break;
+		case PPP_IPV6CP:
+			(*pr)("IPV6CP)\n");
+			break;
+		case PPP_IP:
+			(*pr)("IP)\n");
+			return m_examine_ip(m, off, modif, pr);
+			break;
+		case PPP_IPV6:
+			(*pr)("IPv6)\n");
+			return m_examine_ip6(m, off, modif, pr);
+			break;
+		default:
+			(*pr)("unknown)\n");
+			break;
+		}
+		break;
+	case CISCO_MULTICAST:
+	case CISCO_UNICAST:
+		if (h.address == CISCO_MULTICAST) {
+			(*pr)("MULTICAST)\n");
+		}
+		else {
+			(*pr)("UNICAST)\n");
+		}
+		(*pr)("SPPP: Protocol = %d(", protocol);
+		switch (protocol) {
+		case CISCO_KEEPALIVE:
+			(*pr)("Keepalive)\n");
+			break;
+		case ETHERTYPE_IP:
+			(*pr)("IP)\n");
+			return m_examine_ip(m, off, modif, pr);
+			break;
+		case ETHERTYPE_IPV6:
+			(*pr)("IPv6)\n");
+			return m_examine_ip6(m, off, modif, pr);
+			break;
+		default:
+			(*pr)("unknown)\n");
+			break;
+		}
+		break;
+	default:
+		(*pr)("unknown)\n", h.address);
+		break;
+	}
+
+	(*pr)("No parser for address %d, protocol %d\n", h.address, protocol);
+	return m_examine_hex(m, off, modif, pr);
+}
+
+static void
+m_examine_arp(const struct mbuf *m, int off, const char *modif,
+    void (*pr)(const char *, ...))
+{
+	unsigned int pktlen;
+	struct arphdr ar;
+	uint16_t hrd, op;
+	struct in_addr isaddr, itaddr;
+	uint8_t esaddr[ETHER_ADDR_LEN], etaddr[ETHER_ADDR_LEN];
+
+	pktlen = m_peek_len(m, modif) - off;
+	if (pktlen < sizeof(ar)) {
+		(*pr)("%s: too short mbuf chain\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+
+	if (m_peek_data(m, off, sizeof(ar), (void *)(&ar)) < 0) {
+		(*pr)("%s: cannot read header\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+	off += sizeof(ar);
+
+	hrd = ntohs(ar.ar_hrd);
+	(*pr)("ARP: AddressType = %u(", hrd);
+	switch (hrd) {
+	case ARPHRD_ETHER:
+		(*pr)("ETHER)\n");
+		break;
+	case ARPHRD_IEEE802:
+		(*pr)("IEEE802)\n");
+		break;
+	default:
+		(*pr)("unknown)\n");
+		return m_examine_hex(m, off, modif, pr);
+		break;
+	}
+	(*pr)("ARP: Protocol Address Format = %u\n", ntohs(ar.ar_pro));
+	(*pr)("ARP: Protocol Address Length = %u\n", ar.ar_pln);
+	(*pr)("ARP: H/W Address Length = %u\n", ar.ar_hln);
+	op = ntohs(ar.ar_op);
+	(*pr)("ARP: Operation = %u(", op);
+	switch (op) {
+	case ARPOP_REQUEST:
+		(*pr)("REQUEST)\n");
+		break;
+	case ARPOP_REPLY:
+		(*pr)("REPLY)\n");
+		break;
+	case ARPOP_REVREQUEST:
+		(*pr)("REVREQUEST)\n");
+		break;
+	case ARPOP_REVREPLY:
+		(*pr)("REVREPLY)\n");
+		break;
+	case ARPOP_INVREQUEST:
+		(*pr)("INVREQUEST)\n");
+		break;
+	case ARPOP_INVREPLY:
+		(*pr)("INVREPLY)\n");
+		break;
+	}
+
+	if (ar.ar_hln == 0 || ar.ar_pln == 0 ||
+	    ar.ar_hln != sizeof(esaddr) || ar.ar_pln != sizeof(isaddr)) {
+		(*pr)("Cannot parse.\n");
+		return m_examine_hex(m, off, modif, pr);
+	}
+
+	if (m_peek_data(m, off, sizeof(esaddr), (void *)(esaddr)) < 0) {
+		(*pr)("Cannot read payload\n");
+		return m_examine_hex(m, off, modif, pr);
+	}
+	off += sizeof(esaddr);
+	(*pr)("ARP: Ether Src = %s\n", str_ethaddr(esaddr));
+
+	if (m_peek_data(m, off, sizeof(isaddr), (void *)(&isaddr)) < 0) {
+		(*pr)("Cannot read payload\n");
+		return m_examine_hex(m, off, modif, pr);
+	}
+	off += sizeof(isaddr);
+	(*pr)("ARP: IP Src = %s\n", str_ipaddr(&isaddr));
+
+	if (m_peek_data(m, off, sizeof(etaddr), (void *)(etaddr)) < 0) {
+		(*pr)("Cannot read payload\n");
+		return m_examine_hex(m, off, modif, pr);
+	}
+	off += sizeof(etaddr);
+	(*pr)("ARP: Ether Tgt = %s\n", str_ethaddr(etaddr));
+
+	if (m_peek_data(m, off, sizeof(itaddr), (void *)(&itaddr)) < 0) {
+		(*pr)("Cannot read payload\n");
+		return m_examine_hex(m, off, modif, pr);
+	}
+	off += sizeof(itaddr);
+	(*pr)("ARP: IP Tgt = %s\n", str_ipaddr(&itaddr));
+
+	return m_examine_hex(m, off, modif, pr);
+}
+
+static void
+m_examine_ip(const struct mbuf *m, int off, const char *modif,
+    void (*pr)(const char *, ...))
+{
+	unsigned int pktlen;
+	struct ip ip;
+	uint16_t offset;
+
+	pktlen = m_peek_len(m, modif) - off;
+	if (pktlen < sizeof(ip)) {
+		(*pr)("%s: too short mbuf chain\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+
+	if (m_peek_data(m, off, sizeof(ip), (void *)(&ip)) < 0) {
+		(*pr)("%s: cannot read header\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+	off += sizeof(ip);
+
+	(*pr)("IP: Version = %u\n", ip.ip_v);
+	(*pr)("IP: Header Length = %u\n", (ip.ip_hl << 2));
+	(*pr)("IP: ToS = 0x%02x\n", ip.ip_tos);
+	(*pr)("IP: Packet Length = %u\n", ntohs(ip.ip_len));
+	(*pr)("IP: ID = %u\n", ntohs(ip.ip_id));
+	offset = ntohs(ip.ip_off);
+	(*pr)("IP: Offset = %u\n", (offset & IP_OFFMASK));
+	if (offset & IP_RF) {
+		(*pr)("IP: Flag 0x%04x (reserved)\n", IP_RF);
+	}
+	if (offset & IP_EF) {
+		(*pr)("IP: Flag 0x%04x (evil flag)\n", IP_EF);
+	}
+	if (offset & IP_DF) {
+		(*pr)("IP: Flag 0x%04x (don't fragment)\n", IP_DF);
+	}
+	if (offset & IP_MF) {
+		(*pr)("IP: Flag 0x%04x (more fragment)\n", IP_MF);
+	}
+	(*pr)("IP: TTL = %u\n", ip.ip_ttl);
+	(*pr)("IP: protocol = %u(%s)\n", ip.ip_p, str_ipproto(ip.ip_p));
+	(*pr)("IP: Src = %s\n", str_ipaddr(&ip.ip_src));
+	(*pr)("IP: Dst = %s\n", str_ipaddr(&ip.ip_dst));
+
+
+	switch (ip.ip_p) {
+	case IPPROTO_ICMP:
+		return m_examine_icmp(m, off, modif, pr);
+		break;
+	case IPPROTO_TCP:
+		return m_examine_tcp(m, off, modif, pr);
+		break;
+	case IPPROTO_UDP:
+		return m_examine_udp(m, off, modif, pr);
+		break;
+	default:
+		break;
+	}
+
+
+	return m_examine_hex(m, off, modif, pr);
+}
+
+static void
+m_examine_icmp(const struct mbuf *m, int off, const char *modif,
+    void (*pr)(const char *, ...))
+{
+	unsigned int pktlen;
+	struct icmp icmphdr;
+
+	pktlen = m_peek_len(m, modif) - off;
+	if (pktlen < sizeof(icmphdr)) {
+		(*pr)("%s: too short mbuf chain\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+
+	if (m_peek_data(m, off, sizeof(icmphdr), (void *)(&icmphdr)) < 0) {
+		(*pr)("%s: cannot read header\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+	off += sizeof(icmphdr);
+
+	(*pr)("ICMP: Type = %u(", icmphdr.icmp_type);
+	switch (icmphdr.icmp_type) {
+	case ICMP_ECHOREPLY:
+		(*pr)("Echo Reply)\n");
+		break;
+	case ICMP_UNREACH:
+		(*pr)("Destination Unreachable)\n");
+		break;
+	case ICMP_SOURCEQUENCH:
+		(*pr)("Source Quench)\n");
+		break;
+	case ICMP_REDIRECT:
+		(*pr)("Redirect)\n");
+		break;
+	case ICMP_TIMXCEED:
+		(*pr)("Time Exceeded)\n");
+		break;
+	default:
+		(*pr)("unknown)\n");
+		break;
+	}
+	(*pr)("ICMP: Code = %d\n", icmphdr.icmp_code);
+
+	return m_examine_hex(m, off, modif, pr);
+}
+
+static void
+m_examine_ip6(const struct mbuf *m, int off, const char *modif,
+    void (*pr)(const char *, ...))
+{
+	unsigned int pktlen;
+	struct ip6_hdr ip6;
+	struct ip6_hbh hbh;
+	int hbhlen;
+	uint32_t flow;
+	uint8_t vfc;
+	uint8_t nxt;
+
+	pktlen = m_peek_len(m, modif) - off;
+	if (pktlen < sizeof(ip6)) {
+		(*pr)("%s: too short mbuf chain\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+
+	if (m_peek_data(m, off, sizeof(ip6), (void *)(&ip6)) < 0) {
+		(*pr)("%s: cannot read header\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+	off += sizeof(ip6);
+
+	vfc = ip6.ip6_vfc;
+	(*pr)("IPv6: Version = %u\n", (vfc & IPV6_VERSION_MASK) >> 4);
+	flow = ntohl(ip6.ip6_flow);
+	(*pr)("IPv6: Flow INFO = 0x%07x\n", flow & IPV6_FLOWINFO_MASK);
+	(*pr)("IPv6: Payload Length = %u\n", ip6.ip6_plen);
+	nxt = ip6.ip6_nxt;
+	(*pr)("IPv6: Next Header = %u(%s)\n", nxt, str_ipproto(nxt));
+	(*pr)("IPv6: Hop Limit = %u\n", ip6.ip6_hlim);
+	(*pr)("IPv6: Src = %s\n", str_ip6addr(&ip6.ip6_src));
+	(*pr)("IPv6: Dst = %s\n", str_ip6addr(&ip6.ip6_dst));
+
+	/* Strip Hop-by-Hop options */
+	if (nxt == IPPROTO_HOPOPTS) {
+		if (m_peek_data(m, off, sizeof(hbh), (void *)(&hbh)) < 0) {
+			(*pr)("Cannot read option\n");
+			return m_examine_hex(m, off, modif, pr);
+		}
+		hbhlen = (hbh.ip6h_len + 1) << 3;
+		nxt = hbh.ip6h_nxt;
+		off += hbhlen;
+
+		(*pr)("IPv6: Stripped Hop-by-Hop\n");
+		(*pr)("IPv6: Next Header = %u(%s)\n", nxt, str_ipproto(nxt));
+	}
+
+	switch (nxt) {
+	case IPPROTO_IPV6_ICMP:
+		return m_examine_icmp6(m, off, modif, pr);
+		break;
+	case IPPROTO_TCP:
+		return m_examine_tcp(m, off, modif, pr);
+		break;
+	case IPPROTO_UDP:
+		return m_examine_udp(m, off, modif, pr);
+		break;
+	default:
+		break;
+	}
+
+	return m_examine_hex(m, off, modif, pr);
+}
+
+static void
+m_examine_icmp6(const struct mbuf *m, int off, const char *modif,
+    void (*pr)(const char *, ...))
+{
+	unsigned int pktlen;
+	struct icmp6_hdr icmp6;
+
+	pktlen = m_peek_len(m, modif) - off;
+	if (pktlen < sizeof(icmp6)) {
+		(*pr)("%s: too short mbuf chain\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+
+	if (m_peek_data(m, off, sizeof(icmp6), (void *)(&icmp6)) < 0) {
+		(*pr)("%s: cannot read header\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+	off += sizeof(icmp6);
+
+	(*pr)("ICMP6: Type = %u(", icmp6.icmp6_type);
+	switch (icmp6.icmp6_type) {
+	case ICMP6_DST_UNREACH:
+		(*pr)("Destination Unreachable)\n");
+		break;
+	case ICMP6_PACKET_TOO_BIG:
+		(*pr)("Packet Too Big)\n");
+		break;
+	case ICMP6_TIME_EXCEEDED:
+		(*pr)("Time Exceeded)\n");
+		break;
+	case ICMP6_PARAM_PROB:
+		(*pr)("Parameter Problem)\n");
+		break;
+	case ICMP6_ECHO_REQUEST:
+		(*pr)("Echo Request)\n");
+		break;
+	case ICMP6_ECHO_REPLY:
+		(*pr)("Echo Reply)\n");
+		break;
+
+	case MLD_LISTENER_QUERY:
+		(*pr)("MLD Listener Query)\n");
+		break;
+	case MLD_LISTENER_REPORT:
+		(*pr)("MLD Listener Report)\n");
+		break;
+	case MLD_LISTENER_DONE:
+		(*pr)("MLD Listener Done)\n");
+		break;
+
+	case ND_ROUTER_SOLICIT:
+		(*pr)("Router Solicitation)\n");
+		break;
+	case ND_ROUTER_ADVERT:
+		(*pr)("Router Advertizement)\n");
+		break;
+	case ND_NEIGHBOR_SOLICIT:
+		(*pr)("Neighbor Solicitation)\n");
+		break;
+	case ND_NEIGHBOR_ADVERT:
+		(*pr)("Neighbor Advertizement)\n");
+		break;
+	case ND_REDIRECT:
+		(*pr)("Redirect)\n");
+		break;
+
+	default:
+		(*pr)("unknown)\n");
+		break;
+	}
+	(*pr)("ICMP6: Code = %u\n", icmp6.icmp6_code);
+
+	return m_examine_hex(m, off, modif, pr);
+}
+
+static void
+m_examine_tcp(const struct mbuf *m, int off, const char *modif,
+    void (*pr)(const char *, ...))
+{
+	unsigned int pktlen;
+	struct tcphdr tcp;
+
+	pktlen = m_peek_len(m, modif) - off;
+	if (pktlen < sizeof(tcp)) {
+		(*pr)("%s: too short mbuf chain\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+
+	if (m_peek_data(m, off, sizeof(tcp), (void *)(&tcp)) < 0) {
+		(*pr)("%s: cannot read header\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+	off += sizeof(tcp);
+
+	(*pr)("TCP: Src = %u\n", ntohs(tcp.th_sport));
+	(*pr)("TCP: Dst = %u\n", ntohs(tcp.th_dport));
+	(*pr)("TCP: Seq. = %u\n", ntohl(tcp.th_seq));
+	(*pr)("TCP: Ack. = %u\n", ntohl(tcp.th_ack));
+	(*pr)("TCP: Header Length = %u\n", ntohl(tcp.th_off) << 2);
+	if (tcp.th_flags) {
+		(*pr)("TCP: Flags 0x%02x : ", tcp.th_flags);
+		if (tcp.th_flags & TH_FIN)
+			(*pr)("FIN ");
+		if (tcp.th_flags & TH_SYN)
+			(*pr)("SYN ");
+		if (tcp.th_flags & TH_RST)
+			(*pr)("RST ");
+		if (tcp.th_flags & TH_PUSH)
+			(*pr)("PUSH ");
+		if (tcp.th_flags & TH_URG)
+			(*pr)("URG ");
+		if (tcp.th_flags & TH_ECE)
+			(*pr)("ECE ");
+		if (tcp.th_flags & TH_CWR)
+			(*pr)("CWR ");
+		(*pr)("\n");
+	}
+	(*pr)("TCP: Windows Size = %u\n", ntohs(tcp.th_win));
+	(*pr)("TCP: Urgent Pointer = %u\n", ntohs(tcp.th_urp));
+
+	return m_examine_hex(m, off, modif, pr);
+}
+
+static void
+m_examine_udp(const struct mbuf *m, int off, const char *modif,
+    void (*pr)(const char *, ...))
+{
+	unsigned int pktlen;
+	struct udphdr udp;
+
+	pktlen = m_peek_len(m, modif) - off;
+	if (pktlen < sizeof(udp)) {
+		(*pr)("%s: too short mbuf chain\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+
+	if (m_peek_data(m, off, sizeof(udp), (void *)(&udp)) < 0) {
+		(*pr)("%s: cannot read header\n", __func__);
+		return m_examine_hex(m, off, modif, pr);
+	}
+	off += sizeof(udp);
+
+	(*pr)("UDP: Src = %u\n", ntohs(udp.uh_sport));
+	(*pr)("UDP: Dst = %u\n", ntohs(udp.uh_dport));
+	(*pr)("UDP: Length = %u\n", ntohs(udp.uh_ulen));
+
+	return m_examine_hex(m, off, modif, pr);
+}
+
+static void
+m_examine_hex(const struct mbuf *m, int off, const char *modif,
+    void (*pr)(const char *, ...))
+{
+	unsigned int pktlen;
+	int newline = 0;
+	uint8_t v;
+
+	pktlen = m_peek_len(m, modif) - off;
+	if (pktlen > EXAMINE_HEX_LIMIT)
+		pktlen = EXAMINE_HEX_LIMIT;
+
+	if (pktlen == 0)
+		return;
+
+	(*pr)("offset %04d: ", off);
+	while (pktlen > 0) {
+		if (m_peek_data(m, off, sizeof(v), (void *)(&v)) < 0)
+			break;
+		pktlen --;
+		off++;
+		newline++;
+
+		(*pr)("%02x", v);
+		if (pktlen == 0)
+			break;
+
+		if ((newline % EXAMINE_HEX_COL) == 0) {
+			(*pr)("\n");
+			(*pr)("offset %04d: ", off);
+		}
+		else {
+			(*pr)(" ");
+		}
+	}
+	(*pr)("\n");
+}
+
+void
+m_examine(const struct mbuf *m, int af, const char *modif,
+    void (*pr)(const char *, ...))
+{
+	if (m == NULL)
+		return;
+
+	if (pr == NULL)
+		return;
+
+	switch (af) {
+	case AF_UNSPEC:
+		return m_examine_hex(m, 0, modif, pr);
+		break;
+	case AF_ETHER:
+		return m_examine_ether(m, 0, modif, pr);
+		break;
+	case AF_ARP:
+		return m_examine_arp(m, 0, modif, pr);
+		break;
+	case AF_INET:
+		return m_examine_ip(m, 0, modif, pr);
+		break;
+	case AF_INET6:
+		return m_examine_ip6(m, 0, modif, pr);
+		break;
+	default:
+		(*pr)("No parser for AF %d\n", af);
+		return m_examine_hex(m, 0, modif, pr);
+		break;
+	}
+
+	/* not reached */
+	return;
+}

Reply via email to