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;
+}