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