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