Home | History | Annotate | Line # | Download | only in kern
      1 /*	$NetBSD: uipc_mbufdebug.c,v 1.9 2025/02/16 18:49:59 jakllsch Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 2017 Internet Initiative Japan Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: uipc_mbufdebug.c,v 1.9 2025/02/16 18:49:59 jakllsch Exp $");
     31 
     32 #include <sys/param.h>
     33 #include <sys/types.h>
     34 
     35 #include <sys/malloc.h>
     36 #include <sys/mbuf.h>
     37 #include <sys/proc.h>
     38 #include <sys/systm.h>
     39 
     40 #include <net/if.h>
     41 #include <net/if_arp.h>
     42 #include <net/if_ether.h>
     43 #include <net/ppp_defs.h>
     44 
     45 #include <netinet/icmp6.h>
     46 #include <netinet/if_inarp.h>
     47 #include <netinet/in.h>
     48 #include <netinet/in_systm.h>
     49 #include <netinet/ip.h>
     50 #include <netinet/ip6.h>
     51 #include <netinet/ip_icmp.h>
     52 #include <netinet/tcp.h>
     53 #include <netinet/udp.h>
     54 
     55 #define EXAMINE_HEX_LIMIT 128
     56 #define EXAMINE_HEX_COL 4
     57 
     58 /* mbuf operations without change of mbuf chain */
     59 static int m_peek_data(const struct mbuf *, int, int, void *);
     60 static unsigned int m_peek_len(const struct mbuf *, const char *);
     61 
     62 /* utility */
     63 static char *str_ethaddr(const uint8_t *);
     64 static char *str_ipaddr(const struct in_addr *);
     65 static char *str_ip6addr(const struct in6_addr *);
     66 static const char *str_ipproto(const uint8_t);
     67 
     68 /* header structure for some protocol */
     69 struct pppoehdr {
     70 	uint8_t vertype;
     71 	uint8_t code;
     72 	uint16_t session;
     73 	uint16_t plen;
     74 } __attribute__((__packed__));
     75 
     76 struct pppoetag {
     77 	uint16_t tag;
     78 	uint16_t len;
     79 } __attribute__((__packed__));
     80 
     81 #define PPPOE_TAG_EOL 0x0000
     82 #define PPPOE_CODE_PADI		0x09	/* Active Discovery Initiation */
     83 #define	PPPOE_CODE_PADO		0x07	/* Active Discovery Offer */
     84 #define	PPPOE_CODE_PADR		0x19	/* Active Discovery Request */
     85 #define	PPPOE_CODE_PADS		0x65	/* Active Discovery Session confirmation */
     86 #define	PPPOE_CODE_PADT		0xA7	/* Active Discovery Terminate */
     87 
     88 struct ppp_header {
     89 	uint8_t address;
     90 	uint8_t control;
     91 	uint16_t protocol;
     92 } __attribute__((__packed__));
     93 
     94 #define CISCO_MULTICAST		0x8f	/* Cisco multicast address */
     95 #define CISCO_UNICAST		0x0f	/* Cisco unicast address */
     96 #define CISCO_KEEPALIVE		0x8035	/* Cisco keepalive protocol */
     97 
     98 #ifndef NELEMS
     99 #define NELEMS(elem) ((sizeof(elem))/(sizeof((elem)[0])))
    100 #endif
    101 
    102 static int
    103 m_peek_data(const struct mbuf *m, int off, int len, void *vp)
    104 {
    105 	unsigned int count;
    106 	char *cp = vp;
    107 
    108 	if (off < 0 || len < 0)
    109 		return -1;
    110 
    111 	while (off > 0) {
    112 		if (m == 0)
    113 			return -1;
    114 		if (off < m->m_len)
    115 			break;
    116 		off -= m->m_len;
    117 		m = m->m_next;
    118 	}
    119 	while (len > 0) {
    120 		if (m == 0)
    121 			return -1;
    122 		count = uimin(m->m_len - off, len);
    123 		memcpy(cp, mtod(m, char *) + off, count);
    124 		len -= count;
    125 		cp += count;
    126 		off = 0;
    127 		m = m->m_next;
    128 	}
    129 
    130 	return 0;
    131 }
    132 
    133 static unsigned int
    134 m_peek_len(const struct mbuf *m, const char *modif)
    135 {
    136 	const struct mbuf *m0;
    137 	unsigned int pktlen;
    138 	bool opt_c = false;
    139 	unsigned char ch;
    140 
    141 	while (modif && (ch = *(modif++)) != '\0') {
    142 		switch (ch) {
    143 		case 'c':
    144 			opt_c = true;
    145 			break;
    146 		}
    147 	}
    148 
    149 	if (opt_c == true)
    150 		return m->m_len;
    151 
    152 	if ((m->m_flags & M_PKTHDR) != 0)
    153 		return m->m_pkthdr.len;
    154 
    155 	pktlen = 0;
    156 	for (m0 = m; m0 != NULL; m0 = m0->m_next)
    157 		pktlen += m0->m_len;
    158 
    159 	return pktlen;
    160 }
    161 
    162 static char *
    163 str_ethaddr(const uint8_t *ap)
    164 {
    165 	static char buf[3 * ETHER_ADDR_LEN];
    166 
    167 	return ether_snprintf(buf, sizeof(buf), ap);
    168 }
    169 
    170 static char *
    171 str_ipaddr(const struct in_addr *ap)
    172 {
    173 	static char buf[INET_ADDRSTRLEN];
    174 
    175 	return IN_PRINT(buf, ap);
    176 }
    177 
    178 static char *
    179 str_ip6addr(const struct in6_addr *ap)
    180 {
    181 	static char buf[INET6_ADDRSTRLEN];
    182 
    183 	return IN6_PRINT(buf, ap);
    184 }
    185 
    186 static const char *
    187 str_ipproto(const uint8_t proto)
    188 {
    189 
    190 	switch (proto) {
    191 	case IPPROTO_HOPOPTS:
    192 		return ("IPv6 Hop-by-Hop");
    193 		break;
    194 	case IPPROTO_TCP:
    195 		return("TCP");
    196 		break;
    197 	case IPPROTO_UDP:
    198 		return("UDP");
    199 		break;
    200 	case IPPROTO_ICMP:
    201 		return("ICMP");
    202 		break;
    203 	case IPPROTO_IGMP:
    204 		return("IGMP");
    205 		break;
    206 	case IPPROTO_ESP:
    207 		return("ESP");
    208 		break;
    209 	case IPPROTO_AH:
    210 		return("AH");
    211 		break;
    212 	case IPPROTO_IPV6_ICMP:
    213 		return("ICMP6");
    214 	default:
    215 		return("unknown");
    216 		break;
    217 	}
    218 
    219 	/* not reached */
    220 	return NULL;
    221 }
    222 
    223 void
    224 m_examine_ether(const struct mbuf *m, int off, const char *modif,
    225     void (*pr)(const char *, ...))
    226 {
    227 	struct ether_header eh;
    228 	unsigned int pktlen;
    229 
    230 	pktlen = m_peek_len(m, modif) - off;
    231 	if (pktlen < sizeof(eh)) {
    232 		(*pr)("%s: too short mbuf chain (%u < %u)\n", __func__,
    233 		    pktlen, sizeof(eh));
    234 		return m_examine_hex(m, off, modif, pr);
    235 	}
    236 
    237 	if (m_peek_data(m, off, sizeof(eh), (void *)(&eh)) < 0) {
    238 		(*pr)("%s: cannot read header\n", __func__);
    239 		return m_examine_hex(m, off, modif, pr);
    240 	}
    241 	off += sizeof(eh);
    242 
    243 	(*pr)("ETHER: DST = %s\n", str_ethaddr(eh.ether_dhost));
    244 	(*pr)("ETHER: SRC = %s\n", str_ethaddr(eh.ether_shost));
    245 
    246 again:
    247 	(*pr)("ETHER: TYPE = 0x%04x(", ntohs(eh.ether_type));
    248 	switch (ntohs(eh.ether_type)) {
    249 	case ETHERTYPE_VLAN:
    250 		(*pr)("VLAN)\n");
    251 
    252 		pktlen = m_peek_len(m, modif) - off;
    253 		if (pktlen < 4) {
    254 			return m_examine_hex(m, off, modif, pr);
    255 		}
    256 		if (m_peek_data(m, off + 2, sizeof(eh.ether_type), (void *)(&eh.ether_type)) < 0) {
    257 			(*pr)("%s: cannot read header\n", __func__);
    258 			return m_examine_hex(m, off, modif, pr);
    259 		}
    260 		off += 4;
    261 		goto again;
    262 		break;
    263 	case ETHERTYPE_PPPOE:
    264 		(*pr)("PPPoE)\n");
    265 		return m_examine_pppoe(m, off, modif, pr);
    266 		break;
    267 	case ETHERTYPE_ARP:
    268 		(*pr)("ARP)\n");
    269 		return m_examine_arp(m, off, modif, pr);
    270 		break;
    271 	case ETHERTYPE_IP:
    272 		(*pr)("IPv4)\n");
    273 		return m_examine_ip(m, off, modif, pr);
    274 		break;
    275 	case ETHERTYPE_IPV6:
    276 		(*pr)("IPv6)\n");
    277 		return m_examine_ip6(m, off, modif, pr);
    278 		break;
    279 	default:
    280 		(*pr)("unknown)\n");
    281 		break;
    282 	}
    283 
    284 	return m_examine_hex(m, off, modif, pr);
    285 }
    286 
    287 void
    288 m_examine_pppoe(const struct mbuf *m, int off, const char *modif,
    289     void (*pr)(const char *, ...))
    290 {
    291 	struct pppoehdr ph;
    292 	struct pppoetag pt;
    293 	unsigned int pktlen;
    294 	uint8_t vt;
    295 
    296 	pktlen = m_peek_len(m, modif) - off;
    297 	if (pktlen < sizeof(ph)) {
    298 		(*pr)("%s: too short mbuf chain (%u, %u)\n", __func__,
    299 		    pktlen, sizeof(ph));
    300 		return m_examine_hex(m, off, modif, pr);
    301 	}
    302 
    303 	if (m_peek_data(m, off, sizeof(ph), (void *)(&ph)) < 0) {
    304 		(*pr)("%s: cannot read header\n", __func__);
    305 		return m_examine_hex(m, off, modif, pr);
    306 	}
    307 	off += sizeof(ph);
    308 
    309 	while (off + sizeof(pt) > pktlen) {
    310 		if (m_peek_data(m, off, sizeof(pt), (void *)(&pt)) < 0) {
    311 			(*pr)("%s: cannot read header\n", __func__);
    312 			return m_examine_hex(m, off, modif, pr);
    313 		}
    314 		off += sizeof(pt);
    315 
    316 		if (ntohs(pt.tag) == PPPOE_TAG_EOL)
    317 			break;
    318 		off += ntohs(pt.len);
    319 	}
    320 
    321 	vt = ph.vertype;
    322 
    323 	(*pr)("PPPoE: Version = %u\n", ((vt >> 4) & 0xff));
    324 	(*pr)("PPPoE: Type = %u\n", (vt & 0xff));
    325 	(*pr)("PPPoE: Code = %u(", ph.code);
    326 	switch (ph.code) {
    327 	case 0:
    328 		(*pr)("DATA");
    329 		break;
    330 	case PPPOE_CODE_PADI:
    331 		(*pr)("PADI");
    332 		break;
    333 	case PPPOE_CODE_PADO:
    334 		(*pr)("PADO");
    335 		break;
    336 	case PPPOE_CODE_PADS:
    337 		(*pr)("PADS");
    338 		break;
    339 	case PPPOE_CODE_PADT:
    340 		(*pr)("PADT");
    341 		break;
    342 	default:
    343 		(*pr)("unknown");
    344 		break;
    345 	}
    346 	(*pr)(")\n");
    347 
    348 	(*pr)("PPPoE: Session = 0x%04x\n", ntohs(ph.session));
    349 	(*pr)("PPPoE: Payload Length = %u\n", ntohs(ph.plen));
    350 
    351 	switch (ph.code) {
    352 	case PPPOE_CODE_PADI:
    353 	case PPPOE_CODE_PADO:
    354 	case PPPOE_CODE_PADS:
    355 	case PPPOE_CODE_PADT:
    356 		(*pr)("No parser for PPPoE control frame.\n");
    357 		return m_examine_hex(m, off, modif, pr);
    358 		break;
    359 	}
    360 
    361 	if (ph.code != 0) {
    362 		(*pr)("Unknown PPPoE code.\n");
    363 		return m_examine_hex(m, off, modif, pr);
    364 	}
    365 
    366 	return m_examine_ppp(m, off, modif, pr);
    367 }
    368 
    369 void
    370 m_examine_ppp(const struct mbuf *m, int off, const char *modif,
    371     void (*pr)(const char *, ...))
    372 {
    373 	struct ppp_header h;
    374 	unsigned int pktlen;
    375 	uint16_t protocol;
    376 
    377 	pktlen = m_peek_len(m, modif) - off;
    378 	if (pktlen < sizeof(h)) {
    379 		(*pr)("%s: too short mbuf chain (%u < %u)\n", __func__,
    380 		    pktlen, sizeof(h));
    381 		return m_examine_hex(m, off, modif, pr);
    382 	}
    383 
    384 	if (m_peek_data(m, off, sizeof(h), (void *)(&h)) < 0) {
    385 		(*pr)("%s: cannot read header\n", __func__);
    386 		return m_examine_hex(m, off, modif, pr);
    387 	}
    388 	off += sizeof(h);
    389 
    390 	protocol = ntohs(h.protocol);
    391 
    392 	(*pr)("SPPP: Address = %d(", h.address);
    393 	switch (h.address) {
    394 	case PPP_ALLSTATIONS:
    395 		(*pr)("ALLSTATIONS)\n");
    396 		(*pr)("SPPP: Protocol = %d(", protocol);
    397 		switch (protocol) {
    398 		case PPP_LCP:
    399 			(*pr)("LCP)\n");
    400 			break;
    401 		case PPP_PAP:
    402 			(*pr)("PAP)\n");
    403 			break;
    404 		case PPP_CHAP:
    405 			(*pr)("CHAP)\n");
    406 			break;
    407 		case PPP_IPCP:
    408 			(*pr)("IPCP)\n");
    409 			break;
    410 		case PPP_IPV6CP:
    411 			(*pr)("IPV6CP)\n");
    412 			break;
    413 		case PPP_IP:
    414 			(*pr)("IP)\n");
    415 			return m_examine_ip(m, off, modif, pr);
    416 			break;
    417 		case PPP_IPV6:
    418 			(*pr)("IPv6)\n");
    419 			return m_examine_ip6(m, off, modif, pr);
    420 			break;
    421 		default:
    422 			(*pr)("unknown)\n");
    423 			break;
    424 		}
    425 		break;
    426 	case CISCO_MULTICAST:
    427 	case CISCO_UNICAST:
    428 		if (h.address == CISCO_MULTICAST)
    429 			(*pr)("MULTICAST)\n");
    430 		else
    431 			(*pr)("UNICAST)\n");
    432 
    433 		(*pr)("SPPP: Protocol = %d(", protocol);
    434 		switch (protocol) {
    435 		case CISCO_KEEPALIVE:
    436 			(*pr)("Keepalive)\n");
    437 			break;
    438 		case ETHERTYPE_IP:
    439 			(*pr)("IP)\n");
    440 			return m_examine_ip(m, off, modif, pr);
    441 			break;
    442 		case ETHERTYPE_IPV6:
    443 			(*pr)("IPv6)\n");
    444 			return m_examine_ip6(m, off, modif, pr);
    445 			break;
    446 		default:
    447 			(*pr)("unknown)\n");
    448 			break;
    449 		}
    450 		break;
    451 	default:
    452 		(*pr)("unknown)\n", h.address);
    453 		break;
    454 	}
    455 
    456 	(*pr)("No parser for address %d, protocol %d\n", h.address, protocol);
    457 	return m_examine_hex(m, off, modif, pr);
    458 }
    459 
    460 void
    461 m_examine_arp(const struct mbuf *m, int off, const char *modif,
    462     void (*pr)(const char *, ...))
    463 {
    464 	unsigned int pktlen;
    465 	struct arphdr ar;
    466 	uint16_t hrd, op;
    467 	struct in_addr isaddr, itaddr;
    468 	uint8_t esaddr[ETHER_ADDR_LEN], etaddr[ETHER_ADDR_LEN];
    469 
    470 	pktlen = m_peek_len(m, modif) - off;
    471 	if (pktlen < sizeof(ar)) {
    472 		(*pr)("%s: too short mbuf chain (%u < %u)\n", __func__,
    473 		    pktlen, sizeof(ar));
    474 		return m_examine_hex(m, off, modif, pr);
    475 	}
    476 
    477 	if (m_peek_data(m, off, sizeof(ar), (void *)(&ar)) < 0) {
    478 		(*pr)("%s: cannot read header\n", __func__);
    479 		return m_examine_hex(m, off, modif, pr);
    480 	}
    481 	off += sizeof(ar);
    482 
    483 	hrd = ntohs(ar.ar_hrd);
    484 	(*pr)("ARP: AddressType = %u(", hrd);
    485 	switch (hrd) {
    486 	case ARPHRD_ETHER:
    487 		(*pr)("ETHER)\n");
    488 		break;
    489 	case ARPHRD_IEEE802:
    490 		(*pr)("IEEE802)\n");
    491 		break;
    492 	default:
    493 		(*pr)("unknown)\n");
    494 		return m_examine_hex(m, off, modif, pr);
    495 		break;
    496 	}
    497 	(*pr)("ARP: Protocol Address Format = %u\n", ntohs(ar.ar_pro));
    498 	(*pr)("ARP: Protocol Address Length = %u\n", ar.ar_pln);
    499 	(*pr)("ARP: H/W Address Length = %u\n", ar.ar_hln);
    500 	op = ntohs(ar.ar_op);
    501 	(*pr)("ARP: Operation = %u(", op);
    502 	switch (op) {
    503 	case ARPOP_REQUEST:
    504 		(*pr)("REQUEST)\n");
    505 		break;
    506 	case ARPOP_REPLY:
    507 		(*pr)("REPLY)\n");
    508 		break;
    509 	case ARPOP_REVREQUEST:
    510 		(*pr)("REVREQUEST)\n");
    511 		break;
    512 	case ARPOP_REVREPLY:
    513 		(*pr)("REVREPLY)\n");
    514 		break;
    515 	case ARPOP_INVREQUEST:
    516 		(*pr)("INVREQUEST)\n");
    517 		break;
    518 	case ARPOP_INVREPLY:
    519 		(*pr)("INVREPLY)\n");
    520 		break;
    521 	}
    522 
    523 	if (ar.ar_hln == 0 || ar.ar_pln == 0 ||
    524 	    ar.ar_hln != sizeof(esaddr) || ar.ar_pln != sizeof(isaddr)) {
    525 		(*pr)("Cannot parse.\n");
    526 		return m_examine_hex(m, off, modif, pr);
    527 	}
    528 
    529 	if (m_peek_data(m, off, sizeof(esaddr), (void *)(esaddr)) < 0) {
    530 		(*pr)("Cannot read payload\n");
    531 		return m_examine_hex(m, off, modif, pr);
    532 	}
    533 	off += sizeof(esaddr);
    534 	(*pr)("ARP: Ether Src = %s\n", str_ethaddr(esaddr));
    535 
    536 	if (m_peek_data(m, off, sizeof(isaddr), (void *)(&isaddr)) < 0) {
    537 		(*pr)("Cannot read payload\n");
    538 		return m_examine_hex(m, off, modif, pr);
    539 	}
    540 	off += sizeof(isaddr);
    541 	(*pr)("ARP: IP Src = %s\n", str_ipaddr(&isaddr));
    542 
    543 	if (m_peek_data(m, off, sizeof(etaddr), (void *)(etaddr)) < 0) {
    544 		(*pr)("Cannot read payload\n");
    545 		return m_examine_hex(m, off, modif, pr);
    546 	}
    547 	off += sizeof(etaddr);
    548 	(*pr)("ARP: Ether Tgt = %s\n", str_ethaddr(etaddr));
    549 
    550 	if (m_peek_data(m, off, sizeof(itaddr), (void *)(&itaddr)) < 0) {
    551 		(*pr)("Cannot read payload\n");
    552 		return m_examine_hex(m, off, modif, pr);
    553 	}
    554 	off += sizeof(itaddr);
    555 	(*pr)("ARP: IP Tgt = %s\n", str_ipaddr(&itaddr));
    556 
    557 	return m_examine_hex(m, off, modif, pr);
    558 }
    559 
    560 void
    561 m_examine_ip(const struct mbuf *m, int off, const char *modif,
    562     void (*pr)(const char *, ...))
    563 {
    564 	unsigned int pktlen;
    565 	struct ip ip;
    566 	uint16_t offset;
    567 
    568 	pktlen = m_peek_len(m, modif) - off;
    569 	if (pktlen < sizeof(ip)) {
    570 		(*pr)("%s: too short mbuf chain (%u < %u)\n", __func__,
    571 		    pktlen, sizeof(ip));
    572 		return m_examine_hex(m, off, modif, pr);
    573 	}
    574 
    575 	if (m_peek_data(m, off, sizeof(ip), (void *)(&ip)) < 0) {
    576 		(*pr)("%s: cannot read header\n", __func__);
    577 		return m_examine_hex(m, off, modif, pr);
    578 	}
    579 	off += sizeof(ip);
    580 
    581 	(*pr)("IP: Version = %u\n", ip.ip_v);
    582 	(*pr)("IP: Header Length = %u\n", (ip.ip_hl << 2));
    583 	(*pr)("IP: ToS = 0x%02x\n", ip.ip_tos);
    584 	(*pr)("IP: Packet Length = %u\n", ntohs(ip.ip_len));
    585 	(*pr)("IP: ID = %u\n", ntohs(ip.ip_id));
    586 	offset = ntohs(ip.ip_off);
    587 	(*pr)("IP: Offset = %u\n", (offset & IP_OFFMASK));
    588 	if (offset & IP_RF)
    589 		(*pr)("IP: Flag 0x%04x (reserved)\n", IP_RF);
    590 	if (offset & IP_EF)
    591 		(*pr)("IP: Flag 0x%04x (evil flag)\n", IP_EF);
    592 	if (offset & IP_DF)
    593 		(*pr)("IP: Flag 0x%04x (don't fragment)\n", IP_DF);
    594 	if (offset & IP_MF)
    595 		(*pr)("IP: Flag 0x%04x (more fragment)\n", IP_MF);
    596 	(*pr)("IP: TTL = %u\n", ip.ip_ttl);
    597 	(*pr)("IP: protocol = %u(%s)\n", ip.ip_p, str_ipproto(ip.ip_p));
    598 	(*pr)("IP: checksum = 0x%04x\n", ntohs(ip.ip_sum));
    599 	(*pr)("IP: Src = %s\n", str_ipaddr(&ip.ip_src));
    600 	(*pr)("IP: Dst = %s\n", str_ipaddr(&ip.ip_dst));
    601 
    602 	switch (ip.ip_p) {
    603 	case IPPROTO_ICMP:
    604 		return m_examine_icmp(m, off, modif, pr);
    605 		break;
    606 	case IPPROTO_TCP:
    607 		return m_examine_tcp(m, off, modif, pr);
    608 		break;
    609 	case IPPROTO_UDP:
    610 		return m_examine_udp(m, off, modif, pr);
    611 		break;
    612 	default:
    613 		break;
    614 	}
    615 
    616 	return m_examine_hex(m, off, modif, pr);
    617 }
    618 
    619 void
    620 m_examine_icmp(const struct mbuf *m, int off, const char *modif,
    621     void (*pr)(const char *, ...))
    622 {
    623 	unsigned int pktlen;
    624 	struct icmp icmphdr;
    625 
    626 	pktlen = m_peek_len(m, modif) - off;
    627 	if (pktlen < sizeof(icmphdr)) {
    628 		(*pr)("%s: too short mbuf chain (%u < %u)\n", __func__,
    629 		    pktlen, sizeof(icmphdr));
    630 		return m_examine_hex(m, off, modif, pr);
    631 	}
    632 
    633 	if (m_peek_data(m, off, sizeof(icmphdr), (void *)(&icmphdr)) < 0) {
    634 		(*pr)("%s: cannot read header\n", __func__);
    635 		return m_examine_hex(m, off, modif, pr);
    636 	}
    637 	off += sizeof(icmphdr);
    638 
    639 	(*pr)("ICMP: Type = %u(", icmphdr.icmp_type);
    640 	switch (icmphdr.icmp_type) {
    641 	case ICMP_ECHOREPLY:
    642 		(*pr)("Echo Reply)\n");
    643 		break;
    644 	case ICMP_UNREACH:
    645 		(*pr)("Destination Unreachable)\n");
    646 		break;
    647 	case ICMP_SOURCEQUENCH:
    648 		(*pr)("Source Quench)\n");
    649 		break;
    650 	case ICMP_REDIRECT:
    651 		(*pr)("Redirect)\n");
    652 		break;
    653 	case ICMP_TIMXCEED:
    654 		(*pr)("Time Exceeded)\n");
    655 		break;
    656 	default:
    657 		(*pr)("unknown)\n");
    658 		break;
    659 	}
    660 	(*pr)("ICMP: Code = %d\n", icmphdr.icmp_code);
    661 
    662 	return m_examine_hex(m, off, modif, pr);
    663 }
    664 
    665 void
    666 m_examine_ip6(const struct mbuf *m, int off, const char *modif,
    667     void (*pr)(const char *, ...))
    668 {
    669 	unsigned int pktlen;
    670 	struct ip6_hdr ip6;
    671 	struct ip6_hbh hbh;
    672 	int hbhlen;
    673 	uint32_t flow;
    674 	uint8_t vfc;
    675 	uint8_t nxt;
    676 
    677 	pktlen = m_peek_len(m, modif) - off;
    678 	if (pktlen < sizeof(ip6)) {
    679 		(*pr)("%s: too short mbuf chain (%u < %u)\n", __func__,
    680 		    pktlen, sizeof(ip6));
    681 		return m_examine_hex(m, off, modif, pr);
    682 	}
    683 
    684 	if (m_peek_data(m, off, sizeof(ip6), (void *)(&ip6)) < 0) {
    685 		(*pr)("%s: cannot read header\n", __func__);
    686 		return m_examine_hex(m, off, modif, pr);
    687 	}
    688 	off += sizeof(ip6);
    689 
    690 	vfc = ip6.ip6_vfc;
    691 	(*pr)("IPv6: Version = %u\n", (vfc & IPV6_VERSION_MASK) >> 4);
    692 	flow = ntohl(ip6.ip6_flow);
    693 	(*pr)("IPv6: Flow INFO = 0x%07x\n", flow & IPV6_FLOWINFO_MASK);
    694 	(*pr)("IPv6: Payload Length = %u\n", ntohs(ip6.ip6_plen));
    695 	nxt = ip6.ip6_nxt;
    696 	(*pr)("IPv6: Next Header = %u(%s)\n", nxt, str_ipproto(nxt));
    697 	(*pr)("IPv6: Hop Limit = %u\n", ip6.ip6_hlim);
    698 	(*pr)("IPv6: Src = %s\n", str_ip6addr(&ip6.ip6_src));
    699 	(*pr)("IPv6: Dst = %s\n", str_ip6addr(&ip6.ip6_dst));
    700 
    701 	/* Strip Hop-by-Hop options */
    702 	if (nxt == IPPROTO_HOPOPTS) {
    703 		if (m_peek_data(m, off, sizeof(hbh), (void *)(&hbh)) < 0) {
    704 			(*pr)("Cannot read option\n");
    705 			return m_examine_hex(m, off, modif, pr);
    706 		}
    707 		hbhlen = (hbh.ip6h_len + 1) << 3;
    708 		nxt = hbh.ip6h_nxt;
    709 		off += hbhlen;
    710 
    711 		(*pr)("IPv6: Stripped Hop-by-Hop\n");
    712 		(*pr)("IPv6: Next Header = %u(%s)\n", nxt, str_ipproto(nxt));
    713 	}
    714 
    715 	switch (nxt) {
    716 	case IPPROTO_IPV6_ICMP:
    717 		return m_examine_icmp6(m, off, modif, pr);
    718 		break;
    719 	case IPPROTO_TCP:
    720 		return m_examine_tcp(m, off, modif, pr);
    721 		break;
    722 	case IPPROTO_UDP:
    723 		return m_examine_udp(m, off, modif, pr);
    724 		break;
    725 	default:
    726 		break;
    727 	}
    728 
    729 	return m_examine_hex(m, off, modif, pr);
    730 }
    731 
    732 void
    733 m_examine_icmp6(const struct mbuf *m, int off, const char *modif,
    734     void (*pr)(const char *, ...))
    735 {
    736 	unsigned int pktlen;
    737 	struct icmp6_hdr icmp6;
    738 
    739 	pktlen = m_peek_len(m, modif) - off;
    740 	if (pktlen < sizeof(icmp6)) {
    741 		(*pr)("%s: too short mbuf chain (%u < %u)\n", __func__,
    742 		    pktlen, sizeof(icmp6));
    743 		return m_examine_hex(m, off, modif, pr);
    744 	}
    745 
    746 	if (m_peek_data(m, off, sizeof(icmp6), (void *)(&icmp6)) < 0) {
    747 		(*pr)("%s: cannot read header\n", __func__);
    748 		return m_examine_hex(m, off, modif, pr);
    749 	}
    750 	off += sizeof(icmp6);
    751 
    752 	(*pr)("ICMP6: Type = %u(", icmp6.icmp6_type);
    753 	switch (icmp6.icmp6_type) {
    754 	case ICMP6_DST_UNREACH:
    755 		(*pr)("Destination Unreachable)\n");
    756 		break;
    757 	case ICMP6_PACKET_TOO_BIG:
    758 		(*pr)("Packet Too Big)\n");
    759 		break;
    760 	case ICMP6_TIME_EXCEEDED:
    761 		(*pr)("Time Exceeded)\n");
    762 		break;
    763 	case ICMP6_PARAM_PROB:
    764 		(*pr)("Parameter Problem)\n");
    765 		break;
    766 	case ICMP6_ECHO_REQUEST:
    767 		(*pr)("Echo Request)\n");
    768 		break;
    769 	case ICMP6_ECHO_REPLY:
    770 		(*pr)("Echo Reply)\n");
    771 		break;
    772 
    773 	case MLD_LISTENER_QUERY:
    774 		(*pr)("MLD Listener Query)\n");
    775 		break;
    776 	case MLD_LISTENER_REPORT:
    777 		(*pr)("MLD Listener Report)\n");
    778 		break;
    779 	case MLD_LISTENER_DONE:
    780 		(*pr)("MLD Listener Done)\n");
    781 		break;
    782 
    783 	case ND_ROUTER_SOLICIT:
    784 		(*pr)("Router Solicitation)\n");
    785 		break;
    786 	case ND_ROUTER_ADVERT:
    787 		(*pr)("Router Advertizement)\n");
    788 		break;
    789 	case ND_NEIGHBOR_SOLICIT:
    790 		(*pr)("Neighbor Solicitation)\n");
    791 		break;
    792 	case ND_NEIGHBOR_ADVERT:
    793 		(*pr)("Neighbor Advertizement)\n");
    794 		break;
    795 	case ND_REDIRECT:
    796 		(*pr)("Redirect)\n");
    797 		break;
    798 
    799 	default:
    800 		(*pr)("unknown)\n");
    801 		break;
    802 	}
    803 	(*pr)("ICMP6: Code = %u\n", icmp6.icmp6_code);
    804 
    805 	return m_examine_hex(m, off, modif, pr);
    806 }
    807 
    808 void
    809 m_examine_tcp(const struct mbuf *m, int off, const char *modif,
    810     void (*pr)(const char *, ...))
    811 {
    812 	unsigned int pktlen;
    813 	struct tcphdr tcp;
    814 
    815 	pktlen = m_peek_len(m, modif) - off;
    816 	if (pktlen < sizeof(tcp)) {
    817 		(*pr)("%s: too short mbuf chain (%u < %u)\n", __func__,
    818 		    pktlen, sizeof(tcp));
    819 		return m_examine_hex(m, off, modif, pr);
    820 	}
    821 
    822 	if (m_peek_data(m, off, sizeof(tcp), (void *)(&tcp)) < 0) {
    823 		(*pr)("%s: cannot read header\n", __func__);
    824 		return m_examine_hex(m, off, modif, pr);
    825 	}
    826 	off += sizeof(tcp);
    827 
    828 	(*pr)("TCP: Src = %u\n", ntohs(tcp.th_sport));
    829 	(*pr)("TCP: Dst = %u\n", ntohs(tcp.th_dport));
    830 	(*pr)("TCP: Seq. = %u\n", ntohl(tcp.th_seq));
    831 	(*pr)("TCP: Ack. = %u\n", ntohl(tcp.th_ack));
    832 	(*pr)("TCP: Header Length = %u\n", tcp.th_off << 2);
    833 	if (tcp.th_flags) {
    834 		(*pr)("TCP: Flags 0x%02x : ", tcp.th_flags);
    835 		if (tcp.th_flags & TH_FIN)
    836 			(*pr)("FIN ");
    837 		if (tcp.th_flags & TH_SYN)
    838 			(*pr)("SYN ");
    839 		if (tcp.th_flags & TH_RST)
    840 			(*pr)("RST ");
    841 		if (tcp.th_flags & TH_PUSH)
    842 			(*pr)("PUSH ");
    843 		if (tcp.th_flags & TH_URG)
    844 			(*pr)("URG ");
    845 		if (tcp.th_flags & TH_ECE)
    846 			(*pr)("ECE ");
    847 		if (tcp.th_flags & TH_CWR)
    848 			(*pr)("CWR ");
    849 		(*pr)("\n");
    850 	}
    851 	(*pr)("TCP: Windows Size = %u\n", ntohs(tcp.th_win));
    852 	(*pr)("TCP: checksum = 0x%04x\n", ntohs(tcp.th_sum));
    853 	(*pr)("TCP: Urgent Pointer = %u\n", ntohs(tcp.th_urp));
    854 
    855 	int len;
    856 	len = (tcp.th_off << 2) - sizeof(struct tcphdr);
    857 	if (len > 0) {
    858 		uint8_t *bufp, *op, opt, optlen;
    859 
    860 		bufp = malloc(len, M_TEMP, M_DONTWAIT);
    861 		if ((bufp == NULL) || (m_peek_data(m, off, len, bufp) < 0)) {
    862 			(*pr)("%s: cannot read TCP option\n", __func__);
    863 			if (bufp != NULL)
    864 				free(bufp, M_TEMP);
    865 			return m_examine_hex(m, off, modif, pr);
    866 		}
    867 		off += len;
    868 		op = bufp;
    869 
    870 		while (len > 0) {
    871 			opt = op[0];
    872 			if (opt == TCPOPT_EOL)
    873 				break;
    874 			if (opt == TCPOPT_NOP) {
    875 				(*pr)("TCP: OPTION: NOP\n");
    876 				op++;
    877 				len--;
    878 				continue;
    879 			}
    880 			if (opt == TCPOPT_PAD) {
    881 				(*pr)("TCP: OPTION: PAD\n");
    882 				op++;
    883 				len--;
    884 				continue;
    885 			}
    886 			optlen = op[1];
    887 			if (optlen == 0)
    888 				break;
    889 
    890 			if (opt == TCPOPT_MAXSEG && optlen == TCPOLEN_MAXSEG) {
    891 				uint16_t mss;
    892 
    893 				bcopy(op + 2, &mss, sizeof(mss));
    894 				(*pr)("TCP: OPTION: MSS = %d\n",
    895 				    ntohs(mss));
    896 
    897 				op += optlen;
    898 				len -= optlen;
    899 				continue;
    900 			} else if (opt == TCPOPT_WINDOW
    901 			    && optlen == TCPOLEN_WINDOW) {
    902 				(*pr)("TCP: OPTION: wscale = %d\n", op[2]);
    903 				op += optlen;
    904 				len -= optlen;
    905 				continue;
    906 			} else if (opt == TCPOPT_SACK_PERMITTED
    907 			    && optlen == TCPOLEN_SACK_PERMITTED) {
    908 				(*pr)("TCP: OPTION: SACK OK\n");
    909 				op += optlen;
    910 				len -= optlen;
    911 				continue;
    912 			} else if (opt == TCPOPT_TIMESTAMP
    913 			    && optlen == TCPOLEN_TIMESTAMP) {
    914 				uint32_t ts_val, ts_ecr;
    915 
    916 				memcpy(&ts_val, op + 2, sizeof(ts_val));
    917 				memcpy(&ts_ecr, op + 6, sizeof(ts_ecr));
    918 				(*pr)("TCP: OPTION: TIMESTAMP = %u, "
    919 				    "ECR = %u\n",
    920 				    ntohl(ts_val), ntohl(ts_ecr));
    921 				op += optlen;
    922 				len -= optlen;
    923 				continue;
    924 			} else {
    925 				(*pr)("TCP: OPTION: unknown (%d, len = %d)\n",
    926 				    opt, optlen);
    927 				op += optlen;
    928 				len -= optlen;
    929 				continue;
    930 			}
    931 		}
    932 		free(bufp, M_TEMP);
    933 	}
    934 
    935 	if (off < pktlen)
    936 		m_examine_hex(m, off, modif, pr);
    937 
    938 	return;
    939 }
    940 
    941 void
    942 m_examine_udp(const struct mbuf *m, int off, const char *modif,
    943     void (*pr)(const char *, ...))
    944 {
    945 	unsigned int pktlen;
    946 	struct udphdr udp;
    947 
    948 	pktlen = m_peek_len(m, modif) - off;
    949 	if (pktlen < sizeof(udp)) {
    950 		(*pr)("%s: too short mbuf chain (%u < %u)\n", __func__,
    951 		    pktlen, sizeof(udp));
    952 		return m_examine_hex(m, off, modif, pr);
    953 	}
    954 
    955 	if (m_peek_data(m, off, sizeof(udp), (void *)(&udp)) < 0) {
    956 		(*pr)("%s: cannot read header\n", __func__);
    957 		return m_examine_hex(m, off, modif, pr);
    958 	}
    959 	off += sizeof(udp);
    960 
    961 	(*pr)("UDP: Src = %u\n", ntohs(udp.uh_sport));
    962 	(*pr)("UDP: Dst = %u\n", ntohs(udp.uh_dport));
    963 	(*pr)("UDP: Length = %u\n", ntohs(udp.uh_ulen));
    964 
    965 	return m_examine_hex(m, off, modif, pr);
    966 }
    967 
    968 void
    969 m_examine_hex(const struct mbuf *m, int off, const char *modif,
    970     void (*pr)(const char *, ...))
    971 {
    972 	unsigned int pktlen;
    973 	int newline = 0;
    974 	uint8_t v;
    975 
    976 	pktlen = m_peek_len(m, modif) - off;
    977 	if (pktlen > EXAMINE_HEX_LIMIT)
    978 		pktlen = EXAMINE_HEX_LIMIT;
    979 
    980 	if (pktlen == 0)
    981 		return;
    982 
    983 	(*pr)("offset %04d: ", off);
    984 	while (pktlen > 0) {
    985 		if (m_peek_data(m, off, sizeof(v), (void *)(&v)) < 0)
    986 			break;
    987 		pktlen --;
    988 		off++;
    989 		newline++;
    990 
    991 		(*pr)("%02x", v);
    992 		if (pktlen == 0)
    993 			break;
    994 
    995 		if ((newline % EXAMINE_HEX_COL) == 0) {
    996 			(*pr)("\n");
    997 			(*pr)("offset %04d: ", off);
    998 		} else
    999 			(*pr)(" ");
   1000 	}
   1001 	(*pr)("\n");
   1002 }
   1003 
   1004 void
   1005 m_examine(const struct mbuf *m, int af, const char *modif,
   1006     void (*pr)(const char *, ...))
   1007 {
   1008 	if (m == NULL)
   1009 		return;
   1010 
   1011 	if (pr == NULL)
   1012 		return;
   1013 
   1014 	switch (af) {
   1015 	case AF_UNSPEC:
   1016 		return m_examine_hex(m, 0, modif, pr);
   1017 		break;
   1018 	case AF_ETHER:
   1019 		return m_examine_ether(m, 0, modif, pr);
   1020 		break;
   1021 	case AF_ARP:
   1022 		return m_examine_arp(m, 0, modif, pr);
   1023 		break;
   1024 	case AF_INET:
   1025 		return m_examine_ip(m, 0, modif, pr);
   1026 		break;
   1027 	case AF_INET6:
   1028 		return m_examine_ip6(m, 0, modif, pr);
   1029 		break;
   1030 	default:
   1031 		(*pr)("No parser for AF %d\n", af);
   1032 		return m_examine_hex(m, 0, modif, pr);
   1033 		break;
   1034 	}
   1035 
   1036 	/* not reached */
   1037 	return;
   1038 }
   1039