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