/* * 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 loopback_message_print(netdissect_options *ndo, const u_char *cp, const u_int len) { const u_char *ep = cp + len; uint16_t function; if (len < 2) goto invalid; /* function */ ND_TCHECK_2(cp); function = EXTRACT_LE_U_2(cp); cp += 2; ND_PRINT(", %s", tok2str(fcode_str, " invalid (%u)", function)); switch (function) { case LOOPBACK_REPLY: if (len < 4) goto invalid; /* receipt number */ ND_TCHECK_2(cp); ND_PRINT(", receipt number %u", EXTRACT_LE_U_2(cp)); cp += 2; /* data */ ND_PRINT(", data (%u octets)", len - 4); ND_TCHECK_LEN(cp, len - 4); break; case LOOPBACK_FWDDATA: if (len < 8) goto invalid; /* forwarding address */ ND_TCHECK_LEN(cp, MAC_ADDR_LEN); ND_PRINT(", forwarding address %s", etheraddr_string(ndo, cp)); cp += MAC_ADDR_LEN; /* data */ ND_PRINT(", data (%u octets)", len - 8); ND_TCHECK_LEN(cp, len - 8); break; default: ND_TCHECK_LEN(cp, len - 2); break; } return; invalid: ND_PRINT("%s", istr); ND_TCHECK_LEN(cp, ep - cp); return; trunc: ND_PRINT("%s", tstr); }
void loopback_print(netdissect_options *ndo, const u_char *cp, const u_int len) { const u_char *ep = cp + len; uint16_t skipCount; ND_PRINT("Loopback"); if (len < 2) goto invalid; /* skipCount */ ND_TCHECK_2(cp); skipCount = EXTRACT_LE_U_2(cp); cp += 2; ND_PRINT(", skipCount %u", skipCount); if (skipCount % 8) ND_PRINT(" (bogus)"); if (skipCount > len - 2) goto invalid; loopback_message_print(ndo, cp + skipCount, len - 2 - skipCount); return; invalid: ND_PRINT("%s", istr); ND_TCHECK_LEN(cp, ep - cp); return; trunc: ND_PRINT("%s", tstr); }
void gre_print(netdissect_options *ndo, const u_char *bp, u_int length) { u_int len = length, vers; ND_TCHECK_2(bp); if (len < 2) goto trunc; vers = EXTRACT_BE_U_2(bp) & GRE_VERS_MASK; ND_PRINT("GREv%u",vers); switch(vers) { case 0: gre_print_0(ndo, bp, len); break; case 1: gre_print_1(ndo, bp, len); break; default: ND_PRINT(" ERROR: unknown-version"); break; } return; trunc: ND_PRINT("%s", tstr); return; }
/* * 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); }
/* * 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); }
/* 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; }
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); }
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; }
/* 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; }
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 lwres_printaddr(netdissect_options *ndo, const u_char *p0) { const u_char *p; const lwres_addr_t *ap; uint16_t l; int i; p = p0; ap = (const lwres_addr_t *)p; ND_TCHECK_2(ap->length); l = EXTRACT_BE_U_2(ap->length); p += LWRES_ADDR_LEN; ND_TCHECK_LEN(p, l); switch (EXTRACT_BE_U_4(ap->family)) { case 1: /* IPv4 */ if (l < 4) return -1; ND_PRINT(" %s", ipaddr_string(ndo, p)); p += sizeof(nd_ipv4); break; case 2: /* IPv6 */ if (l < 16) return -1; ND_PRINT(" %s", ip6addr_string(ndo, p)); p += sizeof(nd_ipv6); break; default: ND_PRINT(" %u/", EXTRACT_BE_U_4(ap->family)); for (i = 0; i < l; i++) { ND_PRINT("%02x", EXTRACT_U_1(p)); p++; } } return p - p0; trunc: return -1; }
static void slow_oam_print(netdissect_options *ndo, const u_char *tptr, u_int tlen) { uint8_t code; uint8_t type, length; uint8_t state; uint8_t command; u_int hexdump; struct slow_oam_common_header_t { nd_uint16_t flags; nd_uint8_t code; }; struct slow_oam_tlv_header_t { nd_uint8_t type; nd_uint8_t length; }; union { const struct slow_oam_common_header_t *slow_oam_common_header; const struct slow_oam_tlv_header_t *slow_oam_tlv_header; } ptr; union { const struct slow_oam_info_t *slow_oam_info; const struct slow_oam_link_event_t *slow_oam_link_event; const struct slow_oam_variablerequest_t *slow_oam_variablerequest; const struct slow_oam_variableresponse_t *slow_oam_variableresponse; const struct slow_oam_loopbackctrl_t *slow_oam_loopbackctrl; } tlv; ptr.slow_oam_common_header = (const struct slow_oam_common_header_t *)tptr; if (tlen < sizeof(*ptr.slow_oam_common_header)) goto tooshort; ND_TCHECK_SIZE(ptr.slow_oam_common_header); tptr += sizeof(struct slow_oam_common_header_t); tlen -= sizeof(struct slow_oam_common_header_t); code = EXTRACT_U_1(ptr.slow_oam_common_header->code); ND_PRINT("\n\tCode %s OAM PDU, Flags [%s]", tok2str(slow_oam_code_values, "Unknown (%u)", code), bittok2str(slow_oam_flag_values, "none", EXTRACT_BE_U_2(ptr.slow_oam_common_header->flags))); switch (code) { case SLOW_OAM_CODE_INFO: while (tlen > 0) { ptr.slow_oam_tlv_header = (const struct slow_oam_tlv_header_t *)tptr; if (tlen < sizeof(*ptr.slow_oam_tlv_header)) goto tooshort; ND_TCHECK_SIZE(ptr.slow_oam_tlv_header); type = EXTRACT_U_1(ptr.slow_oam_tlv_header->type); length = EXTRACT_U_1(ptr.slow_oam_tlv_header->length); ND_PRINT("\n\t %s Information Type (%u), length %u", tok2str(slow_oam_info_type_values, "Reserved", type), type, length); if (type == SLOW_OAM_INFO_TYPE_END_OF_TLV) { /* * As IEEE Std 802.3-2015 says for the End of TLV Marker, * "(the length and value of the Type 0x00 TLV can be ignored)". */ return; } /* length includes the type and length fields */ if (length < sizeof(struct slow_oam_tlv_header_t)) { ND_PRINT("\n\t ERROR: illegal length - should be >= %u", (u_int)sizeof(struct slow_oam_tlv_header_t)); return; } if (tlen < length) goto tooshort; ND_TCHECK_LEN(tptr, length); hexdump = FALSE; switch (type) { case SLOW_OAM_INFO_TYPE_LOCAL: /* identical format - fall through */ case SLOW_OAM_INFO_TYPE_REMOTE: tlv.slow_oam_info = (const struct slow_oam_info_t *)tptr; if (EXTRACT_U_1(tlv.slow_oam_info->info_length) != sizeof(struct slow_oam_info_t)) { ND_PRINT("\n\t ERROR: illegal length - should be %lu", (unsigned long) sizeof(struct slow_oam_info_t)); hexdump = TRUE; goto badlength_code_info; } ND_PRINT("\n\t OAM-Version %u, Revision %u", EXTRACT_U_1(tlv.slow_oam_info->oam_version), EXTRACT_BE_U_2(tlv.slow_oam_info->revision)); state = EXTRACT_U_1(tlv.slow_oam_info->state); ND_PRINT("\n\t State-Parser-Action %s, State-MUX-Action %s", tok2str(slow_oam_info_type_state_parser_values, "Reserved", state & OAM_INFO_TYPE_PARSER_MASK), tok2str(slow_oam_info_type_state_mux_values, "Reserved", state & OAM_INFO_TYPE_MUX_MASK)); ND_PRINT("\n\t OAM-Config Flags [%s], OAM-PDU-Config max-PDU size %u", bittok2str(slow_oam_info_type_oam_config_values, "none", EXTRACT_U_1(tlv.slow_oam_info->oam_config)), EXTRACT_BE_U_2(tlv.slow_oam_info->oam_pdu_config) & OAM_INFO_TYPE_PDU_SIZE_MASK); ND_PRINT("\n\t OUI %s (0x%06x), Vendor-Private 0x%08x", tok2str(oui_values, "Unknown", EXTRACT_BE_U_3(tlv.slow_oam_info->oui)), EXTRACT_BE_U_3(tlv.slow_oam_info->oui), EXTRACT_BE_U_4(tlv.slow_oam_info->vendor_private)); break; case SLOW_OAM_INFO_TYPE_ORG_SPECIFIC: hexdump = TRUE; break; default: hexdump = TRUE; break; } badlength_code_info: /* do we also want to see a hex dump ? */ if (ndo->ndo_vflag > 1 || hexdump==TRUE) { print_unknown_data(ndo, tptr, "\n\t ", length); } tlen -= length; tptr += length; } break; case SLOW_OAM_CODE_EVENT_NOTIF: /* Sequence number */ if (tlen < 2) goto tooshort; ND_TCHECK_2(tptr); ND_PRINT("\n\t Sequence Number %u", EXTRACT_BE_U_2(tptr)); tlen -= 2; tptr += 2; /* TLVs */ while (tlen > 0) { ptr.slow_oam_tlv_header = (const struct slow_oam_tlv_header_t *)tptr; if (tlen < sizeof(*ptr.slow_oam_tlv_header)) goto tooshort; ND_TCHECK_SIZE(ptr.slow_oam_tlv_header); type = EXTRACT_U_1(ptr.slow_oam_tlv_header->type); length = EXTRACT_U_1(ptr.slow_oam_tlv_header->length); ND_PRINT("\n\t %s Link Event Type (%u), length %u", tok2str(slow_oam_link_event_values, "Reserved", type), type, length); if (type == SLOW_OAM_INFO_TYPE_END_OF_TLV) { /* * As IEEE Std 802.3-2015 says for the End of TLV Marker, * "(the length and value of the Type 0x00 TLV can be ignored)". */ return; } /* length includes the type and length fields */ if (length < sizeof(struct slow_oam_tlv_header_t)) { ND_PRINT("\n\t ERROR: illegal length - should be >= %u", (u_int)sizeof(struct slow_oam_tlv_header_t)); return; } if (tlen < length) goto tooshort; ND_TCHECK_LEN(tptr, length); hexdump = FALSE; switch (type) { case SLOW_OAM_LINK_EVENT_ERR_SYM_PER: /* identical format - fall through */ case SLOW_OAM_LINK_EVENT_ERR_FRM: case SLOW_OAM_LINK_EVENT_ERR_FRM_PER: case SLOW_OAM_LINK_EVENT_ERR_FRM_SUMM: tlv.slow_oam_link_event = (const struct slow_oam_link_event_t *)tptr; if (EXTRACT_U_1(tlv.slow_oam_link_event->event_length) != sizeof(struct slow_oam_link_event_t)) { ND_PRINT("\n\t ERROR: illegal length - should be %lu", (unsigned long) sizeof(struct slow_oam_link_event_t)); hexdump = TRUE; goto badlength_event_notif; } ND_PRINT("\n\t Timestamp %u ms, Errored Window %" PRIu64 "\n\t Errored Threshold %" PRIu64 "\n\t Errors %" PRIu64 "\n\t Error Running Total %" PRIu64 "\n\t Event Running Total %u", EXTRACT_BE_U_2(tlv.slow_oam_link_event->time_stamp)*100, EXTRACT_BE_U_8(tlv.slow_oam_link_event->window), EXTRACT_BE_U_8(tlv.slow_oam_link_event->threshold), EXTRACT_BE_U_8(tlv.slow_oam_link_event->errors), EXTRACT_BE_U_8(tlv.slow_oam_link_event->errors_running_total), EXTRACT_BE_U_4(tlv.slow_oam_link_event->event_running_total)); break; case SLOW_OAM_LINK_EVENT_ORG_SPECIFIC: hexdump = TRUE; break; default: hexdump = TRUE; break; } badlength_event_notif: /* do we also want to see a hex dump ? */ if (ndo->ndo_vflag > 1 || hexdump==TRUE) { print_unknown_data(ndo, tptr, "\n\t ", length); } tlen -= length; tptr += length; } break; case SLOW_OAM_CODE_LOOPBACK_CTRL: tlv.slow_oam_loopbackctrl = (const struct slow_oam_loopbackctrl_t *)tptr; if (tlen < sizeof(*tlv.slow_oam_loopbackctrl)) goto tooshort; ND_TCHECK_SIZE(tlv.slow_oam_loopbackctrl); command = EXTRACT_U_1(tlv.slow_oam_loopbackctrl->command); ND_PRINT("\n\t Command %s (%u)", tok2str(slow_oam_loopbackctrl_cmd_values, "Unknown", command), command); tptr ++; tlen --; break; /* * FIXME those are the defined codes that lack a decoder * you are welcome to contribute code ;-) */ case SLOW_OAM_CODE_VAR_REQUEST: case SLOW_OAM_CODE_VAR_RESPONSE: case SLOW_OAM_CODE_PRIVATE: default: if (ndo->ndo_vflag <= 1) { print_unknown_data(ndo, tptr, "\n\t ", tlen); } break; } return; tooshort: ND_PRINT("\n\t\t packet is too short"); return; trunc: ND_PRINT("%s", tstr); }
u_int chdlc_print(netdissect_options *ndo, const u_char *p, u_int length) { u_int proto; const u_char *bp = p; if (length < CHDLC_HDRLEN) goto trunc; ND_TCHECK_LEN(p, CHDLC_HDRLEN); proto = EXTRACT_BE_U_2(p + 2); if (ndo->ndo_eflag) { ND_PRINT("%s, ethertype %s (0x%04x), length %u: ", tok2str(chdlc_cast_values, "0x%02x", EXTRACT_U_1(p)), tok2str(ethertype_values, "Unknown", proto), proto, length); } length -= CHDLC_HDRLEN; p += CHDLC_HDRLEN; switch (proto) { case ETHERTYPE_IP: ip_print(ndo, p, length); break; case ETHERTYPE_IPV6: ip6_print(ndo, p, length); break; case CHDLC_TYPE_SLARP: chdlc_slarp_print(ndo, p, length); break; #if 0 case CHDLC_TYPE_CDP: chdlc_cdp_print(p, length); break; #endif case ETHERTYPE_MPLS: case ETHERTYPE_MPLS_MULTI: mpls_print(ndo, p, length); break; case ETHERTYPE_ISO: /* is the fudge byte set ? lets verify by spotting ISO headers */ if (length < 2) goto trunc; ND_TCHECK_2(p); if (EXTRACT_U_1(p + 1) == NLPID_CLNP || EXTRACT_U_1(p + 1) == NLPID_ESIS || EXTRACT_U_1(p + 1) == NLPID_ISIS) isoclns_print(ndo, p + 1, length - 1); else isoclns_print(ndo, p, length); break; default: if (!ndo->ndo_eflag) ND_PRINT("unknown CHDLC protocol (0x%04x)", proto); break; } return (CHDLC_HDRLEN); trunc: ND_PRINT("[|chdlc]"); return ndo->ndo_snapend - bp; }
/* Standard PPP printer */ u_int ppp_print(netdissect_options *ndo, const u_char *p, u_int length) { u_int proto,ppp_header; u_int olen = length; /* _o_riginal length */ u_int hdr_len = 0; /* * Here, we assume that p points to the Address and Control * field (if they present). */ if (length < 2) goto trunc; ND_TCHECK_2(p); ppp_header = EXTRACT_BE_U_2(p); switch(ppp_header) { case (PPP_WITHDIRECTION_IN << 8 | PPP_CONTROL): if (ndo->ndo_eflag) ND_PRINT("In "); p += 2; length -= 2; hdr_len += 2; break; case (PPP_WITHDIRECTION_OUT << 8 | PPP_CONTROL): if (ndo->ndo_eflag) ND_PRINT("Out "); p += 2; length -= 2; hdr_len += 2; break; case (PPP_ADDRESS << 8 | PPP_CONTROL): p += 2; /* ACFC not used */ length -= 2; hdr_len += 2; break; default: break; } if (length < 2) goto trunc; ND_TCHECK_1(p); if (EXTRACT_U_1(p) % 2) { proto = EXTRACT_U_1(p); /* PFC is used */ p++; length--; hdr_len++; } else { ND_TCHECK_2(p); proto = EXTRACT_BE_U_2(p); p += 2; length -= 2; hdr_len += 2; } if (ndo->ndo_eflag) ND_PRINT("%s (0x%04x), length %u: ", tok2str(ppptype2str, "unknown", proto), proto, olen); handle_ppp(ndo, proto, p, length); return (hdr_len); trunc: ND_PRINT("[|ppp]"); return (0); }
/* PAP (see RFC 1334) */ static void handle_pap(netdissect_options *ndo, const u_char *p, u_int length) { u_int code, len; u_int peerid_len, passwd_len, msg_len; const u_char *p0; u_int i; p0 = p; if (length < 1) { ND_PRINT("[|pap]"); return; } else if (length < 4) { ND_TCHECK_1(p); ND_PRINT("[|pap 0x%02x]", EXTRACT_U_1(p)); return; } ND_TCHECK_1(p); code = EXTRACT_U_1(p); ND_PRINT("PAP, %s (0x%02x)", tok2str(papcode_values, "unknown", code), code); p++; ND_TCHECK_1(p); ND_PRINT(", id %u", EXTRACT_U_1(p)); /* ID */ p++; ND_TCHECK_2(p); len = EXTRACT_BE_U_2(p); p += 2; if (len > length) { ND_PRINT(", length %u > packet size", len); return; } length = len; if (length < (size_t)(p - p0)) { ND_PRINT(", length %u < PAP header length", length); return; } switch (code) { case PAP_AREQ: /* A valid Authenticate-Request is 6 or more octets long. */ if (len < 6) goto trunc; if (length - (p - p0) < 1) return; ND_TCHECK_1(p); peerid_len = EXTRACT_U_1(p); /* Peer-ID Length */ p++; if (length - (p - p0) < peerid_len) return; ND_PRINT(", Peer "); for (i = 0; i < peerid_len; i++) { ND_TCHECK_1(p); safeputchar(ndo, EXTRACT_U_1(p)); p++; } if (length - (p - p0) < 1) return; ND_TCHECK_1(p); passwd_len = EXTRACT_U_1(p); /* Password Length */ p++; if (length - (p - p0) < passwd_len) return; ND_PRINT(", Name "); for (i = 0; i < passwd_len; i++) { ND_TCHECK_1(p); safeputchar(ndo, EXTRACT_U_1(p)); p++; } break; case PAP_AACK: case PAP_ANAK: /* Although some implementations ignore truncation at * this point and at least one generates a truncated * packet, RFC 1334 section 2.2.2 clearly states that * both AACK and ANAK are at least 5 bytes long. */ if (len < 5) goto trunc; if (length - (p - p0) < 1) return; ND_TCHECK_1(p); msg_len = EXTRACT_U_1(p); /* Msg-Length */ p++; if (length - (p - p0) < msg_len) return; ND_PRINT(", Msg "); for (i = 0; i< msg_len; i++) { ND_TCHECK_1(p); safeputchar(ndo, EXTRACT_U_1(p)); p++; } break; } return; trunc: ND_PRINT("[|pap]"); }
/* generic Control Protocol (e.g. LCP, IPCP, CCP, etc.) handler */ static void handle_ctrl_proto(netdissect_options *ndo, u_int proto, const u_char *pptr, u_int length) { const char *typestr; u_int code, len; u_int (*pfunc)(netdissect_options *, const u_char *, u_int); u_int x, j; const u_char *tptr; tptr=pptr; typestr = tok2str(ppptype2str, "unknown ctrl-proto (0x%04x)", proto); ND_PRINT("%s, ", typestr); if (length < 4) /* FIXME weak boundary checking */ goto trunc; ND_TCHECK_2(tptr); code = EXTRACT_U_1(tptr); tptr++; ND_PRINT("%s (0x%02x), id %u, length %u", tok2str(cpcodes, "Unknown Opcode",code), code, EXTRACT_U_1(tptr), /* ID */ length + 2); tptr++; if (!ndo->ndo_vflag) return; ND_TCHECK_2(tptr); len = EXTRACT_BE_U_2(tptr); tptr += 2; if (len < 4) { ND_PRINT("\n\tencoded length %u (< 4))", len); return; } if (len > length) { ND_PRINT("\n\tencoded length %u (> packet length %u))", len, length); return; } length = len; ND_PRINT("\n\tencoded length %u (=Option(s) length %u)", len, len - 4); if (length == 4) return; /* there may be a NULL confreq etc. */ if (ndo->ndo_vflag > 1) print_unknown_data(ndo, pptr - 2, "\n\t", 6); switch (code) { case CPCODES_VEXT: if (length < 11) break; ND_TCHECK_4(tptr); ND_PRINT("\n\t Magic-Num 0x%08x", EXTRACT_BE_U_4(tptr)); tptr += 4; ND_TCHECK_3(tptr); ND_PRINT(" Vendor: %s (%u)", tok2str(oui_values,"Unknown",EXTRACT_BE_U_3(tptr)), EXTRACT_BE_U_3(tptr)); /* XXX: need to decode Kind and Value(s)? */ break; case CPCODES_CONF_REQ: case CPCODES_CONF_ACK: case CPCODES_CONF_NAK: case CPCODES_CONF_REJ: x = len - 4; /* Code(1), Identifier(1) and Length(2) */ do { switch (proto) { case PPP_LCP: pfunc = print_lcp_config_options; break; case PPP_IPCP: pfunc = print_ipcp_config_options; break; case PPP_IPV6CP: pfunc = print_ip6cp_config_options; break; case PPP_CCP: pfunc = print_ccp_config_options; break; case PPP_BACP: pfunc = print_bacp_config_options; break; default: /* * No print routine for the options for * this protocol. */ pfunc = NULL; break; } if (pfunc == NULL) /* catch the above null pointer if unknown CP */ break; if ((j = (*pfunc)(ndo, tptr, len)) == 0) break; x -= j; tptr += j; } while (x != 0); break; case CPCODES_TERM_REQ: case CPCODES_TERM_ACK: /* XXX: need to decode Data? */ break; case CPCODES_CODE_REJ: /* XXX: need to decode Rejected-Packet? */ break; case CPCODES_PROT_REJ: if (length < 6) break; ND_TCHECK_2(tptr); ND_PRINT("\n\t Rejected %s Protocol (0x%04x)", tok2str(ppptype2str,"unknown", EXTRACT_BE_U_2(tptr)), EXTRACT_BE_U_2(tptr)); /* XXX: need to decode Rejected-Information? - hexdump for now */ if (len > 6) { ND_PRINT("\n\t Rejected Packet"); print_unknown_data(ndo, tptr + 2, "\n\t ", len - 2); } break; case CPCODES_ECHO_REQ: case CPCODES_ECHO_RPL: case CPCODES_DISC_REQ: if (length < 8) break; ND_TCHECK_4(tptr); ND_PRINT("\n\t Magic-Num 0x%08x", EXTRACT_BE_U_4(tptr)); /* XXX: need to decode Data? - hexdump for now */ if (len > 8) { ND_PRINT("\n\t -----trailing data-----"); ND_TCHECK_LEN(tptr + 4, len - 8); print_unknown_data(ndo, tptr + 4, "\n\t ", len - 8); } break; case CPCODES_ID: if (length < 8) break; ND_TCHECK_4(tptr); ND_PRINT("\n\t Magic-Num 0x%08x", EXTRACT_BE_U_4(tptr)); /* RFC 1661 says this is intended to be human readable */ if (len > 8) { ND_PRINT("\n\t Message\n\t "); if (fn_printn(ndo, tptr + 4, len - 4, ndo->ndo_snapend)) goto trunc; } break; case CPCODES_TIME_REM: if (length < 12) break; ND_TCHECK_4(tptr); ND_PRINT("\n\t Magic-Num 0x%08x", EXTRACT_BE_U_4(tptr)); ND_TCHECK_4(tptr + 4); ND_PRINT(", Seconds-Remaining %us", EXTRACT_BE_U_4(tptr + 4)); /* XXX: need to decode Message? */ break; default: /* XXX this is dirty but we do not get the * original pointer passed to the begin * the PPP packet */ if (ndo->ndo_vflag <= 1) print_unknown_data(ndo, pptr - 2, "\n\t ", length + 2); break; } return; trunc: ND_PRINT("[|%s]", typestr); }
/* CHAP */ static void handle_chap(netdissect_options *ndo, const u_char *p, u_int length) { u_int code, len; u_int val_size, name_size, msg_size; const u_char *p0; u_int i; p0 = p; if (length < 1) { ND_PRINT("[|chap]"); return; } else if (length < 4) { ND_TCHECK_1(p); ND_PRINT("[|chap 0x%02x]", EXTRACT_U_1(p)); return; } ND_TCHECK_1(p); code = EXTRACT_U_1(p); ND_PRINT("CHAP, %s (0x%02x)", tok2str(chapcode_values,"unknown",code), code); p++; ND_TCHECK_1(p); ND_PRINT(", id %u", EXTRACT_U_1(p)); /* ID */ p++; ND_TCHECK_2(p); len = EXTRACT_BE_U_2(p); p += 2; /* * Note that this is a generic CHAP decoding routine. Since we * don't know which flavor of CHAP (i.e. CHAP-MD5, MS-CHAPv1, * MS-CHAPv2) is used at this point, we can't decode packet * specifically to each algorithms. Instead, we simply decode * the GCD (Gratest Common Denominator) for all algorithms. */ switch (code) { case CHAP_CHAL: case CHAP_RESP: if (length - (p - p0) < 1) return; ND_TCHECK_1(p); val_size = EXTRACT_U_1(p); /* value size */ p++; if (length - (p - p0) < val_size) return; ND_PRINT(", Value "); for (i = 0; i < val_size; i++) { ND_TCHECK_1(p); ND_PRINT("%02x", EXTRACT_U_1(p)); p++; } name_size = len - (p - p0); ND_PRINT(", Name "); for (i = 0; i < name_size; i++) { ND_TCHECK_1(p); safeputchar(ndo, EXTRACT_U_1(p)); p++; } break; case CHAP_SUCC: case CHAP_FAIL: msg_size = len - (p - p0); ND_PRINT(", Msg "); for (i = 0; i< msg_size; i++) { ND_TCHECK_1(p); safeputchar(ndo, EXTRACT_U_1(p)); p++; } break; } return; trunc: ND_PRINT("[|chap]"); }
/* CCP config options */ static u_int print_ccp_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(ccpconfopts_values, "Unknown", opt), opt, len); return 0; } ND_PRINT("\n\t %s Option (0x%02x), length %u", tok2str(ccpconfopts_values, "Unknown", opt), opt, len); switch (opt) { case CCPOPT_BSDCOMP: if (len < 3) { ND_PRINT(" (length bogus, should be >= 3)"); return len; } ND_TCHECK_1(p + 2); ND_PRINT(": Version: %u, Dictionary Bits: %u", EXTRACT_U_1(p + 2) >> 5, EXTRACT_U_1(p + 2) & 0x1f); break; case CCPOPT_MVRCA: if (len < 4) { ND_PRINT(" (length bogus, should be >= 4)"); return len; } ND_TCHECK_1(p + 3); ND_PRINT(": Features: %u, PxP: %s, History: %u, #CTX-ID: %u", (EXTRACT_U_1(p + 2) & 0xc0) >> 6, (EXTRACT_U_1(p + 2) & 0x20) ? "Enabled" : "Disabled", EXTRACT_U_1(p + 2) & 0x1f, EXTRACT_U_1(p + 3)); break; case CCPOPT_DEFLATE: if (len < 4) { ND_PRINT(" (length bogus, should be >= 4)"); return len; } ND_TCHECK_1(p + 3); ND_PRINT(": Window: %uK, Method: %s (0x%x), MBZ: %u, CHK: %u", (EXTRACT_U_1(p + 2) & 0xf0) >> 4, ((EXTRACT_U_1(p + 2) & 0x0f) == 8) ? "zlib" : "unknown", EXTRACT_U_1(p + 2) & 0x0f, (EXTRACT_U_1(p + 3) & 0xfc) >> 2, EXTRACT_U_1(p + 3) & 0x03); break; /* XXX: to be supported */ #if 0 case CCPOPT_OUI: case CCPOPT_PRED1: case CCPOPT_PRED2: case CCPOPT_PJUMP: case CCPOPT_HPPPC: case CCPOPT_STACLZS: case CCPOPT_MPPC: case CCPOPT_GFZA: case CCPOPT_V42BIS: case CCPOPT_LZSDCP: case CCPOPT_DEC: case CCPOPT_RESV: break; #endif 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("[|ccp]"); return 0; }
static int stp_print_mstp_bpdu(netdissect_options *ndo, const struct stp_bpdu_ *stp_bpdu, u_int length) { const u_char *ptr; uint8_t bpdu_flags; uint16_t v3len; uint16_t len; uint16_t msti; u_int offset; ptr = (const u_char *)stp_bpdu; ND_TCHECK_1(stp_bpdu->flags); bpdu_flags = EXTRACT_U_1(stp_bpdu->flags); ND_PRINT(", CIST Flags [%s], length %u", bittok2str(stp_bpdu_flag_values, "none", bpdu_flags), length); /* * in non-verbose mode just print the flags. */ if (!ndo->ndo_vflag) { return 1; } ND_PRINT("\n\tport-role %s, ", tok2str(rstp_obj_port_role_values, "Unknown", RSTP_EXTRACT_PORT_ROLE(bpdu_flags))); ND_TCHECK_4(stp_bpdu->root_path_cost); ND_PRINT("CIST root-id %s, CIST ext-pathcost %u", stp_print_bridge_id((const u_char *)&stp_bpdu->root_id), EXTRACT_BE_U_4(stp_bpdu->root_path_cost)); ND_TCHECK_SIZE(&stp_bpdu->bridge_id); ND_PRINT("\n\tCIST regional-root-id %s, ", stp_print_bridge_id((const u_char *)&stp_bpdu->bridge_id)); ND_TCHECK_2(stp_bpdu->port_id); ND_PRINT("CIST port-id %04x,", EXTRACT_BE_U_2(stp_bpdu->port_id)); 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_TCHECK_2(ptr + MST_BPDU_VER3_LEN_OFFSET); ND_PRINT("\n\tv3len %u, ", EXTRACT_BE_U_2(ptr + MST_BPDU_VER3_LEN_OFFSET)); ND_TCHECK_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 12); ND_PRINT("MCID Name "); if (fn_printzp(ndo, ptr + MST_BPDU_CONFIG_NAME_OFFSET, 32, ndo->ndo_snapend)) goto trunc; ND_PRINT(", rev %u," "\n\t\tdigest %08x%08x%08x%08x, ", EXTRACT_BE_U_2(ptr + MST_BPDU_CONFIG_NAME_OFFSET + 32), EXTRACT_BE_U_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET), EXTRACT_BE_U_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 4), EXTRACT_BE_U_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 8), EXTRACT_BE_U_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 12)); ND_TCHECK_4(ptr + MST_BPDU_CIST_INT_PATH_COST_OFFSET); ND_PRINT("CIST int-root-pathcost %u,", EXTRACT_BE_U_4(ptr + MST_BPDU_CIST_INT_PATH_COST_OFFSET)); ND_TCHECK_BRIDGE_ID(ptr + MST_BPDU_CIST_BRIDGE_ID_OFFSET); ND_PRINT("\n\tCIST bridge-id %s, ", stp_print_bridge_id(ptr + MST_BPDU_CIST_BRIDGE_ID_OFFSET)); ND_TCHECK_1(ptr + MST_BPDU_CIST_REMAIN_HOPS_OFFSET); ND_PRINT("CIST remaining-hops %u", EXTRACT_U_1(ptr + MST_BPDU_CIST_REMAIN_HOPS_OFFSET)); /* Dump all MSTI's */ ND_TCHECK_2(ptr + MST_BPDU_VER3_LEN_OFFSET); v3len = EXTRACT_BE_U_2(ptr + MST_BPDU_VER3_LEN_OFFSET); if (v3len > MST_BPDU_CONFIG_INFO_LENGTH) { len = v3len - MST_BPDU_CONFIG_INFO_LENGTH; offset = MST_BPDU_MSTI_OFFSET; while (len >= MST_BPDU_MSTI_LENGTH) { ND_TCHECK_LEN(ptr + offset, MST_BPDU_MSTI_LENGTH); msti = EXTRACT_BE_U_2(ptr + offset + MST_BPDU_MSTI_ROOT_PRIO_OFFSET); msti = msti & 0x0FFF; ND_PRINT("\n\tMSTI %u, Flags [%s], port-role %s", msti, bittok2str(stp_bpdu_flag_values, "none", EXTRACT_U_1(ptr + offset)), tok2str(rstp_obj_port_role_values, "Unknown", RSTP_EXTRACT_PORT_ROLE(EXTRACT_U_1(ptr + offset)))); ND_PRINT("\n\t\tMSTI regional-root-id %s, pathcost %u", stp_print_bridge_id(ptr + offset + MST_BPDU_MSTI_ROOT_PRIO_OFFSET), EXTRACT_BE_U_4(ptr + offset + MST_BPDU_MSTI_ROOT_PATH_COST_OFFSET)); ND_PRINT("\n\t\tMSTI bridge-prio %u, port-prio %u, hops %u", EXTRACT_U_1(ptr + offset + MST_BPDU_MSTI_BRIDGE_PRIO_OFFSET) >> 4, EXTRACT_U_1(ptr + offset + MST_BPDU_MSTI_PORT_PRIO_OFFSET) >> 4, EXTRACT_U_1(ptr + offset + MST_BPDU_MSTI_REMAIN_HOPS_OFFSET)); len -= MST_BPDU_MSTI_LENGTH; offset += MST_BPDU_MSTI_LENGTH; } }
static int cdp_print_addr(netdissect_options *ndo, const u_char * p, u_int l) { u_int pt, pl, al, num; const u_char *endp = p + l; static const u_char prot_ipv6[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x86, 0xdd }; ND_TCHECK_4(p); if (p + 4 > endp) goto trunc; num = EXTRACT_BE_U_4(p); p += 4; while (p < endp && num != 0) { ND_TCHECK_2(p); if (p + 2 > endp) goto trunc; pt = EXTRACT_U_1(p); /* type of "protocol" field */ pl = EXTRACT_U_1(p + 1); /* length of "protocol" field */ p += 2; ND_TCHECK_2(p + pl); if (p + pl + 2 > endp) goto trunc; al = EXTRACT_BE_U_2(p + pl); /* address length */ if (pt == PT_NLPID && pl == 1 && EXTRACT_U_1(p) == NLPID_IP && al == 4) { /* * IPv4: protocol type = NLPID, protocol length = 1 * (1-byte NLPID), protocol = 0xcc (NLPID for IPv4), * address length = 4 */ p += 3; ND_TCHECK_4(p); if (p + 4 > endp) goto trunc; ND_PRINT("IPv4 (%u) %s", num, ipaddr_string(ndo, p)); p += 4; } else if (pt == PT_IEEE_802_2 && pl == 8 && memcmp(p, prot_ipv6, 8) == 0 && al == 16) { /* * IPv6: protocol type = IEEE 802.2 header, * protocol length = 8 (size of LLC+SNAP header), * protocol = LLC+SNAP header with the IPv6 * Ethertype, address length = 16 */ p += 10; ND_TCHECK_LEN(p, al); if (p + al > endp) goto trunc; ND_PRINT("IPv6 (%u) %s", num, ip6addr_string(ndo, p)); p += al; } else { /* * Generic case: just print raw data */ ND_TCHECK_LEN(p, pl); if (p + pl > endp) goto trunc; ND_PRINT("pt=0x%02x, pl=%u, pb=", EXTRACT_U_1((p - 2)), pl); while (pl-- > 0) { ND_PRINT(" %02x", EXTRACT_U_1(p)); p++; } ND_TCHECK_2(p); if (p + 2 > endp) goto trunc; ND_PRINT(", al=%u, a=", al); p += 2; ND_TCHECK_LEN(p, al); if (p + al > endp) goto trunc; while (al-- > 0) { ND_PRINT(" %02x", EXTRACT_U_1(p)); p++; } } num--; if (num) ND_PRINT(" "); } return 0; trunc: return -1; }
void vtp_print(netdissect_options *ndo, const u_char *pptr, u_int length) { u_int type, len, name_len, tlv_len, tlv_value, mgmtd_len; const u_char *tptr; const struct vtp_vlan_ *vtp_vlan; ndo->ndo_protocol = "vtp"; if (length < VTP_HEADER_LEN) goto trunc; tptr = pptr; ND_TCHECK_LEN(tptr, VTP_HEADER_LEN); type = EXTRACT_U_1(tptr + 1); ND_PRINT("VTPv%u, Message %s (0x%02x), length %u", EXTRACT_U_1(tptr), tok2str(vtp_message_type_values,"Unknown message type", type), type, length); /* In non-verbose mode, just print version and message type */ if (ndo->ndo_vflag < 1) { return; } /* verbose mode print all fields */ ND_PRINT("\n\tDomain name: "); mgmtd_len = EXTRACT_U_1(tptr + 3); if (mgmtd_len < 1 || mgmtd_len > 32) { ND_PRINT(" [invalid MgmtD Len %u]", mgmtd_len); return; } nd_printzp(ndo, tptr + 4, mgmtd_len, NULL); ND_PRINT(", %s: %u", tok2str(vtp_header_values, "Unknown", type), EXTRACT_U_1(tptr + 2)); tptr += VTP_HEADER_LEN; switch (type) { case VTP_SUMMARY_ADV: /* * SUMMARY ADVERTISEMENT * * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Version | Code | Followers | MgmtD Len | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Management Domain Name (zero-padded to 32 bytes) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Configuration revision number | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Updater Identity IP address | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Update Timestamp (12 bytes) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | MD5 digest (16 bytes) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */ ND_TCHECK_8(tptr); ND_PRINT("\n\t Config Rev %x, Updater %s", EXTRACT_BE_U_4(tptr), ipaddr_string(ndo, tptr+4)); tptr += 8; ND_TCHECK_LEN(tptr, VTP_UPDATE_TIMESTAMP_LEN); ND_PRINT(", Timestamp 0x%08x 0x%08x 0x%08x", EXTRACT_BE_U_4(tptr), EXTRACT_BE_U_4(tptr + 4), EXTRACT_BE_U_4(tptr + 8)); tptr += VTP_UPDATE_TIMESTAMP_LEN; ND_TCHECK_LEN(tptr, VTP_MD5_DIGEST_LEN); ND_PRINT(", MD5 digest: %08x%08x%08x%08x", EXTRACT_BE_U_4(tptr), EXTRACT_BE_U_4(tptr + 4), EXTRACT_BE_U_4(tptr + 8), EXTRACT_BE_U_4(tptr + 12)); tptr += VTP_MD5_DIGEST_LEN; break; case VTP_SUBSET_ADV: /* * SUBSET ADVERTISEMENT * * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Version | Code | Seq number | MgmtD Len | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Management Domain Name (zero-padded to 32 bytes) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Configuration revision number | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | VLAN info field 1 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ................ | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | VLAN info field N | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */ ND_TCHECK_4(tptr); ND_PRINT(", Config Rev %x", EXTRACT_BE_U_4(tptr)); /* * VLAN INFORMATION * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | V info len | Status | VLAN type | VLAN name len | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ISL vlan id | MTU size | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | 802.10 index (SAID) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | VLAN name | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */ tptr += 4; while (tptr < (pptr+length)) { ND_TCHECK_1(tptr); len = EXTRACT_U_1(tptr); if (len == 0) break; ND_TCHECK_LEN(tptr, len); vtp_vlan = (const struct vtp_vlan_*)tptr; if (len < VTP_VLAN_INFO_FIXED_PART_LEN) goto trunc; ND_TCHECK_SIZE(vtp_vlan); ND_PRINT("\n\tVLAN info status %s, type %s, VLAN-id %u, MTU %u, SAID 0x%08x, Name ", tok2str(vtp_vlan_status,"Unknown",EXTRACT_U_1(vtp_vlan->status)), tok2str(vtp_vlan_type_values,"Unknown",EXTRACT_U_1(vtp_vlan->type)), EXTRACT_BE_U_2(vtp_vlan->vlanid), EXTRACT_BE_U_2(vtp_vlan->mtu), EXTRACT_BE_U_4(vtp_vlan->index)); len -= VTP_VLAN_INFO_FIXED_PART_LEN; tptr += VTP_VLAN_INFO_FIXED_PART_LEN; name_len = EXTRACT_U_1(vtp_vlan->name_len); if (len < 4*((name_len + 3)/4)) goto trunc; ND_TCHECK_LEN(tptr, name_len); nd_printzp(ndo, tptr, name_len, NULL); /* * Vlan names are aligned to 32-bit boundaries. */ len -= 4*((name_len + 3)/4); tptr += 4*((name_len + 3)/4); /* TLV information follows */ while (len > 0) { /* * Cisco specs say 2 bytes for type + 2 bytes for length; * see http://docstore.mik.ua/univercd/cc/td/doc/product/lan/trsrb/frames.htm * However, actual packets on the wire appear to use 1 * byte for the type and 1 byte for the length, so that's * what we do. */ if (len < 2) goto trunc; ND_TCHECK_2(tptr); type = EXTRACT_U_1(tptr); tlv_len = EXTRACT_U_1(tptr + 1); ND_PRINT("\n\t\t%s (0x%04x) TLV", tok2str(vtp_vlan_tlv_values, "Unknown", type), type); if (len < tlv_len * 2 + 2) { ND_PRINT(" (TLV goes past the end of the packet)"); return; } ND_TCHECK_LEN(tptr, tlv_len * 2 + 2); /* * We assume the value is a 2-byte integer; the length is * in units of 16-bit words. */ if (tlv_len != 1) { ND_PRINT(" (invalid TLV length %u != 1)", tlv_len); return; } else { tlv_value = EXTRACT_BE_U_2(tptr + 2); switch (type) { case VTP_VLAN_STE_HOP_COUNT: ND_PRINT(", %u", tlv_value); break; case VTP_VLAN_PRUNING: ND_PRINT(", %s (%u)", tlv_value == 1 ? "Enabled" : "Disabled", tlv_value); break; case VTP_VLAN_STP_TYPE: ND_PRINT(", %s (%u)", tok2str(vtp_stp_type_values, "Unknown", tlv_value), tlv_value); break; case VTP_VLAN_BRIDGE_TYPE: ND_PRINT(", %s (%u)", tlv_value == 1 ? "SRB" : "SRT", tlv_value); break; case VTP_VLAN_BACKUP_CRF_MODE: ND_PRINT(", %s (%u)", tlv_value == 1 ? "Backup" : "Not backup", tlv_value); break; /* * FIXME those are the defined TLVs that lack a decoder * you are welcome to contribute code ;-) */ case VTP_VLAN_SOURCE_ROUTING_RING_NUMBER: case VTP_VLAN_SOURCE_ROUTING_BRIDGE_NUMBER: case VTP_VLAN_PARENT_VLAN: case VTP_VLAN_TRANS_BRIDGED_VLAN: case VTP_VLAN_ARP_HOP_COUNT: default: print_unknown_data(ndo, tptr, "\n\t\t ", 2 + tlv_len*2); break; } } len -= 2 + tlv_len*2; tptr += 2 + tlv_len*2; } } break; case VTP_ADV_REQUEST: /* * ADVERTISEMENT REQUEST * * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Version | Code | Reserved | MgmtD Len | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Management Domain Name (zero-padded to 32 bytes) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Start value | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */ ND_TCHECK_4(tptr); ND_PRINT("\n\tStart value: %u", EXTRACT_BE_U_4(tptr)); break; case VTP_JOIN_MESSAGE: /* FIXME - Could not find message format */ break; default: break; } return; trunc: nd_print_trunc(ndo); }
static void rfc1048_print(netdissect_options *ndo, const u_char *bp) { uint16_t tag; u_int len; const char *cp; char c; int first, idx; uint8_t subopt, suboptlen; ND_PRINT("\n\t Vendor-rfc1048 Extensions"); /* Step over magic cookie */ ND_PRINT("\n\t Magic Cookie 0x%08x", EXTRACT_BE_U_4(bp)); bp += sizeof(int32_t); /* Loop while we there is a tag left in the buffer */ while (ND_TTEST_1(bp)) { tag = EXTRACT_U_1(bp); bp++; if (tag == TAG_PAD && ndo->ndo_vflag < 3) continue; if (tag == TAG_END && ndo->ndo_vflag < 3) return; if (tag == TAG_EXTENDED_OPTION) { ND_TCHECK_2(bp + 1); tag = EXTRACT_BE_U_2(bp + 1); /* XXX we don't know yet if the IANA will * preclude overlap of 1-byte and 2-byte spaces. * If not, we need to offset tag after this step. */ cp = tok2str(xtag2str, "?xT%u", tag); } else cp = tok2str(tag2str, "?T%u", tag); c = *cp++; if (tag == TAG_PAD || tag == TAG_END) len = 0; else { /* Get the length; check for truncation */ ND_TCHECK_1(bp); len = EXTRACT_U_1(bp); bp++; } ND_PRINT("\n\t %s Option %u, length %u%s", cp, tag, len, len > 0 ? ": " : ""); if (tag == TAG_PAD && ndo->ndo_vflag > 2) { u_int ntag = 1; while (ND_TTEST_1(bp) && EXTRACT_U_1(bp) == TAG_PAD) { bp++; ntag++; } if (ntag > 1) ND_PRINT(", occurs %u", ntag); } ND_TCHECK_LEN(bp, len); if (tag == TAG_DHCP_MESSAGE && len == 1) { ND_PRINT("%s", tok2str(dhcp_msg_values, "Unknown (%u)", EXTRACT_U_1(bp))); bp++; continue; } if (tag == TAG_PARM_REQUEST) { idx = 0; while (len > 0) { cp = tok2str(tag2str, "?Option %u", EXTRACT_U_1(bp)); bp++; len--; if (idx % 4 == 0) ND_PRINT("\n\t "); else ND_PRINT(", "); ND_PRINT("%s", cp + 1); idx++; } continue; } if (tag == TAG_EXTENDED_REQUEST) { first = 1; while (len > 1) { cp = tok2str(xtag2str, "?xT%u", EXTRACT_BE_U_2(bp)); bp += 2; len -= 2; if (!first) ND_PRINT("+"); ND_PRINT("%s", cp + 1); first = 0; } continue; } /* Print data */ if (c == '?') { /* Base default formats for unknown tags on data size */ if (len & 1) c = 'b'; else if (len & 2) c = 's'; else c = 'l'; } first = 1; switch (c) { case 'a': /* ASCII strings */ ND_PRINT("\""); if (nd_printn(ndo, bp, len, ndo->ndo_snapend)) { ND_PRINT("\""); goto trunc; } ND_PRINT("\""); bp += len; len = 0; break; case 'i': case 'l': case 'L': /* ip addresses/32-bit words */ while (len >= 4) { if (!first) ND_PRINT(","); if (c == 'i') ND_PRINT("%s", ipaddr_string(ndo, bp)); else if (c == 'L') ND_PRINT("%d", EXTRACT_BE_S_4(bp)); else ND_PRINT("%u", EXTRACT_BE_U_4(bp)); bp += 4; len -= 4; first = 0; } break; case 'p': /* IP address pairs */ while (len >= 2*4) { if (!first) ND_PRINT(","); ND_PRINT("(%s:", ipaddr_string(ndo, bp)); bp += 4; len -= 4; ND_PRINT("%s)", ipaddr_string(ndo, bp)); bp += 4; len -= 4; first = 0; } break; case 's': /* shorts */ while (len >= 2) { if (!first) ND_PRINT(","); ND_PRINT("%u", EXTRACT_BE_U_2(bp)); bp += 2; len -= 2; first = 0; } break; case 'B': /* boolean */ while (len > 0) { uint8_t bool_value; if (!first) ND_PRINT(","); bool_value = EXTRACT_U_1(bp); switch (bool_value) { case 0: ND_PRINT("N"); break; case 1: ND_PRINT("Y"); break; default: ND_PRINT("%u?", bool_value); break; } ++bp; --len; first = 0; } break; case 'b': case 'x': default: /* Bytes */ while (len > 0) { uint8_t byte_value; if (!first) ND_PRINT(c == 'x' ? ":" : "."); byte_value = EXTRACT_U_1(bp); if (c == 'x') ND_PRINT("%02x", byte_value); else ND_PRINT("%u", byte_value); ++bp; --len; first = 0; } break; case '$': /* Guys we can't handle with one of the usual cases */ switch (tag) { case TAG_NETBIOS_NODE: /* this option should be at least 1 byte long */ if (len < 1) { ND_PRINT("ERROR: length < 1 bytes"); break; } tag = EXTRACT_U_1(bp); ++bp; --len; ND_PRINT("%s", tok2str(nbo2str, NULL, tag)); break; case TAG_OPT_OVERLOAD: /* this option should be at least 1 byte long */ if (len < 1) { ND_PRINT("ERROR: length < 1 bytes"); break; } tag = EXTRACT_U_1(bp); ++bp; --len; ND_PRINT("%s", tok2str(oo2str, NULL, tag)); break; case TAG_CLIENT_FQDN: /* this option should be at least 3 bytes long */ if (len < 3) { ND_PRINT("ERROR: length < 3 bytes"); bp += len; len = 0; break; } if (EXTRACT_U_1(bp)) ND_PRINT("[%s] ", client_fqdn_flags(EXTRACT_U_1(bp))); bp++; if (EXTRACT_U_1(bp) || EXTRACT_U_1(bp + 1)) ND_PRINT("%u/%u ", EXTRACT_U_1(bp), EXTRACT_U_1(bp + 1)); bp += 2; ND_PRINT("\""); if (nd_printn(ndo, bp, len - 3, ndo->ndo_snapend)) { ND_PRINT("\""); goto trunc; } ND_PRINT("\""); bp += len - 3; len = 0; break; case TAG_CLIENT_ID: { int type; /* this option should be at least 1 byte long */ if (len < 1) { ND_PRINT("ERROR: length < 1 bytes"); break; } type = EXTRACT_U_1(bp); bp++; len--; if (type == 0) { ND_PRINT("\""); if (nd_printn(ndo, bp, len, ndo->ndo_snapend)) { ND_PRINT("\""); goto trunc; } ND_PRINT("\""); bp += len; len = 0; break; } else { ND_PRINT("%s ", tok2str(arp2str, "hardware-type %u,", type)); while (len > 0) { if (!first) ND_PRINT(":"); ND_PRINT("%02x", EXTRACT_U_1(bp)); ++bp; --len; first = 0; } } break; } case TAG_AGENT_CIRCUIT: while (len >= 2) { subopt = EXTRACT_U_1(bp); suboptlen = EXTRACT_U_1(bp + 1); bp += 2; len -= 2; if (suboptlen > len) { ND_PRINT("\n\t %s SubOption %u, length %u: length goes past end of option", tok2str(agent_suboption_values, "Unknown", subopt), subopt, suboptlen); bp += len; len = 0; break; } ND_PRINT("\n\t %s SubOption %u, length %u: ", tok2str(agent_suboption_values, "Unknown", subopt), subopt, suboptlen); switch (subopt) { case AGENT_SUBOPTION_CIRCUIT_ID: /* fall through */ case AGENT_SUBOPTION_REMOTE_ID: case AGENT_SUBOPTION_SUBSCRIBER_ID: if (nd_printn(ndo, bp, suboptlen, ndo->ndo_snapend)) goto trunc; break; default: print_unknown_data(ndo, bp, "\n\t\t", suboptlen); } len -= suboptlen; bp += suboptlen; } break; case TAG_CLASSLESS_STATIC_RT: case TAG_CLASSLESS_STA_RT_MS: { u_int mask_width, significant_octets, i; /* this option should be at least 5 bytes long */ if (len < 5) { ND_PRINT("ERROR: length < 5 bytes"); bp += len; len = 0; break; } while (len > 0) { if (!first) ND_PRINT(","); mask_width = EXTRACT_U_1(bp); bp++; len--; /* mask_width <= 32 */ if (mask_width > 32) { ND_PRINT("[ERROR: Mask width (%u) > 32]", mask_width); bp += len; len = 0; break; } significant_octets = (mask_width + 7) / 8; /* significant octets + router(4) */ if (len < significant_octets + 4) { ND_PRINT("[ERROR: Remaining length (%u) < %u bytes]", len, significant_octets + 4); bp += len; len = 0; break; } ND_PRINT("("); if (mask_width == 0) ND_PRINT("default"); else { for (i = 0; i < significant_octets ; i++) { if (i > 0) ND_PRINT("."); ND_PRINT("%u", EXTRACT_U_1(bp)); bp++; } for (i = significant_octets ; i < 4 ; i++) ND_PRINT(".0"); ND_PRINT("/%u", mask_width); } ND_PRINT(":%s)", ipaddr_string(ndo, bp)); bp += 4; len -= (significant_octets + 4); first = 0; } break; } case TAG_USER_CLASS: { u_int suboptnumber = 1; first = 1; if (len < 2) { ND_PRINT("ERROR: length < 2 bytes"); bp += len; len = 0; break; } while (len > 0) { suboptlen = EXTRACT_U_1(bp); bp++; len--; ND_PRINT("\n\t "); ND_PRINT("instance#%u: ", suboptnumber); if (suboptlen == 0) { ND_PRINT("ERROR: suboption length must be non-zero"); bp += len; len = 0; break; } if (len < suboptlen) { ND_PRINT("ERROR: invalid option"); bp += len; len = 0; break; } ND_PRINT("\""); if (nd_printn(ndo, bp, suboptlen, ndo->ndo_snapend)) { ND_PRINT("\""); goto trunc; } ND_PRINT("\""); ND_PRINT(", length %u", suboptlen); suboptnumber++; len -= suboptlen; bp += suboptlen; } break; } default: ND_PRINT("[unknown special tag %u, size %u]", tag, len); bp += len; len = 0; break; } break; } /* Data left over? */ if (len) { ND_PRINT("\n\t trailing data length %u", len); bp += len; } } return; trunc: nd_print_trunc(ndo); }
/* * Print bootp requests */ void bootp_print(netdissect_options *ndo, const u_char *cp, u_int length) { const struct bootp *bp; static const u_char vm_cmu[4] = VM_CMU; static const u_char vm_rfc1048[4] = VM_RFC1048; uint8_t bp_op, bp_htype, bp_hlen; ndo->ndo_protocol = "bootp"; bp = (const struct bootp *)cp; ND_TCHECK_1(bp->bp_op); bp_op = EXTRACT_U_1(bp->bp_op); ND_PRINT("BOOTP/DHCP, %s", tok2str(bootp_op_values, "unknown (0x%02x)", bp_op)); ND_TCHECK_1(bp->bp_hlen); bp_htype = EXTRACT_U_1(bp->bp_htype); bp_hlen = EXTRACT_U_1(bp->bp_hlen); if (bp_htype == 1 && bp_hlen == 6 && bp_op == BOOTPREQUEST) { ND_TCHECK_6(bp->bp_chaddr); ND_PRINT(" from %s", etheraddr_string(ndo, bp->bp_chaddr)); } ND_PRINT(", length %u", length); if (!ndo->ndo_vflag) return; ND_TCHECK_2(bp->bp_secs); /* The usual hardware address type is 1 (10Mb Ethernet) */ if (bp_htype != 1) ND_PRINT(", htype %u", bp_htype); /* The usual length for 10Mb Ethernet address is 6 bytes */ if (bp_htype != 1 || bp_hlen != 6) ND_PRINT(", hlen %u", bp_hlen); /* Only print interesting fields */ if (EXTRACT_U_1(bp->bp_hops)) ND_PRINT(", hops %u", EXTRACT_U_1(bp->bp_hops)); if (EXTRACT_BE_U_4(bp->bp_xid)) ND_PRINT(", xid 0x%x", EXTRACT_BE_U_4(bp->bp_xid)); if (EXTRACT_BE_U_2(bp->bp_secs)) ND_PRINT(", secs %u", EXTRACT_BE_U_2(bp->bp_secs)); ND_TCHECK_2(bp->bp_flags); ND_PRINT(", Flags [%s]", bittok2str(bootp_flag_values, "none", EXTRACT_BE_U_2(bp->bp_flags))); if (ndo->ndo_vflag > 1) ND_PRINT(" (0x%04x)", EXTRACT_BE_U_2(bp->bp_flags)); /* Client's ip address */ ND_TCHECK_4(bp->bp_ciaddr); if (EXTRACT_IPV4_TO_NETWORK_ORDER(bp->bp_ciaddr)) ND_PRINT("\n\t Client-IP %s", ipaddr_string(ndo, bp->bp_ciaddr)); /* 'your' ip address (bootp client) */ ND_TCHECK_4(bp->bp_yiaddr); if (EXTRACT_IPV4_TO_NETWORK_ORDER(bp->bp_yiaddr)) ND_PRINT("\n\t Your-IP %s", ipaddr_string(ndo, bp->bp_yiaddr)); /* Server's ip address */ ND_TCHECK_4(bp->bp_siaddr); if (EXTRACT_IPV4_TO_NETWORK_ORDER(bp->bp_siaddr)) ND_PRINT("\n\t Server-IP %s", ipaddr_string(ndo, bp->bp_siaddr)); /* Gateway's ip address */ ND_TCHECK_4(bp->bp_giaddr); if (EXTRACT_IPV4_TO_NETWORK_ORDER(bp->bp_giaddr)) ND_PRINT("\n\t Gateway-IP %s", ipaddr_string(ndo, bp->bp_giaddr)); /* Client's Ethernet address */ if (bp_htype == 1 && bp_hlen == 6) { ND_TCHECK_6(bp->bp_chaddr); ND_PRINT("\n\t Client-Ethernet-Address %s", etheraddr_string(ndo, bp->bp_chaddr)); } ND_TCHECK_1(bp->bp_sname); /* check first char only */ if (EXTRACT_U_1(bp->bp_sname)) { ND_PRINT("\n\t sname \""); if (nd_printztn(ndo, bp->bp_sname, (u_int)sizeof(bp->bp_sname), ndo->ndo_snapend) == 0) { ND_PRINT("\""); nd_print_trunc(ndo); return; } ND_PRINT("\""); } ND_TCHECK_1(bp->bp_file); /* check first char only */ if (EXTRACT_U_1(bp->bp_file)) { ND_PRINT("\n\t file \""); if (nd_printztn(ndo, bp->bp_file, (u_int)sizeof(bp->bp_file), ndo->ndo_snapend) == 0) { ND_PRINT("\""); nd_print_trunc(ndo); return; } ND_PRINT("\""); } /* Decode the vendor buffer */ ND_TCHECK_4(bp->bp_vend); if (memcmp((const char *)bp->bp_vend, vm_rfc1048, sizeof(uint32_t)) == 0) rfc1048_print(ndo, bp->bp_vend); else if (memcmp((const char *)bp->bp_vend, vm_cmu, sizeof(uint32_t)) == 0) cmu_print(ndo, bp->bp_vend); else { uint32_t ul; ul = EXTRACT_BE_U_4(bp->bp_vend); if (ul != 0) ND_PRINT("\n\t Vendor-#0x%x", ul); } return; trunc: nd_print_trunc(ndo); }
void lwres_print(netdissect_options *ndo, const u_char *bp, u_int length) { const u_char *p; const struct lwres_lwpacket *np; uint32_t v; const u_char *s; int response; int advance; int unsupported = 0; ndo->ndo_protocol = "lwres"; np = (const struct lwres_lwpacket *)bp; ND_TCHECK_2(np->authlength); ND_PRINT(" lwres"); v = EXTRACT_BE_U_2(np->version); if (ndo->ndo_vflag || v != LWRES_LWPACKETVERSION_0) ND_PRINT(" v%u", v); if (v != LWRES_LWPACKETVERSION_0) { s = bp + EXTRACT_BE_U_4(np->length); goto tail; } response = EXTRACT_BE_U_2(np->pktflags) & LWRES_LWPACKETFLAG_RESPONSE; /* opcode and pktflags */ v = EXTRACT_BE_U_4(np->opcode); ND_PRINT(" %s%s", tok2str(opcode, "#0x%x", v), response ? "" : "?"); /* pktflags */ v = EXTRACT_BE_U_2(np->pktflags); if (v & ~LWRES_LWPACKETFLAG_RESPONSE) ND_PRINT("[0x%x]", v); if (ndo->ndo_vflag > 1) { ND_PRINT(" ("); /*)*/ ND_PRINT("serial:0x%x", EXTRACT_BE_U_4(np->serial)); ND_PRINT(" result:0x%x", EXTRACT_BE_U_4(np->result)); ND_PRINT(" recvlen:%u", EXTRACT_BE_U_4(np->recvlength)); /* BIND910: not used */ if (ndo->ndo_vflag > 2) { ND_PRINT(" authtype:0x%x", EXTRACT_BE_U_2(np->authtype)); ND_PRINT(" authlen:%u", EXTRACT_BE_U_2(np->authlength)); } /*(*/ ND_PRINT(")"); } /* per-opcode content */ if (!response) { /* * queries */ const lwres_gabnrequest_t *gabn; const lwres_gnbarequest_t *gnba; const lwres_grbnrequest_t *grbn; uint32_t l; gabn = NULL; gnba = NULL; grbn = NULL; p = (const u_char *)(np + 1); switch (EXTRACT_BE_U_4(np->opcode)) { case LWRES_OPCODE_NOOP: s = p; break; case LWRES_OPCODE_GETADDRSBYNAME: gabn = (const lwres_gabnrequest_t *)p; ND_TCHECK_2(gabn->namelen); /* BIND910: not used */ if (ndo->ndo_vflag > 2) { ND_PRINT(" flags:0x%x", EXTRACT_BE_U_4(gabn->flags)); } v = EXTRACT_BE_U_4(gabn->addrtypes); switch (v & (LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6)) { case LWRES_ADDRTYPE_V4: ND_PRINT(" IPv4"); break; case LWRES_ADDRTYPE_V6: ND_PRINT(" IPv6"); break; case LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6: ND_PRINT(" IPv4/6"); break; } if (v & ~(LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6)) ND_PRINT("[0x%x]", v); s = p + LWRES_GABNREQUEST_LEN; l = EXTRACT_BE_U_2(gabn->namelen); advance = lwres_printname(ndo, l, s); if (advance < 0) goto trunc; s += advance; break; case LWRES_OPCODE_GETNAMEBYADDR: gnba = (const lwres_gnbarequest_t *)p; ND_TCHECK_4(gnba->flags); /* BIND910: not used */ if (ndo->ndo_vflag > 2) { ND_PRINT(" flags:0x%x", EXTRACT_BE_U_4(gnba->flags)); } s = p + LWRES_GNBAREQUEST_LEN; advance = lwres_printaddr(ndo, s); if (advance < 0) goto trunc; s += advance; break; case LWRES_OPCODE_GETRDATABYNAME: /* XXX no trace, not tested */ grbn = (const lwres_grbnrequest_t *)p; ND_TCHECK_2(grbn->namelen); /* BIND910: not used */ if (ndo->ndo_vflag > 2) { ND_PRINT(" flags:0x%x", EXTRACT_BE_U_4(grbn->flags)); } ND_PRINT(" %s", tok2str(ns_type2str, "Type%u", EXTRACT_BE_U_2(grbn->rdtype))); if (EXTRACT_BE_U_2(grbn->rdclass) != C_IN) { ND_PRINT(" %s", tok2str(ns_class2str, "Class%u", EXTRACT_BE_U_2(grbn->rdclass))); } s = p + LWRES_GRBNREQUEST_LEN; l = EXTRACT_BE_U_2(grbn->namelen); advance = lwres_printname(ndo, l, s); if (advance < 0) goto trunc; s += advance; break; default: s = p; unsupported++; break; } } else { /* * responses */ const lwres_gabnresponse_t *gabn; const lwres_gnbaresponse_t *gnba; const lwres_grbnresponse_t *grbn; uint32_t l, na; uint32_t i; gabn = NULL; gnba = NULL; grbn = NULL; p = (const u_char *)(np + 1); switch (EXTRACT_BE_U_4(np->opcode)) { case LWRES_OPCODE_NOOP: s = p; break; case LWRES_OPCODE_GETADDRSBYNAME: gabn = (const lwres_gabnresponse_t *)p; ND_TCHECK_2(gabn->realnamelen); /* BIND910: not used */ if (ndo->ndo_vflag > 2) { ND_PRINT(" flags:0x%x", EXTRACT_BE_U_4(gabn->flags)); } ND_PRINT(" %u/%u", EXTRACT_BE_U_2(gabn->naliases), EXTRACT_BE_U_2(gabn->naddrs)); s = p + LWRES_GABNRESPONSE_LEN; l = EXTRACT_BE_U_2(gabn->realnamelen); advance = lwres_printname(ndo, l, s); if (advance < 0) goto trunc; s += advance; /* aliases */ na = EXTRACT_BE_U_2(gabn->naliases); for (i = 0; i < na; i++) { advance = lwres_printnamelen(ndo, s); if (advance < 0) goto trunc; s += advance; } /* addrs */ na = EXTRACT_BE_U_2(gabn->naddrs); for (i = 0; i < na; i++) { advance = lwres_printaddr(ndo, s); if (advance < 0) goto trunc; s += advance; } break; case LWRES_OPCODE_GETNAMEBYADDR: gnba = (const lwres_gnbaresponse_t *)p; ND_TCHECK_2(gnba->realnamelen); /* BIND910: not used */ if (ndo->ndo_vflag > 2) { ND_PRINT(" flags:0x%x", EXTRACT_BE_U_4(gnba->flags)); } ND_PRINT(" %u", EXTRACT_BE_U_2(gnba->naliases)); s = p + LWRES_GNBARESPONSE_LEN; l = EXTRACT_BE_U_2(gnba->realnamelen); advance = lwres_printname(ndo, l, s); if (advance < 0) goto trunc; s += advance; /* aliases */ na = EXTRACT_BE_U_2(gnba->naliases); for (i = 0; i < na; i++) { advance = lwres_printnamelen(ndo, s); if (advance < 0) goto trunc; s += advance; } break; case LWRES_OPCODE_GETRDATABYNAME: /* XXX no trace, not tested */ grbn = (const lwres_grbnresponse_t *)p; ND_TCHECK_2(grbn->nsigs); /* BIND910: not used */ if (ndo->ndo_vflag > 2) { ND_PRINT(" flags:0x%x", EXTRACT_BE_U_4(grbn->flags)); } ND_PRINT(" %s", tok2str(ns_type2str, "Type%u", EXTRACT_BE_U_2(grbn->rdtype))); if (EXTRACT_BE_U_2(grbn->rdclass) != C_IN) { ND_PRINT(" %s", tok2str(ns_class2str, "Class%u", EXTRACT_BE_U_2(grbn->rdclass))); } ND_PRINT(" TTL "); unsigned_relts_print(ndo, EXTRACT_BE_U_4(grbn->ttl)); ND_PRINT(" %u/%u", EXTRACT_BE_U_2(grbn->nrdatas), EXTRACT_BE_U_2(grbn->nsigs)); s = p + LWRES_GRBNRESPONSE_LEN; advance = lwres_printnamelen(ndo, s); if (advance < 0) goto trunc; s += advance; /* rdatas */ na = EXTRACT_BE_U_2(grbn->nrdatas); for (i = 0; i < na; i++) { /* XXX should decode resource data */ advance = lwres_printbinlen(ndo, s); if (advance < 0) goto trunc; s += advance; } /* sigs */ na = EXTRACT_BE_U_2(grbn->nsigs); for (i = 0; i < na; i++) { /* XXX how should we print it? */ advance = lwres_printbinlen(ndo, s); if (advance < 0) goto trunc; s += advance; } break; default: s = p; unsupported++; break; } } tail: /* length mismatch */ if (EXTRACT_BE_U_4(np->length) != length) { ND_PRINT(" [len: %u != %u]", EXTRACT_BE_U_4(np->length), length); } if (!unsupported && s < bp + EXTRACT_BE_U_4(np->length)) ND_PRINT("[extra]"); return; trunc: ND_PRINT("[|lwres]"); }
static void gre_print_0(netdissect_options *ndo, const u_char *bp, u_int length) { u_int len = length; uint16_t flags, prot; /* 16 bits ND_TCHECKed in gre_print() */ flags = EXTRACT_BE_U_2(bp); if (ndo->ndo_vflag) ND_PRINT(", Flags [%s]", bittok2str(gre_flag_values,"none",flags)); len -= 2; bp += 2; ND_TCHECK_2(bp); if (len < 2) goto trunc; prot = EXTRACT_BE_U_2(bp); len -= 2; bp += 2; if ((flags & GRE_CP) | (flags & GRE_RP)) { ND_TCHECK_2(bp); if (len < 2) goto trunc; if (ndo->ndo_vflag) ND_PRINT(", sum 0x%x", EXTRACT_BE_U_2(bp)); bp += 2; len -= 2; ND_TCHECK_2(bp); if (len < 2) goto trunc; ND_PRINT(", off 0x%x", EXTRACT_BE_U_2(bp)); bp += 2; len -= 2; } if (flags & GRE_KP) { ND_TCHECK_4(bp); if (len < 4) goto trunc; ND_PRINT(", key=0x%x", EXTRACT_BE_U_4(bp)); bp += 4; len -= 4; } if (flags & GRE_SP) { ND_TCHECK_4(bp); if (len < 4) goto trunc; ND_PRINT(", seq %u", EXTRACT_BE_U_4(bp)); bp += 4; len -= 4; } if (flags & GRE_RP) { for (;;) { uint16_t af; uint8_t sreoff; uint8_t srelen; ND_TCHECK_4(bp); if (len < 4) goto trunc; af = EXTRACT_BE_U_2(bp); sreoff = EXTRACT_U_1(bp + 2); srelen = EXTRACT_U_1(bp + 3); bp += 4; len -= 4; if (af == 0 && srelen == 0) break; if (!gre_sre_print(ndo, af, sreoff, srelen, bp, len)) goto trunc; if (len < srelen) goto trunc; bp += srelen; len -= srelen; } } if (ndo->ndo_eflag) ND_PRINT(", proto %s (0x%04x)", tok2str(ethertype_values,"unknown",prot), prot); ND_PRINT(", length %u",length); if (ndo->ndo_vflag < 1) ND_PRINT(": "); /* put in a colon as protocol demarc */ else ND_PRINT("\n\t"); /* if verbose go multiline */ switch (prot) { case ETHERTYPE_IP: ip_print(ndo, bp, len); break; case ETHERTYPE_IPV6: ip6_print(ndo, bp, len); break; case ETHERTYPE_MPLS: mpls_print(ndo, bp, len); break; case ETHERTYPE_IPX: ipx_print(ndo, bp, len); break; case ETHERTYPE_ATALK: atalk_print(ndo, bp, len); break; case ETHERTYPE_GRE_ISO: isoclns_print(ndo, bp, len); break; case ETHERTYPE_TEB: ether_print(ndo, bp, len, ndo->ndo_snapend - bp, NULL, NULL); break; default: ND_PRINT("gre-proto-0x%x", prot); } return; trunc: ND_PRINT("%s", tstr); }
static void gre_print_1(netdissect_options *ndo, const u_char *bp, u_int length) { u_int len = length; uint16_t flags, prot; /* 16 bits ND_TCHECKed in gre_print() */ flags = EXTRACT_BE_U_2(bp); len -= 2; bp += 2; if (ndo->ndo_vflag) ND_PRINT(", Flags [%s]", bittok2str(gre_flag_values,"none",flags)); ND_TCHECK_2(bp); if (len < 2) goto trunc; prot = EXTRACT_BE_U_2(bp); len -= 2; bp += 2; if (flags & GRE_KP) { uint32_t k; ND_TCHECK_4(bp); if (len < 4) goto trunc; k = EXTRACT_BE_U_4(bp); ND_PRINT(", call %u", k & 0xffff); len -= 4; bp += 4; } if (flags & GRE_SP) { ND_TCHECK_4(bp); if (len < 4) goto trunc; ND_PRINT(", seq %u", EXTRACT_BE_U_4(bp)); bp += 4; len -= 4; } if (flags & GRE_AP) { ND_TCHECK_4(bp); if (len < 4) goto trunc; ND_PRINT(", ack %u", EXTRACT_BE_U_4(bp)); bp += 4; len -= 4; } if ((flags & GRE_SP) == 0) ND_PRINT(", no-payload"); if (ndo->ndo_eflag) ND_PRINT(", proto %s (0x%04x)", tok2str(ethertype_values,"unknown",prot), prot); ND_PRINT(", length %u",length); if ((flags & GRE_SP) == 0) return; if (ndo->ndo_vflag < 1) ND_PRINT(": "); /* put in a colon as protocol demarc */ else ND_PRINT("\n\t"); /* if verbose go multiline */ switch (prot) { case ETHERTYPE_PPP: ppp_print(ndo, bp, len); break; default: ND_PRINT("gre-proto-0x%x", prot); break; } return; trunc: ND_PRINT("%s", tstr); }
static void egpnrprint(netdissect_options *ndo, const struct egp_packet *egp, u_int length) { const uint8_t *cp; uint32_t addr; uint32_t net; u_int netlen; u_int gateways, distances, networks; u_int intgw, extgw, t_gateways; const char *comma; addr = EXTRACT_IPV4_TO_NETWORK_ORDER(egp->egp_sourcenet); if (IN_CLASSA(addr)) { net = addr & IN_CLASSA_NET; netlen = 1; } else if (IN_CLASSB(addr)) { net = addr & IN_CLASSB_NET; netlen = 2; } else if (IN_CLASSC(addr)) { net = addr & IN_CLASSC_NET; netlen = 3; } else { net = 0; netlen = 0; } cp = (const uint8_t *)(egp + 1); length -= sizeof(*egp); intgw = EXTRACT_U_1(egp->egp_intgw); extgw = EXTRACT_U_1(egp->egp_extgw); t_gateways = intgw + extgw; for (gateways = 0; gateways < t_gateways; ++gateways) { /* Pickup host part of gateway address */ addr = 0; if (length < 4 - netlen) goto trunc; ND_TCHECK_LEN(cp, 4 - netlen); switch (netlen) { case 1: addr = EXTRACT_U_1(cp); cp++; /* fall through */ case 2: addr = (addr << 8) | EXTRACT_U_1(cp); cp++; /* fall through */ case 3: addr = (addr << 8) | EXTRACT_U_1(cp); cp++; break; } addr |= net; length -= 4 - netlen; if (length < 1) goto trunc; ND_TCHECK_1(cp); distances = EXTRACT_U_1(cp); cp++; length--; ND_PRINT(" %s %s ", gateways < intgw ? "int" : "ext", ipaddr_string(ndo, (const u_char *)&addr)); comma = ""; ND_PRINT("("); while (distances != 0) { if (length < 2) goto trunc; ND_TCHECK_2(cp); ND_PRINT("%sd%u:", comma, EXTRACT_U_1(cp)); cp++; comma = ", "; networks = EXTRACT_U_1(cp); cp++; length -= 2; while (networks != 0) { /* Pickup network number */ if (length < 1) goto trunc; ND_TCHECK_1(cp); addr = ((uint32_t) EXTRACT_U_1(cp)) << 24; cp++; length--; if (IN_CLASSB(addr)) { if (length < 1) goto trunc; ND_TCHECK_1(cp); addr |= ((uint32_t) EXTRACT_U_1(cp)) << 16; cp++; length--; } else if (!IN_CLASSA(addr)) { if (length < 2) goto trunc; ND_TCHECK_2(cp); addr |= ((uint32_t) EXTRACT_U_1(cp)) << 16; cp++; addr |= ((uint32_t) EXTRACT_U_1(cp)) << 8; cp++; length -= 2; } ND_PRINT(" %s", ipaddr_string(ndo, (const u_char *)&addr)); networks--; } distances--; } ND_PRINT(")"); } return; trunc: ND_PRINT("[|]"); }
/* LCP config options */ static u_int print_lcp_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) { if (opt < NUM_LCPOPTS) ND_PRINT("\n\t %s Option (0x%02x), length %u (length bogus, should be >= 2)", lcpconfopts[opt], opt, len); else ND_PRINT("\n\tunknown LCP option 0x%02x", opt); return 0; } if (opt < NUM_LCPOPTS) ND_PRINT("\n\t %s Option (0x%02x), length %u", lcpconfopts[opt], opt, len); else { ND_PRINT("\n\tunknown LCP option 0x%02x", opt); return len; } switch (opt) { case LCPOPT_VEXT: if (len < 6) { ND_PRINT(" (length bogus, should be >= 6)"); return len; } ND_TCHECK_3(p + 2); ND_PRINT(": Vendor: %s (%u)", tok2str(oui_values,"Unknown",EXTRACT_BE_U_3(p + 2)), EXTRACT_BE_U_3(p + 2)); #if 0 ND_TCHECK_1(p + 5); ND_PRINT(", kind: 0x%02x", EXTRACT_U_1(p + 5)); ND_PRINT(", Value: 0x"); for (i = 0; i < len - 6; i++) { ND_TCHECK_1(p + 6 + i); ND_PRINT("%02x", EXTRACT_U_1(p + 6 + i)); } #endif break; case LCPOPT_MRU: if (len != 4) { ND_PRINT(" (length bogus, should be = 4)"); return len; } ND_TCHECK_2(p + 2); ND_PRINT(": %u", EXTRACT_BE_U_2(p + 2)); break; case LCPOPT_ACCM: if (len != 6) { ND_PRINT(" (length bogus, should be = 6)"); return len; } ND_TCHECK_4(p + 2); ND_PRINT(": 0x%08x", EXTRACT_BE_U_4(p + 2)); break; case LCPOPT_AP: if (len < 4) { ND_PRINT(" (length bogus, should be >= 4)"); return len; } ND_TCHECK_2(p + 2); ND_PRINT(": %s", tok2str(ppptype2str, "Unknown Auth Proto (0x04x)", EXTRACT_BE_U_2(p + 2))); switch (EXTRACT_BE_U_2(p + 2)) { case PPP_CHAP: ND_TCHECK_1(p + 4); ND_PRINT(", %s", tok2str(authalg_values, "Unknown Auth Alg %u", EXTRACT_U_1(p + 4))); break; case PPP_PAP: /* fall through */ case PPP_EAP: case PPP_SPAP: case PPP_SPAP_OLD: break; default: print_unknown_data(ndo, p, "\n\t", len); } break; case LCPOPT_QP: if (len < 4) { ND_PRINT(" (length bogus, should be >= 4)"); return 0; } ND_TCHECK_2(p + 2); if (EXTRACT_BE_U_2(p + 2) == PPP_LQM) ND_PRINT(": LQR"); else ND_PRINT(": unknown"); break; case LCPOPT_MN: if (len != 6) { ND_PRINT(" (length bogus, should be = 6)"); return 0; } ND_TCHECK_4(p + 2); ND_PRINT(": 0x%08x", EXTRACT_BE_U_4(p + 2)); break; case LCPOPT_PFC: break; case LCPOPT_ACFC: break; case LCPOPT_LD: if (len != 4) { ND_PRINT(" (length bogus, should be = 4)"); return 0; } ND_TCHECK_2(p + 2); ND_PRINT(": 0x%04x", EXTRACT_BE_U_2(p + 2)); break; case LCPOPT_CBACK: if (len < 3) { ND_PRINT(" (length bogus, should be >= 3)"); return 0; } ND_PRINT(": "); ND_TCHECK_1(p + 2); ND_PRINT(": Callback Operation %s (%u)", tok2str(ppp_callback_values, "Unknown", EXTRACT_U_1(p + 2)), EXTRACT_U_1(p + 2)); break; case LCPOPT_MLMRRU: if (len != 4) { ND_PRINT(" (length bogus, should be = 4)"); return 0; } ND_TCHECK_2(p + 2); ND_PRINT(": %u", EXTRACT_BE_U_2(p + 2)); break; case LCPOPT_MLED: if (len < 3) { ND_PRINT(" (length bogus, should be >= 3)"); return 0; } ND_TCHECK_1(p + 2); switch (EXTRACT_U_1(p + 2)) { /* class */ case MEDCLASS_NULL: ND_PRINT(": Null"); break; case MEDCLASS_LOCAL: ND_PRINT(": Local"); /* XXX */ break; case MEDCLASS_IPV4: if (len != 7) { ND_PRINT(" (length bogus, should be = 7)"); return 0; } ND_TCHECK_4(p + 3); ND_PRINT(": IPv4 %s", ipaddr_string(ndo, p + 3)); break; case MEDCLASS_MAC: if (len != 9) { ND_PRINT(" (length bogus, should be = 9)"); return 0; } ND_TCHECK_6(p + 3); ND_PRINT(": MAC %s", etheraddr_string(ndo, p + 3)); break; case MEDCLASS_MNB: ND_PRINT(": Magic-Num-Block"); /* XXX */ break; case MEDCLASS_PSNDN: ND_PRINT(": PSNDN"); /* XXX */ break; default: ND_PRINT(": Unknown class %u", EXTRACT_U_1(p + 2)); break; } break; /* XXX: to be supported */ #if 0 case LCPOPT_DEP6: case LCPOPT_FCSALT: case LCPOPT_SDP: case LCPOPT_NUMMODE: case LCPOPT_DEP12: case LCPOPT_DEP14: case LCPOPT_DEP15: case LCPOPT_DEP16: case LCPOPT_MLSSNHF: case LCPOPT_PROP: case LCPOPT_DCEID: case LCPOPT_MPP: case LCPOPT_LCPAOPT: case LCPOPT_COBS: case LCPOPT_PE: case LCPOPT_MLHF: case LCPOPT_I18N: case LCPOPT_SDLOS: case LCPOPT_PPPMUX: break; #endif 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("[|lcp]"); return 0; }