void medsa_print(netdissect_options *ndo, const u_char *bp, u_int length, u_int caplen) { register const struct ether_header *ep; const struct medsa_pkthdr *medsa; u_short ether_type; medsa = (const struct medsa_pkthdr *)bp; ep = (const struct ether_header *)(bp - sizeof(*ep)); ND_TCHECK(*medsa); if (!ndo->ndo_eflag) ND_PRINT((ndo, "MEDSA %d.%d:%d: ", SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa))); else medsa_print_full(ndo, medsa, caplen); bp += 8; length -= 8; caplen -= 8; ether_type = EXTRACT_16BITS(&medsa->ether_type); if (ether_type <= ETHERMTU) { /* Try to print the LLC-layer header & higher layers */ if (llc_print(ndo, bp, length, caplen, ESRC(ep), EDST(ep)) < 0) { /* packet type not known, print raw packet */ if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(bp, caplen); } } else { if (ndo->ndo_eflag) ND_PRINT((ndo, "ethertype %s (0x%04x) ", tok2str(ethertype_values, "Unknown", ether_type), ether_type)); if (ethertype_print(ndo, ether_type, bp, length, caplen) == 0) { /* ether_type not known, print raw packet */ if (!ndo->ndo_eflag) ND_PRINT((ndo, "ethertype %s (0x%04x) ", tok2str(ethertype_values, "Unknown", ether_type), ether_type)); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(bp, caplen); } } return; trunc: ND_PRINT((ndo, "%s", tstr)); }
/* * This is the top level routine of the printer. 'p' points * to the ether header of the packet, 'h->ts' is the timestamp, * 'h->len' is the length of the packet off the wire, and 'h->caplen' * is the number of bytes actually captured. */ u_int ap1394_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { u_int length = h->len; u_int caplen = h->caplen; struct firewire_header *fp; u_short ether_type; if (caplen < FIREWIRE_HDRLEN) { ND_PRINT((ndo, "[|ap1394]")); return FIREWIRE_HDRLEN; } if (ndo->ndo_eflag) ap1394_hdr_print(ndo, p, length); length -= FIREWIRE_HDRLEN; caplen -= FIREWIRE_HDRLEN; fp = (struct firewire_header *)p; p += FIREWIRE_HDRLEN; ether_type = EXTRACT_16BITS(&fp->firewire_type); if (ethertype_print(ndo, ether_type, p, length, caplen) == 0) { /* ether_type not known, print raw packet */ if (!ndo->ndo_eflag) ap1394_hdr_print(ndo, (u_char *)fp, length + FIREWIRE_HDRLEN); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } return FIREWIRE_HDRLEN; }
/* * This is the top level routine of the printer. 'p' points * to the bluetooth header of the packet, 'h->ts' is the timestamp, * 'h->len' is the length of the packet off the wire, and 'h->caplen' * is the number of bytes actually captured. */ u_int bt_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { u_int length = h->len; u_int caplen = h->caplen; const pcap_bluetooth_h4_header* hdr = (const pcap_bluetooth_h4_header*)p; ndo->ndo_protocol = "bt_if"; if (caplen < BT_HDRLEN || length < BT_HDRLEN) goto trunc; caplen -= BT_HDRLEN; length -= BT_HDRLEN; p += BT_HDRLEN; ND_TCHECK_4(&hdr->direction); if (ndo->ndo_eflag) ND_PRINT("hci length %u, direction %s, ", length, (EXTRACT_BE_U_4(&hdr->direction)&0x1) ? "in" : "out"); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); trunc: ND_PRINT("%s", tstr); return (BT_HDRLEN); }
static u_int ppi_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { if_printer printer; const ppi_header_t *hdr; u_int caplen = h->caplen; u_int length = h->len; uint16_t len; uint32_t dlt; uint32_t hdrlen; struct pcap_pkthdr nhdr; if (caplen < sizeof(ppi_header_t)) { ND_PRINT((ndo, "[|ppi]")); return (caplen); } hdr = (const ppi_header_t *)p; len = EXTRACT_LE_16BITS(&hdr->ppi_len); if (caplen < len) { /* * If we don't have the entire PPI header, don't * bother. */ ND_PRINT((ndo, "[|ppi]")); return (caplen); } if (len < sizeof(ppi_header_t)) { ND_PRINT((ndo, "[|ppi]")); return (len); } dlt = EXTRACT_LE_32BITS(&hdr->ppi_dlt); if (ndo->ndo_eflag) ppi_header_print(ndo, p, length); length -= len; caplen -= len; p += len; if ((printer = lookup_printer(dlt)) != NULL) { nhdr = *h; nhdr.caplen = caplen; nhdr.len = length; hdrlen = printer(ndo, &nhdr, p); } else { if (!ndo->ndo_eflag) ppi_header_print(ndo, (const u_char *)hdr, length + len); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); hdrlen = 0; } return (len + hdrlen); }
/* * This is the top level routine of the printer. 'p' points * to the ether header of the packet, 'h->ts' is the timestamp, * 'h->len' is the length of the packet off the wire, and 'h->caplen' * is the number of bytes actually captured. */ u_int symantec_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { u_int length = h->len; u_int caplen = h->caplen; struct symantec_header *sp; u_short ether_type; if (caplen < sizeof (struct symantec_header)) { ND_PRINT((ndo, "[|symantec]")); return caplen; } if (ndo->ndo_eflag) symantec_hdr_print(ndo, p, length); length -= sizeof (struct symantec_header); caplen -= sizeof (struct symantec_header); sp = (struct symantec_header *)p; p += sizeof (struct symantec_header); ether_type = EXTRACT_16BITS(&sp->ether_type); if (ether_type <= ETHERMTU) { /* ether_type not known, print raw packet */ if (!ndo->ndo_eflag) symantec_hdr_print(ndo, (u_char *)sp, length + sizeof (struct symantec_header)); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } else if (ethertype_print(ndo, ether_type, p, length, caplen) == 0) { /* ether_type not known, print raw packet */ if (!ndo->ndo_eflag) symantec_hdr_print(ndo, (u_char *)sp, length + sizeof (struct symantec_header)); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } return (sizeof (struct symantec_header)); }
static void medsa_print_full(netdissect_options *ndo, const struct medsa_pkthdr *medsa, u_int caplen) { u_char tag = TAG(medsa); ND_PRINT((ndo, "%s", tok2str(tag_values, "Unknown (%u)", tag))); switch (tag) { case TAG_TO_CPU: ND_PRINT((ndo, ", %stagged", SRC_TAG(medsa) ? "" : "un")); ND_PRINT((ndo, ", dev.port:vlan %d.%d:%d", SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa))); ND_PRINT((ndo, ", %s", tok2str(code_values, "Unknown (%u)", CODE(medsa)))); if (CFI(medsa)) ND_PRINT((ndo, ", CFI")); ND_PRINT((ndo, ", pri %d: ", PRI(medsa))); break; case TAG_FROM_CPU: ND_PRINT((ndo, ", %stagged", SRC_TAG(medsa) ? "" : "un")); ND_PRINT((ndo, ", dev.port:vlan %d.%d:%d", SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa))); if (CFI(medsa)) ND_PRINT((ndo, ", CFI")); ND_PRINT((ndo, ", pri %d: ", PRI(medsa))); break; case TAG_FORWARD: ND_PRINT((ndo, ", %stagged", SRC_TAG(medsa) ? "" : "un")); if (TRUNK(medsa)) ND_PRINT((ndo, ", dev.trunk:vlan %d.%d:%d", SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa))); else ND_PRINT((ndo, ", dev.port:vlan %d.%d:%d", SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa))); if (CFI(medsa)) ND_PRINT((ndo, ", CFI")); ND_PRINT((ndo, ", pri %d: ", PRI(medsa))); break; default: ND_DEFAULTPRINT((const u_char *)medsa, caplen); return; } }
/* * Print an RFC 1483 LLC-encapsulated ATM frame. */ static u_int atm_llc_print(netdissect_options *ndo, const u_char *p, int length, int caplen) { int llc_hdrlen; llc_hdrlen = llc_print(ndo, p, length, caplen, NULL, NULL); if (llc_hdrlen < 0) { /* packet not known, print raw packet */ if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); llc_hdrlen = -llc_hdrlen; } return (llc_hdrlen); }
/* * This is the top level routine of the printer. 'bp' points * to the calm header of the packet. */ void calm_fast_print(netdissect_options *ndo, const u_char *eth, const u_char *bp, u_int length) { int srcNwref = bp[0]; int dstNwref = bp[1]; length -= 2; bp += 2; ND_PRINT((ndo, "CALM FAST src:%s; ", etheraddr_string(eth+6))); ND_PRINT((ndo, "SrcNwref:%d; ", srcNwref)); ND_PRINT((ndo, "DstNwref:%d; ", dstNwref)); if (ndo->ndo_vflag) ND_DEFAULTPRINT(bp, length); }
/* * This is the top level routine of the printer. 'p' points * to the ARCNET header of the packet, 'h->ts' is the timestamp, * 'h->len' is the length of the packet off the wire, and 'h->caplen' * is the number of bytes actually captured. It is quite similar * to the non-Linux style printer except that Linux doesn't ever * supply packets that look like exception frames, it always supplies * reassembled packets rather than raw frames, and headers have an * extra "offset" field between the src/dest and packet type. */ u_int arcnet_linux_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { u_int caplen = h->caplen; u_int length = h->len; const struct arc_linux_header *ap; int archdrlen = 0; u_char arc_type; if (caplen < ARC_LINUX_HDRLEN || length < ARC_LINUX_HDRLEN) { ND_PRINT("[|arcnet]"); return (caplen); } ap = (const struct arc_linux_header *)p; arc_type = EXTRACT_U_1(ap->arc_type); switch (arc_type) { default: archdrlen = ARC_LINUX_HDRNEWLEN; if (caplen < ARC_LINUX_HDRNEWLEN || length < ARC_LINUX_HDRNEWLEN) { ND_PRINT("[|arcnet]"); return (caplen); } break; case ARCTYPE_IP_OLD: case ARCTYPE_ARP_OLD: case ARCTYPE_DIAGNOSE: archdrlen = ARC_LINUX_HDRLEN; break; } if (ndo->ndo_eflag) arcnet_print(ndo, p, length, 0, 0, 0); /* * Go past the ARCNET header. */ length -= archdrlen; caplen -= archdrlen; p += archdrlen; if (!arcnet_encap_print(ndo, arc_type, p, length, caplen)) ND_DEFAULTPRINT(p, caplen); return (archdrlen); }
/* * This is the top level routine of the printer. 'p' points * to the LLC/SNAP or raw header of the packet, 'h->ts' is the timestamp, * 'h->len' is the length of the packet off the wire, and 'h->caplen' * is the number of bytes actually captured. */ u_int cip_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { u_int caplen = h->caplen; u_int length = h->len; size_t cmplen; int llc_hdrlen; ndo->ndo_protocol = "cip_if"; cmplen = sizeof(rfcllc); if (cmplen > caplen) cmplen = caplen; if (cmplen > length) cmplen = length; if (ndo->ndo_eflag) cip_print(ndo, length); if (cmplen == 0) { ND_PRINT("[|cip]"); return 0; } if (memcmp(rfcllc, p, cmplen) == 0) { /* * LLC header is present. Try to print it & higher layers. */ llc_hdrlen = llc_print(ndo, p, length, caplen, NULL, NULL); if (llc_hdrlen < 0) { /* packet type not known, print raw packet */ if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); llc_hdrlen = -llc_hdrlen; } } else { /* * LLC header is absent; treat it as just IP. */ llc_hdrlen = 0; ip_print(ndo, p, length); } return (llc_hdrlen); }
static void ipnet_print(netdissect_options *ndo, const u_char *p, u_int length, u_int caplen) { const ipnet_hdr_t *hdr; if (caplen < sizeof(ipnet_hdr_t)) goto trunc; if (ndo->ndo_eflag) ipnet_hdr_print(ndo, p, length); length -= sizeof(ipnet_hdr_t); caplen -= sizeof(ipnet_hdr_t); hdr = (const ipnet_hdr_t *)p; p += sizeof(ipnet_hdr_t); ND_TCHECK_1(hdr->iph_family); switch (EXTRACT_U_1(hdr->iph_family)) { case IPH_AF_INET: ip_print(ndo, p, length); break; case IPH_AF_INET6: ip6_print(ndo, p, length); break; default: if (!ndo->ndo_eflag) ipnet_hdr_print(ndo, (const u_char *)hdr, length + sizeof(ipnet_hdr_t)); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); break; } return; trunc: ND_PRINT(" %s", tstr); }
/* * This is the top level routine of the printer. 'p' points * to the LLC/SNAP or raw header of the packet, 'h->ts' is the timestamp, * 'h->len' is the length of the packet off the wire, and 'h->caplen' * is the number of bytes actually captured. */ u_int cip_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { u_int caplen = h->caplen; u_int length = h->len; u_short extracted_ethertype; if (memcmp(rfcllc, p, sizeof(rfcllc))==0 && caplen < RFC1483LLC_LEN) { ND_PRINT((ndo, "[|cip]")); return (0); } if (ndo->ndo_eflag) cip_print(ndo, length); if (memcmp(rfcllc, p, sizeof(rfcllc)) == 0) { /* * LLC header is present. Try to print it & higher layers. */ if (llc_print(ndo, p, length, caplen, NULL, NULL, &extracted_ethertype) == 0) { /* ether_type not known, print raw packet */ if (!ndo->ndo_eflag) cip_print(ndo, length); if (extracted_ethertype) { ND_PRINT((ndo, "(LLC %s) ", etherproto_string(htons(extracted_ethertype)))); } if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } } else { /* * LLC header is absent; treat it as just IP. */ ip_print(ndo, p, length); } return (0); }
/* * This is the top level routine of the printer. 'p' points * to the ether header of the packet, 'h->ts' is the timestamp, * 'h->len' is the length of the packet off the wire, and 'h->caplen' * is the number of bytes actually captured. */ u_int ap1394_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { u_int length = h->len; u_int caplen = h->caplen; const struct firewire_header *fp; u_short ether_type; struct lladdr_info src, dst; ndo->ndo_protocol = "ap1394_if"; if (caplen < FIREWIRE_HDRLEN) { nd_print_trunc(ndo); return FIREWIRE_HDRLEN; } if (ndo->ndo_eflag) ap1394_hdr_print(ndo, p, length); length -= FIREWIRE_HDRLEN; caplen -= FIREWIRE_HDRLEN; fp = (const struct firewire_header *)p; p += FIREWIRE_HDRLEN; ether_type = GET_BE_U_2(fp->firewire_type); src.addr = fp->firewire_shost; src.addr_string = fwaddr_string; dst.addr = fp->firewire_dhost; dst.addr_string = fwaddr_string; if (ethertype_print(ndo, ether_type, p, length, caplen, &src, &dst) == 0) { /* ether_type not known, print raw packet */ if (!ndo->ndo_eflag) ap1394_hdr_print(ndo, (const u_char *)fp, length + FIREWIRE_HDRLEN); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } return FIREWIRE_HDRLEN; }
static void ipnet_print(netdissect_options *ndo, const u_char *p, u_int length, u_int caplen) { const ipnet_hdr_t *hdr; if (caplen < sizeof(ipnet_hdr_t)) { ND_PRINT((ndo, "[|ipnet]")); return; } if (ndo->ndo_eflag) ipnet_hdr_print(ndo, p, length); length -= sizeof(ipnet_hdr_t); caplen -= sizeof(ipnet_hdr_t); hdr = (const ipnet_hdr_t *)p; p += sizeof(ipnet_hdr_t); switch (hdr->iph_family) { case IPH_AF_INET: ip_print(ndo, p, length); break; case IPH_AF_INET6: ip6_print(ndo, p, length); break; default: if (!ndo->ndo_eflag) ipnet_hdr_print(ndo, (const u_char *)hdr, length + sizeof(ipnet_hdr_t)); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); break; } }
static void atmarp_print(netdissect_options *ndo, const u_char *bp, u_int length, u_int caplen) { const struct atmarp_pkthdr *ap; u_short pro, hrd, op; ap = (const struct atmarp_pkthdr *)bp; ND_TCHECK(*ap); hrd = ATMHRD(ap); pro = ATMPRO(ap); op = ATMOP(ap); if (!ND_TTEST2(*aar_tpa(ap), ATMTPROTO_LEN(ap))) { ND_PRINT((ndo, "[|ARP]")); ND_DEFAULTPRINT((const u_char *)ap, length); return; } if (!ndo->ndo_eflag) { ND_PRINT((ndo, "ARP, ")); } if ((pro != ETHERTYPE_IP && pro != ETHERTYPE_TRAIL) || ATMSPROTO_LEN(ap) != 4 || ATMTPROTO_LEN(ap) != 4 || ndo->ndo_vflag) { ND_PRINT((ndo, "%s, %s (len %u/%u)", tok2str(arphrd_values, "Unknown Hardware (%u)", hrd), tok2str(ethertype_values, "Unknown Protocol (0x%04x)", pro), ATMSPROTO_LEN(ap), ATMTPROTO_LEN(ap))); /* don't know know about the address formats */ if (!ndo->ndo_vflag) { goto out; } } /* print operation */ printf("%s%s ", ndo->ndo_vflag ? ", " : "", tok2str(arpop_values, "Unknown (%u)", op)); switch (op) { case ARPOP_REQUEST: ND_PRINT((ndo, "who-has %s", ipaddr_string(ATMTPA(ap)))); if (ATMTHRD_LEN(ap) != 0) { ND_PRINT((ndo, " (")); atmarp_addr_print(ndo, ATMTHA(ap), ATMTHRD_LEN(ap), ATMTSA(ap), ATMTSLN(ap)); ND_PRINT((ndo, ")")); } ND_PRINT((ndo, "tell %s", ipaddr_string(ATMSPA(ap)))); break; case ARPOP_REPLY: ND_PRINT((ndo, "%s is-at ", ipaddr_string(ATMSPA(ap)))); atmarp_addr_print(ndo, ATMSHA(ap), ATMSHRD_LEN(ap), ATMSSA(ap), ATMSSLN(ap)); break; case ARPOP_INVREQUEST: ND_PRINT((ndo, "who-is ")); atmarp_addr_print(ndo, ATMTHA(ap), ATMTHRD_LEN(ap), ATMTSA(ap), ATMTSLN(ap)); ND_PRINT((ndo, " tell ")); atmarp_addr_print(ndo, ATMSHA(ap), ATMSHRD_LEN(ap), ATMSSA(ap), ATMSSLN(ap)); break; case ARPOP_INVREPLY: atmarp_addr_print(ndo, ATMSHA(ap), ATMSHRD_LEN(ap), ATMSSA(ap), ATMSSLN(ap)); ND_PRINT((ndo, "at %s", ipaddr_string(ATMSPA(ap)))); break; case ARPOP_NAK: ND_PRINT((ndo, "for %s", ipaddr_string(ATMSPA(ap)))); break; default: ND_DEFAULTPRINT((const u_char *)ap, caplen); return; } out: ND_PRINT((ndo, ", length %u", length)); return; trunc: ND_PRINT((ndo, "[|ARP]")); }
u_int _token_print(netdissect_options *ndo, const u_char *p, u_int length, u_int caplen) { const struct token_header *trp; u_short extracted_ethertype; struct ether_header ehdr; u_int route_len = 0, hdr_len = TOKEN_HDRLEN; int seg; trp = (const struct token_header *)p; if (caplen < TOKEN_HDRLEN) { ND_PRINT((ndo, "%s", tstr)); return hdr_len; } /* * Get the TR addresses into a canonical form */ extract_token_addrs(trp, (char*)ESRC(&ehdr), (char*)EDST(&ehdr)); /* Adjust for source routing information in the MAC header */ if (IS_SOURCE_ROUTED(trp)) { /* Clear source-routed bit */ *ESRC(&ehdr) &= 0x7f; if (ndo->ndo_eflag) token_hdr_print(ndo, trp, length, ESRC(&ehdr), EDST(&ehdr)); if (caplen < TOKEN_HDRLEN + 2) { ND_PRINT((ndo, "%s", tstr)); return hdr_len; } route_len = RIF_LENGTH(trp); hdr_len += route_len; if (caplen < hdr_len) { ND_PRINT((ndo, "%s", tstr)); return hdr_len; } if (ndo->ndo_vflag) { ND_PRINT((ndo, "%s ", broadcast_indicator[BROADCAST(trp)])); ND_PRINT((ndo, "%s", direction[DIRECTION(trp)])); for (seg = 0; seg < SEGMENT_COUNT(trp); seg++) ND_PRINT((ndo, " [%d:%d]", RING_NUMBER(trp, seg), BRIDGE_NUMBER(trp, seg))); } else { ND_PRINT((ndo, "rt = %x", EXTRACT_16BITS(&trp->token_rcf))); for (seg = 0; seg < SEGMENT_COUNT(trp); seg++) ND_PRINT((ndo, ":%x", EXTRACT_16BITS(&trp->token_rseg[seg]))); } ND_PRINT((ndo, " (%s) ", largest_frame[LARGEST_FRAME(trp)])); } else { if (ndo->ndo_eflag) token_hdr_print(ndo, trp, length, ESRC(&ehdr), EDST(&ehdr)); } /* Skip over token ring MAC header and routing information */ length -= hdr_len; p += hdr_len; caplen -= hdr_len; /* Frame Control field determines interpretation of packet */ if (FRAME_TYPE(trp) == TOKEN_FC_LLC) { /* Try to print the LLC-layer header & higher layers */ if (llc_print(ndo, p, length, caplen, ESRC(&ehdr), EDST(&ehdr), &extracted_ethertype) == 0) { /* ether_type not known, print raw packet */ if (!ndo->ndo_eflag) token_hdr_print(ndo, trp, length + TOKEN_HDRLEN + route_len, ESRC(&ehdr), EDST(&ehdr)); if (extracted_ethertype) { ND_PRINT((ndo, "(LLC %s) ", etherproto_string(htons(extracted_ethertype)))); } if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } } else { /* Some kinds of TR packet we cannot handle intelligently */ /* XXX - dissect MAC packets if frame type is 0 */ if (!ndo->ndo_eflag) token_hdr_print(ndo, trp, length + TOKEN_HDRLEN + route_len, ESRC(&ehdr), EDST(&ehdr)); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } return (hdr_len); }
u_int nflog_if_print(struct netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { const nflog_hdr_t *hdr = (const nflog_hdr_t *)p; const nflog_tlv_t *tlv; u_int16_t size; u_int16_t h_size = sizeof(nflog_hdr_t); u_int caplen = h->caplen; u_int length = h->len; if (caplen < (int) sizeof(nflog_hdr_t) || length < (int) sizeof(nflog_hdr_t)) { ND_PRINT((ndo, "[|nflog]")); return h_size; } if (!(hdr->nflog_version) == 0) { ND_PRINT((ndo, "version %u (unknown)", hdr->nflog_version)); return h_size; } if (ndo->ndo_eflag) nflog_hdr_print(ndo, hdr, length); p += sizeof(nflog_hdr_t); length -= sizeof(nflog_hdr_t); caplen -= sizeof(nflog_hdr_t); while (length > 0) { /* We have some data. Do we have enough for the TLV header? */ if (caplen < sizeof(nflog_tlv_t) || length < sizeof(nflog_tlv_t)) { /* No. */ ND_PRINT((ndo, "[|nflog]")); return h_size; } tlv = (const nflog_tlv_t *) p; size = tlv->tlv_length; if (size % 4 != 0) size += 4 - size % 4; /* Is the TLV's length less than the minimum? */ if (size < sizeof(nflog_tlv_t)) { /* Yes. Give up now. */ ND_PRINT((ndo, "[|nflog]")); return h_size; } /* Do we have enough data for the full TLV? */ if (caplen < size || length < size) { /* No. */ ND_PRINT((ndo, "[|nflog]")); return h_size; } if (tlv->tlv_type == NFULA_PAYLOAD) { /* * This TLV's data is the packet payload. * Skip past the TLV header, and break out * of the loop so we print the packet data. */ p += sizeof(nflog_tlv_t); h_size += sizeof(nflog_tlv_t); length -= sizeof(nflog_tlv_t); caplen -= sizeof(nflog_tlv_t); break; } p += size; h_size += size; length -= size; caplen -= size; } switch (hdr->nflog_family) { case AF_INET: ip_print(ndo, p, length); break; #ifdef INET6 case AF_INET6: ip6_print(ndo, p, length); break; #endif /*INET6*/ default: if (!ndo->ndo_eflag) nflog_hdr_print(ndo, hdr, length + sizeof(nflog_hdr_t)); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); break; } return h_size; }
/* * This is the top level routine of the printer. 'p' points * to the ether header of the packet, 'h->ts' is the timestamp, * 'h->len' is the length of the packet off the wire, and 'h->caplen' * is the number of bytes actually captured. */ u_int null_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { u_int length = h->len; u_int caplen = h->caplen; u_int family; if (caplen < NULL_HDRLEN) { ND_PRINT((ndo, "[|null]")); return (NULL_HDRLEN); } memcpy((char *)&family, (char *)p, sizeof(family)); /* * This isn't necessarily in our host byte order; if this is * a DLT_LOOP capture, it's in network byte order, and if * this is a DLT_NULL capture from a machine with the opposite * byte-order, it's in the opposite byte order from ours. * * If the upper 16 bits aren't all zero, assume it's byte-swapped. */ if ((family & 0xFFFF0000) != 0) family = SWAPLONG(family); if (ndo->ndo_eflag) null_hdr_print(ndo, family, length); length -= NULL_HDRLEN; caplen -= NULL_HDRLEN; p += NULL_HDRLEN; switch (family) { case BSD_AFNUM_INET: ip_print(ndo, p, length); break; case BSD_AFNUM_INET6_BSD: case BSD_AFNUM_INET6_FREEBSD: case BSD_AFNUM_INET6_DARWIN: ip6_print(ndo, p, length); break; case BSD_AFNUM_ISO: isoclns_print(ndo, p, length, caplen); break; case BSD_AFNUM_APPLETALK: atalk_print(ndo, p, length); break; case BSD_AFNUM_IPX: ipx_print(ndo, p, length); break; default: /* unknown AF_ value */ if (!ndo->ndo_eflag) null_hdr_print(ndo, family, length + NULL_HDRLEN); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } return (NULL_HDRLEN); }
/* * This is the top level routine of the printer. 'p' points * to the ether header of the packet, 'h->ts' is the timestamp, * 'h->len' is the length of the packet off the wire, and 'h->caplen' * is the number of bytes actually captured. */ u_int pktap_if_print(struct netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { uint32_t dlt, hdrlen, rectype; u_int caplen = h->caplen; u_int length = h->len; if_ndo_printer ndo_printer; if_printer printer; pktap_header_t *hdr; if (caplen < sizeof(pktap_header_t) || length < sizeof(pktap_header_t)) { ND_PRINT((ndo, "[|pktap]")); return (0); } hdr = (pktap_header_t *)p; dlt = EXTRACT_LE_32BITS(&hdr->pkt_dlt); hdrlen = EXTRACT_LE_32BITS(&hdr->pkt_len); if (hdrlen < sizeof(pktap_header_t)) { /* * Claimed header length < structure length. * XXX - does this just mean some fields aren't * being supplied, or is it truly an error (i.e., * is the length supplied so that the header can * be expanded in the future)? */ ND_PRINT((ndo, "[|pktap]")); return (0); } if (caplen < hdrlen || length < hdrlen) { ND_PRINT((ndo, "[|pktap]")); return (hdrlen); } if (ndo->ndo_eflag) pktap_header_print(ndo, p, length); length -= hdrlen; caplen -= hdrlen; p += hdrlen; rectype = EXTRACT_LE_32BITS(&hdr->pkt_rectype); switch (rectype) { case PKT_REC_NONE: ND_PRINT((ndo, "no data")); break; case PKT_REC_PACKET: if ((printer = lookup_printer(dlt)) != NULL) { printer(h, p); } else if ((ndo_printer = lookup_ndo_printer(dlt)) != NULL) { ndo_printer(ndo, h, p); } else { if (!ndo->ndo_eflag) pktap_header_print(ndo, (u_char *)hdr, length + hdrlen); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } break; } return (hdrlen); }
void _sctp_print(netdissect_options *ndo, const u_char *bp, /* beginning of sctp packet */ const u_char *bp2, /* beginning of enclosing */ u_int sctpPacketLength) /* ip packet */ { const struct sctpHeader *sctpPktHdr; const struct ip *ip; #ifdef INET6 const struct ip6_hdr *ip6; #endif const void *endPacketPtr; u_short sourcePort, destPort; int chunkCount; const struct sctpChunkDesc *chunkDescPtr; const void *nextChunk; const char *sep; int isforces = 0; sctpPktHdr = (const struct sctpHeader*) bp; endPacketPtr = (const u_char*)sctpPktHdr+sctpPacketLength; if( (u_long) endPacketPtr > (u_long) ndo->ndo_snapend) endPacketPtr = (const void *) ndo->ndo_snapend; ip = (struct ip *)bp2; #ifdef INET6 if (IP_V(ip) == 6) ip6 = (const struct ip6_hdr *)bp2; else ip6 = NULL; #endif /*INET6*/ ND_TCHECK(*sctpPktHdr); if (sctpPacketLength < sizeof(struct sctpHeader)) { ND_PRINT((ndo, "truncated-sctp - %ld bytes missing!", (long)sctpPacketLength-sizeof(struct sctpHeader))); return; } /* sctpPacketLength -= sizeof(struct sctpHeader); packet length */ /* is now only as long as the payload */ sourcePort = EXTRACT_16BITS(&sctpPktHdr->source); destPort = EXTRACT_16BITS(&sctpPktHdr->destination); #ifdef INET6 if (ip6) { ND_PRINT((ndo, "%s.%d > %s.%d: sctp", ip6addr_string(ndo, &ip6->ip6_src), sourcePort, ip6addr_string(ndo, &ip6->ip6_dst), destPort)); } else #endif /*INET6*/ { ND_PRINT((ndo, "%s.%d > %s.%d: sctp", ipaddr_string(ndo, &ip->ip_src), sourcePort, ipaddr_string(ndo, &ip->ip_dst), destPort)); } if (isForCES_port(sourcePort)) { ND_PRINT((ndo, "[%s]", tok2str(ForCES_channels, NULL, sourcePort))); isforces = 1; } if (isForCES_port(destPort)) { ND_PRINT((ndo, "[%s]", tok2str(ForCES_channels, NULL, destPort))); isforces = 1; } if (ndo->ndo_vflag >= 2) sep = "\n\t"; else sep = " ("; /* cycle through all chunks, printing information on each one */ for (chunkCount = 0, chunkDescPtr = (const struct sctpChunkDesc *) ((const u_char*) sctpPktHdr + sizeof(struct sctpHeader)); chunkDescPtr != NULL && ( (const void *) ((const u_char *) chunkDescPtr + sizeof(struct sctpChunkDesc)) <= endPacketPtr); chunkDescPtr = (const struct sctpChunkDesc *) nextChunk, chunkCount++) { uint16_t chunkLength; const u_char *chunkEnd; uint16_t align; ND_TCHECK(*chunkDescPtr); chunkLength = EXTRACT_16BITS(&chunkDescPtr->chunkLength); if (chunkLength < sizeof(*chunkDescPtr)) { ND_PRINT((ndo, "%s%d) [Bad chunk length %u]", sep, chunkCount+1, chunkLength)); break; } ND_TCHECK2(*((uint8_t *)chunkDescPtr), chunkLength); chunkEnd = ((const u_char*)chunkDescPtr + chunkLength); align=chunkLength % 4; if (align != 0) align = 4 - align; nextChunk = (const void *) (chunkEnd + align); ND_PRINT((ndo, "%s%d) ", sep, chunkCount+1)); ND_PRINT((ndo, "[%s] ", tok2str(sctp_chunkid_str, "Unknown chunk type: 0x%x", chunkDescPtr->chunkID))); switch (chunkDescPtr->chunkID) { case SCTP_DATA : { const struct sctpDataPart *dataHdrPtr; uint32_t ppid; const u_char *payloadPtr; u_int payload_size; if ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED) == SCTP_DATA_UNORDERED) ND_PRINT((ndo, "(U)")); if ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG) ND_PRINT((ndo, "(B)")); if ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG) == SCTP_DATA_LAST_FRAG) ND_PRINT((ndo, "(E)")); if( ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED) == SCTP_DATA_UNORDERED) || ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG) || ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG) == SCTP_DATA_LAST_FRAG) ) ND_PRINT((ndo, " ")); dataHdrPtr=(const struct sctpDataPart*)(chunkDescPtr+1); ppid = EXTRACT_32BITS(&dataHdrPtr->payloadtype); ND_PRINT((ndo, "[TSN: %u] ", EXTRACT_32BITS(&dataHdrPtr->TSN))); ND_PRINT((ndo, "[SID: %u] ", EXTRACT_16BITS(&dataHdrPtr->streamId))); ND_PRINT((ndo, "[SSEQ %u] ", EXTRACT_16BITS(&dataHdrPtr->sequence))); ND_PRINT((ndo, "[PPID %s] ", tok2str(PayloadProto_idents, "0x%x", ppid))); if (!isforces) { isforces = (ppid == SCTP_PPID_FORCES_HP) || (ppid == SCTP_PPID_FORCES_MP) || (ppid == SCTP_PPID_FORCES_LP); } payloadPtr = (const u_char *) (dataHdrPtr + 1); if (EXTRACT_16BITS(&chunkDescPtr->chunkLength) < sizeof(struct sctpDataPart) + sizeof(struct sctpChunkDesc) + 1) { ND_PRINT((ndo, "bogus chunk length %u]", EXTRACT_16BITS(&chunkDescPtr->chunkLength))); return; } payload_size = EXTRACT_16BITS(&chunkDescPtr->chunkLength) - (sizeof(struct sctpDataPart) + sizeof(struct sctpChunkDesc)); if (isforces) { forces_print(ndo, payloadPtr, payload_size); } else if (ndo->ndo_vflag >= 2) { /* if verbose output is specified */ /* at the command line */ switch (ppid) { case SCTP_PPID_M3UA : m3ua_print(ndo, payloadPtr, payload_size); break; default: ND_PRINT((ndo, "[Payload")); if (!ndo->ndo_suppress_default_print) { ND_PRINT((ndo, ":")); ND_DEFAULTPRINT(payloadPtr, payload_size); } ND_PRINT((ndo, "]")); break; } } break; } case SCTP_INITIATION : { const struct sctpInitiation *init; init=(const struct sctpInitiation*)(chunkDescPtr+1); ND_PRINT((ndo, "[init tag: %u] ", EXTRACT_32BITS(&init->initTag))); ND_PRINT((ndo, "[rwnd: %u] ", EXTRACT_32BITS(&init->rcvWindowCredit))); ND_PRINT((ndo, "[OS: %u] ", EXTRACT_16BITS(&init->NumPreopenStreams))); ND_PRINT((ndo, "[MIS: %u] ", EXTRACT_16BITS(&init->MaxInboundStreams))); ND_PRINT((ndo, "[init TSN: %u] ", EXTRACT_32BITS(&init->initialTSN))); #if(0) /* ALC you can add code for optional params here */ if( (init+1) < chunkEnd ) ND_PRINT((ndo, " @@@@@ UNFINISHED @@@@@@%s\n", "Optional params present, but not printed.")); #endif break; } case SCTP_INITIATION_ACK : { const struct sctpInitiation *init; init=(const struct sctpInitiation*)(chunkDescPtr+1); ND_PRINT((ndo, "[init tag: %u] ", EXTRACT_32BITS(&init->initTag))); ND_PRINT((ndo, "[rwnd: %u] ", EXTRACT_32BITS(&init->rcvWindowCredit))); ND_PRINT((ndo, "[OS: %u] ", EXTRACT_16BITS(&init->NumPreopenStreams))); ND_PRINT((ndo, "[MIS: %u] ", EXTRACT_16BITS(&init->MaxInboundStreams))); ND_PRINT((ndo, "[init TSN: %u] ", EXTRACT_32BITS(&init->initialTSN))); #if(0) /* ALC you can add code for optional params here */ if( (init+1) < chunkEnd ) ND_PRINT((ndo, " @@@@@ UNFINISHED @@@@@@%s\n", "Optional params present, but not printed.")); #endif break; } case SCTP_SELECTIVE_ACK: { const struct sctpSelectiveAck *sack; const struct sctpSelectiveFrag *frag; int fragNo, tsnNo; const u_char *dupTSN; sack=(const struct sctpSelectiveAck*)(chunkDescPtr+1); ND_PRINT((ndo, "[cum ack %u] ", EXTRACT_32BITS(&sack->highestConseqTSN))); ND_PRINT((ndo, "[a_rwnd %u] ", EXTRACT_32BITS(&sack->updatedRwnd))); ND_PRINT((ndo, "[#gap acks %u] ", EXTRACT_16BITS(&sack->numberOfdesc))); ND_PRINT((ndo, "[#dup tsns %u] ", EXTRACT_16BITS(&sack->numDupTsns))); /* print gaps */ for (frag = ( (const struct sctpSelectiveFrag *) ((const struct sctpSelectiveAck *) sack+1)), fragNo=0; (const void *)frag < nextChunk && fragNo < EXTRACT_16BITS(&sack->numberOfdesc); frag++, fragNo++) ND_PRINT((ndo, "\n\t\t[gap ack block #%d: start = %u, end = %u] ", fragNo+1, EXTRACT_32BITS(&sack->highestConseqTSN) + EXTRACT_16BITS(&frag->fragmentStart), EXTRACT_32BITS(&sack->highestConseqTSN) + EXTRACT_16BITS(&frag->fragmentEnd))); /* print duplicate TSNs */ for (dupTSN = (const u_char *)frag, tsnNo=0; (const void *) dupTSN < nextChunk && tsnNo<EXTRACT_16BITS(&sack->numDupTsns); dupTSN += 4, tsnNo++) ND_PRINT((ndo, "\n\t\t[dup TSN #%u: %u] ", tsnNo+1, EXTRACT_32BITS(dupTSN))); break; } } if (ndo->ndo_vflag < 2) sep = ", ("; } return; trunc: ND_PRINT((ndo, "[|sctp]")); }
/* * This is the top level routine of the printer. 'p' points to the * Linux "cooked capture" header of the packet, 'h->ts' is the timestamp, * 'h->len' is the length of the packet off the wire, and 'h->caplen' * is the number of bytes actually captured. */ u_int sll_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { u_int caplen = h->caplen; u_int length = h->len; register const struct sll_header *sllp; u_short ether_type; u_short extracted_ethertype; if (caplen < SLL_HDR_LEN) { /* * XXX - this "can't happen" because "pcap-linux.c" always * adds this many bytes of header to every packet in a * cooked socket capture. */ ND_PRINT((ndo, "[|sll]")); return (caplen); } sllp = (const struct sll_header *)p; if (ndo->ndo_eflag) sll_print(ndo, sllp, length); /* * Go past the cooked-mode header. */ length -= SLL_HDR_LEN; caplen -= SLL_HDR_LEN; p += SLL_HDR_LEN; ether_type = EXTRACT_16BITS(&sllp->sll_protocol); recurse: /* * Is it (gag) an 802.3 encapsulation, or some non-Ethernet * packet type? */ if (ether_type <= ETHERMTU) { /* * Yes - what type is it? */ switch (ether_type) { case LINUX_SLL_P_802_3: /* * Ethernet_802.3 IPX frame. */ ipx_print(ndo, p, length); break; case LINUX_SLL_P_802_2: /* * 802.2. * Try to print the LLC-layer header & higher layers. */ if (llc_print(ndo, p, length, caplen, NULL, NULL, &extracted_ethertype) == 0) goto unknown; /* unknown LLC type */ break; default: extracted_ethertype = 0; /*FALLTHROUGH*/ unknown: /* ether_type not known, print raw packet */ if (!ndo->ndo_eflag) sll_print(ndo, sllp, length + SLL_HDR_LEN); if (extracted_ethertype) { ND_PRINT((ndo, "(LLC %s) ", etherproto_string(htons(extracted_ethertype)))); } if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); break; } } else if (ether_type == ETHERTYPE_8021Q) { /* * Print VLAN information, and then go back and process * the enclosed type field. */ if (caplen < 4 || length < 4) { ND_PRINT((ndo, "[|vlan]")); return (SLL_HDR_LEN); } if (ndo->ndo_eflag) { uint16_t tag = EXTRACT_16BITS(p); ND_PRINT((ndo, "vlan %u, p %u%s, ", tag & 0xfff, tag >> 13, (tag & 0x1000) ? ", CFI" : "")); } ether_type = EXTRACT_16BITS(p + 2); if (ether_type <= ETHERMTU) ether_type = LINUX_SLL_P_802_2; if (!ndo->ndo_qflag) { ND_PRINT((ndo, "ethertype %s, ", tok2str(ethertype_values, "Unknown", ether_type))); } p += 4; length -= 4; caplen -= 4; goto recurse; } else {
/* * Print an Ethernet frame. * This might be encapsulated within another frame; we might be passed * a pointer to a function that can print header information for that * frame's protocol, and an argument to pass to that function. */ void ether_print(netdissect_options *ndo, const u_char *p, u_int length, u_int caplen, void (*print_encap_header)(netdissect_options *ndo, const u_char *), const u_char *encap_header_arg) { struct ether_header *ep; u_int orig_length; u_short ether_type; u_short extracted_ether_type; if (caplen < ETHER_HDRLEN || length < ETHER_HDRLEN) { ND_PRINT((ndo, "[|ether]")); return; } if (ndo->ndo_eflag) { if (print_encap_header != NULL) (*print_encap_header)(ndo, encap_header_arg); ether_hdr_print(ndo, p, length); } orig_length = length; length -= ETHER_HDRLEN; caplen -= ETHER_HDRLEN; ep = (struct ether_header *)p; p += ETHER_HDRLEN; ether_type = EXTRACT_16BITS(&ep->ether_type); recurse: /* * Is it (gag) an 802.3 encapsulation? */ if (ether_type <= ETHERMTU) { /* Try to print the LLC-layer header & higher layers */ if (llc_print(ndo, p, length, caplen, ESRC(ep), EDST(ep), &extracted_ether_type) == 0) { /* ether_type not known, print raw packet */ if (!ndo->ndo_eflag) { if (print_encap_header != NULL) (*print_encap_header)(ndo, encap_header_arg); ether_hdr_print(ndo, (u_char *)ep, orig_length); } if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } } else if (ether_type == ETHERTYPE_8021Q || ether_type == ETHERTYPE_8021Q9100 || ether_type == ETHERTYPE_8021Q9200 || ether_type == ETHERTYPE_8021QinQ) { /* * Print VLAN information, and then go back and process * the enclosed type field. */ if (caplen < 4 || length < 4) { ND_PRINT((ndo, "[|vlan]")); return; } if (ndo->ndo_eflag) { uint16_t tag = EXTRACT_16BITS(p); ND_PRINT((ndo, "%s, ", ieee8021q_tci_string(tag))); } ether_type = EXTRACT_16BITS(p + 2); if (ndo->ndo_eflag && ether_type > ETHERMTU) ND_PRINT((ndo, "ethertype %s, ", tok2str(ethertype_values,"0x%04x", ether_type))); p += 4; length -= 4; caplen -= 4; goto recurse; } else if (ether_type == ETHERTYPE_JUMBO) { /* * Alteon jumbo frames. * See * * http://tools.ietf.org/html/draft-ietf-isis-ext-eth-01 * * which indicates that, following the type field, * there's an LLC header and payload. */ /* Try to print the LLC-layer header & higher layers */ if (llc_print(ndo, p, length, caplen, ESRC(ep), EDST(ep), &extracted_ether_type) == 0) { /* ether_type not known, print raw packet */ if (!ndo->ndo_eflag) { if (print_encap_header != NULL) (*print_encap_header)(ndo, encap_header_arg); ether_hdr_print(ndo, (u_char *)ep, orig_length); } if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } } else { if (ethertype_print(ndo, ether_type, p, length, caplen) == 0) { /* ether_type not known, print raw packet */ if (!ndo->ndo_eflag) { if (print_encap_header != NULL) (*print_encap_header)(ndo, encap_header_arg); ether_hdr_print(ndo, (u_char *)ep, orig_length); } if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } } }
/* * If we printed information about the payload, returns the length of the LLC * header, plus the length of any SNAP header following it. * * Otherwise (for example, if the packet has unknown SAPs or has a SNAP * header with an unknown OUI/PID combination), returns the *negative* * of that value. */ int llc_print(netdissect_options *ndo, const u_char *p, u_int length, u_int caplen, const struct lladdr_info *src, const struct lladdr_info *dst) { uint8_t dsap_field, dsap, ssap_field, ssap; uint16_t control; int hdrlen; int is_u; if (caplen < 3) { ND_PRINT("[|llc]"); ND_DEFAULTPRINT((const u_char *)p, caplen); return (caplen); } if (length < 3) { ND_PRINT("[|llc]"); ND_DEFAULTPRINT((const u_char *)p, caplen); return (length); } dsap_field = EXTRACT_U_1(p); ssap_field = EXTRACT_U_1(p + 1); /* * OK, what type of LLC frame is this? The length * of the control field depends on that - I frames * have a two-byte control field, and U frames have * a one-byte control field. */ control = EXTRACT_U_1(p + 2); if ((control & LLC_U_FMT) == LLC_U_FMT) { /* * U frame. */ is_u = 1; hdrlen = 3; /* DSAP, SSAP, 1-byte control field */ } else { /* * The control field in I and S frames is * 2 bytes... */ if (caplen < 4) { ND_PRINT("[|llc]"); ND_DEFAULTPRINT((const u_char *)p, caplen); return (caplen); } if (length < 4) { ND_PRINT("[|llc]"); ND_DEFAULTPRINT((const u_char *)p, caplen); return (length); } /* * ...and is little-endian. */ control = EXTRACT_LE_U_2(p + 2); is_u = 0; hdrlen = 4; /* DSAP, SSAP, 2-byte control field */ } if (ssap_field == LLCSAP_GLOBAL && dsap_field == LLCSAP_GLOBAL) { /* * This is an Ethernet_802.3 IPX frame; it has an * 802.3 header (i.e., an Ethernet header where the * type/length field is <= MAX_ETHERNET_LENGTH_VAL, * i.e. it's a length field, not a type field), but * has no 802.2 header - the IPX packet starts right * after the Ethernet header, with a signature of two * bytes of 0xFF (which is LLCSAP_GLOBAL). * * (It might also have been an Ethernet_802.3 IPX at * one time, but got bridged onto another network, * such as an 802.11 network; this has appeared in at * least one capture file.) */ if (ndo->ndo_eflag) ND_PRINT("IPX 802.3: "); ipx_print(ndo, p, length); return (0); /* no LLC header */ } dsap = dsap_field & ~LLC_IG; ssap = ssap_field & ~LLC_GSAP; if (ndo->ndo_eflag) { ND_PRINT("LLC, dsap %s (0x%02x) %s, ssap %s (0x%02x) %s", tok2str(llc_values, "Unknown", dsap), dsap, tok2str(llc_ig_flag_values, "Unknown", dsap_field & LLC_IG), tok2str(llc_values, "Unknown", ssap), ssap, tok2str(llc_flag_values, "Unknown", ssap_field & LLC_GSAP)); if (is_u) { ND_PRINT(", ctrl 0x%02x: ", control); } else { ND_PRINT(", ctrl 0x%04x: ", control); } } /* * Skip LLC header. */ p += hdrlen; length -= hdrlen; caplen -= hdrlen; if (ssap == LLCSAP_SNAP && dsap == LLCSAP_SNAP && control == LLC_UI) { /* * XXX - what *is* the right bridge pad value here? * Does anybody ever bridge one form of LAN traffic * over a networking type that uses 802.2 LLC? */ if (!snap_print(ndo, p, length, caplen, src, dst, 2)) { /* * Unknown packet type; tell our caller, by * returning a negative value, so they * can print the raw packet. */ return (-(hdrlen + 5)); /* include LLC and SNAP header */ } else return (hdrlen + 5); /* include LLC and SNAP header */ } if (ssap == LLCSAP_8021D && dsap == LLCSAP_8021D && control == LLC_UI) { stp_print(ndo, p, length); return (hdrlen); } if (ssap == LLCSAP_IP && dsap == LLCSAP_IP && control == LLC_UI) { /* * This is an RFC 948-style IP packet, with * an 802.3 header and an 802.2 LLC header * with the source and destination SAPs being * the IP SAP. */ ip_print(ndo, p, length); return (hdrlen); } if (ssap == LLCSAP_IPX && dsap == LLCSAP_IPX && control == LLC_UI) { /* * This is an Ethernet_802.2 IPX frame, with an 802.3 * header and an 802.2 LLC header with the source and * destination SAPs being the IPX SAP. */ if (ndo->ndo_eflag) ND_PRINT("IPX 802.2: "); ipx_print(ndo, p, length); return (hdrlen); } #ifdef ENABLE_SMB if (ssap == LLCSAP_NETBEUI && dsap == LLCSAP_NETBEUI && (!(control & LLC_S_FMT) || control == LLC_U_FMT)) { /* * we don't actually have a full netbeui parser yet, but the * smb parser can handle many smb-in-netbeui packets, which * is very useful, so we call that * * We don't call it for S frames, however, just I frames * (which are frames that don't have the low-order bit, * LLC_S_FMT, set in the first byte of the control field) * and UI frames (whose control field is just 3, LLC_U_FMT). */ netbeui_print(ndo, control, p, length); return (hdrlen); } #endif if (ssap == LLCSAP_ISONS && dsap == LLCSAP_ISONS && control == LLC_UI) { isoclns_print(ndo, p, length); return (hdrlen); } if (!ndo->ndo_eflag) { if (ssap == dsap) { if (src == NULL || dst == NULL) ND_PRINT("%s ", tok2str(llc_values, "Unknown DSAP 0x%02x", dsap)); else ND_PRINT("%s > %s %s ", (src->addr_string)(ndo, src->addr), (dst->addr_string)(ndo, dst->addr), tok2str(llc_values, "Unknown DSAP 0x%02x", dsap)); } else { if (src == NULL || dst == NULL) ND_PRINT("%s > %s ", tok2str(llc_values, "Unknown SSAP 0x%02x", ssap), tok2str(llc_values, "Unknown DSAP 0x%02x", dsap)); else ND_PRINT("%s %s > %s %s ", (src->addr_string)(ndo, src->addr), tok2str(llc_values, "Unknown SSAP 0x%02x", ssap), (dst->addr_string)(ndo, dst->addr), tok2str(llc_values, "Unknown DSAP 0x%02x", dsap)); } } if (is_u) { ND_PRINT("Unnumbered, %s, Flags [%s], length %u", tok2str(llc_cmd_values, "%02x", LLC_U_CMD(control)), tok2str(llc_flag_values,"?",(ssap_field & LLC_GSAP) | (control & LLC_U_POLL)), length + hdrlen); if ((control & ~LLC_U_POLL) == LLC_XID) { if (length == 0) { /* * XID with no payload. * This could, for example, be an SNA * "short form" XID. */ return (hdrlen); } if (caplen < 1) { ND_PRINT("[|llc]"); if (caplen > 0) ND_DEFAULTPRINT((const u_char *)p, caplen); return (hdrlen); } if (EXTRACT_U_1(p) == LLC_XID_FI) { if (caplen < 3 || length < 3) { ND_PRINT("[|llc]"); if (caplen > 0) ND_DEFAULTPRINT((const u_char *)p, caplen); } else ND_PRINT(": %02x %02x", EXTRACT_U_1(p + 1), EXTRACT_U_1(p + 2)); return (hdrlen); } } } else { if ((control & LLC_S_FMT) == LLC_S_FMT) { ND_PRINT("Supervisory, %s, rcv seq %u, Flags [%s], length %u", tok2str(llc_supervisory_values,"?",LLC_S_CMD(control)), LLC_IS_NR(control), tok2str(llc_flag_values,"?",(ssap_field & LLC_GSAP) | (control & LLC_IS_POLL)), length + hdrlen); return (hdrlen); /* no payload to print */ } else { ND_PRINT("Information, send seq %u, rcv seq %u, Flags [%s], length %u", LLC_I_NS(control), LLC_IS_NR(control), tok2str(llc_flag_values,"?",(ssap_field & LLC_GSAP) | (control & LLC_IS_POLL)), length + hdrlen); } } return (-hdrlen); }
u_int ieee802_15_4_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { u_int caplen = h->caplen; int hdrlen; u_int16_t fc; u_int8_t seq; if (caplen < 3) { ND_PRINT((ndo, "[|802.15.4] %x", caplen)); return caplen; } fc = EXTRACT_LE_16BITS(p); hdrlen = extract_header_length(fc); seq = EXTRACT_LE_8BITS(p + 2); p += 3; caplen -= 3; ND_PRINT((ndo,"IEEE 802.15.4 %s packet ", ftypes[fc & 0x7])); if (ndo->ndo_vflag) ND_PRINT((ndo,"seq %02x ", seq)); if (hdrlen == -1) { ND_PRINT((ndo,"malformed! ")); return caplen; } if (!ndo->ndo_vflag) { p+= hdrlen; caplen -= hdrlen; } else { u_int16_t panid = 0; switch ((fc >> 10) & 0x3) { case 0x00: ND_PRINT((ndo,"none ")); break; case 0x01: ND_PRINT((ndo,"reserved destination addressing mode")); return 0; case 0x02: panid = EXTRACT_LE_16BITS(p); p += 2; ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p))); p += 2; break; case 0x03: panid = EXTRACT_LE_16BITS(p); p += 2; ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(p))); p += 8; break; } ND_PRINT((ndo,"< ")); switch ((fc >> 14) & 0x3) { case 0x00: ND_PRINT((ndo,"none ")); break; case 0x01: ND_PRINT((ndo,"reserved source addressing mode")); return 0; case 0x02: if (!(fc & (1 << 6))) { panid = EXTRACT_LE_16BITS(p); p += 2; } ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p))); p += 2; break; case 0x03: if (!(fc & (1 << 6))) { panid = EXTRACT_LE_16BITS(p); p += 2; } ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(p))); p += 8; break; } caplen -= hdrlen; } if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); return 0; }
void arp_print(netdissect_options *ndo, const u_char *bp, u_int length, u_int caplen) { const struct arp_pkthdr *ap; u_short pro, hrd, op, linkaddr; ap = (const struct arp_pkthdr *)bp; ND_TCHECK(*ap); hrd = HRD(ap); pro = PRO(ap); op = OP(ap); /* if its ATM then call the ATM ARP printer for Frame-relay ARP most of the fields are similar to Ethernet so overload the Ethernet Printer and set the linkaddr type for linkaddr_string() accordingly */ switch(hrd) { case ARPHRD_ATM2225: atmarp_print(ndo, bp, length, caplen); return; case ARPHRD_FRELAY: linkaddr = LINKADDR_FRELAY; break; default: linkaddr = LINKADDR_ETHER; break; } if (!ND_TTEST2(*ar_tpa(ap), PROTO_LEN(ap))) { ND_PRINT((ndo, "[|ARP]")); ND_DEFAULTPRINT((const u_char *)ap, length); return; } if (!ndo->ndo_eflag) { ND_PRINT((ndo, "ARP, ")); } /* print hardware type/len and proto type/len */ if ((pro != ETHERTYPE_IP && pro != ETHERTYPE_TRAIL) || PROTO_LEN(ap) != 4 || HRD_LEN(ap) == 0 || ndo->ndo_vflag) { ND_PRINT((ndo, "%s (len %u), %s (len %u)", tok2str(arphrd_values, "Unknown Hardware (%u)", hrd), HRD_LEN(ap), tok2str(ethertype_values, "Unknown Protocol (0x%04x)", pro), PROTO_LEN(ap))); /* don't know know about the address formats */ if (!ndo->ndo_vflag) { goto out; } } /* print operation */ printf("%s%s ", ndo->ndo_vflag ? ", " : "", tok2str(arpop_values, "Unknown (%u)", op)); switch (op) { case ARPOP_REQUEST: ND_PRINT((ndo, "who-has %s", ipaddr_string(TPA(ap)))); if (memcmp((const char *)ezero, (const char *)THA(ap), HRD_LEN(ap)) != 0) ND_PRINT((ndo, " (%s)", linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)))); ND_PRINT((ndo, " tell %s", ipaddr_string(SPA(ap)))); break; case ARPOP_REPLY: ND_PRINT((ndo, "%s is-at %s", ipaddr_string(SPA(ap)), linkaddr_string(SHA(ap), linkaddr, HRD_LEN(ap)))); break; case ARPOP_REVREQUEST: ND_PRINT((ndo, "who-is %s tell %s", linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)), linkaddr_string(SHA(ap), linkaddr, HRD_LEN(ap)))); break; case ARPOP_REVREPLY: ND_PRINT((ndo, "%s at %s", linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)), ipaddr_string(TPA(ap)))); break; case ARPOP_INVREQUEST: ND_PRINT((ndo, "who-is %s tell %s", linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)), linkaddr_string(SHA(ap), linkaddr, HRD_LEN(ap)))); break; case ARPOP_INVREPLY: ND_PRINT((ndo,"%s at %s", linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)), ipaddr_string(TPA(ap)))); break; default: ND_DEFAULTPRINT((const u_char *)ap, caplen); return; } out: ND_PRINT((ndo, ", length %u", length)); return; trunc: ND_PRINT((ndo, "[|ARP]")); }
/* * RFC3032: MPLS label stack encoding */ void mpls_print(netdissect_options *ndo, const u_char *bp, u_int length) { const u_char *p; uint32_t label_entry; uint16_t label_stack_depth = 0; enum mpls_packet_type pt = PT_UNKNOWN; p = bp; ND_PRINT((ndo, "MPLS")); do { ND_TCHECK2(*p, sizeof(label_entry)); label_entry = EXTRACT_32BITS(p); ND_PRINT((ndo, "%s(label %u", (label_stack_depth && ndo->ndo_vflag) ? "\n\t" : " ", MPLS_LABEL(label_entry))); label_stack_depth++; if (ndo->ndo_vflag && MPLS_LABEL(label_entry) < sizeof(mpls_labelname) / sizeof(mpls_labelname[0])) ND_PRINT((ndo, " (%s)", mpls_labelname[MPLS_LABEL(label_entry)])); ND_PRINT((ndo, ", exp %u", MPLS_EXP(label_entry))); if (MPLS_STACK(label_entry)) ND_PRINT((ndo, ", [S]")); ND_PRINT((ndo, ", ttl %u)", MPLS_TTL(label_entry))); p += sizeof(label_entry); } while (!MPLS_STACK(label_entry)); /* * Try to figure out the packet type. */ switch (MPLS_LABEL(label_entry)) { case 0: /* IPv4 explicit NULL label */ case 3: /* IPv4 implicit NULL label */ pt = PT_IPV4; break; case 2: /* IPv6 explicit NULL label */ pt = PT_IPV6; break; default: /* * Generally there's no indication of protocol in MPLS label * encoding. * * However, draft-hsmit-isis-aal5mux-00.txt describes a * technique for encapsulating IS-IS and IP traffic on the * same ATM virtual circuit; you look at the first payload * byte to determine the network layer protocol, based on * the fact that * * 1) the first byte of an IP header is 0x45-0x4f * for IPv4 and 0x60-0x6f for IPv6; * * 2) the first byte of an OSI CLNP packet is 0x81, * the first byte of an OSI ES-IS packet is 0x82, * and the first byte of an OSI IS-IS packet is * 0x83; * * so the network layer protocol can be inferred from the * first byte of the packet, if the protocol is one of the * ones listed above. * * Cisco sends control-plane traffic MPLS-encapsulated in * this fashion. */ switch(*p) { case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: pt = PT_IPV4; break; case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: pt = PT_IPV6; break; case 0x81: case 0x82: case 0x83: pt = PT_OSI; break; default: /* ok bail out - we did not figure out what it is*/ break; } } /* * Print the payload. */ if (pt == PT_UNKNOWN) { if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, length - (p - bp)); return; } ND_PRINT((ndo, ndo->ndo_vflag ? "\n\t" : " ")); switch (pt) { case PT_IPV4: ip_print(ndo, p, length - (p - bp)); break; case PT_IPV6: ip6_print(ndo, p, length - (p - bp)); break; case PT_OSI: isoclns_print(ndo, p, length - (p - bp), length - (p - bp)); break; default: break; } return; trunc: ND_PRINT((ndo, "[|MPLS]")); }
/* * Print an Ethernet frame. * This might be encapsulated within another frame; we might be passed * a pointer to a function that can print header information for that * frame's protocol, and an argument to pass to that function. */ void ether_print(netdissect_options *ndo, const u_char *p, u_int length, u_int caplen, void (*print_encap_header)(netdissect_options *ndo, const u_char *), const u_char *encap_header_arg) { struct ether_header *ep; u_int orig_length; u_short ether_type; u_short extracted_ether_type; if (caplen < ETHER_HDRLEN || length < ETHER_HDRLEN) { ND_PRINT((ndo, "[|ether]")); return; } if (ndo->ndo_eflag) { if (print_encap_header != NULL) (*print_encap_header)(ndo, encap_header_arg); ether_hdr_print(ndo, p, length); } orig_length = length; length -= ETHER_HDRLEN; caplen -= ETHER_HDRLEN; ep = (struct ether_header *)p; p += ETHER_HDRLEN; ether_type = EXTRACT_16BITS(&ep->ether_type); recurse: /* * Is it (gag) an 802.3 encapsulation? */ if (ether_type <= ETHERMTU) { /* Try to print the LLC-layer header & higher layers */ if (llc_print(ndo, p, length, caplen, ESRC(ep), EDST(ep), &extracted_ether_type) == 0) { /* ether_type not known, print raw packet */ if (!ndo->ndo_eflag) { if (print_encap_header != NULL) (*print_encap_header)(ndo, encap_header_arg); ether_hdr_print(ndo, (u_char *)ep, orig_length); } if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } } else if (ether_type == ETHERTYPE_8021Q || ether_type == ETHERTYPE_8021Q9100 || ether_type == ETHERTYPE_8021Q9200 || ether_type == ETHERTYPE_8021QinQ) { /* * Print VLAN information, and then go back and process * the enclosed type field. */ if (caplen < 4 || length < 4) { ND_PRINT((ndo, "[|vlan]")); return; } if (ndo->ndo_eflag) { uint16_t tag = EXTRACT_16BITS(p); ND_PRINT((ndo, "vlan %u, p %u%s, ", tag & 0xfff, tag >> 13, (tag & 0x1000) ? ", CFI" : "")); } ether_type = EXTRACT_16BITS(p + 2); if (ndo->ndo_eflag && ether_type > ETHERMTU) ND_PRINT((ndo, "ethertype %s, ", tok2str(ethertype_values,"0x%04x", ether_type))); p += 4; length -= 4; caplen -= 4; goto recurse; } else if (ether_type == ETHERTYPE_JUMBO) {
/* * This is the top level routine of the printer. 'p' points * to the ARCNET header of the packet, 'h->ts' is the timestamp, * 'h->len' is the length of the packet off the wire, and 'h->caplen' * is the number of bytes actually captured. */ u_int arcnet_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { u_int caplen = h->caplen; u_int length = h->len; const struct arc_header *ap; int phds; u_int flag = 0, archdrlen = 0; u_int seqid = 0; u_char arc_type; if (caplen < ARC_HDRLEN || length < ARC_HDRLEN) { ND_PRINT("[|arcnet]"); return (caplen); } ap = (const struct arc_header *)p; arc_type = EXTRACT_U_1(ap->arc_type); switch (arc_type) { default: phds = 1; break; case ARCTYPE_IP_OLD: case ARCTYPE_ARP_OLD: case ARCTYPE_DIAGNOSE: phds = 0; archdrlen = ARC_HDRLEN; break; } if (phds) { if (caplen < ARC_HDRNEWLEN || length < ARC_HDRNEWLEN) { arcnet_print(ndo, p, length, 0, 0, 0); ND_PRINT("[|phds]"); return (caplen); } flag = EXTRACT_U_1(ap->arc_flag); if (flag == 0xff) { if (caplen < ARC_HDRNEWLEN_EXC || length < ARC_HDRNEWLEN_EXC) { arcnet_print(ndo, p, length, 0, 0, 0); ND_PRINT("[|phds extended]"); return (caplen); } flag = EXTRACT_U_1(ap->arc_flag2); seqid = EXTRACT_BE_U_2(ap->arc_seqid2); archdrlen = ARC_HDRNEWLEN_EXC; } else { seqid = EXTRACT_BE_U_2(ap->arc_seqid); archdrlen = ARC_HDRNEWLEN; } } if (ndo->ndo_eflag) arcnet_print(ndo, p, length, phds, flag, seqid); /* * Go past the ARCNET header. */ length -= archdrlen; caplen -= archdrlen; p += archdrlen; if (phds && flag && (flag & 1) == 0) { /* * This is a middle fragment. */ return (archdrlen); } if (!arcnet_encap_print(ndo, arc_type, p, length, caplen)) ND_DEFAULTPRINT(p, caplen); return (archdrlen); }
/* * This is the top level routine of the printer. 'p' points * to the ether header of the packet, 'h->ts' is the timestamp, * 'h->len' is the length of the packet off the wire, and 'h->caplen' * is the number of bytes actually captured. */ u_int pktap_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { uint32_t dlt, hdrlen, rectype; u_int caplen = h->caplen; u_int length = h->len; if_printer printer; const pktap_header_t *hdr; struct pcap_pkthdr nhdr; ndo->ndo_protocol = "pktap_if"; if (caplen < sizeof(pktap_header_t)) { nd_print_trunc(ndo); return (caplen); } hdr = (const pktap_header_t *)p; dlt = EXTRACT_LE_U_4(hdr->pkt_dlt); hdrlen = EXTRACT_LE_U_4(hdr->pkt_len); if (hdrlen < sizeof(pktap_header_t)) { /* * Claimed header length < structure length. * XXX - does this just mean some fields aren't * being supplied, or is it truly an error (i.e., * is the length supplied so that the header can * be expanded in the future)? */ nd_print_trunc(ndo); return (caplen); } if (caplen < hdrlen) { nd_print_trunc(ndo); return (caplen); } if (ndo->ndo_eflag) pktap_header_print(ndo, p, length); length -= hdrlen; caplen -= hdrlen; p += hdrlen; rectype = EXTRACT_LE_U_4(hdr->pkt_rectype); switch (rectype) { case PKT_REC_NONE: ND_PRINT("no data"); break; case PKT_REC_PACKET: if ((printer = lookup_printer(dlt)) != NULL) { nhdr = *h; nhdr.caplen = caplen; nhdr.len = length; hdrlen += printer(ndo, &nhdr, p); } else { if (!ndo->ndo_eflag) pktap_header_print(ndo, (const u_char *)hdr, length + hdrlen); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } break; } return (hdrlen); }
u_int pflog_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, register const u_char *p) { u_int length = h->len; u_int hdrlen; u_int caplen = h->caplen; const struct pfloghdr *hdr; uint8_t af; /* check length */ if (caplen < sizeof(uint8_t)) { ND_PRINT((ndo, "%s", tstr)); return (caplen); } #define MIN_PFLOG_HDRLEN 45 hdr = (const struct pfloghdr *)p; if (hdr->length < MIN_PFLOG_HDRLEN) { ND_PRINT((ndo, "[pflog: invalid header length!]")); return (hdr->length); /* XXX: not really */ } hdrlen = BPF_WORDALIGN(hdr->length); if (caplen < hdrlen) { ND_PRINT((ndo, "%s", tstr)); return (hdrlen); /* XXX: true? */ } /* print what we know */ ND_TCHECK(*hdr); if (ndo->ndo_eflag) pflog_print(ndo, hdr); /* skip to the real packet */ af = hdr->af; length -= hdrlen; caplen -= hdrlen; p += hdrlen; switch (af) { case AF_INET: #if OPENBSD_AF_INET != AF_INET case OPENBSD_AF_INET: /* XXX: read pcap files */ #endif ip_print(ndo, p, length); break; #if defined(AF_INET6) || defined(OPENBSD_AF_INET6) #ifdef AF_INET6 case AF_INET6: #endif /* AF_INET6 */ #if !defined(AF_INET6) || OPENBSD_AF_INET6 != AF_INET6 case OPENBSD_AF_INET6: /* XXX: read pcap files */ #endif /* !defined(AF_INET6) || OPENBSD_AF_INET6 != AF_INET6 */ ip6_print(ndo, p, length); break; #endif /* defined(AF_INET6) || defined(OPENBSD_AF_INET6) */ default: /* address family not handled, print raw packet */ if (!ndo->ndo_eflag) pflog_print(ndo, hdr); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } return (hdrlen); trunc: ND_PRINT((ndo, "%s", tstr)); return (hdrlen); }