print-slow.c 25 KB

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