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