"Fossies" - the Fresh Open Source Software Archive

Member "tcpdump-4.99.1/./print-forces.c" (7 Jun 2021, 42507 Bytes) of package /linux/misc/tcpdump-4.99.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "print-forces.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.99.0_vs_4.99.1.

    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 /* \summary: Forwarding and Control Element Separation (ForCES) Protocol printer */
   18 
   19 /* specification: RFC 5810 */
   20 
   21 #ifdef HAVE_CONFIG_H
   22 #include <config.h>
   23 #endif
   24 
   25 #include "netdissect-stdinc.h"
   26 
   27 #include "netdissect.h"
   28 #include "extract.h"
   29 
   30 
   31 #define ForCES_VERS 1
   32 #define ForCES_HDRL 24
   33 #define ForCES_ALNL 4U
   34 #define TLV_HDRL    4
   35 #define ILV_HDRL    8
   36 
   37 #define TOM_RSVD    0x0
   38 #define TOM_ASSNSETUP   0x1
   39 #define TOM_ASSNTEARD   0x2
   40 #define TOM_CONFIG  0x3
   41 #define TOM_QUERY   0x4
   42 #define TOM_EVENTNOT    0x5
   43 #define TOM_PKTREDIR    0x6
   44 #define TOM_HEARTBT     0x0F
   45 #define TOM_ASSNSETREP  0x11
   46 #define TOM_CONFIGREP   0x13
   47 #define TOM_QUERYREP    0x14
   48 
   49 /*
   50  * tom_h Flags: resv1(8b):maxtlvs(4b):resv2(2b):mintlv(2b)
   51 */
   52 #define ZERO_TTLV   0x01
   53 #define ZERO_MORE_TTLV  0x02
   54 #define ONE_MORE_TTLV   0x04
   55 #define ZERO_TLV    0x00
   56 #define ONE_TLV     0x10
   57 #define TWO_TLV     0x20
   58 #define MAX_TLV     0xF0
   59 
   60 #define TTLV_T1     (ONE_MORE_TTLV|ONE_TLV)
   61 #define TTLV_T2     (ONE_MORE_TTLV|MAX_TLV)
   62 
   63 struct tom_h {
   64     uint32_t v;
   65     uint16_t flags;
   66     uint16_t op_msk;
   67     const char *s;
   68     int (*print) (netdissect_options *ndo, const u_char * pptr, u_int len,
   69               uint16_t op_msk, int indent);
   70 };
   71 
   72 enum {
   73     TOM_RSV_I,
   74     TOM_ASS_I,
   75     TOM_AST_I,
   76     TOM_CFG_I,
   77     TOM_QRY_I,
   78     TOM_EVN_I,
   79     TOM_RED_I,
   80     TOM_HBT_I,
   81     TOM_ASR_I,
   82     TOM_CNR_I,
   83     TOM_QRR_I,
   84     _TOM_RSV_MAX
   85 };
   86 #define TOM_MAX_IND (_TOM_RSV_MAX - 1)
   87 
   88 static int
   89 tom_valid(uint8_t tom)
   90 {
   91     if (tom > 0) {
   92         if (tom >= 0x7 && tom <= 0xe)
   93             return 0;
   94         if (tom == 0x10)
   95             return 0;
   96         if (tom > 0x14)
   97             return 0;
   98         return 1;
   99     } else
  100         return 0;
  101 }
  102 
  103 static const char *
  104 ForCES_node(uint32_t node)
  105 {
  106     if (node <= 0x3FFFFFFF)
  107         return "FE";
  108     if (node >= 0x40000000 && node <= 0x7FFFFFFF)
  109         return "CE";
  110     if (node >= 0xC0000000 && node <= 0xFFFFFFEF)
  111         return "AllMulticast";
  112     if (node == 0xFFFFFFFD)
  113         return "AllCEsBroadcast";
  114     if (node == 0xFFFFFFFE)
  115         return "AllFEsBroadcast";
  116     if (node == 0xFFFFFFFF)
  117         return "AllBroadcast";
  118 
  119     return "ForCESreserved";
  120 
  121 }
  122 
  123 static const struct tok ForCES_ACKs[] = {
  124     {0x0, "NoACK"},
  125     {0x1, "SuccessACK"},
  126     {0x2, "FailureACK"},
  127     {0x3, "AlwaysACK"},
  128     {0, NULL}
  129 };
  130 
  131 static const struct tok ForCES_EMs[] = {
  132     {0x0, "EMReserved"},
  133     {0x1, "execute-all-or-none"},
  134     {0x2, "execute-until-failure"},
  135     {0x3, "continue-execute-on-failure"},
  136     {0, NULL}
  137 };
  138 
  139 static const struct tok ForCES_ATs[] = {
  140     {0x0, "Standalone"},
  141     {0x1, "2PCtransaction"},
  142     {0, NULL}
  143 };
  144 
  145 static const struct tok ForCES_TPs[] = {
  146     {0x0, "StartofTransaction"},
  147     {0x1, "MiddleofTransaction"},
  148     {0x2, "EndofTransaction"},
  149     {0x3, "abort"},
  150     {0, NULL}
  151 };
  152 
  153 /*
  154  * Structure of forces header, naked of TLVs.
  155  */
  156 struct forcesh {
  157     nd_uint8_t fm_vrsvd;    /* version and reserved */
  158 #define ForCES_V(forcesh)   (GET_U_1((forcesh)->fm_vrsvd) >> 4)
  159     nd_uint8_t fm_tom;  /* type of message */
  160     nd_uint16_t fm_len; /* total length * 4 bytes */
  161 #define ForCES_BLN(forcesh) ((uint32_t)(GET_BE_U_2((forcesh)->fm_len) << 2))
  162     nd_uint32_t fm_sid; /* Source ID */
  163 #define ForCES_SID(forcesh) GET_BE_U_4((forcesh)->fm_sid)
  164     nd_uint32_t fm_did; /* Destination ID */
  165 #define ForCES_DID(forcesh) GET_BE_U_4((forcesh)->fm_did)
  166     nd_uint8_t fm_cor[8];   /* correlator */
  167     nd_uint32_t fm_flags;   /* flags */
  168 #define ForCES_ACK(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0xC0000000) >> 30)
  169 #define ForCES_PRI(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x38000000) >> 27)
  170 #define ForCES_RS1(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x07000000) >> 24)
  171 #define ForCES_EM(forcesh)  ((GET_BE_U_4((forcesh)->fm_flags)&0x00C00000) >> 22)
  172 #define ForCES_AT(forcesh)  ((GET_BE_U_4((forcesh)->fm_flags)&0x00200000) >> 21)
  173 #define ForCES_TP(forcesh)  ((GET_BE_U_4((forcesh)->fm_flags)&0x00180000) >> 19)
  174 #define ForCES_RS2(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x0007FFFF) >> 0)
  175 };
  176 
  177 #define ForCES_HLN_VALID(fhl,tlen) ((tlen) >= ForCES_HDRL && \
  178                    (fhl) >= ForCES_HDRL && \
  179                    (fhl) == (tlen))
  180 
  181 #define F_LFB_RSVD 0x0
  182 #define F_LFB_FEO 0x1
  183 #define F_LFB_FEPO 0x2
  184 static const struct tok ForCES_LFBs[] = {
  185     {F_LFB_RSVD, "Invalid TLV"},
  186     {F_LFB_FEO, "FEObj LFB"},
  187     {F_LFB_FEPO, "FEProtoObj LFB"},
  188     {0, NULL}
  189 };
  190 
  191 /* this is defined in RFC5810 section A.2 */
  192 /*   https://www.iana.org/assignments/forces/forces.xhtml#oper-tlv-types */
  193 enum {
  194     F_OP_RSV        = 0,
  195     F_OP_SET        = 1,
  196     F_OP_SETPROP    = 2,
  197     F_OP_SETRESP    = 3,
  198     F_OP_SETPRESP   = 4,
  199     F_OP_DEL        = 5,
  200     F_OP_DELRESP    = 6,
  201     F_OP_GET        = 7,
  202     F_OP_GETPROP    = 8,
  203     F_OP_GETRESP    = 9,
  204     F_OP_GETPRESP   = 10,
  205     F_OP_REPORT     = 11,
  206     F_OP_COMMIT     = 12,
  207     F_OP_RCOMMIT    = 13,
  208     F_OP_RTRCOMP    = 14,
  209     _F_OP_MAX
  210 };
  211 #define F_OP_MAX    (_F_OP_MAX - 1)
  212 
  213 enum {
  214     B_OP_SET = 1 << (F_OP_SET - 1),
  215     B_OP_SETPROP = 1 << (F_OP_SETPROP - 1),
  216     B_OP_SETRESP = 1 << (F_OP_SETRESP - 1),
  217     B_OP_SETPRESP = 1 << (F_OP_SETPRESP - 1),
  218     B_OP_DEL = 1 << (F_OP_DEL - 1),
  219     B_OP_DELRESP = 1 << (F_OP_DELRESP - 1),
  220     B_OP_GET = 1 << (F_OP_GET - 1),
  221     B_OP_GETPROP = 1 << (F_OP_GETPROP - 1),
  222     B_OP_GETRESP = 1 << (F_OP_GETRESP - 1),
  223     B_OP_GETPRESP = 1 << (F_OP_GETPRESP - 1),
  224     B_OP_REPORT = 1 << (F_OP_REPORT - 1),
  225     B_OP_COMMIT = 1 << (F_OP_COMMIT - 1),
  226     B_OP_RCOMMIT = 1 << (F_OP_RCOMMIT - 1),
  227     B_OP_RTRCOMP = 1 << (F_OP_RTRCOMP - 1)
  228 };
  229 
  230 struct optlv_h {
  231     uint16_t flags;
  232     uint16_t op_msk;
  233     const char *s;
  234     int (*print) (netdissect_options *ndo, const u_char * pptr, u_int len,
  235               uint16_t op_msk, int indent);
  236 };
  237 
  238 static int genoptlv_print(netdissect_options *, const u_char * pptr, u_int len,
  239              uint16_t op_msk, int indent);
  240 static int recpdoptlv_print(netdissect_options *, const u_char * pptr, u_int len,
  241                 uint16_t op_msk, int indent);
  242 static int invoptlv_print(netdissect_options *, const u_char * pptr, u_int len,
  243               uint16_t op_msk, int indent);
  244 
  245 #define OP_MIN_SIZ 8
  246 struct pathdata_h {
  247     nd_uint16_t pflags;
  248     nd_uint16_t pIDcnt;
  249 };
  250 
  251 #define B_FULLD     0x1
  252 #define B_SPARD     0x2
  253 #define B_RESTV     0x4
  254 #define B_KEYIN     0x8
  255 #define B_APPND     0x10
  256 #define B_TRNG      0x20
  257 
  258 static const struct optlv_h OPTLV_msg[F_OP_MAX + 1] = {
  259     /* F_OP_RSV */ {ZERO_TTLV, 0, "Invalid OPTLV", invoptlv_print},
  260     /* F_OP_SET */ {TTLV_T2, B_FULLD | B_SPARD, " Set", recpdoptlv_print},
  261     /* F_OP_SETPROP */
  262         {TTLV_T2, B_FULLD | B_SPARD, " SetProp", recpdoptlv_print},
  263     /* F_OP_SETRESP */ {TTLV_T2, B_RESTV, " SetResp", recpdoptlv_print},
  264     /* F_OP_SETPRESP */ {TTLV_T2, B_RESTV, " SetPropResp", recpdoptlv_print},
  265     /* F_OP_DEL */ {ZERO_TTLV, 0, " Del", recpdoptlv_print},
  266     /* F_OP_DELRESP */ {TTLV_T2, B_RESTV, " DelResp", recpdoptlv_print},
  267     /* F_OP_GET */ {ZERO_TTLV, 0, " Get", recpdoptlv_print},
  268     /* F_OP_GETPROP */ {ZERO_TTLV, 0, " GetProp", recpdoptlv_print},
  269     /* F_OP_GETRESP */
  270         {TTLV_T2, B_FULLD | B_SPARD | B_RESTV, " GetResp", recpdoptlv_print},
  271     /* F_OP_GETPRESP */
  272         {TTLV_T2, B_FULLD | B_RESTV, " GetPropResp", recpdoptlv_print},
  273     /* F_OP_REPORT */
  274         {TTLV_T2, B_FULLD | B_SPARD, " Report", recpdoptlv_print},
  275     /* F_OP_COMMIT */ {ZERO_TTLV, 0, " Commit", NULL},
  276     /* F_OP_RCOMMIT */ {TTLV_T1, B_RESTV, " RCommit", genoptlv_print},
  277     /* F_OP_RTRCOMP */ {ZERO_TTLV, 0, " RTRCOMP", NULL},
  278 };
  279 
  280 static const struct optlv_h *
  281 get_forces_optlv_h(uint16_t opt)
  282 {
  283     if (opt > F_OP_MAX || opt == F_OP_RSV)
  284         return &OPTLV_msg[F_OP_RSV];
  285 
  286     return &OPTLV_msg[opt];
  287 }
  288 
  289 #define IND_SIZE 256
  290 #define IND_CHR ' '
  291 #define IND_PREF '\n'
  292 #define IND_SUF 0x0
  293 static char ind_buf[IND_SIZE];
  294 
  295 static char *
  296 indent_pr(int indent, int nlpref)
  297 {
  298     int i = 0;
  299     char *r = ind_buf;
  300 
  301     if (indent > (IND_SIZE - 1))
  302         indent = IND_SIZE - 1;
  303 
  304     if (nlpref) {
  305         r[i] = IND_PREF;
  306         i++;
  307         indent--;
  308     }
  309 
  310     while (--indent >= 0)
  311         r[i++] = IND_CHR;
  312 
  313     r[i] = IND_SUF;
  314     return r;
  315 }
  316 
  317 static int
  318 op_valid(uint16_t op, uint16_t mask)
  319 {
  320     if (op == 0)
  321         return 0;
  322     if (op <= F_OP_MAX)
  323         return (1 << (op - 1)) & mask; /* works only for 0x0001 through 0x0010 */
  324     /* I guess we should allow vendor operations? */
  325     if (op >= 0x8000)
  326         return 1;
  327     return 0;
  328 }
  329 
  330 #define F_TLV_RSVD  0x0000
  331 #define F_TLV_REDR  0x0001
  332 #define F_TLV_ASRS  0x0010
  333 #define F_TLV_ASRT  0x0011
  334 #define F_TLV_LFBS  0x1000
  335 #define F_TLV_PDAT  0x0110
  336 #define F_TLV_KEYI  0x0111
  337 #define F_TLV_FULD  0x0112
  338 #define F_TLV_SPAD  0x0113
  339 #define F_TLV_REST  0x0114
  340 #define F_TLV_METD  0x0115
  341 #define F_TLV_REDD  0x0116
  342 #define F_TLV_TRNG  0x0117
  343 
  344 
  345 #define F_TLV_VNST  0x8000
  346 
  347 static const struct tok ForCES_TLV[] = {
  348     {F_TLV_RSVD, "Invalid TLV"},
  349     {F_TLV_REDR, "REDIRECT TLV"},
  350     {F_TLV_ASRS, "ASResult TLV"},
  351     {F_TLV_ASRT, "ASTreason TLV"},
  352     {F_TLV_LFBS, "LFBselect TLV"},
  353     {F_TLV_PDAT, "PATH-DATA TLV"},
  354     {F_TLV_KEYI, "KEYINFO TLV"},
  355     {F_TLV_FULD, "FULLDATA TLV"},
  356     {F_TLV_SPAD, "SPARSEDATA TLV"},
  357     {F_TLV_REST, "RESULT TLV"},
  358     {F_TLV_METD, "METADATA TLV"},
  359     {F_TLV_REDD, "REDIRECTDATA TLV"},
  360     {0, NULL}
  361 };
  362 
  363 #define TLV_HLN 4
  364 static int
  365 ttlv_valid(uint16_t ttlv)
  366 {
  367     if (ttlv > 0) {
  368         if (ttlv == 1 || ttlv == 0x1000)
  369             return 1;
  370         if (ttlv >= 0x10 && ttlv <= 0x11)
  371             return 1;
  372         if (ttlv >= 0x110 && ttlv <= 0x116)
  373             return 1;
  374         if (ttlv >= 0x8000)
  375             return 0;   /* XXX: */
  376     }
  377 
  378     return 0;
  379 }
  380 
  381 struct forces_ilv {
  382     nd_uint32_t type;
  383     nd_uint32_t length;
  384 };
  385 
  386 struct forces_tlv {
  387     nd_uint16_t type;
  388     nd_uint16_t length;
  389 };
  390 
  391 #define F_ALN_LEN(len) roundup2(len, ForCES_ALNL)
  392 #define GET_TOP_TLV(fhdr) ((const struct forces_tlv *)((fhdr) + sizeof (struct forcesh)))
  393 #define TLV_SET_LEN(len)  (F_ALN_LEN(TLV_HDRL) + (len))
  394 #define TLV_DATA(tlvp)   ((const void*)(((const char*)(tlvp)) + TLV_SET_LEN(0)))
  395 #define GO_NXT_TLV(tlv,rlen) ((rlen) -= F_ALN_LEN(GET_BE_U_2((tlv)->length)), \
  396                       (const struct forces_tlv*)(((const char*)(tlv)) \
  397                       + F_ALN_LEN(GET_BE_U_2((tlv)->length))))
  398 #define ILV_SET_LEN(len)  (F_ALN_LEN(ILV_HDRL) + (len))
  399 #define ILV_DATA(ilvp)   ((const void*)(((const char*)(ilvp)) + ILV_SET_LEN(0)))
  400 #define GO_NXT_ILV(ilv,rlen) ((rlen) -= F_ALN_LEN(GET_BE_U_4((ilv)->length)), \
  401                       (const struct forces_ilv *)(((const char*)(ilv)) \
  402                       + F_ALN_LEN(GET_BE_U_4((ilv)->length))))
  403 #define INVALID_RLEN 1
  404 #define INVALID_STLN 2
  405 #define INVALID_LTLN 3
  406 #define INVALID_ALEN 4
  407 
  408 static const struct tok ForCES_TLV_err[] = {
  409     {INVALID_RLEN, "Invalid total length"},
  410     {INVALID_STLN, "xLV too short"},
  411     {INVALID_LTLN, "xLV too long"},
  412     {INVALID_ALEN, "data padding missing"},
  413     {0, NULL}
  414 };
  415 
  416 static u_int
  417 tlv_valid(u_int tlvl, u_int rlen)
  418 {
  419     if (rlen < TLV_HDRL)
  420         return INVALID_RLEN;
  421     if (tlvl < TLV_HDRL)
  422         return INVALID_STLN;
  423     if (tlvl > rlen)
  424         return INVALID_LTLN;
  425     if (rlen < F_ALN_LEN(tlvl))
  426         return INVALID_ALEN;
  427 
  428     return 0;
  429 }
  430 
  431 static int
  432 ilv_valid(netdissect_options *ndo, const struct forces_ilv *ilv, u_int rlen)
  433 {
  434     if (rlen < ILV_HDRL)
  435         return INVALID_RLEN;
  436     if (GET_BE_U_4(ilv->length) < ILV_HDRL)
  437         return INVALID_STLN;
  438     if (GET_BE_U_4(ilv->length) > rlen)
  439         return INVALID_LTLN;
  440     if (rlen < F_ALN_LEN(GET_BE_U_4(ilv->length)))
  441         return INVALID_ALEN;
  442 
  443     return 0;
  444 }
  445 
  446 static int lfbselect_print(netdissect_options *, const u_char * pptr, u_int len,
  447                uint16_t op_msk, int indent);
  448 static int redirect_print(netdissect_options *, const u_char * pptr, u_int len,
  449               uint16_t op_msk, int indent);
  450 static int asrtlv_print(netdissect_options *, const u_char * pptr, u_int len,
  451             uint16_t op_msk, int indent);
  452 static int asttlv_print(netdissect_options *, const u_char * pptr, u_int len,
  453             uint16_t op_msk, int indent);
  454 
  455 struct forces_lfbsh {
  456     nd_uint32_t class;
  457     nd_uint32_t instance;
  458 };
  459 
  460 #define ASSNS_OPS (B_OP_REPORT)
  461 #define CFG_OPS (B_OP_SET|B_OP_SETPROP|B_OP_DEL|B_OP_COMMIT|B_OP_RTRCOMP)
  462 #define CFG_ROPS (B_OP_SETRESP|B_OP_SETPRESP|B_OP_DELRESP|B_OP_RCOMMIT)
  463 #define CFG_QY (B_OP_GET|B_OP_GETPROP)
  464 #define CFG_QYR (B_OP_GETRESP|B_OP_GETPRESP)
  465 #define CFG_EVN (B_OP_REPORT)
  466 
  467 static const struct tom_h ForCES_msg[TOM_MAX_IND + 1] = {
  468     /* TOM_RSV_I */ {TOM_RSVD, ZERO_TTLV, 0, "Invalid message", NULL},
  469     /* TOM_ASS_I */ {TOM_ASSNSETUP, ZERO_MORE_TTLV | TWO_TLV, ASSNS_OPS,
  470                "Association Setup", lfbselect_print},
  471     /* TOM_AST_I */
  472         {TOM_ASSNTEARD, TTLV_T1, 0, "Association TearDown", asttlv_print},
  473     /* TOM_CFG_I */ {TOM_CONFIG, TTLV_T2, CFG_OPS, "Config", lfbselect_print},
  474     /* TOM_QRY_I */ {TOM_QUERY, TTLV_T2, CFG_QY, "Query", lfbselect_print},
  475     /* TOM_EVN_I */ {TOM_EVENTNOT, TTLV_T1, CFG_EVN, "Event Notification",
  476                lfbselect_print},
  477     /* TOM_RED_I */
  478         {TOM_PKTREDIR, TTLV_T2, 0, "Packet Redirect", redirect_print},
  479     /* TOM_HBT_I */ {TOM_HEARTBT, ZERO_TTLV, 0, "HeartBeat", NULL},
  480     /* TOM_ASR_I */
  481         {TOM_ASSNSETREP, TTLV_T1, 0, "Association Response", asrtlv_print},
  482     /* TOM_CNR_I */ {TOM_CONFIGREP, TTLV_T2, CFG_ROPS, "Config Response",
  483                lfbselect_print},
  484     /* TOM_QRR_I */
  485         {TOM_QUERYREP, TTLV_T2, CFG_QYR, "Query Response", lfbselect_print},
  486 };
  487 
  488 static const struct tom_h *
  489 get_forces_tom(uint8_t tom)
  490 {
  491     int i;
  492     for (i = TOM_RSV_I; i <= TOM_MAX_IND; i++) {
  493         const struct tom_h *th = &ForCES_msg[i];
  494         if (th->v == tom)
  495             return th;
  496     }
  497     return &ForCES_msg[TOM_RSV_I];
  498 }
  499 
  500 struct pdata_ops {
  501     uint32_t v;
  502     uint16_t flags;
  503     uint16_t op_msk;
  504     const char *s;
  505     int (*print) (netdissect_options *, const u_char * pptr, u_int len,
  506               uint16_t op_msk, int indent);
  507 };
  508 
  509 enum {
  510     PD_RSV_I,
  511     PD_SEL_I,
  512     PD_FDT_I,
  513     PD_SDT_I,
  514     PD_RES_I,
  515     PD_PDT_I,
  516     _PD_RSV_MAX
  517 };
  518 #define PD_MAX_IND (_TOM_RSV_MAX - 1)
  519 
  520 static int
  521 pd_valid(uint16_t pd)
  522 {
  523     if (pd >= F_TLV_PDAT && pd <= F_TLV_REST)
  524         return 1;
  525     return 0;
  526 }
  527 
  528 static void
  529 chk_op_type(netdissect_options *ndo,
  530             uint16_t type, uint16_t msk, uint16_t omsk)
  531 {
  532     if (type != F_TLV_PDAT) {
  533         if (msk & B_KEYIN) {
  534             if (type != F_TLV_KEYI) {
  535                 ND_PRINT("Based on flags expected KEYINFO TLV!\n");
  536             }
  537         } else {
  538             if (!(msk & omsk)) {
  539                 ND_PRINT("Illegal DATA encoding for type 0x%x programmed %x got %x\n",
  540                           type, omsk, msk);
  541             }
  542         }
  543     }
  544 
  545 }
  546 
  547 #define F_SELKEY 1
  548 #define F_SELTABRANGE 2
  549 #define F_TABAPPEND 4
  550 
  551 struct res_val {
  552     nd_uint8_t result;
  553     nd_uint8_t resv1;
  554     nd_uint16_t resv2;
  555 };
  556 
  557 static int prestlv_print(netdissect_options *, const u_char * pptr, u_int len,
  558              uint16_t op_msk, int indent);
  559 static int pkeyitlv_print(netdissect_options *, const u_char * pptr, u_int len,
  560               uint16_t op_msk, int indent);
  561 static int fdatatlv_print(netdissect_options *, const u_char * pptr, u_int len,
  562               uint16_t op_msk, int indent);
  563 static int sdatatlv_print(netdissect_options *, const u_char * pptr, u_int len,
  564               uint16_t op_msk, int indent);
  565 
  566 static const struct pdata_ops ForCES_pdata[PD_MAX_IND + 1] = {
  567     /* PD_RSV_I */ {0, 0, 0, "Invalid message", NULL},
  568     /* PD_SEL_I */ {F_TLV_KEYI, 0, 0, "KEYINFO TLV", pkeyitlv_print},
  569     /* PD_FDT_I */ {F_TLV_FULD, 0, B_FULLD, "FULLDATA TLV", fdatatlv_print},
  570     /* PD_SDT_I */ {F_TLV_SPAD, 0, B_SPARD, "SPARSEDATA TLV", sdatatlv_print},
  571     /* PD_RES_I */ {F_TLV_REST, 0, B_RESTV, "RESULT TLV", prestlv_print},
  572     /* PD_PDT_I */
  573         {F_TLV_PDAT, 0, 0, "Inner PATH-DATA TLV", recpdoptlv_print},
  574 };
  575 
  576 static const struct pdata_ops *
  577 get_forces_pd(uint16_t pd)
  578 {
  579     int i;
  580     for (i = PD_RSV_I + 1; i <= PD_MAX_IND; i++) {
  581         const struct pdata_ops *pdo = &ForCES_pdata[i];
  582         if (pdo->v == pd)
  583             return pdo;
  584     }
  585     return &ForCES_pdata[TOM_RSV_I];
  586 }
  587 
  588 enum {
  589     E_SUCCESS,
  590     E_INVALID_HEADER,
  591     E_LENGTH_MISMATCH,
  592     E_VERSION_MISMATCH,
  593     E_INVALID_DESTINATION_PID,
  594     E_LFB_UNKNOWN,
  595     E_LFB_NOT_FOUND,
  596     E_LFB_INSTANCE_ID_NOT_FOUND,
  597     E_INVALID_PATH,
  598     E_COMPONENT_DOES_NOT_EXIST,
  599     E_EXISTS,
  600     E_NOT_FOUND,
  601     E_READ_ONLY,
  602     E_INVALID_ARRAY_CREATION,
  603     E_VALUE_OUT_OF_RANGE,
  604     E_CONTENTS_TOO_LONG,
  605     E_INVALID_PARAMETERS,
  606     E_INVALID_MESSAGE_TYPE,
  607     E_INVALID_FLAGS,
  608     E_INVALID_TLV,
  609     E_EVENT_ERROR,
  610     E_NOT_SUPPORTED,
  611     E_MEMORY_ERROR,
  612     E_INTERNAL_ERROR,
  613     /* 0x18-0xFE are reserved .. */
  614     E_UNSPECIFIED_ERROR = 0XFF
  615 };
  616 
  617 static const struct tok ForCES_errs[] = {
  618     {E_SUCCESS, "SUCCESS"},
  619     {E_INVALID_HEADER, "INVALID HEADER"},
  620     {E_LENGTH_MISMATCH, "LENGTH MISMATCH"},
  621     {E_VERSION_MISMATCH, "VERSION MISMATCH"},
  622     {E_INVALID_DESTINATION_PID, "INVALID DESTINATION PID"},
  623     {E_LFB_UNKNOWN, "LFB UNKNOWN"},
  624     {E_LFB_NOT_FOUND, "LFB NOT FOUND"},
  625     {E_LFB_INSTANCE_ID_NOT_FOUND, "LFB INSTANCE ID NOT FOUND"},
  626     {E_INVALID_PATH, "INVALID PATH"},
  627     {E_COMPONENT_DOES_NOT_EXIST, "COMPONENT DOES NOT EXIST"},
  628     {E_EXISTS, "EXISTS ALREADY"},
  629     {E_NOT_FOUND, "NOT FOUND"},
  630     {E_READ_ONLY, "READ ONLY"},
  631     {E_INVALID_ARRAY_CREATION, "INVALID ARRAY CREATION"},
  632     {E_VALUE_OUT_OF_RANGE, "VALUE OUT OF RANGE"},
  633     {E_CONTENTS_TOO_LONG, "CONTENTS TOO LONG"},
  634     {E_INVALID_PARAMETERS, "INVALID PARAMETERS"},
  635     {E_INVALID_MESSAGE_TYPE, "INVALID MESSAGE TYPE"},
  636     {E_INVALID_FLAGS, "INVALID FLAGS"},
  637     {E_INVALID_TLV, "INVALID TLV"},
  638     {E_EVENT_ERROR, "EVENT ERROR"},
  639     {E_NOT_SUPPORTED, "NOT SUPPORTED"},
  640     {E_MEMORY_ERROR, "MEMORY ERROR"},
  641     {E_INTERNAL_ERROR, "INTERNAL ERROR"},
  642     {E_UNSPECIFIED_ERROR, "UNSPECIFIED ERROR"},
  643     {0, NULL}
  644 };
  645 
  646 #define RESLEN  4
  647 
  648 static int
  649 prestlv_print(netdissect_options *ndo,
  650               const u_char * pptr, u_int len,
  651               uint16_t op_msk _U_, int indent)
  652 {
  653     const struct forces_tlv *tlv = (const struct forces_tlv *)pptr;
  654     const u_char *tdp = (const u_char *) TLV_DATA(tlv);
  655     const struct res_val *r = (const struct res_val *)tdp;
  656     u_int dlen;
  657     uint8_t result;
  658 
  659     /*
  660      * pdatacnt_print() has ensured that len (the TLV length)
  661      * >= TLV_HDRL.
  662      */
  663     dlen = len - TLV_HDRL;
  664     if (dlen != RESLEN) {
  665         ND_PRINT("illegal RESULT-TLV: %u bytes!\n", dlen);
  666         return -1;
  667     }
  668 
  669     ND_TCHECK_SIZE(r);
  670     result = GET_U_1(r->result);
  671     if (result >= 0x18 && result <= 0xFE) {
  672         ND_PRINT("illegal reserved result code: 0x%x!\n", result);
  673         return -1;
  674     }
  675 
  676     if (ndo->ndo_vflag >= 3) {
  677         char *ib = indent_pr(indent, 0);
  678         ND_PRINT("%s  Result: %s (code 0x%x)\n", ib,
  679                tok2str(ForCES_errs, NULL, result), result);
  680     }
  681     return 0;
  682 
  683 trunc:
  684     nd_print_trunc(ndo);
  685     return -1;
  686 }
  687 
  688 static int
  689 fdatatlv_print(netdissect_options *ndo,
  690                const u_char * pptr, u_int len,
  691                uint16_t op_msk _U_, int indent)
  692 {
  693     const struct forces_tlv *tlv = (const struct forces_tlv *)pptr;
  694     u_int rlen;
  695     const u_char *tdp = (const u_char *) TLV_DATA(tlv);
  696     uint16_t type;
  697 
  698     /*
  699      * pdatacnt_print() or pkeyitlv_print() has ensured that len
  700      * (the TLV length) >= TLV_HDRL.
  701      */
  702     rlen = len - TLV_HDRL;
  703     ND_TCHECK_SIZE(tlv);
  704     type = GET_BE_U_2(tlv->type);
  705     if (type != F_TLV_FULD) {
  706         ND_PRINT("Error: expecting FULLDATA!\n");
  707         return -1;
  708     }
  709 
  710     if (ndo->ndo_vflag >= 3) {
  711         char *ib = indent_pr(indent + 2, 1);
  712         ND_PRINT("%s[", ib + 1);
  713         hex_print(ndo, ib, tdp, rlen);
  714         ND_PRINT("\n%s]", ib + 1);
  715     }
  716     return 0;
  717 
  718 trunc:
  719     nd_print_trunc(ndo);
  720     return -1;
  721 }
  722 
  723 static int
  724 sdatailv_print(netdissect_options *ndo,
  725                const u_char * pptr, u_int len,
  726                uint16_t op_msk _U_, int indent)
  727 {
  728     u_int rlen;
  729     const struct forces_ilv *ilv = (const struct forces_ilv *)pptr;
  730     int invilv;
  731 
  732     if (len < ILV_HDRL) {
  733         ND_PRINT("Error: BAD SPARSEDATA-TLV!\n");
  734         return -1;
  735     }
  736     rlen = len;
  737     indent += 1;
  738     while (rlen != 0) {
  739 #if 0
  740         ND_PRINT("Jamal - outstanding length <%u>\n", rlen);
  741 #endif
  742         char *ib = indent_pr(indent, 1);
  743         const u_char *tdp = (const u_char *) ILV_DATA(ilv);
  744         invilv = ilv_valid(ndo, ilv, rlen);
  745         if (invilv) {
  746             ND_PRINT("Error: %s, rlen %u\n",
  747                      tok2str(ForCES_TLV_err, NULL, invilv), rlen);
  748             return -1;
  749         }
  750         if (ndo->ndo_vflag >= 3) {
  751             u_int ilvl = GET_BE_U_4(ilv->length);
  752             ND_PRINT("\n%s ILV: type %x length %u\n", ib + 1,
  753                   GET_BE_U_4(ilv->type), ilvl);
  754             hex_print(ndo, "\t\t[", tdp, ilvl-ILV_HDRL);
  755         }
  756 
  757         ilv = GO_NXT_ILV(ilv, rlen);
  758     }
  759 
  760     return 0;
  761 }
  762 
  763 static int
  764 sdatatlv_print(netdissect_options *ndo,
  765                const u_char * pptr, u_int len,
  766                uint16_t op_msk, int indent)
  767 {
  768     const struct forces_tlv *tlv = (const struct forces_tlv *)pptr;
  769     u_int rlen;
  770     const u_char *tdp = (const u_char *) TLV_DATA(tlv);
  771     uint16_t type;
  772 
  773     /*
  774      * pdatacnt_print() has ensured that len (the TLV length)
  775      * >= TLV_HDRL.
  776      */
  777     rlen = len - TLV_HDRL;
  778     ND_TCHECK_SIZE(tlv);
  779     type = GET_BE_U_2(tlv->type);
  780     if (type != F_TLV_SPAD) {
  781         ND_PRINT("Error: expecting SPARSEDATA!\n");
  782         return -1;
  783     }
  784 
  785     return sdatailv_print(ndo, tdp, rlen, op_msk, indent);
  786 
  787 trunc:
  788     nd_print_trunc(ndo);
  789     return -1;
  790 }
  791 
  792 static int
  793 pkeyitlv_print(netdissect_options *ndo,
  794                const u_char * pptr, u_int len,
  795                uint16_t op_msk, int indent)
  796 {
  797     const struct forces_tlv *tlv = (const struct forces_tlv *)pptr;
  798     const u_char *tdp = (const u_char *) TLV_DATA(tlv);
  799     const u_char *dp = tdp + 4;
  800     const struct forces_tlv *kdtlv = (const struct forces_tlv *)dp;
  801     uint32_t id;
  802     char *ib = indent_pr(indent, 0);
  803     uint16_t type, tll;
  804     u_int invtlv;
  805 
  806     id = GET_BE_U_4(tdp);
  807     ND_PRINT("%sKeyinfo: Key 0x%x\n", ib, id);
  808     type = GET_BE_U_2(kdtlv->type);
  809     tll = GET_BE_U_2(kdtlv->length);
  810     invtlv = tlv_valid(tll, len);
  811 
  812     if (invtlv) {
  813         ND_PRINT("%s TLV type 0x%x len %u\n",
  814                tok2str(ForCES_TLV_err, NULL, invtlv), type,
  815                tll);
  816         return -1;
  817     }
  818     /*
  819      * At this point, tlv_valid() has ensured that the TLV
  820      * length is large enough but not too large (it doesn't
  821      * go past the end of the containing TLV).
  822      */
  823     tll = GET_BE_U_2(kdtlv->length);
  824     dp = (const u_char *) TLV_DATA(kdtlv);
  825     return fdatatlv_print(ndo, dp, tll, op_msk, indent);
  826 }
  827 
  828 #define PTH_DESC_SIZE 12
  829 
  830 static int
  831 pdatacnt_print(netdissect_options *ndo,
  832                const u_char * pptr, u_int len,
  833                uint16_t IDcnt, uint16_t op_msk, int indent)
  834 {
  835     u_int i;
  836     uint32_t id;
  837     char *ib = indent_pr(indent, 0);
  838 
  839     if ((op_msk & B_APPND) && ndo->ndo_vflag >= 3) {
  840         ND_PRINT("%sTABLE APPEND\n", ib);
  841     }
  842     for (i = 0; i < IDcnt; i++) {
  843         ND_TCHECK_4(pptr);
  844         if (len < 4)
  845             goto trunc;
  846         id = GET_BE_U_4(pptr);
  847         if (ndo->ndo_vflag >= 3)
  848             ND_PRINT("%sID#%02u: %u\n", ib, i + 1, id);
  849         len -= 4;
  850         pptr += 4;
  851     }
  852 
  853     if ((op_msk & B_TRNG) || (op_msk & B_KEYIN)) {
  854         if (op_msk & B_TRNG) {
  855             uint32_t starti, endi;
  856 
  857             if (len < PTH_DESC_SIZE) {
  858                 ND_PRINT("pathlength %u with key/range too short %u\n",
  859                        len, PTH_DESC_SIZE);
  860                 return -1;
  861             }
  862 
  863             pptr += sizeof(struct forces_tlv);
  864             len -= sizeof(struct forces_tlv);
  865 
  866             starti = GET_BE_U_4(pptr);
  867             pptr += 4;
  868             len -= 4;
  869 
  870             endi = GET_BE_U_4(pptr);
  871             pptr += 4;
  872             len -= 4;
  873 
  874             if (ndo->ndo_vflag >= 3)
  875                 ND_PRINT("%sTable range: [%u,%u]\n", ib, starti, endi);
  876         }
  877 
  878         if (op_msk & B_KEYIN) {
  879             const struct forces_tlv *keytlv;
  880             uint16_t tll;
  881 
  882             if (len < PTH_DESC_SIZE) {
  883                 ND_PRINT("pathlength %u with key/range too short %u\n",
  884                        len, PTH_DESC_SIZE);
  885                 return -1;
  886             }
  887 
  888             /* skip keyid */
  889             pptr += 4;
  890             len -= 4;
  891             keytlv = (const struct forces_tlv *)pptr;
  892             /* skip header */
  893             pptr += sizeof(struct forces_tlv);
  894             len -= sizeof(struct forces_tlv);
  895             /* skip key content */
  896             tll = GET_BE_U_2(keytlv->length);
  897             if (tll < TLV_HDRL) {
  898                 ND_PRINT("key content length %u < %u\n",
  899                     tll, TLV_HDRL);
  900                 return -1;
  901             }
  902             tll -= TLV_HDRL;
  903             if (len < tll) {
  904                 ND_PRINT("key content too short\n");
  905                 return -1;
  906             }
  907             pptr += tll;
  908             len -= tll;
  909         }
  910 
  911     }
  912 
  913     if (len) {
  914         const struct forces_tlv *pdtlv = (const struct forces_tlv *)pptr;
  915         uint16_t type;
  916         uint16_t tlvl, tll;
  917         u_int pad = 0;
  918         u_int aln;
  919         u_int invtlv;
  920 
  921         type = GET_BE_U_2(pdtlv->type);
  922         tlvl = GET_BE_U_2(pdtlv->length);
  923         invtlv = tlv_valid(tlvl, len);
  924         if (invtlv) {
  925             ND_PRINT("%s Outstanding bytes %u for TLV type 0x%x TLV len %u\n",
  926                       tok2str(ForCES_TLV_err, NULL, invtlv), len, type,
  927                       tlvl);
  928             goto pd_err;
  929         }
  930         /*
  931          * At this point, tlv_valid() has ensured that the TLV
  932          * length is large enough but not too large (it doesn't
  933          * go past the end of the containing TLV).
  934          */
  935         tll = tlvl - TLV_HDRL;
  936         aln = F_ALN_LEN(tlvl);
  937         if (aln > tlvl) {
  938             if (aln > len) {
  939                 ND_PRINT("Invalid padded pathdata TLV type 0x%x len %u missing %u pad bytes\n",
  940                           type, tlvl, aln - len);
  941             } else {
  942                 pad = aln - tlvl;
  943             }
  944         }
  945         if (pd_valid(type)) {
  946             const struct pdata_ops *ops = get_forces_pd(type);
  947 
  948             if (ndo->ndo_vflag >= 3 && ops->v != F_TLV_PDAT) {
  949                 if (pad)
  950                     ND_PRINT("%s  %s (Length %u DataLen %u pad %u Bytes)\n",
  951                               ib, ops->s, tlvl, tll, pad);
  952                 else
  953                     ND_PRINT("%s  %s (Length %u DataLen %u Bytes)\n",
  954                               ib, ops->s, tlvl, tll);
  955             }
  956 
  957             chk_op_type(ndo, type, op_msk, ops->op_msk);
  958 
  959             if (ops->print(ndo, (const u_char *)pdtlv,
  960                     tll + pad + TLV_HDRL, op_msk,
  961                     indent + 2) == -1)
  962                 return -1;
  963             len -= (TLV_HDRL + pad + tll);
  964         } else {
  965             ND_PRINT("Invalid path data content type 0x%x len %u\n",
  966                    type, tlvl);
  967 pd_err:
  968             if (tlvl) {
  969                                 hex_print(ndo, "Bad Data val\n\t  [",
  970                       pptr, len);
  971                 ND_PRINT("]\n");
  972 
  973                 return -1;
  974             }
  975         }
  976     }
  977     return len;
  978 
  979 trunc:
  980     nd_print_trunc(ndo);
  981     return -1;
  982 }
  983 
  984 static int
  985 pdata_print(netdissect_options *ndo,
  986             const u_char * pptr, u_int len,
  987             uint16_t op_msk, int indent)
  988 {
  989     const struct pathdata_h *pdh = (const struct pathdata_h *)pptr;
  990     char *ib = indent_pr(indent, 0);
  991     u_int minsize = 0;
  992     int more_pd = 0;
  993     uint16_t idcnt = 0;
  994 
  995     ND_TCHECK_SIZE(pdh);
  996     if (len < sizeof(struct pathdata_h))
  997         goto trunc;
  998     if (ndo->ndo_vflag >= 3) {
  999         ND_PRINT("\n%sPathdata: Flags 0x%x ID count %u\n",
 1000                ib, GET_BE_U_2(pdh->pflags),
 1001                GET_BE_U_2(pdh->pIDcnt));
 1002     }
 1003 
 1004     if (GET_BE_U_2(pdh->pflags) & F_SELKEY) {
 1005         op_msk |= B_KEYIN;
 1006     }
 1007 
 1008     /* Table GET Range operation */
 1009     if (GET_BE_U_2(pdh->pflags) & F_SELTABRANGE) {
 1010         op_msk |= B_TRNG;
 1011     }
 1012     /* Table SET append operation */
 1013     if (GET_BE_U_2(pdh->pflags) & F_TABAPPEND) {
 1014         op_msk |= B_APPND;
 1015     }
 1016 
 1017     pptr += sizeof(struct pathdata_h);
 1018     len -= sizeof(struct pathdata_h);
 1019     idcnt = GET_BE_U_2(pdh->pIDcnt);
 1020     minsize = idcnt * 4;
 1021     if (len < minsize) {
 1022         ND_PRINT("\t\t\ttruncated IDs expected %uB got %uB\n", minsize,
 1023                len);
 1024         hex_print(ndo, "\t\t\tID Data[", pptr, len);
 1025         ND_PRINT("]\n");
 1026         return -1;
 1027     }
 1028 
 1029     if ((op_msk & B_TRNG) && (op_msk & B_KEYIN)) {
 1030         ND_PRINT("\t\t\tIllegal to have both Table ranges and keys\n");
 1031         return -1;
 1032     }
 1033 
 1034     more_pd = pdatacnt_print(ndo, pptr, len, idcnt, op_msk, indent);
 1035     if (more_pd > 0) {
 1036         int consumed = len - more_pd;
 1037         pptr += consumed;
 1038         len = more_pd;
 1039         /* XXX: Argh, recurse some more */
 1040         return recpdoptlv_print(ndo, pptr, len, op_msk, indent+1);
 1041     } else
 1042         return 0;
 1043 
 1044 trunc:
 1045     nd_print_trunc(ndo);
 1046     return -1;
 1047 }
 1048 
 1049 static int
 1050 genoptlv_print(netdissect_options *ndo,
 1051                const u_char * pptr, u_int len,
 1052                uint16_t op_msk, int indent)
 1053 {
 1054     const struct forces_tlv *pdtlv = (const struct forces_tlv *)pptr;
 1055     uint16_t type;
 1056     u_int tlvl;
 1057     u_int invtlv;
 1058     char *ib = indent_pr(indent, 0);
 1059 
 1060     type = GET_BE_U_2(pdtlv->type);
 1061     tlvl = GET_BE_U_2(pdtlv->length);
 1062     invtlv = tlv_valid(tlvl, len);
 1063     ND_PRINT("genoptlvprint - %s TLV type 0x%x len %u\n",
 1064            tok2str(ForCES_TLV, NULL, type), type, tlvl);
 1065     if (!invtlv) {
 1066         /*
 1067          * At this point, tlv_valid() has ensured that the TLV
 1068          * length is large enough but not too large (it doesn't
 1069          * go past the end of the containing TLV).
 1070          */
 1071         const u_char *dp = (const u_char *) TLV_DATA(pdtlv);
 1072 
 1073         if (!ttlv_valid(type)) {
 1074             ND_PRINT("%s TLV type 0x%x len %u\n",
 1075                    tok2str(ForCES_TLV_err, NULL, invtlv), type,
 1076                    tlvl);
 1077             return -1;
 1078         }
 1079         if (ndo->ndo_vflag >= 3)
 1080             ND_PRINT("%s%s, length %u (data length %u Bytes)",
 1081                    ib, tok2str(ForCES_TLV, NULL, type),
 1082                    tlvl, tlvl - TLV_HDRL);
 1083 
 1084         return pdata_print(ndo, dp, tlvl - TLV_HDRL, op_msk, indent + 1);
 1085     } else {
 1086         ND_PRINT("\t\t\tInvalid ForCES TLV type=%x", type);
 1087         return -1;
 1088     }
 1089 }
 1090 
 1091 static int
 1092 recpdoptlv_print(netdissect_options *ndo,
 1093                  const u_char * pptr, u_int len,
 1094                  uint16_t op_msk, int indent)
 1095 {
 1096     const struct forces_tlv *pdtlv = (const struct forces_tlv *)pptr;
 1097 
 1098     while (len != 0) {
 1099         uint16_t type, tlvl;
 1100         u_int invtlv;
 1101         char *ib;
 1102         const u_char *dp;
 1103 
 1104         tlvl = GET_BE_U_2(pdtlv->length);
 1105         invtlv = tlv_valid(tlvl, len);
 1106         if (invtlv) {
 1107             break;
 1108         }
 1109 
 1110         /*
 1111          * At this point, tlv_valid() has ensured that the TLV
 1112          * length is large enough but not too large (it doesn't
 1113          * go past the end of the containing TLV).
 1114          */
 1115         ib = indent_pr(indent, 0);
 1116         type = GET_BE_U_2(pdtlv->type);
 1117         dp = (const u_char *) TLV_DATA(pdtlv);
 1118 
 1119         if (ndo->ndo_vflag >= 3)
 1120             ND_PRINT("%s%s, length %u (data encapsulated %u Bytes)",
 1121                       ib, tok2str(ForCES_TLV, NULL, type),
 1122                       tlvl,
 1123                       tlvl - TLV_HDRL);
 1124 
 1125         if (pdata_print(ndo, dp, tlvl - TLV_HDRL, op_msk, indent + 1) == -1)
 1126             return -1;
 1127         pdtlv = GO_NXT_TLV(pdtlv, len);
 1128     }
 1129 
 1130     if (len) {
 1131         ND_PRINT("\n\t\tMessy PATHDATA TLV header, type (0x%x)\n\t\texcess of %u Bytes ",
 1132                   GET_BE_U_2(pdtlv->type),
 1133                   len - GET_BE_U_2(pdtlv->length));
 1134         return -1;
 1135     }
 1136 
 1137     return 0;
 1138 }
 1139 
 1140 static int
 1141 invoptlv_print(netdissect_options *ndo,
 1142                const u_char * pptr, u_int len,
 1143                uint16_t op_msk _U_, int indent)
 1144 {
 1145     char *ib = indent_pr(indent, 1);
 1146 
 1147     if (ndo->ndo_vflag >= 3) {
 1148         ND_PRINT("%sData[", ib + 1);
 1149         hex_print(ndo, ib, pptr, len);
 1150         ND_PRINT("%s]\n", ib);
 1151     }
 1152     return -1;
 1153 }
 1154 
 1155 static int
 1156 otlv_print(netdissect_options *ndo,
 1157            const struct forces_tlv *otlv, uint16_t op_msk _U_, int indent)
 1158 {
 1159     int rc = 0;
 1160     const u_char *dp = (const u_char *) TLV_DATA(otlv);
 1161     uint16_t type;
 1162     u_int tll;
 1163     char *ib = indent_pr(indent, 0);
 1164     const struct optlv_h *ops;
 1165 
 1166     /*
 1167      * lfbselect_print() has ensured that GET_BE_U_2(otlv->length)
 1168      * >= TLV_HDRL.
 1169      */
 1170     type = GET_BE_U_2(otlv->type);
 1171     tll = GET_BE_U_2(otlv->length) - TLV_HDRL;
 1172     ops = get_forces_optlv_h(type);
 1173     if (ndo->ndo_vflag >= 3) {
 1174         ND_PRINT("%sOper TLV %s(0x%x) length %u\n", ib, ops->s, type,
 1175                GET_BE_U_2(otlv->length));
 1176     }
 1177     /* rest of ops must at least have 12B {pathinfo} */
 1178     if (tll < OP_MIN_SIZ) {
 1179         ND_PRINT("\t\tOper TLV %s(0x%x) length %u\n", ops->s, type,
 1180                GET_BE_U_2(otlv->length));
 1181         ND_PRINT("\t\tTruncated data size %u minimum required %u\n", tll,
 1182                OP_MIN_SIZ);
 1183         return invoptlv_print(ndo, dp, tll, ops->op_msk, indent);
 1184 
 1185     }
 1186 
 1187     /* XXX - do anything with ops->flags? */
 1188         if(ops->print) {
 1189                 rc = ops->print(ndo, dp, tll, ops->op_msk, indent + 1);
 1190         }
 1191     return rc;
 1192 }
 1193 
 1194 #define ASTDLN  4
 1195 #define ASTMCD  255
 1196 static int
 1197 asttlv_print(netdissect_options *ndo,
 1198              const u_char * pptr, u_int len,
 1199              uint16_t op_msk _U_, int indent)
 1200 {
 1201     uint32_t rescode;
 1202     u_int dlen;
 1203     char *ib = indent_pr(indent, 0);
 1204 
 1205     /*
 1206      * forces_type_print() has ensured that len (the TLV length)
 1207      * >= TLV_HDRL.
 1208      */
 1209     dlen = len - TLV_HDRL;
 1210     if (dlen != ASTDLN) {
 1211         ND_PRINT("illegal ASTresult-TLV: %u bytes!\n", dlen);
 1212         return -1;
 1213     }
 1214     rescode = GET_BE_U_4(pptr);
 1215     if (rescode > ASTMCD) {
 1216         ND_PRINT("illegal ASTresult result code: %u!\n", rescode);
 1217         return -1;
 1218     }
 1219 
 1220     if (ndo->ndo_vflag >= 3) {
 1221         ND_PRINT("Teardown reason:\n%s", ib);
 1222         switch (rescode) {
 1223         case 0:
 1224             ND_PRINT("Normal Teardown");
 1225             break;
 1226         case 1:
 1227             ND_PRINT("Loss of Heartbeats");
 1228             break;
 1229         case 2:
 1230             ND_PRINT("Out of bandwidth");
 1231             break;
 1232         case 3:
 1233             ND_PRINT("Out of Memory");
 1234             break;
 1235         case 4:
 1236             ND_PRINT("Application Crash");
 1237             break;
 1238         default:
 1239             ND_PRINT("Unknown Teardown reason");
 1240             break;
 1241         }
 1242         ND_PRINT("(%x)\n%s", rescode, ib);
 1243     }
 1244     return 0;
 1245 }
 1246 
 1247 #define ASRDLN  4
 1248 #define ASRMCD  3
 1249 static int
 1250 asrtlv_print(netdissect_options *ndo,
 1251              const u_char * pptr, u_int len,
 1252              uint16_t op_msk _U_, int indent)
 1253 {
 1254     uint32_t rescode;
 1255     u_int dlen;
 1256     char *ib = indent_pr(indent, 0);
 1257 
 1258     /*
 1259      * forces_type_print() has ensured that len (the TLV length)
 1260      * >= TLV_HDRL.
 1261      */
 1262     dlen = len - TLV_HDRL;
 1263     if (dlen != ASRDLN) {   /* id, instance, oper tlv */
 1264         ND_PRINT("illegal ASRresult-TLV: %u bytes!\n", dlen);
 1265         return -1;
 1266     }
 1267     rescode = GET_BE_U_4(pptr);
 1268 
 1269     if (rescode > ASRMCD) {
 1270         ND_PRINT("illegal ASRresult result code: %u!\n", rescode);
 1271         return -1;
 1272     }
 1273 
 1274     if (ndo->ndo_vflag >= 3) {
 1275         ND_PRINT("\n%s", ib);
 1276         switch (rescode) {
 1277         case 0:
 1278             ND_PRINT("Success ");
 1279             break;
 1280         case 1:
 1281             ND_PRINT("FE ID invalid ");
 1282             break;
 1283         case 2:
 1284             ND_PRINT("permission denied ");
 1285             break;
 1286         default:
 1287             ND_PRINT("Unknown ");
 1288             break;
 1289         }
 1290         ND_PRINT("(%x)\n%s", rescode, ib);
 1291     }
 1292     return 0;
 1293 }
 1294 
 1295 #if 0
 1296 /*
 1297  * XXX - not used.
 1298  */
 1299 static int
 1300 gentltlv_print(netdissect_options *ndo,
 1301                const u_char * pptr _U_, u_int len,
 1302                uint16_t op_msk _U_, int indent _U_)
 1303 {
 1304     u_int dlen = len - TLV_HDRL;
 1305 
 1306     if (dlen < 4) {     /* at least 32 bits must exist */
 1307         ND_PRINT("truncated TLV: %u bytes missing! ", 4 - dlen);
 1308         return -1;
 1309     }
 1310     return 0;
 1311 }
 1312 #endif
 1313 
 1314 #define RD_MIN 8
 1315 
 1316 static int
 1317 print_metailv(netdissect_options *ndo,
 1318               const u_char * pptr, uint16_t op_msk _U_, int indent)
 1319 {
 1320     u_int rlen;
 1321     char *ib = indent_pr(indent, 0);
 1322     /* XXX: check header length */
 1323     const struct forces_ilv *ilv = (const struct forces_ilv *)pptr;
 1324 
 1325     /*
 1326      * print_metatlv() has ensured that len (what remains in the
 1327      * ILV) >= ILV_HDRL.
 1328      */
 1329     rlen = GET_BE_U_4(ilv->length) - ILV_HDRL;
 1330     ND_PRINT("%sMetaID 0x%x length %u\n", ib, GET_BE_U_4(ilv->type),
 1331           GET_BE_U_4(ilv->length));
 1332     if (ndo->ndo_vflag >= 3) {
 1333         hex_print(ndo, "\t\t[", ILV_DATA(ilv), rlen);
 1334         ND_PRINT(" ]\n");
 1335     }
 1336     return 0;
 1337 }
 1338 
 1339 static int
 1340 print_metatlv(netdissect_options *ndo,
 1341               const u_char * pptr, u_int len,
 1342               uint16_t op_msk _U_, int indent)
 1343 {
 1344     u_int dlen;
 1345     char *ib = indent_pr(indent, 0);
 1346     u_int rlen;
 1347     const struct forces_ilv *ilv = (const struct forces_ilv *)pptr;
 1348     int invilv;
 1349 
 1350     /*
 1351      * redirect_print() has ensured that len (what remains in the
 1352      * TLV) >= TLV_HDRL.
 1353      */
 1354     dlen = len - TLV_HDRL;
 1355     rlen = dlen;
 1356     ND_PRINT("\n%s METADATA length %u\n", ib, rlen);
 1357     while (rlen != 0) {
 1358         invilv = ilv_valid(ndo, ilv, rlen);
 1359         if (invilv) {
 1360             break;
 1361         }
 1362 
 1363         /*
 1364          * At this point, ilv_valid() has ensured that the ILV
 1365          * length is large enough but not too large (it doesn't
 1366          * go past the end of the containing TLV).
 1367          */
 1368         print_metailv(ndo, (const u_char *) ilv, 0, indent + 1);
 1369         ilv = GO_NXT_ILV(ilv, rlen);
 1370     }
 1371 
 1372     return 0;
 1373 }
 1374 
 1375 
 1376 static int
 1377 print_reddata(netdissect_options *ndo,
 1378               const u_char * pptr, u_int len,
 1379               uint16_t op_msk _U_, int indent)
 1380 {
 1381     u_int dlen;
 1382     char *ib = indent_pr(indent, 0);
 1383     u_int rlen;
 1384 
 1385     dlen = len - TLV_HDRL;
 1386     rlen = dlen;
 1387     ND_PRINT("\n%s Redirect Data length %u\n", ib, rlen);
 1388 
 1389     if (ndo->ndo_vflag >= 3) {
 1390         ND_PRINT("\t\t[");
 1391         hex_print(ndo, "\n\t\t", pptr, rlen);
 1392         ND_PRINT("\n\t\t]");
 1393     }
 1394 
 1395     return 0;
 1396 }
 1397 
 1398 static int
 1399 redirect_print(netdissect_options *ndo,
 1400                const u_char * pptr, u_int len,
 1401                uint16_t op_msk _U_, int indent)
 1402 {
 1403     const struct forces_tlv *tlv = (const struct forces_tlv *)pptr;
 1404     u_int dlen;
 1405     u_int rlen;
 1406     u_int invtlv;
 1407 
 1408     /*
 1409      * forces_type_print() has ensured that len (the TLV length)
 1410      * >= TLV_HDRL.
 1411      */
 1412     dlen = len - TLV_HDRL;
 1413     if (dlen <= RD_MIN) {
 1414         ND_PRINT("\n\t\ttruncated Redirect TLV: %u bytes missing! ",
 1415                RD_MIN - dlen);
 1416         return -1;
 1417     }
 1418 
 1419     rlen = dlen;
 1420     indent += 1;
 1421     while (rlen != 0) {
 1422         uint16_t type, tlvl;
 1423 
 1424         type = GET_BE_U_2(tlv->type);
 1425         tlvl = GET_BE_U_2(tlv->length);
 1426         invtlv = tlv_valid(tlvl, rlen);
 1427         if (invtlv) {
 1428             ND_PRINT("Bad Redirect data\n");
 1429             break;
 1430         }
 1431 
 1432         /*
 1433          * At this point, tlv_valid() has ensured that the TLV
 1434          * length is large enough but not too large (it doesn't
 1435          * go past the end of the containing TLV).
 1436          */
 1437         if (type == F_TLV_METD) {
 1438             print_metatlv(ndo, (const u_char *) TLV_DATA(tlv),
 1439                       tlvl, 0,
 1440                       indent);
 1441         } else if (type == F_TLV_REDD) {
 1442             print_reddata(ndo, (const u_char *) TLV_DATA(tlv),
 1443                       tlvl, 0,
 1444                       indent);
 1445         } else {
 1446             ND_PRINT("Unknown REDIRECT TLV 0x%x len %u\n",
 1447                    type,
 1448                    tlvl);
 1449         }
 1450 
 1451         tlv = GO_NXT_TLV(tlv, rlen);
 1452     }
 1453 
 1454     if (rlen) {
 1455         ND_PRINT("\n\t\tMessy Redirect TLV header, type (0x%x)\n\t\texcess of %u Bytes ",
 1456                   GET_BE_U_2(tlv->type),
 1457                   rlen - GET_BE_U_2(tlv->length));
 1458         return -1;
 1459     }
 1460 
 1461     return 0;
 1462 }
 1463 
 1464 #define OP_OFF 8
 1465 #define OP_MIN 12
 1466 
 1467 static int
 1468 lfbselect_print(netdissect_options *ndo,
 1469                 const u_char * pptr, u_int len,
 1470                 uint16_t op_msk, int indent)
 1471 {
 1472     const struct forces_lfbsh *lfbs;
 1473     const struct forces_tlv *otlv;
 1474     char *ib = indent_pr(indent, 0);
 1475     u_int dlen;
 1476     u_int rlen;
 1477     u_int invtlv;
 1478 
 1479     /*
 1480      * forces_type_print() has ensured that len (the TLV length)
 1481      * >= TLV_HDRL.
 1482      */
 1483     dlen = len - TLV_HDRL;
 1484     if (dlen <= OP_MIN) {   /* id, instance, oper tlv header .. */
 1485         ND_PRINT("\n\t\ttruncated lfb selector: %u bytes missing! ",
 1486                OP_MIN - dlen);
 1487         return -1;
 1488     }
 1489 
 1490     /*
 1491      * At this point, we know that dlen > OP_MIN; OP_OFF < OP_MIN, so
 1492      * we also know that it's > OP_OFF.
 1493      */
 1494     rlen = dlen - OP_OFF;
 1495 
 1496     lfbs = (const struct forces_lfbsh *)pptr;
 1497     ND_TCHECK_SIZE(lfbs);
 1498     if (ndo->ndo_vflag >= 3) {
 1499         ND_PRINT("\n%s%s(Classid %x) instance %x\n",
 1500                ib,
 1501                tok2str(ForCES_LFBs, NULL, GET_BE_U_4(lfbs->class)),
 1502                GET_BE_U_4(lfbs->class),
 1503                GET_BE_U_4(lfbs->instance));
 1504     }
 1505 
 1506     otlv = (const struct forces_tlv *)(lfbs + 1);
 1507 
 1508     indent += 1;
 1509     while (rlen != 0) {
 1510         uint16_t type, tlvl;
 1511 
 1512         type = GET_BE_U_2(otlv->type);
 1513         tlvl = GET_BE_U_2(otlv->length);
 1514         invtlv = tlv_valid(tlvl, rlen);
 1515         if (invtlv)
 1516             break;
 1517 
 1518         /*
 1519          * At this point, tlv_valid() has ensured that the TLV
 1520          * length is large enough but not too large (it doesn't
 1521          * go past the end of the containing TLV).
 1522          */
 1523         if (op_valid(type, op_msk)) {
 1524             otlv_print(ndo, otlv, 0, indent);
 1525         } else {
 1526             if (ndo->ndo_vflag < 3)
 1527                 ND_PRINT("\n");
 1528             ND_PRINT("\t\tINValid oper-TLV type 0x%x length %u for this ForCES message\n",
 1529                       type, tlvl);
 1530             invoptlv_print(ndo, (const u_char *)otlv, rlen, 0, indent);
 1531         }
 1532         otlv = GO_NXT_TLV(otlv, rlen);
 1533     }
 1534 
 1535     if (rlen) {
 1536         ND_PRINT("\n\t\tMessy oper TLV header, type (0x%x)\n\t\texcess of %u Bytes ",
 1537                   GET_BE_U_2(otlv->type),
 1538                   rlen - GET_BE_U_2(otlv->length));
 1539         return -1;
 1540     }
 1541 
 1542     return 0;
 1543 
 1544 trunc:
 1545     nd_print_trunc(ndo);
 1546     return -1;
 1547 }
 1548 
 1549 static int
 1550 forces_type_print(netdissect_options *ndo,
 1551                   const u_char * pptr, const struct forcesh *fhdr _U_,
 1552                   u_int mlen, const struct tom_h *tops)
 1553 {
 1554     const struct forces_tlv *tltlv;
 1555     u_int rlen;
 1556     u_int invtlv;
 1557     int rc = 0;
 1558     u_int ttlv = 0;
 1559 
 1560     /*
 1561      * forces_print() has already checked that mlen >= ForCES_HDRL
 1562      * by calling ForCES_HLN_VALID().
 1563      */
 1564     rlen = mlen - ForCES_HDRL;
 1565 
 1566     if (rlen > TLV_HLN) {
 1567         if (tops->flags & ZERO_TTLV) {
 1568             ND_PRINT("<0x%x>Illegal Top level TLV!\n", tops->flags);
 1569             return -1;
 1570         }
 1571     } else {
 1572         if (tops->flags & ZERO_MORE_TTLV)
 1573             return 0;
 1574         if (tops->flags & ONE_MORE_TTLV) {
 1575             ND_PRINT("\tTop level TLV Data missing!\n");
 1576             return -1;
 1577         }
 1578     }
 1579 
 1580     if (tops->flags & ZERO_TTLV) {
 1581         return 0;
 1582     }
 1583 
 1584     ttlv = tops->flags >> 4;
 1585     tltlv = GET_TOP_TLV(pptr);
 1586 
 1587     /*XXX: 15 top level tlvs will probably be fine
 1588        You are nuts if you send more ;-> */
 1589     while (rlen != 0) {
 1590         uint16_t type, tlvl;
 1591 
 1592         type = GET_BE_U_2(tltlv->type);
 1593         tlvl = GET_BE_U_2(tltlv->length);
 1594         invtlv = tlv_valid(tlvl, rlen);
 1595         if (invtlv)
 1596             break;
 1597 
 1598         /*
 1599          * At this point, tlv_valid() has ensured that the TLV
 1600          * length is large enough but not too large (it doesn't
 1601          * go past the end of the packet).
 1602          */
 1603         if (!ttlv_valid(type)) {
 1604             ND_PRINT("\n\tInvalid ForCES Top TLV type=0x%x",
 1605                    type);
 1606             return -1;
 1607         }
 1608 
 1609         if (ndo->ndo_vflag >= 3)
 1610             ND_PRINT("\t%s, length %u (data length %u Bytes)",
 1611                    tok2str(ForCES_TLV, NULL, type),
 1612                    tlvl,
 1613                    tlvl - TLV_HDRL);
 1614 
 1615         rc = tops->print(ndo, (const u_char *) TLV_DATA(tltlv),
 1616                  tlvl,
 1617                  tops->op_msk, 9);
 1618         if (rc < 0) {
 1619             return -1;
 1620         }
 1621         tltlv = GO_NXT_TLV(tltlv, rlen);
 1622         ttlv--;
 1623         if (ttlv <= 0)
 1624             break;
 1625     }
 1626     /*
 1627      * XXX - if ttlv != 0, does that mean that the packet was too
 1628      * short, and didn't have *enough* TLVs in it?
 1629      */
 1630     if (rlen) {
 1631         ND_PRINT("\tMess TopTLV header: min %u, total %u advertised %u ",
 1632                TLV_HDRL, rlen, GET_BE_U_2(tltlv->length));
 1633         return -1;
 1634     }
 1635 
 1636     return 0;
 1637 }
 1638 
 1639 void
 1640 forces_print(netdissect_options *ndo,
 1641              const u_char * pptr, u_int len)
 1642 {
 1643     const struct forcesh *fhdr;
 1644     u_int mlen;
 1645     uint32_t flg_raw;
 1646     uint8_t tom;
 1647     const struct tom_h *tops;
 1648     int rc = 0;
 1649 
 1650     ndo->ndo_protocol = "forces";
 1651     fhdr = (const struct forcesh *)pptr;
 1652     ND_TCHECK_SIZE(fhdr);
 1653     tom = GET_U_1(fhdr->fm_tom);
 1654     if (!tom_valid(tom)) {
 1655         ND_PRINT("Invalid ForCES message type %u\n", tom);
 1656         goto error;
 1657     }
 1658 
 1659     mlen = ForCES_BLN(fhdr);
 1660 
 1661     tops = get_forces_tom(tom);
 1662     if (tops->v == TOM_RSVD) {
 1663         ND_PRINT("\n\tUnknown ForCES message type=0x%x", tom);
 1664         goto error;
 1665     }
 1666 
 1667     ND_PRINT("\n\tForCES %s ", tops->s);
 1668     if (!ForCES_HLN_VALID(mlen, len)) {
 1669         ND_PRINT("Illegal ForCES pkt len - min %u, total recvd %u, advertised %u ",
 1670                   ForCES_HDRL, len, ForCES_BLN(fhdr));
 1671         goto error;
 1672     }
 1673 
 1674     flg_raw = GET_BE_U_4(pptr + 20);
 1675     if (ndo->ndo_vflag >= 1) {
 1676         ND_PRINT("\n\tForCES Version %u len %uB flags 0x%08x ",
 1677                ForCES_V(fhdr), mlen, flg_raw);
 1678         ND_PRINT("\n\tSrcID 0x%x(%s) DstID 0x%x(%s) Correlator 0x%" PRIx64,
 1679                ForCES_SID(fhdr), ForCES_node(ForCES_SID(fhdr)),
 1680                ForCES_DID(fhdr), ForCES_node(ForCES_DID(fhdr)),
 1681                GET_BE_U_8(fhdr->fm_cor));
 1682 
 1683     }
 1684     if (ndo->ndo_vflag >= 2) {
 1685         ND_PRINT("\n\tForCES flags:\n\t  %s(0x%x), prio=%u, %s(0x%x),\n\t  %s(0x%x), %s(0x%x)\n",
 1686              tok2str(ForCES_ACKs, "ACKUnknown", ForCES_ACK(fhdr)),
 1687              ForCES_ACK(fhdr),
 1688              ForCES_PRI(fhdr),
 1689              tok2str(ForCES_EMs, "EMUnknown", ForCES_EM(fhdr)),
 1690              ForCES_EM(fhdr),
 1691              tok2str(ForCES_ATs, "ATUnknown", ForCES_AT(fhdr)),
 1692              ForCES_AT(fhdr),
 1693              tok2str(ForCES_TPs, "TPUnknown", ForCES_TP(fhdr)),
 1694              ForCES_TP(fhdr));
 1695         ND_PRINT("\t  Extra flags: rsv(b5-7) 0x%x rsv(b13-31) 0x%x\n",
 1696              ForCES_RS1(fhdr), ForCES_RS2(fhdr));
 1697     }
 1698     rc = forces_type_print(ndo, pptr, fhdr, mlen, tops);
 1699     if (rc < 0) {
 1700 error:
 1701         hex_print(ndo, "\n\t[", pptr, len);
 1702         ND_PRINT("\n\t]");
 1703         return;
 1704     }
 1705 
 1706     if (ndo->ndo_vflag >= 4) {
 1707         ND_PRINT("\n\t  Raw ForCES message\n\t [");
 1708         hex_print(ndo, "\n\t ", pptr, len);
 1709         ND_PRINT("\n\t ]");
 1710     }
 1711     return;
 1712 
 1713 trunc:
 1714     nd_print_trunc(ndo);
 1715 }