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