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