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