xref: /freebsd/contrib/tcpdump/print-forces.c (revision b1f9167f94059fd55c630891d359bcff987bd7eb)
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 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #include <tcpdump-stdinc.h>
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 
26 #include "interface.h"
27 #include "extract.h"
28 
29 #include "forces.h"
30 
31 #define RESLEN	4
32 
33 int
34 prestlv_print(register const u_char * pptr, register u_int len,
35 	      u_int16_t op_msk _U_, int indent)
36 {
37 	const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
38 	register const u_char *tdp = (u_char *) TLV_DATA(tlv);
39 	struct res_val *r = (struct res_val *)tdp;
40 	u_int dlen;
41 
42 	/*
43 	 * pdatacnt_print() has ensured that len (the TLV length)
44 	 * >= TLV_HDRL.
45 	 */
46 	dlen = len - TLV_HDRL;
47 	if (dlen != RESLEN) {
48 		printf("illegal RESULT-TLV: %d bytes!\n", dlen);
49 		return -1;
50 	}
51 
52 	TCHECK(*r);
53 	if (r->result >= 0x18 && r->result <= 0xFE) {
54 		printf("illegal reserved result code: 0x%x!\n", r->result);
55 		return -1;
56 	}
57 
58 	if (vflag >= 3) {
59 		char *ib = indent_pr(indent, 0);
60 		printf("%s  Result: %s (code 0x%x)\n", ib,
61 		       tok2str(ForCES_errs, NULL, r->result), r->result);
62 	}
63 	return 0;
64 
65 trunc:
66 	fputs("[|forces]", stdout);
67 	return -1;
68 }
69 
70 int
71 fdatatlv_print(register const u_char * pptr, register u_int len,
72 	       u_int16_t op_msk _U_, int indent)
73 {
74 	const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
75 	u_int rlen;
76 	register const u_char *tdp = (u_char *) TLV_DATA(tlv);
77 	u_int16_t type;
78 
79 	/*
80 	 * pdatacnt_print() or pkeyitlv_print() has ensured that len
81 	 * (the TLV length) >= TLV_HDRL.
82 	 */
83 	rlen = len - TLV_HDRL;
84 	TCHECK(*tlv);
85 	type = EXTRACT_16BITS(&tlv->type);
86 	if (type != F_TLV_FULD) {
87 		printf("Error: expecting FULLDATA!\n");
88 		return -1;
89 	}
90 
91 	if (vflag >= 3) {
92 		char *ib = indent_pr(indent + 2, 1);
93 		printf("%s[", &ib[1]);
94 		hex_print_with_offset(ib, tdp, rlen, 0);
95 		printf("\n%s]\n", &ib[1]);
96 	}
97 	return 0;
98 
99 trunc:
100 	fputs("[|forces]", stdout);
101 	return -1;
102 }
103 
104 int
105 sdatailv_print(register const u_char * pptr, register u_int len,
106 	       u_int16_t op_msk _U_, int indent)
107 {
108 	u_int rlen;
109 	const struct forces_ilv *ilv = (struct forces_ilv *)pptr;
110 	int invilv;
111 
112 	if (len < ILV_HDRL) {
113 		printf("Error: BAD SPARSEDATA-TLV!\n");
114 		return -1;
115 	}
116 	rlen = len;
117 	indent += 1;
118 	while (rlen != 0) {
119 		char *ib = indent_pr(indent, 1);
120 		register const u_char *tdp = (u_char *) ILV_DATA(ilv);
121 		TCHECK(*ilv);
122 		invilv = ilv_valid(ilv, rlen);
123 		if (invilv) {
124 			printf("%s[", &ib[1]);
125 			hex_print_with_offset(ib, tdp, rlen, 0);
126 			printf("\n%s]\n", &ib[1]);
127 			return -1;
128 		}
129 		if (vflag >= 3) {
130 			int ilvl = EXTRACT_32BITS(&ilv->length);
131 			printf("\n%s ILV: type %x length %d\n", &ib[1],
132 			       EXTRACT_32BITS(&ilv->type), ilvl);
133 			hex_print_with_offset("\t\t[", tdp, ilvl-ILV_HDRL, 0);
134 		}
135 
136 		ilv = GO_NXT_ILV(ilv, rlen);
137 	}
138 
139 	return 0;
140 
141 trunc:
142 	fputs("[|forces]", stdout);
143 	return -1;
144 }
145 
146 int
147 sdatatlv_print(register const u_char * pptr, register u_int len,
148 	       u_int16_t op_msk, int indent)
149 {
150 	const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
151 	u_int rlen;
152 	register const u_char *tdp = (u_char *) TLV_DATA(tlv);
153 	u_int16_t type;
154 
155 	/*
156 	 * pdatacnt_print() has ensured that len (the TLV length)
157 	 * >= TLV_HDRL.
158 	 */
159 	rlen = len - TLV_HDRL;
160 	TCHECK(*tlv);
161 	type = EXTRACT_16BITS(&tlv->type);
162 	if (type != F_TLV_SPAD) {
163 		printf("Error: expecting SPARSEDATA!\n");
164 		return -1;
165 	}
166 
167 	return sdatailv_print(tdp, rlen, op_msk, indent);
168 
169 trunc:
170 	fputs("[|forces]", stdout);
171 	return -1;
172 }
173 
174 int
175 pkeyitlv_print(register const u_char * pptr, register u_int len,
176 	       u_int16_t op_msk, int indent)
177 {
178 	const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
179 	register const u_char *tdp = (u_char *) TLV_DATA(tlv);
180 	register const u_char *dp = tdp + 4;
181 	const struct forces_tlv *kdtlv = (struct forces_tlv *)dp;
182 	u_int32_t id;
183 	char *ib = indent_pr(indent, 0);
184 	u_int16_t type, tll;
185 	int invtlv;
186 
187 	TCHECK(*tdp);
188 	id = EXTRACT_32BITS(tdp);
189 	printf("%sKeyinfo: Key 0x%x\n", ib, id);
190 	TCHECK(*kdtlv);
191 	type = EXTRACT_16BITS(&kdtlv->type);
192 	invtlv = tlv_valid(kdtlv, len);
193 
194 	if (invtlv) {
195 		printf("%s TLV type 0x%x len %d\n",
196 		       tok2str(ForCES_TLV_err, NULL, invtlv), type,
197 		       EXTRACT_16BITS(&kdtlv->length));
198 		return -1;
199 	}
200 	/*
201 	 * At this point, tlv_valid() has ensured that the TLV
202 	 * length is large enough but not too large (it doesn't
203 	 * go past the end of the containing TLV).
204 	 */
205 	tll = EXTRACT_16BITS(&kdtlv->length);
206 	dp = (u_char *) TLV_DATA(kdtlv);
207 	return fdatatlv_print(dp, tll, op_msk, indent);
208 
209 trunc:
210 	fputs("[|forces]", stdout);
211 	return -1;
212 }
213 
214 int
215 pdatacnt_print(register const u_char * pptr, register u_int len,
216 	       u_int16_t IDcnt, u_int16_t op_msk, int indent)
217 {
218 	u_int i;
219 	u_int32_t id;
220 	char *ib = indent_pr(indent, 0);
221 
222 	for (i = 0; i < IDcnt; i++) {
223 		TCHECK2(*pptr, 4);
224 		if (len < 4)
225 			goto trunc;
226 		id = EXTRACT_32BITS(pptr);
227 		if (vflag >= 3)
228 			printf("%s  ID#%02u: %d\n", ib, i + 1, id);
229 		len -= 4;
230 		pptr += 4;
231 	}
232 	if (len) {
233 		const struct forces_tlv *pdtlv = (struct forces_tlv *)pptr;
234 		u_int16_t type;
235 		u_int16_t tll;
236 		int pad = 0;
237 		u_int aln;
238 		int invtlv;
239 
240 		TCHECK(*pdtlv);
241 		type = EXTRACT_16BITS(&pdtlv->type);
242 		invtlv = tlv_valid(pdtlv, len);
243 		if (invtlv) {
244 			printf
245 			    ("%s Outstanding bytes %d for TLV type 0x%x TLV len %d\n",
246 			     tok2str(ForCES_TLV_err, NULL, invtlv), len, type,
247 			     EXTRACT_16BITS(&pdtlv->length));
248 			goto pd_err;
249 		}
250 		/*
251 		 * At this point, tlv_valid() has ensured that the TLV
252 		 * length is large enough but not too large (it doesn't
253 		 * go past the end of the containing TLV).
254 		 */
255 		tll = EXTRACT_16BITS(&pdtlv->length) - TLV_HDRL;
256 		aln = F_ALN_LEN(EXTRACT_16BITS(&pdtlv->length));
257 		if (aln > EXTRACT_16BITS(&pdtlv->length)) {
258 			if (aln > len) {
259 				printf
260 				    ("Invalid padded pathdata TLV type 0x%x len %d missing %d pad bytes\n",
261 				     type, EXTRACT_16BITS(&pdtlv->length), aln - len);
262 			} else {
263 				pad = aln - EXTRACT_16BITS(&pdtlv->length);
264 			}
265 		}
266 		if (pd_valid(type)) {
267 			const struct pdata_ops *ops = get_forces_pd(type);
268 
269 			if (vflag >= 3 && ops->v != F_TLV_PDAT) {
270 				if (pad)
271 					printf
272 					    ("%s  %s (Length %d DataLen %d pad %d Bytes)\n",
273 					     ib, ops->s, EXTRACT_16BITS(&pdtlv->length),
274 					     tll, pad);
275 				else
276 					printf
277 					    ("%s  %s (Length %d DataLen %d Bytes)\n",
278 					     ib, ops->s, EXTRACT_16BITS(&pdtlv->length),
279 					     tll);
280 			}
281 
282 			chk_op_type(type, op_msk, ops->op_msk);
283 
284 			if (ops->print((const u_char *)pdtlv,
285 					tll + pad + TLV_HDRL, op_msk,
286 					indent + 2) == -1)
287 				return -1;
288 			len -= (TLV_HDRL + pad + tll);
289 		} else {
290 			printf("Invalid path data content type 0x%x len %d\n",
291 			       type, EXTRACT_16BITS(&pdtlv->length));
292 pd_err:
293 			if (EXTRACT_16BITS(&pdtlv->length)) {
294 				hex_print_with_offset("Bad Data val\n\t  [",
295 						      pptr, len, 0);
296 				printf("]\n");
297 
298 				return -1;
299 			}
300 		}
301 	}
302 	return len;
303 
304 trunc:
305 	fputs("[|forces]", stdout);
306 	return -1;
307 }
308 
309 int
310 pdata_print(register const u_char * pptr, register u_int len,
311 	    u_int16_t op_msk, int indent)
312 {
313 	const struct pathdata_h *pdh = (struct pathdata_h *)pptr;
314 	char *ib = indent_pr(indent, 0);
315 	u_int minsize = 0;
316 	int more_pd = 0;
317 	u_int16_t idcnt = 0;
318 
319 	TCHECK(*pdh);
320 	if (len < sizeof(struct pathdata_h))
321 		goto trunc;
322 	if (vflag >= 3) {
323 		printf("\n%sPathdata: Flags 0x%x ID count %d\n",
324 		       ib, EXTRACT_16BITS(&pdh->pflags), EXTRACT_16BITS(&pdh->pIDcnt));
325 	}
326 
327 	if (EXTRACT_16BITS(&pdh->pflags) & F_SELKEY) {
328 		op_msk |= B_KEYIN;
329 	}
330 	pptr += sizeof(struct pathdata_h);
331 	len -= sizeof(struct pathdata_h);
332 	idcnt = EXTRACT_16BITS(&pdh->pIDcnt);
333 	minsize = idcnt * 4;
334 	if (len < minsize) {
335 		printf("\t\t\ttruncated IDs expected %uB got %uB\n", minsize,
336 		       len);
337 		hex_print_with_offset("\t\t\tID Data[", pptr, len, 0);
338 		printf("]\n");
339 		return -1;
340 	}
341 	more_pd = pdatacnt_print(pptr, len, idcnt, op_msk, indent);
342 	if (more_pd > 0) {
343 		int consumed = len - more_pd;
344 		pptr += consumed;
345 		len = more_pd;
346 		/* XXX: Argh, recurse some more */
347 		return recpdoptlv_print(pptr, len, op_msk, indent+1);
348 	} else
349 		return 0;
350 
351 trunc:
352 	fputs("[|forces]", stdout);
353 	return -1;
354 }
355 
356 int
357 genoptlv_print(register const u_char * pptr, register u_int len,
358 	       u_int16_t op_msk, int indent)
359 {
360 	const struct forces_tlv *pdtlv = (struct forces_tlv *)pptr;
361 	u_int16_t type;
362 	int tll;
363 	int invtlv;
364 	char *ib = indent_pr(indent, 0);
365 
366 	TCHECK(*pdtlv);
367 	type = EXTRACT_16BITS(&pdtlv->type);
368 	tll = EXTRACT_16BITS(&pdtlv->length) - TLV_HDRL;
369 	invtlv = tlv_valid(pdtlv, len);
370 	printf("genoptlvprint - %s TLV type 0x%x len %d\n",
371 	       tok2str(ForCES_TLV, NULL, type), type, EXTRACT_16BITS(&pdtlv->length));
372 	if (!invtlv) {
373 		/*
374 		 * At this point, tlv_valid() has ensured that the TLV
375 		 * length is large enough but not too large (it doesn't
376 		 * go past the end of the containing TLV).
377 		 */
378 		register const u_char *dp = (u_char *) TLV_DATA(pdtlv);
379 		if (!ttlv_valid(type)) {
380 			printf("%s TLV type 0x%x len %d\n",
381 			       tok2str(ForCES_TLV_err, NULL, invtlv), type,
382 			       EXTRACT_16BITS(&pdtlv->length));
383 			return -1;
384 		}
385 		if (vflag >= 3)
386 			printf("%s%s, length %d (data length %d Bytes)",
387 			       ib, tok2str(ForCES_TLV, NULL, type),
388 			       EXTRACT_16BITS(&pdtlv->length), tll);
389 
390 		return pdata_print(dp, tll, op_msk, indent + 1);
391 	} else {
392 		printf("\t\t\tInvalid ForCES TLV type=%x", type);
393 		return -1;
394 	}
395 
396 trunc:
397 	fputs("[|forces]", stdout);
398 	return -1;
399 }
400 
401 int
402 recpdoptlv_print(register const u_char * pptr, register u_int len,
403 		 u_int16_t op_msk, int indent)
404 {
405 	const struct forces_tlv *pdtlv = (struct forces_tlv *)pptr;
406 	int tll;
407 	int invtlv;
408 	u_int16_t type;
409 	register const u_char *dp;
410 	char *ib;
411 
412 	while (len != 0) {
413 		TCHECK(*pdtlv);
414 		invtlv = tlv_valid(pdtlv, len);
415 		if (invtlv) {
416 			break;
417 		}
418 
419 		/*
420 		 * At this point, tlv_valid() has ensured that the TLV
421 		 * length is large enough but not too large (it doesn't
422 		 * go past the end of the containing TLV).
423 		 */
424 		ib = indent_pr(indent, 0);
425 		type = EXTRACT_16BITS(&pdtlv->type);
426 		dp = (u_char *) TLV_DATA(pdtlv);
427 		tll = EXTRACT_16BITS(&pdtlv->length) - TLV_HDRL;
428 
429 		if (vflag >= 3)
430 			printf
431 			    ("%s%s, length %d (data encapsulated %d Bytes)",
432 			     ib, tok2str(ForCES_TLV, NULL, type),
433 			     EXTRACT_16BITS(&pdtlv->length),
434 			     EXTRACT_16BITS(&pdtlv->length) - TLV_HDRL);
435 
436 		if (pdata_print(dp, tll, op_msk, indent + 1) == -1)
437 			return -1;
438 		pdtlv = GO_NXT_TLV(pdtlv, len);
439 	}
440 
441 	if (len) {
442 		printf
443 		    ("\n\t\tMessy PATHDATA TLV header, type (0x%x)\n\t\texcess of %d Bytes ",
444 		     EXTRACT_16BITS(&pdtlv->type), len - EXTRACT_16BITS(&pdtlv->length));
445 		return -1;
446 	}
447 
448 	return 0;
449 
450 trunc:
451 	fputs("[|forces]", stdout);
452 	return -1;
453 }
454 
455 int
456 invoptlv_print(register const u_char * pptr, register u_int len,
457 	       u_int16_t op_msk _U_, int indent)
458 {
459 	char *ib = indent_pr(indent, 1);
460 
461 	if (vflag >= 3) {
462 		printf("%sData[", &ib[1]);
463 		hex_print_with_offset(ib, pptr, len, 0);
464 		printf("%s]\n", ib);
465 	}
466 	return -1;
467 }
468 
469 int otlv_print(const struct forces_tlv *otlv, u_int16_t op_msk _U_, int indent)
470 {
471 	int rc = 0;
472 	register const u_char *dp = (u_char *) TLV_DATA(otlv);
473 	u_int16_t type;
474 	int tll;
475 	char *ib = indent_pr(indent, 0);
476 	const struct optlv_h *ops;
477 
478 	/*
479 	 * lfbselect_print() has ensured that EXTRACT_16BITS(&otlv->length)
480 	 * >= TLV_HDRL.
481 	 */
482 	TCHECK(*otlv);
483 	type = EXTRACT_16BITS(&otlv->type);
484 	tll = EXTRACT_16BITS(&otlv->length) - TLV_HDRL;
485 	ops = get_forces_optlv_h(type);
486 	if (vflag >= 3) {
487 		printf("%sOper TLV %s(0x%x) length %d\n", ib, ops->s, type,
488 		       EXTRACT_16BITS(&otlv->length));
489 	}
490 	/* empty TLVs like COMMIT and TRCOMMIT are empty, we stop here .. */
491 	if (!ops->flags & ZERO_TTLV) {
492 		if (tll != 0)	/* instead of "if (tll)" - for readability .. */
493 			printf("%s: Illegal - MUST be empty\n", ops->s);
494 		return rc;
495 	}
496 	/* rest of ops must at least have 12B {pathinfo} */
497 	if (tll < OP_MIN_SIZ) {
498 		printf("\t\tOper TLV %s(0x%x) length %d\n", ops->s, type,
499 		       EXTRACT_16BITS(&otlv->length));
500 		printf("\t\tTruncated data size %d minimum required %d\n", tll,
501 		       OP_MIN_SIZ);
502 		return invoptlv_print(dp, tll, ops->op_msk, indent);
503 
504 	}
505 
506 	rc = ops->print(dp, tll, ops->op_msk, indent + 1);
507 	return rc;
508 
509 trunc:
510 	fputs("[|forces]", stdout);
511 	return -1;
512 }
513 
514 #define ASTDLN	4
515 #define ASTMCD	255
516 int
517 asttlv_print(register const u_char * pptr, register u_int len,
518 	     u_int16_t op_msk _U_, int indent)
519 {
520 	u_int32_t rescode;
521 	u_int dlen;
522 	char *ib = indent_pr(indent, 0);
523 
524 	/*
525 	 * forces_type_print() has ensured that len (the TLV length)
526 	 * >= TLV_HDRL.
527 	 */
528 	dlen = len - TLV_HDRL;
529 	if (dlen != ASTDLN) {
530 		printf("illegal ASTresult-TLV: %d bytes!\n", dlen);
531 		return -1;
532 	}
533 	TCHECK2(*pptr, 4);
534 	rescode = EXTRACT_32BITS(pptr);
535 	if (rescode > ASTMCD) {
536 		printf("illegal ASTresult result code: %d!\n", rescode);
537 		return -1;
538 	}
539 
540 	if (vflag >= 3) {
541 		printf("Teardown reason:\n%s", ib);
542 		switch (rescode) {
543 		case 0:
544 			printf("Normal Teardown");
545 			break;
546 		case 1:
547 			printf("Loss of Heartbeats");
548 			break;
549 		case 2:
550 			printf("Out of bandwidth");
551 			break;
552 		case 3:
553 			printf("Out of Memory");
554 			break;
555 		case 4:
556 			printf("Application Crash");
557 			break;
558 		default:
559 			printf("Unknown Teardown reason");
560 			break;
561 		}
562 		printf("(%x)\n%s", rescode, ib);
563 	}
564 	return 0;
565 
566 trunc:
567 	fputs("[|forces]", stdout);
568 	return -1;
569 }
570 
571 #define ASRDLN	4
572 #define ASRMCD	3
573 int
574 asrtlv_print(register const u_char * pptr, register u_int len,
575 	     u_int16_t op_msk _U_, int indent)
576 {
577 	u_int32_t rescode;
578 	u_int dlen;
579 	char *ib = indent_pr(indent, 0);
580 
581 	/*
582 	 * forces_type_print() has ensured that len (the TLV length)
583 	 * >= TLV_HDRL.
584 	 */
585 	dlen = len - TLV_HDRL;
586 	if (dlen != ASRDLN) {	/* id, instance, oper tlv */
587 		printf("illegal ASRresult-TLV: %d bytes!\n", dlen);
588 		return -1;
589 	}
590 	TCHECK2(*pptr, 4);
591 	rescode = EXTRACT_32BITS(pptr);
592 
593 	if (rescode > ASRMCD) {
594 		printf("illegal ASRresult result code: %d!\n", rescode);
595 		return -1;
596 	}
597 
598 	if (vflag >= 3) {
599 		printf("\n%s", ib);
600 		switch (rescode) {
601 		case 0:
602 			printf("Success ");
603 			break;
604 		case 1:
605 			printf("FE ID invalid ");
606 			break;
607 		case 2:
608 			printf("permission denied ");
609 			break;
610 		default:
611 			printf("Unknown ");
612 			break;
613 		}
614 		printf("(%x)\n%s", rescode, ib);
615 	}
616 	return 0;
617 
618 trunc:
619 	fputs("[|forces]", stdout);
620 	return -1;
621 }
622 
623 /*
624  * XXX - not used.
625  */
626 int
627 gentltlv_print(register const u_char * pptr _U_, register u_int len,
628 	       u_int16_t op_msk _U_, int indent _U_)
629 {
630 	u_int dlen = len - TLV_HDRL;
631 
632 	if (dlen < 4) {		/* at least 32 bits must exist */
633 		printf("truncated TLV: %d bytes missing! ", 4 - dlen);
634 		return -1;
635 	}
636 	return 0;
637 }
638 
639 #define RD_MIN 8
640 int
641 print_metailv(register const u_char * pptr, register u_int len,
642 	      u_int16_t op_msk _U_, int indent)
643 {
644 	u_int dlen;
645 	u_int rlen;
646 	char *ib = indent_pr(indent, 0);
647 	/* XXX: check header length */
648 	const struct forces_ilv *ilv = (struct forces_ilv *)pptr;
649 
650 	/*
651 	 * print_metatlv() has ensured that len (what remains in the
652 	 * ILV) >= ILV_HDRL.
653 	 */
654 	dlen = len - ILV_HDRL;
655 	rlen = dlen;
656 	TCHECK(*ilv);
657 	printf("\n%sMetaID 0x%x length %d\n", ib, EXTRACT_32BITS(&ilv->type),
658 	       EXTRACT_32BITS(&ilv->length));
659 	hex_print_with_offset("\n\t\t\t\t[", ILV_DATA(ilv), rlen, 0);
660 	return 0;
661 
662 trunc:
663 	fputs("[|forces]", stdout);
664 	return -1;
665 }
666 
667 int
668 print_metatlv(register const u_char * pptr, register u_int len,
669 	      u_int16_t op_msk _U_, int indent)
670 {
671 	u_int dlen;
672 	char *ib = indent_pr(indent, 0);
673 	u_int rlen;
674 	const struct forces_ilv *ilv = (struct forces_ilv *)pptr;
675 	int invilv;
676 
677 	/*
678 	 * redirect_print() has ensured that len (what remains in the
679 	 * TLV) >= TLV_HDRL.
680 	 */
681 	dlen = len - TLV_HDRL;
682 	rlen = dlen;
683 	printf("\n%s METADATA\n", ib);
684 	while (rlen != 0) {
685 		TCHECK(*ilv);
686 		invilv = ilv_valid(ilv, rlen);
687 		if (invilv)
688 			break;
689 
690 		/*
691 		 * At this point, ilv_valid() has ensured that the ILV
692 		 * length is large enough but not too large (it doesn't
693 		 * go past the end of the containing TLV).
694 		 */
695 		print_metailv((u_char *) ilv, rlen, 0, indent + 1);
696 
697 		ilv = GO_NXT_ILV(ilv, rlen);
698 	}
699 
700 	return 0;
701 
702 trunc:
703 	fputs("[|forces]", stdout);
704 	return -1;
705 }
706 
707 /*
708 */
709 int
710 print_reddata(register const u_char * pptr, register u_int len,
711 	      u_int16_t op_msk _U_, int indent _U_)
712 {
713 	u_int dlen;
714 	u_int rlen;
715 	int invtlv;
716 	const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
717 
718 	/*
719 	 * redirect_print() has ensured that len (what remains in the
720 	 * TLV) >= TLV_HDRL.
721 	 */
722 	dlen = len - TLV_HDRL;
723 	printf("\n\t\t Redirect DATA\n");
724 	if (dlen <= RD_MIN) {
725 		printf("\n\t\ttruncated Redirect data: %d bytes missing! ",
726 		       RD_MIN - dlen);
727 		return -1;
728 	}
729 
730 	rlen = dlen;
731 	TCHECK(*tlv);
732 	invtlv = tlv_valid(tlv, rlen);
733 
734 	if (invtlv) {
735 		printf("Redir data type 0x%x len %d\n", EXTRACT_16BITS(&tlv->type),
736 		       EXTRACT_16BITS(&tlv->length));
737 		return -1;
738 	}
739 
740 	/*
741 	 * At this point, tlv_valid() has ensured that the TLV
742 	 * length is large enough but not too large (it doesn't
743 	 * go past the end of the containing TLV).
744 	 */
745 	rlen -= TLV_HDRL;
746 	hex_print_with_offset("\n\t\t\t[", TLV_DATA(tlv), rlen, 0);
747 	return 0;
748 
749 trunc:
750 	fputs("[|forces]", stdout);
751 	return -1;
752 }
753 
754 int
755 redirect_print(register const u_char * pptr, register u_int len,
756 	       u_int16_t op_msk _U_, int indent)
757 {
758 	const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
759 	u_int dlen;
760 	u_int rlen;
761 	int invtlv;
762 
763 	/*
764 	 * forces_type_print() has ensured that len (the TLV length)
765 	 * >= TLV_HDRL.
766 	 */
767 	dlen = len - TLV_HDRL;
768 	if (dlen <= RD_MIN) {
769 		printf("\n\t\ttruncated Redirect TLV: %d bytes missing! ",
770 		       RD_MIN - dlen);
771 		return -1;
772 	}
773 
774 	rlen = dlen;
775 	indent += 1;
776 	while (rlen != 0) {
777 		TCHECK(*tlv);
778 		invtlv = tlv_valid(tlv, rlen);
779 		if (invtlv)
780 			break;
781 
782 		/*
783 		 * At this point, tlv_valid() has ensured that the TLV
784 		 * length is large enough but not too large (it doesn't
785 		 * go past the end of the containing TLV).
786 		 */
787 		if (EXTRACT_16BITS(&tlv->type) == F_TLV_METD) {
788 			print_metatlv((u_char *) TLV_DATA(tlv), rlen, 0, indent);
789 		} else if ((EXTRACT_16BITS(&tlv->type) == F_TLV_REDD)) {
790 			print_reddata((u_char *) TLV_DATA(tlv), rlen, 0, indent);
791 		} else {
792 			printf("Unknown REDIRECT TLV 0x%x len %d\n",
793 			       EXTRACT_16BITS(&tlv->type), EXTRACT_16BITS(&tlv->length));
794 		}
795 
796 		tlv = GO_NXT_TLV(tlv, rlen);
797 	}
798 
799 	if (rlen) {
800 		printf
801 		    ("\n\t\tMessy Redirect TLV header, type (0x%x)\n\t\texcess of %d Bytes ",
802 		     EXTRACT_16BITS(&tlv->type), rlen - EXTRACT_16BITS(&tlv->length));
803 		return -1;
804 	}
805 
806 	return 0;
807 
808 trunc:
809 	fputs("[|forces]", stdout);
810 	return -1;
811 }
812 
813 #define OP_OFF 8
814 #define OP_MIN 12
815 
816 int
817 lfbselect_print(register const u_char * pptr, register u_int len,
818 		u_int16_t op_msk, int indent)
819 {
820 	const struct forces_lfbsh *lfbs;
821 	const struct forces_tlv *otlv;
822 	char *ib = indent_pr(indent, 0);
823 	u_int dlen;
824 	u_int rlen;
825 	int invtlv;
826 
827 	/*
828 	 * forces_type_print() has ensured that len (the TLV length)
829 	 * >= TLV_HDRL.
830 	 */
831 	dlen = len - TLV_HDRL;
832 	if (dlen <= OP_MIN) {	/* id, instance, oper tlv header .. */
833 		printf("\n\t\ttruncated lfb selector: %d bytes missing! ",
834 		       OP_MIN - dlen);
835 		return -1;
836 	}
837 
838 	/*
839 	 * At this point, we know that dlen > OP_MIN; OP_OFF < OP_MIN, so
840 	 * we also know that it's > OP_OFF.
841 	 */
842 	rlen = dlen - OP_OFF;
843 
844 	lfbs = (const struct forces_lfbsh *)pptr;
845 	TCHECK(*lfbs);
846 	if (vflag >= 3) {
847 		printf("\n%s%s(Classid %x) instance %x\n",
848 		       ib, tok2str(ForCES_LFBs, NULL, EXTRACT_32BITS(&lfbs->class)),
849 		       EXTRACT_32BITS(&lfbs->class),
850 		       EXTRACT_32BITS(&lfbs->instance));
851 	}
852 
853 	otlv = (struct forces_tlv *)(lfbs + 1);
854 
855 	indent += 1;
856 	while (rlen != 0) {
857 		TCHECK(*otlv);
858 		invtlv = tlv_valid(otlv, rlen);
859 		if (invtlv)
860 			break;
861 
862 		/*
863 		 * At this point, tlv_valid() has ensured that the TLV
864 		 * length is large enough but not too large (it doesn't
865 		 * go past the end of the containing TLV).
866 		 */
867 		if (op_valid(EXTRACT_16BITS(&otlv->type), op_msk)) {
868 			otlv_print(otlv, 0, indent);
869 		} else {
870 			if (vflag < 3)
871 				printf("\n");
872 			printf
873 			    ("\t\tINValid oper-TLV type 0x%x length %d for this ForCES message\n",
874 			     EXTRACT_16BITS(&otlv->type), EXTRACT_16BITS(&otlv->length));
875 			invoptlv_print((u_char *)otlv, rlen, 0, indent);
876 		}
877 		otlv = GO_NXT_TLV(otlv, rlen);
878 	}
879 
880 	if (rlen) {
881 		printf
882 		    ("\n\t\tMessy oper TLV header, type (0x%x)\n\t\texcess of %d Bytes ",
883 		     EXTRACT_16BITS(&otlv->type), rlen - EXTRACT_16BITS(&otlv->length));
884 		return -1;
885 	}
886 
887 	return 0;
888 
889 trunc:
890 	fputs("[|forces]", stdout);
891 	return -1;
892 }
893 
894 int
895 forces_type_print(register const u_char * pptr, const struct forcesh *fhdr _U_,
896 		  register u_int mlen, const struct tom_h *tops)
897 {
898 	const struct forces_tlv *tltlv;
899 	u_int rlen;
900 	int invtlv;
901 	int rc = 0;
902 	int ttlv = 0;
903 
904 	/*
905 	 * forces_print() has already checked that mlen >= ForCES_HDRL
906 	 * by calling ForCES_HLN_VALID().
907 	 */
908 	rlen = mlen - ForCES_HDRL;
909 
910 	if (rlen > TLV_HLN) {
911 		if (tops->flags & ZERO_TTLV) {
912 			printf("<0x%x>Illegal Top level TLV!\n", tops->flags);
913 			return -1;
914 		}
915 	} else {
916 		if (tops->flags & ZERO_MORE_TTLV)
917 			return 0;
918 		if (tops->flags & ONE_MORE_TTLV) {
919 			printf("\tTop level TLV Data missing!\n");
920 			return -1;
921 		}
922 	}
923 
924 	if (tops->flags & ZERO_TTLV) {
925 		return 0;
926 	}
927 
928 	ttlv = tops->flags >> 4;
929 	tltlv = GET_TOP_TLV(pptr);
930 
931 	/*XXX: 15 top level tlvs will probably be fine
932 	   You are nuts if you send more ;-> */
933 	while (rlen != 0) {
934 		TCHECK(*tltlv);
935 		invtlv = tlv_valid(tltlv, rlen);
936 		if (invtlv)
937 			break;
938 
939 		/*
940 		 * At this point, tlv_valid() has ensured that the TLV
941 		 * length is large enough but not too large (it doesn't
942 		 * go past the end of the packet).
943 		 */
944 		if (!ttlv_valid(EXTRACT_16BITS(&tltlv->type))) {
945 			printf("\n\tInvalid ForCES Top TLV type=0x%x",
946 			       EXTRACT_16BITS(&tltlv->type));
947 			return -1;
948 		}
949 
950 		if (vflag >= 3)
951 			printf("\t%s, length %d (data length %d Bytes)",
952 			       tok2str(ForCES_TLV, NULL, EXTRACT_16BITS(&tltlv->type)),
953 			       EXTRACT_16BITS(&tltlv->length),
954 			       EXTRACT_16BITS(&tltlv->length) - TLV_HDRL);
955 
956 		rc = tops->print((u_char *) TLV_DATA(tltlv),
957 				 EXTRACT_16BITS(&tltlv->length), tops->op_msk, 9);
958 		if (rc < 0) {
959 			return -1;
960 		}
961 		tltlv = GO_NXT_TLV(tltlv, rlen);
962 		ttlv--;
963 		if (ttlv <= 0)
964 			break;
965 	}
966 	/*
967 	 * XXX - if ttlv != 0, does that mean that the packet was too
968 	 * short, and didn't have *enough* TLVs in it?
969 	 */
970 	if (rlen) {
971 		printf("\tMess TopTLV header: min %u, total %d advertised %d ",
972 		       TLV_HDRL, rlen, EXTRACT_16BITS(&tltlv->length));
973 		return -1;
974 	}
975 
976 	return 0;
977 
978 trunc:
979 	fputs("[|forces]", stdout);
980 	return -1;
981 }
982 
983 void forces_print(register const u_char * pptr, register u_int len)
984 {
985 	const struct forcesh *fhdr;
986 	u_int mlen;
987 	u_int32_t flg_raw;
988 	const struct tom_h *tops;
989 	int rc = 0;
990 
991 	fhdr = (const struct forcesh *)pptr;
992 	TCHECK(*fhdr);
993 	if (!tom_valid(fhdr->fm_tom)) {
994 		printf("Invalid ForCES message type %d\n", fhdr->fm_tom);
995 		goto error;
996 	}
997 
998 	mlen = ForCES_BLN(fhdr);
999 
1000 	tops = get_forces_tom(fhdr->fm_tom);
1001 	if (tops->v == TOM_RSVD) {
1002 		printf("\n\tUnknown ForCES message type=0x%x", fhdr->fm_tom);
1003 		goto error;
1004 	}
1005 
1006 	printf("\n\tForCES %s ", tops->s);
1007 	if (!ForCES_HLN_VALID(mlen, len)) {
1008 		printf
1009 		    ("Illegal ForCES pkt len - min %u, total recvd %d, advertised %d ",
1010 		     ForCES_HDRL, len, ForCES_BLN(fhdr));
1011 		goto error;
1012 	}
1013 
1014 	TCHECK2(*(pptr + 20), 4);
1015 	flg_raw = EXTRACT_32BITS(pptr + 20);
1016 	if (vflag >= 1) {
1017 		printf("\n\tForCES Version %d len %uB flags 0x%08x ",
1018 		       ForCES_V(fhdr), mlen, flg_raw);
1019 		printf("\n\tSrcID 0x%x(%s) DstID 0x%x(%s) Correlator 0x%" PRIx64,
1020 		       ForCES_SID(fhdr), ForCES_node(ForCES_SID(fhdr)),
1021 		       ForCES_DID(fhdr), ForCES_node(ForCES_DID(fhdr)),
1022 		       EXTRACT_64BITS(fhdr->fm_cor));
1023 
1024 	}
1025 	if (vflag >= 2) {
1026 		printf
1027 		    ("\n\tForCES flags:\n\t  %s(0x%x), prio=%d, %s(0x%x),\n\t  %s(0x%x), %s(0x%x)\n",
1028 		     ForCES_ACKp(ForCES_ACK(fhdr)), ForCES_ACK(fhdr),
1029 		     ForCES_PRI(fhdr),
1030 		     ForCES_EMp(ForCES_EM(fhdr)), ForCES_EM(fhdr),
1031 		     ForCES_ATp(ForCES_AT(fhdr)), ForCES_AT(fhdr),
1032 		     ForCES_TPp(ForCES_TP(fhdr)), ForCES_TP(fhdr));
1033 		printf
1034 		    ("\t  Extra flags: rsv(b5-7) 0x%x rsv(b13-31) 0x%x\n",
1035 		     ForCES_RS1(fhdr), ForCES_RS2(fhdr));
1036 	}
1037 	rc = forces_type_print(pptr, fhdr, mlen, tops);
1038 	if (rc < 0) {
1039 error:
1040 		hex_print_with_offset("\n\t[", pptr, len, 0);
1041 		printf("\n\t]");
1042 		return;
1043 	}
1044 
1045 	if (vflag >= 4) {
1046 		printf("\n\t  Raw ForCES message\n\t [");
1047 		hex_print_with_offset("\n\t ", pptr, len, 0);
1048 		printf("\n\t ]");
1049 	}
1050 	printf("\n");
1051 	return;
1052 
1053 trunc:
1054 	fputs("[|forces]", stdout);
1055 }
1056