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
33int
34prestlv_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
65trunc:
66	fputs("[|forces]", stdout);
67	return -1;
68}
69
70int
71fdatatlv_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
99trunc:
100	fputs("[|forces]", stdout);
101	return -1;
102}
103
104int
105sdatailv_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
141trunc:
142	fputs("[|forces]", stdout);
143	return -1;
144}
145
146int
147sdatatlv_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
169trunc:
170	fputs("[|forces]", stdout);
171	return -1;
172}
173
174int
175pkeyitlv_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
209trunc:
210	fputs("[|forces]", stdout);
211	return -1;
212}
213
214int
215pdatacnt_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));
292pd_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
304trunc:
305	fputs("[|forces]", stdout);
306	return -1;
307}
308
309int
310pdata_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
351trunc:
352	fputs("[|forces]", stdout);
353	return -1;
354}
355
356int
357genoptlv_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
396trunc:
397	fputs("[|forces]", stdout);
398	return -1;
399}
400
401int
402recpdoptlv_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
450trunc:
451	fputs("[|forces]", stdout);
452	return -1;
453}
454
455int
456invoptlv_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
469int 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
509trunc:
510	fputs("[|forces]", stdout);
511	return -1;
512}
513
514#define ASTDLN	4
515#define ASTMCD	255
516int
517asttlv_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
566trunc:
567	fputs("[|forces]", stdout);
568	return -1;
569}
570
571#define ASRDLN	4
572#define ASRMCD	3
573int
574asrtlv_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
618trunc:
619	fputs("[|forces]", stdout);
620	return -1;
621}
622
623/*
624 * XXX - not used.
625 */
626int
627gentltlv_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
640int
641print_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
662trunc:
663	fputs("[|forces]", stdout);
664	return -1;
665}
666
667int
668print_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
702trunc:
703	fputs("[|forces]", stdout);
704	return -1;
705}
706
707/*
708*/
709int
710print_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
749trunc:
750	fputs("[|forces]", stdout);
751	return -1;
752}
753
754int
755redirect_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
808trunc:
809	fputs("[|forces]", stdout);
810	return -1;
811}
812
813#define OP_OFF 8
814#define OP_MIN 12
815
816int
817lfbselect_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
889trunc:
890	fputs("[|forces]", stdout);
891	return -1;
892}
893
894int
895forces_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
978trunc:
979	fputs("[|forces]", stdout);
980	return -1;
981}
982
983void 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) {
1039error:
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
1053trunc:
1054	fputs("[|forces]", stdout);
1055}
1056