/* * 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); } } }
/* * 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; int llc_hdrlen; u_int hdrlen; 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; hdrlen = 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. */ llc_hdrlen = llc_print(ndo, p, length, caplen, NULL, NULL); if (llc_hdrlen < 0) goto unknown; /* unknown LLC type */ hdrlen += llc_hdrlen; break; default: /*FALLTHROUGH*/ unknown: /* packet type not known, print raw packet */ 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) { ND_PRINT((ndo, "[|vlan]")); return (hdrlen + caplen); } if (length < 4) { ND_PRINT((ndo, "[|vlan]")); return (hdrlen + length); } 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 (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; hdrlen += 4; goto recurse; } else { if (ethertype_print(ndo, ether_type, p, length, caplen) == 0) { /* ether_type not known, print raw packet */ if (!ndo->ndo_eflag) sll_print(ndo, sllp, length + SLL_HDR_LEN); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } } return (hdrlen); }