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