10f74e101Schristos /* 20f74e101Schristos * Redistribution and use in source and binary forms, with or without 30f74e101Schristos * modification, are permitted provided that: (1) source code 40f74e101Schristos * distributions retain the above copyright notice and this paragraph 50f74e101Schristos * in its entirety, and (2) distributions including binary code include 60f74e101Schristos * the above copyright notice and this paragraph in its entirety in 70f74e101Schristos * the documentation or other materials provided with the distribution. 80f74e101Schristos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 90f74e101Schristos * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 100f74e101Schristos * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 110f74e101Schristos * FOR A PARTICULAR PURPOSE. 120f74e101Schristos * 130f74e101Schristos * Copyright (c) 2009 Mojatatu Networks, Inc 140f74e101Schristos * 150f74e101Schristos */ 160f74e101Schristos 17fdccd7e4Schristos #include <sys/cdefs.h> 18fdccd7e4Schristos #ifndef lint 19*26ba0b50Schristos __RCSID("$NetBSD: print-forces.c,v 1.8 2024/09/02 16:15:31 christos Exp $"); 20fdccd7e4Schristos #endif 21fdccd7e4Schristos 22dc860a36Sspz /* \summary: Forwarding and Control Element Separation (ForCES) Protocol printer */ 23dc860a36Sspz 24dc860a36Sspz /* specification: RFC 5810 */ 25dc860a36Sspz 26c74ad251Schristos #include <config.h> 270f74e101Schristos 28c74ad251Schristos #include "netdissect-stdinc.h" 290f74e101Schristos 30fdccd7e4Schristos #include "netdissect.h" 310f74e101Schristos #include "extract.h" 320f74e101Schristos 33026d7285Schristos 34026d7285Schristos #define ForCES_VERS 1 35026d7285Schristos #define ForCES_HDRL 24 36026d7285Schristos #define ForCES_ALNL 4U 37026d7285Schristos #define TLV_HDRL 4 38026d7285Schristos #define ILV_HDRL 8 39026d7285Schristos 40026d7285Schristos #define TOM_RSVD 0x0 41026d7285Schristos #define TOM_ASSNSETUP 0x1 42026d7285Schristos #define TOM_ASSNTEARD 0x2 43026d7285Schristos #define TOM_CONFIG 0x3 44026d7285Schristos #define TOM_QUERY 0x4 45026d7285Schristos #define TOM_EVENTNOT 0x5 46026d7285Schristos #define TOM_PKTREDIR 0x6 47026d7285Schristos #define TOM_HEARTBT 0x0F 48026d7285Schristos #define TOM_ASSNSETREP 0x11 49026d7285Schristos #define TOM_CONFIGREP 0x13 50026d7285Schristos #define TOM_QUERYREP 0x14 51026d7285Schristos 52026d7285Schristos /* 53026d7285Schristos * tom_h Flags: resv1(8b):maxtlvs(4b):resv2(2b):mintlv(2b) 54026d7285Schristos */ 55026d7285Schristos #define ZERO_TTLV 0x01 56026d7285Schristos #define ZERO_MORE_TTLV 0x02 57026d7285Schristos #define ONE_MORE_TTLV 0x04 58026d7285Schristos #define ZERO_TLV 0x00 59026d7285Schristos #define ONE_TLV 0x10 60026d7285Schristos #define TWO_TLV 0x20 61026d7285Schristos #define MAX_TLV 0xF0 62026d7285Schristos 63026d7285Schristos #define TTLV_T1 (ONE_MORE_TTLV|ONE_TLV) 64026d7285Schristos #define TTLV_T2 (ONE_MORE_TTLV|MAX_TLV) 65026d7285Schristos 66026d7285Schristos struct tom_h { 67b3a00663Schristos uint32_t v; 68b3a00663Schristos uint16_t flags; 69b3a00663Schristos uint16_t op_msk; 70026d7285Schristos const char *s; 71c74ad251Schristos int (*print) (netdissect_options *ndo, const u_char * pptr, u_int len, 72b3a00663Schristos uint16_t op_msk, int indent); 73026d7285Schristos }; 74026d7285Schristos 75026d7285Schristos enum { 76026d7285Schristos TOM_RSV_I, 77026d7285Schristos TOM_ASS_I, 78026d7285Schristos TOM_AST_I, 79026d7285Schristos TOM_CFG_I, 80026d7285Schristos TOM_QRY_I, 81026d7285Schristos TOM_EVN_I, 82026d7285Schristos TOM_RED_I, 83026d7285Schristos TOM_HBT_I, 84026d7285Schristos TOM_ASR_I, 85026d7285Schristos TOM_CNR_I, 86026d7285Schristos TOM_QRR_I, 87026d7285Schristos _TOM_RSV_MAX 88026d7285Schristos }; 89026d7285Schristos #define TOM_MAX_IND (_TOM_RSV_MAX - 1) 90026d7285Schristos 91c74ad251Schristos static int 92c74ad251Schristos tom_valid(uint8_t tom) 93026d7285Schristos { 94026d7285Schristos if (tom > 0) { 95026d7285Schristos if (tom >= 0x7 && tom <= 0xe) 96026d7285Schristos return 0; 97026d7285Schristos if (tom == 0x10) 98026d7285Schristos return 0; 99026d7285Schristos if (tom > 0x14) 100026d7285Schristos return 0; 101026d7285Schristos return 1; 102026d7285Schristos } else 103026d7285Schristos return 0; 104026d7285Schristos } 105026d7285Schristos 106c74ad251Schristos static const char * 107c74ad251Schristos ForCES_node(uint32_t node) 108026d7285Schristos { 109026d7285Schristos if (node <= 0x3FFFFFFF) 110026d7285Schristos return "FE"; 111026d7285Schristos if (node >= 0x40000000 && node <= 0x7FFFFFFF) 112026d7285Schristos return "CE"; 113026d7285Schristos if (node >= 0xC0000000 && node <= 0xFFFFFFEF) 114026d7285Schristos return "AllMulticast"; 115026d7285Schristos if (node == 0xFFFFFFFD) 116026d7285Schristos return "AllCEsBroadcast"; 117026d7285Schristos if (node == 0xFFFFFFFE) 118026d7285Schristos return "AllFEsBroadcast"; 119026d7285Schristos if (node == 0xFFFFFFFF) 120026d7285Schristos return "AllBroadcast"; 121026d7285Schristos 122026d7285Schristos return "ForCESreserved"; 123026d7285Schristos 124026d7285Schristos } 125026d7285Schristos 126b3a00663Schristos static const struct tok ForCES_ACKs[] = { 127b3a00663Schristos {0x0, "NoACK"}, 128b3a00663Schristos {0x1, "SuccessACK"}, 129b3a00663Schristos {0x2, "FailureACK"}, 130b3a00663Schristos {0x3, "AlwaysACK"}, 131b3a00663Schristos {0, NULL} 132b3a00663Schristos }; 133026d7285Schristos 134b3a00663Schristos static const struct tok ForCES_EMs[] = { 135b3a00663Schristos {0x0, "EMReserved"}, 136b3a00663Schristos {0x1, "execute-all-or-none"}, 137b3a00663Schristos {0x2, "execute-until-failure"}, 138b3a00663Schristos {0x3, "continue-execute-on-failure"}, 139b3a00663Schristos {0, NULL} 140b3a00663Schristos }; 141026d7285Schristos 142b3a00663Schristos static const struct tok ForCES_ATs[] = { 143b3a00663Schristos {0x0, "Standalone"}, 144b3a00663Schristos {0x1, "2PCtransaction"}, 145b3a00663Schristos {0, NULL} 146b3a00663Schristos }; 147026d7285Schristos 148b3a00663Schristos static const struct tok ForCES_TPs[] = { 149b3a00663Schristos {0x0, "StartofTransaction"}, 150b3a00663Schristos {0x1, "MiddleofTransaction"}, 151b3a00663Schristos {0x2, "EndofTransaction"}, 152b3a00663Schristos {0x3, "abort"}, 153b3a00663Schristos {0, NULL} 154b3a00663Schristos }; 155026d7285Schristos 156026d7285Schristos /* 157026d7285Schristos * Structure of forces header, naked of TLVs. 158026d7285Schristos */ 159026d7285Schristos struct forcesh { 160dc860a36Sspz nd_uint8_t fm_vrsvd; /* version and reserved */ 161c74ad251Schristos #define ForCES_V(forcesh) (GET_U_1((forcesh)->fm_vrsvd) >> 4) 162dc860a36Sspz nd_uint8_t fm_tom; /* type of message */ 163dc860a36Sspz nd_uint16_t fm_len; /* total length * 4 bytes */ 164c74ad251Schristos #define ForCES_BLN(forcesh) ((uint32_t)(GET_BE_U_2((forcesh)->fm_len) << 2)) 165dc860a36Sspz nd_uint32_t fm_sid; /* Source ID */ 166c74ad251Schristos #define ForCES_SID(forcesh) GET_BE_U_4((forcesh)->fm_sid) 167dc860a36Sspz nd_uint32_t fm_did; /* Destination ID */ 168c74ad251Schristos #define ForCES_DID(forcesh) GET_BE_U_4((forcesh)->fm_did) 169dc860a36Sspz nd_uint8_t fm_cor[8]; /* correlator */ 170dc860a36Sspz nd_uint32_t fm_flags; /* flags */ 171c74ad251Schristos #define ForCES_ACK(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0xC0000000) >> 30) 172c74ad251Schristos #define ForCES_PRI(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x38000000) >> 27) 173c74ad251Schristos #define ForCES_RS1(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x07000000) >> 24) 174c74ad251Schristos #define ForCES_EM(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x00C00000) >> 22) 175c74ad251Schristos #define ForCES_AT(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x00200000) >> 21) 176c74ad251Schristos #define ForCES_TP(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x00180000) >> 19) 177c74ad251Schristos #define ForCES_RS2(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x0007FFFF) >> 0) 178026d7285Schristos }; 179026d7285Schristos 180026d7285Schristos #define ForCES_HLN_VALID(fhl,tlen) ((tlen) >= ForCES_HDRL && \ 181026d7285Schristos (fhl) >= ForCES_HDRL && \ 182026d7285Schristos (fhl) == (tlen)) 183026d7285Schristos 184026d7285Schristos #define F_LFB_RSVD 0x0 185026d7285Schristos #define F_LFB_FEO 0x1 186026d7285Schristos #define F_LFB_FEPO 0x2 187026d7285Schristos static const struct tok ForCES_LFBs[] = { 188026d7285Schristos {F_LFB_RSVD, "Invalid TLV"}, 189026d7285Schristos {F_LFB_FEO, "FEObj LFB"}, 190026d7285Schristos {F_LFB_FEPO, "FEProtoObj LFB"}, 191026d7285Schristos {0, NULL} 192026d7285Schristos }; 193026d7285Schristos 194ba2ff121Schristos /* this is defined in RFC5810 section A.2 */ 195c74ad251Schristos /* https://www.iana.org/assignments/forces/forces.xhtml#oper-tlv-types */ 196026d7285Schristos enum { 197ba2ff121Schristos F_OP_RSV = 0, 198ba2ff121Schristos F_OP_SET = 1, 199ba2ff121Schristos F_OP_SETPROP = 2, 200ba2ff121Schristos F_OP_SETRESP = 3, 201ba2ff121Schristos F_OP_SETPRESP = 4, 202ba2ff121Schristos F_OP_DEL = 5, 203ba2ff121Schristos F_OP_DELRESP = 6, 204ba2ff121Schristos F_OP_GET = 7, 205ba2ff121Schristos F_OP_GETPROP = 8, 206ba2ff121Schristos F_OP_GETRESP = 9, 207ba2ff121Schristos F_OP_GETPRESP = 10, 208ba2ff121Schristos F_OP_REPORT = 11, 209ba2ff121Schristos F_OP_COMMIT = 12, 210ba2ff121Schristos F_OP_RCOMMIT = 13, 211ba2ff121Schristos F_OP_RTRCOMP = 14, 212026d7285Schristos _F_OP_MAX 213026d7285Schristos }; 214026d7285Schristos #define F_OP_MAX (_F_OP_MAX - 1) 215ba2ff121Schristos 216026d7285Schristos enum { 217026d7285Schristos B_OP_SET = 1 << (F_OP_SET - 1), 218026d7285Schristos B_OP_SETPROP = 1 << (F_OP_SETPROP - 1), 219026d7285Schristos B_OP_SETRESP = 1 << (F_OP_SETRESP - 1), 220026d7285Schristos B_OP_SETPRESP = 1 << (F_OP_SETPRESP - 1), 221026d7285Schristos B_OP_DEL = 1 << (F_OP_DEL - 1), 222026d7285Schristos B_OP_DELRESP = 1 << (F_OP_DELRESP - 1), 223026d7285Schristos B_OP_GET = 1 << (F_OP_GET - 1), 224026d7285Schristos B_OP_GETPROP = 1 << (F_OP_GETPROP - 1), 225026d7285Schristos B_OP_GETRESP = 1 << (F_OP_GETRESP - 1), 226026d7285Schristos B_OP_GETPRESP = 1 << (F_OP_GETPRESP - 1), 227026d7285Schristos B_OP_REPORT = 1 << (F_OP_REPORT - 1), 228026d7285Schristos B_OP_COMMIT = 1 << (F_OP_COMMIT - 1), 229026d7285Schristos B_OP_RCOMMIT = 1 << (F_OP_RCOMMIT - 1), 230fdccd7e4Schristos B_OP_RTRCOMP = 1 << (F_OP_RTRCOMP - 1) 231026d7285Schristos }; 232026d7285Schristos 233026d7285Schristos struct optlv_h { 234b3a00663Schristos uint16_t flags; 235b3a00663Schristos uint16_t op_msk; 236026d7285Schristos const char *s; 237c74ad251Schristos int (*print) (netdissect_options *ndo, const u_char * pptr, u_int len, 238b3a00663Schristos uint16_t op_msk, int indent); 239026d7285Schristos }; 240026d7285Schristos 241c74ad251Schristos static int genoptlv_print(netdissect_options *, const u_char * pptr, u_int len, 242b3a00663Schristos uint16_t op_msk, int indent); 243c74ad251Schristos static int recpdoptlv_print(netdissect_options *, const u_char * pptr, u_int len, 244b3a00663Schristos uint16_t op_msk, int indent); 245c74ad251Schristos static int invoptlv_print(netdissect_options *, const u_char * pptr, u_int len, 246b3a00663Schristos uint16_t op_msk, int indent); 247026d7285Schristos 248026d7285Schristos #define OP_MIN_SIZ 8 249026d7285Schristos struct pathdata_h { 250dc860a36Sspz nd_uint16_t pflags; 251dc860a36Sspz nd_uint16_t pIDcnt; 252026d7285Schristos }; 253026d7285Schristos 254026d7285Schristos #define B_FULLD 0x1 255026d7285Schristos #define B_SPARD 0x2 256026d7285Schristos #define B_RESTV 0x4 257026d7285Schristos #define B_KEYIN 0x8 258026d7285Schristos #define B_APPND 0x10 259026d7285Schristos #define B_TRNG 0x20 260026d7285Schristos 261026d7285Schristos static const struct optlv_h OPTLV_msg[F_OP_MAX + 1] = { 262026d7285Schristos /* F_OP_RSV */ {ZERO_TTLV, 0, "Invalid OPTLV", invoptlv_print}, 263026d7285Schristos /* F_OP_SET */ {TTLV_T2, B_FULLD | B_SPARD, " Set", recpdoptlv_print}, 264026d7285Schristos /* F_OP_SETPROP */ 265026d7285Schristos {TTLV_T2, B_FULLD | B_SPARD, " SetProp", recpdoptlv_print}, 266026d7285Schristos /* F_OP_SETRESP */ {TTLV_T2, B_RESTV, " SetResp", recpdoptlv_print}, 267026d7285Schristos /* F_OP_SETPRESP */ {TTLV_T2, B_RESTV, " SetPropResp", recpdoptlv_print}, 268026d7285Schristos /* F_OP_DEL */ {ZERO_TTLV, 0, " Del", recpdoptlv_print}, 269026d7285Schristos /* F_OP_DELRESP */ {TTLV_T2, B_RESTV, " DelResp", recpdoptlv_print}, 270026d7285Schristos /* F_OP_GET */ {ZERO_TTLV, 0, " Get", recpdoptlv_print}, 271026d7285Schristos /* F_OP_GETPROP */ {ZERO_TTLV, 0, " GetProp", recpdoptlv_print}, 272026d7285Schristos /* F_OP_GETRESP */ 273026d7285Schristos {TTLV_T2, B_FULLD | B_SPARD | B_RESTV, " GetResp", recpdoptlv_print}, 274026d7285Schristos /* F_OP_GETPRESP */ 275026d7285Schristos {TTLV_T2, B_FULLD | B_RESTV, " GetPropResp", recpdoptlv_print}, 276026d7285Schristos /* F_OP_REPORT */ 277026d7285Schristos {TTLV_T2, B_FULLD | B_SPARD, " Report", recpdoptlv_print}, 278026d7285Schristos /* F_OP_COMMIT */ {ZERO_TTLV, 0, " Commit", NULL}, 279026d7285Schristos /* F_OP_RCOMMIT */ {TTLV_T1, B_RESTV, " RCommit", genoptlv_print}, 280026d7285Schristos /* F_OP_RTRCOMP */ {ZERO_TTLV, 0, " RTRCOMP", NULL}, 281026d7285Schristos }; 282026d7285Schristos 283c74ad251Schristos static const struct optlv_h * 284c74ad251Schristos get_forces_optlv_h(uint16_t opt) 285026d7285Schristos { 286c74ad251Schristos if (opt > F_OP_MAX || opt == F_OP_RSV) 287026d7285Schristos return &OPTLV_msg[F_OP_RSV]; 288026d7285Schristos 289026d7285Schristos return &OPTLV_msg[opt]; 290026d7285Schristos } 291026d7285Schristos 292026d7285Schristos #define IND_SIZE 256 293026d7285Schristos #define IND_CHR ' ' 294026d7285Schristos #define IND_PREF '\n' 295026d7285Schristos #define IND_SUF 0x0 296dc860a36Sspz static char ind_buf[IND_SIZE]; 297026d7285Schristos 298c74ad251Schristos static char * 299c74ad251Schristos indent_pr(int indent, int nlpref) 300026d7285Schristos { 301026d7285Schristos int i = 0; 302026d7285Schristos char *r = ind_buf; 303026d7285Schristos 304026d7285Schristos if (indent > (IND_SIZE - 1)) 305026d7285Schristos indent = IND_SIZE - 1; 306026d7285Schristos 307026d7285Schristos if (nlpref) { 308026d7285Schristos r[i] = IND_PREF; 309026d7285Schristos i++; 310026d7285Schristos indent--; 311026d7285Schristos } 312026d7285Schristos 313026d7285Schristos while (--indent >= 0) 314026d7285Schristos r[i++] = IND_CHR; 315026d7285Schristos 316026d7285Schristos r[i] = IND_SUF; 317026d7285Schristos return r; 318026d7285Schristos } 319026d7285Schristos 320c74ad251Schristos static int 321c74ad251Schristos op_valid(uint16_t op, uint16_t mask) 322026d7285Schristos { 323026d7285Schristos if (op == 0) 324026d7285Schristos return 0; 325c74ad251Schristos if (op <= F_OP_MAX) 326c74ad251Schristos return (1 << (op - 1)) & mask; /* works only for 0x0001 through 0x0010 */ 327026d7285Schristos /* I guess we should allow vendor operations? */ 328026d7285Schristos if (op >= 0x8000) 329026d7285Schristos return 1; 330026d7285Schristos return 0; 331026d7285Schristos } 332026d7285Schristos 333026d7285Schristos #define F_TLV_RSVD 0x0000 334026d7285Schristos #define F_TLV_REDR 0x0001 335026d7285Schristos #define F_TLV_ASRS 0x0010 336026d7285Schristos #define F_TLV_ASRT 0x0011 337026d7285Schristos #define F_TLV_LFBS 0x1000 338026d7285Schristos #define F_TLV_PDAT 0x0110 339026d7285Schristos #define F_TLV_KEYI 0x0111 340026d7285Schristos #define F_TLV_FULD 0x0112 341026d7285Schristos #define F_TLV_SPAD 0x0113 342026d7285Schristos #define F_TLV_REST 0x0114 343026d7285Schristos #define F_TLV_METD 0x0115 344026d7285Schristos #define F_TLV_REDD 0x0116 345026d7285Schristos #define F_TLV_TRNG 0x0117 346026d7285Schristos 347026d7285Schristos 348026d7285Schristos #define F_TLV_VNST 0x8000 349026d7285Schristos 350026d7285Schristos static const struct tok ForCES_TLV[] = { 351026d7285Schristos {F_TLV_RSVD, "Invalid TLV"}, 352026d7285Schristos {F_TLV_REDR, "REDIRECT TLV"}, 353026d7285Schristos {F_TLV_ASRS, "ASResult TLV"}, 354026d7285Schristos {F_TLV_ASRT, "ASTreason TLV"}, 355026d7285Schristos {F_TLV_LFBS, "LFBselect TLV"}, 356026d7285Schristos {F_TLV_PDAT, "PATH-DATA TLV"}, 357026d7285Schristos {F_TLV_KEYI, "KEYINFO TLV"}, 358026d7285Schristos {F_TLV_FULD, "FULLDATA TLV"}, 359026d7285Schristos {F_TLV_SPAD, "SPARSEDATA TLV"}, 360026d7285Schristos {F_TLV_REST, "RESULT TLV"}, 361026d7285Schristos {F_TLV_METD, "METADATA TLV"}, 362026d7285Schristos {F_TLV_REDD, "REDIRECTDATA TLV"}, 363026d7285Schristos {0, NULL} 364026d7285Schristos }; 365026d7285Schristos 366026d7285Schristos #define TLV_HLN 4 367c74ad251Schristos static int 368c74ad251Schristos ttlv_valid(uint16_t ttlv) 369026d7285Schristos { 370026d7285Schristos if (ttlv > 0) { 371026d7285Schristos if (ttlv == 1 || ttlv == 0x1000) 372026d7285Schristos return 1; 373026d7285Schristos if (ttlv >= 0x10 && ttlv <= 0x11) 374026d7285Schristos return 1; 375026d7285Schristos if (ttlv >= 0x110 && ttlv <= 0x116) 376026d7285Schristos return 1; 377026d7285Schristos if (ttlv >= 0x8000) 378026d7285Schristos return 0; /* XXX: */ 379026d7285Schristos } 380026d7285Schristos 381026d7285Schristos return 0; 382026d7285Schristos } 383026d7285Schristos 384026d7285Schristos struct forces_ilv { 385dc860a36Sspz nd_uint32_t type; 386dc860a36Sspz nd_uint32_t length; 387026d7285Schristos }; 388026d7285Schristos 389026d7285Schristos struct forces_tlv { 390dc860a36Sspz nd_uint16_t type; 391dc860a36Sspz nd_uint16_t length; 392026d7285Schristos }; 393026d7285Schristos 394c74ad251Schristos #define F_ALN_LEN(len) roundup2(len, ForCES_ALNL) 395fdccd7e4Schristos #define GET_TOP_TLV(fhdr) ((const struct forces_tlv *)((fhdr) + sizeof (struct forcesh))) 396026d7285Schristos #define TLV_SET_LEN(len) (F_ALN_LEN(TLV_HDRL) + (len)) 397fdccd7e4Schristos #define TLV_DATA(tlvp) ((const void*)(((const char*)(tlvp)) + TLV_SET_LEN(0))) 398c74ad251Schristos #define GO_NXT_TLV(tlv,rlen) ((rlen) -= F_ALN_LEN(GET_BE_U_2((tlv)->length)), \ 399fdccd7e4Schristos (const struct forces_tlv*)(((const char*)(tlv)) \ 400c74ad251Schristos + F_ALN_LEN(GET_BE_U_2((tlv)->length)))) 401026d7285Schristos #define ILV_SET_LEN(len) (F_ALN_LEN(ILV_HDRL) + (len)) 402fdccd7e4Schristos #define ILV_DATA(ilvp) ((const void*)(((const char*)(ilvp)) + ILV_SET_LEN(0))) 403c74ad251Schristos #define GO_NXT_ILV(ilv,rlen) ((rlen) -= F_ALN_LEN(GET_BE_U_4((ilv)->length)), \ 404fdccd7e4Schristos (const struct forces_ilv *)(((const char*)(ilv)) \ 405c74ad251Schristos + F_ALN_LEN(GET_BE_U_4((ilv)->length)))) 406b3a00663Schristos #define INVALID_RLEN 1 407b3a00663Schristos #define INVALID_STLN 2 408b3a00663Schristos #define INVALID_LTLN 3 409b3a00663Schristos #define INVALID_ALEN 4 410026d7285Schristos 411026d7285Schristos static const struct tok ForCES_TLV_err[] = { 412026d7285Schristos {INVALID_RLEN, "Invalid total length"}, 413026d7285Schristos {INVALID_STLN, "xLV too short"}, 414026d7285Schristos {INVALID_LTLN, "xLV too long"}, 415026d7285Schristos {INVALID_ALEN, "data padding missing"}, 416026d7285Schristos {0, NULL} 417026d7285Schristos }; 418026d7285Schristos 419c74ad251Schristos static u_int 420c74ad251Schristos tlv_valid(u_int tlvl, u_int rlen) 421026d7285Schristos { 422026d7285Schristos if (rlen < TLV_HDRL) 423026d7285Schristos return INVALID_RLEN; 424c74ad251Schristos if (tlvl < TLV_HDRL) 425026d7285Schristos return INVALID_STLN; 426c74ad251Schristos if (tlvl > rlen) 427026d7285Schristos return INVALID_LTLN; 428c74ad251Schristos if (rlen < F_ALN_LEN(tlvl)) 429026d7285Schristos return INVALID_ALEN; 430026d7285Schristos 431026d7285Schristos return 0; 432026d7285Schristos } 433026d7285Schristos 434c74ad251Schristos static int 435c74ad251Schristos ilv_valid(netdissect_options *ndo, const struct forces_ilv *ilv, u_int rlen) 436026d7285Schristos { 437026d7285Schristos if (rlen < ILV_HDRL) 438026d7285Schristos return INVALID_RLEN; 439c74ad251Schristos if (GET_BE_U_4(ilv->length) < ILV_HDRL) 440026d7285Schristos return INVALID_STLN; 441c74ad251Schristos if (GET_BE_U_4(ilv->length) > rlen) 442026d7285Schristos return INVALID_LTLN; 443c74ad251Schristos if (rlen < F_ALN_LEN(GET_BE_U_4(ilv->length))) 444026d7285Schristos return INVALID_ALEN; 445026d7285Schristos 446026d7285Schristos return 0; 447026d7285Schristos } 448026d7285Schristos 449c74ad251Schristos static int lfbselect_print(netdissect_options *, const u_char * pptr, u_int len, 450b3a00663Schristos uint16_t op_msk, int indent); 451c74ad251Schristos static int redirect_print(netdissect_options *, const u_char * pptr, u_int len, 452b3a00663Schristos uint16_t op_msk, int indent); 453c74ad251Schristos static int asrtlv_print(netdissect_options *, const u_char * pptr, u_int len, 454b3a00663Schristos uint16_t op_msk, int indent); 455c74ad251Schristos static int asttlv_print(netdissect_options *, const u_char * pptr, u_int len, 456b3a00663Schristos uint16_t op_msk, int indent); 457026d7285Schristos 458026d7285Schristos struct forces_lfbsh { 459dc860a36Sspz nd_uint32_t class; 460dc860a36Sspz nd_uint32_t instance; 461026d7285Schristos }; 462026d7285Schristos 463026d7285Schristos #define ASSNS_OPS (B_OP_REPORT) 464026d7285Schristos #define CFG_OPS (B_OP_SET|B_OP_SETPROP|B_OP_DEL|B_OP_COMMIT|B_OP_RTRCOMP) 465026d7285Schristos #define CFG_ROPS (B_OP_SETRESP|B_OP_SETPRESP|B_OP_DELRESP|B_OP_RCOMMIT) 466026d7285Schristos #define CFG_QY (B_OP_GET|B_OP_GETPROP) 467026d7285Schristos #define CFG_QYR (B_OP_GETRESP|B_OP_GETPRESP) 468026d7285Schristos #define CFG_EVN (B_OP_REPORT) 469026d7285Schristos 470026d7285Schristos static const struct tom_h ForCES_msg[TOM_MAX_IND + 1] = { 471026d7285Schristos /* TOM_RSV_I */ {TOM_RSVD, ZERO_TTLV, 0, "Invalid message", NULL}, 472026d7285Schristos /* TOM_ASS_I */ {TOM_ASSNSETUP, ZERO_MORE_TTLV | TWO_TLV, ASSNS_OPS, 473026d7285Schristos "Association Setup", lfbselect_print}, 474026d7285Schristos /* TOM_AST_I */ 475026d7285Schristos {TOM_ASSNTEARD, TTLV_T1, 0, "Association TearDown", asttlv_print}, 476026d7285Schristos /* TOM_CFG_I */ {TOM_CONFIG, TTLV_T2, CFG_OPS, "Config", lfbselect_print}, 477026d7285Schristos /* TOM_QRY_I */ {TOM_QUERY, TTLV_T2, CFG_QY, "Query", lfbselect_print}, 478026d7285Schristos /* TOM_EVN_I */ {TOM_EVENTNOT, TTLV_T1, CFG_EVN, "Event Notification", 479026d7285Schristos lfbselect_print}, 480026d7285Schristos /* TOM_RED_I */ 481026d7285Schristos {TOM_PKTREDIR, TTLV_T2, 0, "Packet Redirect", redirect_print}, 482026d7285Schristos /* TOM_HBT_I */ {TOM_HEARTBT, ZERO_TTLV, 0, "HeartBeat", NULL}, 483026d7285Schristos /* TOM_ASR_I */ 484026d7285Schristos {TOM_ASSNSETREP, TTLV_T1, 0, "Association Response", asrtlv_print}, 485026d7285Schristos /* TOM_CNR_I */ {TOM_CONFIGREP, TTLV_T2, CFG_ROPS, "Config Response", 486026d7285Schristos lfbselect_print}, 487026d7285Schristos /* TOM_QRR_I */ 488026d7285Schristos {TOM_QUERYREP, TTLV_T2, CFG_QYR, "Query Response", lfbselect_print}, 489026d7285Schristos }; 490026d7285Schristos 491c74ad251Schristos static const struct tom_h * 492c74ad251Schristos get_forces_tom(uint8_t tom) 493026d7285Schristos { 494026d7285Schristos int i; 495026d7285Schristos for (i = TOM_RSV_I; i <= TOM_MAX_IND; i++) { 496026d7285Schristos const struct tom_h *th = &ForCES_msg[i]; 497026d7285Schristos if (th->v == tom) 498026d7285Schristos return th; 499026d7285Schristos } 500026d7285Schristos return &ForCES_msg[TOM_RSV_I]; 501026d7285Schristos } 502026d7285Schristos 503026d7285Schristos struct pdata_ops { 504b3a00663Schristos uint32_t v; 505b3a00663Schristos uint16_t flags; 506b3a00663Schristos uint16_t op_msk; 507026d7285Schristos const char *s; 508c74ad251Schristos int (*print) (netdissect_options *, const u_char * pptr, u_int len, 509b3a00663Schristos uint16_t op_msk, int indent); 510026d7285Schristos }; 511026d7285Schristos 512026d7285Schristos enum { 513026d7285Schristos PD_RSV_I, 514026d7285Schristos PD_SEL_I, 515026d7285Schristos PD_FDT_I, 516026d7285Schristos PD_SDT_I, 517026d7285Schristos PD_RES_I, 518026d7285Schristos PD_PDT_I, 519026d7285Schristos _PD_RSV_MAX 520026d7285Schristos }; 521026d7285Schristos #define PD_MAX_IND (_TOM_RSV_MAX - 1) 522026d7285Schristos 523c74ad251Schristos static int 524c74ad251Schristos pd_valid(uint16_t pd) 525026d7285Schristos { 526026d7285Schristos if (pd >= F_TLV_PDAT && pd <= F_TLV_REST) 527026d7285Schristos return 1; 528026d7285Schristos return 0; 529026d7285Schristos } 530026d7285Schristos 531c74ad251Schristos static void 532b3a00663Schristos chk_op_type(netdissect_options *ndo, 533b3a00663Schristos uint16_t type, uint16_t msk, uint16_t omsk) 534026d7285Schristos { 535026d7285Schristos if (type != F_TLV_PDAT) { 536026d7285Schristos if (msk & B_KEYIN) { 537026d7285Schristos if (type != F_TLV_KEYI) { 538c74ad251Schristos ND_PRINT("Based on flags expected KEYINFO TLV!\n"); 539026d7285Schristos } 540026d7285Schristos } else { 541026d7285Schristos if (!(msk & omsk)) { 542c74ad251Schristos ND_PRINT("Illegal DATA encoding for type 0x%x programmed %x got %x\n", 543c74ad251Schristos type, omsk, msk); 544026d7285Schristos } 545026d7285Schristos } 546026d7285Schristos } 547026d7285Schristos 548026d7285Schristos } 549026d7285Schristos 550026d7285Schristos #define F_SELKEY 1 551026d7285Schristos #define F_SELTABRANGE 2 552026d7285Schristos #define F_TABAPPEND 4 553026d7285Schristos 554026d7285Schristos struct res_val { 555dc860a36Sspz nd_uint8_t result; 556dc860a36Sspz nd_uint8_t resv1; 557dc860a36Sspz nd_uint16_t resv2; 558026d7285Schristos }; 559026d7285Schristos 560c74ad251Schristos static int prestlv_print(netdissect_options *, const u_char * pptr, u_int len, 561b3a00663Schristos uint16_t op_msk, int indent); 562c74ad251Schristos static int pkeyitlv_print(netdissect_options *, const u_char * pptr, u_int len, 563b3a00663Schristos uint16_t op_msk, int indent); 564c74ad251Schristos static int fdatatlv_print(netdissect_options *, const u_char * pptr, u_int len, 565b3a00663Schristos uint16_t op_msk, int indent); 566c74ad251Schristos static int sdatatlv_print(netdissect_options *, const u_char * pptr, u_int len, 567b3a00663Schristos uint16_t op_msk, int indent); 568026d7285Schristos 569026d7285Schristos static const struct pdata_ops ForCES_pdata[PD_MAX_IND + 1] = { 570026d7285Schristos /* PD_RSV_I */ {0, 0, 0, "Invalid message", NULL}, 571026d7285Schristos /* PD_SEL_I */ {F_TLV_KEYI, 0, 0, "KEYINFO TLV", pkeyitlv_print}, 572026d7285Schristos /* PD_FDT_I */ {F_TLV_FULD, 0, B_FULLD, "FULLDATA TLV", fdatatlv_print}, 573026d7285Schristos /* PD_SDT_I */ {F_TLV_SPAD, 0, B_SPARD, "SPARSEDATA TLV", sdatatlv_print}, 574026d7285Schristos /* PD_RES_I */ {F_TLV_REST, 0, B_RESTV, "RESULT TLV", prestlv_print}, 575026d7285Schristos /* PD_PDT_I */ 576026d7285Schristos {F_TLV_PDAT, 0, 0, "Inner PATH-DATA TLV", recpdoptlv_print}, 577026d7285Schristos }; 578026d7285Schristos 579c74ad251Schristos static const struct pdata_ops * 580c74ad251Schristos get_forces_pd(uint16_t pd) 581026d7285Schristos { 582026d7285Schristos int i; 583026d7285Schristos for (i = PD_RSV_I + 1; i <= PD_MAX_IND; i++) { 584026d7285Schristos const struct pdata_ops *pdo = &ForCES_pdata[i]; 585026d7285Schristos if (pdo->v == pd) 586026d7285Schristos return pdo; 587026d7285Schristos } 588026d7285Schristos return &ForCES_pdata[TOM_RSV_I]; 589026d7285Schristos } 590026d7285Schristos 591026d7285Schristos enum { 592026d7285Schristos E_SUCCESS, 593026d7285Schristos E_INVALID_HEADER, 594026d7285Schristos E_LENGTH_MISMATCH, 595026d7285Schristos E_VERSION_MISMATCH, 596026d7285Schristos E_INVALID_DESTINATION_PID, 597026d7285Schristos E_LFB_UNKNOWN, 598026d7285Schristos E_LFB_NOT_FOUND, 599026d7285Schristos E_LFB_INSTANCE_ID_NOT_FOUND, 600026d7285Schristos E_INVALID_PATH, 601026d7285Schristos E_COMPONENT_DOES_NOT_EXIST, 602026d7285Schristos E_EXISTS, 603026d7285Schristos E_NOT_FOUND, 604026d7285Schristos E_READ_ONLY, 605026d7285Schristos E_INVALID_ARRAY_CREATION, 606026d7285Schristos E_VALUE_OUT_OF_RANGE, 607026d7285Schristos E_CONTENTS_TOO_LONG, 608026d7285Schristos E_INVALID_PARAMETERS, 609026d7285Schristos E_INVALID_MESSAGE_TYPE, 610026d7285Schristos E_INVALID_FLAGS, 611026d7285Schristos E_INVALID_TLV, 612026d7285Schristos E_EVENT_ERROR, 613026d7285Schristos E_NOT_SUPPORTED, 614026d7285Schristos E_MEMORY_ERROR, 615026d7285Schristos E_INTERNAL_ERROR, 616026d7285Schristos /* 0x18-0xFE are reserved .. */ 617026d7285Schristos E_UNSPECIFIED_ERROR = 0XFF 618026d7285Schristos }; 619026d7285Schristos 620026d7285Schristos static const struct tok ForCES_errs[] = { 621026d7285Schristos {E_SUCCESS, "SUCCESS"}, 622026d7285Schristos {E_INVALID_HEADER, "INVALID HEADER"}, 623026d7285Schristos {E_LENGTH_MISMATCH, "LENGTH MISMATCH"}, 624026d7285Schristos {E_VERSION_MISMATCH, "VERSION MISMATCH"}, 625026d7285Schristos {E_INVALID_DESTINATION_PID, "INVALID DESTINATION PID"}, 626026d7285Schristos {E_LFB_UNKNOWN, "LFB UNKNOWN"}, 627026d7285Schristos {E_LFB_NOT_FOUND, "LFB NOT FOUND"}, 628026d7285Schristos {E_LFB_INSTANCE_ID_NOT_FOUND, "LFB INSTANCE ID NOT FOUND"}, 629026d7285Schristos {E_INVALID_PATH, "INVALID PATH"}, 630026d7285Schristos {E_COMPONENT_DOES_NOT_EXIST, "COMPONENT DOES NOT EXIST"}, 631026d7285Schristos {E_EXISTS, "EXISTS ALREADY"}, 632026d7285Schristos {E_NOT_FOUND, "NOT FOUND"}, 633026d7285Schristos {E_READ_ONLY, "READ ONLY"}, 634026d7285Schristos {E_INVALID_ARRAY_CREATION, "INVALID ARRAY CREATION"}, 635026d7285Schristos {E_VALUE_OUT_OF_RANGE, "VALUE OUT OF RANGE"}, 636026d7285Schristos {E_CONTENTS_TOO_LONG, "CONTENTS TOO LONG"}, 637026d7285Schristos {E_INVALID_PARAMETERS, "INVALID PARAMETERS"}, 638026d7285Schristos {E_INVALID_MESSAGE_TYPE, "INVALID MESSAGE TYPE"}, 639026d7285Schristos {E_INVALID_FLAGS, "INVALID FLAGS"}, 640026d7285Schristos {E_INVALID_TLV, "INVALID TLV"}, 641026d7285Schristos {E_EVENT_ERROR, "EVENT ERROR"}, 642026d7285Schristos {E_NOT_SUPPORTED, "NOT SUPPORTED"}, 643026d7285Schristos {E_MEMORY_ERROR, "MEMORY ERROR"}, 644026d7285Schristos {E_INTERNAL_ERROR, "INTERNAL ERROR"}, 645026d7285Schristos {E_UNSPECIFIED_ERROR, "UNSPECIFIED ERROR"}, 646026d7285Schristos {0, NULL} 647026d7285Schristos }; 6480f74e101Schristos 6490f74e101Schristos #define RESLEN 4 6500f74e101Schristos 651026d7285Schristos static int 652b3a00663Schristos prestlv_print(netdissect_options *ndo, 653c74ad251Schristos const u_char * pptr, u_int len, 654b3a00663Schristos uint16_t op_msk _U_, int indent) 6550f74e101Schristos { 656fdccd7e4Schristos const struct forces_tlv *tlv = (const struct forces_tlv *)pptr; 657c74ad251Schristos const u_char *tdp = (const u_char *) TLV_DATA(tlv); 658fdccd7e4Schristos const struct res_val *r = (const struct res_val *)tdp; 6590f74e101Schristos u_int dlen; 660c74ad251Schristos uint8_t result; 6610f74e101Schristos 6620f74e101Schristos /* 6630f74e101Schristos * pdatacnt_print() has ensured that len (the TLV length) 6640f74e101Schristos * >= TLV_HDRL. 6650f74e101Schristos */ 6660f74e101Schristos dlen = len - TLV_HDRL; 6670f74e101Schristos if (dlen != RESLEN) { 668c74ad251Schristos ND_PRINT("illegal RESULT-TLV: %u bytes!\n", dlen); 6690f74e101Schristos return -1; 6700f74e101Schristos } 6710f74e101Schristos 672c74ad251Schristos ND_TCHECK_SIZE(r); 673c74ad251Schristos result = GET_U_1(r->result); 674c74ad251Schristos if (result >= 0x18 && result <= 0xFE) { 675c74ad251Schristos ND_PRINT("illegal reserved result code: 0x%x!\n", result); 6760f74e101Schristos return -1; 6770f74e101Schristos } 6780f74e101Schristos 679b3a00663Schristos if (ndo->ndo_vflag >= 3) { 6800f74e101Schristos char *ib = indent_pr(indent, 0); 681c74ad251Schristos ND_PRINT("%s Result: %s (code 0x%x)\n", ib, 682c74ad251Schristos tok2str(ForCES_errs, NULL, result), result); 6830f74e101Schristos } 6840f74e101Schristos return 0; 6850f74e101Schristos 6860f74e101Schristos trunc: 687c74ad251Schristos nd_print_trunc(ndo); 6880f74e101Schristos return -1; 6890f74e101Schristos } 6900f74e101Schristos 691026d7285Schristos static int 692b3a00663Schristos fdatatlv_print(netdissect_options *ndo, 693c74ad251Schristos const u_char * pptr, u_int len, 694b3a00663Schristos uint16_t op_msk _U_, int indent) 6950f74e101Schristos { 696fdccd7e4Schristos const struct forces_tlv *tlv = (const struct forces_tlv *)pptr; 6970f74e101Schristos u_int rlen; 698c74ad251Schristos const u_char *tdp = (const u_char *) TLV_DATA(tlv); 699b3a00663Schristos uint16_t type; 7000f74e101Schristos 7010f74e101Schristos /* 7020f74e101Schristos * pdatacnt_print() or pkeyitlv_print() has ensured that len 7030f74e101Schristos * (the TLV length) >= TLV_HDRL. 7040f74e101Schristos */ 7050f74e101Schristos rlen = len - TLV_HDRL; 706c74ad251Schristos ND_TCHECK_SIZE(tlv); 707c74ad251Schristos type = GET_BE_U_2(tlv->type); 7080f74e101Schristos if (type != F_TLV_FULD) { 709c74ad251Schristos ND_PRINT("Error: expecting FULLDATA!\n"); 7100f74e101Schristos return -1; 7110f74e101Schristos } 7120f74e101Schristos 713b3a00663Schristos if (ndo->ndo_vflag >= 3) { 7140f74e101Schristos char *ib = indent_pr(indent + 2, 1); 715c74ad251Schristos ND_PRINT("%s[", ib + 1); 716c74ad251Schristos hex_print(ndo, ib, tdp, rlen); 717c74ad251Schristos ND_PRINT("\n%s]", ib + 1); 7180f74e101Schristos } 7190f74e101Schristos return 0; 7200f74e101Schristos 7210f74e101Schristos trunc: 722c74ad251Schristos nd_print_trunc(ndo); 7230f74e101Schristos return -1; 7240f74e101Schristos } 7250f74e101Schristos 726026d7285Schristos static int 727b3a00663Schristos sdatailv_print(netdissect_options *ndo, 728c74ad251Schristos const u_char * pptr, u_int len, 729b3a00663Schristos uint16_t op_msk _U_, int indent) 7300f74e101Schristos { 7310f74e101Schristos u_int rlen; 732fdccd7e4Schristos const struct forces_ilv *ilv = (const struct forces_ilv *)pptr; 7330f74e101Schristos int invilv; 7340f74e101Schristos 7350f74e101Schristos if (len < ILV_HDRL) { 736c74ad251Schristos ND_PRINT("Error: BAD SPARSEDATA-TLV!\n"); 7370f74e101Schristos return -1; 7380f74e101Schristos } 7399546e36dSchristos rlen = len; 7400f74e101Schristos indent += 1; 7410f74e101Schristos while (rlen != 0) { 742026d7285Schristos #if 0 743c74ad251Schristos ND_PRINT("Jamal - outstanding length <%u>\n", rlen); 744026d7285Schristos #endif 7459546e36dSchristos char *ib = indent_pr(indent, 1); 746c74ad251Schristos const u_char *tdp = (const u_char *) ILV_DATA(ilv); 747c74ad251Schristos invilv = ilv_valid(ndo, ilv, rlen); 7480f74e101Schristos if (invilv) { 749c74ad251Schristos ND_PRINT("Error: %s, rlen %u\n", 750c74ad251Schristos tok2str(ForCES_TLV_err, NULL, invilv), rlen); 7519546e36dSchristos return -1; 7529546e36dSchristos } 753b3a00663Schristos if (ndo->ndo_vflag >= 3) { 754c74ad251Schristos u_int ilvl = GET_BE_U_4(ilv->length); 755c74ad251Schristos ND_PRINT("\n%s ILV: type %x length %u\n", ib + 1, 756c74ad251Schristos GET_BE_U_4(ilv->type), ilvl); 757c74ad251Schristos hex_print(ndo, "\t\t[", tdp, ilvl-ILV_HDRL); 7580f74e101Schristos } 7590f74e101Schristos 7600f74e101Schristos ilv = GO_NXT_ILV(ilv, rlen); 7610f74e101Schristos } 7620f74e101Schristos 7630f74e101Schristos return 0; 7640f74e101Schristos } 7650f74e101Schristos 766026d7285Schristos static int 767b3a00663Schristos sdatatlv_print(netdissect_options *ndo, 768c74ad251Schristos const u_char * pptr, u_int len, 769b3a00663Schristos uint16_t op_msk, int indent) 7700f74e101Schristos { 771fdccd7e4Schristos const struct forces_tlv *tlv = (const struct forces_tlv *)pptr; 7720f74e101Schristos u_int rlen; 773c74ad251Schristos const u_char *tdp = (const u_char *) TLV_DATA(tlv); 774b3a00663Schristos uint16_t type; 7750f74e101Schristos 7760f74e101Schristos /* 7770f74e101Schristos * pdatacnt_print() has ensured that len (the TLV length) 7780f74e101Schristos * >= TLV_HDRL. 7790f74e101Schristos */ 7800f74e101Schristos rlen = len - TLV_HDRL; 781c74ad251Schristos ND_TCHECK_SIZE(tlv); 782c74ad251Schristos type = GET_BE_U_2(tlv->type); 7830f74e101Schristos if (type != F_TLV_SPAD) { 784c74ad251Schristos ND_PRINT("Error: expecting SPARSEDATA!\n"); 7850f74e101Schristos return -1; 7860f74e101Schristos } 7870f74e101Schristos 788b3a00663Schristos return sdatailv_print(ndo, tdp, rlen, op_msk, indent); 7890f74e101Schristos 7900f74e101Schristos trunc: 791c74ad251Schristos nd_print_trunc(ndo); 7920f74e101Schristos return -1; 7930f74e101Schristos } 7940f74e101Schristos 795026d7285Schristos static int 796b3a00663Schristos pkeyitlv_print(netdissect_options *ndo, 797c74ad251Schristos const u_char * pptr, u_int len, 798b3a00663Schristos uint16_t op_msk, int indent) 7990f74e101Schristos { 800fdccd7e4Schristos const struct forces_tlv *tlv = (const struct forces_tlv *)pptr; 801c74ad251Schristos const u_char *tdp = (const u_char *) TLV_DATA(tlv); 802c74ad251Schristos const u_char *dp = tdp + 4; 803fdccd7e4Schristos const struct forces_tlv *kdtlv = (const struct forces_tlv *)dp; 804b3a00663Schristos uint32_t id; 8050f74e101Schristos char *ib = indent_pr(indent, 0); 806b3a00663Schristos uint16_t type, tll; 807b3a00663Schristos u_int invtlv; 8080f74e101Schristos 809c74ad251Schristos id = GET_BE_U_4(tdp); 810c74ad251Schristos ND_PRINT("%sKeyinfo: Key 0x%x\n", ib, id); 811c74ad251Schristos type = GET_BE_U_2(kdtlv->type); 812c74ad251Schristos tll = GET_BE_U_2(kdtlv->length); 813c74ad251Schristos invtlv = tlv_valid(tll, len); 8140f74e101Schristos 8150f74e101Schristos if (invtlv) { 816c74ad251Schristos ND_PRINT("%s TLV type 0x%x len %u\n", 8170f74e101Schristos tok2str(ForCES_TLV_err, NULL, invtlv), type, 818c74ad251Schristos tll); 8190f74e101Schristos return -1; 8200f74e101Schristos } 8210f74e101Schristos /* 8220f74e101Schristos * At this point, tlv_valid() has ensured that the TLV 8230f74e101Schristos * length is large enough but not too large (it doesn't 8240f74e101Schristos * go past the end of the containing TLV). 8250f74e101Schristos */ 826c74ad251Schristos tll = GET_BE_U_2(kdtlv->length); 827fdccd7e4Schristos dp = (const u_char *) TLV_DATA(kdtlv); 828b3a00663Schristos return fdatatlv_print(ndo, dp, tll, op_msk, indent); 8290f74e101Schristos } 8300f74e101Schristos 831026d7285Schristos #define PTH_DESC_SIZE 12 832026d7285Schristos 833026d7285Schristos static int 834b3a00663Schristos pdatacnt_print(netdissect_options *ndo, 835c74ad251Schristos const u_char * pptr, u_int len, 836b3a00663Schristos uint16_t IDcnt, uint16_t op_msk, int indent) 8370f74e101Schristos { 8380f74e101Schristos u_int i; 839b3a00663Schristos uint32_t id; 8400f74e101Schristos char *ib = indent_pr(indent, 0); 8410f74e101Schristos 842b3a00663Schristos if ((op_msk & B_APPND) && ndo->ndo_vflag >= 3) { 843c74ad251Schristos ND_PRINT("%sTABLE APPEND\n", ib); 844026d7285Schristos } 8450f74e101Schristos for (i = 0; i < IDcnt; i++) { 846c74ad251Schristos ND_TCHECK_4(pptr); 8470f74e101Schristos if (len < 4) 8480f74e101Schristos goto trunc; 849c74ad251Schristos id = GET_BE_U_4(pptr); 850b3a00663Schristos if (ndo->ndo_vflag >= 3) 851c74ad251Schristos ND_PRINT("%sID#%02u: %u\n", ib, i + 1, id); 8520f74e101Schristos len -= 4; 8530f74e101Schristos pptr += 4; 8540f74e101Schristos } 855026d7285Schristos 856026d7285Schristos if ((op_msk & B_TRNG) || (op_msk & B_KEYIN)) { 857026d7285Schristos if (op_msk & B_TRNG) { 858b3a00663Schristos uint32_t starti, endi; 859026d7285Schristos 860026d7285Schristos if (len < PTH_DESC_SIZE) { 861c74ad251Schristos ND_PRINT("pathlength %u with key/range too short %u\n", 862c74ad251Schristos len, PTH_DESC_SIZE); 863026d7285Schristos return -1; 864026d7285Schristos } 865026d7285Schristos 866026d7285Schristos pptr += sizeof(struct forces_tlv); 867026d7285Schristos len -= sizeof(struct forces_tlv); 868026d7285Schristos 869c74ad251Schristos starti = GET_BE_U_4(pptr); 870026d7285Schristos pptr += 4; 871026d7285Schristos len -= 4; 872026d7285Schristos 873c74ad251Schristos endi = GET_BE_U_4(pptr); 874026d7285Schristos pptr += 4; 875026d7285Schristos len -= 4; 876026d7285Schristos 877b3a00663Schristos if (ndo->ndo_vflag >= 3) 878c74ad251Schristos ND_PRINT("%sTable range: [%u,%u]\n", ib, starti, endi); 879026d7285Schristos } 880026d7285Schristos 881026d7285Schristos if (op_msk & B_KEYIN) { 882fdccd7e4Schristos const struct forces_tlv *keytlv; 883b3a00663Schristos uint16_t tll; 884026d7285Schristos 885026d7285Schristos if (len < PTH_DESC_SIZE) { 886c74ad251Schristos ND_PRINT("pathlength %u with key/range too short %u\n", 887c74ad251Schristos len, PTH_DESC_SIZE); 888026d7285Schristos return -1; 889026d7285Schristos } 890026d7285Schristos 891026d7285Schristos /* skip keyid */ 892026d7285Schristos pptr += 4; 893026d7285Schristos len -= 4; 894fdccd7e4Schristos keytlv = (const struct forces_tlv *)pptr; 895026d7285Schristos /* skip header */ 896026d7285Schristos pptr += sizeof(struct forces_tlv); 897026d7285Schristos len -= sizeof(struct forces_tlv); 898026d7285Schristos /* skip key content */ 899c74ad251Schristos tll = GET_BE_U_2(keytlv->length); 900026d7285Schristos if (tll < TLV_HDRL) { 901c74ad251Schristos ND_PRINT("key content length %u < %u\n", 902c74ad251Schristos tll, TLV_HDRL); 903026d7285Schristos return -1; 904026d7285Schristos } 905026d7285Schristos tll -= TLV_HDRL; 906026d7285Schristos if (len < tll) { 907c74ad251Schristos ND_PRINT("key content too short\n"); 908026d7285Schristos return -1; 909026d7285Schristos } 910026d7285Schristos pptr += tll; 911026d7285Schristos len -= tll; 912026d7285Schristos } 913026d7285Schristos 914026d7285Schristos } 915026d7285Schristos 9160f74e101Schristos if (len) { 917fdccd7e4Schristos const struct forces_tlv *pdtlv = (const struct forces_tlv *)pptr; 918b3a00663Schristos uint16_t type; 919c74ad251Schristos uint16_t tlvl, tll; 920c74ad251Schristos u_int pad = 0; 9210f74e101Schristos u_int aln; 922b3a00663Schristos u_int invtlv; 9230f74e101Schristos 924c74ad251Schristos type = GET_BE_U_2(pdtlv->type); 925c74ad251Schristos tlvl = GET_BE_U_2(pdtlv->length); 926c74ad251Schristos invtlv = tlv_valid(tlvl, len); 9270f74e101Schristos if (invtlv) { 928c74ad251Schristos ND_PRINT("%s Outstanding bytes %u for TLV type 0x%x TLV len %u\n", 9290f74e101Schristos tok2str(ForCES_TLV_err, NULL, invtlv), len, type, 930c74ad251Schristos tlvl); 9310f74e101Schristos goto pd_err; 9320f74e101Schristos } 9330f74e101Schristos /* 9340f74e101Schristos * At this point, tlv_valid() has ensured that the TLV 9350f74e101Schristos * length is large enough but not too large (it doesn't 9360f74e101Schristos * go past the end of the containing TLV). 9370f74e101Schristos */ 938c74ad251Schristos tll = tlvl - TLV_HDRL; 939c74ad251Schristos aln = F_ALN_LEN(tlvl); 940c74ad251Schristos if (aln > tlvl) { 9410f74e101Schristos if (aln > len) { 942c74ad251Schristos ND_PRINT("Invalid padded pathdata TLV type 0x%x len %u missing %u pad bytes\n", 943c74ad251Schristos type, tlvl, aln - len); 9440f74e101Schristos } else { 945c74ad251Schristos pad = aln - tlvl; 9460f74e101Schristos } 9470f74e101Schristos } 9480f74e101Schristos if (pd_valid(type)) { 9490f74e101Schristos const struct pdata_ops *ops = get_forces_pd(type); 9500f74e101Schristos 951b3a00663Schristos if (ndo->ndo_vflag >= 3 && ops->v != F_TLV_PDAT) { 9520f74e101Schristos if (pad) 953c74ad251Schristos ND_PRINT("%s %s (Length %u DataLen %u pad %u Bytes)\n", 954c74ad251Schristos ib, ops->s, tlvl, tll, pad); 9550f74e101Schristos else 956c74ad251Schristos ND_PRINT("%s %s (Length %u DataLen %u Bytes)\n", 957c74ad251Schristos ib, ops->s, tlvl, tll); 9580f74e101Schristos } 9590f74e101Schristos 960b3a00663Schristos chk_op_type(ndo, type, op_msk, ops->op_msk); 9610f74e101Schristos 962b3a00663Schristos if (ops->print(ndo, (const u_char *)pdtlv, 9630f74e101Schristos tll + pad + TLV_HDRL, op_msk, 9649546e36dSchristos indent + 2) == -1) 9659546e36dSchristos return -1; 9669546e36dSchristos len -= (TLV_HDRL + pad + tll); 9670f74e101Schristos } else { 968c74ad251Schristos ND_PRINT("Invalid path data content type 0x%x len %u\n", 969c74ad251Schristos type, tlvl); 9700f74e101Schristos pd_err: 971c74ad251Schristos if (tlvl) { 972c74ad251Schristos hex_print(ndo, "Bad Data val\n\t [", 973c74ad251Schristos pptr, len); 974c74ad251Schristos ND_PRINT("]\n"); 9750f74e101Schristos 9760f74e101Schristos return -1; 9770f74e101Schristos } 9780f74e101Schristos } 9790f74e101Schristos } 9809546e36dSchristos return len; 9810f74e101Schristos 9820f74e101Schristos trunc: 983c74ad251Schristos nd_print_trunc(ndo); 9840f74e101Schristos return -1; 9850f74e101Schristos } 9860f74e101Schristos 987026d7285Schristos static int 988b3a00663Schristos pdata_print(netdissect_options *ndo, 989c74ad251Schristos const u_char * pptr, u_int len, 990b3a00663Schristos uint16_t op_msk, int indent) 9910f74e101Schristos { 992fdccd7e4Schristos const struct pathdata_h *pdh = (const struct pathdata_h *)pptr; 9930f74e101Schristos char *ib = indent_pr(indent, 0); 9940f74e101Schristos u_int minsize = 0; 9959546e36dSchristos int more_pd = 0; 996b3a00663Schristos uint16_t idcnt = 0; 9970f74e101Schristos 998c74ad251Schristos ND_TCHECK_SIZE(pdh); 9990f74e101Schristos if (len < sizeof(struct pathdata_h)) 10000f74e101Schristos goto trunc; 1001b3a00663Schristos if (ndo->ndo_vflag >= 3) { 1002c74ad251Schristos ND_PRINT("\n%sPathdata: Flags 0x%x ID count %u\n", 1003c74ad251Schristos ib, GET_BE_U_2(pdh->pflags), 1004c74ad251Schristos GET_BE_U_2(pdh->pIDcnt)); 10050f74e101Schristos } 10060f74e101Schristos 1007c74ad251Schristos if (GET_BE_U_2(pdh->pflags) & F_SELKEY) { 10080f74e101Schristos op_msk |= B_KEYIN; 10090f74e101Schristos } 1010026d7285Schristos 1011026d7285Schristos /* Table GET Range operation */ 1012c74ad251Schristos if (GET_BE_U_2(pdh->pflags) & F_SELTABRANGE) { 1013026d7285Schristos op_msk |= B_TRNG; 1014026d7285Schristos } 1015026d7285Schristos /* Table SET append operation */ 1016c74ad251Schristos if (GET_BE_U_2(pdh->pflags) & F_TABAPPEND) { 1017026d7285Schristos op_msk |= B_APPND; 1018026d7285Schristos } 1019026d7285Schristos 10200f74e101Schristos pptr += sizeof(struct pathdata_h); 10210f74e101Schristos len -= sizeof(struct pathdata_h); 1022c74ad251Schristos idcnt = GET_BE_U_2(pdh->pIDcnt); 10239546e36dSchristos minsize = idcnt * 4; 10240f74e101Schristos if (len < minsize) { 1025c74ad251Schristos ND_PRINT("\t\t\ttruncated IDs expected %uB got %uB\n", minsize, 1026c74ad251Schristos len); 1027c74ad251Schristos hex_print(ndo, "\t\t\tID Data[", pptr, len); 1028c74ad251Schristos ND_PRINT("]\n"); 10290f74e101Schristos return -1; 10300f74e101Schristos } 1031026d7285Schristos 1032026d7285Schristos if ((op_msk & B_TRNG) && (op_msk & B_KEYIN)) { 1033c74ad251Schristos ND_PRINT("\t\t\tIllegal to have both Table ranges and keys\n"); 1034026d7285Schristos return -1; 1035026d7285Schristos } 1036026d7285Schristos 1037b3a00663Schristos more_pd = pdatacnt_print(ndo, pptr, len, idcnt, op_msk, indent); 10389546e36dSchristos if (more_pd > 0) { 10399546e36dSchristos int consumed = len - more_pd; 10409546e36dSchristos pptr += consumed; 10419546e36dSchristos len = more_pd; 10429546e36dSchristos /* XXX: Argh, recurse some more */ 1043b3a00663Schristos return recpdoptlv_print(ndo, pptr, len, op_msk, indent+1); 10449546e36dSchristos } else 10459546e36dSchristos return 0; 10460f74e101Schristos 10470f74e101Schristos trunc: 1048c74ad251Schristos nd_print_trunc(ndo); 10490f74e101Schristos return -1; 10500f74e101Schristos } 10510f74e101Schristos 1052026d7285Schristos static int 1053b3a00663Schristos genoptlv_print(netdissect_options *ndo, 1054c74ad251Schristos const u_char * pptr, u_int len, 1055b3a00663Schristos uint16_t op_msk, int indent) 10560f74e101Schristos { 1057fdccd7e4Schristos const struct forces_tlv *pdtlv = (const struct forces_tlv *)pptr; 1058b3a00663Schristos uint16_t type; 1059c74ad251Schristos u_int tlvl; 1060b3a00663Schristos u_int invtlv; 10610f74e101Schristos char *ib = indent_pr(indent, 0); 10620f74e101Schristos 1063c74ad251Schristos type = GET_BE_U_2(pdtlv->type); 1064c74ad251Schristos tlvl = GET_BE_U_2(pdtlv->length); 1065c74ad251Schristos invtlv = tlv_valid(tlvl, len); 1066c74ad251Schristos ND_PRINT("genoptlvprint - %s TLV type 0x%x len %u\n", 1067c74ad251Schristos tok2str(ForCES_TLV, NULL, type), type, tlvl); 10680f74e101Schristos if (!invtlv) { 10690f74e101Schristos /* 10700f74e101Schristos * At this point, tlv_valid() has ensured that the TLV 10710f74e101Schristos * length is large enough but not too large (it doesn't 10720f74e101Schristos * go past the end of the containing TLV). 10730f74e101Schristos */ 1074c74ad251Schristos const u_char *dp = (const u_char *) TLV_DATA(pdtlv); 1075c74ad251Schristos 10760f74e101Schristos if (!ttlv_valid(type)) { 1077c74ad251Schristos ND_PRINT("%s TLV type 0x%x len %u\n", 10780f74e101Schristos tok2str(ForCES_TLV_err, NULL, invtlv), type, 1079c74ad251Schristos tlvl); 10800f74e101Schristos return -1; 10810f74e101Schristos } 1082b3a00663Schristos if (ndo->ndo_vflag >= 3) 1083c74ad251Schristos ND_PRINT("%s%s, length %u (data length %u Bytes)", 10840f74e101Schristos ib, tok2str(ForCES_TLV, NULL, type), 1085c74ad251Schristos tlvl, tlvl - TLV_HDRL); 10860f74e101Schristos 1087c74ad251Schristos return pdata_print(ndo, dp, tlvl - TLV_HDRL, op_msk, indent + 1); 10880f74e101Schristos } else { 1089c74ad251Schristos ND_PRINT("\t\t\tInvalid ForCES TLV type=%x", type); 10900f74e101Schristos return -1; 10910f74e101Schristos } 10920f74e101Schristos } 10930f74e101Schristos 1094026d7285Schristos static int 1095b3a00663Schristos recpdoptlv_print(netdissect_options *ndo, 1096c74ad251Schristos const u_char * pptr, u_int len, 1097b3a00663Schristos uint16_t op_msk, int indent) 10980f74e101Schristos { 1099fdccd7e4Schristos const struct forces_tlv *pdtlv = (const struct forces_tlv *)pptr; 11000f74e101Schristos 11010f74e101Schristos while (len != 0) { 1102c74ad251Schristos uint16_t type, tlvl; 1103c74ad251Schristos u_int invtlv; 1104c74ad251Schristos char *ib; 1105c74ad251Schristos const u_char *dp; 1106c74ad251Schristos 1107c74ad251Schristos tlvl = GET_BE_U_2(pdtlv->length); 1108c74ad251Schristos invtlv = tlv_valid(tlvl, len); 11090f74e101Schristos if (invtlv) { 11100f74e101Schristos break; 11110f74e101Schristos } 11120f74e101Schristos 11130f74e101Schristos /* 11140f74e101Schristos * At this point, tlv_valid() has ensured that the TLV 11150f74e101Schristos * length is large enough but not too large (it doesn't 11160f74e101Schristos * go past the end of the containing TLV). 11170f74e101Schristos */ 11180f74e101Schristos ib = indent_pr(indent, 0); 1119c74ad251Schristos type = GET_BE_U_2(pdtlv->type); 1120fdccd7e4Schristos dp = (const u_char *) TLV_DATA(pdtlv); 11210f74e101Schristos 1122b3a00663Schristos if (ndo->ndo_vflag >= 3) 1123c74ad251Schristos ND_PRINT("%s%s, length %u (data encapsulated %u Bytes)", 11240f74e101Schristos ib, tok2str(ForCES_TLV, NULL, type), 1125c74ad251Schristos tlvl, 1126c74ad251Schristos tlvl - TLV_HDRL); 11270f74e101Schristos 1128c74ad251Schristos if (pdata_print(ndo, dp, tlvl - TLV_HDRL, op_msk, indent + 1) == -1) 11299546e36dSchristos return -1; 11300f74e101Schristos pdtlv = GO_NXT_TLV(pdtlv, len); 11310f74e101Schristos } 11320f74e101Schristos 11330f74e101Schristos if (len) { 1134c74ad251Schristos ND_PRINT("\n\t\tMessy PATHDATA TLV header, type (0x%x)\n\t\texcess of %u Bytes ", 1135c74ad251Schristos GET_BE_U_2(pdtlv->type), 1136c74ad251Schristos len - GET_BE_U_2(pdtlv->length)); 11370f74e101Schristos return -1; 11380f74e101Schristos } 11390f74e101Schristos 11400f74e101Schristos return 0; 11410f74e101Schristos } 11420f74e101Schristos 1143026d7285Schristos static int 1144b3a00663Schristos invoptlv_print(netdissect_options *ndo, 1145c74ad251Schristos const u_char * pptr, u_int len, 1146b3a00663Schristos uint16_t op_msk _U_, int indent) 11470f74e101Schristos { 11480f74e101Schristos char *ib = indent_pr(indent, 1); 11490f74e101Schristos 1150b3a00663Schristos if (ndo->ndo_vflag >= 3) { 1151c74ad251Schristos ND_PRINT("%sData[", ib + 1); 1152c74ad251Schristos hex_print(ndo, ib, pptr, len); 1153c74ad251Schristos ND_PRINT("%s]\n", ib); 11540f74e101Schristos } 11550f74e101Schristos return -1; 11560f74e101Schristos } 11570f74e101Schristos 1158026d7285Schristos static int 1159b3a00663Schristos otlv_print(netdissect_options *ndo, 1160b3a00663Schristos const struct forces_tlv *otlv, uint16_t op_msk _U_, int indent) 11610f74e101Schristos { 11620f74e101Schristos int rc = 0; 1163c74ad251Schristos const u_char *dp = (const u_char *) TLV_DATA(otlv); 1164b3a00663Schristos uint16_t type; 1165c74ad251Schristos u_int tll; 11660f74e101Schristos char *ib = indent_pr(indent, 0); 11670f74e101Schristos const struct optlv_h *ops; 11680f74e101Schristos 11690f74e101Schristos /* 1170c74ad251Schristos * lfbselect_print() has ensured that GET_BE_U_2(otlv->length) 11710f74e101Schristos * >= TLV_HDRL. 11720f74e101Schristos */ 1173c74ad251Schristos type = GET_BE_U_2(otlv->type); 1174c74ad251Schristos tll = GET_BE_U_2(otlv->length) - TLV_HDRL; 11750f74e101Schristos ops = get_forces_optlv_h(type); 1176b3a00663Schristos if (ndo->ndo_vflag >= 3) { 1177c74ad251Schristos ND_PRINT("%sOper TLV %s(0x%x) length %u\n", ib, ops->s, type, 1178c74ad251Schristos GET_BE_U_2(otlv->length)); 11790f74e101Schristos } 11800f74e101Schristos /* rest of ops must at least have 12B {pathinfo} */ 11810f74e101Schristos if (tll < OP_MIN_SIZ) { 1182c74ad251Schristos ND_PRINT("\t\tOper TLV %s(0x%x) length %u\n", ops->s, type, 1183c74ad251Schristos GET_BE_U_2(otlv->length)); 1184c74ad251Schristos ND_PRINT("\t\tTruncated data size %u minimum required %u\n", tll, 1185c74ad251Schristos OP_MIN_SIZ); 1186b3a00663Schristos return invoptlv_print(ndo, dp, tll, ops->op_msk, indent); 11870f74e101Schristos 11880f74e101Schristos } 11890f74e101Schristos 1190ba2ff121Schristos /* XXX - do anything with ops->flags? */ 1191ba2ff121Schristos if(ops->print) { 1192b3a00663Schristos rc = ops->print(ndo, dp, tll, ops->op_msk, indent + 1); 1193ba2ff121Schristos } 11940f74e101Schristos return rc; 11950f74e101Schristos } 11960f74e101Schristos 11970f74e101Schristos #define ASTDLN 4 11980f74e101Schristos #define ASTMCD 255 1199026d7285Schristos static int 1200b3a00663Schristos asttlv_print(netdissect_options *ndo, 1201c74ad251Schristos const u_char * pptr, u_int len, 1202b3a00663Schristos uint16_t op_msk _U_, int indent) 12030f74e101Schristos { 1204b3a00663Schristos uint32_t rescode; 12050f74e101Schristos u_int dlen; 12060f74e101Schristos char *ib = indent_pr(indent, 0); 12070f74e101Schristos 12080f74e101Schristos /* 12090f74e101Schristos * forces_type_print() has ensured that len (the TLV length) 12100f74e101Schristos * >= TLV_HDRL. 12110f74e101Schristos */ 12120f74e101Schristos dlen = len - TLV_HDRL; 12130f74e101Schristos if (dlen != ASTDLN) { 1214c74ad251Schristos ND_PRINT("illegal ASTresult-TLV: %u bytes!\n", dlen); 12150f74e101Schristos return -1; 12160f74e101Schristos } 1217c74ad251Schristos rescode = GET_BE_U_4(pptr); 12180f74e101Schristos if (rescode > ASTMCD) { 1219c74ad251Schristos ND_PRINT("illegal ASTresult result code: %u!\n", rescode); 12200f74e101Schristos return -1; 12210f74e101Schristos } 12220f74e101Schristos 1223b3a00663Schristos if (ndo->ndo_vflag >= 3) { 1224c74ad251Schristos ND_PRINT("Teardown reason:\n%s", ib); 12250f74e101Schristos switch (rescode) { 12260f74e101Schristos case 0: 1227c74ad251Schristos ND_PRINT("Normal Teardown"); 12280f74e101Schristos break; 12290f74e101Schristos case 1: 1230c74ad251Schristos ND_PRINT("Loss of Heartbeats"); 12310f74e101Schristos break; 12320f74e101Schristos case 2: 1233c74ad251Schristos ND_PRINT("Out of bandwidth"); 12340f74e101Schristos break; 12350f74e101Schristos case 3: 1236c74ad251Schristos ND_PRINT("Out of Memory"); 12370f74e101Schristos break; 12380f74e101Schristos case 4: 1239c74ad251Schristos ND_PRINT("Application Crash"); 12400f74e101Schristos break; 12410f74e101Schristos default: 1242c74ad251Schristos ND_PRINT("Unknown Teardown reason"); 12430f74e101Schristos break; 12440f74e101Schristos } 1245c74ad251Schristos ND_PRINT("(%x)\n%s", rescode, ib); 12460f74e101Schristos } 12470f74e101Schristos return 0; 12480f74e101Schristos } 12490f74e101Schristos 12500f74e101Schristos #define ASRDLN 4 12510f74e101Schristos #define ASRMCD 3 1252026d7285Schristos static int 1253b3a00663Schristos asrtlv_print(netdissect_options *ndo, 1254c74ad251Schristos const u_char * pptr, u_int len, 1255b3a00663Schristos uint16_t op_msk _U_, int indent) 12560f74e101Schristos { 1257b3a00663Schristos uint32_t rescode; 12580f74e101Schristos u_int dlen; 12590f74e101Schristos char *ib = indent_pr(indent, 0); 12600f74e101Schristos 12610f74e101Schristos /* 12620f74e101Schristos * forces_type_print() has ensured that len (the TLV length) 12630f74e101Schristos * >= TLV_HDRL. 12640f74e101Schristos */ 12650f74e101Schristos dlen = len - TLV_HDRL; 12660f74e101Schristos if (dlen != ASRDLN) { /* id, instance, oper tlv */ 1267c74ad251Schristos ND_PRINT("illegal ASRresult-TLV: %u bytes!\n", dlen); 12680f74e101Schristos return -1; 12690f74e101Schristos } 1270c74ad251Schristos rescode = GET_BE_U_4(pptr); 12710f74e101Schristos 12720f74e101Schristos if (rescode > ASRMCD) { 1273c74ad251Schristos ND_PRINT("illegal ASRresult result code: %u!\n", rescode); 12740f74e101Schristos return -1; 12750f74e101Schristos } 12760f74e101Schristos 1277b3a00663Schristos if (ndo->ndo_vflag >= 3) { 1278c74ad251Schristos ND_PRINT("\n%s", ib); 12790f74e101Schristos switch (rescode) { 12800f74e101Schristos case 0: 1281c74ad251Schristos ND_PRINT("Success "); 12820f74e101Schristos break; 12830f74e101Schristos case 1: 1284c74ad251Schristos ND_PRINT("FE ID invalid "); 12850f74e101Schristos break; 12860f74e101Schristos case 2: 1287c74ad251Schristos ND_PRINT("permission denied "); 12880f74e101Schristos break; 12890f74e101Schristos default: 1290c74ad251Schristos ND_PRINT("Unknown "); 12910f74e101Schristos break; 12920f74e101Schristos } 1293c74ad251Schristos ND_PRINT("(%x)\n%s", rescode, ib); 12940f74e101Schristos } 12950f74e101Schristos return 0; 12960f74e101Schristos } 12970f74e101Schristos 1298026d7285Schristos #if 0 12990f74e101Schristos /* 13000f74e101Schristos * XXX - not used. 13010f74e101Schristos */ 1302026d7285Schristos static int 1303b3a00663Schristos gentltlv_print(netdissect_options *ndo, 1304c74ad251Schristos const u_char * pptr _U_, u_int len, 1305b3a00663Schristos uint16_t op_msk _U_, int indent _U_) 13060f74e101Schristos { 13070f74e101Schristos u_int dlen = len - TLV_HDRL; 13080f74e101Schristos 13090f74e101Schristos if (dlen < 4) { /* at least 32 bits must exist */ 1310c74ad251Schristos ND_PRINT("truncated TLV: %u bytes missing! ", 4 - dlen); 13110f74e101Schristos return -1; 13120f74e101Schristos } 13130f74e101Schristos return 0; 13140f74e101Schristos } 1315026d7285Schristos #endif 13160f74e101Schristos 13170f74e101Schristos #define RD_MIN 8 1318026d7285Schristos 1319026d7285Schristos static int 1320b3a00663Schristos print_metailv(netdissect_options *ndo, 1321c74ad251Schristos const u_char * pptr, uint16_t op_msk _U_, int indent) 13220f74e101Schristos { 13230f74e101Schristos u_int rlen; 13240f74e101Schristos char *ib = indent_pr(indent, 0); 13250f74e101Schristos /* XXX: check header length */ 1326fdccd7e4Schristos const struct forces_ilv *ilv = (const struct forces_ilv *)pptr; 13270f74e101Schristos 13280f74e101Schristos /* 13290f74e101Schristos * print_metatlv() has ensured that len (what remains in the 13300f74e101Schristos * ILV) >= ILV_HDRL. 13310f74e101Schristos */ 1332c74ad251Schristos rlen = GET_BE_U_4(ilv->length) - ILV_HDRL; 1333c74ad251Schristos ND_PRINT("%sMetaID 0x%x length %u\n", ib, GET_BE_U_4(ilv->type), 1334c74ad251Schristos GET_BE_U_4(ilv->length)); 1335b3a00663Schristos if (ndo->ndo_vflag >= 3) { 1336c74ad251Schristos hex_print(ndo, "\t\t[", ILV_DATA(ilv), rlen); 1337c74ad251Schristos ND_PRINT(" ]\n"); 1338026d7285Schristos } 13390f74e101Schristos return 0; 13400f74e101Schristos } 13410f74e101Schristos 1342026d7285Schristos static int 1343b3a00663Schristos print_metatlv(netdissect_options *ndo, 1344c74ad251Schristos const u_char * pptr, u_int len, 1345b3a00663Schristos uint16_t op_msk _U_, int indent) 13460f74e101Schristos { 13470f74e101Schristos u_int dlen; 13480f74e101Schristos char *ib = indent_pr(indent, 0); 13490f74e101Schristos u_int rlen; 1350fdccd7e4Schristos const struct forces_ilv *ilv = (const struct forces_ilv *)pptr; 13510f74e101Schristos int invilv; 13520f74e101Schristos 13530f74e101Schristos /* 13540f74e101Schristos * redirect_print() has ensured that len (what remains in the 13550f74e101Schristos * TLV) >= TLV_HDRL. 13560f74e101Schristos */ 13570f74e101Schristos dlen = len - TLV_HDRL; 13580f74e101Schristos rlen = dlen; 1359c74ad251Schristos ND_PRINT("\n%s METADATA length %u\n", ib, rlen); 13600f74e101Schristos while (rlen != 0) { 1361c74ad251Schristos invilv = ilv_valid(ndo, ilv, rlen); 1362026d7285Schristos if (invilv) { 13630f74e101Schristos break; 1364026d7285Schristos } 13650f74e101Schristos 13660f74e101Schristos /* 13670f74e101Schristos * At this point, ilv_valid() has ensured that the ILV 13680f74e101Schristos * length is large enough but not too large (it doesn't 13690f74e101Schristos * go past the end of the containing TLV). 13700f74e101Schristos */ 1371fdccd7e4Schristos print_metailv(ndo, (const u_char *) ilv, 0, indent + 1); 13720f74e101Schristos ilv = GO_NXT_ILV(ilv, rlen); 13730f74e101Schristos } 13740f74e101Schristos 13750f74e101Schristos return 0; 13760f74e101Schristos } 13770f74e101Schristos 1378026d7285Schristos 1379026d7285Schristos static int 1380b3a00663Schristos print_reddata(netdissect_options *ndo, 1381c74ad251Schristos const u_char * pptr, u_int len, 1382dc860a36Sspz uint16_t op_msk _U_, int indent) 13830f74e101Schristos { 13840f74e101Schristos u_int dlen; 1385026d7285Schristos char *ib = indent_pr(indent, 0); 13860f74e101Schristos u_int rlen; 13870f74e101Schristos 13880f74e101Schristos dlen = len - TLV_HDRL; 13890f74e101Schristos rlen = dlen; 1390c74ad251Schristos ND_PRINT("\n%s Redirect Data length %u\n", ib, rlen); 13910f74e101Schristos 1392b3a00663Schristos if (ndo->ndo_vflag >= 3) { 1393c74ad251Schristos ND_PRINT("\t\t["); 1394c74ad251Schristos hex_print(ndo, "\n\t\t", pptr, rlen); 1395c74ad251Schristos ND_PRINT("\n\t\t]"); 13960f74e101Schristos } 13970f74e101Schristos 13980f74e101Schristos return 0; 13990f74e101Schristos } 14000f74e101Schristos 1401026d7285Schristos static int 1402b3a00663Schristos redirect_print(netdissect_options *ndo, 1403c74ad251Schristos const u_char * pptr, u_int len, 1404b3a00663Schristos uint16_t op_msk _U_, int indent) 14050f74e101Schristos { 1406fdccd7e4Schristos const struct forces_tlv *tlv = (const struct forces_tlv *)pptr; 14070f74e101Schristos u_int dlen; 14080f74e101Schristos u_int rlen; 1409b3a00663Schristos u_int invtlv; 14100f74e101Schristos 14110f74e101Schristos /* 14120f74e101Schristos * forces_type_print() has ensured that len (the TLV length) 14130f74e101Schristos * >= TLV_HDRL. 14140f74e101Schristos */ 14150f74e101Schristos dlen = len - TLV_HDRL; 14160f74e101Schristos if (dlen <= RD_MIN) { 1417c74ad251Schristos ND_PRINT("\n\t\ttruncated Redirect TLV: %u bytes missing! ", 1418c74ad251Schristos RD_MIN - dlen); 14190f74e101Schristos return -1; 14200f74e101Schristos } 14210f74e101Schristos 14220f74e101Schristos rlen = dlen; 14230f74e101Schristos indent += 1; 14240f74e101Schristos while (rlen != 0) { 1425c74ad251Schristos uint16_t type, tlvl; 1426c74ad251Schristos 1427c74ad251Schristos type = GET_BE_U_2(tlv->type); 1428c74ad251Schristos tlvl = GET_BE_U_2(tlv->length); 1429c74ad251Schristos invtlv = tlv_valid(tlvl, rlen); 1430026d7285Schristos if (invtlv) { 1431c74ad251Schristos ND_PRINT("Bad Redirect data\n"); 14320f74e101Schristos break; 1433026d7285Schristos } 14340f74e101Schristos 14350f74e101Schristos /* 14360f74e101Schristos * At this point, tlv_valid() has ensured that the TLV 14370f74e101Schristos * length is large enough but not too large (it doesn't 14380f74e101Schristos * go past the end of the containing TLV). 14390f74e101Schristos */ 1440c74ad251Schristos if (type == F_TLV_METD) { 1441fdccd7e4Schristos print_metatlv(ndo, (const u_char *) TLV_DATA(tlv), 1442c74ad251Schristos tlvl, 0, 1443c74ad251Schristos indent); 1444c74ad251Schristos } else if (type == F_TLV_REDD) { 1445fdccd7e4Schristos print_reddata(ndo, (const u_char *) TLV_DATA(tlv), 1446c74ad251Schristos tlvl, 0, 1447c74ad251Schristos indent); 14480f74e101Schristos } else { 1449c74ad251Schristos ND_PRINT("Unknown REDIRECT TLV 0x%x len %u\n", 1450c74ad251Schristos type, 1451c74ad251Schristos tlvl); 14520f74e101Schristos } 14530f74e101Schristos 14540f74e101Schristos tlv = GO_NXT_TLV(tlv, rlen); 14550f74e101Schristos } 14560f74e101Schristos 14570f74e101Schristos if (rlen) { 1458c74ad251Schristos ND_PRINT("\n\t\tMessy Redirect TLV header, type (0x%x)\n\t\texcess of %u Bytes ", 1459c74ad251Schristos GET_BE_U_2(tlv->type), 1460c74ad251Schristos rlen - GET_BE_U_2(tlv->length)); 14610f74e101Schristos return -1; 14620f74e101Schristos } 14630f74e101Schristos 14640f74e101Schristos return 0; 14650f74e101Schristos } 14660f74e101Schristos 14670f74e101Schristos #define OP_OFF 8 14680f74e101Schristos #define OP_MIN 12 14690f74e101Schristos 1470026d7285Schristos static int 1471b3a00663Schristos lfbselect_print(netdissect_options *ndo, 1472c74ad251Schristos const u_char * pptr, u_int len, 1473b3a00663Schristos uint16_t op_msk, int indent) 14740f74e101Schristos { 14750f74e101Schristos const struct forces_lfbsh *lfbs; 14760f74e101Schristos const struct forces_tlv *otlv; 14770f74e101Schristos char *ib = indent_pr(indent, 0); 14780f74e101Schristos u_int dlen; 14790f74e101Schristos u_int rlen; 1480b3a00663Schristos u_int invtlv; 14810f74e101Schristos 14820f74e101Schristos /* 14830f74e101Schristos * forces_type_print() has ensured that len (the TLV length) 14840f74e101Schristos * >= TLV_HDRL. 14850f74e101Schristos */ 14860f74e101Schristos dlen = len - TLV_HDRL; 14870f74e101Schristos if (dlen <= OP_MIN) { /* id, instance, oper tlv header .. */ 1488c74ad251Schristos ND_PRINT("\n\t\ttruncated lfb selector: %u bytes missing! ", 1489c74ad251Schristos OP_MIN - dlen); 14900f74e101Schristos return -1; 14910f74e101Schristos } 14920f74e101Schristos 14930f74e101Schristos /* 14940f74e101Schristos * At this point, we know that dlen > OP_MIN; OP_OFF < OP_MIN, so 14950f74e101Schristos * we also know that it's > OP_OFF. 14960f74e101Schristos */ 14970f74e101Schristos rlen = dlen - OP_OFF; 14980f74e101Schristos 14990f74e101Schristos lfbs = (const struct forces_lfbsh *)pptr; 1500c74ad251Schristos ND_TCHECK_SIZE(lfbs); 1501b3a00663Schristos if (ndo->ndo_vflag >= 3) { 1502c74ad251Schristos ND_PRINT("\n%s%s(Classid %x) instance %x\n", 1503c74ad251Schristos ib, 1504c74ad251Schristos tok2str(ForCES_LFBs, NULL, GET_BE_U_4(lfbs->class)), 1505c74ad251Schristos GET_BE_U_4(lfbs->class), 1506c74ad251Schristos GET_BE_U_4(lfbs->instance)); 15070f74e101Schristos } 15080f74e101Schristos 1509fdccd7e4Schristos otlv = (const struct forces_tlv *)(lfbs + 1); 15100f74e101Schristos 15110f74e101Schristos indent += 1; 15120f74e101Schristos while (rlen != 0) { 1513c74ad251Schristos uint16_t type, tlvl; 1514c74ad251Schristos 1515c74ad251Schristos type = GET_BE_U_2(otlv->type); 1516c74ad251Schristos tlvl = GET_BE_U_2(otlv->length); 1517c74ad251Schristos invtlv = tlv_valid(tlvl, rlen); 15180f74e101Schristos if (invtlv) 15190f74e101Schristos break; 15200f74e101Schristos 15210f74e101Schristos /* 15220f74e101Schristos * At this point, tlv_valid() has ensured that the TLV 15230f74e101Schristos * length is large enough but not too large (it doesn't 15240f74e101Schristos * go past the end of the containing TLV). 15250f74e101Schristos */ 1526c74ad251Schristos if (op_valid(type, op_msk)) { 1527b3a00663Schristos otlv_print(ndo, otlv, 0, indent); 15280f74e101Schristos } else { 1529b3a00663Schristos if (ndo->ndo_vflag < 3) 1530c74ad251Schristos ND_PRINT("\n"); 1531c74ad251Schristos ND_PRINT("\t\tINValid oper-TLV type 0x%x length %u for this ForCES message\n", 1532c74ad251Schristos type, tlvl); 1533fdccd7e4Schristos invoptlv_print(ndo, (const u_char *)otlv, rlen, 0, indent); 15340f74e101Schristos } 15350f74e101Schristos otlv = GO_NXT_TLV(otlv, rlen); 15360f74e101Schristos } 15370f74e101Schristos 15380f74e101Schristos if (rlen) { 1539c74ad251Schristos ND_PRINT("\n\t\tMessy oper TLV header, type (0x%x)\n\t\texcess of %u Bytes ", 1540c74ad251Schristos GET_BE_U_2(otlv->type), 1541c74ad251Schristos rlen - GET_BE_U_2(otlv->length)); 15420f74e101Schristos return -1; 15430f74e101Schristos } 15440f74e101Schristos 15450f74e101Schristos return 0; 15460f74e101Schristos 15470f74e101Schristos trunc: 1548c74ad251Schristos nd_print_trunc(ndo); 15490f74e101Schristos return -1; 15500f74e101Schristos } 15510f74e101Schristos 1552026d7285Schristos static int 1553b3a00663Schristos forces_type_print(netdissect_options *ndo, 1554c74ad251Schristos const u_char * pptr, const struct forcesh *fhdr _U_, 1555c74ad251Schristos u_int mlen, const struct tom_h *tops) 15560f74e101Schristos { 15570f74e101Schristos const struct forces_tlv *tltlv; 15580f74e101Schristos u_int rlen; 1559b3a00663Schristos u_int invtlv; 15600f74e101Schristos int rc = 0; 1561c74ad251Schristos u_int ttlv = 0; 15620f74e101Schristos 15630f74e101Schristos /* 15640f74e101Schristos * forces_print() has already checked that mlen >= ForCES_HDRL 15650f74e101Schristos * by calling ForCES_HLN_VALID(). 15660f74e101Schristos */ 15670f74e101Schristos rlen = mlen - ForCES_HDRL; 15680f74e101Schristos 15690f74e101Schristos if (rlen > TLV_HLN) { 15700f74e101Schristos if (tops->flags & ZERO_TTLV) { 1571c74ad251Schristos ND_PRINT("<0x%x>Illegal Top level TLV!\n", tops->flags); 15720f74e101Schristos return -1; 15730f74e101Schristos } 15740f74e101Schristos } else { 15750f74e101Schristos if (tops->flags & ZERO_MORE_TTLV) 15760f74e101Schristos return 0; 15770f74e101Schristos if (tops->flags & ONE_MORE_TTLV) { 1578c74ad251Schristos ND_PRINT("\tTop level TLV Data missing!\n"); 15790f74e101Schristos return -1; 15800f74e101Schristos } 15810f74e101Schristos } 15820f74e101Schristos 15830f74e101Schristos if (tops->flags & ZERO_TTLV) { 15840f74e101Schristos return 0; 15850f74e101Schristos } 15860f74e101Schristos 15870f74e101Schristos ttlv = tops->flags >> 4; 15880f74e101Schristos tltlv = GET_TOP_TLV(pptr); 15890f74e101Schristos 15900f74e101Schristos /*XXX: 15 top level tlvs will probably be fine 15910f74e101Schristos You are nuts if you send more ;-> */ 15920f74e101Schristos while (rlen != 0) { 1593c74ad251Schristos uint16_t type, tlvl; 1594c74ad251Schristos 1595c74ad251Schristos type = GET_BE_U_2(tltlv->type); 1596c74ad251Schristos tlvl = GET_BE_U_2(tltlv->length); 1597c74ad251Schristos invtlv = tlv_valid(tlvl, rlen); 15980f74e101Schristos if (invtlv) 15990f74e101Schristos break; 16000f74e101Schristos 16010f74e101Schristos /* 16020f74e101Schristos * At this point, tlv_valid() has ensured that the TLV 16030f74e101Schristos * length is large enough but not too large (it doesn't 16040f74e101Schristos * go past the end of the packet). 16050f74e101Schristos */ 1606c74ad251Schristos if (!ttlv_valid(type)) { 1607c74ad251Schristos ND_PRINT("\n\tInvalid ForCES Top TLV type=0x%x", 1608c74ad251Schristos type); 16090f74e101Schristos return -1; 16100f74e101Schristos } 16110f74e101Schristos 1612b3a00663Schristos if (ndo->ndo_vflag >= 3) 1613c74ad251Schristos ND_PRINT("\t%s, length %u (data length %u Bytes)", 1614c74ad251Schristos tok2str(ForCES_TLV, NULL, type), 1615c74ad251Schristos tlvl, 1616c74ad251Schristos tlvl - TLV_HDRL); 16170f74e101Schristos 1618fdccd7e4Schristos rc = tops->print(ndo, (const u_char *) TLV_DATA(tltlv), 1619c74ad251Schristos tlvl, 1620c74ad251Schristos tops->op_msk, 9); 16210f74e101Schristos if (rc < 0) { 16220f74e101Schristos return -1; 16230f74e101Schristos } 16240f74e101Schristos tltlv = GO_NXT_TLV(tltlv, rlen); 16250f74e101Schristos ttlv--; 16260f74e101Schristos if (ttlv <= 0) 16270f74e101Schristos break; 16280f74e101Schristos } 16290f74e101Schristos /* 16300f74e101Schristos * XXX - if ttlv != 0, does that mean that the packet was too 16310f74e101Schristos * short, and didn't have *enough* TLVs in it? 16320f74e101Schristos */ 16330f74e101Schristos if (rlen) { 1634c74ad251Schristos ND_PRINT("\tMess TopTLV header: min %u, total %u advertised %u ", 1635c74ad251Schristos TLV_HDRL, rlen, GET_BE_U_2(tltlv->length)); 16360f74e101Schristos return -1; 16370f74e101Schristos } 16380f74e101Schristos 16390f74e101Schristos return 0; 16400f74e101Schristos } 16410f74e101Schristos 1642026d7285Schristos void 1643b3a00663Schristos forces_print(netdissect_options *ndo, 1644c74ad251Schristos const u_char * pptr, u_int len) 16450f74e101Schristos { 16460f74e101Schristos const struct forcesh *fhdr; 16470f74e101Schristos u_int mlen; 1648b3a00663Schristos uint32_t flg_raw; 1649c74ad251Schristos uint8_t tom; 16500f74e101Schristos const struct tom_h *tops; 16510f74e101Schristos int rc = 0; 16520f74e101Schristos 1653c74ad251Schristos ndo->ndo_protocol = "forces"; 16540f74e101Schristos fhdr = (const struct forcesh *)pptr; 1655c74ad251Schristos ND_TCHECK_SIZE(fhdr); 1656c74ad251Schristos tom = GET_U_1(fhdr->fm_tom); 1657c74ad251Schristos if (!tom_valid(tom)) { 1658c74ad251Schristos ND_PRINT("Invalid ForCES message type %u\n", tom); 16590f74e101Schristos goto error; 16600f74e101Schristos } 16610f74e101Schristos 16620f74e101Schristos mlen = ForCES_BLN(fhdr); 16630f74e101Schristos 1664c74ad251Schristos tops = get_forces_tom(tom); 16650f74e101Schristos if (tops->v == TOM_RSVD) { 1666c74ad251Schristos ND_PRINT("\n\tUnknown ForCES message type=0x%x", tom); 16670f74e101Schristos goto error; 16680f74e101Schristos } 16690f74e101Schristos 1670c74ad251Schristos ND_PRINT("\n\tForCES %s ", tops->s); 16710f74e101Schristos if (!ForCES_HLN_VALID(mlen, len)) { 1672c74ad251Schristos ND_PRINT("Illegal ForCES pkt len - min %u, total recvd %u, advertised %u ", 1673c74ad251Schristos ForCES_HDRL, len, ForCES_BLN(fhdr)); 16740f74e101Schristos goto error; 16750f74e101Schristos } 16760f74e101Schristos 1677c74ad251Schristos flg_raw = GET_BE_U_4(pptr + 20); 1678b3a00663Schristos if (ndo->ndo_vflag >= 1) { 1679c74ad251Schristos ND_PRINT("\n\tForCES Version %u len %uB flags 0x%08x ", 1680c74ad251Schristos ForCES_V(fhdr), mlen, flg_raw); 1681c74ad251Schristos ND_PRINT("\n\tSrcID 0x%x(%s) DstID 0x%x(%s) Correlator 0x%" PRIx64, 16820f74e101Schristos ForCES_SID(fhdr), ForCES_node(ForCES_SID(fhdr)), 16830f74e101Schristos ForCES_DID(fhdr), ForCES_node(ForCES_DID(fhdr)), 1684c74ad251Schristos GET_BE_U_8(fhdr->fm_cor)); 16850f74e101Schristos 16860f74e101Schristos } 1687b3a00663Schristos if (ndo->ndo_vflag >= 2) { 1688c74ad251Schristos ND_PRINT("\n\tForCES flags:\n\t %s(0x%x), prio=%u, %s(0x%x),\n\t %s(0x%x), %s(0x%x)\n", 1689b3a00663Schristos tok2str(ForCES_ACKs, "ACKUnknown", ForCES_ACK(fhdr)), 1690b3a00663Schristos ForCES_ACK(fhdr), 16910f74e101Schristos ForCES_PRI(fhdr), 1692b3a00663Schristos tok2str(ForCES_EMs, "EMUnknown", ForCES_EM(fhdr)), 1693b3a00663Schristos ForCES_EM(fhdr), 1694b3a00663Schristos tok2str(ForCES_ATs, "ATUnknown", ForCES_AT(fhdr)), 1695b3a00663Schristos ForCES_AT(fhdr), 1696b3a00663Schristos tok2str(ForCES_TPs, "TPUnknown", ForCES_TP(fhdr)), 1697c74ad251Schristos ForCES_TP(fhdr)); 1698c74ad251Schristos ND_PRINT("\t Extra flags: rsv(b5-7) 0x%x rsv(b13-31) 0x%x\n", 1699c74ad251Schristos ForCES_RS1(fhdr), ForCES_RS2(fhdr)); 17000f74e101Schristos } 1701b3a00663Schristos rc = forces_type_print(ndo, pptr, fhdr, mlen, tops); 17020f74e101Schristos if (rc < 0) { 17030f74e101Schristos error: 1704c74ad251Schristos hex_print(ndo, "\n\t[", pptr, len); 1705c74ad251Schristos ND_PRINT("\n\t]"); 17060f74e101Schristos return; 17070f74e101Schristos } 17080f74e101Schristos 1709b3a00663Schristos if (ndo->ndo_vflag >= 4) { 1710c74ad251Schristos ND_PRINT("\n\t Raw ForCES message\n\t ["); 1711c74ad251Schristos hex_print(ndo, "\n\t ", pptr, len); 1712c74ad251Schristos ND_PRINT("\n\t ]"); 17130f74e101Schristos } 17140f74e101Schristos return; 17150f74e101Schristos 17160f74e101Schristos trunc: 1717c74ad251Schristos nd_print_trunc(ndo); 17180f74e101Schristos } 1719