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