1 /* 2 * Redistribution and use in source and binary forms, with or without 3 * modification, are permitted provided that: (1) source code 4 * distributions retain the above copyright notice and this paragraph 5 * in its entirety, and (2) distributions including binary code include 6 * the above copyright notice and this paragraph in its entirety in 7 * the documentation or other materials provided with the distribution. 8 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 9 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 10 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 11 * FOR A PARTICULAR PURPOSE. 12 * 13 * Copyright (c) 2009 Mojatatu Networks, Inc 14 * 15 */ 16 17 /* \summary: Forwarding and Control Element Separation (ForCES) Protocol printer */ 18 19 /* specification: RFC 5810 */ 20 21 #ifdef HAVE_CONFIG_H 22 #include <config.h> 23 #endif 24 25 #include "netdissect-stdinc.h" 26 27 #include "netdissect.h" 28 #include "extract.h" 29 30 31 #define ForCES_VERS 1 32 #define ForCES_HDRL 24 33 #define ForCES_ALNL 4U 34 #define TLV_HDRL 4 35 #define ILV_HDRL 8 36 37 #define TOM_RSVD 0x0 38 #define TOM_ASSNSETUP 0x1 39 #define TOM_ASSNTEARD 0x2 40 #define TOM_CONFIG 0x3 41 #define TOM_QUERY 0x4 42 #define TOM_EVENTNOT 0x5 43 #define TOM_PKTREDIR 0x6 44 #define TOM_HEARTBT 0x0F 45 #define TOM_ASSNSETREP 0x11 46 #define TOM_CONFIGREP 0x13 47 #define TOM_QUERYREP 0x14 48 49 /* 50 * tom_h Flags: resv1(8b):maxtlvs(4b):resv2(2b):mintlv(2b) 51 */ 52 #define ZERO_TTLV 0x01 53 #define ZERO_MORE_TTLV 0x02 54 #define ONE_MORE_TTLV 0x04 55 #define ZERO_TLV 0x00 56 #define ONE_TLV 0x10 57 #define TWO_TLV 0x20 58 #define MAX_TLV 0xF0 59 60 #define TTLV_T1 (ONE_MORE_TTLV|ONE_TLV) 61 #define TTLV_T2 (ONE_MORE_TTLV|MAX_TLV) 62 63 struct tom_h { 64 uint32_t v; 65 uint16_t flags; 66 uint16_t op_msk; 67 const char *s; 68 int (*print) (netdissect_options *ndo, const u_char * pptr, u_int len, 69 uint16_t op_msk, int indent); 70 }; 71 72 enum { 73 TOM_RSV_I, 74 TOM_ASS_I, 75 TOM_AST_I, 76 TOM_CFG_I, 77 TOM_QRY_I, 78 TOM_EVN_I, 79 TOM_RED_I, 80 TOM_HBT_I, 81 TOM_ASR_I, 82 TOM_CNR_I, 83 TOM_QRR_I, 84 _TOM_RSV_MAX 85 }; 86 #define TOM_MAX_IND (_TOM_RSV_MAX - 1) 87 88 static int 89 tom_valid(uint8_t tom) 90 { 91 if (tom > 0) { 92 if (tom >= 0x7 && tom <= 0xe) 93 return 0; 94 if (tom == 0x10) 95 return 0; 96 if (tom > 0x14) 97 return 0; 98 return 1; 99 } else 100 return 0; 101 } 102 103 static const char * 104 ForCES_node(uint32_t node) 105 { 106 if (node <= 0x3FFFFFFF) 107 return "FE"; 108 if (node >= 0x40000000 && node <= 0x7FFFFFFF) 109 return "CE"; 110 if (node >= 0xC0000000 && node <= 0xFFFFFFEF) 111 return "AllMulticast"; 112 if (node == 0xFFFFFFFD) 113 return "AllCEsBroadcast"; 114 if (node == 0xFFFFFFFE) 115 return "AllFEsBroadcast"; 116 if (node == 0xFFFFFFFF) 117 return "AllBroadcast"; 118 119 return "ForCESreserved"; 120 121 } 122 123 static const struct tok ForCES_ACKs[] = { 124 {0x0, "NoACK"}, 125 {0x1, "SuccessACK"}, 126 {0x2, "FailureACK"}, 127 {0x3, "AlwaysACK"}, 128 {0, NULL} 129 }; 130 131 static const struct tok ForCES_EMs[] = { 132 {0x0, "EMReserved"}, 133 {0x1, "execute-all-or-none"}, 134 {0x2, "execute-until-failure"}, 135 {0x3, "continue-execute-on-failure"}, 136 {0, NULL} 137 }; 138 139 static const struct tok ForCES_ATs[] = { 140 {0x0, "Standalone"}, 141 {0x1, "2PCtransaction"}, 142 {0, NULL} 143 }; 144 145 static const struct tok ForCES_TPs[] = { 146 {0x0, "StartofTransaction"}, 147 {0x1, "MiddleofTransaction"}, 148 {0x2, "EndofTransaction"}, 149 {0x3, "abort"}, 150 {0, NULL} 151 }; 152 153 /* 154 * Structure of forces header, naked of TLVs. 155 */ 156 struct forcesh { 157 nd_uint8_t fm_vrsvd; /* version and reserved */ 158 #define ForCES_V(forcesh) (GET_U_1((forcesh)->fm_vrsvd) >> 4) 159 nd_uint8_t fm_tom; /* type of message */ 160 nd_uint16_t fm_len; /* total length * 4 bytes */ 161 #define ForCES_BLN(forcesh) ((uint32_t)(GET_BE_U_2((forcesh)->fm_len) << 2)) 162 nd_uint32_t fm_sid; /* Source ID */ 163 #define ForCES_SID(forcesh) GET_BE_U_4((forcesh)->fm_sid) 164 nd_uint32_t fm_did; /* Destination ID */ 165 #define ForCES_DID(forcesh) GET_BE_U_4((forcesh)->fm_did) 166 nd_uint8_t fm_cor[8]; /* correlator */ 167 nd_uint32_t fm_flags; /* flags */ 168 #define ForCES_ACK(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0xC0000000) >> 30) 169 #define ForCES_PRI(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x38000000) >> 27) 170 #define ForCES_RS1(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x07000000) >> 24) 171 #define ForCES_EM(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x00C00000) >> 22) 172 #define ForCES_AT(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x00200000) >> 21) 173 #define ForCES_TP(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x00180000) >> 19) 174 #define ForCES_RS2(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x0007FFFF) >> 0) 175 }; 176 177 #define ForCES_HLN_VALID(fhl,tlen) ((tlen) >= ForCES_HDRL && \ 178 (fhl) >= ForCES_HDRL && \ 179 (fhl) == (tlen)) 180 181 #define F_LFB_RSVD 0x0 182 #define F_LFB_FEO 0x1 183 #define F_LFB_FEPO 0x2 184 static const struct tok ForCES_LFBs[] = { 185 {F_LFB_RSVD, "Invalid TLV"}, 186 {F_LFB_FEO, "FEObj LFB"}, 187 {F_LFB_FEPO, "FEProtoObj LFB"}, 188 {0, NULL} 189 }; 190 191 /* this is defined in RFC5810 section A.2 */ 192 /* https://www.iana.org/assignments/forces/forces.xhtml#oper-tlv-types */ 193 enum { 194 F_OP_RSV = 0, 195 F_OP_SET = 1, 196 F_OP_SETPROP = 2, 197 F_OP_SETRESP = 3, 198 F_OP_SETPRESP = 4, 199 F_OP_DEL = 5, 200 F_OP_DELRESP = 6, 201 F_OP_GET = 7, 202 F_OP_GETPROP = 8, 203 F_OP_GETRESP = 9, 204 F_OP_GETPRESP = 10, 205 F_OP_REPORT = 11, 206 F_OP_COMMIT = 12, 207 F_OP_RCOMMIT = 13, 208 F_OP_RTRCOMP = 14, 209 _F_OP_MAX 210 }; 211 #define F_OP_MAX (_F_OP_MAX - 1) 212 213 enum { 214 B_OP_SET = 1 << (F_OP_SET - 1), 215 B_OP_SETPROP = 1 << (F_OP_SETPROP - 1), 216 B_OP_SETRESP = 1 << (F_OP_SETRESP - 1), 217 B_OP_SETPRESP = 1 << (F_OP_SETPRESP - 1), 218 B_OP_DEL = 1 << (F_OP_DEL - 1), 219 B_OP_DELRESP = 1 << (F_OP_DELRESP - 1), 220 B_OP_GET = 1 << (F_OP_GET - 1), 221 B_OP_GETPROP = 1 << (F_OP_GETPROP - 1), 222 B_OP_GETRESP = 1 << (F_OP_GETRESP - 1), 223 B_OP_GETPRESP = 1 << (F_OP_GETPRESP - 1), 224 B_OP_REPORT = 1 << (F_OP_REPORT - 1), 225 B_OP_COMMIT = 1 << (F_OP_COMMIT - 1), 226 B_OP_RCOMMIT = 1 << (F_OP_RCOMMIT - 1), 227 B_OP_RTRCOMP = 1 << (F_OP_RTRCOMP - 1) 228 }; 229 230 struct optlv_h { 231 uint16_t flags; 232 uint16_t op_msk; 233 const char *s; 234 int (*print) (netdissect_options *ndo, const u_char * pptr, u_int len, 235 uint16_t op_msk, int indent); 236 }; 237 238 static int genoptlv_print(netdissect_options *, const u_char * pptr, u_int len, 239 uint16_t op_msk, int indent); 240 static int recpdoptlv_print(netdissect_options *, const u_char * pptr, u_int len, 241 uint16_t op_msk, int indent); 242 static int invoptlv_print(netdissect_options *, const u_char * pptr, u_int len, 243 uint16_t op_msk, int indent); 244 245 #define OP_MIN_SIZ 8 246 struct pathdata_h { 247 nd_uint16_t pflags; 248 nd_uint16_t pIDcnt; 249 }; 250 251 #define B_FULLD 0x1 252 #define B_SPARD 0x2 253 #define B_RESTV 0x4 254 #define B_KEYIN 0x8 255 #define B_APPND 0x10 256 #define B_TRNG 0x20 257 258 static const struct optlv_h OPTLV_msg[F_OP_MAX + 1] = { 259 /* F_OP_RSV */ {ZERO_TTLV, 0, "Invalid OPTLV", invoptlv_print}, 260 /* F_OP_SET */ {TTLV_T2, B_FULLD | B_SPARD, " Set", recpdoptlv_print}, 261 /* F_OP_SETPROP */ 262 {TTLV_T2, B_FULLD | B_SPARD, " SetProp", recpdoptlv_print}, 263 /* F_OP_SETRESP */ {TTLV_T2, B_RESTV, " SetResp", recpdoptlv_print}, 264 /* F_OP_SETPRESP */ {TTLV_T2, B_RESTV, " SetPropResp", recpdoptlv_print}, 265 /* F_OP_DEL */ {ZERO_TTLV, 0, " Del", recpdoptlv_print}, 266 /* F_OP_DELRESP */ {TTLV_T2, B_RESTV, " DelResp", recpdoptlv_print}, 267 /* F_OP_GET */ {ZERO_TTLV, 0, " Get", recpdoptlv_print}, 268 /* F_OP_GETPROP */ {ZERO_TTLV, 0, " GetProp", recpdoptlv_print}, 269 /* F_OP_GETRESP */ 270 {TTLV_T2, B_FULLD | B_SPARD | B_RESTV, " GetResp", recpdoptlv_print}, 271 /* F_OP_GETPRESP */ 272 {TTLV_T2, B_FULLD | B_RESTV, " GetPropResp", recpdoptlv_print}, 273 /* F_OP_REPORT */ 274 {TTLV_T2, B_FULLD | B_SPARD, " Report", recpdoptlv_print}, 275 /* F_OP_COMMIT */ {ZERO_TTLV, 0, " Commit", NULL}, 276 /* F_OP_RCOMMIT */ {TTLV_T1, B_RESTV, " RCommit", genoptlv_print}, 277 /* F_OP_RTRCOMP */ {ZERO_TTLV, 0, " RTRCOMP", NULL}, 278 }; 279 280 static const struct optlv_h * 281 get_forces_optlv_h(uint16_t opt) 282 { 283 if (opt > F_OP_MAX || opt == F_OP_RSV) 284 return &OPTLV_msg[F_OP_RSV]; 285 286 return &OPTLV_msg[opt]; 287 } 288 289 #define IND_SIZE 256 290 #define IND_CHR ' ' 291 #define IND_PREF '\n' 292 #define IND_SUF 0x0 293 static char ind_buf[IND_SIZE]; 294 295 static char * 296 indent_pr(int indent, int nlpref) 297 { 298 int i = 0; 299 char *r = ind_buf; 300 301 if (indent > (IND_SIZE - 1)) 302 indent = IND_SIZE - 1; 303 304 if (nlpref) { 305 r[i] = IND_PREF; 306 i++; 307 indent--; 308 } 309 310 while (--indent >= 0) 311 r[i++] = IND_CHR; 312 313 r[i] = IND_SUF; 314 return r; 315 } 316 317 static int 318 op_valid(uint16_t op, uint16_t mask) 319 { 320 if (op == 0) 321 return 0; 322 if (op <= F_OP_MAX) 323 return (1 << (op - 1)) & mask; /* works only for 0x0001 through 0x0010 */ 324 /* I guess we should allow vendor operations? */ 325 if (op >= 0x8000) 326 return 1; 327 return 0; 328 } 329 330 #define F_TLV_RSVD 0x0000 331 #define F_TLV_REDR 0x0001 332 #define F_TLV_ASRS 0x0010 333 #define F_TLV_ASRT 0x0011 334 #define F_TLV_LFBS 0x1000 335 #define F_TLV_PDAT 0x0110 336 #define F_TLV_KEYI 0x0111 337 #define F_TLV_FULD 0x0112 338 #define F_TLV_SPAD 0x0113 339 #define F_TLV_REST 0x0114 340 #define F_TLV_METD 0x0115 341 #define F_TLV_REDD 0x0116 342 #define F_TLV_TRNG 0x0117 343 344 345 #define F_TLV_VNST 0x8000 346 347 static const struct tok ForCES_TLV[] = { 348 {F_TLV_RSVD, "Invalid TLV"}, 349 {F_TLV_REDR, "REDIRECT TLV"}, 350 {F_TLV_ASRS, "ASResult TLV"}, 351 {F_TLV_ASRT, "ASTreason TLV"}, 352 {F_TLV_LFBS, "LFBselect TLV"}, 353 {F_TLV_PDAT, "PATH-DATA TLV"}, 354 {F_TLV_KEYI, "KEYINFO TLV"}, 355 {F_TLV_FULD, "FULLDATA TLV"}, 356 {F_TLV_SPAD, "SPARSEDATA TLV"}, 357 {F_TLV_REST, "RESULT TLV"}, 358 {F_TLV_METD, "METADATA TLV"}, 359 {F_TLV_REDD, "REDIRECTDATA TLV"}, 360 {0, NULL} 361 }; 362 363 #define TLV_HLN 4 364 static int 365 ttlv_valid(uint16_t ttlv) 366 { 367 if (ttlv > 0) { 368 if (ttlv == 1 || ttlv == 0x1000) 369 return 1; 370 if (ttlv >= 0x10 && ttlv <= 0x11) 371 return 1; 372 if (ttlv >= 0x110 && ttlv <= 0x116) 373 return 1; 374 if (ttlv >= 0x8000) 375 return 0; /* XXX: */ 376 } 377 378 return 0; 379 } 380 381 struct forces_ilv { 382 nd_uint32_t type; 383 nd_uint32_t length; 384 }; 385 386 struct forces_tlv { 387 nd_uint16_t type; 388 nd_uint16_t length; 389 }; 390 391 #define F_ALN_LEN(len) roundup2(len, ForCES_ALNL) 392 #define GET_TOP_TLV(fhdr) ((const struct forces_tlv *)((fhdr) + sizeof (struct forcesh))) 393 #define TLV_SET_LEN(len) (F_ALN_LEN(TLV_HDRL) + (len)) 394 #define TLV_DATA(tlvp) ((const void*)(((const char*)(tlvp)) + TLV_SET_LEN(0))) 395 #define GO_NXT_TLV(tlv,rlen) ((rlen) -= F_ALN_LEN(GET_BE_U_2((tlv)->length)), \ 396 (const struct forces_tlv*)(((const char*)(tlv)) \ 397 + F_ALN_LEN(GET_BE_U_2((tlv)->length)))) 398 #define ILV_SET_LEN(len) (F_ALN_LEN(ILV_HDRL) + (len)) 399 #define ILV_DATA(ilvp) ((const void*)(((const char*)(ilvp)) + ILV_SET_LEN(0))) 400 #define GO_NXT_ILV(ilv,rlen) ((rlen) -= F_ALN_LEN(GET_BE_U_4((ilv)->length)), \ 401 (const struct forces_ilv *)(((const char*)(ilv)) \ 402 + F_ALN_LEN(GET_BE_U_4((ilv)->length)))) 403 #define INVALID_RLEN 1 404 #define INVALID_STLN 2 405 #define INVALID_LTLN 3 406 #define INVALID_ALEN 4 407 408 static const struct tok ForCES_TLV_err[] = { 409 {INVALID_RLEN, "Invalid total length"}, 410 {INVALID_STLN, "xLV too short"}, 411 {INVALID_LTLN, "xLV too long"}, 412 {INVALID_ALEN, "data padding missing"}, 413 {0, NULL} 414 }; 415 416 static u_int 417 tlv_valid(u_int tlvl, u_int rlen) 418 { 419 if (rlen < TLV_HDRL) 420 return INVALID_RLEN; 421 if (tlvl < TLV_HDRL) 422 return INVALID_STLN; 423 if (tlvl > rlen) 424 return INVALID_LTLN; 425 if (rlen < F_ALN_LEN(tlvl)) 426 return INVALID_ALEN; 427 428 return 0; 429 } 430 431 static int 432 ilv_valid(netdissect_options *ndo, const struct forces_ilv *ilv, u_int rlen) 433 { 434 if (rlen < ILV_HDRL) 435 return INVALID_RLEN; 436 if (GET_BE_U_4(ilv->length) < ILV_HDRL) 437 return INVALID_STLN; 438 if (GET_BE_U_4(ilv->length) > rlen) 439 return INVALID_LTLN; 440 if (rlen < F_ALN_LEN(GET_BE_U_4(ilv->length))) 441 return INVALID_ALEN; 442 443 return 0; 444 } 445 446 static int lfbselect_print(netdissect_options *, const u_char * pptr, u_int len, 447 uint16_t op_msk, int indent); 448 static int redirect_print(netdissect_options *, const u_char * pptr, u_int len, 449 uint16_t op_msk, int indent); 450 static int asrtlv_print(netdissect_options *, const u_char * pptr, u_int len, 451 uint16_t op_msk, int indent); 452 static int asttlv_print(netdissect_options *, const u_char * pptr, u_int len, 453 uint16_t op_msk, int indent); 454 455 struct forces_lfbsh { 456 nd_uint32_t class; 457 nd_uint32_t instance; 458 }; 459 460 #define ASSNS_OPS (B_OP_REPORT) 461 #define CFG_OPS (B_OP_SET|B_OP_SETPROP|B_OP_DEL|B_OP_COMMIT|B_OP_RTRCOMP) 462 #define CFG_ROPS (B_OP_SETRESP|B_OP_SETPRESP|B_OP_DELRESP|B_OP_RCOMMIT) 463 #define CFG_QY (B_OP_GET|B_OP_GETPROP) 464 #define CFG_QYR (B_OP_GETRESP|B_OP_GETPRESP) 465 #define CFG_EVN (B_OP_REPORT) 466 467 static const struct tom_h ForCES_msg[TOM_MAX_IND + 1] = { 468 /* TOM_RSV_I */ {TOM_RSVD, ZERO_TTLV, 0, "Invalid message", NULL}, 469 /* TOM_ASS_I */ {TOM_ASSNSETUP, ZERO_MORE_TTLV | TWO_TLV, ASSNS_OPS, 470 "Association Setup", lfbselect_print}, 471 /* TOM_AST_I */ 472 {TOM_ASSNTEARD, TTLV_T1, 0, "Association TearDown", asttlv_print}, 473 /* TOM_CFG_I */ {TOM_CONFIG, TTLV_T2, CFG_OPS, "Config", lfbselect_print}, 474 /* TOM_QRY_I */ {TOM_QUERY, TTLV_T2, CFG_QY, "Query", lfbselect_print}, 475 /* TOM_EVN_I */ {TOM_EVENTNOT, TTLV_T1, CFG_EVN, "Event Notification", 476 lfbselect_print}, 477 /* TOM_RED_I */ 478 {TOM_PKTREDIR, TTLV_T2, 0, "Packet Redirect", redirect_print}, 479 /* TOM_HBT_I */ {TOM_HEARTBT, ZERO_TTLV, 0, "HeartBeat", NULL}, 480 /* TOM_ASR_I */ 481 {TOM_ASSNSETREP, TTLV_T1, 0, "Association Response", asrtlv_print}, 482 /* TOM_CNR_I */ {TOM_CONFIGREP, TTLV_T2, CFG_ROPS, "Config Response", 483 lfbselect_print}, 484 /* TOM_QRR_I */ 485 {TOM_QUERYREP, TTLV_T2, CFG_QYR, "Query Response", lfbselect_print}, 486 }; 487 488 static const struct tom_h * 489 get_forces_tom(uint8_t tom) 490 { 491 int i; 492 for (i = TOM_RSV_I; i <= TOM_MAX_IND; i++) { 493 const struct tom_h *th = &ForCES_msg[i]; 494 if (th->v == tom) 495 return th; 496 } 497 return &ForCES_msg[TOM_RSV_I]; 498 } 499 500 struct pdata_ops { 501 uint32_t v; 502 uint16_t flags; 503 uint16_t op_msk; 504 const char *s; 505 int (*print) (netdissect_options *, const u_char * pptr, u_int len, 506 uint16_t op_msk, int indent); 507 }; 508 509 enum { 510 PD_RSV_I, 511 PD_SEL_I, 512 PD_FDT_I, 513 PD_SDT_I, 514 PD_RES_I, 515 PD_PDT_I, 516 _PD_RSV_MAX 517 }; 518 #define PD_MAX_IND (_TOM_RSV_MAX - 1) 519 520 static int 521 pd_valid(uint16_t pd) 522 { 523 if (pd >= F_TLV_PDAT && pd <= F_TLV_REST) 524 return 1; 525 return 0; 526 } 527 528 static void 529 chk_op_type(netdissect_options *ndo, 530 uint16_t type, uint16_t msk, uint16_t omsk) 531 { 532 if (type != F_TLV_PDAT) { 533 if (msk & B_KEYIN) { 534 if (type != F_TLV_KEYI) { 535 ND_PRINT("Based on flags expected KEYINFO TLV!\n"); 536 } 537 } else { 538 if (!(msk & omsk)) { 539 ND_PRINT("Illegal DATA encoding for type 0x%x programmed %x got %x\n", 540 type, omsk, msk); 541 } 542 } 543 } 544 545 } 546 547 #define F_SELKEY 1 548 #define F_SELTABRANGE 2 549 #define F_TABAPPEND 4 550 551 struct res_val { 552 nd_uint8_t result; 553 nd_uint8_t resv1; 554 nd_uint16_t resv2; 555 }; 556 557 static int prestlv_print(netdissect_options *, const u_char * pptr, u_int len, 558 uint16_t op_msk, int indent); 559 static int pkeyitlv_print(netdissect_options *, const u_char * pptr, u_int len, 560 uint16_t op_msk, int indent); 561 static int fdatatlv_print(netdissect_options *, const u_char * pptr, u_int len, 562 uint16_t op_msk, int indent); 563 static int sdatatlv_print(netdissect_options *, const u_char * pptr, u_int len, 564 uint16_t op_msk, int indent); 565 566 static const struct pdata_ops ForCES_pdata[PD_MAX_IND + 1] = { 567 /* PD_RSV_I */ {0, 0, 0, "Invalid message", NULL}, 568 /* PD_SEL_I */ {F_TLV_KEYI, 0, 0, "KEYINFO TLV", pkeyitlv_print}, 569 /* PD_FDT_I */ {F_TLV_FULD, 0, B_FULLD, "FULLDATA TLV", fdatatlv_print}, 570 /* PD_SDT_I */ {F_TLV_SPAD, 0, B_SPARD, "SPARSEDATA TLV", sdatatlv_print}, 571 /* PD_RES_I */ {F_TLV_REST, 0, B_RESTV, "RESULT TLV", prestlv_print}, 572 /* PD_PDT_I */ 573 {F_TLV_PDAT, 0, 0, "Inner PATH-DATA TLV", recpdoptlv_print}, 574 }; 575 576 static const struct pdata_ops * 577 get_forces_pd(uint16_t pd) 578 { 579 int i; 580 for (i = PD_RSV_I + 1; i <= PD_MAX_IND; i++) { 581 const struct pdata_ops *pdo = &ForCES_pdata[i]; 582 if (pdo->v == pd) 583 return pdo; 584 } 585 return &ForCES_pdata[TOM_RSV_I]; 586 } 587 588 enum { 589 E_SUCCESS, 590 E_INVALID_HEADER, 591 E_LENGTH_MISMATCH, 592 E_VERSION_MISMATCH, 593 E_INVALID_DESTINATION_PID, 594 E_LFB_UNKNOWN, 595 E_LFB_NOT_FOUND, 596 E_LFB_INSTANCE_ID_NOT_FOUND, 597 E_INVALID_PATH, 598 E_COMPONENT_DOES_NOT_EXIST, 599 E_EXISTS, 600 E_NOT_FOUND, 601 E_READ_ONLY, 602 E_INVALID_ARRAY_CREATION, 603 E_VALUE_OUT_OF_RANGE, 604 E_CONTENTS_TOO_LONG, 605 E_INVALID_PARAMETERS, 606 E_INVALID_MESSAGE_TYPE, 607 E_INVALID_FLAGS, 608 E_INVALID_TLV, 609 E_EVENT_ERROR, 610 E_NOT_SUPPORTED, 611 E_MEMORY_ERROR, 612 E_INTERNAL_ERROR, 613 /* 0x18-0xFE are reserved .. */ 614 E_UNSPECIFIED_ERROR = 0XFF 615 }; 616 617 static const struct tok ForCES_errs[] = { 618 {E_SUCCESS, "SUCCESS"}, 619 {E_INVALID_HEADER, "INVALID HEADER"}, 620 {E_LENGTH_MISMATCH, "LENGTH MISMATCH"}, 621 {E_VERSION_MISMATCH, "VERSION MISMATCH"}, 622 {E_INVALID_DESTINATION_PID, "INVALID DESTINATION PID"}, 623 {E_LFB_UNKNOWN, "LFB UNKNOWN"}, 624 {E_LFB_NOT_FOUND, "LFB NOT FOUND"}, 625 {E_LFB_INSTANCE_ID_NOT_FOUND, "LFB INSTANCE ID NOT FOUND"}, 626 {E_INVALID_PATH, "INVALID PATH"}, 627 {E_COMPONENT_DOES_NOT_EXIST, "COMPONENT DOES NOT EXIST"}, 628 {E_EXISTS, "EXISTS ALREADY"}, 629 {E_NOT_FOUND, "NOT FOUND"}, 630 {E_READ_ONLY, "READ ONLY"}, 631 {E_INVALID_ARRAY_CREATION, "INVALID ARRAY CREATION"}, 632 {E_VALUE_OUT_OF_RANGE, "VALUE OUT OF RANGE"}, 633 {E_CONTENTS_TOO_LONG, "CONTENTS TOO LONG"}, 634 {E_INVALID_PARAMETERS, "INVALID PARAMETERS"}, 635 {E_INVALID_MESSAGE_TYPE, "INVALID MESSAGE TYPE"}, 636 {E_INVALID_FLAGS, "INVALID FLAGS"}, 637 {E_INVALID_TLV, "INVALID TLV"}, 638 {E_EVENT_ERROR, "EVENT ERROR"}, 639 {E_NOT_SUPPORTED, "NOT SUPPORTED"}, 640 {E_MEMORY_ERROR, "MEMORY ERROR"}, 641 {E_INTERNAL_ERROR, "INTERNAL ERROR"}, 642 {E_UNSPECIFIED_ERROR, "UNSPECIFIED ERROR"}, 643 {0, NULL} 644 }; 645 646 #define RESLEN 4 647 648 static int 649 prestlv_print(netdissect_options *ndo, 650 const u_char * pptr, u_int len, 651 uint16_t op_msk _U_, int indent) 652 { 653 const struct forces_tlv *tlv = (const struct forces_tlv *)pptr; 654 const u_char *tdp = (const u_char *) TLV_DATA(tlv); 655 const struct res_val *r = (const struct res_val *)tdp; 656 u_int dlen; 657 uint8_t result; 658 659 /* 660 * pdatacnt_print() has ensured that len (the TLV length) 661 * >= TLV_HDRL. 662 */ 663 dlen = len - TLV_HDRL; 664 if (dlen != RESLEN) { 665 ND_PRINT("illegal RESULT-TLV: %u bytes!\n", dlen); 666 return -1; 667 } 668 669 ND_TCHECK_SIZE(r); 670 result = GET_U_1(r->result); 671 if (result >= 0x18 && result <= 0xFE) { 672 ND_PRINT("illegal reserved result code: 0x%x!\n", result); 673 return -1; 674 } 675 676 if (ndo->ndo_vflag >= 3) { 677 char *ib = indent_pr(indent, 0); 678 ND_PRINT("%s Result: %s (code 0x%x)\n", ib, 679 tok2str(ForCES_errs, NULL, result), result); 680 } 681 return 0; 682 683 trunc: 684 nd_print_trunc(ndo); 685 return -1; 686 } 687 688 static int 689 fdatatlv_print(netdissect_options *ndo, 690 const u_char * pptr, u_int len, 691 uint16_t op_msk _U_, int indent) 692 { 693 const struct forces_tlv *tlv = (const struct forces_tlv *)pptr; 694 u_int rlen; 695 const u_char *tdp = (const u_char *) TLV_DATA(tlv); 696 uint16_t type; 697 698 /* 699 * pdatacnt_print() or pkeyitlv_print() has ensured that len 700 * (the TLV length) >= TLV_HDRL. 701 */ 702 rlen = len - TLV_HDRL; 703 ND_TCHECK_SIZE(tlv); 704 type = GET_BE_U_2(tlv->type); 705 if (type != F_TLV_FULD) { 706 ND_PRINT("Error: expecting FULLDATA!\n"); 707 return -1; 708 } 709 710 if (ndo->ndo_vflag >= 3) { 711 char *ib = indent_pr(indent + 2, 1); 712 ND_PRINT("%s[", ib + 1); 713 hex_print(ndo, ib, tdp, rlen); 714 ND_PRINT("\n%s]", ib + 1); 715 } 716 return 0; 717 718 trunc: 719 nd_print_trunc(ndo); 720 return -1; 721 } 722 723 static int 724 sdatailv_print(netdissect_options *ndo, 725 const u_char * pptr, u_int len, 726 uint16_t op_msk _U_, int indent) 727 { 728 u_int rlen; 729 const struct forces_ilv *ilv = (const struct forces_ilv *)pptr; 730 int invilv; 731 732 if (len < ILV_HDRL) { 733 ND_PRINT("Error: BAD SPARSEDATA-TLV!\n"); 734 return -1; 735 } 736 rlen = len; 737 indent += 1; 738 while (rlen != 0) { 739 #if 0 740 ND_PRINT("Jamal - outstanding length <%u>\n", rlen); 741 #endif 742 char *ib = indent_pr(indent, 1); 743 const u_char *tdp = (const u_char *) ILV_DATA(ilv); 744 invilv = ilv_valid(ndo, ilv, rlen); 745 if (invilv) { 746 ND_PRINT("Error: %s, rlen %u\n", 747 tok2str(ForCES_TLV_err, NULL, invilv), rlen); 748 return -1; 749 } 750 if (ndo->ndo_vflag >= 3) { 751 u_int ilvl = GET_BE_U_4(ilv->length); 752 ND_PRINT("\n%s ILV: type %x length %u\n", ib + 1, 753 GET_BE_U_4(ilv->type), ilvl); 754 hex_print(ndo, "\t\t[", tdp, ilvl-ILV_HDRL); 755 } 756 757 ilv = GO_NXT_ILV(ilv, rlen); 758 } 759 760 return 0; 761 } 762 763 static int 764 sdatatlv_print(netdissect_options *ndo, 765 const u_char * pptr, u_int len, 766 uint16_t op_msk, int indent) 767 { 768 const struct forces_tlv *tlv = (const struct forces_tlv *)pptr; 769 u_int rlen; 770 const u_char *tdp = (const u_char *) TLV_DATA(tlv); 771 uint16_t type; 772 773 /* 774 * pdatacnt_print() has ensured that len (the TLV length) 775 * >= TLV_HDRL. 776 */ 777 rlen = len - TLV_HDRL; 778 ND_TCHECK_SIZE(tlv); 779 type = GET_BE_U_2(tlv->type); 780 if (type != F_TLV_SPAD) { 781 ND_PRINT("Error: expecting SPARSEDATA!\n"); 782 return -1; 783 } 784 785 return sdatailv_print(ndo, tdp, rlen, op_msk, indent); 786 787 trunc: 788 nd_print_trunc(ndo); 789 return -1; 790 } 791 792 static int 793 pkeyitlv_print(netdissect_options *ndo, 794 const u_char * pptr, u_int len, 795 uint16_t op_msk, int indent) 796 { 797 const struct forces_tlv *tlv = (const struct forces_tlv *)pptr; 798 const u_char *tdp = (const u_char *) TLV_DATA(tlv); 799 const u_char *dp = tdp + 4; 800 const struct forces_tlv *kdtlv = (const struct forces_tlv *)dp; 801 uint32_t id; 802 char *ib = indent_pr(indent, 0); 803 uint16_t type, tll; 804 u_int invtlv; 805 806 id = GET_BE_U_4(tdp); 807 ND_PRINT("%sKeyinfo: Key 0x%x\n", ib, id); 808 type = GET_BE_U_2(kdtlv->type); 809 tll = GET_BE_U_2(kdtlv->length); 810 invtlv = tlv_valid(tll, len); 811 812 if (invtlv) { 813 ND_PRINT("%s TLV type 0x%x len %u\n", 814 tok2str(ForCES_TLV_err, NULL, invtlv), type, 815 tll); 816 return -1; 817 } 818 /* 819 * At this point, tlv_valid() has ensured that the TLV 820 * length is large enough but not too large (it doesn't 821 * go past the end of the containing TLV). 822 */ 823 tll = GET_BE_U_2(kdtlv->length); 824 dp = (const u_char *) TLV_DATA(kdtlv); 825 return fdatatlv_print(ndo, dp, tll, op_msk, indent); 826 } 827 828 #define PTH_DESC_SIZE 12 829 830 static int 831 pdatacnt_print(netdissect_options *ndo, 832 const u_char * pptr, u_int len, 833 uint16_t IDcnt, uint16_t op_msk, int indent) 834 { 835 u_int i; 836 uint32_t id; 837 char *ib = indent_pr(indent, 0); 838 839 if ((op_msk & B_APPND) && ndo->ndo_vflag >= 3) { 840 ND_PRINT("%sTABLE APPEND\n", ib); 841 } 842 for (i = 0; i < IDcnt; i++) { 843 ND_TCHECK_4(pptr); 844 if (len < 4) 845 goto trunc; 846 id = GET_BE_U_4(pptr); 847 if (ndo->ndo_vflag >= 3) 848 ND_PRINT("%sID#%02u: %u\n", ib, i + 1, id); 849 len -= 4; 850 pptr += 4; 851 } 852 853 if ((op_msk & B_TRNG) || (op_msk & B_KEYIN)) { 854 if (op_msk & B_TRNG) { 855 uint32_t starti, endi; 856 857 if (len < PTH_DESC_SIZE) { 858 ND_PRINT("pathlength %u with key/range too short %u\n", 859 len, PTH_DESC_SIZE); 860 return -1; 861 } 862 863 pptr += sizeof(struct forces_tlv); 864 len -= sizeof(struct forces_tlv); 865 866 starti = GET_BE_U_4(pptr); 867 pptr += 4; 868 len -= 4; 869 870 endi = GET_BE_U_4(pptr); 871 pptr += 4; 872 len -= 4; 873 874 if (ndo->ndo_vflag >= 3) 875 ND_PRINT("%sTable range: [%u,%u]\n", ib, starti, endi); 876 } 877 878 if (op_msk & B_KEYIN) { 879 const struct forces_tlv *keytlv; 880 uint16_t tll; 881 882 if (len < PTH_DESC_SIZE) { 883 ND_PRINT("pathlength %u with key/range too short %u\n", 884 len, PTH_DESC_SIZE); 885 return -1; 886 } 887 888 /* skip keyid */ 889 pptr += 4; 890 len -= 4; 891 keytlv = (const struct forces_tlv *)pptr; 892 /* skip header */ 893 pptr += sizeof(struct forces_tlv); 894 len -= sizeof(struct forces_tlv); 895 /* skip key content */ 896 tll = GET_BE_U_2(keytlv->length); 897 if (tll < TLV_HDRL) { 898 ND_PRINT("key content length %u < %u\n", 899 tll, TLV_HDRL); 900 return -1; 901 } 902 tll -= TLV_HDRL; 903 if (len < tll) { 904 ND_PRINT("key content too short\n"); 905 return -1; 906 } 907 pptr += tll; 908 len -= tll; 909 } 910 911 } 912 913 if (len) { 914 const struct forces_tlv *pdtlv = (const struct forces_tlv *)pptr; 915 uint16_t type; 916 uint16_t tlvl, tll; 917 u_int pad = 0; 918 u_int aln; 919 u_int invtlv; 920 921 type = GET_BE_U_2(pdtlv->type); 922 tlvl = GET_BE_U_2(pdtlv->length); 923 invtlv = tlv_valid(tlvl, len); 924 if (invtlv) { 925 ND_PRINT("%s Outstanding bytes %u for TLV type 0x%x TLV len %u\n", 926 tok2str(ForCES_TLV_err, NULL, invtlv), len, type, 927 tlvl); 928 goto pd_err; 929 } 930 /* 931 * At this point, tlv_valid() has ensured that the TLV 932 * length is large enough but not too large (it doesn't 933 * go past the end of the containing TLV). 934 */ 935 tll = tlvl - TLV_HDRL; 936 aln = F_ALN_LEN(tlvl); 937 if (aln > tlvl) { 938 if (aln > len) { 939 ND_PRINT("Invalid padded pathdata TLV type 0x%x len %u missing %u pad bytes\n", 940 type, tlvl, aln - len); 941 } else { 942 pad = aln - tlvl; 943 } 944 } 945 if (pd_valid(type)) { 946 const struct pdata_ops *ops = get_forces_pd(type); 947 948 if (ndo->ndo_vflag >= 3 && ops->v != F_TLV_PDAT) { 949 if (pad) 950 ND_PRINT("%s %s (Length %u DataLen %u pad %u Bytes)\n", 951 ib, ops->s, tlvl, tll, pad); 952 else 953 ND_PRINT("%s %s (Length %u DataLen %u Bytes)\n", 954 ib, ops->s, tlvl, tll); 955 } 956 957 chk_op_type(ndo, type, op_msk, ops->op_msk); 958 959 if (ops->print(ndo, (const u_char *)pdtlv, 960 tll + pad + TLV_HDRL, op_msk, 961 indent + 2) == -1) 962 return -1; 963 len -= (TLV_HDRL + pad + tll); 964 } else { 965 ND_PRINT("Invalid path data content type 0x%x len %u\n", 966 type, tlvl); 967 pd_err: 968 if (tlvl) { 969 hex_print(ndo, "Bad Data val\n\t [", 970 pptr, len); 971 ND_PRINT("]\n"); 972 973 return -1; 974 } 975 } 976 } 977 return len; 978 979 trunc: 980 nd_print_trunc(ndo); 981 return -1; 982 } 983 984 static int 985 pdata_print(netdissect_options *ndo, 986 const u_char * pptr, u_int len, 987 uint16_t op_msk, int indent) 988 { 989 const struct pathdata_h *pdh = (const struct pathdata_h *)pptr; 990 char *ib = indent_pr(indent, 0); 991 u_int minsize = 0; 992 int more_pd = 0; 993 uint16_t idcnt = 0; 994 995 ND_TCHECK_SIZE(pdh); 996 if (len < sizeof(struct pathdata_h)) 997 goto trunc; 998 if (ndo->ndo_vflag >= 3) { 999 ND_PRINT("\n%sPathdata: Flags 0x%x ID count %u\n", 1000 ib, GET_BE_U_2(pdh->pflags), 1001 GET_BE_U_2(pdh->pIDcnt)); 1002 } 1003 1004 if (GET_BE_U_2(pdh->pflags) & F_SELKEY) { 1005 op_msk |= B_KEYIN; 1006 } 1007 1008 /* Table GET Range operation */ 1009 if (GET_BE_U_2(pdh->pflags) & F_SELTABRANGE) { 1010 op_msk |= B_TRNG; 1011 } 1012 /* Table SET append operation */ 1013 if (GET_BE_U_2(pdh->pflags) & F_TABAPPEND) { 1014 op_msk |= B_APPND; 1015 } 1016 1017 pptr += sizeof(struct pathdata_h); 1018 len -= sizeof(struct pathdata_h); 1019 idcnt = GET_BE_U_2(pdh->pIDcnt); 1020 minsize = idcnt * 4; 1021 if (len < minsize) { 1022 ND_PRINT("\t\t\ttruncated IDs expected %uB got %uB\n", minsize, 1023 len); 1024 hex_print(ndo, "\t\t\tID Data[", pptr, len); 1025 ND_PRINT("]\n"); 1026 return -1; 1027 } 1028 1029 if ((op_msk & B_TRNG) && (op_msk & B_KEYIN)) { 1030 ND_PRINT("\t\t\tIllegal to have both Table ranges and keys\n"); 1031 return -1; 1032 } 1033 1034 more_pd = pdatacnt_print(ndo, pptr, len, idcnt, op_msk, indent); 1035 if (more_pd > 0) { 1036 int consumed = len - more_pd; 1037 pptr += consumed; 1038 len = more_pd; 1039 /* XXX: Argh, recurse some more */ 1040 return recpdoptlv_print(ndo, pptr, len, op_msk, indent+1); 1041 } else 1042 return 0; 1043 1044 trunc: 1045 nd_print_trunc(ndo); 1046 return -1; 1047 } 1048 1049 static int 1050 genoptlv_print(netdissect_options *ndo, 1051 const u_char * pptr, u_int len, 1052 uint16_t op_msk, int indent) 1053 { 1054 const struct forces_tlv *pdtlv = (const struct forces_tlv *)pptr; 1055 uint16_t type; 1056 u_int tlvl; 1057 u_int invtlv; 1058 char *ib = indent_pr(indent, 0); 1059 1060 type = GET_BE_U_2(pdtlv->type); 1061 tlvl = GET_BE_U_2(pdtlv->length); 1062 invtlv = tlv_valid(tlvl, len); 1063 ND_PRINT("genoptlvprint - %s TLV type 0x%x len %u\n", 1064 tok2str(ForCES_TLV, NULL, type), type, tlvl); 1065 if (!invtlv) { 1066 /* 1067 * At this point, tlv_valid() has ensured that the TLV 1068 * length is large enough but not too large (it doesn't 1069 * go past the end of the containing TLV). 1070 */ 1071 const u_char *dp = (const u_char *) TLV_DATA(pdtlv); 1072 1073 if (!ttlv_valid(type)) { 1074 ND_PRINT("%s TLV type 0x%x len %u\n", 1075 tok2str(ForCES_TLV_err, NULL, invtlv), type, 1076 tlvl); 1077 return -1; 1078 } 1079 if (ndo->ndo_vflag >= 3) 1080 ND_PRINT("%s%s, length %u (data length %u Bytes)", 1081 ib, tok2str(ForCES_TLV, NULL, type), 1082 tlvl, tlvl - TLV_HDRL); 1083 1084 return pdata_print(ndo, dp, tlvl - TLV_HDRL, op_msk, indent + 1); 1085 } else { 1086 ND_PRINT("\t\t\tInvalid ForCES TLV type=%x", type); 1087 return -1; 1088 } 1089 } 1090 1091 static int 1092 recpdoptlv_print(netdissect_options *ndo, 1093 const u_char * pptr, u_int len, 1094 uint16_t op_msk, int indent) 1095 { 1096 const struct forces_tlv *pdtlv = (const struct forces_tlv *)pptr; 1097 1098 while (len != 0) { 1099 uint16_t type, tlvl; 1100 u_int invtlv; 1101 char *ib; 1102 const u_char *dp; 1103 1104 tlvl = GET_BE_U_2(pdtlv->length); 1105 invtlv = tlv_valid(tlvl, len); 1106 if (invtlv) { 1107 break; 1108 } 1109 1110 /* 1111 * At this point, tlv_valid() has ensured that the TLV 1112 * length is large enough but not too large (it doesn't 1113 * go past the end of the containing TLV). 1114 */ 1115 ib = indent_pr(indent, 0); 1116 type = GET_BE_U_2(pdtlv->type); 1117 dp = (const u_char *) TLV_DATA(pdtlv); 1118 1119 if (ndo->ndo_vflag >= 3) 1120 ND_PRINT("%s%s, length %u (data encapsulated %u Bytes)", 1121 ib, tok2str(ForCES_TLV, NULL, type), 1122 tlvl, 1123 tlvl - TLV_HDRL); 1124 1125 if (pdata_print(ndo, dp, tlvl - TLV_HDRL, op_msk, indent + 1) == -1) 1126 return -1; 1127 pdtlv = GO_NXT_TLV(pdtlv, len); 1128 } 1129 1130 if (len) { 1131 ND_PRINT("\n\t\tMessy PATHDATA TLV header, type (0x%x)\n\t\texcess of %u Bytes ", 1132 GET_BE_U_2(pdtlv->type), 1133 len - GET_BE_U_2(pdtlv->length)); 1134 return -1; 1135 } 1136 1137 return 0; 1138 } 1139 1140 static int 1141 invoptlv_print(netdissect_options *ndo, 1142 const u_char * pptr, u_int len, 1143 uint16_t op_msk _U_, int indent) 1144 { 1145 char *ib = indent_pr(indent, 1); 1146 1147 if (ndo->ndo_vflag >= 3) { 1148 ND_PRINT("%sData[", ib + 1); 1149 hex_print(ndo, ib, pptr, len); 1150 ND_PRINT("%s]\n", ib); 1151 } 1152 return -1; 1153 } 1154 1155 static int 1156 otlv_print(netdissect_options *ndo, 1157 const struct forces_tlv *otlv, uint16_t op_msk _U_, int indent) 1158 { 1159 int rc = 0; 1160 const u_char *dp = (const u_char *) TLV_DATA(otlv); 1161 uint16_t type; 1162 u_int tll; 1163 char *ib = indent_pr(indent, 0); 1164 const struct optlv_h *ops; 1165 1166 /* 1167 * lfbselect_print() has ensured that GET_BE_U_2(otlv->length) 1168 * >= TLV_HDRL. 1169 */ 1170 type = GET_BE_U_2(otlv->type); 1171 tll = GET_BE_U_2(otlv->length) - TLV_HDRL; 1172 ops = get_forces_optlv_h(type); 1173 if (ndo->ndo_vflag >= 3) { 1174 ND_PRINT("%sOper TLV %s(0x%x) length %u\n", ib, ops->s, type, 1175 GET_BE_U_2(otlv->length)); 1176 } 1177 /* rest of ops must at least have 12B {pathinfo} */ 1178 if (tll < OP_MIN_SIZ) { 1179 ND_PRINT("\t\tOper TLV %s(0x%x) length %u\n", ops->s, type, 1180 GET_BE_U_2(otlv->length)); 1181 ND_PRINT("\t\tTruncated data size %u minimum required %u\n", tll, 1182 OP_MIN_SIZ); 1183 return invoptlv_print(ndo, dp, tll, ops->op_msk, indent); 1184 1185 } 1186 1187 /* XXX - do anything with ops->flags? */ 1188 if(ops->print) { 1189 rc = ops->print(ndo, dp, tll, ops->op_msk, indent + 1); 1190 } 1191 return rc; 1192 } 1193 1194 #define ASTDLN 4 1195 #define ASTMCD 255 1196 static int 1197 asttlv_print(netdissect_options *ndo, 1198 const u_char * pptr, u_int len, 1199 uint16_t op_msk _U_, int indent) 1200 { 1201 uint32_t rescode; 1202 u_int dlen; 1203 char *ib = indent_pr(indent, 0); 1204 1205 /* 1206 * forces_type_print() has ensured that len (the TLV length) 1207 * >= TLV_HDRL. 1208 */ 1209 dlen = len - TLV_HDRL; 1210 if (dlen != ASTDLN) { 1211 ND_PRINT("illegal ASTresult-TLV: %u bytes!\n", dlen); 1212 return -1; 1213 } 1214 rescode = GET_BE_U_4(pptr); 1215 if (rescode > ASTMCD) { 1216 ND_PRINT("illegal ASTresult result code: %u!\n", rescode); 1217 return -1; 1218 } 1219 1220 if (ndo->ndo_vflag >= 3) { 1221 ND_PRINT("Teardown reason:\n%s", ib); 1222 switch (rescode) { 1223 case 0: 1224 ND_PRINT("Normal Teardown"); 1225 break; 1226 case 1: 1227 ND_PRINT("Loss of Heartbeats"); 1228 break; 1229 case 2: 1230 ND_PRINT("Out of bandwidth"); 1231 break; 1232 case 3: 1233 ND_PRINT("Out of Memory"); 1234 break; 1235 case 4: 1236 ND_PRINT("Application Crash"); 1237 break; 1238 default: 1239 ND_PRINT("Unknown Teardown reason"); 1240 break; 1241 } 1242 ND_PRINT("(%x)\n%s", rescode, ib); 1243 } 1244 return 0; 1245 } 1246 1247 #define ASRDLN 4 1248 #define ASRMCD 3 1249 static int 1250 asrtlv_print(netdissect_options *ndo, 1251 const u_char * pptr, u_int len, 1252 uint16_t op_msk _U_, int indent) 1253 { 1254 uint32_t rescode; 1255 u_int dlen; 1256 char *ib = indent_pr(indent, 0); 1257 1258 /* 1259 * forces_type_print() has ensured that len (the TLV length) 1260 * >= TLV_HDRL. 1261 */ 1262 dlen = len - TLV_HDRL; 1263 if (dlen != ASRDLN) { /* id, instance, oper tlv */ 1264 ND_PRINT("illegal ASRresult-TLV: %u bytes!\n", dlen); 1265 return -1; 1266 } 1267 rescode = GET_BE_U_4(pptr); 1268 1269 if (rescode > ASRMCD) { 1270 ND_PRINT("illegal ASRresult result code: %u!\n", rescode); 1271 return -1; 1272 } 1273 1274 if (ndo->ndo_vflag >= 3) { 1275 ND_PRINT("\n%s", ib); 1276 switch (rescode) { 1277 case 0: 1278 ND_PRINT("Success "); 1279 break; 1280 case 1: 1281 ND_PRINT("FE ID invalid "); 1282 break; 1283 case 2: 1284 ND_PRINT("permission denied "); 1285 break; 1286 default: 1287 ND_PRINT("Unknown "); 1288 break; 1289 } 1290 ND_PRINT("(%x)\n%s", rescode, ib); 1291 } 1292 return 0; 1293 } 1294 1295 #if 0 1296 /* 1297 * XXX - not used. 1298 */ 1299 static int 1300 gentltlv_print(netdissect_options *ndo, 1301 const u_char * pptr _U_, u_int len, 1302 uint16_t op_msk _U_, int indent _U_) 1303 { 1304 u_int dlen = len - TLV_HDRL; 1305 1306 if (dlen < 4) { /* at least 32 bits must exist */ 1307 ND_PRINT("truncated TLV: %u bytes missing! ", 4 - dlen); 1308 return -1; 1309 } 1310 return 0; 1311 } 1312 #endif 1313 1314 #define RD_MIN 8 1315 1316 static int 1317 print_metailv(netdissect_options *ndo, 1318 const u_char * pptr, uint16_t op_msk _U_, int indent) 1319 { 1320 u_int rlen; 1321 char *ib = indent_pr(indent, 0); 1322 /* XXX: check header length */ 1323 const struct forces_ilv *ilv = (const struct forces_ilv *)pptr; 1324 1325 /* 1326 * print_metatlv() has ensured that len (what remains in the 1327 * ILV) >= ILV_HDRL. 1328 */ 1329 rlen = GET_BE_U_4(ilv->length) - ILV_HDRL; 1330 ND_PRINT("%sMetaID 0x%x length %u\n", ib, GET_BE_U_4(ilv->type), 1331 GET_BE_U_4(ilv->length)); 1332 if (ndo->ndo_vflag >= 3) { 1333 hex_print(ndo, "\t\t[", ILV_DATA(ilv), rlen); 1334 ND_PRINT(" ]\n"); 1335 } 1336 return 0; 1337 } 1338 1339 static int 1340 print_metatlv(netdissect_options *ndo, 1341 const u_char * pptr, u_int len, 1342 uint16_t op_msk _U_, int indent) 1343 { 1344 u_int dlen; 1345 char *ib = indent_pr(indent, 0); 1346 u_int rlen; 1347 const struct forces_ilv *ilv = (const struct forces_ilv *)pptr; 1348 int invilv; 1349 1350 /* 1351 * redirect_print() has ensured that len (what remains in the 1352 * TLV) >= TLV_HDRL. 1353 */ 1354 dlen = len - TLV_HDRL; 1355 rlen = dlen; 1356 ND_PRINT("\n%s METADATA length %u\n", ib, rlen); 1357 while (rlen != 0) { 1358 invilv = ilv_valid(ndo, ilv, rlen); 1359 if (invilv) { 1360 break; 1361 } 1362 1363 /* 1364 * At this point, ilv_valid() has ensured that the ILV 1365 * length is large enough but not too large (it doesn't 1366 * go past the end of the containing TLV). 1367 */ 1368 print_metailv(ndo, (const u_char *) ilv, 0, indent + 1); 1369 ilv = GO_NXT_ILV(ilv, rlen); 1370 } 1371 1372 return 0; 1373 } 1374 1375 1376 static int 1377 print_reddata(netdissect_options *ndo, 1378 const u_char * pptr, u_int len, 1379 uint16_t op_msk _U_, int indent) 1380 { 1381 u_int dlen; 1382 char *ib = indent_pr(indent, 0); 1383 u_int rlen; 1384 1385 dlen = len - TLV_HDRL; 1386 rlen = dlen; 1387 ND_PRINT("\n%s Redirect Data length %u\n", ib, rlen); 1388 1389 if (ndo->ndo_vflag >= 3) { 1390 ND_PRINT("\t\t["); 1391 hex_print(ndo, "\n\t\t", pptr, rlen); 1392 ND_PRINT("\n\t\t]"); 1393 } 1394 1395 return 0; 1396 } 1397 1398 static int 1399 redirect_print(netdissect_options *ndo, 1400 const u_char * pptr, u_int len, 1401 uint16_t op_msk _U_, int indent) 1402 { 1403 const struct forces_tlv *tlv = (const struct forces_tlv *)pptr; 1404 u_int dlen; 1405 u_int rlen; 1406 u_int invtlv; 1407 1408 /* 1409 * forces_type_print() has ensured that len (the TLV length) 1410 * >= TLV_HDRL. 1411 */ 1412 dlen = len - TLV_HDRL; 1413 if (dlen <= RD_MIN) { 1414 ND_PRINT("\n\t\ttruncated Redirect TLV: %u bytes missing! ", 1415 RD_MIN - dlen); 1416 return -1; 1417 } 1418 1419 rlen = dlen; 1420 indent += 1; 1421 while (rlen != 0) { 1422 uint16_t type, tlvl; 1423 1424 type = GET_BE_U_2(tlv->type); 1425 tlvl = GET_BE_U_2(tlv->length); 1426 invtlv = tlv_valid(tlvl, rlen); 1427 if (invtlv) { 1428 ND_PRINT("Bad Redirect data\n"); 1429 break; 1430 } 1431 1432 /* 1433 * At this point, tlv_valid() has ensured that the TLV 1434 * length is large enough but not too large (it doesn't 1435 * go past the end of the containing TLV). 1436 */ 1437 if (type == F_TLV_METD) { 1438 print_metatlv(ndo, (const u_char *) TLV_DATA(tlv), 1439 tlvl, 0, 1440 indent); 1441 } else if (type == F_TLV_REDD) { 1442 print_reddata(ndo, (const u_char *) TLV_DATA(tlv), 1443 tlvl, 0, 1444 indent); 1445 } else { 1446 ND_PRINT("Unknown REDIRECT TLV 0x%x len %u\n", 1447 type, 1448 tlvl); 1449 } 1450 1451 tlv = GO_NXT_TLV(tlv, rlen); 1452 } 1453 1454 if (rlen) { 1455 ND_PRINT("\n\t\tMessy Redirect TLV header, type (0x%x)\n\t\texcess of %u Bytes ", 1456 GET_BE_U_2(tlv->type), 1457 rlen - GET_BE_U_2(tlv->length)); 1458 return -1; 1459 } 1460 1461 return 0; 1462 } 1463 1464 #define OP_OFF 8 1465 #define OP_MIN 12 1466 1467 static int 1468 lfbselect_print(netdissect_options *ndo, 1469 const u_char * pptr, u_int len, 1470 uint16_t op_msk, int indent) 1471 { 1472 const struct forces_lfbsh *lfbs; 1473 const struct forces_tlv *otlv; 1474 char *ib = indent_pr(indent, 0); 1475 u_int dlen; 1476 u_int rlen; 1477 u_int invtlv; 1478 1479 /* 1480 * forces_type_print() has ensured that len (the TLV length) 1481 * >= TLV_HDRL. 1482 */ 1483 dlen = len - TLV_HDRL; 1484 if (dlen <= OP_MIN) { /* id, instance, oper tlv header .. */ 1485 ND_PRINT("\n\t\ttruncated lfb selector: %u bytes missing! ", 1486 OP_MIN - dlen); 1487 return -1; 1488 } 1489 1490 /* 1491 * At this point, we know that dlen > OP_MIN; OP_OFF < OP_MIN, so 1492 * we also know that it's > OP_OFF. 1493 */ 1494 rlen = dlen - OP_OFF; 1495 1496 lfbs = (const struct forces_lfbsh *)pptr; 1497 ND_TCHECK_SIZE(lfbs); 1498 if (ndo->ndo_vflag >= 3) { 1499 ND_PRINT("\n%s%s(Classid %x) instance %x\n", 1500 ib, 1501 tok2str(ForCES_LFBs, NULL, GET_BE_U_4(lfbs->class)), 1502 GET_BE_U_4(lfbs->class), 1503 GET_BE_U_4(lfbs->instance)); 1504 } 1505 1506 otlv = (const struct forces_tlv *)(lfbs + 1); 1507 1508 indent += 1; 1509 while (rlen != 0) { 1510 uint16_t type, tlvl; 1511 1512 type = GET_BE_U_2(otlv->type); 1513 tlvl = GET_BE_U_2(otlv->length); 1514 invtlv = tlv_valid(tlvl, rlen); 1515 if (invtlv) 1516 break; 1517 1518 /* 1519 * At this point, tlv_valid() has ensured that the TLV 1520 * length is large enough but not too large (it doesn't 1521 * go past the end of the containing TLV). 1522 */ 1523 if (op_valid(type, op_msk)) { 1524 otlv_print(ndo, otlv, 0, indent); 1525 } else { 1526 if (ndo->ndo_vflag < 3) 1527 ND_PRINT("\n"); 1528 ND_PRINT("\t\tINValid oper-TLV type 0x%x length %u for this ForCES message\n", 1529 type, tlvl); 1530 invoptlv_print(ndo, (const u_char *)otlv, rlen, 0, indent); 1531 } 1532 otlv = GO_NXT_TLV(otlv, rlen); 1533 } 1534 1535 if (rlen) { 1536 ND_PRINT("\n\t\tMessy oper TLV header, type (0x%x)\n\t\texcess of %u Bytes ", 1537 GET_BE_U_2(otlv->type), 1538 rlen - GET_BE_U_2(otlv->length)); 1539 return -1; 1540 } 1541 1542 return 0; 1543 1544 trunc: 1545 nd_print_trunc(ndo); 1546 return -1; 1547 } 1548 1549 static int 1550 forces_type_print(netdissect_options *ndo, 1551 const u_char * pptr, const struct forcesh *fhdr _U_, 1552 u_int mlen, const struct tom_h *tops) 1553 { 1554 const struct forces_tlv *tltlv; 1555 u_int rlen; 1556 u_int invtlv; 1557 int rc = 0; 1558 u_int ttlv = 0; 1559 1560 /* 1561 * forces_print() has already checked that mlen >= ForCES_HDRL 1562 * by calling ForCES_HLN_VALID(). 1563 */ 1564 rlen = mlen - ForCES_HDRL; 1565 1566 if (rlen > TLV_HLN) { 1567 if (tops->flags & ZERO_TTLV) { 1568 ND_PRINT("<0x%x>Illegal Top level TLV!\n", tops->flags); 1569 return -1; 1570 } 1571 } else { 1572 if (tops->flags & ZERO_MORE_TTLV) 1573 return 0; 1574 if (tops->flags & ONE_MORE_TTLV) { 1575 ND_PRINT("\tTop level TLV Data missing!\n"); 1576 return -1; 1577 } 1578 } 1579 1580 if (tops->flags & ZERO_TTLV) { 1581 return 0; 1582 } 1583 1584 ttlv = tops->flags >> 4; 1585 tltlv = GET_TOP_TLV(pptr); 1586 1587 /*XXX: 15 top level tlvs will probably be fine 1588 You are nuts if you send more ;-> */ 1589 while (rlen != 0) { 1590 uint16_t type, tlvl; 1591 1592 type = GET_BE_U_2(tltlv->type); 1593 tlvl = GET_BE_U_2(tltlv->length); 1594 invtlv = tlv_valid(tlvl, rlen); 1595 if (invtlv) 1596 break; 1597 1598 /* 1599 * At this point, tlv_valid() has ensured that the TLV 1600 * length is large enough but not too large (it doesn't 1601 * go past the end of the packet). 1602 */ 1603 if (!ttlv_valid(type)) { 1604 ND_PRINT("\n\tInvalid ForCES Top TLV type=0x%x", 1605 type); 1606 return -1; 1607 } 1608 1609 if (ndo->ndo_vflag >= 3) 1610 ND_PRINT("\t%s, length %u (data length %u Bytes)", 1611 tok2str(ForCES_TLV, NULL, type), 1612 tlvl, 1613 tlvl - TLV_HDRL); 1614 1615 rc = tops->print(ndo, (const u_char *) TLV_DATA(tltlv), 1616 tlvl, 1617 tops->op_msk, 9); 1618 if (rc < 0) { 1619 return -1; 1620 } 1621 tltlv = GO_NXT_TLV(tltlv, rlen); 1622 ttlv--; 1623 if (ttlv <= 0) 1624 break; 1625 } 1626 /* 1627 * XXX - if ttlv != 0, does that mean that the packet was too 1628 * short, and didn't have *enough* TLVs in it? 1629 */ 1630 if (rlen) { 1631 ND_PRINT("\tMess TopTLV header: min %u, total %u advertised %u ", 1632 TLV_HDRL, rlen, GET_BE_U_2(tltlv->length)); 1633 return -1; 1634 } 1635 1636 return 0; 1637 } 1638 1639 void 1640 forces_print(netdissect_options *ndo, 1641 const u_char * pptr, u_int len) 1642 { 1643 const struct forcesh *fhdr; 1644 u_int mlen; 1645 uint32_t flg_raw; 1646 uint8_t tom; 1647 const struct tom_h *tops; 1648 int rc = 0; 1649 1650 ndo->ndo_protocol = "forces"; 1651 fhdr = (const struct forcesh *)pptr; 1652 ND_TCHECK_SIZE(fhdr); 1653 tom = GET_U_1(fhdr->fm_tom); 1654 if (!tom_valid(tom)) { 1655 ND_PRINT("Invalid ForCES message type %u\n", tom); 1656 goto error; 1657 } 1658 1659 mlen = ForCES_BLN(fhdr); 1660 1661 tops = get_forces_tom(tom); 1662 if (tops->v == TOM_RSVD) { 1663 ND_PRINT("\n\tUnknown ForCES message type=0x%x", tom); 1664 goto error; 1665 } 1666 1667 ND_PRINT("\n\tForCES %s ", tops->s); 1668 if (!ForCES_HLN_VALID(mlen, len)) { 1669 ND_PRINT("Illegal ForCES pkt len - min %u, total recvd %u, advertised %u ", 1670 ForCES_HDRL, len, ForCES_BLN(fhdr)); 1671 goto error; 1672 } 1673 1674 flg_raw = GET_BE_U_4(pptr + 20); 1675 if (ndo->ndo_vflag >= 1) { 1676 ND_PRINT("\n\tForCES Version %u len %uB flags 0x%08x ", 1677 ForCES_V(fhdr), mlen, flg_raw); 1678 ND_PRINT("\n\tSrcID 0x%x(%s) DstID 0x%x(%s) Correlator 0x%" PRIx64, 1679 ForCES_SID(fhdr), ForCES_node(ForCES_SID(fhdr)), 1680 ForCES_DID(fhdr), ForCES_node(ForCES_DID(fhdr)), 1681 GET_BE_U_8(fhdr->fm_cor)); 1682 1683 } 1684 if (ndo->ndo_vflag >= 2) { 1685 ND_PRINT("\n\tForCES flags:\n\t %s(0x%x), prio=%u, %s(0x%x),\n\t %s(0x%x), %s(0x%x)\n", 1686 tok2str(ForCES_ACKs, "ACKUnknown", ForCES_ACK(fhdr)), 1687 ForCES_ACK(fhdr), 1688 ForCES_PRI(fhdr), 1689 tok2str(ForCES_EMs, "EMUnknown", ForCES_EM(fhdr)), 1690 ForCES_EM(fhdr), 1691 tok2str(ForCES_ATs, "ATUnknown", ForCES_AT(fhdr)), 1692 ForCES_AT(fhdr), 1693 tok2str(ForCES_TPs, "TPUnknown", ForCES_TP(fhdr)), 1694 ForCES_TP(fhdr)); 1695 ND_PRINT("\t Extra flags: rsv(b5-7) 0x%x rsv(b13-31) 0x%x\n", 1696 ForCES_RS1(fhdr), ForCES_RS2(fhdr)); 1697 } 1698 rc = forces_type_print(ndo, pptr, fhdr, mlen, tops); 1699 if (rc < 0) { 1700 error: 1701 hex_print(ndo, "\n\t[", pptr, len); 1702 ND_PRINT("\n\t]"); 1703 return; 1704 } 1705 1706 if (ndo->ndo_vflag >= 4) { 1707 ND_PRINT("\n\t Raw ForCES message\n\t ["); 1708 hex_print(ndo, "\n\t ", pptr, len); 1709 ND_PRINT("\n\t ]"); 1710 } 1711 return; 1712 1713 trunc: 1714 nd_print_trunc(ndo); 1715 } 1716