1 1.1 christos /* 2 1.1 christos * Copyright (c) 1998-2006 The TCPDUMP project 3 1.1 christos * 4 1.1 christos * Redistribution and use in source and binary forms, with or without 5 1.1 christos * modification, are permitted provided that: (1) source code 6 1.1 christos * distributions retain the above copyright notice and this paragraph 7 1.1 christos * in its entirety, and (2) distributions including binary code include 8 1.1 christos * the above copyright notice and this paragraph in its entirety in 9 1.1 christos * the documentation or other materials provided with the distribution. 10 1.1 christos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 11 1.1 christos * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 12 1.1 christos * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 13 1.1 christos * FOR A PARTICULAR PURPOSE. 14 1.1 christos * 15 1.1 christos * support for the IEEE "slow protocols" LACP, MARKER as per 802.3ad 16 1.1 christos * OAM as per 802.3ah 17 1.1 christos * 18 1.9 christos * Original code by Hannes Gredler (hannes (at) gredler.at) 19 1.1 christos */ 20 1.1 christos 21 1.2 christos #include <sys/cdefs.h> 22 1.1 christos #ifndef lint 23 1.11 christos __RCSID("$NetBSD: print-slow.c,v 1.11 2024/09/02 16:15:33 christos Exp $"); 24 1.1 christos #endif 25 1.1 christos 26 1.8 spz /* \summary: IEEE "slow protocols" (802.3ad/802.3ah) printer */ 27 1.8 spz 28 1.10 christos #include <config.h> 29 1.1 christos 30 1.10 christos #include "netdissect-stdinc.h" 31 1.1 christos 32 1.10 christos #define ND_LONGJMP_FROM_TCHECK 33 1.7 christos #include "netdissect.h" 34 1.1 christos #include "extract.h" 35 1.1 christos #include "addrtoname.h" 36 1.1 christos #include "oui.h" 37 1.1 christos 38 1.10 christos 39 1.1 christos #define SLOW_PROTO_LACP 1 40 1.1 christos #define SLOW_PROTO_MARKER 2 41 1.1 christos #define SLOW_PROTO_OAM 3 42 1.1 christos 43 1.1 christos #define LACP_VERSION 1 44 1.1 christos #define MARKER_VERSION 1 45 1.1 christos 46 1.1 christos static const struct tok slow_proto_values[] = { 47 1.1 christos { SLOW_PROTO_LACP, "LACP" }, 48 1.1 christos { SLOW_PROTO_MARKER, "MARKER" }, 49 1.1 christos { SLOW_PROTO_OAM, "OAM" }, 50 1.1 christos { 0, NULL} 51 1.1 christos }; 52 1.1 christos 53 1.1 christos static const struct tok slow_oam_flag_values[] = { 54 1.1 christos { 0x0001, "Link Fault" }, 55 1.1 christos { 0x0002, "Dying Gasp" }, 56 1.1 christos { 0x0004, "Critical Event" }, 57 1.1 christos { 0x0008, "Local Evaluating" }, 58 1.1 christos { 0x0010, "Local Stable" }, 59 1.1 christos { 0x0020, "Remote Evaluating" }, 60 1.1 christos { 0x0040, "Remote Stable" }, 61 1.1 christos { 0, NULL} 62 1.5 christos }; 63 1.1 christos 64 1.1 christos #define SLOW_OAM_CODE_INFO 0x00 65 1.1 christos #define SLOW_OAM_CODE_EVENT_NOTIF 0x01 66 1.1 christos #define SLOW_OAM_CODE_VAR_REQUEST 0x02 67 1.1 christos #define SLOW_OAM_CODE_VAR_RESPONSE 0x03 68 1.1 christos #define SLOW_OAM_CODE_LOOPBACK_CTRL 0x04 69 1.1 christos #define SLOW_OAM_CODE_PRIVATE 0xfe 70 1.1 christos 71 1.1 christos static const struct tok slow_oam_code_values[] = { 72 1.1 christos { SLOW_OAM_CODE_INFO, "Information" }, 73 1.1 christos { SLOW_OAM_CODE_EVENT_NOTIF, "Event Notification" }, 74 1.1 christos { SLOW_OAM_CODE_VAR_REQUEST, "Variable Request" }, 75 1.1 christos { SLOW_OAM_CODE_VAR_RESPONSE, "Variable Response" }, 76 1.1 christos { SLOW_OAM_CODE_LOOPBACK_CTRL, "Loopback Control" }, 77 1.1 christos { SLOW_OAM_CODE_PRIVATE, "Vendor Private" }, 78 1.1 christos { 0, NULL} 79 1.1 christos }; 80 1.1 christos 81 1.1 christos struct slow_oam_info_t { 82 1.10 christos nd_uint8_t info_type; 83 1.10 christos nd_uint8_t info_length; 84 1.10 christos nd_uint8_t oam_version; 85 1.10 christos nd_uint16_t revision; 86 1.10 christos nd_uint8_t state; 87 1.10 christos nd_uint8_t oam_config; 88 1.10 christos nd_uint16_t oam_pdu_config; 89 1.10 christos nd_uint24_t oui; 90 1.10 christos nd_uint32_t vendor_private; 91 1.1 christos }; 92 1.1 christos 93 1.1 christos #define SLOW_OAM_INFO_TYPE_END_OF_TLV 0x00 94 1.1 christos #define SLOW_OAM_INFO_TYPE_LOCAL 0x01 95 1.1 christos #define SLOW_OAM_INFO_TYPE_REMOTE 0x02 96 1.1 christos #define SLOW_OAM_INFO_TYPE_ORG_SPECIFIC 0xfe 97 1.1 christos 98 1.1 christos static const struct tok slow_oam_info_type_values[] = { 99 1.1 christos { SLOW_OAM_INFO_TYPE_END_OF_TLV, "End of TLV marker" }, 100 1.1 christos { SLOW_OAM_INFO_TYPE_LOCAL, "Local" }, 101 1.1 christos { SLOW_OAM_INFO_TYPE_REMOTE, "Remote" }, 102 1.1 christos { SLOW_OAM_INFO_TYPE_ORG_SPECIFIC, "Organization specific" }, 103 1.1 christos { 0, NULL} 104 1.1 christos }; 105 1.1 christos 106 1.1 christos #define OAM_INFO_TYPE_PARSER_MASK 0x3 107 1.1 christos static const struct tok slow_oam_info_type_state_parser_values[] = { 108 1.1 christos { 0x00, "forwarding" }, 109 1.1 christos { 0x01, "looping back" }, 110 1.1 christos { 0x02, "discarding" }, 111 1.1 christos { 0x03, "reserved" }, 112 1.1 christos { 0, NULL} 113 1.1 christos }; 114 1.1 christos 115 1.1 christos #define OAM_INFO_TYPE_MUX_MASK 0x4 116 1.1 christos static const struct tok slow_oam_info_type_state_mux_values[] = { 117 1.1 christos { 0x00, "forwarding" }, 118 1.1 christos { 0x04, "discarding" }, 119 1.1 christos { 0, NULL} 120 1.1 christos }; 121 1.1 christos 122 1.1 christos static const struct tok slow_oam_info_type_oam_config_values[] = { 123 1.1 christos { 0x01, "Active" }, 124 1.1 christos { 0x02, "Unidirectional" }, 125 1.1 christos { 0x04, "Remote-Loopback" }, 126 1.1 christos { 0x08, "Link-Events" }, 127 1.1 christos { 0x10, "Variable-Retrieval" }, 128 1.1 christos { 0, NULL} 129 1.1 christos }; 130 1.1 christos 131 1.1 christos /* 11 Bits */ 132 1.1 christos #define OAM_INFO_TYPE_PDU_SIZE_MASK 0x7ff 133 1.1 christos 134 1.1 christos #define SLOW_OAM_LINK_EVENT_END_OF_TLV 0x00 135 1.1 christos #define SLOW_OAM_LINK_EVENT_ERR_SYM_PER 0x01 136 1.1 christos #define SLOW_OAM_LINK_EVENT_ERR_FRM 0x02 137 1.1 christos #define SLOW_OAM_LINK_EVENT_ERR_FRM_PER 0x03 138 1.1 christos #define SLOW_OAM_LINK_EVENT_ERR_FRM_SUMM 0x04 139 1.1 christos #define SLOW_OAM_LINK_EVENT_ORG_SPECIFIC 0xfe 140 1.1 christos 141 1.1 christos static const struct tok slow_oam_link_event_values[] = { 142 1.1 christos { SLOW_OAM_LINK_EVENT_END_OF_TLV, "End of TLV marker" }, 143 1.1 christos { SLOW_OAM_LINK_EVENT_ERR_SYM_PER, "Errored Symbol Period Event" }, 144 1.1 christos { SLOW_OAM_LINK_EVENT_ERR_FRM, "Errored Frame Event" }, 145 1.1 christos { SLOW_OAM_LINK_EVENT_ERR_FRM_PER, "Errored Frame Period Event" }, 146 1.1 christos { SLOW_OAM_LINK_EVENT_ERR_FRM_SUMM, "Errored Frame Seconds Summary Event" }, 147 1.1 christos { SLOW_OAM_LINK_EVENT_ORG_SPECIFIC, "Organization specific" }, 148 1.1 christos { 0, NULL} 149 1.1 christos }; 150 1.1 christos 151 1.1 christos struct slow_oam_link_event_t { 152 1.10 christos nd_uint8_t event_type; 153 1.10 christos nd_uint8_t event_length; 154 1.10 christos nd_uint16_t time_stamp; 155 1.10 christos nd_uint64_t window; 156 1.10 christos nd_uint64_t threshold; 157 1.10 christos nd_uint64_t errors; 158 1.10 christos nd_uint64_t errors_running_total; 159 1.10 christos nd_uint32_t event_running_total; 160 1.1 christos }; 161 1.1 christos 162 1.1 christos struct slow_oam_variablerequest_t { 163 1.10 christos nd_uint8_t branch; 164 1.10 christos nd_uint16_t leaf; 165 1.1 christos }; 166 1.1 christos 167 1.1 christos struct slow_oam_variableresponse_t { 168 1.10 christos nd_uint8_t branch; 169 1.10 christos nd_uint16_t leaf; 170 1.10 christos nd_uint8_t length; 171 1.1 christos }; 172 1.1 christos 173 1.1 christos struct slow_oam_loopbackctrl_t { 174 1.10 christos nd_uint8_t command; 175 1.1 christos }; 176 1.1 christos 177 1.1 christos static const struct tok slow_oam_loopbackctrl_cmd_values[] = { 178 1.1 christos { 0x01, "Enable OAM Remote Loopback" }, 179 1.1 christos { 0x02, "Disable OAM Remote Loopback" }, 180 1.1 christos { 0, NULL} 181 1.1 christos }; 182 1.1 christos 183 1.1 christos struct tlv_header_t { 184 1.10 christos nd_uint8_t type; 185 1.10 christos nd_uint8_t length; 186 1.1 christos }; 187 1.1 christos 188 1.8 spz #define LACP_MARKER_TLV_TERMINATOR 0x00 /* same code for LACP and Marker */ 189 1.8 spz 190 1.8 spz #define LACP_TLV_ACTOR_INFO 0x01 191 1.8 spz #define LACP_TLV_PARTNER_INFO 0x02 192 1.8 spz #define LACP_TLV_COLLECTOR_INFO 0x03 193 1.1 christos 194 1.8 spz #define MARKER_TLV_MARKER_INFO 0x01 195 1.1 christos 196 1.1 christos static const struct tok slow_tlv_values[] = { 197 1.8 spz { (SLOW_PROTO_LACP << 8) + LACP_MARKER_TLV_TERMINATOR, "Terminator"}, 198 1.1 christos { (SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO, "Actor Information"}, 199 1.1 christos { (SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO, "Partner Information"}, 200 1.1 christos { (SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO, "Collector Information"}, 201 1.1 christos 202 1.8 spz { (SLOW_PROTO_MARKER << 8) + LACP_MARKER_TLV_TERMINATOR, "Terminator"}, 203 1.1 christos { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO, "Marker Information"}, 204 1.1 christos { 0, NULL} 205 1.1 christos }; 206 1.1 christos 207 1.1 christos struct lacp_tlv_actor_partner_info_t { 208 1.10 christos nd_uint16_t sys_pri; 209 1.10 christos nd_mac_addr sys; 210 1.10 christos nd_uint16_t key; 211 1.10 christos nd_uint16_t port_pri; 212 1.10 christos nd_uint16_t port; 213 1.10 christos nd_uint8_t state; 214 1.10 christos nd_byte pad[3]; 215 1.5 christos }; 216 1.1 christos 217 1.1 christos static const struct tok lacp_tlv_actor_partner_info_state_values[] = { 218 1.1 christos { 0x01, "Activity"}, 219 1.1 christos { 0x02, "Timeout"}, 220 1.1 christos { 0x04, "Aggregation"}, 221 1.1 christos { 0x08, "Synchronization"}, 222 1.1 christos { 0x10, "Collecting"}, 223 1.1 christos { 0x20, "Distributing"}, 224 1.1 christos { 0x40, "Default"}, 225 1.1 christos { 0x80, "Expired"}, 226 1.1 christos { 0, NULL} 227 1.1 christos }; 228 1.1 christos 229 1.1 christos struct lacp_tlv_collector_info_t { 230 1.10 christos nd_uint16_t max_delay; 231 1.10 christos nd_byte pad[12]; 232 1.5 christos }; 233 1.1 christos 234 1.1 christos struct marker_tlv_marker_info_t { 235 1.10 christos nd_uint16_t req_port; 236 1.10 christos nd_mac_addr req_sys; 237 1.10 christos nd_uint32_t req_trans_id; 238 1.10 christos nd_byte pad[2]; 239 1.5 christos }; 240 1.1 christos 241 1.1 christos struct lacp_marker_tlv_terminator_t { 242 1.10 christos nd_byte pad[50]; 243 1.5 christos }; 244 1.1 christos 245 1.10 christos static void slow_marker_lacp_print(netdissect_options *, const u_char *, u_int, u_int); 246 1.10 christos static void slow_oam_print(netdissect_options *, const u_char *, u_int); 247 1.1 christos 248 1.1 christos void 249 1.5 christos slow_print(netdissect_options *ndo, 250 1.10 christos const u_char *pptr, u_int len) 251 1.6 christos { 252 1.1 christos int print_version; 253 1.8 spz u_int subtype; 254 1.1 christos 255 1.10 christos ndo->ndo_protocol = "slow"; 256 1.8 spz if (len < 1) 257 1.8 spz goto tooshort; 258 1.10 christos subtype = GET_U_1(pptr); 259 1.1 christos 260 1.1 christos /* 261 1.1 christos * Sanity checking of the header. 262 1.1 christos */ 263 1.8 spz switch (subtype) { 264 1.1 christos case SLOW_PROTO_LACP: 265 1.8 spz if (len < 2) 266 1.8 spz goto tooshort; 267 1.10 christos if (GET_U_1(pptr + 1) != LACP_VERSION) { 268 1.10 christos ND_PRINT("LACP version %u packet not supported", 269 1.10 christos GET_U_1(pptr + 1)); 270 1.1 christos return; 271 1.1 christos } 272 1.1 christos print_version = 1; 273 1.1 christos break; 274 1.1 christos 275 1.1 christos case SLOW_PROTO_MARKER: 276 1.8 spz if (len < 2) 277 1.8 spz goto tooshort; 278 1.10 christos if (GET_U_1(pptr + 1) != MARKER_VERSION) { 279 1.10 christos ND_PRINT("MARKER version %u packet not supported", 280 1.10 christos GET_U_1(pptr + 1)); 281 1.1 christos return; 282 1.1 christos } 283 1.1 christos print_version = 1; 284 1.1 christos break; 285 1.1 christos 286 1.1 christos case SLOW_PROTO_OAM: /* fall through */ 287 1.1 christos print_version = 0; 288 1.1 christos break; 289 1.1 christos 290 1.1 christos default: 291 1.1 christos /* print basic information and exit */ 292 1.1 christos print_version = -1; 293 1.1 christos break; 294 1.1 christos } 295 1.1 christos 296 1.8 spz if (print_version == 1) { 297 1.10 christos ND_PRINT("%sv%u, length %u", 298 1.8 spz tok2str(slow_proto_values, "unknown (%u)", subtype), 299 1.10 christos GET_U_1((pptr + 1)), 300 1.10 christos len); 301 1.1 christos } else { 302 1.1 christos /* some slow protos don't have a version number in the header */ 303 1.10 christos ND_PRINT("%s, length %u", 304 1.8 spz tok2str(slow_proto_values, "unknown (%u)", subtype), 305 1.10 christos len); 306 1.1 christos } 307 1.1 christos 308 1.1 christos /* unrecognized subtype */ 309 1.1 christos if (print_version == -1) { 310 1.5 christos print_unknown_data(ndo, pptr, "\n\t", len); 311 1.1 christos return; 312 1.1 christos } 313 1.1 christos 314 1.5 christos if (!ndo->ndo_vflag) 315 1.1 christos return; 316 1.1 christos 317 1.8 spz switch (subtype) { 318 1.1 christos default: /* should not happen */ 319 1.1 christos break; 320 1.1 christos 321 1.1 christos case SLOW_PROTO_OAM: 322 1.8 spz /* skip subtype */ 323 1.8 spz len -= 1; 324 1.8 spz pptr += 1; 325 1.8 spz slow_oam_print(ndo, pptr, len); 326 1.1 christos break; 327 1.1 christos 328 1.1 christos case SLOW_PROTO_LACP: /* LACP and MARKER share the same semantics */ 329 1.1 christos case SLOW_PROTO_MARKER: 330 1.8 spz /* skip subtype and version */ 331 1.8 spz len -= 2; 332 1.8 spz pptr += 2; 333 1.8 spz slow_marker_lacp_print(ndo, pptr, len, subtype); 334 1.1 christos break; 335 1.1 christos } 336 1.1 christos return; 337 1.1 christos 338 1.8 spz tooshort: 339 1.8 spz if (!ndo->ndo_vflag) 340 1.10 christos ND_PRINT(" (packet is too short)"); 341 1.8 spz else 342 1.10 christos ND_PRINT("\n\t\t packet is too short"); 343 1.1 christos } 344 1.1 christos 345 1.5 christos static void 346 1.5 christos slow_marker_lacp_print(netdissect_options *ndo, 347 1.10 christos const u_char *tptr, u_int tlen, 348 1.8 spz u_int proto_subtype) 349 1.6 christos { 350 1.1 christos const struct tlv_header_t *tlv_header; 351 1.1 christos const u_char *tlv_tptr; 352 1.10 christos u_int tlv_type, tlv_len, tlv_tlen; 353 1.1 christos 354 1.1 christos union { 355 1.1 christos const struct lacp_marker_tlv_terminator_t *lacp_marker_tlv_terminator; 356 1.1 christos const struct lacp_tlv_actor_partner_info_t *lacp_tlv_actor_partner_info; 357 1.1 christos const struct lacp_tlv_collector_info_t *lacp_tlv_collector_info; 358 1.1 christos const struct marker_tlv_marker_info_t *marker_tlv_marker_info; 359 1.1 christos } tlv_ptr; 360 1.5 christos 361 1.1 christos while(tlen>0) { 362 1.8 spz /* is the packet big enough to include the tlv header ? */ 363 1.8 spz if (tlen < sizeof(struct tlv_header_t)) 364 1.8 spz goto tooshort; 365 1.1 christos /* did we capture enough for fully decoding the tlv header ? */ 366 1.1 christos tlv_header = (const struct tlv_header_t *)tptr; 367 1.10 christos tlv_type = GET_U_1(tlv_header->type); 368 1.10 christos tlv_len = GET_U_1(tlv_header->length); 369 1.1 christos 370 1.10 christos ND_PRINT("\n\t%s TLV (0x%02x), length %u", 371 1.1 christos tok2str(slow_tlv_values, 372 1.1 christos "Unknown", 373 1.10 christos (proto_subtype << 8) + tlv_type), 374 1.10 christos tlv_type, 375 1.10 christos tlv_len); 376 1.1 christos 377 1.10 christos if (tlv_type == LACP_MARKER_TLV_TERMINATOR) { 378 1.8 spz /* 379 1.8 spz * This TLV has a length of zero, and means there are no 380 1.8 spz * more TLVs to process. 381 1.8 spz */ 382 1.1 christos return; 383 1.1 christos } 384 1.1 christos 385 1.8 spz /* length includes the type and length fields */ 386 1.8 spz if (tlv_len < sizeof(struct tlv_header_t)) { 387 1.10 christos ND_PRINT("\n\t ERROR: illegal length - should be >= %zu", 388 1.10 christos sizeof(struct tlv_header_t)); 389 1.8 spz return; 390 1.8 spz } 391 1.1 christos 392 1.8 spz /* is the packet big enough to include the tlv ? */ 393 1.8 spz if (tlen < tlv_len) 394 1.8 spz goto tooshort; 395 1.1 christos /* did we capture enough for fully decoding the tlv ? */ 396 1.10 christos ND_TCHECK_LEN(tptr, tlv_len); 397 1.1 christos 398 1.8 spz tlv_tptr=tptr+sizeof(struct tlv_header_t); 399 1.8 spz tlv_tlen=tlv_len-sizeof(struct tlv_header_t); 400 1.8 spz 401 1.10 christos switch((proto_subtype << 8) + tlv_type) { 402 1.1 christos 403 1.1 christos /* those two TLVs have the same structure -> fall through */ 404 1.1 christos case ((SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO): 405 1.1 christos case ((SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO): 406 1.8 spz if (tlv_tlen != 407 1.8 spz sizeof(struct lacp_tlv_actor_partner_info_t)) { 408 1.10 christos ND_PRINT("\n\t ERROR: illegal length - should be %zu", 409 1.10 christos sizeof(struct tlv_header_t) + sizeof(struct lacp_tlv_actor_partner_info_t)); 410 1.8 spz goto badlength; 411 1.8 spz } 412 1.8 spz 413 1.1 christos tlv_ptr.lacp_tlv_actor_partner_info = (const struct lacp_tlv_actor_partner_info_t *)tlv_tptr; 414 1.1 christos 415 1.10 christos ND_PRINT("\n\t System %s, System Priority %u, Key %u" 416 1.1 christos ", Port %u, Port Priority %u\n\t State Flags [%s]", 417 1.10 christos GET_ETHERADDR_STRING(tlv_ptr.lacp_tlv_actor_partner_info->sys), 418 1.10 christos GET_BE_U_2(tlv_ptr.lacp_tlv_actor_partner_info->sys_pri), 419 1.10 christos GET_BE_U_2(tlv_ptr.lacp_tlv_actor_partner_info->key), 420 1.10 christos GET_BE_U_2(tlv_ptr.lacp_tlv_actor_partner_info->port), 421 1.10 christos GET_BE_U_2(tlv_ptr.lacp_tlv_actor_partner_info->port_pri), 422 1.1 christos bittok2str(lacp_tlv_actor_partner_info_state_values, 423 1.1 christos "none", 424 1.10 christos GET_U_1(tlv_ptr.lacp_tlv_actor_partner_info->state))); 425 1.1 christos 426 1.1 christos break; 427 1.1 christos 428 1.1 christos case ((SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO): 429 1.8 spz if (tlv_tlen != 430 1.8 spz sizeof(struct lacp_tlv_collector_info_t)) { 431 1.10 christos ND_PRINT("\n\t ERROR: illegal length - should be %zu", 432 1.10 christos sizeof(struct tlv_header_t) + sizeof(struct lacp_tlv_collector_info_t)); 433 1.8 spz goto badlength; 434 1.8 spz } 435 1.8 spz 436 1.1 christos tlv_ptr.lacp_tlv_collector_info = (const struct lacp_tlv_collector_info_t *)tlv_tptr; 437 1.1 christos 438 1.10 christos ND_PRINT("\n\t Max Delay %u", 439 1.10 christos GET_BE_U_2(tlv_ptr.lacp_tlv_collector_info->max_delay)); 440 1.1 christos 441 1.1 christos break; 442 1.1 christos 443 1.1 christos case ((SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO): 444 1.8 spz if (tlv_tlen != 445 1.8 spz sizeof(struct marker_tlv_marker_info_t)) { 446 1.10 christos ND_PRINT("\n\t ERROR: illegal length - should be %zu", 447 1.10 christos sizeof(struct tlv_header_t) + sizeof(struct marker_tlv_marker_info_t)); 448 1.8 spz goto badlength; 449 1.8 spz } 450 1.8 spz 451 1.1 christos tlv_ptr.marker_tlv_marker_info = (const struct marker_tlv_marker_info_t *)tlv_tptr; 452 1.1 christos 453 1.10 christos ND_PRINT("\n\t Request System %s, Request Port %u, Request Transaction ID 0x%08x", 454 1.10 christos GET_ETHERADDR_STRING(tlv_ptr.marker_tlv_marker_info->req_sys), 455 1.10 christos GET_BE_U_2(tlv_ptr.marker_tlv_marker_info->req_port), 456 1.10 christos GET_BE_U_4(tlv_ptr.marker_tlv_marker_info->req_trans_id)); 457 1.1 christos 458 1.1 christos break; 459 1.1 christos 460 1.1 christos default: 461 1.5 christos if (ndo->ndo_vflag <= 1) 462 1.5 christos print_unknown_data(ndo, tlv_tptr, "\n\t ", tlv_tlen); 463 1.1 christos break; 464 1.1 christos } 465 1.8 spz 466 1.8 spz badlength: 467 1.1 christos /* do we want to see an additional hexdump ? */ 468 1.5 christos if (ndo->ndo_vflag > 1) { 469 1.5 christos print_unknown_data(ndo, tptr+sizeof(struct tlv_header_t), "\n\t ", 470 1.1 christos tlv_len-sizeof(struct tlv_header_t)); 471 1.1 christos } 472 1.1 christos 473 1.1 christos tptr+=tlv_len; 474 1.1 christos tlen-=tlv_len; 475 1.1 christos } 476 1.1 christos return; 477 1.8 spz 478 1.8 spz tooshort: 479 1.10 christos ND_PRINT("\n\t\t packet is too short"); 480 1.1 christos } 481 1.1 christos 482 1.5 christos static void 483 1.5 christos slow_oam_print(netdissect_options *ndo, 484 1.10 christos const u_char *tptr, u_int tlen) 485 1.6 christos { 486 1.10 christos uint8_t code; 487 1.10 christos uint8_t type, length; 488 1.10 christos uint8_t state; 489 1.10 christos uint8_t command; 490 1.1 christos u_int hexdump; 491 1.1 christos 492 1.1 christos struct slow_oam_common_header_t { 493 1.10 christos nd_uint16_t flags; 494 1.10 christos nd_uint8_t code; 495 1.1 christos }; 496 1.1 christos 497 1.1 christos struct slow_oam_tlv_header_t { 498 1.10 christos nd_uint8_t type; 499 1.10 christos nd_uint8_t length; 500 1.1 christos }; 501 1.1 christos 502 1.1 christos union { 503 1.1 christos const struct slow_oam_common_header_t *slow_oam_common_header; 504 1.1 christos const struct slow_oam_tlv_header_t *slow_oam_tlv_header; 505 1.1 christos } ptr; 506 1.1 christos 507 1.1 christos union { 508 1.10 christos const struct slow_oam_info_t *slow_oam_info; 509 1.1 christos const struct slow_oam_link_event_t *slow_oam_link_event; 510 1.1 christos const struct slow_oam_variablerequest_t *slow_oam_variablerequest; 511 1.1 christos const struct slow_oam_variableresponse_t *slow_oam_variableresponse; 512 1.1 christos const struct slow_oam_loopbackctrl_t *slow_oam_loopbackctrl; 513 1.1 christos } tlv; 514 1.5 christos 515 1.7 christos ptr.slow_oam_common_header = (const struct slow_oam_common_header_t *)tptr; 516 1.8 spz if (tlen < sizeof(*ptr.slow_oam_common_header)) 517 1.8 spz goto tooshort; 518 1.10 christos ND_TCHECK_SIZE(ptr.slow_oam_common_header); 519 1.1 christos tptr += sizeof(struct slow_oam_common_header_t); 520 1.1 christos tlen -= sizeof(struct slow_oam_common_header_t); 521 1.1 christos 522 1.10 christos code = GET_U_1(ptr.slow_oam_common_header->code); 523 1.10 christos ND_PRINT("\n\tCode %s OAM PDU, Flags [%s]", 524 1.10 christos tok2str(slow_oam_code_values, "Unknown (%u)", code), 525 1.1 christos bittok2str(slow_oam_flag_values, 526 1.1 christos "none", 527 1.10 christos GET_BE_U_2(ptr.slow_oam_common_header->flags))); 528 1.1 christos 529 1.10 christos switch (code) { 530 1.1 christos case SLOW_OAM_CODE_INFO: 531 1.1 christos while (tlen > 0) { 532 1.1 christos ptr.slow_oam_tlv_header = (const struct slow_oam_tlv_header_t *)tptr; 533 1.8 spz if (tlen < sizeof(*ptr.slow_oam_tlv_header)) 534 1.8 spz goto tooshort; 535 1.10 christos ND_TCHECK_SIZE(ptr.slow_oam_tlv_header); 536 1.10 christos type = GET_U_1(ptr.slow_oam_tlv_header->type); 537 1.10 christos length = GET_U_1(ptr.slow_oam_tlv_header->length); 538 1.10 christos ND_PRINT("\n\t %s Information Type (%u), length %u", 539 1.10 christos tok2str(slow_oam_info_type_values, "Reserved", type), 540 1.10 christos type, 541 1.10 christos length); 542 1.1 christos 543 1.10 christos if (type == SLOW_OAM_INFO_TYPE_END_OF_TLV) { 544 1.8 spz /* 545 1.8 spz * As IEEE Std 802.3-2015 says for the End of TLV Marker, 546 1.8 spz * "(the length and value of the Type 0x00 TLV can be ignored)". 547 1.8 spz */ 548 1.8 spz return; 549 1.8 spz } 550 1.8 spz 551 1.8 spz /* length includes the type and length fields */ 552 1.10 christos if (length < sizeof(struct slow_oam_tlv_header_t)) { 553 1.10 christos ND_PRINT("\n\t ERROR: illegal length - should be >= %zu", 554 1.10 christos sizeof(struct slow_oam_tlv_header_t)); 555 1.8 spz return; 556 1.8 spz } 557 1.8 spz 558 1.10 christos if (tlen < length) 559 1.8 spz goto tooshort; 560 1.10 christos ND_TCHECK_LEN(tptr, length); 561 1.8 spz 562 1.1 christos hexdump = FALSE; 563 1.10 christos switch (type) { 564 1.1 christos case SLOW_OAM_INFO_TYPE_LOCAL: /* identical format - fall through */ 565 1.1 christos case SLOW_OAM_INFO_TYPE_REMOTE: 566 1.1 christos tlv.slow_oam_info = (const struct slow_oam_info_t *)tptr; 567 1.5 christos 568 1.10 christos if (GET_U_1(tlv.slow_oam_info->info_length) != 569 1.1 christos sizeof(struct slow_oam_info_t)) { 570 1.10 christos ND_PRINT("\n\t ERROR: illegal length - should be %zu", 571 1.10 christos sizeof(struct slow_oam_info_t)); 572 1.8 spz hexdump = TRUE; 573 1.8 spz goto badlength_code_info; 574 1.1 christos } 575 1.1 christos 576 1.10 christos ND_PRINT("\n\t OAM-Version %u, Revision %u", 577 1.10 christos GET_U_1(tlv.slow_oam_info->oam_version), 578 1.10 christos GET_BE_U_2(tlv.slow_oam_info->revision)); 579 1.1 christos 580 1.10 christos state = GET_U_1(tlv.slow_oam_info->state); 581 1.10 christos ND_PRINT("\n\t State-Parser-Action %s, State-MUX-Action %s", 582 1.1 christos tok2str(slow_oam_info_type_state_parser_values, "Reserved", 583 1.10 christos state & OAM_INFO_TYPE_PARSER_MASK), 584 1.1 christos tok2str(slow_oam_info_type_state_mux_values, "Reserved", 585 1.10 christos state & OAM_INFO_TYPE_MUX_MASK)); 586 1.10 christos ND_PRINT("\n\t OAM-Config Flags [%s], OAM-PDU-Config max-PDU size %u", 587 1.1 christos bittok2str(slow_oam_info_type_oam_config_values, "none", 588 1.10 christos GET_U_1(tlv.slow_oam_info->oam_config)), 589 1.10 christos GET_BE_U_2(tlv.slow_oam_info->oam_pdu_config) & 590 1.10 christos OAM_INFO_TYPE_PDU_SIZE_MASK); 591 1.10 christos ND_PRINT("\n\t OUI %s (0x%06x), Vendor-Private 0x%08x", 592 1.1 christos tok2str(oui_values, "Unknown", 593 1.10 christos GET_BE_U_3(tlv.slow_oam_info->oui)), 594 1.10 christos GET_BE_U_3(tlv.slow_oam_info->oui), 595 1.10 christos GET_BE_U_4(tlv.slow_oam_info->vendor_private)); 596 1.1 christos break; 597 1.5 christos 598 1.1 christos case SLOW_OAM_INFO_TYPE_ORG_SPECIFIC: 599 1.1 christos hexdump = TRUE; 600 1.1 christos break; 601 1.5 christos 602 1.1 christos default: 603 1.1 christos hexdump = TRUE; 604 1.1 christos break; 605 1.1 christos } 606 1.1 christos 607 1.8 spz badlength_code_info: 608 1.1 christos /* do we also want to see a hex dump ? */ 609 1.5 christos if (ndo->ndo_vflag > 1 || hexdump==TRUE) { 610 1.5 christos print_unknown_data(ndo, tptr, "\n\t ", 611 1.10 christos length); 612 1.1 christos } 613 1.1 christos 614 1.10 christos tlen -= length; 615 1.10 christos tptr += length; 616 1.1 christos } 617 1.1 christos break; 618 1.1 christos 619 1.1 christos case SLOW_OAM_CODE_EVENT_NOTIF: 620 1.8 spz /* Sequence number */ 621 1.8 spz if (tlen < 2) 622 1.8 spz goto tooshort; 623 1.10 christos ND_PRINT("\n\t Sequence Number %u", GET_BE_U_2(tptr)); 624 1.8 spz tlen -= 2; 625 1.8 spz tptr += 2; 626 1.8 spz 627 1.8 spz /* TLVs */ 628 1.1 christos while (tlen > 0) { 629 1.1 christos ptr.slow_oam_tlv_header = (const struct slow_oam_tlv_header_t *)tptr; 630 1.8 spz if (tlen < sizeof(*ptr.slow_oam_tlv_header)) 631 1.8 spz goto tooshort; 632 1.10 christos type = GET_U_1(ptr.slow_oam_tlv_header->type); 633 1.10 christos length = GET_U_1(ptr.slow_oam_tlv_header->length); 634 1.10 christos ND_PRINT("\n\t %s Link Event Type (%u), length %u", 635 1.1 christos tok2str(slow_oam_link_event_values, "Reserved", 636 1.10 christos type), 637 1.10 christos type, 638 1.10 christos length); 639 1.1 christos 640 1.10 christos if (type == SLOW_OAM_INFO_TYPE_END_OF_TLV) { 641 1.8 spz /* 642 1.8 spz * As IEEE Std 802.3-2015 says for the End of TLV Marker, 643 1.8 spz * "(the length and value of the Type 0x00 TLV can be ignored)". 644 1.8 spz */ 645 1.8 spz return; 646 1.8 spz } 647 1.8 spz 648 1.8 spz /* length includes the type and length fields */ 649 1.10 christos if (length < sizeof(struct slow_oam_tlv_header_t)) { 650 1.10 christos ND_PRINT("\n\t ERROR: illegal length - should be >= %zu", 651 1.10 christos sizeof(struct slow_oam_tlv_header_t)); 652 1.8 spz return; 653 1.8 spz } 654 1.8 spz 655 1.10 christos if (tlen < length) 656 1.8 spz goto tooshort; 657 1.10 christos ND_TCHECK_LEN(tptr, length); 658 1.8 spz 659 1.1 christos hexdump = FALSE; 660 1.10 christos switch (type) { 661 1.1 christos case SLOW_OAM_LINK_EVENT_ERR_SYM_PER: /* identical format - fall through */ 662 1.1 christos case SLOW_OAM_LINK_EVENT_ERR_FRM: 663 1.1 christos case SLOW_OAM_LINK_EVENT_ERR_FRM_PER: 664 1.1 christos case SLOW_OAM_LINK_EVENT_ERR_FRM_SUMM: 665 1.1 christos tlv.slow_oam_link_event = (const struct slow_oam_link_event_t *)tptr; 666 1.5 christos 667 1.10 christos if (GET_U_1(tlv.slow_oam_link_event->event_length) != 668 1.1 christos sizeof(struct slow_oam_link_event_t)) { 669 1.10 christos ND_PRINT("\n\t ERROR: illegal length - should be %zu", 670 1.10 christos sizeof(struct slow_oam_link_event_t)); 671 1.8 spz hexdump = TRUE; 672 1.8 spz goto badlength_event_notif; 673 1.1 christos } 674 1.1 christos 675 1.10 christos ND_PRINT("\n\t Timestamp %u ms, Errored Window %" PRIu64 676 1.1 christos "\n\t Errored Threshold %" PRIu64 677 1.1 christos "\n\t Errors %" PRIu64 678 1.1 christos "\n\t Error Running Total %" PRIu64 679 1.1 christos "\n\t Event Running Total %u", 680 1.10 christos GET_BE_U_2(tlv.slow_oam_link_event->time_stamp)*100, 681 1.10 christos GET_BE_U_8(tlv.slow_oam_link_event->window), 682 1.10 christos GET_BE_U_8(tlv.slow_oam_link_event->threshold), 683 1.10 christos GET_BE_U_8(tlv.slow_oam_link_event->errors), 684 1.10 christos GET_BE_U_8(tlv.slow_oam_link_event->errors_running_total), 685 1.10 christos GET_BE_U_4(tlv.slow_oam_link_event->event_running_total)); 686 1.1 christos break; 687 1.5 christos 688 1.1 christos case SLOW_OAM_LINK_EVENT_ORG_SPECIFIC: 689 1.1 christos hexdump = TRUE; 690 1.1 christos break; 691 1.5 christos 692 1.1 christos default: 693 1.1 christos hexdump = TRUE; 694 1.1 christos break; 695 1.1 christos } 696 1.1 christos 697 1.8 spz badlength_event_notif: 698 1.1 christos /* do we also want to see a hex dump ? */ 699 1.5 christos if (ndo->ndo_vflag > 1 || hexdump==TRUE) { 700 1.5 christos print_unknown_data(ndo, tptr, "\n\t ", 701 1.10 christos length); 702 1.1 christos } 703 1.1 christos 704 1.10 christos tlen -= length; 705 1.10 christos tptr += length; 706 1.1 christos } 707 1.1 christos break; 708 1.5 christos 709 1.1 christos case SLOW_OAM_CODE_LOOPBACK_CTRL: 710 1.1 christos tlv.slow_oam_loopbackctrl = (const struct slow_oam_loopbackctrl_t *)tptr; 711 1.8 spz if (tlen < sizeof(*tlv.slow_oam_loopbackctrl)) 712 1.8 spz goto tooshort; 713 1.10 christos command = GET_U_1(tlv.slow_oam_loopbackctrl->command); 714 1.10 christos ND_PRINT("\n\t Command %s (%u)", 715 1.1 christos tok2str(slow_oam_loopbackctrl_cmd_values, 716 1.1 christos "Unknown", 717 1.10 christos command), 718 1.10 christos command); 719 1.8 spz tptr ++; 720 1.8 spz tlen --; 721 1.1 christos break; 722 1.1 christos 723 1.1 christos /* 724 1.1 christos * FIXME those are the defined codes that lack a decoder 725 1.1 christos * you are welcome to contribute code ;-) 726 1.1 christos */ 727 1.1 christos case SLOW_OAM_CODE_VAR_REQUEST: 728 1.1 christos case SLOW_OAM_CODE_VAR_RESPONSE: 729 1.1 christos case SLOW_OAM_CODE_PRIVATE: 730 1.1 christos default: 731 1.5 christos if (ndo->ndo_vflag <= 1) { 732 1.5 christos print_unknown_data(ndo, tptr, "\n\t ", tlen); 733 1.1 christos } 734 1.1 christos break; 735 1.1 christos } 736 1.1 christos return; 737 1.8 spz 738 1.8 spz tooshort: 739 1.10 christos ND_PRINT("\n\t\t packet is too short"); 740 1.1 christos } 741