1214456Srpaulo/*
2214456Srpaulo * Redistribution and use in source and binary forms, with or without
3214456Srpaulo * modification, are permitted provided that: (1) source code
4214456Srpaulo * distributions retain the above copyright notice and this paragraph
5214456Srpaulo * in its entirety, and (2) distributions including binary code include
6214456Srpaulo * the above copyright notice and this paragraph in its entirety in
7214456Srpaulo * the documentation or other materials provided with the distribution.
8214456Srpaulo * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
9214456Srpaulo * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
10214456Srpaulo * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
11214456Srpaulo * FOR A PARTICULAR PURPOSE.
12214456Srpaulo *
13214456Srpaulo * Copyright (c) 2009 Mojatatu Networks, Inc
14214456Srpaulo *
15214456Srpaulo */
16214456Srpaulo
17214456Srpaulo#ifdef HAVE_CONFIG_H
18214456Srpaulo#include "config.h"
19214456Srpaulo#endif
20214456Srpaulo
21214456Srpaulo#include <tcpdump-stdinc.h>
22214456Srpaulo
23214456Srpaulo#include <stdio.h>
24214456Srpaulo#include <stdlib.h>
25214456Srpaulo
26214456Srpaulo#include "interface.h"
27214456Srpaulo#include "extract.h"
28214456Srpaulo
29214456Srpaulo#include "forces.h"
30214456Srpaulo
31214456Srpaulo#define RESLEN	4
32214456Srpaulo
33214456Srpauloint
34214456Srpauloprestlv_print(register const u_char * pptr, register u_int len,
35214456Srpaulo	      u_int16_t op_msk _U_, int indent)
36214456Srpaulo{
37214456Srpaulo	const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
38214456Srpaulo	register const u_char *tdp = (u_char *) TLV_DATA(tlv);
39214456Srpaulo	struct res_val *r = (struct res_val *)tdp;
40214456Srpaulo	u_int dlen;
41214456Srpaulo
42214456Srpaulo	/*
43214456Srpaulo	 * pdatacnt_print() has ensured that len (the TLV length)
44214456Srpaulo	 * >= TLV_HDRL.
45214456Srpaulo	 */
46214456Srpaulo	dlen = len - TLV_HDRL;
47214456Srpaulo	if (dlen != RESLEN) {
48214456Srpaulo		printf("illegal RESULT-TLV: %d bytes!\n", dlen);
49214456Srpaulo		return -1;
50214456Srpaulo	}
51214456Srpaulo
52214456Srpaulo	TCHECK(*r);
53214456Srpaulo	if (r->result >= 0x18 && r->result <= 0xFE) {
54214456Srpaulo		printf("illegal reserved result code: 0x%x!\n", r->result);
55214456Srpaulo		return -1;
56214456Srpaulo	}
57214456Srpaulo
58214456Srpaulo	if (vflag >= 3) {
59214456Srpaulo		char *ib = indent_pr(indent, 0);
60214456Srpaulo		printf("%s  Result: %s (code 0x%x)\n", ib,
61214456Srpaulo		       tok2str(ForCES_errs, NULL, r->result), r->result);
62214456Srpaulo	}
63214456Srpaulo	return 0;
64214456Srpaulo
65214456Srpaulotrunc:
66214456Srpaulo	fputs("[|forces]", stdout);
67214456Srpaulo	return -1;
68214456Srpaulo}
69214456Srpaulo
70214456Srpauloint
71214456Srpaulofdatatlv_print(register const u_char * pptr, register u_int len,
72214456Srpaulo	       u_int16_t op_msk _U_, int indent)
73214456Srpaulo{
74214456Srpaulo	const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
75214456Srpaulo	u_int rlen;
76214456Srpaulo	register const u_char *tdp = (u_char *) TLV_DATA(tlv);
77214456Srpaulo	u_int16_t type;
78214456Srpaulo
79214456Srpaulo	/*
80214456Srpaulo	 * pdatacnt_print() or pkeyitlv_print() has ensured that len
81214456Srpaulo	 * (the TLV length) >= TLV_HDRL.
82214456Srpaulo	 */
83214456Srpaulo	rlen = len - TLV_HDRL;
84214456Srpaulo	TCHECK(*tlv);
85214456Srpaulo	type = EXTRACT_16BITS(&tlv->type);
86214456Srpaulo	if (type != F_TLV_FULD) {
87214456Srpaulo		printf("Error: expecting FULLDATA!\n");
88214456Srpaulo		return -1;
89214456Srpaulo	}
90214456Srpaulo
91214456Srpaulo	if (vflag >= 3) {
92214456Srpaulo		char *ib = indent_pr(indent + 2, 1);
93214456Srpaulo		printf("%s[", &ib[1]);
94214456Srpaulo		hex_print_with_offset(ib, tdp, rlen, 0);
95214456Srpaulo		printf("\n%s]\n", &ib[1]);
96214456Srpaulo	}
97214456Srpaulo	return 0;
98214456Srpaulo
99214456Srpaulotrunc:
100214456Srpaulo	fputs("[|forces]", stdout);
101214456Srpaulo	return -1;
102214456Srpaulo}
103214456Srpaulo
104214456Srpauloint
105214456Srpaulosdatailv_print(register const u_char * pptr, register u_int len,
106214456Srpaulo	       u_int16_t op_msk _U_, int indent)
107214456Srpaulo{
108214456Srpaulo	u_int rlen;
109214456Srpaulo	const struct forces_ilv *ilv = (struct forces_ilv *)pptr;
110214456Srpaulo	int invilv;
111214456Srpaulo
112214456Srpaulo	if (len < ILV_HDRL) {
113214456Srpaulo		printf("Error: BAD SPARSEDATA-TLV!\n");
114214456Srpaulo		return -1;
115214456Srpaulo	}
116241235Sdelphij	rlen = len;
117214456Srpaulo	indent += 1;
118214456Srpaulo	while (rlen != 0) {
119241235Sdelphij		char *ib = indent_pr(indent, 1);
120241235Sdelphij		register const u_char *tdp = (u_char *) ILV_DATA(ilv);
121214456Srpaulo		TCHECK(*ilv);
122214456Srpaulo		invilv = ilv_valid(ilv, rlen);
123214456Srpaulo		if (invilv) {
124214456Srpaulo			printf("%s[", &ib[1]);
125214456Srpaulo			hex_print_with_offset(ib, tdp, rlen, 0);
126214456Srpaulo			printf("\n%s]\n", &ib[1]);
127241235Sdelphij			return -1;
128214456Srpaulo		}
129241235Sdelphij		if (vflag >= 3) {
130241235Sdelphij			int ilvl = EXTRACT_32BITS(&ilv->length);
131241235Sdelphij			printf("\n%s ILV: type %x length %d\n", &ib[1],
132241235Sdelphij			       EXTRACT_32BITS(&ilv->type), ilvl);
133241235Sdelphij			hex_print_with_offset("\t\t[", tdp, ilvl-ILV_HDRL, 0);
134241235Sdelphij		}
135214456Srpaulo
136214456Srpaulo		ilv = GO_NXT_ILV(ilv, rlen);
137214456Srpaulo	}
138214456Srpaulo
139214456Srpaulo	return 0;
140214456Srpaulo
141214456Srpaulotrunc:
142214456Srpaulo	fputs("[|forces]", stdout);
143214456Srpaulo	return -1;
144214456Srpaulo}
145214456Srpaulo
146214456Srpauloint
147214456Srpaulosdatatlv_print(register const u_char * pptr, register u_int len,
148214456Srpaulo	       u_int16_t op_msk, int indent)
149214456Srpaulo{
150214456Srpaulo	const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
151214456Srpaulo	u_int rlen;
152214456Srpaulo	register const u_char *tdp = (u_char *) TLV_DATA(tlv);
153214456Srpaulo	u_int16_t type;
154214456Srpaulo
155214456Srpaulo	/*
156214456Srpaulo	 * pdatacnt_print() has ensured that len (the TLV length)
157214456Srpaulo	 * >= TLV_HDRL.
158214456Srpaulo	 */
159214456Srpaulo	rlen = len - TLV_HDRL;
160214456Srpaulo	TCHECK(*tlv);
161214456Srpaulo	type = EXTRACT_16BITS(&tlv->type);
162214456Srpaulo	if (type != F_TLV_SPAD) {
163214456Srpaulo		printf("Error: expecting SPARSEDATA!\n");
164214456Srpaulo		return -1;
165214456Srpaulo	}
166214456Srpaulo
167214456Srpaulo	return sdatailv_print(tdp, rlen, op_msk, indent);
168214456Srpaulo
169214456Srpaulotrunc:
170214456Srpaulo	fputs("[|forces]", stdout);
171214456Srpaulo	return -1;
172214456Srpaulo}
173214456Srpaulo
174214456Srpauloint
175214456Srpaulopkeyitlv_print(register const u_char * pptr, register u_int len,
176214456Srpaulo	       u_int16_t op_msk, int indent)
177214456Srpaulo{
178214456Srpaulo	const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
179214456Srpaulo	register const u_char *tdp = (u_char *) TLV_DATA(tlv);
180214456Srpaulo	register const u_char *dp = tdp + 4;
181214456Srpaulo	const struct forces_tlv *kdtlv = (struct forces_tlv *)dp;
182214456Srpaulo	u_int32_t id;
183214456Srpaulo	char *ib = indent_pr(indent, 0);
184214456Srpaulo	u_int16_t type, tll;
185214456Srpaulo	int invtlv;
186214456Srpaulo
187214456Srpaulo	TCHECK(*tdp);
188214456Srpaulo	id = EXTRACT_32BITS(tdp);
189214456Srpaulo	printf("%sKeyinfo: Key 0x%x\n", ib, id);
190214456Srpaulo	TCHECK(*kdtlv);
191214456Srpaulo	type = EXTRACT_16BITS(&kdtlv->type);
192214456Srpaulo	invtlv = tlv_valid(kdtlv, len);
193214456Srpaulo
194214456Srpaulo	if (invtlv) {
195214456Srpaulo		printf("%s TLV type 0x%x len %d\n",
196214456Srpaulo		       tok2str(ForCES_TLV_err, NULL, invtlv), type,
197214456Srpaulo		       EXTRACT_16BITS(&kdtlv->length));
198214456Srpaulo		return -1;
199214456Srpaulo	}
200214456Srpaulo	/*
201214456Srpaulo	 * At this point, tlv_valid() has ensured that the TLV
202214456Srpaulo	 * length is large enough but not too large (it doesn't
203214456Srpaulo	 * go past the end of the containing TLV).
204214456Srpaulo	 */
205214456Srpaulo	tll = EXTRACT_16BITS(&kdtlv->length);
206214456Srpaulo	dp = (u_char *) TLV_DATA(kdtlv);
207214456Srpaulo	return fdatatlv_print(dp, tll, op_msk, indent);
208214456Srpaulo
209214456Srpaulotrunc:
210214456Srpaulo	fputs("[|forces]", stdout);
211214456Srpaulo	return -1;
212214456Srpaulo}
213214456Srpaulo
214214456Srpauloint
215214456Srpaulopdatacnt_print(register const u_char * pptr, register u_int len,
216235530Sdelphij	       u_int16_t IDcnt, u_int16_t op_msk, int indent)
217214456Srpaulo{
218214456Srpaulo	u_int i;
219214456Srpaulo	u_int32_t id;
220214456Srpaulo	char *ib = indent_pr(indent, 0);
221214456Srpaulo
222214456Srpaulo	for (i = 0; i < IDcnt; i++) {
223214456Srpaulo		TCHECK2(*pptr, 4);
224214456Srpaulo		if (len < 4)
225214456Srpaulo			goto trunc;
226214456Srpaulo		id = EXTRACT_32BITS(pptr);
227214456Srpaulo		if (vflag >= 3)
228214456Srpaulo			printf("%s  ID#%02u: %d\n", ib, i + 1, id);
229214456Srpaulo		len -= 4;
230214456Srpaulo		pptr += 4;
231214456Srpaulo	}
232214456Srpaulo	if (len) {
233214456Srpaulo		const struct forces_tlv *pdtlv = (struct forces_tlv *)pptr;
234214456Srpaulo		u_int16_t type;
235214456Srpaulo		u_int16_t tll;
236214456Srpaulo		int pad = 0;
237214456Srpaulo		u_int aln;
238214456Srpaulo		int invtlv;
239214456Srpaulo
240214456Srpaulo		TCHECK(*pdtlv);
241214456Srpaulo		type = EXTRACT_16BITS(&pdtlv->type);
242214456Srpaulo		invtlv = tlv_valid(pdtlv, len);
243214456Srpaulo		if (invtlv) {
244214456Srpaulo			printf
245214456Srpaulo			    ("%s Outstanding bytes %d for TLV type 0x%x TLV len %d\n",
246214456Srpaulo			     tok2str(ForCES_TLV_err, NULL, invtlv), len, type,
247214456Srpaulo			     EXTRACT_16BITS(&pdtlv->length));
248214456Srpaulo			goto pd_err;
249214456Srpaulo		}
250214456Srpaulo		/*
251214456Srpaulo		 * At this point, tlv_valid() has ensured that the TLV
252214456Srpaulo		 * length is large enough but not too large (it doesn't
253214456Srpaulo		 * go past the end of the containing TLV).
254214456Srpaulo		 */
255214456Srpaulo		tll = EXTRACT_16BITS(&pdtlv->length) - TLV_HDRL;
256214456Srpaulo		aln = F_ALN_LEN(EXTRACT_16BITS(&pdtlv->length));
257214456Srpaulo		if (aln > EXTRACT_16BITS(&pdtlv->length)) {
258214456Srpaulo			if (aln > len) {
259214456Srpaulo				printf
260214456Srpaulo				    ("Invalid padded pathdata TLV type 0x%x len %d missing %d pad bytes\n",
261214456Srpaulo				     type, EXTRACT_16BITS(&pdtlv->length), aln - len);
262214456Srpaulo			} else {
263214456Srpaulo				pad = aln - EXTRACT_16BITS(&pdtlv->length);
264214456Srpaulo			}
265214456Srpaulo		}
266214456Srpaulo		if (pd_valid(type)) {
267214456Srpaulo			const struct pdata_ops *ops = get_forces_pd(type);
268214456Srpaulo
269214456Srpaulo			if (vflag >= 3 && ops->v != F_TLV_PDAT) {
270214456Srpaulo				if (pad)
271214456Srpaulo					printf
272235530Sdelphij					    ("%s  %s (Length %d DataLen %d pad %d Bytes)\n",
273214456Srpaulo					     ib, ops->s, EXTRACT_16BITS(&pdtlv->length),
274214456Srpaulo					     tll, pad);
275214456Srpaulo				else
276214456Srpaulo					printf
277214456Srpaulo					    ("%s  %s (Length %d DataLen %d Bytes)\n",
278214456Srpaulo					     ib, ops->s, EXTRACT_16BITS(&pdtlv->length),
279214456Srpaulo					     tll);
280214456Srpaulo			}
281214456Srpaulo
282214456Srpaulo			chk_op_type(type, op_msk, ops->op_msk);
283214456Srpaulo
284241235Sdelphij			if (ops->print((const u_char *)pdtlv,
285214456Srpaulo					tll + pad + TLV_HDRL, op_msk,
286241235Sdelphij					indent + 2) == -1)
287241235Sdelphij				return -1;
288235530Sdelphij			len -= (TLV_HDRL + pad + tll);
289214456Srpaulo		} else {
290214456Srpaulo			printf("Invalid path data content type 0x%x len %d\n",
291214456Srpaulo			       type, EXTRACT_16BITS(&pdtlv->length));
292214456Srpaulopd_err:
293214456Srpaulo			if (EXTRACT_16BITS(&pdtlv->length)) {
294214456Srpaulo				hex_print_with_offset("Bad Data val\n\t  [",
295214456Srpaulo						      pptr, len, 0);
296214456Srpaulo				printf("]\n");
297214456Srpaulo
298214456Srpaulo				return -1;
299214456Srpaulo			}
300214456Srpaulo		}
301214456Srpaulo	}
302235530Sdelphij	return len;
303214456Srpaulo
304214456Srpaulotrunc:
305214456Srpaulo	fputs("[|forces]", stdout);
306214456Srpaulo	return -1;
307214456Srpaulo}
308214456Srpaulo
309214456Srpauloint
310214456Srpaulopdata_print(register const u_char * pptr, register u_int len,
311214456Srpaulo	    u_int16_t op_msk, int indent)
312214456Srpaulo{
313214456Srpaulo	const struct pathdata_h *pdh = (struct pathdata_h *)pptr;
314214456Srpaulo	char *ib = indent_pr(indent, 0);
315214456Srpaulo	u_int minsize = 0;
316235530Sdelphij	int more_pd = 0;
317235530Sdelphij	u_int16_t idcnt = 0;
318214456Srpaulo
319214456Srpaulo	TCHECK(*pdh);
320214456Srpaulo	if (len < sizeof(struct pathdata_h))
321214456Srpaulo		goto trunc;
322214456Srpaulo	if (vflag >= 3) {
323214456Srpaulo		printf("\n%sPathdata: Flags 0x%x ID count %d\n",
324214456Srpaulo		       ib, EXTRACT_16BITS(&pdh->pflags), EXTRACT_16BITS(&pdh->pIDcnt));
325214456Srpaulo	}
326214456Srpaulo
327214456Srpaulo	if (EXTRACT_16BITS(&pdh->pflags) & F_SELKEY) {
328214456Srpaulo		op_msk |= B_KEYIN;
329214456Srpaulo	}
330214456Srpaulo	pptr += sizeof(struct pathdata_h);
331214456Srpaulo	len -= sizeof(struct pathdata_h);
332235530Sdelphij	idcnt = EXTRACT_16BITS(&pdh->pIDcnt);
333235530Sdelphij	minsize = idcnt * 4;
334214456Srpaulo	if (len < minsize) {
335214456Srpaulo		printf("\t\t\ttruncated IDs expected %uB got %uB\n", minsize,
336214456Srpaulo		       len);
337214456Srpaulo		hex_print_with_offset("\t\t\tID Data[", pptr, len, 0);
338214456Srpaulo		printf("]\n");
339214456Srpaulo		return -1;
340214456Srpaulo	}
341235530Sdelphij	more_pd = pdatacnt_print(pptr, len, idcnt, op_msk, indent);
342235530Sdelphij	if (more_pd > 0) {
343235530Sdelphij		int consumed = len - more_pd;
344235530Sdelphij		pptr += consumed;
345235530Sdelphij		len = more_pd;
346235530Sdelphij		/* XXX: Argh, recurse some more */
347235530Sdelphij		return recpdoptlv_print(pptr, len, op_msk, indent+1);
348235530Sdelphij	} else
349235530Sdelphij		return 0;
350214456Srpaulo
351214456Srpaulotrunc:
352214456Srpaulo	fputs("[|forces]", stdout);
353214456Srpaulo	return -1;
354214456Srpaulo}
355214456Srpaulo
356214456Srpauloint
357214456Srpaulogenoptlv_print(register const u_char * pptr, register u_int len,
358214456Srpaulo	       u_int16_t op_msk, int indent)
359214456Srpaulo{
360214456Srpaulo	const struct forces_tlv *pdtlv = (struct forces_tlv *)pptr;
361214456Srpaulo	u_int16_t type;
362214456Srpaulo	int tll;
363214456Srpaulo	int invtlv;
364214456Srpaulo	char *ib = indent_pr(indent, 0);
365214456Srpaulo
366214456Srpaulo	TCHECK(*pdtlv);
367214456Srpaulo	type = EXTRACT_16BITS(&pdtlv->type);
368214456Srpaulo	tll = EXTRACT_16BITS(&pdtlv->length) - TLV_HDRL;
369214456Srpaulo	invtlv = tlv_valid(pdtlv, len);
370214456Srpaulo	printf("genoptlvprint - %s TLV type 0x%x len %d\n",
371214456Srpaulo	       tok2str(ForCES_TLV, NULL, type), type, EXTRACT_16BITS(&pdtlv->length));
372214456Srpaulo	if (!invtlv) {
373214456Srpaulo		/*
374214456Srpaulo		 * At this point, tlv_valid() has ensured that the TLV
375214456Srpaulo		 * length is large enough but not too large (it doesn't
376214456Srpaulo		 * go past the end of the containing TLV).
377214456Srpaulo		 */
378214456Srpaulo		register const u_char *dp = (u_char *) TLV_DATA(pdtlv);
379214456Srpaulo		if (!ttlv_valid(type)) {
380214456Srpaulo			printf("%s TLV type 0x%x len %d\n",
381214456Srpaulo			       tok2str(ForCES_TLV_err, NULL, invtlv), type,
382214456Srpaulo			       EXTRACT_16BITS(&pdtlv->length));
383214456Srpaulo			return -1;
384214456Srpaulo		}
385214456Srpaulo		if (vflag >= 3)
386214456Srpaulo			printf("%s%s, length %d (data length %d Bytes)",
387214456Srpaulo			       ib, tok2str(ForCES_TLV, NULL, type),
388214456Srpaulo			       EXTRACT_16BITS(&pdtlv->length), tll);
389214456Srpaulo
390214456Srpaulo		return pdata_print(dp, tll, op_msk, indent + 1);
391214456Srpaulo	} else {
392214456Srpaulo		printf("\t\t\tInvalid ForCES TLV type=%x", type);
393214456Srpaulo		return -1;
394214456Srpaulo	}
395214456Srpaulo
396214456Srpaulotrunc:
397214456Srpaulo	fputs("[|forces]", stdout);
398214456Srpaulo	return -1;
399214456Srpaulo}
400214456Srpaulo
401214456Srpauloint
402214456Srpaulorecpdoptlv_print(register const u_char * pptr, register u_int len,
403214456Srpaulo		 u_int16_t op_msk, int indent)
404214456Srpaulo{
405214456Srpaulo	const struct forces_tlv *pdtlv = (struct forces_tlv *)pptr;
406214456Srpaulo	int tll;
407214456Srpaulo	int invtlv;
408214456Srpaulo	u_int16_t type;
409214456Srpaulo	register const u_char *dp;
410214456Srpaulo	char *ib;
411214456Srpaulo
412214456Srpaulo	while (len != 0) {
413214456Srpaulo		TCHECK(*pdtlv);
414214456Srpaulo		invtlv = tlv_valid(pdtlv, len);
415214456Srpaulo		if (invtlv) {
416214456Srpaulo			break;
417214456Srpaulo		}
418214456Srpaulo
419214456Srpaulo		/*
420214456Srpaulo		 * At this point, tlv_valid() has ensured that the TLV
421214456Srpaulo		 * length is large enough but not too large (it doesn't
422214456Srpaulo		 * go past the end of the containing TLV).
423214456Srpaulo		 */
424214456Srpaulo		ib = indent_pr(indent, 0);
425214456Srpaulo		type = EXTRACT_16BITS(&pdtlv->type);
426214456Srpaulo		dp = (u_char *) TLV_DATA(pdtlv);
427214456Srpaulo		tll = EXTRACT_16BITS(&pdtlv->length) - TLV_HDRL;
428214456Srpaulo
429214456Srpaulo		if (vflag >= 3)
430214456Srpaulo			printf
431214456Srpaulo			    ("%s%s, length %d (data encapsulated %d Bytes)",
432214456Srpaulo			     ib, tok2str(ForCES_TLV, NULL, type),
433214456Srpaulo			     EXTRACT_16BITS(&pdtlv->length),
434214456Srpaulo			     EXTRACT_16BITS(&pdtlv->length) - TLV_HDRL);
435214456Srpaulo
436241235Sdelphij		if (pdata_print(dp, tll, op_msk, indent + 1) == -1)
437241235Sdelphij			return -1;
438214456Srpaulo		pdtlv = GO_NXT_TLV(pdtlv, len);
439214456Srpaulo	}
440214456Srpaulo
441214456Srpaulo	if (len) {
442214456Srpaulo		printf
443214456Srpaulo		    ("\n\t\tMessy PATHDATA TLV header, type (0x%x)\n\t\texcess of %d Bytes ",
444214456Srpaulo		     EXTRACT_16BITS(&pdtlv->type), len - EXTRACT_16BITS(&pdtlv->length));
445214456Srpaulo		return -1;
446214456Srpaulo	}
447214456Srpaulo
448214456Srpaulo	return 0;
449214456Srpaulo
450214456Srpaulotrunc:
451214456Srpaulo	fputs("[|forces]", stdout);
452214456Srpaulo	return -1;
453214456Srpaulo}
454214456Srpaulo
455214456Srpauloint
456214456Srpauloinvoptlv_print(register const u_char * pptr, register u_int len,
457214456Srpaulo	       u_int16_t op_msk _U_, int indent)
458214456Srpaulo{
459214456Srpaulo	char *ib = indent_pr(indent, 1);
460214456Srpaulo
461214456Srpaulo	if (vflag >= 3) {
462214456Srpaulo		printf("%sData[", &ib[1]);
463214456Srpaulo		hex_print_with_offset(ib, pptr, len, 0);
464214456Srpaulo		printf("%s]\n", ib);
465214456Srpaulo	}
466214456Srpaulo	return -1;
467214456Srpaulo}
468214456Srpaulo
469214456Srpauloint otlv_print(const struct forces_tlv *otlv, u_int16_t op_msk _U_, int indent)
470214456Srpaulo{
471214456Srpaulo	int rc = 0;
472214456Srpaulo	register const u_char *dp = (u_char *) TLV_DATA(otlv);
473214456Srpaulo	u_int16_t type;
474214456Srpaulo	int tll;
475214456Srpaulo	char *ib = indent_pr(indent, 0);
476214456Srpaulo	const struct optlv_h *ops;
477214456Srpaulo
478214456Srpaulo	/*
479214456Srpaulo	 * lfbselect_print() has ensured that EXTRACT_16BITS(&otlv->length)
480214456Srpaulo	 * >= TLV_HDRL.
481214456Srpaulo	 */
482214456Srpaulo	TCHECK(*otlv);
483214456Srpaulo	type = EXTRACT_16BITS(&otlv->type);
484214456Srpaulo	tll = EXTRACT_16BITS(&otlv->length) - TLV_HDRL;
485214456Srpaulo	ops = get_forces_optlv_h(type);
486214456Srpaulo	if (vflag >= 3) {
487214456Srpaulo		printf("%sOper TLV %s(0x%x) length %d\n", ib, ops->s, type,
488214456Srpaulo		       EXTRACT_16BITS(&otlv->length));
489214456Srpaulo	}
490214456Srpaulo	/* empty TLVs like COMMIT and TRCOMMIT are empty, we stop here .. */
491214456Srpaulo	if (!ops->flags & ZERO_TTLV) {
492214456Srpaulo		if (tll != 0)	/* instead of "if (tll)" - for readability .. */
493214456Srpaulo			printf("%s: Illegal - MUST be empty\n", ops->s);
494214456Srpaulo		return rc;
495214456Srpaulo	}
496214456Srpaulo	/* rest of ops must at least have 12B {pathinfo} */
497214456Srpaulo	if (tll < OP_MIN_SIZ) {
498214456Srpaulo		printf("\t\tOper TLV %s(0x%x) length %d\n", ops->s, type,
499214456Srpaulo		       EXTRACT_16BITS(&otlv->length));
500214456Srpaulo		printf("\t\tTruncated data size %d minimum required %d\n", tll,
501214456Srpaulo		       OP_MIN_SIZ);
502214456Srpaulo		return invoptlv_print(dp, tll, ops->op_msk, indent);
503214456Srpaulo
504214456Srpaulo	}
505214456Srpaulo
506214456Srpaulo	rc = ops->print(dp, tll, ops->op_msk, indent + 1);
507214456Srpaulo	return rc;
508214456Srpaulo
509214456Srpaulotrunc:
510214456Srpaulo	fputs("[|forces]", stdout);
511214456Srpaulo	return -1;
512214456Srpaulo}
513214456Srpaulo
514214456Srpaulo#define ASTDLN	4
515214456Srpaulo#define ASTMCD	255
516214456Srpauloint
517214456Srpauloasttlv_print(register const u_char * pptr, register u_int len,
518214456Srpaulo	     u_int16_t op_msk _U_, int indent)
519214456Srpaulo{
520214456Srpaulo	u_int32_t rescode;
521214456Srpaulo	u_int dlen;
522214456Srpaulo	char *ib = indent_pr(indent, 0);
523214456Srpaulo
524214456Srpaulo	/*
525214456Srpaulo	 * forces_type_print() has ensured that len (the TLV length)
526214456Srpaulo	 * >= TLV_HDRL.
527214456Srpaulo	 */
528214456Srpaulo	dlen = len - TLV_HDRL;
529214456Srpaulo	if (dlen != ASTDLN) {
530214456Srpaulo		printf("illegal ASTresult-TLV: %d bytes!\n", dlen);
531214456Srpaulo		return -1;
532214456Srpaulo	}
533214456Srpaulo	TCHECK2(*pptr, 4);
534214456Srpaulo	rescode = EXTRACT_32BITS(pptr);
535214456Srpaulo	if (rescode > ASTMCD) {
536214456Srpaulo		printf("illegal ASTresult result code: %d!\n", rescode);
537214456Srpaulo		return -1;
538214456Srpaulo	}
539214456Srpaulo
540214456Srpaulo	if (vflag >= 3) {
541214456Srpaulo		printf("Teardown reason:\n%s", ib);
542214456Srpaulo		switch (rescode) {
543214456Srpaulo		case 0:
544214456Srpaulo			printf("Normal Teardown");
545214456Srpaulo			break;
546214456Srpaulo		case 1:
547214456Srpaulo			printf("Loss of Heartbeats");
548214456Srpaulo			break;
549214456Srpaulo		case 2:
550214456Srpaulo			printf("Out of bandwidth");
551214456Srpaulo			break;
552214456Srpaulo		case 3:
553214456Srpaulo			printf("Out of Memory");
554214456Srpaulo			break;
555214456Srpaulo		case 4:
556214456Srpaulo			printf("Application Crash");
557214456Srpaulo			break;
558214456Srpaulo		default:
559214456Srpaulo			printf("Unknown Teardown reason");
560214456Srpaulo			break;
561214456Srpaulo		}
562214456Srpaulo		printf("(%x)\n%s", rescode, ib);
563214456Srpaulo	}
564214456Srpaulo	return 0;
565214456Srpaulo
566214456Srpaulotrunc:
567214456Srpaulo	fputs("[|forces]", stdout);
568214456Srpaulo	return -1;
569214456Srpaulo}
570214456Srpaulo
571214456Srpaulo#define ASRDLN	4
572214456Srpaulo#define ASRMCD	3
573214456Srpauloint
574214456Srpauloasrtlv_print(register const u_char * pptr, register u_int len,
575214456Srpaulo	     u_int16_t op_msk _U_, int indent)
576214456Srpaulo{
577214456Srpaulo	u_int32_t rescode;
578214456Srpaulo	u_int dlen;
579214456Srpaulo	char *ib = indent_pr(indent, 0);
580214456Srpaulo
581214456Srpaulo	/*
582214456Srpaulo	 * forces_type_print() has ensured that len (the TLV length)
583214456Srpaulo	 * >= TLV_HDRL.
584214456Srpaulo	 */
585214456Srpaulo	dlen = len - TLV_HDRL;
586214456Srpaulo	if (dlen != ASRDLN) {	/* id, instance, oper tlv */
587214456Srpaulo		printf("illegal ASRresult-TLV: %d bytes!\n", dlen);
588214456Srpaulo		return -1;
589214456Srpaulo	}
590214456Srpaulo	TCHECK2(*pptr, 4);
591214456Srpaulo	rescode = EXTRACT_32BITS(pptr);
592214456Srpaulo
593214456Srpaulo	if (rescode > ASRMCD) {
594214456Srpaulo		printf("illegal ASRresult result code: %d!\n", rescode);
595214456Srpaulo		return -1;
596214456Srpaulo	}
597214456Srpaulo
598214456Srpaulo	if (vflag >= 3) {
599214456Srpaulo		printf("\n%s", ib);
600214456Srpaulo		switch (rescode) {
601214456Srpaulo		case 0:
602214456Srpaulo			printf("Success ");
603214456Srpaulo			break;
604214456Srpaulo		case 1:
605214456Srpaulo			printf("FE ID invalid ");
606214456Srpaulo			break;
607214456Srpaulo		case 2:
608214456Srpaulo			printf("permission denied ");
609214456Srpaulo			break;
610214456Srpaulo		default:
611214456Srpaulo			printf("Unknown ");
612214456Srpaulo			break;
613214456Srpaulo		}
614214456Srpaulo		printf("(%x)\n%s", rescode, ib);
615214456Srpaulo	}
616214456Srpaulo	return 0;
617214456Srpaulo
618214456Srpaulotrunc:
619214456Srpaulo	fputs("[|forces]", stdout);
620214456Srpaulo	return -1;
621214456Srpaulo}
622214456Srpaulo
623214456Srpaulo/*
624214456Srpaulo * XXX - not used.
625214456Srpaulo */
626214456Srpauloint
627214456Srpaulogentltlv_print(register const u_char * pptr _U_, register u_int len,
628214456Srpaulo	       u_int16_t op_msk _U_, int indent _U_)
629214456Srpaulo{
630214456Srpaulo	u_int dlen = len - TLV_HDRL;
631214456Srpaulo
632214456Srpaulo	if (dlen < 4) {		/* at least 32 bits must exist */
633214456Srpaulo		printf("truncated TLV: %d bytes missing! ", 4 - dlen);
634214456Srpaulo		return -1;
635214456Srpaulo	}
636214456Srpaulo	return 0;
637214456Srpaulo}
638214456Srpaulo
639214456Srpaulo#define RD_MIN 8
640214456Srpauloint
641214456Srpauloprint_metailv(register const u_char * pptr, register u_int len,
642214456Srpaulo	      u_int16_t op_msk _U_, int indent)
643214456Srpaulo{
644214456Srpaulo	u_int dlen;
645214456Srpaulo	u_int rlen;
646214456Srpaulo	char *ib = indent_pr(indent, 0);
647214456Srpaulo	/* XXX: check header length */
648214456Srpaulo	const struct forces_ilv *ilv = (struct forces_ilv *)pptr;
649214456Srpaulo
650214456Srpaulo	/*
651214456Srpaulo	 * print_metatlv() has ensured that len (what remains in the
652214456Srpaulo	 * ILV) >= ILV_HDRL.
653214456Srpaulo	 */
654214456Srpaulo	dlen = len - ILV_HDRL;
655214456Srpaulo	rlen = dlen;
656214456Srpaulo	TCHECK(*ilv);
657214456Srpaulo	printf("\n%sMetaID 0x%x length %d\n", ib, EXTRACT_32BITS(&ilv->type),
658214456Srpaulo	       EXTRACT_32BITS(&ilv->length));
659214456Srpaulo	hex_print_with_offset("\n\t\t\t\t[", ILV_DATA(ilv), rlen, 0);
660214456Srpaulo	return 0;
661214456Srpaulo
662214456Srpaulotrunc:
663214456Srpaulo	fputs("[|forces]", stdout);
664214456Srpaulo	return -1;
665214456Srpaulo}
666214456Srpaulo
667214456Srpauloint
668214456Srpauloprint_metatlv(register const u_char * pptr, register u_int len,
669214456Srpaulo	      u_int16_t op_msk _U_, int indent)
670214456Srpaulo{
671214456Srpaulo	u_int dlen;
672214456Srpaulo	char *ib = indent_pr(indent, 0);
673214456Srpaulo	u_int rlen;
674214456Srpaulo	const struct forces_ilv *ilv = (struct forces_ilv *)pptr;
675214456Srpaulo	int invilv;
676214456Srpaulo
677214456Srpaulo	/*
678214456Srpaulo	 * redirect_print() has ensured that len (what remains in the
679214456Srpaulo	 * TLV) >= TLV_HDRL.
680214456Srpaulo	 */
681214456Srpaulo	dlen = len - TLV_HDRL;
682214456Srpaulo	rlen = dlen;
683214456Srpaulo	printf("\n%s METADATA\n", ib);
684214456Srpaulo	while (rlen != 0) {
685214456Srpaulo		TCHECK(*ilv);
686214456Srpaulo		invilv = ilv_valid(ilv, rlen);
687214456Srpaulo		if (invilv)
688214456Srpaulo			break;
689214456Srpaulo
690214456Srpaulo		/*
691214456Srpaulo		 * At this point, ilv_valid() has ensured that the ILV
692214456Srpaulo		 * length is large enough but not too large (it doesn't
693214456Srpaulo		 * go past the end of the containing TLV).
694214456Srpaulo		 */
695214456Srpaulo		print_metailv((u_char *) ilv, rlen, 0, indent + 1);
696214456Srpaulo
697214456Srpaulo		ilv = GO_NXT_ILV(ilv, rlen);
698214456Srpaulo	}
699214456Srpaulo
700214456Srpaulo	return 0;
701214456Srpaulo
702214456Srpaulotrunc:
703214456Srpaulo	fputs("[|forces]", stdout);
704214456Srpaulo	return -1;
705214456Srpaulo}
706214456Srpaulo
707214456Srpaulo/*
708214456Srpaulo*/
709214456Srpauloint
710214456Srpauloprint_reddata(register const u_char * pptr, register u_int len,
711214456Srpaulo	      u_int16_t op_msk _U_, int indent _U_)
712214456Srpaulo{
713214456Srpaulo	u_int dlen;
714214456Srpaulo	u_int rlen;
715214456Srpaulo	int invtlv;
716214456Srpaulo	const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
717214456Srpaulo
718214456Srpaulo	/*
719214456Srpaulo	 * redirect_print() has ensured that len (what remains in the
720214456Srpaulo	 * TLV) >= TLV_HDRL.
721214456Srpaulo	 */
722214456Srpaulo	dlen = len - TLV_HDRL;
723214456Srpaulo	printf("\n\t\t Redirect DATA\n");
724214456Srpaulo	if (dlen <= RD_MIN) {
725214456Srpaulo		printf("\n\t\ttruncated Redirect data: %d bytes missing! ",
726214456Srpaulo		       RD_MIN - dlen);
727214456Srpaulo		return -1;
728214456Srpaulo	}
729214456Srpaulo
730214456Srpaulo	rlen = dlen;
731214456Srpaulo	TCHECK(*tlv);
732214456Srpaulo	invtlv = tlv_valid(tlv, rlen);
733214456Srpaulo
734214456Srpaulo	if (invtlv) {
735214456Srpaulo		printf("Redir data type 0x%x len %d\n", EXTRACT_16BITS(&tlv->type),
736214456Srpaulo		       EXTRACT_16BITS(&tlv->length));
737214456Srpaulo		return -1;
738214456Srpaulo	}
739214456Srpaulo
740214456Srpaulo	/*
741214456Srpaulo	 * At this point, tlv_valid() has ensured that the TLV
742214456Srpaulo	 * length is large enough but not too large (it doesn't
743214456Srpaulo	 * go past the end of the containing TLV).
744214456Srpaulo	 */
745214456Srpaulo	rlen -= TLV_HDRL;
746214456Srpaulo	hex_print_with_offset("\n\t\t\t[", TLV_DATA(tlv), rlen, 0);
747214456Srpaulo	return 0;
748214456Srpaulo
749214456Srpaulotrunc:
750214456Srpaulo	fputs("[|forces]", stdout);
751214456Srpaulo	return -1;
752214456Srpaulo}
753214456Srpaulo
754214456Srpauloint
755214456Srpauloredirect_print(register const u_char * pptr, register u_int len,
756214456Srpaulo	       u_int16_t op_msk _U_, int indent)
757214456Srpaulo{
758214456Srpaulo	const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
759214456Srpaulo	u_int dlen;
760214456Srpaulo	u_int rlen;
761214456Srpaulo	int invtlv;
762214456Srpaulo
763214456Srpaulo	/*
764214456Srpaulo	 * forces_type_print() has ensured that len (the TLV length)
765214456Srpaulo	 * >= TLV_HDRL.
766214456Srpaulo	 */
767214456Srpaulo	dlen = len - TLV_HDRL;
768214456Srpaulo	if (dlen <= RD_MIN) {
769214456Srpaulo		printf("\n\t\ttruncated Redirect TLV: %d bytes missing! ",
770214456Srpaulo		       RD_MIN - dlen);
771214456Srpaulo		return -1;
772214456Srpaulo	}
773214456Srpaulo
774214456Srpaulo	rlen = dlen;
775214456Srpaulo	indent += 1;
776214456Srpaulo	while (rlen != 0) {
777214456Srpaulo		TCHECK(*tlv);
778214456Srpaulo		invtlv = tlv_valid(tlv, rlen);
779214456Srpaulo		if (invtlv)
780214456Srpaulo			break;
781214456Srpaulo
782214456Srpaulo		/*
783214456Srpaulo		 * At this point, tlv_valid() has ensured that the TLV
784214456Srpaulo		 * length is large enough but not too large (it doesn't
785214456Srpaulo		 * go past the end of the containing TLV).
786214456Srpaulo		 */
787214456Srpaulo		if (EXTRACT_16BITS(&tlv->type) == F_TLV_METD) {
788214456Srpaulo			print_metatlv((u_char *) TLV_DATA(tlv), rlen, 0, indent);
789214456Srpaulo		} else if ((EXTRACT_16BITS(&tlv->type) == F_TLV_REDD)) {
790214456Srpaulo			print_reddata((u_char *) TLV_DATA(tlv), rlen, 0, indent);
791214456Srpaulo		} else {
792214456Srpaulo			printf("Unknown REDIRECT TLV 0x%x len %d\n",
793214456Srpaulo			       EXTRACT_16BITS(&tlv->type), EXTRACT_16BITS(&tlv->length));
794214456Srpaulo		}
795214456Srpaulo
796214456Srpaulo		tlv = GO_NXT_TLV(tlv, rlen);
797214456Srpaulo	}
798214456Srpaulo
799214456Srpaulo	if (rlen) {
800214456Srpaulo		printf
801214456Srpaulo		    ("\n\t\tMessy Redirect TLV header, type (0x%x)\n\t\texcess of %d Bytes ",
802214456Srpaulo		     EXTRACT_16BITS(&tlv->type), rlen - EXTRACT_16BITS(&tlv->length));
803214456Srpaulo		return -1;
804214456Srpaulo	}
805214456Srpaulo
806214456Srpaulo	return 0;
807214456Srpaulo
808214456Srpaulotrunc:
809214456Srpaulo	fputs("[|forces]", stdout);
810214456Srpaulo	return -1;
811214456Srpaulo}
812214456Srpaulo
813214456Srpaulo#define OP_OFF 8
814214456Srpaulo#define OP_MIN 12
815214456Srpaulo
816214456Srpauloint
817214456Srpaulolfbselect_print(register const u_char * pptr, register u_int len,
818214456Srpaulo		u_int16_t op_msk, int indent)
819214456Srpaulo{
820214456Srpaulo	const struct forces_lfbsh *lfbs;
821214456Srpaulo	const struct forces_tlv *otlv;
822214456Srpaulo	char *ib = indent_pr(indent, 0);
823214456Srpaulo	u_int dlen;
824214456Srpaulo	u_int rlen;
825214456Srpaulo	int invtlv;
826214456Srpaulo
827214456Srpaulo	/*
828214456Srpaulo	 * forces_type_print() has ensured that len (the TLV length)
829214456Srpaulo	 * >= TLV_HDRL.
830214456Srpaulo	 */
831214456Srpaulo	dlen = len - TLV_HDRL;
832214456Srpaulo	if (dlen <= OP_MIN) {	/* id, instance, oper tlv header .. */
833214456Srpaulo		printf("\n\t\ttruncated lfb selector: %d bytes missing! ",
834214456Srpaulo		       OP_MIN - dlen);
835214456Srpaulo		return -1;
836214456Srpaulo	}
837214456Srpaulo
838214456Srpaulo	/*
839214456Srpaulo	 * At this point, we know that dlen > OP_MIN; OP_OFF < OP_MIN, so
840214456Srpaulo	 * we also know that it's > OP_OFF.
841214456Srpaulo	 */
842214456Srpaulo	rlen = dlen - OP_OFF;
843214456Srpaulo
844214456Srpaulo	lfbs = (const struct forces_lfbsh *)pptr;
845214456Srpaulo	TCHECK(*lfbs);
846214456Srpaulo	if (vflag >= 3) {
847214456Srpaulo		printf("\n%s%s(Classid %x) instance %x\n",
848214456Srpaulo		       ib, tok2str(ForCES_LFBs, NULL, EXTRACT_32BITS(&lfbs->class)),
849214456Srpaulo		       EXTRACT_32BITS(&lfbs->class),
850214456Srpaulo		       EXTRACT_32BITS(&lfbs->instance));
851214456Srpaulo	}
852214456Srpaulo
853214456Srpaulo	otlv = (struct forces_tlv *)(lfbs + 1);
854214456Srpaulo
855214456Srpaulo	indent += 1;
856214456Srpaulo	while (rlen != 0) {
857214456Srpaulo		TCHECK(*otlv);
858214456Srpaulo		invtlv = tlv_valid(otlv, rlen);
859214456Srpaulo		if (invtlv)
860214456Srpaulo			break;
861214456Srpaulo
862214456Srpaulo		/*
863214456Srpaulo		 * At this point, tlv_valid() has ensured that the TLV
864214456Srpaulo		 * length is large enough but not too large (it doesn't
865214456Srpaulo		 * go past the end of the containing TLV).
866214456Srpaulo		 */
867214456Srpaulo		if (op_valid(EXTRACT_16BITS(&otlv->type), op_msk)) {
868214456Srpaulo			otlv_print(otlv, 0, indent);
869214456Srpaulo		} else {
870214456Srpaulo			if (vflag < 3)
871214456Srpaulo				printf("\n");
872214456Srpaulo			printf
873214456Srpaulo			    ("\t\tINValid oper-TLV type 0x%x length %d for this ForCES message\n",
874214456Srpaulo			     EXTRACT_16BITS(&otlv->type), EXTRACT_16BITS(&otlv->length));
875214456Srpaulo			invoptlv_print((u_char *)otlv, rlen, 0, indent);
876214456Srpaulo		}
877214456Srpaulo		otlv = GO_NXT_TLV(otlv, rlen);
878214456Srpaulo	}
879214456Srpaulo
880214456Srpaulo	if (rlen) {
881214456Srpaulo		printf
882214456Srpaulo		    ("\n\t\tMessy oper TLV header, type (0x%x)\n\t\texcess of %d Bytes ",
883214456Srpaulo		     EXTRACT_16BITS(&otlv->type), rlen - EXTRACT_16BITS(&otlv->length));
884214456Srpaulo		return -1;
885214456Srpaulo	}
886214456Srpaulo
887214456Srpaulo	return 0;
888214456Srpaulo
889214456Srpaulotrunc:
890214456Srpaulo	fputs("[|forces]", stdout);
891214456Srpaulo	return -1;
892214456Srpaulo}
893214456Srpaulo
894214456Srpauloint
895214456Srpauloforces_type_print(register const u_char * pptr, const struct forcesh *fhdr _U_,
896214456Srpaulo		  register u_int mlen, const struct tom_h *tops)
897214456Srpaulo{
898214456Srpaulo	const struct forces_tlv *tltlv;
899214456Srpaulo	u_int rlen;
900214456Srpaulo	int invtlv;
901214456Srpaulo	int rc = 0;
902214456Srpaulo	int ttlv = 0;
903214456Srpaulo
904214456Srpaulo	/*
905214456Srpaulo	 * forces_print() has already checked that mlen >= ForCES_HDRL
906214456Srpaulo	 * by calling ForCES_HLN_VALID().
907214456Srpaulo	 */
908214456Srpaulo	rlen = mlen - ForCES_HDRL;
909214456Srpaulo
910214456Srpaulo	if (rlen > TLV_HLN) {
911214456Srpaulo		if (tops->flags & ZERO_TTLV) {
912214456Srpaulo			printf("<0x%x>Illegal Top level TLV!\n", tops->flags);
913214456Srpaulo			return -1;
914214456Srpaulo		}
915214456Srpaulo	} else {
916214456Srpaulo		if (tops->flags & ZERO_MORE_TTLV)
917214456Srpaulo			return 0;
918214456Srpaulo		if (tops->flags & ONE_MORE_TTLV) {
919214456Srpaulo			printf("\tTop level TLV Data missing!\n");
920214456Srpaulo			return -1;
921214456Srpaulo		}
922214456Srpaulo	}
923214456Srpaulo
924214456Srpaulo	if (tops->flags & ZERO_TTLV) {
925214456Srpaulo		return 0;
926214456Srpaulo	}
927214456Srpaulo
928214456Srpaulo	ttlv = tops->flags >> 4;
929214456Srpaulo	tltlv = GET_TOP_TLV(pptr);
930214456Srpaulo
931214456Srpaulo	/*XXX: 15 top level tlvs will probably be fine
932214456Srpaulo	   You are nuts if you send more ;-> */
933214456Srpaulo	while (rlen != 0) {
934214456Srpaulo		TCHECK(*tltlv);
935214456Srpaulo		invtlv = tlv_valid(tltlv, rlen);
936214456Srpaulo		if (invtlv)
937214456Srpaulo			break;
938214456Srpaulo
939214456Srpaulo		/*
940214456Srpaulo		 * At this point, tlv_valid() has ensured that the TLV
941214456Srpaulo		 * length is large enough but not too large (it doesn't
942214456Srpaulo		 * go past the end of the packet).
943214456Srpaulo		 */
944214456Srpaulo		if (!ttlv_valid(EXTRACT_16BITS(&tltlv->type))) {
945214456Srpaulo			printf("\n\tInvalid ForCES Top TLV type=0x%x",
946214456Srpaulo			       EXTRACT_16BITS(&tltlv->type));
947214456Srpaulo			return -1;
948214456Srpaulo		}
949214456Srpaulo
950214456Srpaulo		if (vflag >= 3)
951214456Srpaulo			printf("\t%s, length %d (data length %d Bytes)",
952214456Srpaulo			       tok2str(ForCES_TLV, NULL, EXTRACT_16BITS(&tltlv->type)),
953214456Srpaulo			       EXTRACT_16BITS(&tltlv->length),
954214456Srpaulo			       EXTRACT_16BITS(&tltlv->length) - TLV_HDRL);
955214456Srpaulo
956214456Srpaulo		rc = tops->print((u_char *) TLV_DATA(tltlv),
957214456Srpaulo				 EXTRACT_16BITS(&tltlv->length), tops->op_msk, 9);
958214456Srpaulo		if (rc < 0) {
959214456Srpaulo			return -1;
960214456Srpaulo		}
961214456Srpaulo		tltlv = GO_NXT_TLV(tltlv, rlen);
962214456Srpaulo		ttlv--;
963214456Srpaulo		if (ttlv <= 0)
964214456Srpaulo			break;
965214456Srpaulo	}
966214456Srpaulo	/*
967214456Srpaulo	 * XXX - if ttlv != 0, does that mean that the packet was too
968214456Srpaulo	 * short, and didn't have *enough* TLVs in it?
969214456Srpaulo	 */
970214456Srpaulo	if (rlen) {
971214456Srpaulo		printf("\tMess TopTLV header: min %u, total %d advertised %d ",
972214456Srpaulo		       TLV_HDRL, rlen, EXTRACT_16BITS(&tltlv->length));
973214456Srpaulo		return -1;
974214456Srpaulo	}
975214456Srpaulo
976214456Srpaulo	return 0;
977214456Srpaulo
978214456Srpaulotrunc:
979214456Srpaulo	fputs("[|forces]", stdout);
980214456Srpaulo	return -1;
981214456Srpaulo}
982214456Srpaulo
983214456Srpaulovoid forces_print(register const u_char * pptr, register u_int len)
984214456Srpaulo{
985214456Srpaulo	const struct forcesh *fhdr;
986214456Srpaulo	u_int mlen;
987214456Srpaulo	u_int32_t flg_raw;
988214456Srpaulo	const struct tom_h *tops;
989214456Srpaulo	int rc = 0;
990214456Srpaulo
991214456Srpaulo	fhdr = (const struct forcesh *)pptr;
992214456Srpaulo	TCHECK(*fhdr);
993214456Srpaulo	if (!tom_valid(fhdr->fm_tom)) {
994214456Srpaulo		printf("Invalid ForCES message type %d\n", fhdr->fm_tom);
995214456Srpaulo		goto error;
996214456Srpaulo	}
997214456Srpaulo
998214456Srpaulo	mlen = ForCES_BLN(fhdr);
999214456Srpaulo
1000214456Srpaulo	tops = get_forces_tom(fhdr->fm_tom);
1001214456Srpaulo	if (tops->v == TOM_RSVD) {
1002214456Srpaulo		printf("\n\tUnknown ForCES message type=0x%x", fhdr->fm_tom);
1003214456Srpaulo		goto error;
1004214456Srpaulo	}
1005214456Srpaulo
1006214456Srpaulo	printf("\n\tForCES %s ", tops->s);
1007214456Srpaulo	if (!ForCES_HLN_VALID(mlen, len)) {
1008214456Srpaulo		printf
1009214456Srpaulo		    ("Illegal ForCES pkt len - min %u, total recvd %d, advertised %d ",
1010214456Srpaulo		     ForCES_HDRL, len, ForCES_BLN(fhdr));
1011214456Srpaulo		goto error;
1012214456Srpaulo	}
1013214456Srpaulo
1014214456Srpaulo	TCHECK2(*(pptr + 20), 4);
1015214456Srpaulo	flg_raw = EXTRACT_32BITS(pptr + 20);
1016214456Srpaulo	if (vflag >= 1) {
1017214456Srpaulo		printf("\n\tForCES Version %d len %uB flags 0x%08x ",
1018214456Srpaulo		       ForCES_V(fhdr), mlen, flg_raw);
1019241235Sdelphij		printf("\n\tSrcID 0x%x(%s) DstID 0x%x(%s) Correlator 0x%" PRIx64,
1020214456Srpaulo		       ForCES_SID(fhdr), ForCES_node(ForCES_SID(fhdr)),
1021214456Srpaulo		       ForCES_DID(fhdr), ForCES_node(ForCES_DID(fhdr)),
1022214456Srpaulo		       EXTRACT_64BITS(fhdr->fm_cor));
1023214456Srpaulo
1024214456Srpaulo	}
1025214456Srpaulo	if (vflag >= 2) {
1026214456Srpaulo		printf
1027214456Srpaulo		    ("\n\tForCES flags:\n\t  %s(0x%x), prio=%d, %s(0x%x),\n\t  %s(0x%x), %s(0x%x)\n",
1028214456Srpaulo		     ForCES_ACKp(ForCES_ACK(fhdr)), ForCES_ACK(fhdr),
1029214456Srpaulo		     ForCES_PRI(fhdr),
1030214456Srpaulo		     ForCES_EMp(ForCES_EM(fhdr)), ForCES_EM(fhdr),
1031214456Srpaulo		     ForCES_ATp(ForCES_AT(fhdr)), ForCES_AT(fhdr),
1032214456Srpaulo		     ForCES_TPp(ForCES_TP(fhdr)), ForCES_TP(fhdr));
1033214456Srpaulo		printf
1034214456Srpaulo		    ("\t  Extra flags: rsv(b5-7) 0x%x rsv(b13-31) 0x%x\n",
1035214456Srpaulo		     ForCES_RS1(fhdr), ForCES_RS2(fhdr));
1036214456Srpaulo	}
1037214456Srpaulo	rc = forces_type_print(pptr, fhdr, mlen, tops);
1038214456Srpaulo	if (rc < 0) {
1039214456Srpauloerror:
1040214456Srpaulo		hex_print_with_offset("\n\t[", pptr, len, 0);
1041214456Srpaulo		printf("\n\t]");
1042214456Srpaulo		return;
1043214456Srpaulo	}
1044214456Srpaulo
1045214456Srpaulo	if (vflag >= 4) {
1046214456Srpaulo		printf("\n\t  Raw ForCES message\n\t [");
1047214456Srpaulo		hex_print_with_offset("\n\t ", pptr, len, 0);
1048214456Srpaulo		printf("\n\t ]");
1049214456Srpaulo	}
1050214456Srpaulo	printf("\n");
1051214456Srpaulo	return;
1052214456Srpaulo
1053214456Srpaulotrunc:
1054214456Srpaulo	fputs("[|forces]", stdout);
1055214456Srpaulo}
1056