static void print_attr_netmask6(netdissect_options *ndo, const u_char *data, u_int length, u_short attr_code _U_) { u_char data2[16]; if (length < 2 || length > 18) { ND_PRINT("ERROR: length %u not in range (2..18)", length); return; } ND_TCHECK_LEN(data, length); if (EXTRACT_U_1(data + 1) > 128) { ND_PRINT("ERROR: netmask %u not in range (0..128)", EXTRACT_U_1(data + 1)); return; } memset(data2, 0, sizeof(data2)); if (length > 2) memcpy(data2, data+2, length-2); ND_PRINT("%s/%u", ip6addr_string(ndo, data2), EXTRACT_U_1(data + 1)); if (EXTRACT_U_1(data + 1) > 8 * (length - 2)) ND_PRINT(" (inconsistent prefix length)"); return; trunc: nd_print_trunc(ndo); }
static inline void ipnet_hdr_print(netdissect_options *ndo, const u_char *bp, u_int length) { const ipnet_hdr_t *hdr; hdr = (const ipnet_hdr_t *)bp; ND_TCHECK_SIZE(hdr); ND_PRINT("%u > %u", EXTRACT_BE_U_4(hdr->iph_zsrc), EXTRACT_BE_U_4(hdr->iph_zdst)); if (!ndo->ndo_qflag) { ND_PRINT(", family %s (%u)", tok2str(ipnet_values, "Unknown", EXTRACT_U_1(hdr->iph_family)), EXTRACT_U_1(hdr->iph_family)); } else { ND_PRINT(", %s", tok2str(ipnet_values, "Unknown Ethertype (0x%04x)", EXTRACT_U_1(hdr->iph_family))); } ND_PRINT(", length %u: ", length); return; trunc: ND_PRINT(" %s", tstr); }
static void igrp_entry_print(netdissect_options *ndo, const struct igrprte *igr, int is_interior, int is_exterior) { u_int delay, bandwidth; u_int metric, mtu; if (is_interior) ND_PRINT(" *.%u.%u.%u", igr->igr_net[0], igr->igr_net[1], igr->igr_net[2]); else if (is_exterior) ND_PRINT(" X%u.%u.%u.0", igr->igr_net[0], igr->igr_net[1], igr->igr_net[2]); else ND_PRINT(" %u.%u.%u.0", igr->igr_net[0], igr->igr_net[1], igr->igr_net[2]); delay = EXTRACT_BE_U_3(igr->igr_dly); bandwidth = EXTRACT_BE_U_3(igr->igr_bw); metric = bandwidth + delay; if (metric > 0xffffff) metric = 0xffffff; mtu = EXTRACT_BE_U_2(igr->igr_mtu); ND_PRINT(" d=%u b=%u r=%u l=%u M=%u mtu=%u in %u hops", 10 * delay, bandwidth == 0 ? 0 : 10000000 / bandwidth, EXTRACT_U_1(igr->igr_rel), EXTRACT_U_1(igr->igr_ld), metric, mtu, EXTRACT_U_1(igr->igr_hct)); }
/* PPP I/F printer */ u_int ppp_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { u_int length = h->len; u_int caplen = h->caplen; if (caplen < PPP_HDRLEN) { ND_PRINT("[|ppp]"); return (caplen); } #if 0 /* * XXX: seems to assume that there are 2 octets prepended to an * actual PPP frame. The 1st octet looks like Input/Output flag * while 2nd octet is unknown, at least to me * ([email protected]). * * That was what the original tcpdump code did. * * FreeBSD's "if_ppp.c" *does* set the first octet to 1 for outbound * packets and 0 for inbound packets - but only if the * protocol field has the 0x8000 bit set (i.e., it's a network * control protocol); it does so before running the packet through * "bpf_filter" to see if it should be discarded, and to see * if we should update the time we sent the most recent packet... * * ...but it puts the original address field back after doing * so. * * NetBSD's "if_ppp.c" doesn't set the first octet in that fashion. * * I don't know if any PPP implementation handed up to a BPF * device packets with the first octet being 1 for outbound and * 0 for inbound packets, so I ([email protected]) don't know * whether that ever needs to be checked or not. * * Note that NetBSD has a DLT_PPP_SERIAL, which it uses for PPP, * and its tcpdump appears to assume that the frame always * begins with an address field and a control field, and that * the address field might be 0x0f or 0x8f, for Cisco * point-to-point with HDLC framing as per section 4.3.1 of RFC * 1547, as well as 0xff, for PPP in HDLC-like framing as per * RFC 1662. * * (Is the Cisco framing in question what DLT_C_HDLC, in * BSD/OS, is?) */ if (ndo->ndo_eflag) ND_PRINT("%c %4d %02x ", EXTRACT_U_1(p) ? 'O' : 'I', length, EXTRACT_U_1(p + 1)); #endif ppp_print(ndo, p, length); return (0); }
void timed_print(netdissect_options *ndo, const u_char *bp) { const struct tsp *tsp = (const struct tsp *)bp; uint8_t tsp_type; int sec, usec; ndo->ndo_protocol = "timed"; ND_TCHECK_1(tsp->tsp_type); tsp_type = EXTRACT_U_1(tsp->tsp_type); if (tsp_type < TSPTYPENUMBER) ND_PRINT("TSP_%s", tsptype[tsp_type]); else ND_PRINT("(tsp_type %#x)", tsp_type); ND_TCHECK_1(tsp->tsp_vers); ND_PRINT(" vers %u", EXTRACT_U_1(tsp->tsp_vers)); ND_TCHECK_2(tsp->tsp_seq); ND_PRINT(" seq %u", EXTRACT_BE_U_2(tsp->tsp_seq)); switch (tsp_type) { case TSP_LOOP: ND_TCHECK_1(tsp->tsp_hopcnt); ND_PRINT(" hopcnt %u", EXTRACT_U_1(tsp->tsp_hopcnt)); break; case TSP_SETTIME: case TSP_ADJTIME: case TSP_SETDATE: case TSP_SETDATEREQ: ND_TCHECK_8(&tsp->tsp_time); sec = EXTRACT_BE_S_4(tsp->tsp_time.tv_sec); usec = EXTRACT_BE_S_4(tsp->tsp_time.tv_usec); /* XXX The comparison below is always false? */ if (usec < 0) /* invalid, skip the rest of the packet */ return; ND_PRINT(" time "); if (sec < 0 && usec != 0) { sec++; if (sec == 0) ND_PRINT("-"); usec = 1000000 - usec; } ND_PRINT("%d.%06d", sec, usec); break; } ND_PRINT(" name "); if (nd_printzp(ndo, tsp->tsp_name, sizeof(tsp->tsp_name), ndo->ndo_snapend)) goto trunc; return; trunc: nd_print_trunc(ndo); }
/* IP6CP config options */ static u_int print_ip6cp_config_options(netdissect_options *ndo, const u_char *p, u_int length) { u_int opt, len; if (length < 2) return 0; ND_TCHECK_2(p); opt = EXTRACT_U_1(p); len = EXTRACT_U_1(p + 1); if (length < len) return 0; if (len < 2) { ND_PRINT("\n\t %s Option (0x%02x), length %u (length bogus, should be >= 2)", tok2str(ip6cpopt_values,"unknown",opt), opt, len); return 0; } ND_PRINT("\n\t %s Option (0x%02x), length %u", tok2str(ip6cpopt_values,"unknown",opt), opt, len); switch (opt) { case IP6CP_IFID: if (len != 10) { ND_PRINT(" (length bogus, should be = 10)"); return len; } ND_TCHECK_8(p + 2); ND_PRINT(": %04x:%04x:%04x:%04x", EXTRACT_BE_U_2(p + 2), EXTRACT_BE_U_2(p + 4), EXTRACT_BE_U_2(p + 6), EXTRACT_BE_U_2(p + 8)); break; default: /* * Unknown option; dump it as raw bytes now if we're * not going to do so below. */ if (ndo->ndo_vflag < 2) print_unknown_data(ndo, p + 2, "\n\t ", len - 2); break; } if (ndo->ndo_vflag > 1) print_unknown_data(ndo, p + 2, "\n\t ", len - 2); /* exclude TLV header */ return len; trunc: ND_PRINT("[|ip6cp]"); return 0; }
/* * print vendor specific attributes */ static void print_vendor_attr(netdissect_options *ndo, const u_char *data, u_int length, u_short attr_code _U_) { u_int idx; u_int vendor_id; u_int vendor_type; u_int vendor_length; if (length < 4) goto trunc; ND_TCHECK_4(data); vendor_id = EXTRACT_BE_U_4(data); data+=4; length-=4; ND_PRINT("Vendor: %s (%u)", tok2str(smi_values,"Unknown",vendor_id), vendor_id); while (length >= 2) { ND_TCHECK_2(data); vendor_type = EXTRACT_U_1(data); vendor_length = EXTRACT_U_1(data + 1); if (vendor_length < 2) { ND_PRINT("\n\t Vendor Attribute: %u, Length: %u (bogus, must be >= 2)", vendor_type, vendor_length); return; } if (vendor_length > length) { ND_PRINT("\n\t Vendor Attribute: %u, Length: %u (bogus, goes past end of vendor-specific attribute)", vendor_type, vendor_length); return; } data+=2; vendor_length-=2; length-=2; ND_TCHECK_LEN(data, vendor_length); ND_PRINT("\n\t Vendor Attribute: %u, Length: %u, Value: ", vendor_type, vendor_length); for (idx = 0; idx < vendor_length ; idx++, data++) ND_PRINT("%c", ND_ISPRINT(EXTRACT_U_1(data)) ? EXTRACT_U_1(data) : '.'); length-=vendor_length; } return; trunc: nd_print_trunc(ndo); }
static void pptp_err_code_print(netdissect_options *ndo, const nd_uint8_t *err_code) { ND_PRINT(" ERR_CODE(%u", EXTRACT_U_1(*err_code)); if (ndo->ndo_vflag) { ND_PRINT(":%s", tok2str(pptp_errcode_str, "?", EXTRACT_U_1(*err_code))); } ND_PRINT(")"); }
/* BACP config options */ static u_int print_bacp_config_options(netdissect_options *ndo, const u_char *p, u_int length) { u_int opt, len; if (length < 2) return 0; ND_TCHECK_2(p); opt = EXTRACT_U_1(p); len = EXTRACT_U_1(p + 1); if (length < len) return 0; if (len < 2) { ND_PRINT("\n\t %s Option (0x%02x), length %u (length bogus, should be >= 2)", tok2str(bacconfopts_values, "Unknown", opt), opt, len); return 0; } ND_PRINT("\n\t %s Option (0x%02x), length %u", tok2str(bacconfopts_values, "Unknown", opt), opt, len); switch (opt) { case BACPOPT_FPEER: if (len != 6) { ND_PRINT(" (length bogus, should be = 6)"); return len; } ND_TCHECK_4(p + 2); ND_PRINT(": Magic-Num 0x%08x", EXTRACT_BE_U_4(p + 2)); break; default: /* * Unknown option; dump it as raw bytes now if we're * not going to do so below. */ if (ndo->ndo_vflag < 2) print_unknown_data(ndo, p + 2, "\n\t ", len - 2); break; } if (ndo->ndo_vflag > 1) print_unknown_data(ndo, p + 2, "\n\t ", len - 2); /* exclude TLV header */ return len; trunc: ND_PRINT("[|bacp]"); return 0; }
/* Print a single OpenFlow message. */ static const u_char * of_header_body_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) { uint8_t version, type; uint16_t length; uint32_t xid; if (ep < cp + OF_HEADER_LEN) goto invalid; /* version */ ND_TCHECK_1(cp); version = EXTRACT_U_1(cp); cp += 1; /* type */ ND_TCHECK_1(cp); type = EXTRACT_U_1(cp); cp += 1; /* length */ ND_TCHECK_2(cp); length = EXTRACT_BE_U_2(cp); cp += 2; /* xid */ ND_TCHECK_4(cp); xid = EXTRACT_BE_U_4(cp); cp += 4; /* Message length includes the header length and a message always includes * the basic header. A message length underrun fails decoding of the rest of * the current packet. At the same time, try decoding as much of the current * message as possible even when it does not end within the current TCP * segment. */ if (length < OF_HEADER_LEN) { of_header_print(ndo, version, type, length, xid); goto invalid; } /* Decode known protocol versions further without printing the header (the * type decoding is version-specific. */ switch (version) { case OF_VER_1_0: return of10_header_body_print(ndo, cp, ep, type, length, xid); default: of_header_print(ndo, version, type, length, xid); ND_TCHECK_LEN(cp, length - OF_HEADER_LEN); return cp + length - OF_HEADER_LEN; /* done with current message */ } invalid: /* fail current packet */ ND_PRINT("%s", istr); ND_TCHECK_LEN(cp, ep - cp); return ep; trunc: ND_PRINT("%s", tstr); return ep; }
void igrp_print(netdissect_options *ndo, const u_char *bp, u_int length) { const struct igrphdr *hdr; const u_char *cp; u_int nint, nsys, next; hdr = (const struct igrphdr *)bp; cp = (const u_char *)(hdr + 1); ND_PRINT("igrp:"); /* Header */ ND_TCHECK_SIZE(hdr); nint = EXTRACT_BE_U_2(hdr->ig_ni); nsys = EXTRACT_BE_U_2(hdr->ig_ns); next = EXTRACT_BE_U_2(hdr->ig_nx); ND_PRINT(" %s V%u edit=%u AS=%u (%u/%u/%u)", tok2str(op2str, "op-#%u", IGRP_OP(EXTRACT_U_1(hdr->ig_vop))), IGRP_V(EXTRACT_U_1(hdr->ig_vop)), EXTRACT_U_1(hdr->ig_ed), EXTRACT_BE_U_2(hdr->ig_as), nint, nsys, next); length -= sizeof(*hdr); while (length >= IGRP_RTE_SIZE) { if (nint > 0) { ND_TCHECK_LEN(cp, IGRP_RTE_SIZE); igrp_entry_print(ndo, (const struct igrprte *)cp, 1, 0); --nint; } else if (nsys > 0) { ND_TCHECK_LEN(cp, IGRP_RTE_SIZE); igrp_entry_print(ndo, (const struct igrprte *)cp, 0, 0); --nsys; } else if (next > 0) { ND_TCHECK_LEN(cp, IGRP_RTE_SIZE); igrp_entry_print(ndo, (const struct igrprte *)cp, 0, 1); --next; } else { ND_PRINT(" [extra bytes %u]", length); break; } cp += IGRP_RTE_SIZE; length -= IGRP_RTE_SIZE; } if (nint == 0 && nsys == 0 && next == 0) return; trunc: ND_PRINT(" [|igrp]"); }
static void cmu_print(netdissect_options *ndo, const u_char *bp) { const struct cmu_vend *cmu; uint8_t v_flags; ND_PRINT(" vend-cmu"); cmu = (const struct cmu_vend *)bp; /* Only print if there are unknown bits */ ND_TCHECK_4(cmu->v_flags); v_flags = EXTRACT_U_1(cmu->v_flags); if ((v_flags & ~(VF_SMASK)) != 0) ND_PRINT(" F:0x%x", v_flags); PRINTCMUADDR(v_dgate, "DG"); PRINTCMUADDR(v_smask, v_flags & VF_SMASK ? "SM" : "SM*"); PRINTCMUADDR(v_dns1, "NS1"); PRINTCMUADDR(v_dns2, "NS2"); PRINTCMUADDR(v_ins1, "IEN1"); PRINTCMUADDR(v_ins2, "IEN2"); PRINTCMUADDR(v_ts1, "TS1"); PRINTCMUADDR(v_ts2, "TS2"); return; trunc: nd_print_trunc(ndo); }
void vxlan_print(netdissect_options *ndo, const u_char *bp, u_int len) { uint8_t flags; uint32_t vni; ndo->ndo_protocol = "vxlan"; if (len < VXLAN_HDR_LEN) goto trunc; ND_TCHECK_LEN(bp, VXLAN_HDR_LEN); flags = EXTRACT_U_1(bp); bp += 4; vni = EXTRACT_BE_U_3(bp); bp += 4; ND_PRINT("VXLAN, "); ND_PRINT("flags [%s] (0x%02x), ", flags & 0x08 ? "I" : ".", flags); ND_PRINT("vni %u\n", vni); ether_print(ndo, bp, len - VXLAN_HDR_LEN, ndo->ndo_snapend - bp, NULL, NULL); return; trunc: nd_print_trunc(ndo); }
/* * Print EtherTalk/TokenTalk packets (or FDDITalk, or whatever it's called * when it runs over FDDI; yes, I've seen FDDI captures with AppleTalk * packets in them). */ void atalk_print(netdissect_options *ndo, const u_char *bp, u_int length) { const struct atDDP *dp; u_short snet; ndo->ndo_protocol = "atalk"; if(!ndo->ndo_eflag) ND_PRINT("AT "); if (length < ddpSize) { ND_PRINT(" [|ddp %u]", length); return; } if (!ND_TTEST_LEN(bp, ddpSize)) { ND_PRINT(" [|ddp]"); return; } dp = (const struct atDDP *)bp; snet = EXTRACT_BE_U_2(dp->srcNet); ND_PRINT("%s.%s", ataddr_string(ndo, snet, EXTRACT_U_1(dp->srcNode)), ddpskt_string(ndo, EXTRACT_U_1(dp->srcSkt))); ND_PRINT(" > %s.%s: ", ataddr_string(ndo, EXTRACT_BE_U_2(dp->dstNet), EXTRACT_U_1(dp->dstNode)), ddpskt_string(ndo, EXTRACT_U_1(dp->dstSkt))); bp += ddpSize; length -= ddpSize; ddp_print(ndo, bp, length, EXTRACT_U_1(dp->type), snet, EXTRACT_U_1(dp->srcNode), EXTRACT_U_1(dp->srcSkt)); }
/* * Print the TR MAC header */ static void token_hdr_print(netdissect_options *ndo, const struct token_header *trp, u_int length, const u_char *fsrc, const u_char *fdst) { const char *srcname, *dstname; srcname = etheraddr_string(ndo, fsrc); dstname = etheraddr_string(ndo, fdst); if (!ndo->ndo_qflag) ND_PRINT("%02x %02x ", EXTRACT_U_1(trp->token_ac), EXTRACT_U_1(trp->token_fc)); ND_PRINT("%s > %s, length %u: ", srcname, dstname, length); }
static void ahcp1_body_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) { uint8_t type, mbz; uint16_t body_len; if (cp + AHCP1_BODY_MIN_LEN > ep) goto invalid; /* Type */ ND_TCHECK_1(cp); type = EXTRACT_U_1(cp); cp += 1; /* MBZ */ ND_TCHECK_1(cp); mbz = EXTRACT_U_1(cp); cp += 1; /* Length */ ND_TCHECK_2(cp); body_len = EXTRACT_BE_U_2(cp); cp += 2; if (ndo->ndo_vflag) { ND_PRINT("\n\t%s", tok2str(ahcp1_msg_str, "Unknown-%u", type)); if (mbz != 0) ND_PRINT(", MBZ %u", mbz); ND_PRINT(", Length %u", body_len); } if (cp + body_len > ep) goto invalid; /* Options */ if (ndo->ndo_vflag >= 2) ahcp1_options_print(ndo, cp, cp + body_len); /* not ep (ignore extra data) */ else ND_TCHECK_LEN(cp, body_len); return; invalid: ND_PRINT("%s", istr); ND_TCHECK_LEN(cp, ep - cp); return; trunc: nd_print_trunc(ndo); }
static int stp_print_config_bpdu(netdissect_options *ndo, const struct stp_bpdu_ *stp_bpdu, u_int length) { uint8_t bpdu_flags; ND_TCHECK_1(stp_bpdu->flags); bpdu_flags = EXTRACT_U_1(stp_bpdu->flags); ND_PRINT(", Flags [%s]", bittok2str(stp_bpdu_flag_values, "none", bpdu_flags)); ND_TCHECK_2(stp_bpdu->port_id); ND_PRINT(", bridge-id %s.%04x, length %u", stp_print_bridge_id((const u_char *)&stp_bpdu->bridge_id), EXTRACT_BE_U_2(stp_bpdu->port_id), length); /* in non-verbose mode just print the bridge-id */ if (!ndo->ndo_vflag) { return 1; } ND_TCHECK_2(stp_bpdu->forward_delay); ND_PRINT("\n\tmessage-age %.2fs, max-age %.2fs" ", hello-time %.2fs, forwarding-delay %.2fs", (float) EXTRACT_BE_U_2(stp_bpdu->message_age) / STP_TIME_BASE, (float) EXTRACT_BE_U_2(stp_bpdu->max_age) / STP_TIME_BASE, (float) EXTRACT_BE_U_2(stp_bpdu->hello_time) / STP_TIME_BASE, (float) EXTRACT_BE_U_2(stp_bpdu->forward_delay) / STP_TIME_BASE); ND_PRINT("\n\troot-id %s, root-pathcost %u", stp_print_bridge_id((const u_char *)&stp_bpdu->root_id), EXTRACT_BE_U_4(stp_bpdu->root_path_cost)); /* Port role is only valid for 802.1w */ if (EXTRACT_U_1(stp_bpdu->protocol_version) == STP_PROTO_RAPID) { ND_PRINT(", port-role %s", tok2str(rstp_obj_port_role_values, "Unknown", RSTP_EXTRACT_PORT_ROLE(bpdu_flags))); } return 1; trunc: return 0; }
/* * Print NTP control message requests and responses */ static void ntp_control_print(netdissect_options *ndo, const struct ntp_control_data *cd, u_int length) { uint8_t control, R, E, M, opcode; uint16_t sequence, status, assoc, offset, count; if (length < NTP_CTRLMSG_MINLEN) goto invalid; ND_TCHECK_1(cd->control); control = EXTRACT_U_1(cd->control); R = (control & 0x80) != 0; E = (control & 0x40) != 0; M = (control & 0x20) != 0; opcode = control & 0x1f; ND_PRINT(", %s, %s, %s, OpCode=%u\n", R ? "Response" : "Request", E ? "Error" : "OK", M ? "More" : "Last", opcode); ND_TCHECK_2(cd->sequence); sequence = EXTRACT_BE_U_2(cd->sequence); ND_PRINT("\tSequence=%hu", sequence); ND_TCHECK_2(cd->status); status = EXTRACT_BE_U_2(cd->status); ND_PRINT(", Status=%#hx", status); ND_TCHECK_2(cd->assoc); assoc = EXTRACT_BE_U_2(cd->assoc); ND_PRINT(", Assoc.=%hu", assoc); ND_TCHECK_2(cd->offset); offset = EXTRACT_BE_U_2(cd->offset); ND_PRINT(", Offset=%hu", offset); ND_TCHECK_2(cd->count); count = EXTRACT_BE_U_2(cd->count); ND_PRINT(", Count=%hu", count); if (NTP_CTRLMSG_MINLEN + count > length) goto invalid; if (count != 0) { ND_TCHECK_LEN(cd->data, count); ND_PRINT("\n\tTO-BE-DONE: data not interpreted"); } return; invalid: nd_print_invalid(ndo); ND_TCHECK_LEN(cd, length); return; trunc: nd_print_trunc(ndo); }
static void pflog_print(netdissect_options *ndo, const struct pfloghdr *hdr) { uint32_t rulenr, subrulenr; ndo->ndo_protocol = "pflog"; rulenr = EXTRACT_BE_U_4(&hdr->rulenr); subrulenr = EXTRACT_BE_U_4(&hdr->subrulenr); if (subrulenr == (uint32_t)-1) ND_PRINT("rule %u/", rulenr); else ND_PRINT("rule %u.%s.%u/", rulenr, hdr->ruleset, subrulenr); ND_PRINT("%s: %s %s on %s: ", tok2str(pf_reasons, "unkn(%u)", EXTRACT_U_1(&hdr->reason)), tok2str(pf_actions, "unkn(%u)", EXTRACT_U_1(&hdr->action)), tok2str(pf_directions, "unkn(%u)", EXTRACT_U_1(&hdr->dir)), hdr->ifname); }
/* read in a <n>-byte number, MSB first * (of course this can handle max sizeof(int)) */ static unsigned int cdp_get_number(const u_char * p, u_int l) { unsigned int res=0; while( l>0 ) { res = (res<<8) + EXTRACT_U_1(p); p++; l--; } return res; }
static u_int dccp_csum_coverage(const struct dccp_hdr* dh, u_int len) { u_int cov; if (DCCPH_CSCOV(dh) == 0) return len; cov = (EXTRACT_U_1(dh->dccph_doff) + DCCPH_CSCOV(dh) - 1) * sizeof(uint32_t); return (cov > len)? len : cov; }
static void geneve_opts_print(netdissect_options *ndo, const u_char *bp, u_int len) { const char *sep = ""; while (len > 0) { uint16_t opt_class; uint8_t opt_type; uint8_t opt_len; ND_PRINT("%s", sep); sep = ", "; opt_class = EXTRACT_BE_U_2(bp); opt_type = EXTRACT_U_1(bp + 2); opt_len = 4 + ((EXTRACT_U_1(bp + 3) & OPT_LEN_MASK) * 4); ND_PRINT("class %s (0x%x) type 0x%x%s len %u", format_opt_class(opt_class), opt_class, opt_type, opt_type & OPT_TYPE_CRITICAL ? "(C)" : "", opt_len); if (opt_len > len) { ND_PRINT(" [bad length]"); return; } if (ndo->ndo_vflag > 1 && opt_len > 4) { const uint32_t *data = (const uint32_t *)(bp + 4); int i; ND_PRINT(" data"); for (i = 4; i < opt_len; i += 4) { ND_PRINT(" %08x", EXTRACT_BE_U_4(data)); data++; } } bp += opt_len; len -= opt_len; } }
static char * stp_print_bridge_id(const u_char *p) { static char bridge_id_str[sizeof("pppp.aa:bb:cc:dd:ee:ff")]; nd_snprintf(bridge_id_str, sizeof(bridge_id_str), "%.2x%.2x.%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", EXTRACT_U_1(p), EXTRACT_U_1(p + 1), EXTRACT_U_1(p + 2), EXTRACT_U_1(p + 3), EXTRACT_U_1(p + 4), EXTRACT_U_1(p + 5), EXTRACT_U_1(p + 6), EXTRACT_U_1(p + 7)); return bridge_id_str; }
/* XXX should probably pass in the snap header and do checks like arp_print() */ void aarp_print(netdissect_options *ndo, const u_char *bp, u_int length) { const struct aarp *ap; #define AT(member) ataddr_string(ndo, (ap->member[1]<<8)|ap->member[2],ap->member[3]) ndo->ndo_protocol = "aarp"; ND_PRINT("aarp "); ap = (const struct aarp *)bp; if (!ND_TTEST_SIZE(ap)) { /* Just bail if we don't have the whole chunk. */ nd_print_trunc(ndo); return; } if (length < sizeof(*ap)) { ND_PRINT(" [|aarp %u]", length); return; } if (EXTRACT_BE_U_2(ap->htype) == 1 && EXTRACT_BE_U_2(ap->ptype) == ETHERTYPE_ATALK && EXTRACT_U_1(ap->halen) == 6 && EXTRACT_U_1(ap->palen) == 4 ) switch (EXTRACT_BE_U_2(ap->op)) { case 1: /* request */ ND_PRINT("who-has %s tell %s", AT(pdaddr), AT(psaddr)); return; case 2: /* response */ ND_PRINT("reply %s is-at %s", AT(psaddr), etheraddr_string(ndo, ap->hsaddr)); return; case 3: /* probe (oy!) */ ND_PRINT("probe %s tell %s", AT(pdaddr), AT(psaddr)); return; } ND_PRINT("len %u op %u htype %u ptype %#x halen %u palen %u", length, EXTRACT_BE_U_2(ap->op), EXTRACT_BE_U_2(ap->htype), EXTRACT_BE_U_2(ap->ptype), EXTRACT_U_1(ap->halen), EXTRACT_U_1(ap->palen)); }
static void ahcp1_options_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) { uint8_t option_no, option_len; while (cp < ep) { /* Option no */ ND_TCHECK_1(cp); option_no = EXTRACT_U_1(cp); cp += 1; ND_PRINT("\n\t %s", tok2str(ahcp1_opt_str, "Unknown-%u", option_no)); if (option_no == AHCP1_OPT_PAD || option_no == AHCP1_OPT_MANDATORY) continue; /* Length */ if (cp + 1 > ep) goto invalid; ND_TCHECK_1(cp); option_len = EXTRACT_U_1(cp); cp += 1; if (cp + option_len > ep) goto invalid; /* Value */ if (option_no <= AHCP1_OPT_MAX && data_decoders[option_no] != NULL) { if (data_decoders[option_no](ndo, cp, cp + option_len) < 0) break; /* truncated and already marked up */ } else { ND_PRINT(" (Length %u)", option_len); ND_TCHECK_LEN(cp, option_len); } cp += option_len; } return; invalid: ND_PRINT("%s", istr); ND_TCHECK_LEN(cp, ep - cp); return; trunc: nd_print_trunc(ndo); }
/* * Print dhcp6 packets */ void dhcp6_print(netdissect_options *ndo, const u_char *cp, u_int length) { const struct dhcp6 *dh6; const struct dhcp6_relay *dh6relay; uint8_t msgtype; const u_char *ep; const u_char *extp; const char *name; ND_PRINT("dhcp6"); ep = ndo->ndo_snapend; if (cp + length < ep) ep = cp + length; dh6 = (const struct dhcp6 *)cp; dh6relay = (const struct dhcp6_relay *)cp; ND_TCHECK_4(dh6->dh6_msgtypexid.xid); msgtype = EXTRACT_U_1(dh6->dh6_msgtypexid.msgtype); name = tok2str(dh6_msgtype_str, "msgtype-%u", msgtype); if (!ndo->ndo_vflag) { ND_PRINT(" %s", name); return; } /* XXX relay agent messages have to be handled differently */ ND_PRINT(" %s (", name); /*)*/ if (msgtype != DH6_RELAY_FORW && msgtype != DH6_RELAY_REPLY) { ND_PRINT("xid=%x", EXTRACT_BE_U_4(dh6->dh6_msgtypexid.xid) & DH6_XIDMASK); extp = (const u_char *)(dh6 + 1); dhcp6opt_print(ndo, extp, ep); } else { /* relay messages */ ND_TCHECK_16(dh6relay->dh6relay_peeraddr); ND_PRINT("linkaddr=%s", ip6addr_string(ndo, dh6relay->dh6relay_linkaddr)); ND_PRINT(" peeraddr=%s", ip6addr_string(ndo, dh6relay->dh6relay_peeraddr)); dhcp6opt_print(ndo, (const u_char *)(dh6relay + 1), ep); } /*(*/ ND_PRINT(")"); return; trunc: ND_PRINT("[|dhcp6]"); }
static int cdp_print_prefixes(netdissect_options *ndo, const u_char * p, u_int l) { if (l % 5) goto trunc; ND_PRINT(" IPv4 Prefixes (%u):", l / 5); while (l > 0) { ND_PRINT(" %u.%u.%u.%u/%u", EXTRACT_U_1(p), EXTRACT_U_1(p + 1), EXTRACT_U_1(p + 2), EXTRACT_U_1(p + 3), EXTRACT_U_1(p + 4)); l -= 5; p += 5; } return 0; trunc: return -1; }
static int cfm_network_addr_print(netdissect_options *ndo, const u_char *tptr, const u_int length) { u_int network_addr_type; u_int hexdump = FALSE; /* * Although AFIs are typically 2 octects wide, * 802.1ab specifies that this field width * is only one octet. */ if (length < 1) { ND_PRINT("\n\t Network Address Type (invalid, no data"); return hexdump; } /* The calling function must make any due ND_TCHECK calls. */ network_addr_type = EXTRACT_U_1(tptr); ND_PRINT("\n\t Network Address Type %s (%u)", tok2str(af_values, "Unknown", network_addr_type), network_addr_type); /* * Resolve the passed in Address. */ switch(network_addr_type) { case AFNUM_INET: if (length != 1 + 4) { ND_PRINT("(invalid IPv4 address length %u)", length - 1); hexdump = TRUE; break; } ND_PRINT(", %s", ipaddr_string(ndo, tptr + 1)); break; case AFNUM_INET6: if (length != 1 + 16) { ND_PRINT("(invalid IPv6 address length %u)", length - 1); hexdump = TRUE; break; } ND_PRINT(", %s", ip6addr_string(ndo, tptr + 1)); break; default: hexdump = TRUE; break; } return hexdump; }
/* * Print RRCP requests */ void rrcp_print(netdissect_options *ndo, const u_char *cp, u_int length _U_, const struct lladdr_info *src, const struct lladdr_info *dst) { uint8_t rrcp_proto; uint8_t rrcp_opcode; ndo->ndo_protocol = "rrcp"; ND_TCHECK_1(cp + RRCP_PROTO_OFFSET); rrcp_proto = EXTRACT_U_1(cp + RRCP_PROTO_OFFSET); ND_TCHECK_1(cp + RRCP_OPCODE_ISREPLY_OFFSET); rrcp_opcode = EXTRACT_U_1((cp + RRCP_OPCODE_ISREPLY_OFFSET)) & RRCP_OPCODE_MASK; if (src != NULL && dst != NULL) { ND_PRINT("%s > %s, ", (src->addr_string)(ndo, src->addr), (dst->addr_string)(ndo, dst->addr)); } ND_PRINT("%s %s", tok2str(proto_values,"RRCP-0x%02x",rrcp_proto), ((EXTRACT_U_1(cp + RRCP_OPCODE_ISREPLY_OFFSET)) & RRCP_ISREPLY) ? "reply" : "query"); if (rrcp_proto==1){ ND_PRINT(": %s", tok2str(opcode_values,"unknown opcode (0x%02x)",rrcp_opcode)); } if (rrcp_opcode==1 || rrcp_opcode==2){ ND_TCHECK_6(cp + RRCP_REG_ADDR_OFFSET); ND_PRINT(" addr=0x%04x, data=0x%08x", EXTRACT_LE_U_2(cp + RRCP_REG_ADDR_OFFSET), EXTRACT_LE_U_4(cp + RRCP_REG_DATA_OFFSET)); } if (rrcp_proto==1){ ND_TCHECK_2(cp + RRCP_AUTHKEY_OFFSET); ND_PRINT(", auth=0x%04x", EXTRACT_BE_U_2(cp + RRCP_AUTHKEY_OFFSET)); } if (rrcp_proto==1 && rrcp_opcode==0 && ((EXTRACT_U_1(cp + RRCP_OPCODE_ISREPLY_OFFSET)) & RRCP_ISREPLY)){ ND_TCHECK_4(cp + RRCP_VENDOR_ID_OFFSET); ND_PRINT(" downlink_port=%u, uplink_port=%u, uplink_mac=%s, vendor_id=%08x ,chip_id=%04x ", EXTRACT_U_1(cp + RRCP_DOWNLINK_PORT_OFFSET), EXTRACT_U_1(cp + RRCP_UPLINK_PORT_OFFSET), etheraddr_string(ndo, cp + RRCP_UPLINK_MAC_OFFSET), EXTRACT_BE_U_4(cp + RRCP_VENDOR_ID_OFFSET), EXTRACT_BE_U_2(cp + RRCP_CHIP_ID_OFFSET)); }else if (rrcp_opcode==1 || rrcp_opcode==2 || rrcp_proto==2){ ND_TCHECK_4(cp + RRCP_COOKIE2_OFFSET); ND_PRINT(", cookie=0x%08x%08x ", EXTRACT_BE_U_4(cp + RRCP_COOKIE2_OFFSET), EXTRACT_BE_U_4(cp + RRCP_COOKIE1_OFFSET)); } return; trunc: nd_print_trunc(ndo); }
/* * 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); }