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