Home | History | Annotate | Line # | Download | only in kern
uipc_mbufdebug.c revision 1.7.4.2
      1 /*	$NetBSD: uipc_mbufdebug.c,v 1.7.4.2 2019/06/10 22:09:04 christos 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.7.4.2 2019/06/10 22:09:04 christos 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 	if ((m->m_flags & M_PKTHDR) != 0)
    151 		return m->m_pkthdr.len;
    152 
    153 	pktlen = 0;
    154 	for (m0 = m; m0 != NULL; m0 = m0->m_next)
    155 		pktlen += m0->m_len;
    156 
    157 	return pktlen;
    158 }
    159 
    160 static char *
    161 str_ethaddr(const uint8_t *ap)
    162 {
    163 	static char buf[3 * ETHER_ADDR_LEN];
    164 
    165 	return ether_snprintf(buf, sizeof(buf), ap);
    166 }
    167 
    168 static char *
    169 str_ipaddr(const struct in_addr *ap)
    170 {
    171 	static char buf[INET_ADDRSTRLEN];
    172 
    173 	return IN_PRINT(buf, ap);
    174 }
    175 
    176 static char *
    177 str_ip6addr(const struct in6_addr *ap)
    178 {
    179 	static char buf[INET6_ADDRSTRLEN];
    180 
    181 	return IN6_PRINT(buf, ap);
    182 }
    183 
    184 static const char *
    185 str_ipproto(const uint8_t proto)
    186 {
    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 		else
    414 			(*pr)("UNICAST)\n");
    415 
    416 		(*pr)("SPPP: Protocol = %d(", protocol);
    417 		switch (protocol) {
    418 		case CISCO_KEEPALIVE:
    419 			(*pr)("Keepalive)\n");
    420 			break;
    421 		case ETHERTYPE_IP:
    422 			(*pr)("IP)\n");
    423 			return m_examine_ip(m, off, modif, pr);
    424 			break;
    425 		case ETHERTYPE_IPV6:
    426 			(*pr)("IPv6)\n");
    427 			return m_examine_ip6(m, off, modif, pr);
    428 			break;
    429 		default:
    430 			(*pr)("unknown)\n");
    431 			break;
    432 		}
    433 		break;
    434 	default:
    435 		(*pr)("unknown)\n", h.address);
    436 		break;
    437 	}
    438 
    439 	(*pr)("No parser for address %d, protocol %d\n", h.address, protocol);
    440 	return m_examine_hex(m, off, modif, pr);
    441 }
    442 
    443 void
    444 m_examine_arp(const struct mbuf *m, int off, const char *modif,
    445     void (*pr)(const char *, ...))
    446 {
    447 	unsigned int pktlen;
    448 	struct arphdr ar;
    449 	uint16_t hrd, op;
    450 	struct in_addr isaddr, itaddr;
    451 	uint8_t esaddr[ETHER_ADDR_LEN], etaddr[ETHER_ADDR_LEN];
    452 
    453 	pktlen = m_peek_len(m, modif) - off;
    454 	if (pktlen < sizeof(ar)) {
    455 		(*pr)("%s: too short mbuf chain (%u < %u)\n", __func__,
    456 		    pktlen, sizeof(ar));
    457 		return m_examine_hex(m, off, modif, pr);
    458 	}
    459 
    460 	if (m_peek_data(m, off, sizeof(ar), (void *)(&ar)) < 0) {
    461 		(*pr)("%s: cannot read header\n", __func__);
    462 		return m_examine_hex(m, off, modif, pr);
    463 	}
    464 	off += sizeof(ar);
    465 
    466 	hrd = ntohs(ar.ar_hrd);
    467 	(*pr)("ARP: AddressType = %u(", hrd);
    468 	switch (hrd) {
    469 	case ARPHRD_ETHER:
    470 		(*pr)("ETHER)\n");
    471 		break;
    472 	case ARPHRD_IEEE802:
    473 		(*pr)("IEEE802)\n");
    474 		break;
    475 	default:
    476 		(*pr)("unknown)\n");
    477 		return m_examine_hex(m, off, modif, pr);
    478 		break;
    479 	}
    480 	(*pr)("ARP: Protocol Address Format = %u\n", ntohs(ar.ar_pro));
    481 	(*pr)("ARP: Protocol Address Length = %u\n", ar.ar_pln);
    482 	(*pr)("ARP: H/W Address Length = %u\n", ar.ar_hln);
    483 	op = ntohs(ar.ar_op);
    484 	(*pr)("ARP: Operation = %u(", op);
    485 	switch (op) {
    486 	case ARPOP_REQUEST:
    487 		(*pr)("REQUEST)\n");
    488 		break;
    489 	case ARPOP_REPLY:
    490 		(*pr)("REPLY)\n");
    491 		break;
    492 	case ARPOP_REVREQUEST:
    493 		(*pr)("REVREQUEST)\n");
    494 		break;
    495 	case ARPOP_REVREPLY:
    496 		(*pr)("REVREPLY)\n");
    497 		break;
    498 	case ARPOP_INVREQUEST:
    499 		(*pr)("INVREQUEST)\n");
    500 		break;
    501 	case ARPOP_INVREPLY:
    502 		(*pr)("INVREPLY)\n");
    503 		break;
    504 	}
    505 
    506 	if (ar.ar_hln == 0 || ar.ar_pln == 0 ||
    507 	    ar.ar_hln != sizeof(esaddr) || ar.ar_pln != sizeof(isaddr)) {
    508 		(*pr)("Cannot parse.\n");
    509 		return m_examine_hex(m, off, modif, pr);
    510 	}
    511 
    512 	if (m_peek_data(m, off, sizeof(esaddr), (void *)(esaddr)) < 0) {
    513 		(*pr)("Cannot read payload\n");
    514 		return m_examine_hex(m, off, modif, pr);
    515 	}
    516 	off += sizeof(esaddr);
    517 	(*pr)("ARP: Ether Src = %s\n", str_ethaddr(esaddr));
    518 
    519 	if (m_peek_data(m, off, sizeof(isaddr), (void *)(&isaddr)) < 0) {
    520 		(*pr)("Cannot read payload\n");
    521 		return m_examine_hex(m, off, modif, pr);
    522 	}
    523 	off += sizeof(isaddr);
    524 	(*pr)("ARP: IP Src = %s\n", str_ipaddr(&isaddr));
    525 
    526 	if (m_peek_data(m, off, sizeof(etaddr), (void *)(etaddr)) < 0) {
    527 		(*pr)("Cannot read payload\n");
    528 		return m_examine_hex(m, off, modif, pr);
    529 	}
    530 	off += sizeof(etaddr);
    531 	(*pr)("ARP: Ether Tgt = %s\n", str_ethaddr(etaddr));
    532 
    533 	if (m_peek_data(m, off, sizeof(itaddr), (void *)(&itaddr)) < 0) {
    534 		(*pr)("Cannot read payload\n");
    535 		return m_examine_hex(m, off, modif, pr);
    536 	}
    537 	off += sizeof(itaddr);
    538 	(*pr)("ARP: IP Tgt = %s\n", str_ipaddr(&itaddr));
    539 
    540 	return m_examine_hex(m, off, modif, pr);
    541 }
    542 
    543 void
    544 m_examine_ip(const struct mbuf *m, int off, const char *modif,
    545     void (*pr)(const char *, ...))
    546 {
    547 	unsigned int pktlen;
    548 	struct ip ip;
    549 	uint16_t offset;
    550 
    551 	pktlen = m_peek_len(m, modif) - off;
    552 	if (pktlen < sizeof(ip)) {
    553 		(*pr)("%s: too short mbuf chain (%u < %u)\n", __func__,
    554 		    pktlen, sizeof(ip));
    555 		return m_examine_hex(m, off, modif, pr);
    556 	}
    557 
    558 	if (m_peek_data(m, off, sizeof(ip), (void *)(&ip)) < 0) {
    559 		(*pr)("%s: cannot read header\n", __func__);
    560 		return m_examine_hex(m, off, modif, pr);
    561 	}
    562 	off += sizeof(ip);
    563 
    564 	(*pr)("IP: Version = %u\n", ip.ip_v);
    565 	(*pr)("IP: Header Length = %u\n", (ip.ip_hl << 2));
    566 	(*pr)("IP: ToS = 0x%02x\n", ip.ip_tos);
    567 	(*pr)("IP: Packet Length = %u\n", ntohs(ip.ip_len));
    568 	(*pr)("IP: ID = %u\n", ntohs(ip.ip_id));
    569 	offset = ntohs(ip.ip_off);
    570 	(*pr)("IP: Offset = %u\n", (offset & IP_OFFMASK));
    571 	if (offset & IP_RF)
    572 		(*pr)("IP: Flag 0x%04x (reserved)\n", IP_RF);
    573 	if (offset & IP_EF)
    574 		(*pr)("IP: Flag 0x%04x (evil flag)\n", IP_EF);
    575 	if (offset & IP_DF)
    576 		(*pr)("IP: Flag 0x%04x (don't fragment)\n", IP_DF);
    577 	if (offset & IP_MF)
    578 		(*pr)("IP: Flag 0x%04x (more fragment)\n", IP_MF);
    579 	(*pr)("IP: TTL = %u\n", ip.ip_ttl);
    580 	(*pr)("IP: protocol = %u(%s)\n", ip.ip_p, str_ipproto(ip.ip_p));
    581 	(*pr)("IP: checksum = 0x%04x\n", ntohs(ip.ip_sum));
    582 	(*pr)("IP: Src = %s\n", str_ipaddr(&ip.ip_src));
    583 	(*pr)("IP: Dst = %s\n", str_ipaddr(&ip.ip_dst));
    584 
    585 	switch (ip.ip_p) {
    586 	case IPPROTO_ICMP:
    587 		return m_examine_icmp(m, off, modif, pr);
    588 		break;
    589 	case IPPROTO_TCP:
    590 		return m_examine_tcp(m, off, modif, pr);
    591 		break;
    592 	case IPPROTO_UDP:
    593 		return m_examine_udp(m, off, modif, pr);
    594 		break;
    595 	default:
    596 		break;
    597 	}
    598 
    599 	return m_examine_hex(m, off, modif, pr);
    600 }
    601 
    602 void
    603 m_examine_icmp(const struct mbuf *m, int off, const char *modif,
    604     void (*pr)(const char *, ...))
    605 {
    606 	unsigned int pktlen;
    607 	struct icmp icmphdr;
    608 
    609 	pktlen = m_peek_len(m, modif) - off;
    610 	if (pktlen < sizeof(icmphdr)) {
    611 		(*pr)("%s: too short mbuf chain (%u < %u)\n", __func__,
    612 		    pktlen, sizeof(icmphdr));
    613 		return m_examine_hex(m, off, modif, pr);
    614 	}
    615 
    616 	if (m_peek_data(m, off, sizeof(icmphdr), (void *)(&icmphdr)) < 0) {
    617 		(*pr)("%s: cannot read header\n", __func__);
    618 		return m_examine_hex(m, off, modif, pr);
    619 	}
    620 	off += sizeof(icmphdr);
    621 
    622 	(*pr)("ICMP: Type = %u(", icmphdr.icmp_type);
    623 	switch (icmphdr.icmp_type) {
    624 	case ICMP_ECHOREPLY:
    625 		(*pr)("Echo Reply)\n");
    626 		break;
    627 	case ICMP_UNREACH:
    628 		(*pr)("Destination Unreachable)\n");
    629 		break;
    630 	case ICMP_SOURCEQUENCH:
    631 		(*pr)("Source Quench)\n");
    632 		break;
    633 	case ICMP_REDIRECT:
    634 		(*pr)("Redirect)\n");
    635 		break;
    636 	case ICMP_TIMXCEED:
    637 		(*pr)("Time Exceeded)\n");
    638 		break;
    639 	default:
    640 		(*pr)("unknown)\n");
    641 		break;
    642 	}
    643 	(*pr)("ICMP: Code = %d\n", icmphdr.icmp_code);
    644 
    645 	return m_examine_hex(m, off, modif, pr);
    646 }
    647 
    648 void
    649 m_examine_ip6(const struct mbuf *m, int off, const char *modif,
    650     void (*pr)(const char *, ...))
    651 {
    652 	unsigned int pktlen;
    653 	struct ip6_hdr ip6;
    654 	struct ip6_hbh hbh;
    655 	int hbhlen;
    656 	uint32_t flow;
    657 	uint8_t vfc;
    658 	uint8_t nxt;
    659 
    660 	pktlen = m_peek_len(m, modif) - off;
    661 	if (pktlen < sizeof(ip6)) {
    662 		(*pr)("%s: too short mbuf chain (%u < %u)\n", __func__,
    663 		    pktlen, sizeof(ip6));
    664 		return m_examine_hex(m, off, modif, pr);
    665 	}
    666 
    667 	if (m_peek_data(m, off, sizeof(ip6), (void *)(&ip6)) < 0) {
    668 		(*pr)("%s: cannot read header\n", __func__);
    669 		return m_examine_hex(m, off, modif, pr);
    670 	}
    671 	off += sizeof(ip6);
    672 
    673 	vfc = ip6.ip6_vfc;
    674 	(*pr)("IPv6: Version = %u\n", (vfc & IPV6_VERSION_MASK) >> 4);
    675 	flow = ntohl(ip6.ip6_flow);
    676 	(*pr)("IPv6: Flow INFO = 0x%07x\n", flow & IPV6_FLOWINFO_MASK);
    677 	(*pr)("IPv6: Payload Length = %u\n", ntohs(ip6.ip6_plen));
    678 	nxt = ip6.ip6_nxt;
    679 	(*pr)("IPv6: Next Header = %u(%s)\n", nxt, str_ipproto(nxt));
    680 	(*pr)("IPv6: Hop Limit = %u\n", ip6.ip6_hlim);
    681 	(*pr)("IPv6: Src = %s\n", str_ip6addr(&ip6.ip6_src));
    682 	(*pr)("IPv6: Dst = %s\n", str_ip6addr(&ip6.ip6_dst));
    683 
    684 	/* Strip Hop-by-Hop options */
    685 	if (nxt == IPPROTO_HOPOPTS) {
    686 		if (m_peek_data(m, off, sizeof(hbh), (void *)(&hbh)) < 0) {
    687 			(*pr)("Cannot read option\n");
    688 			return m_examine_hex(m, off, modif, pr);
    689 		}
    690 		hbhlen = (hbh.ip6h_len + 1) << 3;
    691 		nxt = hbh.ip6h_nxt;
    692 		off += hbhlen;
    693 
    694 		(*pr)("IPv6: Stripped Hop-by-Hop\n");
    695 		(*pr)("IPv6: Next Header = %u(%s)\n", nxt, str_ipproto(nxt));
    696 	}
    697 
    698 	switch (nxt) {
    699 	case IPPROTO_IPV6_ICMP:
    700 		return m_examine_icmp6(m, off, modif, pr);
    701 		break;
    702 	case IPPROTO_TCP:
    703 		return m_examine_tcp(m, off, modif, pr);
    704 		break;
    705 	case IPPROTO_UDP:
    706 		return m_examine_udp(m, off, modif, pr);
    707 		break;
    708 	default:
    709 		break;
    710 	}
    711 
    712 	return m_examine_hex(m, off, modif, pr);
    713 }
    714 
    715 void
    716 m_examine_icmp6(const struct mbuf *m, int off, const char *modif,
    717     void (*pr)(const char *, ...))
    718 {
    719 	unsigned int pktlen;
    720 	struct icmp6_hdr icmp6;
    721 
    722 	pktlen = m_peek_len(m, modif) - off;
    723 	if (pktlen < sizeof(icmp6)) {
    724 		(*pr)("%s: too short mbuf chain (%u < %u)\n", __func__,
    725 		    pktlen, sizeof(icmp6));
    726 		return m_examine_hex(m, off, modif, pr);
    727 	}
    728 
    729 	if (m_peek_data(m, off, sizeof(icmp6), (void *)(&icmp6)) < 0) {
    730 		(*pr)("%s: cannot read header\n", __func__);
    731 		return m_examine_hex(m, off, modif, pr);
    732 	}
    733 	off += sizeof(icmp6);
    734 
    735 	(*pr)("ICMP6: Type = %u(", icmp6.icmp6_type);
    736 	switch (icmp6.icmp6_type) {
    737 	case ICMP6_DST_UNREACH:
    738 		(*pr)("Destination Unreachable)\n");
    739 		break;
    740 	case ICMP6_PACKET_TOO_BIG:
    741 		(*pr)("Packet Too Big)\n");
    742 		break;
    743 	case ICMP6_TIME_EXCEEDED:
    744 		(*pr)("Time Exceeded)\n");
    745 		break;
    746 	case ICMP6_PARAM_PROB:
    747 		(*pr)("Parameter Problem)\n");
    748 		break;
    749 	case ICMP6_ECHO_REQUEST:
    750 		(*pr)("Echo Request)\n");
    751 		break;
    752 	case ICMP6_ECHO_REPLY:
    753 		(*pr)("Echo Reply)\n");
    754 		break;
    755 
    756 	case MLD_LISTENER_QUERY:
    757 		(*pr)("MLD Listener Query)\n");
    758 		break;
    759 	case MLD_LISTENER_REPORT:
    760 		(*pr)("MLD Listener Report)\n");
    761 		break;
    762 	case MLD_LISTENER_DONE:
    763 		(*pr)("MLD Listener Done)\n");
    764 		break;
    765 
    766 	case ND_ROUTER_SOLICIT:
    767 		(*pr)("Router Solicitation)\n");
    768 		break;
    769 	case ND_ROUTER_ADVERT:
    770 		(*pr)("Router Advertizement)\n");
    771 		break;
    772 	case ND_NEIGHBOR_SOLICIT:
    773 		(*pr)("Neighbor Solicitation)\n");
    774 		break;
    775 	case ND_NEIGHBOR_ADVERT:
    776 		(*pr)("Neighbor Advertizement)\n");
    777 		break;
    778 	case ND_REDIRECT:
    779 		(*pr)("Redirect)\n");
    780 		break;
    781 
    782 	default:
    783 		(*pr)("unknown)\n");
    784 		break;
    785 	}
    786 	(*pr)("ICMP6: Code = %u\n", icmp6.icmp6_code);
    787 
    788 	return m_examine_hex(m, off, modif, pr);
    789 }
    790 
    791 void
    792 m_examine_tcp(const struct mbuf *m, int off, const char *modif,
    793     void (*pr)(const char *, ...))
    794 {
    795 	unsigned int pktlen;
    796 	struct tcphdr tcp;
    797 
    798 	pktlen = m_peek_len(m, modif) - off;
    799 	if (pktlen < sizeof(tcp)) {
    800 		(*pr)("%s: too short mbuf chain (%u < %u)\n", __func__,
    801 		    pktlen, sizeof(tcp));
    802 		return m_examine_hex(m, off, modif, pr);
    803 	}
    804 
    805 	if (m_peek_data(m, off, sizeof(tcp), (void *)(&tcp)) < 0) {
    806 		(*pr)("%s: cannot read header\n", __func__);
    807 		return m_examine_hex(m, off, modif, pr);
    808 	}
    809 	off += sizeof(tcp);
    810 
    811 	(*pr)("TCP: Src = %u\n", ntohs(tcp.th_sport));
    812 	(*pr)("TCP: Dst = %u\n", ntohs(tcp.th_dport));
    813 	(*pr)("TCP: Seq. = %u\n", ntohl(tcp.th_seq));
    814 	(*pr)("TCP: Ack. = %u\n", ntohl(tcp.th_ack));
    815 	(*pr)("TCP: Header Length = %u\n", tcp.th_off << 2);
    816 	if (tcp.th_flags) {
    817 		(*pr)("TCP: Flags 0x%02x : ", tcp.th_flags);
    818 		if (tcp.th_flags & TH_FIN)
    819 			(*pr)("FIN ");
    820 		if (tcp.th_flags & TH_SYN)
    821 			(*pr)("SYN ");
    822 		if (tcp.th_flags & TH_RST)
    823 			(*pr)("RST ");
    824 		if (tcp.th_flags & TH_PUSH)
    825 			(*pr)("PUSH ");
    826 		if (tcp.th_flags & TH_URG)
    827 			(*pr)("URG ");
    828 		if (tcp.th_flags & TH_ECE)
    829 			(*pr)("ECE ");
    830 		if (tcp.th_flags & TH_CWR)
    831 			(*pr)("CWR ");
    832 		(*pr)("\n");
    833 	}
    834 	(*pr)("TCP: Windows Size = %u\n", ntohs(tcp.th_win));
    835 	(*pr)("TCP: checksum = 0x%04x\n", ntohs(tcp.th_sum));
    836 	(*pr)("TCP: Urgent Pointer = %u\n", ntohs(tcp.th_urp));
    837 
    838 	int len;
    839 	len = (tcp.th_off << 2) - sizeof(struct tcphdr);
    840 	if (len > 0) {
    841 		uint8_t *bufp, *op, opt, optlen;
    842 
    843 		bufp = malloc(len, M_TEMP, M_DONTWAIT);
    844 		if ((bufp == NULL) || (m_peek_data(m, off, len, bufp) < 0)) {
    845 			(*pr)("%s: cannot read TCP option\n", __func__);
    846 			if (bufp != NULL)
    847 				free(bufp, M_TEMP);
    848 			return m_examine_hex(m, off, modif, pr);
    849 		}
    850 		off += len;
    851 		op = bufp;
    852 
    853 		while (len > 0) {
    854 			opt = op[0];
    855 			if (opt == TCPOPT_EOL)
    856 				break;
    857 			if (opt == TCPOPT_NOP) {
    858 				(*pr)("TCP: OPTION: NOP\n");
    859 				op++;
    860 				len--;
    861 				continue;
    862 			}
    863 			if (opt == TCPOPT_PAD) {
    864 				(*pr)("TCP: OPTION: PAD\n");
    865 				op++;
    866 				len--;
    867 				continue;
    868 			}
    869 			optlen = op[1];
    870 			if (optlen == 0)
    871 				break;
    872 
    873 			if (opt == TCPOPT_MAXSEG && optlen == TCPOLEN_MAXSEG) {
    874 				uint16_t mss;
    875 
    876 				bcopy(op + 2, &mss, sizeof(mss));
    877 				(*pr)("TCP: OPTION: MSS = %d\n",
    878 				    ntohs(mss));
    879 
    880 				op += optlen;
    881 				len -= optlen;
    882 				continue;
    883 			} else if (opt == TCPOPT_WINDOW
    884 			    && optlen == TCPOLEN_WINDOW) {
    885 				(*pr)("TCP: OPTION: wscale = %d\n", op[2]);
    886 				op += optlen;
    887 				len -= optlen;
    888 				continue;
    889 			} else if (opt == TCPOPT_SACK_PERMITTED
    890 			    && optlen == TCPOLEN_SACK_PERMITTED) {
    891 				(*pr)("TCP: OPTION: SACK OK\n");
    892 				op += optlen;
    893 				len -= optlen;
    894 				continue;
    895 			} else if (opt == TCPOPT_TIMESTAMP
    896 			    && optlen == TCPOLEN_TIMESTAMP) {
    897 				uint32_t ts_val, ts_ecr;
    898 
    899 				memcpy(&ts_val, op + 2, sizeof(ts_val));
    900 				memcpy(&ts_ecr, op + 6, sizeof(ts_ecr));
    901 				(*pr)("TCP: OPTION: TIMESTAMP = %u, "
    902 				    "ECR = %u\n",
    903 				    ntohl(ts_val), ntohl(ts_ecr));
    904 				op += optlen;
    905 				len -= optlen;
    906 				continue;
    907 			} else {
    908 				(*pr)("TCP: OPTION: unknown (%d, len = %d)\n",
    909 				    opt, optlen);
    910 				op += optlen;
    911 				len -= optlen;
    912 				continue;
    913 			}
    914 		}
    915 		free(bufp, M_TEMP);
    916 	}
    917 
    918 	if (off < pktlen)
    919 		m_examine_hex(m, off, modif, pr);
    920 
    921 	return;
    922 }
    923 
    924 void
    925 m_examine_udp(const struct mbuf *m, int off, const char *modif,
    926     void (*pr)(const char *, ...))
    927 {
    928 	unsigned int pktlen;
    929 	struct udphdr udp;
    930 
    931 	pktlen = m_peek_len(m, modif) - off;
    932 	if (pktlen < sizeof(udp)) {
    933 		(*pr)("%s: too short mbuf chain (%u < %u)\n", __func__,
    934 		    pktlen, sizeof(udp));
    935 		return m_examine_hex(m, off, modif, pr);
    936 	}
    937 
    938 	if (m_peek_data(m, off, sizeof(udp), (void *)(&udp)) < 0) {
    939 		(*pr)("%s: cannot read header\n", __func__);
    940 		return m_examine_hex(m, off, modif, pr);
    941 	}
    942 	off += sizeof(udp);
    943 
    944 	(*pr)("UDP: Src = %u\n", ntohs(udp.uh_sport));
    945 	(*pr)("UDP: Dst = %u\n", ntohs(udp.uh_dport));
    946 	(*pr)("UDP: Length = %u\n", ntohs(udp.uh_ulen));
    947 
    948 	return m_examine_hex(m, off, modif, pr);
    949 }
    950 
    951 void
    952 m_examine_hex(const struct mbuf *m, int off, const char *modif,
    953     void (*pr)(const char *, ...))
    954 {
    955 	unsigned int pktlen;
    956 	int newline = 0;
    957 	uint8_t v;
    958 
    959 	pktlen = m_peek_len(m, modif) - off;
    960 	if (pktlen > EXAMINE_HEX_LIMIT)
    961 		pktlen = EXAMINE_HEX_LIMIT;
    962 
    963 	if (pktlen == 0)
    964 		return;
    965 
    966 	(*pr)("offset %04d: ", off);
    967 	while (pktlen > 0) {
    968 		if (m_peek_data(m, off, sizeof(v), (void *)(&v)) < 0)
    969 			break;
    970 		pktlen --;
    971 		off++;
    972 		newline++;
    973 
    974 		(*pr)("%02x", v);
    975 		if (pktlen == 0)
    976 			break;
    977 
    978 		if ((newline % EXAMINE_HEX_COL) == 0) {
    979 			(*pr)("\n");
    980 			(*pr)("offset %04d: ", off);
    981 		} else
    982 			(*pr)(" ");
    983 	}
    984 	(*pr)("\n");
    985 }
    986 
    987 void
    988 m_examine(const struct mbuf *m, int af, const char *modif,
    989     void (*pr)(const char *, ...))
    990 {
    991 	if (m == NULL)
    992 		return;
    993 
    994 	if (pr == NULL)
    995 		return;
    996 
    997 	switch (af) {
    998 	case AF_UNSPEC:
    999 		return m_examine_hex(m, 0, modif, pr);
   1000 		break;
   1001 	case AF_ETHER:
   1002 		return m_examine_ether(m, 0, modif, pr);
   1003 		break;
   1004 	case AF_ARP:
   1005 		return m_examine_arp(m, 0, modif, pr);
   1006 		break;
   1007 	case AF_INET:
   1008 		return m_examine_ip(m, 0, modif, pr);
   1009 		break;
   1010 	case AF_INET6:
   1011 		return m_examine_ip6(m, 0, modif, pr);
   1012 		break;
   1013 	default:
   1014 		(*pr)("No parser for AF %d\n", af);
   1015 		return m_examine_hex(m, 0, modif, pr);
   1016 		break;
   1017 	}
   1018 
   1019 	/* not reached */
   1020 	return;
   1021 }
   1022