127df3f5dSRui Paulo /* 227df3f5dSRui Paulo * Redistribution and use in source and binary forms, with or without 327df3f5dSRui Paulo * modification, are permitted provided that: (1) source code 427df3f5dSRui Paulo * distributions retain the above copyright notice and this paragraph 527df3f5dSRui Paulo * in its entirety, and (2) distributions including binary code include 627df3f5dSRui Paulo * the above copyright notice and this paragraph in its entirety in 727df3f5dSRui Paulo * the documentation or other materials provided with the distribution. 827df3f5dSRui Paulo * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 927df3f5dSRui Paulo * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 1027df3f5dSRui Paulo * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 1127df3f5dSRui Paulo * FOR A PARTICULAR PURPOSE. 1227df3f5dSRui Paulo * 1327df3f5dSRui Paulo * Copyright (c) 2009 Mojatatu Networks, Inc 1427df3f5dSRui Paulo * 1527df3f5dSRui Paulo */ 1627df3f5dSRui Paulo 173340d773SGleb Smirnoff /* \summary: Forwarding and Control Element Separation (ForCES) Protocol printer */ 183340d773SGleb Smirnoff 193340d773SGleb Smirnoff /* specification: RFC 5810 */ 203340d773SGleb Smirnoff 21*ee67461eSJoseph Mingrone #include <config.h> 2227df3f5dSRui Paulo 23*ee67461eSJoseph Mingrone #include "netdissect-stdinc.h" 2427df3f5dSRui Paulo 253340d773SGleb Smirnoff #include "netdissect.h" 2627df3f5dSRui Paulo #include "extract.h" 2727df3f5dSRui Paulo 283c602fabSXin LI 293c602fabSXin LI #define ForCES_VERS 1 303c602fabSXin LI #define ForCES_HDRL 24 313c602fabSXin LI #define ForCES_ALNL 4U 323c602fabSXin LI #define TLV_HDRL 4 333c602fabSXin LI #define ILV_HDRL 8 343c602fabSXin LI 353c602fabSXin LI #define TOM_RSVD 0x0 363c602fabSXin LI #define TOM_ASSNSETUP 0x1 373c602fabSXin LI #define TOM_ASSNTEARD 0x2 383c602fabSXin LI #define TOM_CONFIG 0x3 393c602fabSXin LI #define TOM_QUERY 0x4 403c602fabSXin LI #define TOM_EVENTNOT 0x5 413c602fabSXin LI #define TOM_PKTREDIR 0x6 423c602fabSXin LI #define TOM_HEARTBT 0x0F 433c602fabSXin LI #define TOM_ASSNSETREP 0x11 443c602fabSXin LI #define TOM_CONFIGREP 0x13 453c602fabSXin LI #define TOM_QUERYREP 0x14 463c602fabSXin LI 473c602fabSXin LI /* 483c602fabSXin LI * tom_h Flags: resv1(8b):maxtlvs(4b):resv2(2b):mintlv(2b) 493c602fabSXin LI */ 503c602fabSXin LI #define ZERO_TTLV 0x01 513c602fabSXin LI #define ZERO_MORE_TTLV 0x02 523c602fabSXin LI #define ONE_MORE_TTLV 0x04 533c602fabSXin LI #define ZERO_TLV 0x00 543c602fabSXin LI #define ONE_TLV 0x10 553c602fabSXin LI #define TWO_TLV 0x20 563c602fabSXin LI #define MAX_TLV 0xF0 573c602fabSXin LI 583c602fabSXin LI #define TTLV_T1 (ONE_MORE_TTLV|ONE_TLV) 593c602fabSXin LI #define TTLV_T2 (ONE_MORE_TTLV|MAX_TLV) 603c602fabSXin LI 613c602fabSXin LI struct tom_h { 623c602fabSXin LI uint32_t v; 633c602fabSXin LI uint16_t flags; 643c602fabSXin LI uint16_t op_msk; 653c602fabSXin LI const char *s; 66*ee67461eSJoseph Mingrone int (*print) (netdissect_options *ndo, const u_char * pptr, u_int len, 673c602fabSXin LI uint16_t op_msk, int indent); 683c602fabSXin LI }; 693c602fabSXin LI 703c602fabSXin LI enum { 713c602fabSXin LI TOM_RSV_I, 723c602fabSXin LI TOM_ASS_I, 733c602fabSXin LI TOM_AST_I, 743c602fabSXin LI TOM_CFG_I, 753c602fabSXin LI TOM_QRY_I, 763c602fabSXin LI TOM_EVN_I, 773c602fabSXin LI TOM_RED_I, 783c602fabSXin LI TOM_HBT_I, 793c602fabSXin LI TOM_ASR_I, 803c602fabSXin LI TOM_CNR_I, 813c602fabSXin LI TOM_QRR_I, 823c602fabSXin LI _TOM_RSV_MAX 833c602fabSXin LI }; 843c602fabSXin LI #define TOM_MAX_IND (_TOM_RSV_MAX - 1) 853c602fabSXin LI 86*ee67461eSJoseph Mingrone static int 87*ee67461eSJoseph Mingrone tom_valid(uint8_t tom) 883c602fabSXin LI { 893c602fabSXin LI if (tom > 0) { 903c602fabSXin LI if (tom >= 0x7 && tom <= 0xe) 913c602fabSXin LI return 0; 923c602fabSXin LI if (tom == 0x10) 933c602fabSXin LI return 0; 943c602fabSXin LI if (tom > 0x14) 953c602fabSXin LI return 0; 963c602fabSXin LI return 1; 973c602fabSXin LI } else 983c602fabSXin LI return 0; 993c602fabSXin LI } 1003c602fabSXin LI 101*ee67461eSJoseph Mingrone static const char * 102*ee67461eSJoseph Mingrone ForCES_node(uint32_t node) 1033c602fabSXin LI { 1043c602fabSXin LI if (node <= 0x3FFFFFFF) 1053c602fabSXin LI return "FE"; 1063c602fabSXin LI if (node >= 0x40000000 && node <= 0x7FFFFFFF) 1073c602fabSXin LI return "CE"; 1083c602fabSXin LI if (node >= 0xC0000000 && node <= 0xFFFFFFEF) 1093c602fabSXin LI return "AllMulticast"; 1103c602fabSXin LI if (node == 0xFFFFFFFD) 1113c602fabSXin LI return "AllCEsBroadcast"; 1123c602fabSXin LI if (node == 0xFFFFFFFE) 1133c602fabSXin LI return "AllFEsBroadcast"; 1143c602fabSXin LI if (node == 0xFFFFFFFF) 1153c602fabSXin LI return "AllBroadcast"; 1163c602fabSXin LI 1173c602fabSXin LI return "ForCESreserved"; 1183c602fabSXin LI 1193c602fabSXin LI } 1203c602fabSXin LI 1213c602fabSXin LI static const struct tok ForCES_ACKs[] = { 1223c602fabSXin LI {0x0, "NoACK"}, 1233c602fabSXin LI {0x1, "SuccessACK"}, 1243c602fabSXin LI {0x2, "FailureACK"}, 1253c602fabSXin LI {0x3, "AlwaysACK"}, 1263c602fabSXin LI {0, NULL} 1273c602fabSXin LI }; 1283c602fabSXin LI 1293c602fabSXin LI static const struct tok ForCES_EMs[] = { 1303c602fabSXin LI {0x0, "EMReserved"}, 1313c602fabSXin LI {0x1, "execute-all-or-none"}, 1323c602fabSXin LI {0x2, "execute-until-failure"}, 1333c602fabSXin LI {0x3, "continue-execute-on-failure"}, 1343c602fabSXin LI {0, NULL} 1353c602fabSXin LI }; 1363c602fabSXin LI 1373c602fabSXin LI static const struct tok ForCES_ATs[] = { 1383c602fabSXin LI {0x0, "Standalone"}, 1393c602fabSXin LI {0x1, "2PCtransaction"}, 1403c602fabSXin LI {0, NULL} 1413c602fabSXin LI }; 1423c602fabSXin LI 1433c602fabSXin LI static const struct tok ForCES_TPs[] = { 1443c602fabSXin LI {0x0, "StartofTransaction"}, 1453c602fabSXin LI {0x1, "MiddleofTransaction"}, 1463c602fabSXin LI {0x2, "EndofTransaction"}, 1473c602fabSXin LI {0x3, "abort"}, 1483c602fabSXin LI {0, NULL} 1493c602fabSXin LI }; 1503c602fabSXin LI 1513c602fabSXin LI /* 1523c602fabSXin LI * Structure of forces header, naked of TLVs. 1533c602fabSXin LI */ 1543c602fabSXin LI struct forcesh { 1553340d773SGleb Smirnoff nd_uint8_t fm_vrsvd; /* version and reserved */ 156*ee67461eSJoseph Mingrone #define ForCES_V(forcesh) (GET_U_1((forcesh)->fm_vrsvd) >> 4) 1573340d773SGleb Smirnoff nd_uint8_t fm_tom; /* type of message */ 1583340d773SGleb Smirnoff nd_uint16_t fm_len; /* total length * 4 bytes */ 159*ee67461eSJoseph Mingrone #define ForCES_BLN(forcesh) ((uint32_t)(GET_BE_U_2((forcesh)->fm_len) << 2)) 1603340d773SGleb Smirnoff nd_uint32_t fm_sid; /* Source ID */ 161*ee67461eSJoseph Mingrone #define ForCES_SID(forcesh) GET_BE_U_4((forcesh)->fm_sid) 1623340d773SGleb Smirnoff nd_uint32_t fm_did; /* Destination ID */ 163*ee67461eSJoseph Mingrone #define ForCES_DID(forcesh) GET_BE_U_4((forcesh)->fm_did) 1643340d773SGleb Smirnoff nd_uint8_t fm_cor[8]; /* correlator */ 1653340d773SGleb Smirnoff nd_uint32_t fm_flags; /* flags */ 166*ee67461eSJoseph Mingrone #define ForCES_ACK(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0xC0000000) >> 30) 167*ee67461eSJoseph Mingrone #define ForCES_PRI(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x38000000) >> 27) 168*ee67461eSJoseph Mingrone #define ForCES_RS1(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x07000000) >> 24) 169*ee67461eSJoseph Mingrone #define ForCES_EM(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x00C00000) >> 22) 170*ee67461eSJoseph Mingrone #define ForCES_AT(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x00200000) >> 21) 171*ee67461eSJoseph Mingrone #define ForCES_TP(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x00180000) >> 19) 172*ee67461eSJoseph Mingrone #define ForCES_RS2(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x0007FFFF) >> 0) 1733c602fabSXin LI }; 1743c602fabSXin LI 1753c602fabSXin LI #define ForCES_HLN_VALID(fhl,tlen) ((tlen) >= ForCES_HDRL && \ 1763c602fabSXin LI (fhl) >= ForCES_HDRL && \ 1773c602fabSXin LI (fhl) == (tlen)) 1783c602fabSXin LI 1793c602fabSXin LI #define F_LFB_RSVD 0x0 1803c602fabSXin LI #define F_LFB_FEO 0x1 1813c602fabSXin LI #define F_LFB_FEPO 0x2 1823c602fabSXin LI static const struct tok ForCES_LFBs[] = { 1833c602fabSXin LI {F_LFB_RSVD, "Invalid TLV"}, 1843c602fabSXin LI {F_LFB_FEO, "FEObj LFB"}, 1853c602fabSXin LI {F_LFB_FEPO, "FEProtoObj LFB"}, 1863c602fabSXin LI {0, NULL} 1873c602fabSXin LI }; 1883c602fabSXin LI 1898bdc5a62SPatrick Kelsey /* this is defined in RFC5810 section A.2 */ 190*ee67461eSJoseph Mingrone /* https://www.iana.org/assignments/forces/forces.xhtml#oper-tlv-types */ 1913c602fabSXin LI enum { 1928bdc5a62SPatrick Kelsey F_OP_RSV = 0, 1938bdc5a62SPatrick Kelsey F_OP_SET = 1, 1948bdc5a62SPatrick Kelsey F_OP_SETPROP = 2, 1958bdc5a62SPatrick Kelsey F_OP_SETRESP = 3, 1968bdc5a62SPatrick Kelsey F_OP_SETPRESP = 4, 1978bdc5a62SPatrick Kelsey F_OP_DEL = 5, 1988bdc5a62SPatrick Kelsey F_OP_DELRESP = 6, 1998bdc5a62SPatrick Kelsey F_OP_GET = 7, 2008bdc5a62SPatrick Kelsey F_OP_GETPROP = 8, 2018bdc5a62SPatrick Kelsey F_OP_GETRESP = 9, 2028bdc5a62SPatrick Kelsey F_OP_GETPRESP = 10, 2038bdc5a62SPatrick Kelsey F_OP_REPORT = 11, 2048bdc5a62SPatrick Kelsey F_OP_COMMIT = 12, 2058bdc5a62SPatrick Kelsey F_OP_RCOMMIT = 13, 2068bdc5a62SPatrick Kelsey F_OP_RTRCOMP = 14, 2073c602fabSXin LI _F_OP_MAX 2083c602fabSXin LI }; 2093c602fabSXin LI #define F_OP_MAX (_F_OP_MAX - 1) 2108bdc5a62SPatrick Kelsey 2113c602fabSXin LI enum { 2123c602fabSXin LI B_OP_SET = 1 << (F_OP_SET - 1), 2133c602fabSXin LI B_OP_SETPROP = 1 << (F_OP_SETPROP - 1), 2143c602fabSXin LI B_OP_SETRESP = 1 << (F_OP_SETRESP - 1), 2153c602fabSXin LI B_OP_SETPRESP = 1 << (F_OP_SETPRESP - 1), 2163c602fabSXin LI B_OP_DEL = 1 << (F_OP_DEL - 1), 2173c602fabSXin LI B_OP_DELRESP = 1 << (F_OP_DELRESP - 1), 2183c602fabSXin LI B_OP_GET = 1 << (F_OP_GET - 1), 2193c602fabSXin LI B_OP_GETPROP = 1 << (F_OP_GETPROP - 1), 2203c602fabSXin LI B_OP_GETRESP = 1 << (F_OP_GETRESP - 1), 2213c602fabSXin LI B_OP_GETPRESP = 1 << (F_OP_GETPRESP - 1), 2223c602fabSXin LI B_OP_REPORT = 1 << (F_OP_REPORT - 1), 2233c602fabSXin LI B_OP_COMMIT = 1 << (F_OP_COMMIT - 1), 2243c602fabSXin LI B_OP_RCOMMIT = 1 << (F_OP_RCOMMIT - 1), 2253340d773SGleb Smirnoff B_OP_RTRCOMP = 1 << (F_OP_RTRCOMP - 1) 2263c602fabSXin LI }; 2273c602fabSXin LI 2283c602fabSXin LI struct optlv_h { 2293c602fabSXin LI uint16_t flags; 2303c602fabSXin LI uint16_t op_msk; 2313c602fabSXin LI const char *s; 232*ee67461eSJoseph Mingrone int (*print) (netdissect_options *ndo, const u_char * pptr, u_int len, 2333c602fabSXin LI uint16_t op_msk, int indent); 2343c602fabSXin LI }; 2353c602fabSXin LI 236*ee67461eSJoseph Mingrone static int genoptlv_print(netdissect_options *, const u_char * pptr, u_int len, 2373c602fabSXin LI uint16_t op_msk, int indent); 238*ee67461eSJoseph Mingrone static int recpdoptlv_print(netdissect_options *, const u_char * pptr, u_int len, 2393c602fabSXin LI uint16_t op_msk, int indent); 240*ee67461eSJoseph Mingrone static int invoptlv_print(netdissect_options *, const u_char * pptr, u_int len, 2413c602fabSXin LI uint16_t op_msk, int indent); 2423c602fabSXin LI 2433c602fabSXin LI #define OP_MIN_SIZ 8 2443c602fabSXin LI struct pathdata_h { 2453340d773SGleb Smirnoff nd_uint16_t pflags; 2463340d773SGleb Smirnoff nd_uint16_t pIDcnt; 2473c602fabSXin LI }; 2483c602fabSXin LI 2493c602fabSXin LI #define B_FULLD 0x1 2503c602fabSXin LI #define B_SPARD 0x2 2513c602fabSXin LI #define B_RESTV 0x4 2523c602fabSXin LI #define B_KEYIN 0x8 2533c602fabSXin LI #define B_APPND 0x10 2543c602fabSXin LI #define B_TRNG 0x20 2553c602fabSXin LI 2563c602fabSXin LI static const struct optlv_h OPTLV_msg[F_OP_MAX + 1] = { 2573c602fabSXin LI /* F_OP_RSV */ {ZERO_TTLV, 0, "Invalid OPTLV", invoptlv_print}, 2583c602fabSXin LI /* F_OP_SET */ {TTLV_T2, B_FULLD | B_SPARD, " Set", recpdoptlv_print}, 2593c602fabSXin LI /* F_OP_SETPROP */ 2603c602fabSXin LI {TTLV_T2, B_FULLD | B_SPARD, " SetProp", recpdoptlv_print}, 2613c602fabSXin LI /* F_OP_SETRESP */ {TTLV_T2, B_RESTV, " SetResp", recpdoptlv_print}, 2623c602fabSXin LI /* F_OP_SETPRESP */ {TTLV_T2, B_RESTV, " SetPropResp", recpdoptlv_print}, 2633c602fabSXin LI /* F_OP_DEL */ {ZERO_TTLV, 0, " Del", recpdoptlv_print}, 2643c602fabSXin LI /* F_OP_DELRESP */ {TTLV_T2, B_RESTV, " DelResp", recpdoptlv_print}, 2653c602fabSXin LI /* F_OP_GET */ {ZERO_TTLV, 0, " Get", recpdoptlv_print}, 2663c602fabSXin LI /* F_OP_GETPROP */ {ZERO_TTLV, 0, " GetProp", recpdoptlv_print}, 2673c602fabSXin LI /* F_OP_GETRESP */ 2683c602fabSXin LI {TTLV_T2, B_FULLD | B_SPARD | B_RESTV, " GetResp", recpdoptlv_print}, 2693c602fabSXin LI /* F_OP_GETPRESP */ 2703c602fabSXin LI {TTLV_T2, B_FULLD | B_RESTV, " GetPropResp", recpdoptlv_print}, 2713c602fabSXin LI /* F_OP_REPORT */ 2723c602fabSXin LI {TTLV_T2, B_FULLD | B_SPARD, " Report", recpdoptlv_print}, 2733c602fabSXin LI /* F_OP_COMMIT */ {ZERO_TTLV, 0, " Commit", NULL}, 2743c602fabSXin LI /* F_OP_RCOMMIT */ {TTLV_T1, B_RESTV, " RCommit", genoptlv_print}, 2753c602fabSXin LI /* F_OP_RTRCOMP */ {ZERO_TTLV, 0, " RTRCOMP", NULL}, 2763c602fabSXin LI }; 2773c602fabSXin LI 278*ee67461eSJoseph Mingrone static const struct optlv_h * 279*ee67461eSJoseph Mingrone get_forces_optlv_h(uint16_t opt) 2803c602fabSXin LI { 281*ee67461eSJoseph Mingrone if (opt > F_OP_MAX || opt == F_OP_RSV) 2823c602fabSXin LI return &OPTLV_msg[F_OP_RSV]; 2833c602fabSXin LI 2843c602fabSXin LI return &OPTLV_msg[opt]; 2853c602fabSXin LI } 2863c602fabSXin LI 2873c602fabSXin LI #define IND_SIZE 256 2883c602fabSXin LI #define IND_CHR ' ' 2893c602fabSXin LI #define IND_PREF '\n' 2903c602fabSXin LI #define IND_SUF 0x0 2913340d773SGleb Smirnoff static char ind_buf[IND_SIZE]; 2923c602fabSXin LI 293*ee67461eSJoseph Mingrone static char * 294*ee67461eSJoseph Mingrone indent_pr(int indent, int nlpref) 2953c602fabSXin LI { 2963c602fabSXin LI int i = 0; 2973c602fabSXin LI char *r = ind_buf; 2983c602fabSXin LI 2993c602fabSXin LI if (indent > (IND_SIZE - 1)) 3003c602fabSXin LI indent = IND_SIZE - 1; 3013c602fabSXin LI 3023c602fabSXin LI if (nlpref) { 3033c602fabSXin LI r[i] = IND_PREF; 3043c602fabSXin LI i++; 3053c602fabSXin LI indent--; 3063c602fabSXin LI } 3073c602fabSXin LI 3083c602fabSXin LI while (--indent >= 0) 3093c602fabSXin LI r[i++] = IND_CHR; 3103c602fabSXin LI 3113c602fabSXin LI r[i] = IND_SUF; 3123c602fabSXin LI return r; 3133c602fabSXin LI } 3143c602fabSXin LI 315*ee67461eSJoseph Mingrone static int 316*ee67461eSJoseph Mingrone op_valid(uint16_t op, uint16_t mask) 3173c602fabSXin LI { 3183c602fabSXin LI if (op == 0) 3193c602fabSXin LI return 0; 320*ee67461eSJoseph Mingrone if (op <= F_OP_MAX) 321*ee67461eSJoseph Mingrone return (1 << (op - 1)) & mask; /* works only for 0x0001 through 0x0010 */ 3223c602fabSXin LI /* I guess we should allow vendor operations? */ 3233c602fabSXin LI if (op >= 0x8000) 3243c602fabSXin LI return 1; 3253c602fabSXin LI return 0; 3263c602fabSXin LI } 3273c602fabSXin LI 3283c602fabSXin LI #define F_TLV_RSVD 0x0000 3293c602fabSXin LI #define F_TLV_REDR 0x0001 3303c602fabSXin LI #define F_TLV_ASRS 0x0010 3313c602fabSXin LI #define F_TLV_ASRT 0x0011 3323c602fabSXin LI #define F_TLV_LFBS 0x1000 3333c602fabSXin LI #define F_TLV_PDAT 0x0110 3343c602fabSXin LI #define F_TLV_KEYI 0x0111 3353c602fabSXin LI #define F_TLV_FULD 0x0112 3363c602fabSXin LI #define F_TLV_SPAD 0x0113 3373c602fabSXin LI #define F_TLV_REST 0x0114 3383c602fabSXin LI #define F_TLV_METD 0x0115 3393c602fabSXin LI #define F_TLV_REDD 0x0116 3403c602fabSXin LI #define F_TLV_TRNG 0x0117 3413c602fabSXin LI 3423c602fabSXin LI 3433c602fabSXin LI #define F_TLV_VNST 0x8000 3443c602fabSXin LI 3453c602fabSXin LI static const struct tok ForCES_TLV[] = { 3463c602fabSXin LI {F_TLV_RSVD, "Invalid TLV"}, 3473c602fabSXin LI {F_TLV_REDR, "REDIRECT TLV"}, 3483c602fabSXin LI {F_TLV_ASRS, "ASResult TLV"}, 3493c602fabSXin LI {F_TLV_ASRT, "ASTreason TLV"}, 3503c602fabSXin LI {F_TLV_LFBS, "LFBselect TLV"}, 3513c602fabSXin LI {F_TLV_PDAT, "PATH-DATA TLV"}, 3523c602fabSXin LI {F_TLV_KEYI, "KEYINFO TLV"}, 3533c602fabSXin LI {F_TLV_FULD, "FULLDATA TLV"}, 3543c602fabSXin LI {F_TLV_SPAD, "SPARSEDATA TLV"}, 3553c602fabSXin LI {F_TLV_REST, "RESULT TLV"}, 3563c602fabSXin LI {F_TLV_METD, "METADATA TLV"}, 3573c602fabSXin LI {F_TLV_REDD, "REDIRECTDATA TLV"}, 3583c602fabSXin LI {0, NULL} 3593c602fabSXin LI }; 3603c602fabSXin LI 3613c602fabSXin LI #define TLV_HLN 4 362*ee67461eSJoseph Mingrone static int 363*ee67461eSJoseph Mingrone ttlv_valid(uint16_t ttlv) 3643c602fabSXin LI { 3653c602fabSXin LI if (ttlv > 0) { 3663c602fabSXin LI if (ttlv == 1 || ttlv == 0x1000) 3673c602fabSXin LI return 1; 3683c602fabSXin LI if (ttlv >= 0x10 && ttlv <= 0x11) 3693c602fabSXin LI return 1; 3703c602fabSXin LI if (ttlv >= 0x110 && ttlv <= 0x116) 3713c602fabSXin LI return 1; 3723c602fabSXin LI if (ttlv >= 0x8000) 3733c602fabSXin LI return 0; /* XXX: */ 3743c602fabSXin LI } 3753c602fabSXin LI 3763c602fabSXin LI return 0; 3773c602fabSXin LI } 3783c602fabSXin LI 3793c602fabSXin LI struct forces_ilv { 3803340d773SGleb Smirnoff nd_uint32_t type; 3813340d773SGleb Smirnoff nd_uint32_t length; 3823c602fabSXin LI }; 3833c602fabSXin LI 3843c602fabSXin LI struct forces_tlv { 3853340d773SGleb Smirnoff nd_uint16_t type; 3863340d773SGleb Smirnoff nd_uint16_t length; 3873c602fabSXin LI }; 3883c602fabSXin LI 389*ee67461eSJoseph Mingrone #define F_ALN_LEN(len) roundup2(len, ForCES_ALNL) 3903340d773SGleb Smirnoff #define GET_TOP_TLV(fhdr) ((const struct forces_tlv *)((fhdr) + sizeof (struct forcesh))) 3913c602fabSXin LI #define TLV_SET_LEN(len) (F_ALN_LEN(TLV_HDRL) + (len)) 3923340d773SGleb Smirnoff #define TLV_DATA(tlvp) ((const void*)(((const char*)(tlvp)) + TLV_SET_LEN(0))) 393*ee67461eSJoseph Mingrone #define GO_NXT_TLV(tlv,rlen) ((rlen) -= F_ALN_LEN(GET_BE_U_2((tlv)->length)), \ 3943340d773SGleb Smirnoff (const struct forces_tlv*)(((const char*)(tlv)) \ 395*ee67461eSJoseph Mingrone + F_ALN_LEN(GET_BE_U_2((tlv)->length)))) 3963c602fabSXin LI #define ILV_SET_LEN(len) (F_ALN_LEN(ILV_HDRL) + (len)) 3973340d773SGleb Smirnoff #define ILV_DATA(ilvp) ((const void*)(((const char*)(ilvp)) + ILV_SET_LEN(0))) 398*ee67461eSJoseph Mingrone #define GO_NXT_ILV(ilv,rlen) ((rlen) -= F_ALN_LEN(GET_BE_U_4((ilv)->length)), \ 3993340d773SGleb Smirnoff (const struct forces_ilv *)(((const char*)(ilv)) \ 400*ee67461eSJoseph Mingrone + F_ALN_LEN(GET_BE_U_4((ilv)->length)))) 4013c602fabSXin LI #define INVALID_RLEN 1 4023c602fabSXin LI #define INVALID_STLN 2 4033c602fabSXin LI #define INVALID_LTLN 3 4043c602fabSXin LI #define INVALID_ALEN 4 4053c602fabSXin LI 4063c602fabSXin LI static const struct tok ForCES_TLV_err[] = { 4073c602fabSXin LI {INVALID_RLEN, "Invalid total length"}, 4083c602fabSXin LI {INVALID_STLN, "xLV too short"}, 4093c602fabSXin LI {INVALID_LTLN, "xLV too long"}, 4103c602fabSXin LI {INVALID_ALEN, "data padding missing"}, 4113c602fabSXin LI {0, NULL} 4123c602fabSXin LI }; 4133c602fabSXin LI 414*ee67461eSJoseph Mingrone static u_int 415*ee67461eSJoseph Mingrone tlv_valid(u_int tlvl, u_int rlen) 4163c602fabSXin LI { 4173c602fabSXin LI if (rlen < TLV_HDRL) 4183c602fabSXin LI return INVALID_RLEN; 419*ee67461eSJoseph Mingrone if (tlvl < TLV_HDRL) 4203c602fabSXin LI return INVALID_STLN; 421*ee67461eSJoseph Mingrone if (tlvl > rlen) 4223c602fabSXin LI return INVALID_LTLN; 423*ee67461eSJoseph Mingrone if (rlen < F_ALN_LEN(tlvl)) 4243c602fabSXin LI return INVALID_ALEN; 4253c602fabSXin LI 4263c602fabSXin LI return 0; 4273c602fabSXin LI } 4283c602fabSXin LI 429*ee67461eSJoseph Mingrone static int 430*ee67461eSJoseph Mingrone ilv_valid(netdissect_options *ndo, const struct forces_ilv *ilv, u_int rlen) 4313c602fabSXin LI { 4323c602fabSXin LI if (rlen < ILV_HDRL) 4333c602fabSXin LI return INVALID_RLEN; 434*ee67461eSJoseph Mingrone if (GET_BE_U_4(ilv->length) < ILV_HDRL) 4353c602fabSXin LI return INVALID_STLN; 436*ee67461eSJoseph Mingrone if (GET_BE_U_4(ilv->length) > rlen) 4373c602fabSXin LI return INVALID_LTLN; 438*ee67461eSJoseph Mingrone if (rlen < F_ALN_LEN(GET_BE_U_4(ilv->length))) 4393c602fabSXin LI return INVALID_ALEN; 4403c602fabSXin LI 4413c602fabSXin LI return 0; 4423c602fabSXin LI } 4433c602fabSXin LI 444*ee67461eSJoseph Mingrone static int lfbselect_print(netdissect_options *, const u_char * pptr, u_int len, 4453c602fabSXin LI uint16_t op_msk, int indent); 446*ee67461eSJoseph Mingrone static int redirect_print(netdissect_options *, const u_char * pptr, u_int len, 4473c602fabSXin LI uint16_t op_msk, int indent); 448*ee67461eSJoseph Mingrone static int asrtlv_print(netdissect_options *, const u_char * pptr, u_int len, 4493c602fabSXin LI uint16_t op_msk, int indent); 450*ee67461eSJoseph Mingrone static int asttlv_print(netdissect_options *, const u_char * pptr, u_int len, 4513c602fabSXin LI uint16_t op_msk, int indent); 4523c602fabSXin LI 4533c602fabSXin LI struct forces_lfbsh { 4543340d773SGleb Smirnoff nd_uint32_t class; 4553340d773SGleb Smirnoff nd_uint32_t instance; 4563c602fabSXin LI }; 4573c602fabSXin LI 4583c602fabSXin LI #define ASSNS_OPS (B_OP_REPORT) 4593c602fabSXin LI #define CFG_OPS (B_OP_SET|B_OP_SETPROP|B_OP_DEL|B_OP_COMMIT|B_OP_RTRCOMP) 4603c602fabSXin LI #define CFG_ROPS (B_OP_SETRESP|B_OP_SETPRESP|B_OP_DELRESP|B_OP_RCOMMIT) 4613c602fabSXin LI #define CFG_QY (B_OP_GET|B_OP_GETPROP) 4623c602fabSXin LI #define CFG_QYR (B_OP_GETRESP|B_OP_GETPRESP) 4633c602fabSXin LI #define CFG_EVN (B_OP_REPORT) 4643c602fabSXin LI 4653c602fabSXin LI static const struct tom_h ForCES_msg[TOM_MAX_IND + 1] = { 4663c602fabSXin LI /* TOM_RSV_I */ {TOM_RSVD, ZERO_TTLV, 0, "Invalid message", NULL}, 4673c602fabSXin LI /* TOM_ASS_I */ {TOM_ASSNSETUP, ZERO_MORE_TTLV | TWO_TLV, ASSNS_OPS, 4683c602fabSXin LI "Association Setup", lfbselect_print}, 4693c602fabSXin LI /* TOM_AST_I */ 4703c602fabSXin LI {TOM_ASSNTEARD, TTLV_T1, 0, "Association TearDown", asttlv_print}, 4713c602fabSXin LI /* TOM_CFG_I */ {TOM_CONFIG, TTLV_T2, CFG_OPS, "Config", lfbselect_print}, 4723c602fabSXin LI /* TOM_QRY_I */ {TOM_QUERY, TTLV_T2, CFG_QY, "Query", lfbselect_print}, 4733c602fabSXin LI /* TOM_EVN_I */ {TOM_EVENTNOT, TTLV_T1, CFG_EVN, "Event Notification", 4743c602fabSXin LI lfbselect_print}, 4753c602fabSXin LI /* TOM_RED_I */ 4763c602fabSXin LI {TOM_PKTREDIR, TTLV_T2, 0, "Packet Redirect", redirect_print}, 4773c602fabSXin LI /* TOM_HBT_I */ {TOM_HEARTBT, ZERO_TTLV, 0, "HeartBeat", NULL}, 4783c602fabSXin LI /* TOM_ASR_I */ 4793c602fabSXin LI {TOM_ASSNSETREP, TTLV_T1, 0, "Association Response", asrtlv_print}, 4803c602fabSXin LI /* TOM_CNR_I */ {TOM_CONFIGREP, TTLV_T2, CFG_ROPS, "Config Response", 4813c602fabSXin LI lfbselect_print}, 4823c602fabSXin LI /* TOM_QRR_I */ 4833c602fabSXin LI {TOM_QUERYREP, TTLV_T2, CFG_QYR, "Query Response", lfbselect_print}, 4843c602fabSXin LI }; 4853c602fabSXin LI 486*ee67461eSJoseph Mingrone static const struct tom_h * 487*ee67461eSJoseph Mingrone get_forces_tom(uint8_t tom) 4883c602fabSXin LI { 4893c602fabSXin LI int i; 4903c602fabSXin LI for (i = TOM_RSV_I; i <= TOM_MAX_IND; i++) { 4913c602fabSXin LI const struct tom_h *th = &ForCES_msg[i]; 4923c602fabSXin LI if (th->v == tom) 4933c602fabSXin LI return th; 4943c602fabSXin LI } 4953c602fabSXin LI return &ForCES_msg[TOM_RSV_I]; 4963c602fabSXin LI } 4973c602fabSXin LI 4983c602fabSXin LI struct pdata_ops { 4993c602fabSXin LI uint32_t v; 5003c602fabSXin LI uint16_t flags; 5013c602fabSXin LI uint16_t op_msk; 5023c602fabSXin LI const char *s; 503*ee67461eSJoseph Mingrone int (*print) (netdissect_options *, const u_char * pptr, u_int len, 5043c602fabSXin LI uint16_t op_msk, int indent); 5053c602fabSXin LI }; 5063c602fabSXin LI 5073c602fabSXin LI enum { 5083c602fabSXin LI PD_RSV_I, 5093c602fabSXin LI PD_SEL_I, 5103c602fabSXin LI PD_FDT_I, 5113c602fabSXin LI PD_SDT_I, 5123c602fabSXin LI PD_RES_I, 5133c602fabSXin LI PD_PDT_I, 5143c602fabSXin LI _PD_RSV_MAX 5153c602fabSXin LI }; 5163c602fabSXin LI #define PD_MAX_IND (_TOM_RSV_MAX - 1) 5173c602fabSXin LI 518*ee67461eSJoseph Mingrone static int 519*ee67461eSJoseph Mingrone pd_valid(uint16_t pd) 5203c602fabSXin LI { 5213c602fabSXin LI if (pd >= F_TLV_PDAT && pd <= F_TLV_REST) 5223c602fabSXin LI return 1; 5233c602fabSXin LI return 0; 5243c602fabSXin LI } 5253c602fabSXin LI 526*ee67461eSJoseph Mingrone static void 5273c602fabSXin LI chk_op_type(netdissect_options *ndo, 5283c602fabSXin LI uint16_t type, uint16_t msk, uint16_t omsk) 5293c602fabSXin LI { 5303c602fabSXin LI if (type != F_TLV_PDAT) { 5313c602fabSXin LI if (msk & B_KEYIN) { 5323c602fabSXin LI if (type != F_TLV_KEYI) { 533*ee67461eSJoseph Mingrone ND_PRINT("Based on flags expected KEYINFO TLV!\n"); 5343c602fabSXin LI } 5353c602fabSXin LI } else { 5363c602fabSXin LI if (!(msk & omsk)) { 537*ee67461eSJoseph Mingrone ND_PRINT("Illegal DATA encoding for type 0x%x programmed %x got %x\n", 538*ee67461eSJoseph Mingrone type, omsk, msk); 5393c602fabSXin LI } 5403c602fabSXin LI } 5413c602fabSXin LI } 5423c602fabSXin LI 5433c602fabSXin LI } 5443c602fabSXin LI 5453c602fabSXin LI #define F_SELKEY 1 5463c602fabSXin LI #define F_SELTABRANGE 2 5473c602fabSXin LI #define F_TABAPPEND 4 5483c602fabSXin LI 5493c602fabSXin LI struct res_val { 5503340d773SGleb Smirnoff nd_uint8_t result; 5513340d773SGleb Smirnoff nd_uint8_t resv1; 5523340d773SGleb Smirnoff nd_uint16_t resv2; 5533c602fabSXin LI }; 5543c602fabSXin LI 555*ee67461eSJoseph Mingrone static int prestlv_print(netdissect_options *, const u_char * pptr, u_int len, 5563c602fabSXin LI uint16_t op_msk, int indent); 557*ee67461eSJoseph Mingrone static int pkeyitlv_print(netdissect_options *, const u_char * pptr, u_int len, 5583c602fabSXin LI uint16_t op_msk, int indent); 559*ee67461eSJoseph Mingrone static int fdatatlv_print(netdissect_options *, const u_char * pptr, u_int len, 5603c602fabSXin LI uint16_t op_msk, int indent); 561*ee67461eSJoseph Mingrone static int sdatatlv_print(netdissect_options *, const u_char * pptr, u_int len, 5623c602fabSXin LI uint16_t op_msk, int indent); 5633c602fabSXin LI 5643c602fabSXin LI static const struct pdata_ops ForCES_pdata[PD_MAX_IND + 1] = { 5653c602fabSXin LI /* PD_RSV_I */ {0, 0, 0, "Invalid message", NULL}, 5663c602fabSXin LI /* PD_SEL_I */ {F_TLV_KEYI, 0, 0, "KEYINFO TLV", pkeyitlv_print}, 5673c602fabSXin LI /* PD_FDT_I */ {F_TLV_FULD, 0, B_FULLD, "FULLDATA TLV", fdatatlv_print}, 5683c602fabSXin LI /* PD_SDT_I */ {F_TLV_SPAD, 0, B_SPARD, "SPARSEDATA TLV", sdatatlv_print}, 5693c602fabSXin LI /* PD_RES_I */ {F_TLV_REST, 0, B_RESTV, "RESULT TLV", prestlv_print}, 5703c602fabSXin LI /* PD_PDT_I */ 5713c602fabSXin LI {F_TLV_PDAT, 0, 0, "Inner PATH-DATA TLV", recpdoptlv_print}, 5723c602fabSXin LI }; 5733c602fabSXin LI 574*ee67461eSJoseph Mingrone static const struct pdata_ops * 575*ee67461eSJoseph Mingrone get_forces_pd(uint16_t pd) 5763c602fabSXin LI { 5773c602fabSXin LI int i; 5783c602fabSXin LI for (i = PD_RSV_I + 1; i <= PD_MAX_IND; i++) { 5793c602fabSXin LI const struct pdata_ops *pdo = &ForCES_pdata[i]; 5803c602fabSXin LI if (pdo->v == pd) 5813c602fabSXin LI return pdo; 5823c602fabSXin LI } 5833c602fabSXin LI return &ForCES_pdata[TOM_RSV_I]; 5843c602fabSXin LI } 5853c602fabSXin LI 5863c602fabSXin LI enum { 5873c602fabSXin LI E_SUCCESS, 5883c602fabSXin LI E_INVALID_HEADER, 5893c602fabSXin LI E_LENGTH_MISMATCH, 5903c602fabSXin LI E_VERSION_MISMATCH, 5913c602fabSXin LI E_INVALID_DESTINATION_PID, 5923c602fabSXin LI E_LFB_UNKNOWN, 5933c602fabSXin LI E_LFB_NOT_FOUND, 5943c602fabSXin LI E_LFB_INSTANCE_ID_NOT_FOUND, 5953c602fabSXin LI E_INVALID_PATH, 5963c602fabSXin LI E_COMPONENT_DOES_NOT_EXIST, 5973c602fabSXin LI E_EXISTS, 5983c602fabSXin LI E_NOT_FOUND, 5993c602fabSXin LI E_READ_ONLY, 6003c602fabSXin LI E_INVALID_ARRAY_CREATION, 6013c602fabSXin LI E_VALUE_OUT_OF_RANGE, 6023c602fabSXin LI E_CONTENTS_TOO_LONG, 6033c602fabSXin LI E_INVALID_PARAMETERS, 6043c602fabSXin LI E_INVALID_MESSAGE_TYPE, 6053c602fabSXin LI E_INVALID_FLAGS, 6063c602fabSXin LI E_INVALID_TLV, 6073c602fabSXin LI E_EVENT_ERROR, 6083c602fabSXin LI E_NOT_SUPPORTED, 6093c602fabSXin LI E_MEMORY_ERROR, 6103c602fabSXin LI E_INTERNAL_ERROR, 6113c602fabSXin LI /* 0x18-0xFE are reserved .. */ 6123c602fabSXin LI E_UNSPECIFIED_ERROR = 0XFF 6133c602fabSXin LI }; 6143c602fabSXin LI 6153c602fabSXin LI static const struct tok ForCES_errs[] = { 6163c602fabSXin LI {E_SUCCESS, "SUCCESS"}, 6173c602fabSXin LI {E_INVALID_HEADER, "INVALID HEADER"}, 6183c602fabSXin LI {E_LENGTH_MISMATCH, "LENGTH MISMATCH"}, 6193c602fabSXin LI {E_VERSION_MISMATCH, "VERSION MISMATCH"}, 6203c602fabSXin LI {E_INVALID_DESTINATION_PID, "INVALID DESTINATION PID"}, 6213c602fabSXin LI {E_LFB_UNKNOWN, "LFB UNKNOWN"}, 6223c602fabSXin LI {E_LFB_NOT_FOUND, "LFB NOT FOUND"}, 6233c602fabSXin LI {E_LFB_INSTANCE_ID_NOT_FOUND, "LFB INSTANCE ID NOT FOUND"}, 6243c602fabSXin LI {E_INVALID_PATH, "INVALID PATH"}, 6253c602fabSXin LI {E_COMPONENT_DOES_NOT_EXIST, "COMPONENT DOES NOT EXIST"}, 6263c602fabSXin LI {E_EXISTS, "EXISTS ALREADY"}, 6273c602fabSXin LI {E_NOT_FOUND, "NOT FOUND"}, 6283c602fabSXin LI {E_READ_ONLY, "READ ONLY"}, 6293c602fabSXin LI {E_INVALID_ARRAY_CREATION, "INVALID ARRAY CREATION"}, 6303c602fabSXin LI {E_VALUE_OUT_OF_RANGE, "VALUE OUT OF RANGE"}, 6313c602fabSXin LI {E_CONTENTS_TOO_LONG, "CONTENTS TOO LONG"}, 6323c602fabSXin LI {E_INVALID_PARAMETERS, "INVALID PARAMETERS"}, 6333c602fabSXin LI {E_INVALID_MESSAGE_TYPE, "INVALID MESSAGE TYPE"}, 6343c602fabSXin LI {E_INVALID_FLAGS, "INVALID FLAGS"}, 6353c602fabSXin LI {E_INVALID_TLV, "INVALID TLV"}, 6363c602fabSXin LI {E_EVENT_ERROR, "EVENT ERROR"}, 6373c602fabSXin LI {E_NOT_SUPPORTED, "NOT SUPPORTED"}, 6383c602fabSXin LI {E_MEMORY_ERROR, "MEMORY ERROR"}, 6393c602fabSXin LI {E_INTERNAL_ERROR, "INTERNAL ERROR"}, 6403c602fabSXin LI {E_UNSPECIFIED_ERROR, "UNSPECIFIED ERROR"}, 6413c602fabSXin LI {0, NULL} 6423c602fabSXin LI }; 64327df3f5dSRui Paulo 64427df3f5dSRui Paulo #define RESLEN 4 64527df3f5dSRui Paulo 6463c602fabSXin LI static int 6473c602fabSXin LI prestlv_print(netdissect_options *ndo, 648*ee67461eSJoseph Mingrone const u_char * pptr, u_int len, 6493c602fabSXin LI uint16_t op_msk _U_, int indent) 65027df3f5dSRui Paulo { 6513340d773SGleb Smirnoff const struct forces_tlv *tlv = (const struct forces_tlv *)pptr; 652*ee67461eSJoseph Mingrone const u_char *tdp = (const u_char *) TLV_DATA(tlv); 6533340d773SGleb Smirnoff const struct res_val *r = (const struct res_val *)tdp; 65427df3f5dSRui Paulo u_int dlen; 655*ee67461eSJoseph Mingrone uint8_t result; 65627df3f5dSRui Paulo 65727df3f5dSRui Paulo /* 65827df3f5dSRui Paulo * pdatacnt_print() has ensured that len (the TLV length) 65927df3f5dSRui Paulo * >= TLV_HDRL. 66027df3f5dSRui Paulo */ 66127df3f5dSRui Paulo dlen = len - TLV_HDRL; 66227df3f5dSRui Paulo if (dlen != RESLEN) { 663*ee67461eSJoseph Mingrone ND_PRINT("illegal RESULT-TLV: %u bytes!\n", dlen); 66427df3f5dSRui Paulo return -1; 66527df3f5dSRui Paulo } 66627df3f5dSRui Paulo 667*ee67461eSJoseph Mingrone ND_TCHECK_SIZE(r); 668*ee67461eSJoseph Mingrone result = GET_U_1(r->result); 669*ee67461eSJoseph Mingrone if (result >= 0x18 && result <= 0xFE) { 670*ee67461eSJoseph Mingrone ND_PRINT("illegal reserved result code: 0x%x!\n", result); 67127df3f5dSRui Paulo return -1; 67227df3f5dSRui Paulo } 67327df3f5dSRui Paulo 6743c602fabSXin LI if (ndo->ndo_vflag >= 3) { 67527df3f5dSRui Paulo char *ib = indent_pr(indent, 0); 676*ee67461eSJoseph Mingrone ND_PRINT("%s Result: %s (code 0x%x)\n", ib, 677*ee67461eSJoseph Mingrone tok2str(ForCES_errs, NULL, result), result); 67827df3f5dSRui Paulo } 67927df3f5dSRui Paulo return 0; 68027df3f5dSRui Paulo 68127df3f5dSRui Paulo trunc: 682*ee67461eSJoseph Mingrone nd_print_trunc(ndo); 68327df3f5dSRui Paulo return -1; 68427df3f5dSRui Paulo } 68527df3f5dSRui Paulo 6863c602fabSXin LI static int 6873c602fabSXin LI fdatatlv_print(netdissect_options *ndo, 688*ee67461eSJoseph Mingrone const u_char * pptr, u_int len, 6893c602fabSXin LI uint16_t op_msk _U_, int indent) 69027df3f5dSRui Paulo { 6913340d773SGleb Smirnoff const struct forces_tlv *tlv = (const struct forces_tlv *)pptr; 69227df3f5dSRui Paulo u_int rlen; 693*ee67461eSJoseph Mingrone const u_char *tdp = (const u_char *) TLV_DATA(tlv); 6943c602fabSXin LI uint16_t type; 69527df3f5dSRui Paulo 69627df3f5dSRui Paulo /* 69727df3f5dSRui Paulo * pdatacnt_print() or pkeyitlv_print() has ensured that len 69827df3f5dSRui Paulo * (the TLV length) >= TLV_HDRL. 69927df3f5dSRui Paulo */ 70027df3f5dSRui Paulo rlen = len - TLV_HDRL; 701*ee67461eSJoseph Mingrone ND_TCHECK_SIZE(tlv); 702*ee67461eSJoseph Mingrone type = GET_BE_U_2(tlv->type); 70327df3f5dSRui Paulo if (type != F_TLV_FULD) { 704*ee67461eSJoseph Mingrone ND_PRINT("Error: expecting FULLDATA!\n"); 70527df3f5dSRui Paulo return -1; 70627df3f5dSRui Paulo } 70727df3f5dSRui Paulo 7083c602fabSXin LI if (ndo->ndo_vflag >= 3) { 70927df3f5dSRui Paulo char *ib = indent_pr(indent + 2, 1); 710*ee67461eSJoseph Mingrone ND_PRINT("%s[", ib + 1); 711*ee67461eSJoseph Mingrone hex_print(ndo, ib, tdp, rlen); 712*ee67461eSJoseph Mingrone ND_PRINT("\n%s]", ib + 1); 71327df3f5dSRui Paulo } 71427df3f5dSRui Paulo return 0; 71527df3f5dSRui Paulo 71627df3f5dSRui Paulo trunc: 717*ee67461eSJoseph Mingrone nd_print_trunc(ndo); 71827df3f5dSRui Paulo return -1; 71927df3f5dSRui Paulo } 72027df3f5dSRui Paulo 7213c602fabSXin LI static int 7223c602fabSXin LI sdatailv_print(netdissect_options *ndo, 723*ee67461eSJoseph Mingrone const u_char * pptr, u_int len, 7243c602fabSXin LI uint16_t op_msk _U_, int indent) 72527df3f5dSRui Paulo { 72627df3f5dSRui Paulo u_int rlen; 7273340d773SGleb Smirnoff const struct forces_ilv *ilv = (const struct forces_ilv *)pptr; 72827df3f5dSRui Paulo int invilv; 72927df3f5dSRui Paulo 73027df3f5dSRui Paulo if (len < ILV_HDRL) { 731*ee67461eSJoseph Mingrone ND_PRINT("Error: BAD SPARSEDATA-TLV!\n"); 73227df3f5dSRui Paulo return -1; 73327df3f5dSRui Paulo } 734d09a7e67SXin LI rlen = len; 73527df3f5dSRui Paulo indent += 1; 73627df3f5dSRui Paulo while (rlen != 0) { 7373c602fabSXin LI #if 0 738*ee67461eSJoseph Mingrone ND_PRINT("Jamal - outstanding length <%u>\n", rlen); 7393c602fabSXin LI #endif 740d09a7e67SXin LI char *ib = indent_pr(indent, 1); 741*ee67461eSJoseph Mingrone const u_char *tdp = (const u_char *) ILV_DATA(ilv); 742*ee67461eSJoseph Mingrone invilv = ilv_valid(ndo, ilv, rlen); 74327df3f5dSRui Paulo if (invilv) { 744*ee67461eSJoseph Mingrone ND_PRINT("Error: %s, rlen %u\n", 745*ee67461eSJoseph Mingrone tok2str(ForCES_TLV_err, NULL, invilv), rlen); 746d09a7e67SXin LI return -1; 747d09a7e67SXin LI } 7483c602fabSXin LI if (ndo->ndo_vflag >= 3) { 749*ee67461eSJoseph Mingrone u_int ilvl = GET_BE_U_4(ilv->length); 750*ee67461eSJoseph Mingrone ND_PRINT("\n%s ILV: type %x length %u\n", ib + 1, 751*ee67461eSJoseph Mingrone GET_BE_U_4(ilv->type), ilvl); 752*ee67461eSJoseph Mingrone hex_print(ndo, "\t\t[", tdp, ilvl-ILV_HDRL); 75327df3f5dSRui Paulo } 75427df3f5dSRui Paulo 75527df3f5dSRui Paulo ilv = GO_NXT_ILV(ilv, rlen); 75627df3f5dSRui Paulo } 75727df3f5dSRui Paulo 75827df3f5dSRui Paulo return 0; 75927df3f5dSRui Paulo } 76027df3f5dSRui Paulo 7613c602fabSXin LI static int 7623c602fabSXin LI sdatatlv_print(netdissect_options *ndo, 763*ee67461eSJoseph Mingrone const u_char * pptr, u_int len, 7643c602fabSXin LI uint16_t op_msk, int indent) 76527df3f5dSRui Paulo { 7663340d773SGleb Smirnoff const struct forces_tlv *tlv = (const struct forces_tlv *)pptr; 76727df3f5dSRui Paulo u_int rlen; 768*ee67461eSJoseph Mingrone const u_char *tdp = (const u_char *) TLV_DATA(tlv); 7693c602fabSXin LI uint16_t type; 77027df3f5dSRui Paulo 77127df3f5dSRui Paulo /* 77227df3f5dSRui Paulo * pdatacnt_print() has ensured that len (the TLV length) 77327df3f5dSRui Paulo * >= TLV_HDRL. 77427df3f5dSRui Paulo */ 77527df3f5dSRui Paulo rlen = len - TLV_HDRL; 776*ee67461eSJoseph Mingrone ND_TCHECK_SIZE(tlv); 777*ee67461eSJoseph Mingrone type = GET_BE_U_2(tlv->type); 77827df3f5dSRui Paulo if (type != F_TLV_SPAD) { 779*ee67461eSJoseph Mingrone ND_PRINT("Error: expecting SPARSEDATA!\n"); 78027df3f5dSRui Paulo return -1; 78127df3f5dSRui Paulo } 78227df3f5dSRui Paulo 7833c602fabSXin LI return sdatailv_print(ndo, tdp, rlen, op_msk, indent); 78427df3f5dSRui Paulo 78527df3f5dSRui Paulo trunc: 786*ee67461eSJoseph Mingrone nd_print_trunc(ndo); 78727df3f5dSRui Paulo return -1; 78827df3f5dSRui Paulo } 78927df3f5dSRui Paulo 7903c602fabSXin LI static int 7913c602fabSXin LI pkeyitlv_print(netdissect_options *ndo, 792*ee67461eSJoseph Mingrone const u_char * pptr, u_int len, 7933c602fabSXin LI uint16_t op_msk, int indent) 79427df3f5dSRui Paulo { 7953340d773SGleb Smirnoff const struct forces_tlv *tlv = (const struct forces_tlv *)pptr; 796*ee67461eSJoseph Mingrone const u_char *tdp = (const u_char *) TLV_DATA(tlv); 797*ee67461eSJoseph Mingrone const u_char *dp = tdp + 4; 7983340d773SGleb Smirnoff const struct forces_tlv *kdtlv = (const struct forces_tlv *)dp; 7993c602fabSXin LI uint32_t id; 80027df3f5dSRui Paulo char *ib = indent_pr(indent, 0); 8013c602fabSXin LI uint16_t type, tll; 8023c602fabSXin LI u_int invtlv; 80327df3f5dSRui Paulo 804*ee67461eSJoseph Mingrone id = GET_BE_U_4(tdp); 805*ee67461eSJoseph Mingrone ND_PRINT("%sKeyinfo: Key 0x%x\n", ib, id); 806*ee67461eSJoseph Mingrone type = GET_BE_U_2(kdtlv->type); 807*ee67461eSJoseph Mingrone tll = GET_BE_U_2(kdtlv->length); 808*ee67461eSJoseph Mingrone invtlv = tlv_valid(tll, len); 80927df3f5dSRui Paulo 81027df3f5dSRui Paulo if (invtlv) { 811*ee67461eSJoseph Mingrone ND_PRINT("%s TLV type 0x%x len %u\n", 81227df3f5dSRui Paulo tok2str(ForCES_TLV_err, NULL, invtlv), type, 813*ee67461eSJoseph Mingrone tll); 81427df3f5dSRui Paulo return -1; 81527df3f5dSRui Paulo } 81627df3f5dSRui Paulo /* 81727df3f5dSRui Paulo * At this point, tlv_valid() has ensured that the TLV 81827df3f5dSRui Paulo * length is large enough but not too large (it doesn't 81927df3f5dSRui Paulo * go past the end of the containing TLV). 82027df3f5dSRui Paulo */ 821*ee67461eSJoseph Mingrone tll = GET_BE_U_2(kdtlv->length); 8223340d773SGleb Smirnoff dp = (const u_char *) TLV_DATA(kdtlv); 8233c602fabSXin LI return fdatatlv_print(ndo, dp, tll, op_msk, indent); 82427df3f5dSRui Paulo } 82527df3f5dSRui Paulo 8263c602fabSXin LI #define PTH_DESC_SIZE 12 8273c602fabSXin LI 8283c602fabSXin LI static int 8293c602fabSXin LI pdatacnt_print(netdissect_options *ndo, 830*ee67461eSJoseph Mingrone const u_char * pptr, u_int len, 8313c602fabSXin LI uint16_t IDcnt, uint16_t op_msk, int indent) 83227df3f5dSRui Paulo { 83327df3f5dSRui Paulo u_int i; 8343c602fabSXin LI uint32_t id; 83527df3f5dSRui Paulo char *ib = indent_pr(indent, 0); 83627df3f5dSRui Paulo 8373c602fabSXin LI if ((op_msk & B_APPND) && ndo->ndo_vflag >= 3) { 838*ee67461eSJoseph Mingrone ND_PRINT("%sTABLE APPEND\n", ib); 8393c602fabSXin LI } 84027df3f5dSRui Paulo for (i = 0; i < IDcnt; i++) { 841*ee67461eSJoseph Mingrone ND_TCHECK_4(pptr); 84227df3f5dSRui Paulo if (len < 4) 84327df3f5dSRui Paulo goto trunc; 844*ee67461eSJoseph Mingrone id = GET_BE_U_4(pptr); 8453c602fabSXin LI if (ndo->ndo_vflag >= 3) 846*ee67461eSJoseph Mingrone ND_PRINT("%sID#%02u: %u\n", ib, i + 1, id); 84727df3f5dSRui Paulo len -= 4; 84827df3f5dSRui Paulo pptr += 4; 84927df3f5dSRui Paulo } 8503c602fabSXin LI 8513c602fabSXin LI if ((op_msk & B_TRNG) || (op_msk & B_KEYIN)) { 8523c602fabSXin LI if (op_msk & B_TRNG) { 8533c602fabSXin LI uint32_t starti, endi; 8543c602fabSXin LI 8553c602fabSXin LI if (len < PTH_DESC_SIZE) { 856*ee67461eSJoseph Mingrone ND_PRINT("pathlength %u with key/range too short %u\n", 857*ee67461eSJoseph Mingrone len, PTH_DESC_SIZE); 8583c602fabSXin LI return -1; 8593c602fabSXin LI } 8603c602fabSXin LI 8613c602fabSXin LI pptr += sizeof(struct forces_tlv); 8623c602fabSXin LI len -= sizeof(struct forces_tlv); 8633c602fabSXin LI 864*ee67461eSJoseph Mingrone starti = GET_BE_U_4(pptr); 8653c602fabSXin LI pptr += 4; 8663c602fabSXin LI len -= 4; 8673c602fabSXin LI 868*ee67461eSJoseph Mingrone endi = GET_BE_U_4(pptr); 8693c602fabSXin LI pptr += 4; 8703c602fabSXin LI len -= 4; 8713c602fabSXin LI 8723c602fabSXin LI if (ndo->ndo_vflag >= 3) 873*ee67461eSJoseph Mingrone ND_PRINT("%sTable range: [%u,%u]\n", ib, starti, endi); 8743c602fabSXin LI } 8753c602fabSXin LI 8763c602fabSXin LI if (op_msk & B_KEYIN) { 8773340d773SGleb Smirnoff const struct forces_tlv *keytlv; 8783c602fabSXin LI uint16_t tll; 8793c602fabSXin LI 8803c602fabSXin LI if (len < PTH_DESC_SIZE) { 881*ee67461eSJoseph Mingrone ND_PRINT("pathlength %u with key/range too short %u\n", 882*ee67461eSJoseph Mingrone len, PTH_DESC_SIZE); 8833c602fabSXin LI return -1; 8843c602fabSXin LI } 8853c602fabSXin LI 8863c602fabSXin LI /* skip keyid */ 8873c602fabSXin LI pptr += 4; 8883c602fabSXin LI len -= 4; 8893340d773SGleb Smirnoff keytlv = (const struct forces_tlv *)pptr; 8903c602fabSXin LI /* skip header */ 8913c602fabSXin LI pptr += sizeof(struct forces_tlv); 8923c602fabSXin LI len -= sizeof(struct forces_tlv); 8933c602fabSXin LI /* skip key content */ 894*ee67461eSJoseph Mingrone tll = GET_BE_U_2(keytlv->length); 8953c602fabSXin LI if (tll < TLV_HDRL) { 896*ee67461eSJoseph Mingrone ND_PRINT("key content length %u < %u\n", 897*ee67461eSJoseph Mingrone tll, TLV_HDRL); 8983c602fabSXin LI return -1; 8993c602fabSXin LI } 9003c602fabSXin LI tll -= TLV_HDRL; 9013c602fabSXin LI if (len < tll) { 902*ee67461eSJoseph Mingrone ND_PRINT("key content too short\n"); 9033c602fabSXin LI return -1; 9043c602fabSXin LI } 9053c602fabSXin LI pptr += tll; 9063c602fabSXin LI len -= tll; 9073c602fabSXin LI } 9083c602fabSXin LI 9093c602fabSXin LI } 9103c602fabSXin LI 91127df3f5dSRui Paulo if (len) { 9123340d773SGleb Smirnoff const struct forces_tlv *pdtlv = (const struct forces_tlv *)pptr; 9133c602fabSXin LI uint16_t type; 914*ee67461eSJoseph Mingrone uint16_t tlvl, tll; 915*ee67461eSJoseph Mingrone u_int pad = 0; 91627df3f5dSRui Paulo u_int aln; 9173c602fabSXin LI u_int invtlv; 91827df3f5dSRui Paulo 919*ee67461eSJoseph Mingrone type = GET_BE_U_2(pdtlv->type); 920*ee67461eSJoseph Mingrone tlvl = GET_BE_U_2(pdtlv->length); 921*ee67461eSJoseph Mingrone invtlv = tlv_valid(tlvl, len); 92227df3f5dSRui Paulo if (invtlv) { 923*ee67461eSJoseph Mingrone ND_PRINT("%s Outstanding bytes %u for TLV type 0x%x TLV len %u\n", 92427df3f5dSRui Paulo tok2str(ForCES_TLV_err, NULL, invtlv), len, type, 925*ee67461eSJoseph Mingrone tlvl); 92627df3f5dSRui Paulo goto pd_err; 92727df3f5dSRui Paulo } 92827df3f5dSRui Paulo /* 92927df3f5dSRui Paulo * At this point, tlv_valid() has ensured that the TLV 93027df3f5dSRui Paulo * length is large enough but not too large (it doesn't 93127df3f5dSRui Paulo * go past the end of the containing TLV). 93227df3f5dSRui Paulo */ 933*ee67461eSJoseph Mingrone tll = tlvl - TLV_HDRL; 934*ee67461eSJoseph Mingrone aln = F_ALN_LEN(tlvl); 935*ee67461eSJoseph Mingrone if (aln > tlvl) { 93627df3f5dSRui Paulo if (aln > len) { 937*ee67461eSJoseph Mingrone ND_PRINT("Invalid padded pathdata TLV type 0x%x len %u missing %u pad bytes\n", 938*ee67461eSJoseph Mingrone type, tlvl, aln - len); 93927df3f5dSRui Paulo } else { 940*ee67461eSJoseph Mingrone pad = aln - tlvl; 94127df3f5dSRui Paulo } 94227df3f5dSRui Paulo } 94327df3f5dSRui Paulo if (pd_valid(type)) { 94427df3f5dSRui Paulo const struct pdata_ops *ops = get_forces_pd(type); 94527df3f5dSRui Paulo 9463c602fabSXin LI if (ndo->ndo_vflag >= 3 && ops->v != F_TLV_PDAT) { 94727df3f5dSRui Paulo if (pad) 948*ee67461eSJoseph Mingrone ND_PRINT("%s %s (Length %u DataLen %u pad %u Bytes)\n", 949*ee67461eSJoseph Mingrone ib, ops->s, tlvl, tll, pad); 95027df3f5dSRui Paulo else 951*ee67461eSJoseph Mingrone ND_PRINT("%s %s (Length %u DataLen %u Bytes)\n", 952*ee67461eSJoseph Mingrone ib, ops->s, tlvl, tll); 95327df3f5dSRui Paulo } 95427df3f5dSRui Paulo 9553c602fabSXin LI chk_op_type(ndo, type, op_msk, ops->op_msk); 95627df3f5dSRui Paulo 9573c602fabSXin LI if (ops->print(ndo, (const u_char *)pdtlv, 95827df3f5dSRui Paulo tll + pad + TLV_HDRL, op_msk, 959d09a7e67SXin LI indent + 2) == -1) 960d09a7e67SXin LI return -1; 961cac3dcd5SXin LI len -= (TLV_HDRL + pad + tll); 96227df3f5dSRui Paulo } else { 963*ee67461eSJoseph Mingrone ND_PRINT("Invalid path data content type 0x%x len %u\n", 964*ee67461eSJoseph Mingrone type, tlvl); 96527df3f5dSRui Paulo pd_err: 966*ee67461eSJoseph Mingrone if (tlvl) { 967*ee67461eSJoseph Mingrone hex_print(ndo, "Bad Data val\n\t [", 968*ee67461eSJoseph Mingrone pptr, len); 969*ee67461eSJoseph Mingrone ND_PRINT("]\n"); 97027df3f5dSRui Paulo 97127df3f5dSRui Paulo return -1; 97227df3f5dSRui Paulo } 97327df3f5dSRui Paulo } 97427df3f5dSRui Paulo } 975cac3dcd5SXin LI return len; 97627df3f5dSRui Paulo 97727df3f5dSRui Paulo trunc: 978*ee67461eSJoseph Mingrone nd_print_trunc(ndo); 97927df3f5dSRui Paulo return -1; 98027df3f5dSRui Paulo } 98127df3f5dSRui Paulo 9823c602fabSXin LI static int 9833c602fabSXin LI pdata_print(netdissect_options *ndo, 984*ee67461eSJoseph Mingrone const u_char * pptr, u_int len, 9853c602fabSXin LI uint16_t op_msk, int indent) 98627df3f5dSRui Paulo { 9873340d773SGleb Smirnoff const struct pathdata_h *pdh = (const struct pathdata_h *)pptr; 98827df3f5dSRui Paulo char *ib = indent_pr(indent, 0); 98927df3f5dSRui Paulo u_int minsize = 0; 990cac3dcd5SXin LI int more_pd = 0; 9913c602fabSXin LI uint16_t idcnt = 0; 99227df3f5dSRui Paulo 993*ee67461eSJoseph Mingrone ND_TCHECK_SIZE(pdh); 99427df3f5dSRui Paulo if (len < sizeof(struct pathdata_h)) 99527df3f5dSRui Paulo goto trunc; 9963c602fabSXin LI if (ndo->ndo_vflag >= 3) { 997*ee67461eSJoseph Mingrone ND_PRINT("\n%sPathdata: Flags 0x%x ID count %u\n", 998*ee67461eSJoseph Mingrone ib, GET_BE_U_2(pdh->pflags), 999*ee67461eSJoseph Mingrone GET_BE_U_2(pdh->pIDcnt)); 100027df3f5dSRui Paulo } 100127df3f5dSRui Paulo 1002*ee67461eSJoseph Mingrone if (GET_BE_U_2(pdh->pflags) & F_SELKEY) { 100327df3f5dSRui Paulo op_msk |= B_KEYIN; 100427df3f5dSRui Paulo } 10053c602fabSXin LI 10063c602fabSXin LI /* Table GET Range operation */ 1007*ee67461eSJoseph Mingrone if (GET_BE_U_2(pdh->pflags) & F_SELTABRANGE) { 10083c602fabSXin LI op_msk |= B_TRNG; 10093c602fabSXin LI } 10103c602fabSXin LI /* Table SET append operation */ 1011*ee67461eSJoseph Mingrone if (GET_BE_U_2(pdh->pflags) & F_TABAPPEND) { 10123c602fabSXin LI op_msk |= B_APPND; 10133c602fabSXin LI } 10143c602fabSXin LI 101527df3f5dSRui Paulo pptr += sizeof(struct pathdata_h); 101627df3f5dSRui Paulo len -= sizeof(struct pathdata_h); 1017*ee67461eSJoseph Mingrone idcnt = GET_BE_U_2(pdh->pIDcnt); 1018cac3dcd5SXin LI minsize = idcnt * 4; 101927df3f5dSRui Paulo if (len < minsize) { 1020*ee67461eSJoseph Mingrone ND_PRINT("\t\t\ttruncated IDs expected %uB got %uB\n", minsize, 1021*ee67461eSJoseph Mingrone len); 1022*ee67461eSJoseph Mingrone hex_print(ndo, "\t\t\tID Data[", pptr, len); 1023*ee67461eSJoseph Mingrone ND_PRINT("]\n"); 102427df3f5dSRui Paulo return -1; 102527df3f5dSRui Paulo } 10263c602fabSXin LI 10273c602fabSXin LI if ((op_msk & B_TRNG) && (op_msk & B_KEYIN)) { 1028*ee67461eSJoseph Mingrone ND_PRINT("\t\t\tIllegal to have both Table ranges and keys\n"); 10293c602fabSXin LI return -1; 10303c602fabSXin LI } 10313c602fabSXin LI 10323c602fabSXin LI more_pd = pdatacnt_print(ndo, pptr, len, idcnt, op_msk, indent); 1033cac3dcd5SXin LI if (more_pd > 0) { 1034cac3dcd5SXin LI int consumed = len - more_pd; 1035cac3dcd5SXin LI pptr += consumed; 1036cac3dcd5SXin LI len = more_pd; 1037cac3dcd5SXin LI /* XXX: Argh, recurse some more */ 10383c602fabSXin LI return recpdoptlv_print(ndo, pptr, len, op_msk, indent+1); 1039cac3dcd5SXin LI } else 1040cac3dcd5SXin LI return 0; 104127df3f5dSRui Paulo 104227df3f5dSRui Paulo trunc: 1043*ee67461eSJoseph Mingrone nd_print_trunc(ndo); 104427df3f5dSRui Paulo return -1; 104527df3f5dSRui Paulo } 104627df3f5dSRui Paulo 10473c602fabSXin LI static int 10483c602fabSXin LI genoptlv_print(netdissect_options *ndo, 1049*ee67461eSJoseph Mingrone const u_char * pptr, u_int len, 10503c602fabSXin LI uint16_t op_msk, int indent) 105127df3f5dSRui Paulo { 10523340d773SGleb Smirnoff const struct forces_tlv *pdtlv = (const struct forces_tlv *)pptr; 10533c602fabSXin LI uint16_t type; 1054*ee67461eSJoseph Mingrone u_int tlvl; 10553c602fabSXin LI u_int invtlv; 105627df3f5dSRui Paulo char *ib = indent_pr(indent, 0); 105727df3f5dSRui Paulo 1058*ee67461eSJoseph Mingrone type = GET_BE_U_2(pdtlv->type); 1059*ee67461eSJoseph Mingrone tlvl = GET_BE_U_2(pdtlv->length); 1060*ee67461eSJoseph Mingrone invtlv = tlv_valid(tlvl, len); 1061*ee67461eSJoseph Mingrone ND_PRINT("genoptlvprint - %s TLV type 0x%x len %u\n", 1062*ee67461eSJoseph Mingrone tok2str(ForCES_TLV, NULL, type), type, tlvl); 106327df3f5dSRui Paulo if (!invtlv) { 106427df3f5dSRui Paulo /* 106527df3f5dSRui Paulo * At this point, tlv_valid() has ensured that the TLV 106627df3f5dSRui Paulo * length is large enough but not too large (it doesn't 106727df3f5dSRui Paulo * go past the end of the containing TLV). 106827df3f5dSRui Paulo */ 1069*ee67461eSJoseph Mingrone const u_char *dp = (const u_char *) TLV_DATA(pdtlv); 1070*ee67461eSJoseph Mingrone 107127df3f5dSRui Paulo if (!ttlv_valid(type)) { 1072*ee67461eSJoseph Mingrone ND_PRINT("%s TLV type 0x%x len %u\n", 107327df3f5dSRui Paulo tok2str(ForCES_TLV_err, NULL, invtlv), type, 1074*ee67461eSJoseph Mingrone tlvl); 107527df3f5dSRui Paulo return -1; 107627df3f5dSRui Paulo } 10773c602fabSXin LI if (ndo->ndo_vflag >= 3) 1078*ee67461eSJoseph Mingrone ND_PRINT("%s%s, length %u (data length %u Bytes)", 107927df3f5dSRui Paulo ib, tok2str(ForCES_TLV, NULL, type), 1080*ee67461eSJoseph Mingrone tlvl, tlvl - TLV_HDRL); 108127df3f5dSRui Paulo 1082*ee67461eSJoseph Mingrone return pdata_print(ndo, dp, tlvl - TLV_HDRL, op_msk, indent + 1); 108327df3f5dSRui Paulo } else { 1084*ee67461eSJoseph Mingrone ND_PRINT("\t\t\tInvalid ForCES TLV type=%x", type); 108527df3f5dSRui Paulo return -1; 108627df3f5dSRui Paulo } 108727df3f5dSRui Paulo } 108827df3f5dSRui Paulo 10893c602fabSXin LI static int 10903c602fabSXin LI recpdoptlv_print(netdissect_options *ndo, 1091*ee67461eSJoseph Mingrone const u_char * pptr, u_int len, 10923c602fabSXin LI uint16_t op_msk, int indent) 109327df3f5dSRui Paulo { 10943340d773SGleb Smirnoff const struct forces_tlv *pdtlv = (const struct forces_tlv *)pptr; 109527df3f5dSRui Paulo 109627df3f5dSRui Paulo while (len != 0) { 1097*ee67461eSJoseph Mingrone uint16_t type, tlvl; 1098*ee67461eSJoseph Mingrone u_int invtlv; 1099*ee67461eSJoseph Mingrone char *ib; 1100*ee67461eSJoseph Mingrone const u_char *dp; 1101*ee67461eSJoseph Mingrone 1102*ee67461eSJoseph Mingrone tlvl = GET_BE_U_2(pdtlv->length); 1103*ee67461eSJoseph Mingrone invtlv = tlv_valid(tlvl, len); 110427df3f5dSRui Paulo if (invtlv) { 110527df3f5dSRui Paulo break; 110627df3f5dSRui Paulo } 110727df3f5dSRui Paulo 110827df3f5dSRui Paulo /* 110927df3f5dSRui Paulo * At this point, tlv_valid() has ensured that the TLV 111027df3f5dSRui Paulo * length is large enough but not too large (it doesn't 111127df3f5dSRui Paulo * go past the end of the containing TLV). 111227df3f5dSRui Paulo */ 111327df3f5dSRui Paulo ib = indent_pr(indent, 0); 1114*ee67461eSJoseph Mingrone type = GET_BE_U_2(pdtlv->type); 11153340d773SGleb Smirnoff dp = (const u_char *) TLV_DATA(pdtlv); 111627df3f5dSRui Paulo 11173c602fabSXin LI if (ndo->ndo_vflag >= 3) 1118*ee67461eSJoseph Mingrone ND_PRINT("%s%s, length %u (data encapsulated %u Bytes)", 111927df3f5dSRui Paulo ib, tok2str(ForCES_TLV, NULL, type), 1120*ee67461eSJoseph Mingrone tlvl, 1121*ee67461eSJoseph Mingrone tlvl - TLV_HDRL); 112227df3f5dSRui Paulo 1123*ee67461eSJoseph Mingrone if (pdata_print(ndo, dp, tlvl - TLV_HDRL, op_msk, indent + 1) == -1) 1124d09a7e67SXin LI return -1; 112527df3f5dSRui Paulo pdtlv = GO_NXT_TLV(pdtlv, len); 112627df3f5dSRui Paulo } 112727df3f5dSRui Paulo 112827df3f5dSRui Paulo if (len) { 1129*ee67461eSJoseph Mingrone ND_PRINT("\n\t\tMessy PATHDATA TLV header, type (0x%x)\n\t\texcess of %u Bytes ", 1130*ee67461eSJoseph Mingrone GET_BE_U_2(pdtlv->type), 1131*ee67461eSJoseph Mingrone len - GET_BE_U_2(pdtlv->length)); 113227df3f5dSRui Paulo return -1; 113327df3f5dSRui Paulo } 113427df3f5dSRui Paulo 113527df3f5dSRui Paulo return 0; 113627df3f5dSRui Paulo } 113727df3f5dSRui Paulo 11383c602fabSXin LI static int 11393c602fabSXin LI invoptlv_print(netdissect_options *ndo, 1140*ee67461eSJoseph Mingrone const u_char * pptr, u_int len, 11413c602fabSXin LI uint16_t op_msk _U_, int indent) 114227df3f5dSRui Paulo { 114327df3f5dSRui Paulo char *ib = indent_pr(indent, 1); 114427df3f5dSRui Paulo 11453c602fabSXin LI if (ndo->ndo_vflag >= 3) { 1146*ee67461eSJoseph Mingrone ND_PRINT("%sData[", ib + 1); 1147*ee67461eSJoseph Mingrone hex_print(ndo, ib, pptr, len); 1148*ee67461eSJoseph Mingrone ND_PRINT("%s]\n", ib); 114927df3f5dSRui Paulo } 115027df3f5dSRui Paulo return -1; 115127df3f5dSRui Paulo } 115227df3f5dSRui Paulo 11533c602fabSXin LI static int 11543c602fabSXin LI otlv_print(netdissect_options *ndo, 11553c602fabSXin LI const struct forces_tlv *otlv, uint16_t op_msk _U_, int indent) 115627df3f5dSRui Paulo { 115727df3f5dSRui Paulo int rc = 0; 1158*ee67461eSJoseph Mingrone const u_char *dp = (const u_char *) TLV_DATA(otlv); 11593c602fabSXin LI uint16_t type; 1160*ee67461eSJoseph Mingrone u_int tll; 116127df3f5dSRui Paulo char *ib = indent_pr(indent, 0); 116227df3f5dSRui Paulo const struct optlv_h *ops; 116327df3f5dSRui Paulo 116427df3f5dSRui Paulo /* 1165*ee67461eSJoseph Mingrone * lfbselect_print() has ensured that GET_BE_U_2(otlv->length) 116627df3f5dSRui Paulo * >= TLV_HDRL. 116727df3f5dSRui Paulo */ 1168*ee67461eSJoseph Mingrone type = GET_BE_U_2(otlv->type); 1169*ee67461eSJoseph Mingrone tll = GET_BE_U_2(otlv->length) - TLV_HDRL; 117027df3f5dSRui Paulo ops = get_forces_optlv_h(type); 11713c602fabSXin LI if (ndo->ndo_vflag >= 3) { 1172*ee67461eSJoseph Mingrone ND_PRINT("%sOper TLV %s(0x%x) length %u\n", ib, ops->s, type, 1173*ee67461eSJoseph Mingrone GET_BE_U_2(otlv->length)); 117427df3f5dSRui Paulo } 117527df3f5dSRui Paulo /* rest of ops must at least have 12B {pathinfo} */ 117627df3f5dSRui Paulo if (tll < OP_MIN_SIZ) { 1177*ee67461eSJoseph Mingrone ND_PRINT("\t\tOper TLV %s(0x%x) length %u\n", ops->s, type, 1178*ee67461eSJoseph Mingrone GET_BE_U_2(otlv->length)); 1179*ee67461eSJoseph Mingrone ND_PRINT("\t\tTruncated data size %u minimum required %u\n", tll, 1180*ee67461eSJoseph Mingrone OP_MIN_SIZ); 11813c602fabSXin LI return invoptlv_print(ndo, dp, tll, ops->op_msk, indent); 118227df3f5dSRui Paulo 118327df3f5dSRui Paulo } 118427df3f5dSRui Paulo 11858bdc5a62SPatrick Kelsey /* XXX - do anything with ops->flags? */ 11868bdc5a62SPatrick Kelsey if(ops->print) { 11873c602fabSXin LI rc = ops->print(ndo, dp, tll, ops->op_msk, indent + 1); 11888bdc5a62SPatrick Kelsey } 118927df3f5dSRui Paulo return rc; 119027df3f5dSRui Paulo } 119127df3f5dSRui Paulo 119227df3f5dSRui Paulo #define ASTDLN 4 119327df3f5dSRui Paulo #define ASTMCD 255 11943c602fabSXin LI static int 11953c602fabSXin LI asttlv_print(netdissect_options *ndo, 1196*ee67461eSJoseph Mingrone const u_char * pptr, u_int len, 11973c602fabSXin LI uint16_t op_msk _U_, int indent) 119827df3f5dSRui Paulo { 11993c602fabSXin LI uint32_t rescode; 120027df3f5dSRui Paulo u_int dlen; 120127df3f5dSRui Paulo char *ib = indent_pr(indent, 0); 120227df3f5dSRui Paulo 120327df3f5dSRui Paulo /* 120427df3f5dSRui Paulo * forces_type_print() has ensured that len (the TLV length) 120527df3f5dSRui Paulo * >= TLV_HDRL. 120627df3f5dSRui Paulo */ 120727df3f5dSRui Paulo dlen = len - TLV_HDRL; 120827df3f5dSRui Paulo if (dlen != ASTDLN) { 1209*ee67461eSJoseph Mingrone ND_PRINT("illegal ASTresult-TLV: %u bytes!\n", dlen); 121027df3f5dSRui Paulo return -1; 121127df3f5dSRui Paulo } 1212*ee67461eSJoseph Mingrone rescode = GET_BE_U_4(pptr); 121327df3f5dSRui Paulo if (rescode > ASTMCD) { 1214*ee67461eSJoseph Mingrone ND_PRINT("illegal ASTresult result code: %u!\n", rescode); 121527df3f5dSRui Paulo return -1; 121627df3f5dSRui Paulo } 121727df3f5dSRui Paulo 12183c602fabSXin LI if (ndo->ndo_vflag >= 3) { 1219*ee67461eSJoseph Mingrone ND_PRINT("Teardown reason:\n%s", ib); 122027df3f5dSRui Paulo switch (rescode) { 122127df3f5dSRui Paulo case 0: 1222*ee67461eSJoseph Mingrone ND_PRINT("Normal Teardown"); 122327df3f5dSRui Paulo break; 122427df3f5dSRui Paulo case 1: 1225*ee67461eSJoseph Mingrone ND_PRINT("Loss of Heartbeats"); 122627df3f5dSRui Paulo break; 122727df3f5dSRui Paulo case 2: 1228*ee67461eSJoseph Mingrone ND_PRINT("Out of bandwidth"); 122927df3f5dSRui Paulo break; 123027df3f5dSRui Paulo case 3: 1231*ee67461eSJoseph Mingrone ND_PRINT("Out of Memory"); 123227df3f5dSRui Paulo break; 123327df3f5dSRui Paulo case 4: 1234*ee67461eSJoseph Mingrone ND_PRINT("Application Crash"); 123527df3f5dSRui Paulo break; 123627df3f5dSRui Paulo default: 1237*ee67461eSJoseph Mingrone ND_PRINT("Unknown Teardown reason"); 123827df3f5dSRui Paulo break; 123927df3f5dSRui Paulo } 1240*ee67461eSJoseph Mingrone ND_PRINT("(%x)\n%s", rescode, ib); 124127df3f5dSRui Paulo } 124227df3f5dSRui Paulo return 0; 124327df3f5dSRui Paulo } 124427df3f5dSRui Paulo 124527df3f5dSRui Paulo #define ASRDLN 4 124627df3f5dSRui Paulo #define ASRMCD 3 12473c602fabSXin LI static int 12483c602fabSXin LI asrtlv_print(netdissect_options *ndo, 1249*ee67461eSJoseph Mingrone const u_char * pptr, u_int len, 12503c602fabSXin LI uint16_t op_msk _U_, int indent) 125127df3f5dSRui Paulo { 12523c602fabSXin LI uint32_t rescode; 125327df3f5dSRui Paulo u_int dlen; 125427df3f5dSRui Paulo char *ib = indent_pr(indent, 0); 125527df3f5dSRui Paulo 125627df3f5dSRui Paulo /* 125727df3f5dSRui Paulo * forces_type_print() has ensured that len (the TLV length) 125827df3f5dSRui Paulo * >= TLV_HDRL. 125927df3f5dSRui Paulo */ 126027df3f5dSRui Paulo dlen = len - TLV_HDRL; 126127df3f5dSRui Paulo if (dlen != ASRDLN) { /* id, instance, oper tlv */ 1262*ee67461eSJoseph Mingrone ND_PRINT("illegal ASRresult-TLV: %u bytes!\n", dlen); 126327df3f5dSRui Paulo return -1; 126427df3f5dSRui Paulo } 1265*ee67461eSJoseph Mingrone rescode = GET_BE_U_4(pptr); 126627df3f5dSRui Paulo 126727df3f5dSRui Paulo if (rescode > ASRMCD) { 1268*ee67461eSJoseph Mingrone ND_PRINT("illegal ASRresult result code: %u!\n", rescode); 126927df3f5dSRui Paulo return -1; 127027df3f5dSRui Paulo } 127127df3f5dSRui Paulo 12723c602fabSXin LI if (ndo->ndo_vflag >= 3) { 1273*ee67461eSJoseph Mingrone ND_PRINT("\n%s", ib); 127427df3f5dSRui Paulo switch (rescode) { 127527df3f5dSRui Paulo case 0: 1276*ee67461eSJoseph Mingrone ND_PRINT("Success "); 127727df3f5dSRui Paulo break; 127827df3f5dSRui Paulo case 1: 1279*ee67461eSJoseph Mingrone ND_PRINT("FE ID invalid "); 128027df3f5dSRui Paulo break; 128127df3f5dSRui Paulo case 2: 1282*ee67461eSJoseph Mingrone ND_PRINT("permission denied "); 128327df3f5dSRui Paulo break; 128427df3f5dSRui Paulo default: 1285*ee67461eSJoseph Mingrone ND_PRINT("Unknown "); 128627df3f5dSRui Paulo break; 128727df3f5dSRui Paulo } 1288*ee67461eSJoseph Mingrone ND_PRINT("(%x)\n%s", rescode, ib); 128927df3f5dSRui Paulo } 129027df3f5dSRui Paulo return 0; 129127df3f5dSRui Paulo } 129227df3f5dSRui Paulo 12933c602fabSXin LI #if 0 129427df3f5dSRui Paulo /* 129527df3f5dSRui Paulo * XXX - not used. 129627df3f5dSRui Paulo */ 12973c602fabSXin LI static int 12983c602fabSXin LI gentltlv_print(netdissect_options *ndo, 1299*ee67461eSJoseph Mingrone const u_char * pptr _U_, u_int len, 13003c602fabSXin LI uint16_t op_msk _U_, int indent _U_) 130127df3f5dSRui Paulo { 130227df3f5dSRui Paulo u_int dlen = len - TLV_HDRL; 130327df3f5dSRui Paulo 130427df3f5dSRui Paulo if (dlen < 4) { /* at least 32 bits must exist */ 1305*ee67461eSJoseph Mingrone ND_PRINT("truncated TLV: %u bytes missing! ", 4 - dlen); 130627df3f5dSRui Paulo return -1; 130727df3f5dSRui Paulo } 130827df3f5dSRui Paulo return 0; 130927df3f5dSRui Paulo } 13103c602fabSXin LI #endif 131127df3f5dSRui Paulo 131227df3f5dSRui Paulo #define RD_MIN 8 13133c602fabSXin LI 13143c602fabSXin LI static int 13153c602fabSXin LI print_metailv(netdissect_options *ndo, 1316*ee67461eSJoseph Mingrone const u_char * pptr, uint16_t op_msk _U_, int indent) 131727df3f5dSRui Paulo { 131827df3f5dSRui Paulo u_int rlen; 131927df3f5dSRui Paulo char *ib = indent_pr(indent, 0); 132027df3f5dSRui Paulo /* XXX: check header length */ 13213340d773SGleb Smirnoff const struct forces_ilv *ilv = (const struct forces_ilv *)pptr; 132227df3f5dSRui Paulo 132327df3f5dSRui Paulo /* 132427df3f5dSRui Paulo * print_metatlv() has ensured that len (what remains in the 132527df3f5dSRui Paulo * ILV) >= ILV_HDRL. 132627df3f5dSRui Paulo */ 1327*ee67461eSJoseph Mingrone rlen = GET_BE_U_4(ilv->length) - ILV_HDRL; 1328*ee67461eSJoseph Mingrone ND_PRINT("%sMetaID 0x%x length %u\n", ib, GET_BE_U_4(ilv->type), 1329*ee67461eSJoseph Mingrone GET_BE_U_4(ilv->length)); 13303c602fabSXin LI if (ndo->ndo_vflag >= 3) { 1331*ee67461eSJoseph Mingrone hex_print(ndo, "\t\t[", ILV_DATA(ilv), rlen); 1332*ee67461eSJoseph Mingrone ND_PRINT(" ]\n"); 13333c602fabSXin LI } 133427df3f5dSRui Paulo return 0; 133527df3f5dSRui Paulo } 133627df3f5dSRui Paulo 13373c602fabSXin LI static int 13383c602fabSXin LI print_metatlv(netdissect_options *ndo, 1339*ee67461eSJoseph Mingrone const u_char * pptr, u_int len, 13403c602fabSXin LI uint16_t op_msk _U_, int indent) 134127df3f5dSRui Paulo { 134227df3f5dSRui Paulo u_int dlen; 134327df3f5dSRui Paulo char *ib = indent_pr(indent, 0); 134427df3f5dSRui Paulo u_int rlen; 13453340d773SGleb Smirnoff const struct forces_ilv *ilv = (const struct forces_ilv *)pptr; 134627df3f5dSRui Paulo int invilv; 134727df3f5dSRui Paulo 134827df3f5dSRui Paulo /* 134927df3f5dSRui Paulo * redirect_print() has ensured that len (what remains in the 135027df3f5dSRui Paulo * TLV) >= TLV_HDRL. 135127df3f5dSRui Paulo */ 135227df3f5dSRui Paulo dlen = len - TLV_HDRL; 135327df3f5dSRui Paulo rlen = dlen; 1354*ee67461eSJoseph Mingrone ND_PRINT("\n%s METADATA length %u\n", ib, rlen); 135527df3f5dSRui Paulo while (rlen != 0) { 1356*ee67461eSJoseph Mingrone invilv = ilv_valid(ndo, ilv, rlen); 13573c602fabSXin LI if (invilv) { 135827df3f5dSRui Paulo break; 13593c602fabSXin LI } 136027df3f5dSRui Paulo 136127df3f5dSRui Paulo /* 136227df3f5dSRui Paulo * At this point, ilv_valid() has ensured that the ILV 136327df3f5dSRui Paulo * length is large enough but not too large (it doesn't 136427df3f5dSRui Paulo * go past the end of the containing TLV). 136527df3f5dSRui Paulo */ 13663340d773SGleb Smirnoff print_metailv(ndo, (const u_char *) ilv, 0, indent + 1); 136727df3f5dSRui Paulo ilv = GO_NXT_ILV(ilv, rlen); 136827df3f5dSRui Paulo } 136927df3f5dSRui Paulo 137027df3f5dSRui Paulo return 0; 137127df3f5dSRui Paulo } 137227df3f5dSRui Paulo 13733c602fabSXin LI 13743c602fabSXin LI static int 13753c602fabSXin LI print_reddata(netdissect_options *ndo, 1376*ee67461eSJoseph Mingrone const u_char * pptr, u_int len, 13773340d773SGleb Smirnoff uint16_t op_msk _U_, int indent) 137827df3f5dSRui Paulo { 137927df3f5dSRui Paulo u_int dlen; 13803c602fabSXin LI char *ib = indent_pr(indent, 0); 138127df3f5dSRui Paulo u_int rlen; 138227df3f5dSRui Paulo 138327df3f5dSRui Paulo dlen = len - TLV_HDRL; 138427df3f5dSRui Paulo rlen = dlen; 1385*ee67461eSJoseph Mingrone ND_PRINT("\n%s Redirect Data length %u\n", ib, rlen); 138627df3f5dSRui Paulo 13873c602fabSXin LI if (ndo->ndo_vflag >= 3) { 1388*ee67461eSJoseph Mingrone ND_PRINT("\t\t["); 1389*ee67461eSJoseph Mingrone hex_print(ndo, "\n\t\t", pptr, rlen); 1390*ee67461eSJoseph Mingrone ND_PRINT("\n\t\t]"); 139127df3f5dSRui Paulo } 139227df3f5dSRui Paulo 139327df3f5dSRui Paulo return 0; 139427df3f5dSRui Paulo } 139527df3f5dSRui Paulo 13963c602fabSXin LI static int 13973c602fabSXin LI redirect_print(netdissect_options *ndo, 1398*ee67461eSJoseph Mingrone const u_char * pptr, u_int len, 13993c602fabSXin LI uint16_t op_msk _U_, int indent) 140027df3f5dSRui Paulo { 14013340d773SGleb Smirnoff const struct forces_tlv *tlv = (const struct forces_tlv *)pptr; 140227df3f5dSRui Paulo u_int dlen; 140327df3f5dSRui Paulo u_int rlen; 14043c602fabSXin LI u_int invtlv; 140527df3f5dSRui Paulo 140627df3f5dSRui Paulo /* 140727df3f5dSRui Paulo * forces_type_print() has ensured that len (the TLV length) 140827df3f5dSRui Paulo * >= TLV_HDRL. 140927df3f5dSRui Paulo */ 141027df3f5dSRui Paulo dlen = len - TLV_HDRL; 141127df3f5dSRui Paulo if (dlen <= RD_MIN) { 1412*ee67461eSJoseph Mingrone ND_PRINT("\n\t\ttruncated Redirect TLV: %u bytes missing! ", 1413*ee67461eSJoseph Mingrone RD_MIN - dlen); 141427df3f5dSRui Paulo return -1; 141527df3f5dSRui Paulo } 141627df3f5dSRui Paulo 141727df3f5dSRui Paulo rlen = dlen; 141827df3f5dSRui Paulo indent += 1; 141927df3f5dSRui Paulo while (rlen != 0) { 1420*ee67461eSJoseph Mingrone uint16_t type, tlvl; 1421*ee67461eSJoseph Mingrone 1422*ee67461eSJoseph Mingrone type = GET_BE_U_2(tlv->type); 1423*ee67461eSJoseph Mingrone tlvl = GET_BE_U_2(tlv->length); 1424*ee67461eSJoseph Mingrone invtlv = tlv_valid(tlvl, rlen); 14253c602fabSXin LI if (invtlv) { 1426*ee67461eSJoseph Mingrone ND_PRINT("Bad Redirect data\n"); 142727df3f5dSRui Paulo break; 14283c602fabSXin LI } 142927df3f5dSRui Paulo 143027df3f5dSRui Paulo /* 143127df3f5dSRui Paulo * At this point, tlv_valid() has ensured that the TLV 143227df3f5dSRui Paulo * length is large enough but not too large (it doesn't 143327df3f5dSRui Paulo * go past the end of the containing TLV). 143427df3f5dSRui Paulo */ 1435*ee67461eSJoseph Mingrone if (type == F_TLV_METD) { 14363340d773SGleb Smirnoff print_metatlv(ndo, (const u_char *) TLV_DATA(tlv), 1437*ee67461eSJoseph Mingrone tlvl, 0, 1438*ee67461eSJoseph Mingrone indent); 1439*ee67461eSJoseph Mingrone } else if (type == F_TLV_REDD) { 14403340d773SGleb Smirnoff print_reddata(ndo, (const u_char *) TLV_DATA(tlv), 1441*ee67461eSJoseph Mingrone tlvl, 0, 1442*ee67461eSJoseph Mingrone indent); 144327df3f5dSRui Paulo } else { 1444*ee67461eSJoseph Mingrone ND_PRINT("Unknown REDIRECT TLV 0x%x len %u\n", 1445*ee67461eSJoseph Mingrone type, 1446*ee67461eSJoseph Mingrone tlvl); 144727df3f5dSRui Paulo } 144827df3f5dSRui Paulo 144927df3f5dSRui Paulo tlv = GO_NXT_TLV(tlv, rlen); 145027df3f5dSRui Paulo } 145127df3f5dSRui Paulo 145227df3f5dSRui Paulo if (rlen) { 1453*ee67461eSJoseph Mingrone ND_PRINT("\n\t\tMessy Redirect TLV header, type (0x%x)\n\t\texcess of %u Bytes ", 1454*ee67461eSJoseph Mingrone GET_BE_U_2(tlv->type), 1455*ee67461eSJoseph Mingrone rlen - GET_BE_U_2(tlv->length)); 145627df3f5dSRui Paulo return -1; 145727df3f5dSRui Paulo } 145827df3f5dSRui Paulo 145927df3f5dSRui Paulo return 0; 146027df3f5dSRui Paulo } 146127df3f5dSRui Paulo 146227df3f5dSRui Paulo #define OP_OFF 8 146327df3f5dSRui Paulo #define OP_MIN 12 146427df3f5dSRui Paulo 14653c602fabSXin LI static int 14663c602fabSXin LI lfbselect_print(netdissect_options *ndo, 1467*ee67461eSJoseph Mingrone const u_char * pptr, u_int len, 14683c602fabSXin LI uint16_t op_msk, int indent) 146927df3f5dSRui Paulo { 147027df3f5dSRui Paulo const struct forces_lfbsh *lfbs; 147127df3f5dSRui Paulo const struct forces_tlv *otlv; 147227df3f5dSRui Paulo char *ib = indent_pr(indent, 0); 147327df3f5dSRui Paulo u_int dlen; 147427df3f5dSRui Paulo u_int rlen; 14753c602fabSXin LI u_int invtlv; 147627df3f5dSRui Paulo 147727df3f5dSRui Paulo /* 147827df3f5dSRui Paulo * forces_type_print() has ensured that len (the TLV length) 147927df3f5dSRui Paulo * >= TLV_HDRL. 148027df3f5dSRui Paulo */ 148127df3f5dSRui Paulo dlen = len - TLV_HDRL; 148227df3f5dSRui Paulo if (dlen <= OP_MIN) { /* id, instance, oper tlv header .. */ 1483*ee67461eSJoseph Mingrone ND_PRINT("\n\t\ttruncated lfb selector: %u bytes missing! ", 1484*ee67461eSJoseph Mingrone OP_MIN - dlen); 148527df3f5dSRui Paulo return -1; 148627df3f5dSRui Paulo } 148727df3f5dSRui Paulo 148827df3f5dSRui Paulo /* 148927df3f5dSRui Paulo * At this point, we know that dlen > OP_MIN; OP_OFF < OP_MIN, so 149027df3f5dSRui Paulo * we also know that it's > OP_OFF. 149127df3f5dSRui Paulo */ 149227df3f5dSRui Paulo rlen = dlen - OP_OFF; 149327df3f5dSRui Paulo 149427df3f5dSRui Paulo lfbs = (const struct forces_lfbsh *)pptr; 1495*ee67461eSJoseph Mingrone ND_TCHECK_SIZE(lfbs); 14963c602fabSXin LI if (ndo->ndo_vflag >= 3) { 1497*ee67461eSJoseph Mingrone ND_PRINT("\n%s%s(Classid %x) instance %x\n", 1498*ee67461eSJoseph Mingrone ib, 1499*ee67461eSJoseph Mingrone tok2str(ForCES_LFBs, NULL, GET_BE_U_4(lfbs->class)), 1500*ee67461eSJoseph Mingrone GET_BE_U_4(lfbs->class), 1501*ee67461eSJoseph Mingrone GET_BE_U_4(lfbs->instance)); 150227df3f5dSRui Paulo } 150327df3f5dSRui Paulo 15043340d773SGleb Smirnoff otlv = (const struct forces_tlv *)(lfbs + 1); 150527df3f5dSRui Paulo 150627df3f5dSRui Paulo indent += 1; 150727df3f5dSRui Paulo while (rlen != 0) { 1508*ee67461eSJoseph Mingrone uint16_t type, tlvl; 1509*ee67461eSJoseph Mingrone 1510*ee67461eSJoseph Mingrone type = GET_BE_U_2(otlv->type); 1511*ee67461eSJoseph Mingrone tlvl = GET_BE_U_2(otlv->length); 1512*ee67461eSJoseph Mingrone invtlv = tlv_valid(tlvl, rlen); 151327df3f5dSRui Paulo if (invtlv) 151427df3f5dSRui Paulo break; 151527df3f5dSRui Paulo 151627df3f5dSRui Paulo /* 151727df3f5dSRui Paulo * At this point, tlv_valid() has ensured that the TLV 151827df3f5dSRui Paulo * length is large enough but not too large (it doesn't 151927df3f5dSRui Paulo * go past the end of the containing TLV). 152027df3f5dSRui Paulo */ 1521*ee67461eSJoseph Mingrone if (op_valid(type, op_msk)) { 15223c602fabSXin LI otlv_print(ndo, otlv, 0, indent); 152327df3f5dSRui Paulo } else { 15243c602fabSXin LI if (ndo->ndo_vflag < 3) 1525*ee67461eSJoseph Mingrone ND_PRINT("\n"); 1526*ee67461eSJoseph Mingrone ND_PRINT("\t\tINValid oper-TLV type 0x%x length %u for this ForCES message\n", 1527*ee67461eSJoseph Mingrone type, tlvl); 15283340d773SGleb Smirnoff invoptlv_print(ndo, (const u_char *)otlv, rlen, 0, indent); 152927df3f5dSRui Paulo } 153027df3f5dSRui Paulo otlv = GO_NXT_TLV(otlv, rlen); 153127df3f5dSRui Paulo } 153227df3f5dSRui Paulo 153327df3f5dSRui Paulo if (rlen) { 1534*ee67461eSJoseph Mingrone ND_PRINT("\n\t\tMessy oper TLV header, type (0x%x)\n\t\texcess of %u Bytes ", 1535*ee67461eSJoseph Mingrone GET_BE_U_2(otlv->type), 1536*ee67461eSJoseph Mingrone rlen - GET_BE_U_2(otlv->length)); 153727df3f5dSRui Paulo return -1; 153827df3f5dSRui Paulo } 153927df3f5dSRui Paulo 154027df3f5dSRui Paulo return 0; 154127df3f5dSRui Paulo 154227df3f5dSRui Paulo trunc: 1543*ee67461eSJoseph Mingrone nd_print_trunc(ndo); 154427df3f5dSRui Paulo return -1; 154527df3f5dSRui Paulo } 154627df3f5dSRui Paulo 15473c602fabSXin LI static int 15483c602fabSXin LI forces_type_print(netdissect_options *ndo, 1549*ee67461eSJoseph Mingrone const u_char * pptr, const struct forcesh *fhdr _U_, 1550*ee67461eSJoseph Mingrone u_int mlen, const struct tom_h *tops) 155127df3f5dSRui Paulo { 155227df3f5dSRui Paulo const struct forces_tlv *tltlv; 155327df3f5dSRui Paulo u_int rlen; 15543c602fabSXin LI u_int invtlv; 155527df3f5dSRui Paulo int rc = 0; 1556*ee67461eSJoseph Mingrone u_int ttlv = 0; 155727df3f5dSRui Paulo 155827df3f5dSRui Paulo /* 155927df3f5dSRui Paulo * forces_print() has already checked that mlen >= ForCES_HDRL 156027df3f5dSRui Paulo * by calling ForCES_HLN_VALID(). 156127df3f5dSRui Paulo */ 156227df3f5dSRui Paulo rlen = mlen - ForCES_HDRL; 156327df3f5dSRui Paulo 156427df3f5dSRui Paulo if (rlen > TLV_HLN) { 156527df3f5dSRui Paulo if (tops->flags & ZERO_TTLV) { 1566*ee67461eSJoseph Mingrone ND_PRINT("<0x%x>Illegal Top level TLV!\n", tops->flags); 156727df3f5dSRui Paulo return -1; 156827df3f5dSRui Paulo } 156927df3f5dSRui Paulo } else { 157027df3f5dSRui Paulo if (tops->flags & ZERO_MORE_TTLV) 157127df3f5dSRui Paulo return 0; 157227df3f5dSRui Paulo if (tops->flags & ONE_MORE_TTLV) { 1573*ee67461eSJoseph Mingrone ND_PRINT("\tTop level TLV Data missing!\n"); 157427df3f5dSRui Paulo return -1; 157527df3f5dSRui Paulo } 157627df3f5dSRui Paulo } 157727df3f5dSRui Paulo 157827df3f5dSRui Paulo if (tops->flags & ZERO_TTLV) { 157927df3f5dSRui Paulo return 0; 158027df3f5dSRui Paulo } 158127df3f5dSRui Paulo 158227df3f5dSRui Paulo ttlv = tops->flags >> 4; 158327df3f5dSRui Paulo tltlv = GET_TOP_TLV(pptr); 158427df3f5dSRui Paulo 158527df3f5dSRui Paulo /*XXX: 15 top level tlvs will probably be fine 158627df3f5dSRui Paulo You are nuts if you send more ;-> */ 158727df3f5dSRui Paulo while (rlen != 0) { 1588*ee67461eSJoseph Mingrone uint16_t type, tlvl; 1589*ee67461eSJoseph Mingrone 1590*ee67461eSJoseph Mingrone type = GET_BE_U_2(tltlv->type); 1591*ee67461eSJoseph Mingrone tlvl = GET_BE_U_2(tltlv->length); 1592*ee67461eSJoseph Mingrone invtlv = tlv_valid(tlvl, rlen); 159327df3f5dSRui Paulo if (invtlv) 159427df3f5dSRui Paulo break; 159527df3f5dSRui Paulo 159627df3f5dSRui Paulo /* 159727df3f5dSRui Paulo * At this point, tlv_valid() has ensured that the TLV 159827df3f5dSRui Paulo * length is large enough but not too large (it doesn't 159927df3f5dSRui Paulo * go past the end of the packet). 160027df3f5dSRui Paulo */ 1601*ee67461eSJoseph Mingrone if (!ttlv_valid(type)) { 1602*ee67461eSJoseph Mingrone ND_PRINT("\n\tInvalid ForCES Top TLV type=0x%x", 1603*ee67461eSJoseph Mingrone type); 160427df3f5dSRui Paulo return -1; 160527df3f5dSRui Paulo } 160627df3f5dSRui Paulo 16073c602fabSXin LI if (ndo->ndo_vflag >= 3) 1608*ee67461eSJoseph Mingrone ND_PRINT("\t%s, length %u (data length %u Bytes)", 1609*ee67461eSJoseph Mingrone tok2str(ForCES_TLV, NULL, type), 1610*ee67461eSJoseph Mingrone tlvl, 1611*ee67461eSJoseph Mingrone tlvl - TLV_HDRL); 161227df3f5dSRui Paulo 16133340d773SGleb Smirnoff rc = tops->print(ndo, (const u_char *) TLV_DATA(tltlv), 1614*ee67461eSJoseph Mingrone tlvl, 1615*ee67461eSJoseph Mingrone tops->op_msk, 9); 161627df3f5dSRui Paulo if (rc < 0) { 161727df3f5dSRui Paulo return -1; 161827df3f5dSRui Paulo } 161927df3f5dSRui Paulo tltlv = GO_NXT_TLV(tltlv, rlen); 162027df3f5dSRui Paulo ttlv--; 162127df3f5dSRui Paulo if (ttlv <= 0) 162227df3f5dSRui Paulo break; 162327df3f5dSRui Paulo } 162427df3f5dSRui Paulo /* 162527df3f5dSRui Paulo * XXX - if ttlv != 0, does that mean that the packet was too 162627df3f5dSRui Paulo * short, and didn't have *enough* TLVs in it? 162727df3f5dSRui Paulo */ 162827df3f5dSRui Paulo if (rlen) { 1629*ee67461eSJoseph Mingrone ND_PRINT("\tMess TopTLV header: min %u, total %u advertised %u ", 1630*ee67461eSJoseph Mingrone TLV_HDRL, rlen, GET_BE_U_2(tltlv->length)); 163127df3f5dSRui Paulo return -1; 163227df3f5dSRui Paulo } 163327df3f5dSRui Paulo 163427df3f5dSRui Paulo return 0; 163527df3f5dSRui Paulo } 163627df3f5dSRui Paulo 16373c602fabSXin LI void 16383c602fabSXin LI forces_print(netdissect_options *ndo, 1639*ee67461eSJoseph Mingrone const u_char * pptr, u_int len) 164027df3f5dSRui Paulo { 164127df3f5dSRui Paulo const struct forcesh *fhdr; 164227df3f5dSRui Paulo u_int mlen; 16433c602fabSXin LI uint32_t flg_raw; 1644*ee67461eSJoseph Mingrone uint8_t tom; 164527df3f5dSRui Paulo const struct tom_h *tops; 164627df3f5dSRui Paulo int rc = 0; 164727df3f5dSRui Paulo 1648*ee67461eSJoseph Mingrone ndo->ndo_protocol = "forces"; 164927df3f5dSRui Paulo fhdr = (const struct forcesh *)pptr; 1650*ee67461eSJoseph Mingrone ND_TCHECK_SIZE(fhdr); 1651*ee67461eSJoseph Mingrone tom = GET_U_1(fhdr->fm_tom); 1652*ee67461eSJoseph Mingrone if (!tom_valid(tom)) { 1653*ee67461eSJoseph Mingrone ND_PRINT("Invalid ForCES message type %u\n", tom); 165427df3f5dSRui Paulo goto error; 165527df3f5dSRui Paulo } 165627df3f5dSRui Paulo 165727df3f5dSRui Paulo mlen = ForCES_BLN(fhdr); 165827df3f5dSRui Paulo 1659*ee67461eSJoseph Mingrone tops = get_forces_tom(tom); 166027df3f5dSRui Paulo if (tops->v == TOM_RSVD) { 1661*ee67461eSJoseph Mingrone ND_PRINT("\n\tUnknown ForCES message type=0x%x", tom); 166227df3f5dSRui Paulo goto error; 166327df3f5dSRui Paulo } 166427df3f5dSRui Paulo 1665*ee67461eSJoseph Mingrone ND_PRINT("\n\tForCES %s ", tops->s); 166627df3f5dSRui Paulo if (!ForCES_HLN_VALID(mlen, len)) { 1667*ee67461eSJoseph Mingrone ND_PRINT("Illegal ForCES pkt len - min %u, total recvd %u, advertised %u ", 1668*ee67461eSJoseph Mingrone ForCES_HDRL, len, ForCES_BLN(fhdr)); 166927df3f5dSRui Paulo goto error; 167027df3f5dSRui Paulo } 167127df3f5dSRui Paulo 1672*ee67461eSJoseph Mingrone flg_raw = GET_BE_U_4(pptr + 20); 16733c602fabSXin LI if (ndo->ndo_vflag >= 1) { 1674*ee67461eSJoseph Mingrone ND_PRINT("\n\tForCES Version %u len %uB flags 0x%08x ", 1675*ee67461eSJoseph Mingrone ForCES_V(fhdr), mlen, flg_raw); 1676*ee67461eSJoseph Mingrone ND_PRINT("\n\tSrcID 0x%x(%s) DstID 0x%x(%s) Correlator 0x%" PRIx64, 167727df3f5dSRui Paulo ForCES_SID(fhdr), ForCES_node(ForCES_SID(fhdr)), 167827df3f5dSRui Paulo ForCES_DID(fhdr), ForCES_node(ForCES_DID(fhdr)), 1679*ee67461eSJoseph Mingrone GET_BE_U_8(fhdr->fm_cor)); 168027df3f5dSRui Paulo 168127df3f5dSRui Paulo } 16823c602fabSXin LI if (ndo->ndo_vflag >= 2) { 1683*ee67461eSJoseph Mingrone ND_PRINT("\n\tForCES flags:\n\t %s(0x%x), prio=%u, %s(0x%x),\n\t %s(0x%x), %s(0x%x)\n", 16843c602fabSXin LI tok2str(ForCES_ACKs, "ACKUnknown", ForCES_ACK(fhdr)), 16853c602fabSXin LI ForCES_ACK(fhdr), 168627df3f5dSRui Paulo ForCES_PRI(fhdr), 16873c602fabSXin LI tok2str(ForCES_EMs, "EMUnknown", ForCES_EM(fhdr)), 16883c602fabSXin LI ForCES_EM(fhdr), 16893c602fabSXin LI tok2str(ForCES_ATs, "ATUnknown", ForCES_AT(fhdr)), 16903c602fabSXin LI ForCES_AT(fhdr), 16913c602fabSXin LI tok2str(ForCES_TPs, "TPUnknown", ForCES_TP(fhdr)), 1692*ee67461eSJoseph Mingrone ForCES_TP(fhdr)); 1693*ee67461eSJoseph Mingrone ND_PRINT("\t Extra flags: rsv(b5-7) 0x%x rsv(b13-31) 0x%x\n", 1694*ee67461eSJoseph Mingrone ForCES_RS1(fhdr), ForCES_RS2(fhdr)); 169527df3f5dSRui Paulo } 16963c602fabSXin LI rc = forces_type_print(ndo, pptr, fhdr, mlen, tops); 169727df3f5dSRui Paulo if (rc < 0) { 169827df3f5dSRui Paulo error: 1699*ee67461eSJoseph Mingrone hex_print(ndo, "\n\t[", pptr, len); 1700*ee67461eSJoseph Mingrone ND_PRINT("\n\t]"); 170127df3f5dSRui Paulo return; 170227df3f5dSRui Paulo } 170327df3f5dSRui Paulo 17043c602fabSXin LI if (ndo->ndo_vflag >= 4) { 1705*ee67461eSJoseph Mingrone ND_PRINT("\n\t Raw ForCES message\n\t ["); 1706*ee67461eSJoseph Mingrone hex_print(ndo, "\n\t ", pptr, len); 1707*ee67461eSJoseph Mingrone ND_PRINT("\n\t ]"); 170827df3f5dSRui Paulo } 170927df3f5dSRui Paulo return; 171027df3f5dSRui Paulo 171127df3f5dSRui Paulo trunc: 1712*ee67461eSJoseph Mingrone nd_print_trunc(ndo); 171327df3f5dSRui Paulo } 1714