127bfbee1SPeter Avalos /*
227bfbee1SPeter Avalos * Redistribution and use in source and binary forms, with or without
327bfbee1SPeter Avalos * modification, are permitted provided that: (1) source code
427bfbee1SPeter Avalos * distributions retain the above copyright notice and this paragraph
527bfbee1SPeter Avalos * in its entirety, and (2) distributions including binary code include
627bfbee1SPeter Avalos * the above copyright notice and this paragraph in its entirety in
727bfbee1SPeter Avalos * the documentation or other materials provided with the distribution.
827bfbee1SPeter Avalos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
927bfbee1SPeter Avalos * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
1027bfbee1SPeter Avalos * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
1127bfbee1SPeter Avalos * FOR A PARTICULAR PURPOSE.
1227bfbee1SPeter Avalos *
1327bfbee1SPeter Avalos * Copyright (c) 2009 Mojatatu Networks, Inc
1427bfbee1SPeter Avalos *
1527bfbee1SPeter Avalos */
1627bfbee1SPeter Avalos
17411677aeSAaron LI /* \summary: Forwarding and Control Element Separation (ForCES) Protocol printer */
18411677aeSAaron LI
19411677aeSAaron LI /* specification: RFC 5810 */
20411677aeSAaron LI
2127bfbee1SPeter Avalos #ifdef HAVE_CONFIG_H
22*ed775ee7SAntonio Huete Jimenez #include <config.h>
2327bfbee1SPeter Avalos #endif
2427bfbee1SPeter Avalos
25*ed775ee7SAntonio Huete Jimenez #include "netdissect-stdinc.h"
2627bfbee1SPeter Avalos
27411677aeSAaron LI #include "netdissect.h"
2827bfbee1SPeter Avalos #include "extract.h"
2927bfbee1SPeter Avalos
30411677aeSAaron LI
31411677aeSAaron LI #define ForCES_VERS 1
32411677aeSAaron LI #define ForCES_HDRL 24
33411677aeSAaron LI #define ForCES_ALNL 4U
34411677aeSAaron LI #define TLV_HDRL 4
35411677aeSAaron LI #define ILV_HDRL 8
36411677aeSAaron LI
37411677aeSAaron LI #define TOM_RSVD 0x0
38411677aeSAaron LI #define TOM_ASSNSETUP 0x1
39411677aeSAaron LI #define TOM_ASSNTEARD 0x2
40411677aeSAaron LI #define TOM_CONFIG 0x3
41411677aeSAaron LI #define TOM_QUERY 0x4
42411677aeSAaron LI #define TOM_EVENTNOT 0x5
43411677aeSAaron LI #define TOM_PKTREDIR 0x6
44411677aeSAaron LI #define TOM_HEARTBT 0x0F
45411677aeSAaron LI #define TOM_ASSNSETREP 0x11
46411677aeSAaron LI #define TOM_CONFIGREP 0x13
47411677aeSAaron LI #define TOM_QUERYREP 0x14
48411677aeSAaron LI
49411677aeSAaron LI /*
50411677aeSAaron LI * tom_h Flags: resv1(8b):maxtlvs(4b):resv2(2b):mintlv(2b)
51411677aeSAaron LI */
52411677aeSAaron LI #define ZERO_TTLV 0x01
53411677aeSAaron LI #define ZERO_MORE_TTLV 0x02
54411677aeSAaron LI #define ONE_MORE_TTLV 0x04
55411677aeSAaron LI #define ZERO_TLV 0x00
56411677aeSAaron LI #define ONE_TLV 0x10
57411677aeSAaron LI #define TWO_TLV 0x20
58411677aeSAaron LI #define MAX_TLV 0xF0
59411677aeSAaron LI
60411677aeSAaron LI #define TTLV_T1 (ONE_MORE_TTLV|ONE_TLV)
61411677aeSAaron LI #define TTLV_T2 (ONE_MORE_TTLV|MAX_TLV)
62411677aeSAaron LI
63411677aeSAaron LI struct tom_h {
64411677aeSAaron LI uint32_t v;
65411677aeSAaron LI uint16_t flags;
66411677aeSAaron LI uint16_t op_msk;
67411677aeSAaron LI const char *s;
68*ed775ee7SAntonio Huete Jimenez int (*print) (netdissect_options *ndo, const u_char * pptr, u_int len,
69411677aeSAaron LI uint16_t op_msk, int indent);
70411677aeSAaron LI };
71411677aeSAaron LI
72411677aeSAaron LI enum {
73411677aeSAaron LI TOM_RSV_I,
74411677aeSAaron LI TOM_ASS_I,
75411677aeSAaron LI TOM_AST_I,
76411677aeSAaron LI TOM_CFG_I,
77411677aeSAaron LI TOM_QRY_I,
78411677aeSAaron LI TOM_EVN_I,
79411677aeSAaron LI TOM_RED_I,
80411677aeSAaron LI TOM_HBT_I,
81411677aeSAaron LI TOM_ASR_I,
82411677aeSAaron LI TOM_CNR_I,
83411677aeSAaron LI TOM_QRR_I,
84411677aeSAaron LI _TOM_RSV_MAX
85411677aeSAaron LI };
86411677aeSAaron LI #define TOM_MAX_IND (_TOM_RSV_MAX - 1)
87411677aeSAaron LI
88*ed775ee7SAntonio Huete Jimenez static int
tom_valid(uint8_t tom)89*ed775ee7SAntonio Huete Jimenez tom_valid(uint8_t tom)
90411677aeSAaron LI {
91411677aeSAaron LI if (tom > 0) {
92411677aeSAaron LI if (tom >= 0x7 && tom <= 0xe)
93411677aeSAaron LI return 0;
94411677aeSAaron LI if (tom == 0x10)
95411677aeSAaron LI return 0;
96411677aeSAaron LI if (tom > 0x14)
97411677aeSAaron LI return 0;
98411677aeSAaron LI return 1;
99411677aeSAaron LI } else
100411677aeSAaron LI return 0;
101411677aeSAaron LI }
102411677aeSAaron LI
103*ed775ee7SAntonio Huete Jimenez static const char *
ForCES_node(uint32_t node)104*ed775ee7SAntonio Huete Jimenez ForCES_node(uint32_t node)
105411677aeSAaron LI {
106411677aeSAaron LI if (node <= 0x3FFFFFFF)
107411677aeSAaron LI return "FE";
108411677aeSAaron LI if (node >= 0x40000000 && node <= 0x7FFFFFFF)
109411677aeSAaron LI return "CE";
110411677aeSAaron LI if (node >= 0xC0000000 && node <= 0xFFFFFFEF)
111411677aeSAaron LI return "AllMulticast";
112411677aeSAaron LI if (node == 0xFFFFFFFD)
113411677aeSAaron LI return "AllCEsBroadcast";
114411677aeSAaron LI if (node == 0xFFFFFFFE)
115411677aeSAaron LI return "AllFEsBroadcast";
116411677aeSAaron LI if (node == 0xFFFFFFFF)
117411677aeSAaron LI return "AllBroadcast";
118411677aeSAaron LI
119411677aeSAaron LI return "ForCESreserved";
120411677aeSAaron LI
121411677aeSAaron LI }
122411677aeSAaron LI
123411677aeSAaron LI static const struct tok ForCES_ACKs[] = {
124411677aeSAaron LI {0x0, "NoACK"},
125411677aeSAaron LI {0x1, "SuccessACK"},
126411677aeSAaron LI {0x2, "FailureACK"},
127411677aeSAaron LI {0x3, "AlwaysACK"},
128411677aeSAaron LI {0, NULL}
129411677aeSAaron LI };
130411677aeSAaron LI
131411677aeSAaron LI static const struct tok ForCES_EMs[] = {
132411677aeSAaron LI {0x0, "EMReserved"},
133411677aeSAaron LI {0x1, "execute-all-or-none"},
134411677aeSAaron LI {0x2, "execute-until-failure"},
135411677aeSAaron LI {0x3, "continue-execute-on-failure"},
136411677aeSAaron LI {0, NULL}
137411677aeSAaron LI };
138411677aeSAaron LI
139411677aeSAaron LI static const struct tok ForCES_ATs[] = {
140411677aeSAaron LI {0x0, "Standalone"},
141411677aeSAaron LI {0x1, "2PCtransaction"},
142411677aeSAaron LI {0, NULL}
143411677aeSAaron LI };
144411677aeSAaron LI
145411677aeSAaron LI static const struct tok ForCES_TPs[] = {
146411677aeSAaron LI {0x0, "StartofTransaction"},
147411677aeSAaron LI {0x1, "MiddleofTransaction"},
148411677aeSAaron LI {0x2, "EndofTransaction"},
149411677aeSAaron LI {0x3, "abort"},
150411677aeSAaron LI {0, NULL}
151411677aeSAaron LI };
152411677aeSAaron LI
153411677aeSAaron LI /*
154411677aeSAaron LI * Structure of forces header, naked of TLVs.
155411677aeSAaron LI */
156411677aeSAaron LI struct forcesh {
157411677aeSAaron LI nd_uint8_t fm_vrsvd; /* version and reserved */
158*ed775ee7SAntonio Huete Jimenez #define ForCES_V(forcesh) (GET_U_1((forcesh)->fm_vrsvd) >> 4)
159411677aeSAaron LI nd_uint8_t fm_tom; /* type of message */
160411677aeSAaron LI nd_uint16_t fm_len; /* total length * 4 bytes */
161*ed775ee7SAntonio Huete Jimenez #define ForCES_BLN(forcesh) ((uint32_t)(GET_BE_U_2((forcesh)->fm_len) << 2))
162411677aeSAaron LI nd_uint32_t fm_sid; /* Source ID */
163*ed775ee7SAntonio Huete Jimenez #define ForCES_SID(forcesh) GET_BE_U_4((forcesh)->fm_sid)
164411677aeSAaron LI nd_uint32_t fm_did; /* Destination ID */
165*ed775ee7SAntonio Huete Jimenez #define ForCES_DID(forcesh) GET_BE_U_4((forcesh)->fm_did)
166411677aeSAaron LI nd_uint8_t fm_cor[8]; /* correlator */
167411677aeSAaron LI nd_uint32_t fm_flags; /* flags */
168*ed775ee7SAntonio Huete Jimenez #define ForCES_ACK(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0xC0000000) >> 30)
169*ed775ee7SAntonio Huete Jimenez #define ForCES_PRI(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x38000000) >> 27)
170*ed775ee7SAntonio Huete Jimenez #define ForCES_RS1(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x07000000) >> 24)
171*ed775ee7SAntonio Huete Jimenez #define ForCES_EM(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x00C00000) >> 22)
172*ed775ee7SAntonio Huete Jimenez #define ForCES_AT(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x00200000) >> 21)
173*ed775ee7SAntonio Huete Jimenez #define ForCES_TP(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x00180000) >> 19)
174*ed775ee7SAntonio Huete Jimenez #define ForCES_RS2(forcesh) ((GET_BE_U_4((forcesh)->fm_flags)&0x0007FFFF) >> 0)
175411677aeSAaron LI };
176411677aeSAaron LI
177411677aeSAaron LI #define ForCES_HLN_VALID(fhl,tlen) ((tlen) >= ForCES_HDRL && \
178411677aeSAaron LI (fhl) >= ForCES_HDRL && \
179411677aeSAaron LI (fhl) == (tlen))
180411677aeSAaron LI
181411677aeSAaron LI #define F_LFB_RSVD 0x0
182411677aeSAaron LI #define F_LFB_FEO 0x1
183411677aeSAaron LI #define F_LFB_FEPO 0x2
184411677aeSAaron LI static const struct tok ForCES_LFBs[] = {
185411677aeSAaron LI {F_LFB_RSVD, "Invalid TLV"},
186411677aeSAaron LI {F_LFB_FEO, "FEObj LFB"},
187411677aeSAaron LI {F_LFB_FEPO, "FEProtoObj LFB"},
188411677aeSAaron LI {0, NULL}
189411677aeSAaron LI };
190411677aeSAaron LI
191411677aeSAaron LI /* this is defined in RFC5810 section A.2 */
192*ed775ee7SAntonio Huete Jimenez /* https://www.iana.org/assignments/forces/forces.xhtml#oper-tlv-types */
193411677aeSAaron LI enum {
194411677aeSAaron LI F_OP_RSV = 0,
195411677aeSAaron LI F_OP_SET = 1,
196411677aeSAaron LI F_OP_SETPROP = 2,
197411677aeSAaron LI F_OP_SETRESP = 3,
198411677aeSAaron LI F_OP_SETPRESP = 4,
199411677aeSAaron LI F_OP_DEL = 5,
200411677aeSAaron LI F_OP_DELRESP = 6,
201411677aeSAaron LI F_OP_GET = 7,
202411677aeSAaron LI F_OP_GETPROP = 8,
203411677aeSAaron LI F_OP_GETRESP = 9,
204411677aeSAaron LI F_OP_GETPRESP = 10,
205411677aeSAaron LI F_OP_REPORT = 11,
206411677aeSAaron LI F_OP_COMMIT = 12,
207411677aeSAaron LI F_OP_RCOMMIT = 13,
208411677aeSAaron LI F_OP_RTRCOMP = 14,
209411677aeSAaron LI _F_OP_MAX
210411677aeSAaron LI };
211411677aeSAaron LI #define F_OP_MAX (_F_OP_MAX - 1)
212411677aeSAaron LI
213411677aeSAaron LI enum {
214411677aeSAaron LI B_OP_SET = 1 << (F_OP_SET - 1),
215411677aeSAaron LI B_OP_SETPROP = 1 << (F_OP_SETPROP - 1),
216411677aeSAaron LI B_OP_SETRESP = 1 << (F_OP_SETRESP - 1),
217411677aeSAaron LI B_OP_SETPRESP = 1 << (F_OP_SETPRESP - 1),
218411677aeSAaron LI B_OP_DEL = 1 << (F_OP_DEL - 1),
219411677aeSAaron LI B_OP_DELRESP = 1 << (F_OP_DELRESP - 1),
220411677aeSAaron LI B_OP_GET = 1 << (F_OP_GET - 1),
221411677aeSAaron LI B_OP_GETPROP = 1 << (F_OP_GETPROP - 1),
222411677aeSAaron LI B_OP_GETRESP = 1 << (F_OP_GETRESP - 1),
223411677aeSAaron LI B_OP_GETPRESP = 1 << (F_OP_GETPRESP - 1),
224411677aeSAaron LI B_OP_REPORT = 1 << (F_OP_REPORT - 1),
225411677aeSAaron LI B_OP_COMMIT = 1 << (F_OP_COMMIT - 1),
226411677aeSAaron LI B_OP_RCOMMIT = 1 << (F_OP_RCOMMIT - 1),
227411677aeSAaron LI B_OP_RTRCOMP = 1 << (F_OP_RTRCOMP - 1)
228411677aeSAaron LI };
229411677aeSAaron LI
230411677aeSAaron LI struct optlv_h {
231411677aeSAaron LI uint16_t flags;
232411677aeSAaron LI uint16_t op_msk;
233411677aeSAaron LI const char *s;
234*ed775ee7SAntonio Huete Jimenez int (*print) (netdissect_options *ndo, const u_char * pptr, u_int len,
235411677aeSAaron LI uint16_t op_msk, int indent);
236411677aeSAaron LI };
237411677aeSAaron LI
238*ed775ee7SAntonio Huete Jimenez static int genoptlv_print(netdissect_options *, const u_char * pptr, u_int len,
239411677aeSAaron LI uint16_t op_msk, int indent);
240*ed775ee7SAntonio Huete Jimenez static int recpdoptlv_print(netdissect_options *, const u_char * pptr, u_int len,
241411677aeSAaron LI uint16_t op_msk, int indent);
242*ed775ee7SAntonio Huete Jimenez static int invoptlv_print(netdissect_options *, const u_char * pptr, u_int len,
243411677aeSAaron LI uint16_t op_msk, int indent);
244411677aeSAaron LI
245411677aeSAaron LI #define OP_MIN_SIZ 8
246411677aeSAaron LI struct pathdata_h {
247411677aeSAaron LI nd_uint16_t pflags;
248411677aeSAaron LI nd_uint16_t pIDcnt;
249411677aeSAaron LI };
250411677aeSAaron LI
251411677aeSAaron LI #define B_FULLD 0x1
252411677aeSAaron LI #define B_SPARD 0x2
253411677aeSAaron LI #define B_RESTV 0x4
254411677aeSAaron LI #define B_KEYIN 0x8
255411677aeSAaron LI #define B_APPND 0x10
256411677aeSAaron LI #define B_TRNG 0x20
257411677aeSAaron LI
258411677aeSAaron LI static const struct optlv_h OPTLV_msg[F_OP_MAX + 1] = {
259411677aeSAaron LI /* F_OP_RSV */ {ZERO_TTLV, 0, "Invalid OPTLV", invoptlv_print},
260411677aeSAaron LI /* F_OP_SET */ {TTLV_T2, B_FULLD | B_SPARD, " Set", recpdoptlv_print},
261411677aeSAaron LI /* F_OP_SETPROP */
262411677aeSAaron LI {TTLV_T2, B_FULLD | B_SPARD, " SetProp", recpdoptlv_print},
263411677aeSAaron LI /* F_OP_SETRESP */ {TTLV_T2, B_RESTV, " SetResp", recpdoptlv_print},
264411677aeSAaron LI /* F_OP_SETPRESP */ {TTLV_T2, B_RESTV, " SetPropResp", recpdoptlv_print},
265411677aeSAaron LI /* F_OP_DEL */ {ZERO_TTLV, 0, " Del", recpdoptlv_print},
266411677aeSAaron LI /* F_OP_DELRESP */ {TTLV_T2, B_RESTV, " DelResp", recpdoptlv_print},
267411677aeSAaron LI /* F_OP_GET */ {ZERO_TTLV, 0, " Get", recpdoptlv_print},
268411677aeSAaron LI /* F_OP_GETPROP */ {ZERO_TTLV, 0, " GetProp", recpdoptlv_print},
269411677aeSAaron LI /* F_OP_GETRESP */
270411677aeSAaron LI {TTLV_T2, B_FULLD | B_SPARD | B_RESTV, " GetResp", recpdoptlv_print},
271411677aeSAaron LI /* F_OP_GETPRESP */
272411677aeSAaron LI {TTLV_T2, B_FULLD | B_RESTV, " GetPropResp", recpdoptlv_print},
273411677aeSAaron LI /* F_OP_REPORT */
274411677aeSAaron LI {TTLV_T2, B_FULLD | B_SPARD, " Report", recpdoptlv_print},
275411677aeSAaron LI /* F_OP_COMMIT */ {ZERO_TTLV, 0, " Commit", NULL},
276411677aeSAaron LI /* F_OP_RCOMMIT */ {TTLV_T1, B_RESTV, " RCommit", genoptlv_print},
277411677aeSAaron LI /* F_OP_RTRCOMP */ {ZERO_TTLV, 0, " RTRCOMP", NULL},
278411677aeSAaron LI };
279411677aeSAaron LI
280*ed775ee7SAntonio Huete Jimenez static const struct optlv_h *
get_forces_optlv_h(uint16_t opt)281*ed775ee7SAntonio Huete Jimenez get_forces_optlv_h(uint16_t opt)
282411677aeSAaron LI {
283*ed775ee7SAntonio Huete Jimenez if (opt > F_OP_MAX || opt == F_OP_RSV)
284411677aeSAaron LI return &OPTLV_msg[F_OP_RSV];
285411677aeSAaron LI
286411677aeSAaron LI return &OPTLV_msg[opt];
287411677aeSAaron LI }
288411677aeSAaron LI
289411677aeSAaron LI #define IND_SIZE 256
290411677aeSAaron LI #define IND_CHR ' '
291411677aeSAaron LI #define IND_PREF '\n'
292411677aeSAaron LI #define IND_SUF 0x0
293411677aeSAaron LI static char ind_buf[IND_SIZE];
294411677aeSAaron LI
295*ed775ee7SAntonio Huete Jimenez static char *
indent_pr(int indent,int nlpref)296*ed775ee7SAntonio Huete Jimenez indent_pr(int indent, int nlpref)
297411677aeSAaron LI {
298411677aeSAaron LI int i = 0;
299411677aeSAaron LI char *r = ind_buf;
300411677aeSAaron LI
301411677aeSAaron LI if (indent > (IND_SIZE - 1))
302411677aeSAaron LI indent = IND_SIZE - 1;
303411677aeSAaron LI
304411677aeSAaron LI if (nlpref) {
305411677aeSAaron LI r[i] = IND_PREF;
306411677aeSAaron LI i++;
307411677aeSAaron LI indent--;
308411677aeSAaron LI }
309411677aeSAaron LI
310411677aeSAaron LI while (--indent >= 0)
311411677aeSAaron LI r[i++] = IND_CHR;
312411677aeSAaron LI
313411677aeSAaron LI r[i] = IND_SUF;
314411677aeSAaron LI return r;
315411677aeSAaron LI }
316411677aeSAaron LI
317*ed775ee7SAntonio Huete Jimenez static int
op_valid(uint16_t op,uint16_t mask)318*ed775ee7SAntonio Huete Jimenez op_valid(uint16_t op, uint16_t mask)
319411677aeSAaron LI {
320411677aeSAaron LI if (op == 0)
321411677aeSAaron LI return 0;
322*ed775ee7SAntonio Huete Jimenez if (op <= F_OP_MAX)
323*ed775ee7SAntonio Huete Jimenez return (1 << (op - 1)) & mask; /* works only for 0x0001 through 0x0010 */
324411677aeSAaron LI /* I guess we should allow vendor operations? */
325411677aeSAaron LI if (op >= 0x8000)
326411677aeSAaron LI return 1;
327411677aeSAaron LI return 0;
328411677aeSAaron LI }
329411677aeSAaron LI
330411677aeSAaron LI #define F_TLV_RSVD 0x0000
331411677aeSAaron LI #define F_TLV_REDR 0x0001
332411677aeSAaron LI #define F_TLV_ASRS 0x0010
333411677aeSAaron LI #define F_TLV_ASRT 0x0011
334411677aeSAaron LI #define F_TLV_LFBS 0x1000
335411677aeSAaron LI #define F_TLV_PDAT 0x0110
336411677aeSAaron LI #define F_TLV_KEYI 0x0111
337411677aeSAaron LI #define F_TLV_FULD 0x0112
338411677aeSAaron LI #define F_TLV_SPAD 0x0113
339411677aeSAaron LI #define F_TLV_REST 0x0114
340411677aeSAaron LI #define F_TLV_METD 0x0115
341411677aeSAaron LI #define F_TLV_REDD 0x0116
342411677aeSAaron LI #define F_TLV_TRNG 0x0117
343411677aeSAaron LI
344411677aeSAaron LI
345411677aeSAaron LI #define F_TLV_VNST 0x8000
346411677aeSAaron LI
347411677aeSAaron LI static const struct tok ForCES_TLV[] = {
348411677aeSAaron LI {F_TLV_RSVD, "Invalid TLV"},
349411677aeSAaron LI {F_TLV_REDR, "REDIRECT TLV"},
350411677aeSAaron LI {F_TLV_ASRS, "ASResult TLV"},
351411677aeSAaron LI {F_TLV_ASRT, "ASTreason TLV"},
352411677aeSAaron LI {F_TLV_LFBS, "LFBselect TLV"},
353411677aeSAaron LI {F_TLV_PDAT, "PATH-DATA TLV"},
354411677aeSAaron LI {F_TLV_KEYI, "KEYINFO TLV"},
355411677aeSAaron LI {F_TLV_FULD, "FULLDATA TLV"},
356411677aeSAaron LI {F_TLV_SPAD, "SPARSEDATA TLV"},
357411677aeSAaron LI {F_TLV_REST, "RESULT TLV"},
358411677aeSAaron LI {F_TLV_METD, "METADATA TLV"},
359411677aeSAaron LI {F_TLV_REDD, "REDIRECTDATA TLV"},
360411677aeSAaron LI {0, NULL}
361411677aeSAaron LI };
362411677aeSAaron LI
363411677aeSAaron LI #define TLV_HLN 4
364*ed775ee7SAntonio Huete Jimenez static int
ttlv_valid(uint16_t ttlv)365*ed775ee7SAntonio Huete Jimenez ttlv_valid(uint16_t ttlv)
366411677aeSAaron LI {
367411677aeSAaron LI if (ttlv > 0) {
368411677aeSAaron LI if (ttlv == 1 || ttlv == 0x1000)
369411677aeSAaron LI return 1;
370411677aeSAaron LI if (ttlv >= 0x10 && ttlv <= 0x11)
371411677aeSAaron LI return 1;
372411677aeSAaron LI if (ttlv >= 0x110 && ttlv <= 0x116)
373411677aeSAaron LI return 1;
374411677aeSAaron LI if (ttlv >= 0x8000)
375411677aeSAaron LI return 0; /* XXX: */
376411677aeSAaron LI }
377411677aeSAaron LI
378411677aeSAaron LI return 0;
379411677aeSAaron LI }
380411677aeSAaron LI
381411677aeSAaron LI struct forces_ilv {
382411677aeSAaron LI nd_uint32_t type;
383411677aeSAaron LI nd_uint32_t length;
384411677aeSAaron LI };
385411677aeSAaron LI
386411677aeSAaron LI struct forces_tlv {
387411677aeSAaron LI nd_uint16_t type;
388411677aeSAaron LI nd_uint16_t length;
389411677aeSAaron LI };
390411677aeSAaron LI
391*ed775ee7SAntonio Huete Jimenez #define F_ALN_LEN(len) roundup2(len, ForCES_ALNL)
392411677aeSAaron LI #define GET_TOP_TLV(fhdr) ((const struct forces_tlv *)((fhdr) + sizeof (struct forcesh)))
393411677aeSAaron LI #define TLV_SET_LEN(len) (F_ALN_LEN(TLV_HDRL) + (len))
394411677aeSAaron LI #define TLV_DATA(tlvp) ((const void*)(((const char*)(tlvp)) + TLV_SET_LEN(0)))
395*ed775ee7SAntonio Huete Jimenez #define GO_NXT_TLV(tlv,rlen) ((rlen) -= F_ALN_LEN(GET_BE_U_2((tlv)->length)), \
396411677aeSAaron LI (const struct forces_tlv*)(((const char*)(tlv)) \
397*ed775ee7SAntonio Huete Jimenez + F_ALN_LEN(GET_BE_U_2((tlv)->length))))
398411677aeSAaron LI #define ILV_SET_LEN(len) (F_ALN_LEN(ILV_HDRL) + (len))
399411677aeSAaron LI #define ILV_DATA(ilvp) ((const void*)(((const char*)(ilvp)) + ILV_SET_LEN(0)))
400*ed775ee7SAntonio Huete Jimenez #define GO_NXT_ILV(ilv,rlen) ((rlen) -= F_ALN_LEN(GET_BE_U_4((ilv)->length)), \
401411677aeSAaron LI (const struct forces_ilv *)(((const char*)(ilv)) \
402*ed775ee7SAntonio Huete Jimenez + F_ALN_LEN(GET_BE_U_4((ilv)->length))))
403411677aeSAaron LI #define INVALID_RLEN 1
404411677aeSAaron LI #define INVALID_STLN 2
405411677aeSAaron LI #define INVALID_LTLN 3
406411677aeSAaron LI #define INVALID_ALEN 4
407411677aeSAaron LI
408411677aeSAaron LI static const struct tok ForCES_TLV_err[] = {
409411677aeSAaron LI {INVALID_RLEN, "Invalid total length"},
410411677aeSAaron LI {INVALID_STLN, "xLV too short"},
411411677aeSAaron LI {INVALID_LTLN, "xLV too long"},
412411677aeSAaron LI {INVALID_ALEN, "data padding missing"},
413411677aeSAaron LI {0, NULL}
414411677aeSAaron LI };
415411677aeSAaron LI
416*ed775ee7SAntonio Huete Jimenez static u_int
tlv_valid(u_int tlvl,u_int rlen)417*ed775ee7SAntonio Huete Jimenez tlv_valid(u_int tlvl, u_int rlen)
418411677aeSAaron LI {
419411677aeSAaron LI if (rlen < TLV_HDRL)
420411677aeSAaron LI return INVALID_RLEN;
421*ed775ee7SAntonio Huete Jimenez if (tlvl < TLV_HDRL)
422411677aeSAaron LI return INVALID_STLN;
423*ed775ee7SAntonio Huete Jimenez if (tlvl > rlen)
424411677aeSAaron LI return INVALID_LTLN;
425*ed775ee7SAntonio Huete Jimenez if (rlen < F_ALN_LEN(tlvl))
426411677aeSAaron LI return INVALID_ALEN;
427411677aeSAaron LI
428411677aeSAaron LI return 0;
429411677aeSAaron LI }
430411677aeSAaron LI
431*ed775ee7SAntonio Huete Jimenez static int
ilv_valid(netdissect_options * ndo,const struct forces_ilv * ilv,u_int rlen)432*ed775ee7SAntonio Huete Jimenez ilv_valid(netdissect_options *ndo, const struct forces_ilv *ilv, u_int rlen)
433411677aeSAaron LI {
434411677aeSAaron LI if (rlen < ILV_HDRL)
435411677aeSAaron LI return INVALID_RLEN;
436*ed775ee7SAntonio Huete Jimenez if (GET_BE_U_4(ilv->length) < ILV_HDRL)
437411677aeSAaron LI return INVALID_STLN;
438*ed775ee7SAntonio Huete Jimenez if (GET_BE_U_4(ilv->length) > rlen)
439411677aeSAaron LI return INVALID_LTLN;
440*ed775ee7SAntonio Huete Jimenez if (rlen < F_ALN_LEN(GET_BE_U_4(ilv->length)))
441411677aeSAaron LI return INVALID_ALEN;
442411677aeSAaron LI
443411677aeSAaron LI return 0;
444411677aeSAaron LI }
445411677aeSAaron LI
446*ed775ee7SAntonio Huete Jimenez static int lfbselect_print(netdissect_options *, const u_char * pptr, u_int len,
447411677aeSAaron LI uint16_t op_msk, int indent);
448*ed775ee7SAntonio Huete Jimenez static int redirect_print(netdissect_options *, const u_char * pptr, u_int len,
449411677aeSAaron LI uint16_t op_msk, int indent);
450*ed775ee7SAntonio Huete Jimenez static int asrtlv_print(netdissect_options *, const u_char * pptr, u_int len,
451411677aeSAaron LI uint16_t op_msk, int indent);
452*ed775ee7SAntonio Huete Jimenez static int asttlv_print(netdissect_options *, const u_char * pptr, u_int len,
453411677aeSAaron LI uint16_t op_msk, int indent);
454411677aeSAaron LI
455411677aeSAaron LI struct forces_lfbsh {
456411677aeSAaron LI nd_uint32_t class;
457411677aeSAaron LI nd_uint32_t instance;
458411677aeSAaron LI };
459411677aeSAaron LI
460411677aeSAaron LI #define ASSNS_OPS (B_OP_REPORT)
461411677aeSAaron LI #define CFG_OPS (B_OP_SET|B_OP_SETPROP|B_OP_DEL|B_OP_COMMIT|B_OP_RTRCOMP)
462411677aeSAaron LI #define CFG_ROPS (B_OP_SETRESP|B_OP_SETPRESP|B_OP_DELRESP|B_OP_RCOMMIT)
463411677aeSAaron LI #define CFG_QY (B_OP_GET|B_OP_GETPROP)
464411677aeSAaron LI #define CFG_QYR (B_OP_GETRESP|B_OP_GETPRESP)
465411677aeSAaron LI #define CFG_EVN (B_OP_REPORT)
466411677aeSAaron LI
467411677aeSAaron LI static const struct tom_h ForCES_msg[TOM_MAX_IND + 1] = {
468411677aeSAaron LI /* TOM_RSV_I */ {TOM_RSVD, ZERO_TTLV, 0, "Invalid message", NULL},
469411677aeSAaron LI /* TOM_ASS_I */ {TOM_ASSNSETUP, ZERO_MORE_TTLV | TWO_TLV, ASSNS_OPS,
470411677aeSAaron LI "Association Setup", lfbselect_print},
471411677aeSAaron LI /* TOM_AST_I */
472411677aeSAaron LI {TOM_ASSNTEARD, TTLV_T1, 0, "Association TearDown", asttlv_print},
473411677aeSAaron LI /* TOM_CFG_I */ {TOM_CONFIG, TTLV_T2, CFG_OPS, "Config", lfbselect_print},
474411677aeSAaron LI /* TOM_QRY_I */ {TOM_QUERY, TTLV_T2, CFG_QY, "Query", lfbselect_print},
475411677aeSAaron LI /* TOM_EVN_I */ {TOM_EVENTNOT, TTLV_T1, CFG_EVN, "Event Notification",
476411677aeSAaron LI lfbselect_print},
477411677aeSAaron LI /* TOM_RED_I */
478411677aeSAaron LI {TOM_PKTREDIR, TTLV_T2, 0, "Packet Redirect", redirect_print},
479411677aeSAaron LI /* TOM_HBT_I */ {TOM_HEARTBT, ZERO_TTLV, 0, "HeartBeat", NULL},
480411677aeSAaron LI /* TOM_ASR_I */
481411677aeSAaron LI {TOM_ASSNSETREP, TTLV_T1, 0, "Association Response", asrtlv_print},
482411677aeSAaron LI /* TOM_CNR_I */ {TOM_CONFIGREP, TTLV_T2, CFG_ROPS, "Config Response",
483411677aeSAaron LI lfbselect_print},
484411677aeSAaron LI /* TOM_QRR_I */
485411677aeSAaron LI {TOM_QUERYREP, TTLV_T2, CFG_QYR, "Query Response", lfbselect_print},
486411677aeSAaron LI };
487411677aeSAaron LI
488*ed775ee7SAntonio Huete Jimenez static const struct tom_h *
get_forces_tom(uint8_t tom)489*ed775ee7SAntonio Huete Jimenez get_forces_tom(uint8_t tom)
490411677aeSAaron LI {
491411677aeSAaron LI int i;
492411677aeSAaron LI for (i = TOM_RSV_I; i <= TOM_MAX_IND; i++) {
493411677aeSAaron LI const struct tom_h *th = &ForCES_msg[i];
494411677aeSAaron LI if (th->v == tom)
495411677aeSAaron LI return th;
496411677aeSAaron LI }
497411677aeSAaron LI return &ForCES_msg[TOM_RSV_I];
498411677aeSAaron LI }
499411677aeSAaron LI
500411677aeSAaron LI struct pdata_ops {
501411677aeSAaron LI uint32_t v;
502411677aeSAaron LI uint16_t flags;
503411677aeSAaron LI uint16_t op_msk;
504411677aeSAaron LI const char *s;
505*ed775ee7SAntonio Huete Jimenez int (*print) (netdissect_options *, const u_char * pptr, u_int len,
506411677aeSAaron LI uint16_t op_msk, int indent);
507411677aeSAaron LI };
508411677aeSAaron LI
509411677aeSAaron LI enum {
510411677aeSAaron LI PD_RSV_I,
511411677aeSAaron LI PD_SEL_I,
512411677aeSAaron LI PD_FDT_I,
513411677aeSAaron LI PD_SDT_I,
514411677aeSAaron LI PD_RES_I,
515411677aeSAaron LI PD_PDT_I,
516411677aeSAaron LI _PD_RSV_MAX
517411677aeSAaron LI };
518411677aeSAaron LI #define PD_MAX_IND (_TOM_RSV_MAX - 1)
519411677aeSAaron LI
520*ed775ee7SAntonio Huete Jimenez static int
pd_valid(uint16_t pd)521*ed775ee7SAntonio Huete Jimenez pd_valid(uint16_t pd)
522411677aeSAaron LI {
523411677aeSAaron LI if (pd >= F_TLV_PDAT && pd <= F_TLV_REST)
524411677aeSAaron LI return 1;
525411677aeSAaron LI return 0;
526411677aeSAaron LI }
527411677aeSAaron LI
528*ed775ee7SAntonio Huete Jimenez static void
chk_op_type(netdissect_options * ndo,uint16_t type,uint16_t msk,uint16_t omsk)529411677aeSAaron LI chk_op_type(netdissect_options *ndo,
530411677aeSAaron LI uint16_t type, uint16_t msk, uint16_t omsk)
531411677aeSAaron LI {
532411677aeSAaron LI if (type != F_TLV_PDAT) {
533411677aeSAaron LI if (msk & B_KEYIN) {
534411677aeSAaron LI if (type != F_TLV_KEYI) {
535*ed775ee7SAntonio Huete Jimenez ND_PRINT("Based on flags expected KEYINFO TLV!\n");
536411677aeSAaron LI }
537411677aeSAaron LI } else {
538411677aeSAaron LI if (!(msk & omsk)) {
539*ed775ee7SAntonio Huete Jimenez ND_PRINT("Illegal DATA encoding for type 0x%x programmed %x got %x\n",
540*ed775ee7SAntonio Huete Jimenez type, omsk, msk);
541411677aeSAaron LI }
542411677aeSAaron LI }
543411677aeSAaron LI }
544411677aeSAaron LI
545411677aeSAaron LI }
546411677aeSAaron LI
547411677aeSAaron LI #define F_SELKEY 1
548411677aeSAaron LI #define F_SELTABRANGE 2
549411677aeSAaron LI #define F_TABAPPEND 4
550411677aeSAaron LI
551411677aeSAaron LI struct res_val {
552411677aeSAaron LI nd_uint8_t result;
553411677aeSAaron LI nd_uint8_t resv1;
554411677aeSAaron LI nd_uint16_t resv2;
555411677aeSAaron LI };
556411677aeSAaron LI
557*ed775ee7SAntonio Huete Jimenez static int prestlv_print(netdissect_options *, const u_char * pptr, u_int len,
558411677aeSAaron LI uint16_t op_msk, int indent);
559*ed775ee7SAntonio Huete Jimenez static int pkeyitlv_print(netdissect_options *, const u_char * pptr, u_int len,
560411677aeSAaron LI uint16_t op_msk, int indent);
561*ed775ee7SAntonio Huete Jimenez static int fdatatlv_print(netdissect_options *, const u_char * pptr, u_int len,
562411677aeSAaron LI uint16_t op_msk, int indent);
563*ed775ee7SAntonio Huete Jimenez static int sdatatlv_print(netdissect_options *, const u_char * pptr, u_int len,
564411677aeSAaron LI uint16_t op_msk, int indent);
565411677aeSAaron LI
566411677aeSAaron LI static const struct pdata_ops ForCES_pdata[PD_MAX_IND + 1] = {
567411677aeSAaron LI /* PD_RSV_I */ {0, 0, 0, "Invalid message", NULL},
568411677aeSAaron LI /* PD_SEL_I */ {F_TLV_KEYI, 0, 0, "KEYINFO TLV", pkeyitlv_print},
569411677aeSAaron LI /* PD_FDT_I */ {F_TLV_FULD, 0, B_FULLD, "FULLDATA TLV", fdatatlv_print},
570411677aeSAaron LI /* PD_SDT_I */ {F_TLV_SPAD, 0, B_SPARD, "SPARSEDATA TLV", sdatatlv_print},
571411677aeSAaron LI /* PD_RES_I */ {F_TLV_REST, 0, B_RESTV, "RESULT TLV", prestlv_print},
572411677aeSAaron LI /* PD_PDT_I */
573411677aeSAaron LI {F_TLV_PDAT, 0, 0, "Inner PATH-DATA TLV", recpdoptlv_print},
574411677aeSAaron LI };
575411677aeSAaron LI
576*ed775ee7SAntonio Huete Jimenez static const struct pdata_ops *
get_forces_pd(uint16_t pd)577*ed775ee7SAntonio Huete Jimenez get_forces_pd(uint16_t pd)
578411677aeSAaron LI {
579411677aeSAaron LI int i;
580411677aeSAaron LI for (i = PD_RSV_I + 1; i <= PD_MAX_IND; i++) {
581411677aeSAaron LI const struct pdata_ops *pdo = &ForCES_pdata[i];
582411677aeSAaron LI if (pdo->v == pd)
583411677aeSAaron LI return pdo;
584411677aeSAaron LI }
585411677aeSAaron LI return &ForCES_pdata[TOM_RSV_I];
586411677aeSAaron LI }
587411677aeSAaron LI
588411677aeSAaron LI enum {
589411677aeSAaron LI E_SUCCESS,
590411677aeSAaron LI E_INVALID_HEADER,
591411677aeSAaron LI E_LENGTH_MISMATCH,
592411677aeSAaron LI E_VERSION_MISMATCH,
593411677aeSAaron LI E_INVALID_DESTINATION_PID,
594411677aeSAaron LI E_LFB_UNKNOWN,
595411677aeSAaron LI E_LFB_NOT_FOUND,
596411677aeSAaron LI E_LFB_INSTANCE_ID_NOT_FOUND,
597411677aeSAaron LI E_INVALID_PATH,
598411677aeSAaron LI E_COMPONENT_DOES_NOT_EXIST,
599411677aeSAaron LI E_EXISTS,
600411677aeSAaron LI E_NOT_FOUND,
601411677aeSAaron LI E_READ_ONLY,
602411677aeSAaron LI E_INVALID_ARRAY_CREATION,
603411677aeSAaron LI E_VALUE_OUT_OF_RANGE,
604411677aeSAaron LI E_CONTENTS_TOO_LONG,
605411677aeSAaron LI E_INVALID_PARAMETERS,
606411677aeSAaron LI E_INVALID_MESSAGE_TYPE,
607411677aeSAaron LI E_INVALID_FLAGS,
608411677aeSAaron LI E_INVALID_TLV,
609411677aeSAaron LI E_EVENT_ERROR,
610411677aeSAaron LI E_NOT_SUPPORTED,
611411677aeSAaron LI E_MEMORY_ERROR,
612411677aeSAaron LI E_INTERNAL_ERROR,
613411677aeSAaron LI /* 0x18-0xFE are reserved .. */
614411677aeSAaron LI E_UNSPECIFIED_ERROR = 0XFF
615411677aeSAaron LI };
616411677aeSAaron LI
617411677aeSAaron LI static const struct tok ForCES_errs[] = {
618411677aeSAaron LI {E_SUCCESS, "SUCCESS"},
619411677aeSAaron LI {E_INVALID_HEADER, "INVALID HEADER"},
620411677aeSAaron LI {E_LENGTH_MISMATCH, "LENGTH MISMATCH"},
621411677aeSAaron LI {E_VERSION_MISMATCH, "VERSION MISMATCH"},
622411677aeSAaron LI {E_INVALID_DESTINATION_PID, "INVALID DESTINATION PID"},
623411677aeSAaron LI {E_LFB_UNKNOWN, "LFB UNKNOWN"},
624411677aeSAaron LI {E_LFB_NOT_FOUND, "LFB NOT FOUND"},
625411677aeSAaron LI {E_LFB_INSTANCE_ID_NOT_FOUND, "LFB INSTANCE ID NOT FOUND"},
626411677aeSAaron LI {E_INVALID_PATH, "INVALID PATH"},
627411677aeSAaron LI {E_COMPONENT_DOES_NOT_EXIST, "COMPONENT DOES NOT EXIST"},
628411677aeSAaron LI {E_EXISTS, "EXISTS ALREADY"},
629411677aeSAaron LI {E_NOT_FOUND, "NOT FOUND"},
630411677aeSAaron LI {E_READ_ONLY, "READ ONLY"},
631411677aeSAaron LI {E_INVALID_ARRAY_CREATION, "INVALID ARRAY CREATION"},
632411677aeSAaron LI {E_VALUE_OUT_OF_RANGE, "VALUE OUT OF RANGE"},
633411677aeSAaron LI {E_CONTENTS_TOO_LONG, "CONTENTS TOO LONG"},
634411677aeSAaron LI {E_INVALID_PARAMETERS, "INVALID PARAMETERS"},
635411677aeSAaron LI {E_INVALID_MESSAGE_TYPE, "INVALID MESSAGE TYPE"},
636411677aeSAaron LI {E_INVALID_FLAGS, "INVALID FLAGS"},
637411677aeSAaron LI {E_INVALID_TLV, "INVALID TLV"},
638411677aeSAaron LI {E_EVENT_ERROR, "EVENT ERROR"},
639411677aeSAaron LI {E_NOT_SUPPORTED, "NOT SUPPORTED"},
640411677aeSAaron LI {E_MEMORY_ERROR, "MEMORY ERROR"},
641411677aeSAaron LI {E_INTERNAL_ERROR, "INTERNAL ERROR"},
642411677aeSAaron LI {E_UNSPECIFIED_ERROR, "UNSPECIFIED ERROR"},
643411677aeSAaron LI {0, NULL}
644411677aeSAaron LI };
64527bfbee1SPeter Avalos
64627bfbee1SPeter Avalos #define RESLEN 4
64727bfbee1SPeter Avalos
648411677aeSAaron LI static int
prestlv_print(netdissect_options * ndo,const u_char * pptr,u_int len,uint16_t op_msk _U_,int indent)649411677aeSAaron LI prestlv_print(netdissect_options *ndo,
650*ed775ee7SAntonio Huete Jimenez const u_char * pptr, u_int len,
651411677aeSAaron LI uint16_t op_msk _U_, int indent)
65227bfbee1SPeter Avalos {
653411677aeSAaron LI const struct forces_tlv *tlv = (const struct forces_tlv *)pptr;
654*ed775ee7SAntonio Huete Jimenez const u_char *tdp = (const u_char *) TLV_DATA(tlv);
655411677aeSAaron LI const struct res_val *r = (const struct res_val *)tdp;
65627bfbee1SPeter Avalos u_int dlen;
657*ed775ee7SAntonio Huete Jimenez uint8_t result;
65827bfbee1SPeter Avalos
65927bfbee1SPeter Avalos /*
66027bfbee1SPeter Avalos * pdatacnt_print() has ensured that len (the TLV length)
66127bfbee1SPeter Avalos * >= TLV_HDRL.
66227bfbee1SPeter Avalos */
66327bfbee1SPeter Avalos dlen = len - TLV_HDRL;
66427bfbee1SPeter Avalos if (dlen != RESLEN) {
665*ed775ee7SAntonio Huete Jimenez ND_PRINT("illegal RESULT-TLV: %u bytes!\n", dlen);
66627bfbee1SPeter Avalos return -1;
66727bfbee1SPeter Avalos }
66827bfbee1SPeter Avalos
669*ed775ee7SAntonio Huete Jimenez ND_TCHECK_SIZE(r);
670*ed775ee7SAntonio Huete Jimenez result = GET_U_1(r->result);
671*ed775ee7SAntonio Huete Jimenez if (result >= 0x18 && result <= 0xFE) {
672*ed775ee7SAntonio Huete Jimenez ND_PRINT("illegal reserved result code: 0x%x!\n", result);
67327bfbee1SPeter Avalos return -1;
67427bfbee1SPeter Avalos }
67527bfbee1SPeter Avalos
676411677aeSAaron LI if (ndo->ndo_vflag >= 3) {
67727bfbee1SPeter Avalos char *ib = indent_pr(indent, 0);
678*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s Result: %s (code 0x%x)\n", ib,
679*ed775ee7SAntonio Huete Jimenez tok2str(ForCES_errs, NULL, result), result);
68027bfbee1SPeter Avalos }
68127bfbee1SPeter Avalos return 0;
68227bfbee1SPeter Avalos
68327bfbee1SPeter Avalos trunc:
684*ed775ee7SAntonio Huete Jimenez nd_print_trunc(ndo);
68527bfbee1SPeter Avalos return -1;
68627bfbee1SPeter Avalos }
68727bfbee1SPeter Avalos
688411677aeSAaron LI static int
fdatatlv_print(netdissect_options * ndo,const u_char * pptr,u_int len,uint16_t op_msk _U_,int indent)689411677aeSAaron LI fdatatlv_print(netdissect_options *ndo,
690*ed775ee7SAntonio Huete Jimenez const u_char * pptr, u_int len,
691411677aeSAaron LI uint16_t op_msk _U_, int indent)
69227bfbee1SPeter Avalos {
693411677aeSAaron LI const struct forces_tlv *tlv = (const struct forces_tlv *)pptr;
69427bfbee1SPeter Avalos u_int rlen;
695*ed775ee7SAntonio Huete Jimenez const u_char *tdp = (const u_char *) TLV_DATA(tlv);
696411677aeSAaron LI uint16_t type;
69727bfbee1SPeter Avalos
69827bfbee1SPeter Avalos /*
69927bfbee1SPeter Avalos * pdatacnt_print() or pkeyitlv_print() has ensured that len
70027bfbee1SPeter Avalos * (the TLV length) >= TLV_HDRL.
70127bfbee1SPeter Avalos */
70227bfbee1SPeter Avalos rlen = len - TLV_HDRL;
703*ed775ee7SAntonio Huete Jimenez ND_TCHECK_SIZE(tlv);
704*ed775ee7SAntonio Huete Jimenez type = GET_BE_U_2(tlv->type);
70527bfbee1SPeter Avalos if (type != F_TLV_FULD) {
706*ed775ee7SAntonio Huete Jimenez ND_PRINT("Error: expecting FULLDATA!\n");
70727bfbee1SPeter Avalos return -1;
70827bfbee1SPeter Avalos }
70927bfbee1SPeter Avalos
710411677aeSAaron LI if (ndo->ndo_vflag >= 3) {
71127bfbee1SPeter Avalos char *ib = indent_pr(indent + 2, 1);
712*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s[", ib + 1);
713*ed775ee7SAntonio Huete Jimenez hex_print(ndo, ib, tdp, rlen);
714*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n%s]", ib + 1);
71527bfbee1SPeter Avalos }
71627bfbee1SPeter Avalos return 0;
71727bfbee1SPeter Avalos
71827bfbee1SPeter Avalos trunc:
719*ed775ee7SAntonio Huete Jimenez nd_print_trunc(ndo);
72027bfbee1SPeter Avalos return -1;
72127bfbee1SPeter Avalos }
72227bfbee1SPeter Avalos
723411677aeSAaron LI static int
sdatailv_print(netdissect_options * ndo,const u_char * pptr,u_int len,uint16_t op_msk _U_,int indent)724411677aeSAaron LI sdatailv_print(netdissect_options *ndo,
725*ed775ee7SAntonio Huete Jimenez const u_char * pptr, u_int len,
726411677aeSAaron LI uint16_t op_msk _U_, int indent)
72727bfbee1SPeter Avalos {
72827bfbee1SPeter Avalos u_int rlen;
729411677aeSAaron LI const struct forces_ilv *ilv = (const struct forces_ilv *)pptr;
73027bfbee1SPeter Avalos int invilv;
73127bfbee1SPeter Avalos
73227bfbee1SPeter Avalos if (len < ILV_HDRL) {
733*ed775ee7SAntonio Huete Jimenez ND_PRINT("Error: BAD SPARSEDATA-TLV!\n");
73427bfbee1SPeter Avalos return -1;
73527bfbee1SPeter Avalos }
7366263709fSPeter Avalos rlen = len;
73727bfbee1SPeter Avalos indent += 1;
73827bfbee1SPeter Avalos while (rlen != 0) {
739411677aeSAaron LI #if 0
740*ed775ee7SAntonio Huete Jimenez ND_PRINT("Jamal - outstanding length <%u>\n", rlen);
741411677aeSAaron LI #endif
7426263709fSPeter Avalos char *ib = indent_pr(indent, 1);
743*ed775ee7SAntonio Huete Jimenez const u_char *tdp = (const u_char *) ILV_DATA(ilv);
744*ed775ee7SAntonio Huete Jimenez invilv = ilv_valid(ndo, ilv, rlen);
74527bfbee1SPeter Avalos if (invilv) {
746*ed775ee7SAntonio Huete Jimenez ND_PRINT("Error: %s, rlen %u\n",
747*ed775ee7SAntonio Huete Jimenez tok2str(ForCES_TLV_err, NULL, invilv), rlen);
7486263709fSPeter Avalos return -1;
7496263709fSPeter Avalos }
750411677aeSAaron LI if (ndo->ndo_vflag >= 3) {
751*ed775ee7SAntonio Huete Jimenez u_int ilvl = GET_BE_U_4(ilv->length);
752*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n%s ILV: type %x length %u\n", ib + 1,
753*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(ilv->type), ilvl);
754*ed775ee7SAntonio Huete Jimenez hex_print(ndo, "\t\t[", tdp, ilvl-ILV_HDRL);
75527bfbee1SPeter Avalos }
75627bfbee1SPeter Avalos
75727bfbee1SPeter Avalos ilv = GO_NXT_ILV(ilv, rlen);
75827bfbee1SPeter Avalos }
75927bfbee1SPeter Avalos
76027bfbee1SPeter Avalos return 0;
76127bfbee1SPeter Avalos }
76227bfbee1SPeter Avalos
763411677aeSAaron LI static int
sdatatlv_print(netdissect_options * ndo,const u_char * pptr,u_int len,uint16_t op_msk,int indent)764411677aeSAaron LI sdatatlv_print(netdissect_options *ndo,
765*ed775ee7SAntonio Huete Jimenez const u_char * pptr, u_int len,
766411677aeSAaron LI uint16_t op_msk, int indent)
76727bfbee1SPeter Avalos {
768411677aeSAaron LI const struct forces_tlv *tlv = (const struct forces_tlv *)pptr;
76927bfbee1SPeter Avalos u_int rlen;
770*ed775ee7SAntonio Huete Jimenez const u_char *tdp = (const u_char *) TLV_DATA(tlv);
771411677aeSAaron LI uint16_t type;
77227bfbee1SPeter Avalos
77327bfbee1SPeter Avalos /*
77427bfbee1SPeter Avalos * pdatacnt_print() has ensured that len (the TLV length)
77527bfbee1SPeter Avalos * >= TLV_HDRL.
77627bfbee1SPeter Avalos */
77727bfbee1SPeter Avalos rlen = len - TLV_HDRL;
778*ed775ee7SAntonio Huete Jimenez ND_TCHECK_SIZE(tlv);
779*ed775ee7SAntonio Huete Jimenez type = GET_BE_U_2(tlv->type);
78027bfbee1SPeter Avalos if (type != F_TLV_SPAD) {
781*ed775ee7SAntonio Huete Jimenez ND_PRINT("Error: expecting SPARSEDATA!\n");
78227bfbee1SPeter Avalos return -1;
78327bfbee1SPeter Avalos }
78427bfbee1SPeter Avalos
785411677aeSAaron LI return sdatailv_print(ndo, tdp, rlen, op_msk, indent);
78627bfbee1SPeter Avalos
78727bfbee1SPeter Avalos trunc:
788*ed775ee7SAntonio Huete Jimenez nd_print_trunc(ndo);
78927bfbee1SPeter Avalos return -1;
79027bfbee1SPeter Avalos }
79127bfbee1SPeter Avalos
792411677aeSAaron LI static int
pkeyitlv_print(netdissect_options * ndo,const u_char * pptr,u_int len,uint16_t op_msk,int indent)793411677aeSAaron LI pkeyitlv_print(netdissect_options *ndo,
794*ed775ee7SAntonio Huete Jimenez const u_char * pptr, u_int len,
795411677aeSAaron LI uint16_t op_msk, int indent)
79627bfbee1SPeter Avalos {
797411677aeSAaron LI const struct forces_tlv *tlv = (const struct forces_tlv *)pptr;
798*ed775ee7SAntonio Huete Jimenez const u_char *tdp = (const u_char *) TLV_DATA(tlv);
799*ed775ee7SAntonio Huete Jimenez const u_char *dp = tdp + 4;
800411677aeSAaron LI const struct forces_tlv *kdtlv = (const struct forces_tlv *)dp;
801411677aeSAaron LI uint32_t id;
80227bfbee1SPeter Avalos char *ib = indent_pr(indent, 0);
803411677aeSAaron LI uint16_t type, tll;
804411677aeSAaron LI u_int invtlv;
80527bfbee1SPeter Avalos
806*ed775ee7SAntonio Huete Jimenez id = GET_BE_U_4(tdp);
807*ed775ee7SAntonio Huete Jimenez ND_PRINT("%sKeyinfo: Key 0x%x\n", ib, id);
808*ed775ee7SAntonio Huete Jimenez type = GET_BE_U_2(kdtlv->type);
809*ed775ee7SAntonio Huete Jimenez tll = GET_BE_U_2(kdtlv->length);
810*ed775ee7SAntonio Huete Jimenez invtlv = tlv_valid(tll, len);
81127bfbee1SPeter Avalos
81227bfbee1SPeter Avalos if (invtlv) {
813*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s TLV type 0x%x len %u\n",
81427bfbee1SPeter Avalos tok2str(ForCES_TLV_err, NULL, invtlv), type,
815*ed775ee7SAntonio Huete Jimenez tll);
81627bfbee1SPeter Avalos return -1;
81727bfbee1SPeter Avalos }
81827bfbee1SPeter Avalos /*
81927bfbee1SPeter Avalos * At this point, tlv_valid() has ensured that the TLV
82027bfbee1SPeter Avalos * length is large enough but not too large (it doesn't
82127bfbee1SPeter Avalos * go past the end of the containing TLV).
82227bfbee1SPeter Avalos */
823*ed775ee7SAntonio Huete Jimenez tll = GET_BE_U_2(kdtlv->length);
824411677aeSAaron LI dp = (const u_char *) TLV_DATA(kdtlv);
825411677aeSAaron LI return fdatatlv_print(ndo, dp, tll, op_msk, indent);
82627bfbee1SPeter Avalos }
82727bfbee1SPeter Avalos
828411677aeSAaron LI #define PTH_DESC_SIZE 12
829411677aeSAaron LI
830411677aeSAaron LI static int
pdatacnt_print(netdissect_options * ndo,const u_char * pptr,u_int len,uint16_t IDcnt,uint16_t op_msk,int indent)831411677aeSAaron LI pdatacnt_print(netdissect_options *ndo,
832*ed775ee7SAntonio Huete Jimenez const u_char * pptr, u_int len,
833411677aeSAaron LI uint16_t IDcnt, uint16_t op_msk, int indent)
83427bfbee1SPeter Avalos {
83527bfbee1SPeter Avalos u_int i;
836411677aeSAaron LI uint32_t id;
83727bfbee1SPeter Avalos char *ib = indent_pr(indent, 0);
83827bfbee1SPeter Avalos
839411677aeSAaron LI if ((op_msk & B_APPND) && ndo->ndo_vflag >= 3) {
840*ed775ee7SAntonio Huete Jimenez ND_PRINT("%sTABLE APPEND\n", ib);
841411677aeSAaron LI }
84227bfbee1SPeter Avalos for (i = 0; i < IDcnt; i++) {
843*ed775ee7SAntonio Huete Jimenez ND_TCHECK_4(pptr);
84427bfbee1SPeter Avalos if (len < 4)
84527bfbee1SPeter Avalos goto trunc;
846*ed775ee7SAntonio Huete Jimenez id = GET_BE_U_4(pptr);
847411677aeSAaron LI if (ndo->ndo_vflag >= 3)
848*ed775ee7SAntonio Huete Jimenez ND_PRINT("%sID#%02u: %u\n", ib, i + 1, id);
84927bfbee1SPeter Avalos len -= 4;
85027bfbee1SPeter Avalos pptr += 4;
85127bfbee1SPeter Avalos }
852411677aeSAaron LI
853411677aeSAaron LI if ((op_msk & B_TRNG) || (op_msk & B_KEYIN)) {
854411677aeSAaron LI if (op_msk & B_TRNG) {
855411677aeSAaron LI uint32_t starti, endi;
856411677aeSAaron LI
857411677aeSAaron LI if (len < PTH_DESC_SIZE) {
858*ed775ee7SAntonio Huete Jimenez ND_PRINT("pathlength %u with key/range too short %u\n",
859*ed775ee7SAntonio Huete Jimenez len, PTH_DESC_SIZE);
860411677aeSAaron LI return -1;
861411677aeSAaron LI }
862411677aeSAaron LI
863411677aeSAaron LI pptr += sizeof(struct forces_tlv);
864411677aeSAaron LI len -= sizeof(struct forces_tlv);
865411677aeSAaron LI
866*ed775ee7SAntonio Huete Jimenez starti = GET_BE_U_4(pptr);
867411677aeSAaron LI pptr += 4;
868411677aeSAaron LI len -= 4;
869411677aeSAaron LI
870*ed775ee7SAntonio Huete Jimenez endi = GET_BE_U_4(pptr);
871411677aeSAaron LI pptr += 4;
872411677aeSAaron LI len -= 4;
873411677aeSAaron LI
874411677aeSAaron LI if (ndo->ndo_vflag >= 3)
875*ed775ee7SAntonio Huete Jimenez ND_PRINT("%sTable range: [%u,%u]\n", ib, starti, endi);
876411677aeSAaron LI }
877411677aeSAaron LI
878411677aeSAaron LI if (op_msk & B_KEYIN) {
879411677aeSAaron LI const struct forces_tlv *keytlv;
880411677aeSAaron LI uint16_t tll;
881411677aeSAaron LI
882411677aeSAaron LI if (len < PTH_DESC_SIZE) {
883*ed775ee7SAntonio Huete Jimenez ND_PRINT("pathlength %u with key/range too short %u\n",
884*ed775ee7SAntonio Huete Jimenez len, PTH_DESC_SIZE);
885411677aeSAaron LI return -1;
886411677aeSAaron LI }
887411677aeSAaron LI
888411677aeSAaron LI /* skip keyid */
889411677aeSAaron LI pptr += 4;
890411677aeSAaron LI len -= 4;
891411677aeSAaron LI keytlv = (const struct forces_tlv *)pptr;
892411677aeSAaron LI /* skip header */
893411677aeSAaron LI pptr += sizeof(struct forces_tlv);
894411677aeSAaron LI len -= sizeof(struct forces_tlv);
895411677aeSAaron LI /* skip key content */
896*ed775ee7SAntonio Huete Jimenez tll = GET_BE_U_2(keytlv->length);
897411677aeSAaron LI if (tll < TLV_HDRL) {
898*ed775ee7SAntonio Huete Jimenez ND_PRINT("key content length %u < %u\n",
899*ed775ee7SAntonio Huete Jimenez tll, TLV_HDRL);
900411677aeSAaron LI return -1;
901411677aeSAaron LI }
902411677aeSAaron LI tll -= TLV_HDRL;
903411677aeSAaron LI if (len < tll) {
904*ed775ee7SAntonio Huete Jimenez ND_PRINT("key content too short\n");
905411677aeSAaron LI return -1;
906411677aeSAaron LI }
907411677aeSAaron LI pptr += tll;
908411677aeSAaron LI len -= tll;
909411677aeSAaron LI }
910411677aeSAaron LI
911411677aeSAaron LI }
912411677aeSAaron LI
91327bfbee1SPeter Avalos if (len) {
914411677aeSAaron LI const struct forces_tlv *pdtlv = (const struct forces_tlv *)pptr;
915411677aeSAaron LI uint16_t type;
916*ed775ee7SAntonio Huete Jimenez uint16_t tlvl, tll;
917*ed775ee7SAntonio Huete Jimenez u_int pad = 0;
91827bfbee1SPeter Avalos u_int aln;
919411677aeSAaron LI u_int invtlv;
92027bfbee1SPeter Avalos
921*ed775ee7SAntonio Huete Jimenez type = GET_BE_U_2(pdtlv->type);
922*ed775ee7SAntonio Huete Jimenez tlvl = GET_BE_U_2(pdtlv->length);
923*ed775ee7SAntonio Huete Jimenez invtlv = tlv_valid(tlvl, len);
92427bfbee1SPeter Avalos if (invtlv) {
925*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s Outstanding bytes %u for TLV type 0x%x TLV len %u\n",
92627bfbee1SPeter Avalos tok2str(ForCES_TLV_err, NULL, invtlv), len, type,
927*ed775ee7SAntonio Huete Jimenez tlvl);
92827bfbee1SPeter Avalos goto pd_err;
92927bfbee1SPeter Avalos }
93027bfbee1SPeter Avalos /*
93127bfbee1SPeter Avalos * At this point, tlv_valid() has ensured that the TLV
93227bfbee1SPeter Avalos * length is large enough but not too large (it doesn't
93327bfbee1SPeter Avalos * go past the end of the containing TLV).
93427bfbee1SPeter Avalos */
935*ed775ee7SAntonio Huete Jimenez tll = tlvl - TLV_HDRL;
936*ed775ee7SAntonio Huete Jimenez aln = F_ALN_LEN(tlvl);
937*ed775ee7SAntonio Huete Jimenez if (aln > tlvl) {
93827bfbee1SPeter Avalos if (aln > len) {
939*ed775ee7SAntonio Huete Jimenez ND_PRINT("Invalid padded pathdata TLV type 0x%x len %u missing %u pad bytes\n",
940*ed775ee7SAntonio Huete Jimenez type, tlvl, aln - len);
94127bfbee1SPeter Avalos } else {
942*ed775ee7SAntonio Huete Jimenez pad = aln - tlvl;
94327bfbee1SPeter Avalos }
94427bfbee1SPeter Avalos }
94527bfbee1SPeter Avalos if (pd_valid(type)) {
94627bfbee1SPeter Avalos const struct pdata_ops *ops = get_forces_pd(type);
94727bfbee1SPeter Avalos
948411677aeSAaron LI if (ndo->ndo_vflag >= 3 && ops->v != F_TLV_PDAT) {
94927bfbee1SPeter Avalos if (pad)
950*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s %s (Length %u DataLen %u pad %u Bytes)\n",
951*ed775ee7SAntonio Huete Jimenez ib, ops->s, tlvl, tll, pad);
95227bfbee1SPeter Avalos else
953*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s %s (Length %u DataLen %u Bytes)\n",
954*ed775ee7SAntonio Huete Jimenez ib, ops->s, tlvl, tll);
95527bfbee1SPeter Avalos }
95627bfbee1SPeter Avalos
957411677aeSAaron LI chk_op_type(ndo, type, op_msk, ops->op_msk);
95827bfbee1SPeter Avalos
959411677aeSAaron LI if (ops->print(ndo, (const u_char *)pdtlv,
96027bfbee1SPeter Avalos tll + pad + TLV_HDRL, op_msk,
9616263709fSPeter Avalos indent + 2) == -1)
9626263709fSPeter Avalos return -1;
96327bfbee1SPeter Avalos len -= (TLV_HDRL + pad + tll);
96427bfbee1SPeter Avalos } else {
965*ed775ee7SAntonio Huete Jimenez ND_PRINT("Invalid path data content type 0x%x len %u\n",
966*ed775ee7SAntonio Huete Jimenez type, tlvl);
96727bfbee1SPeter Avalos pd_err:
968*ed775ee7SAntonio Huete Jimenez if (tlvl) {
969*ed775ee7SAntonio Huete Jimenez hex_print(ndo, "Bad Data val\n\t [",
970*ed775ee7SAntonio Huete Jimenez pptr, len);
971*ed775ee7SAntonio Huete Jimenez ND_PRINT("]\n");
97227bfbee1SPeter Avalos
97327bfbee1SPeter Avalos return -1;
97427bfbee1SPeter Avalos }
97527bfbee1SPeter Avalos }
97627bfbee1SPeter Avalos }
97727bfbee1SPeter Avalos return len;
97827bfbee1SPeter Avalos
97927bfbee1SPeter Avalos trunc:
980*ed775ee7SAntonio Huete Jimenez nd_print_trunc(ndo);
98127bfbee1SPeter Avalos return -1;
98227bfbee1SPeter Avalos }
98327bfbee1SPeter Avalos
984411677aeSAaron LI static int
pdata_print(netdissect_options * ndo,const u_char * pptr,u_int len,uint16_t op_msk,int indent)985411677aeSAaron LI pdata_print(netdissect_options *ndo,
986*ed775ee7SAntonio Huete Jimenez const u_char * pptr, u_int len,
987411677aeSAaron LI uint16_t op_msk, int indent)
98827bfbee1SPeter Avalos {
989411677aeSAaron LI const struct pathdata_h *pdh = (const struct pathdata_h *)pptr;
99027bfbee1SPeter Avalos char *ib = indent_pr(indent, 0);
99127bfbee1SPeter Avalos u_int minsize = 0;
99227bfbee1SPeter Avalos int more_pd = 0;
993411677aeSAaron LI uint16_t idcnt = 0;
99427bfbee1SPeter Avalos
995*ed775ee7SAntonio Huete Jimenez ND_TCHECK_SIZE(pdh);
99627bfbee1SPeter Avalos if (len < sizeof(struct pathdata_h))
99727bfbee1SPeter Avalos goto trunc;
998411677aeSAaron LI if (ndo->ndo_vflag >= 3) {
999*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n%sPathdata: Flags 0x%x ID count %u\n",
1000*ed775ee7SAntonio Huete Jimenez ib, GET_BE_U_2(pdh->pflags),
1001*ed775ee7SAntonio Huete Jimenez GET_BE_U_2(pdh->pIDcnt));
100227bfbee1SPeter Avalos }
100327bfbee1SPeter Avalos
1004*ed775ee7SAntonio Huete Jimenez if (GET_BE_U_2(pdh->pflags) & F_SELKEY) {
100527bfbee1SPeter Avalos op_msk |= B_KEYIN;
100627bfbee1SPeter Avalos }
1007411677aeSAaron LI
1008411677aeSAaron LI /* Table GET Range operation */
1009*ed775ee7SAntonio Huete Jimenez if (GET_BE_U_2(pdh->pflags) & F_SELTABRANGE) {
1010411677aeSAaron LI op_msk |= B_TRNG;
1011411677aeSAaron LI }
1012411677aeSAaron LI /* Table SET append operation */
1013*ed775ee7SAntonio Huete Jimenez if (GET_BE_U_2(pdh->pflags) & F_TABAPPEND) {
1014411677aeSAaron LI op_msk |= B_APPND;
1015411677aeSAaron LI }
1016411677aeSAaron LI
101727bfbee1SPeter Avalos pptr += sizeof(struct pathdata_h);
101827bfbee1SPeter Avalos len -= sizeof(struct pathdata_h);
1019*ed775ee7SAntonio Huete Jimenez idcnt = GET_BE_U_2(pdh->pIDcnt);
102027bfbee1SPeter Avalos minsize = idcnt * 4;
102127bfbee1SPeter Avalos if (len < minsize) {
1022*ed775ee7SAntonio Huete Jimenez ND_PRINT("\t\t\ttruncated IDs expected %uB got %uB\n", minsize,
1023*ed775ee7SAntonio Huete Jimenez len);
1024*ed775ee7SAntonio Huete Jimenez hex_print(ndo, "\t\t\tID Data[", pptr, len);
1025*ed775ee7SAntonio Huete Jimenez ND_PRINT("]\n");
102627bfbee1SPeter Avalos return -1;
102727bfbee1SPeter Avalos }
1028411677aeSAaron LI
1029411677aeSAaron LI if ((op_msk & B_TRNG) && (op_msk & B_KEYIN)) {
1030*ed775ee7SAntonio Huete Jimenez ND_PRINT("\t\t\tIllegal to have both Table ranges and keys\n");
1031411677aeSAaron LI return -1;
1032411677aeSAaron LI }
1033411677aeSAaron LI
1034411677aeSAaron LI more_pd = pdatacnt_print(ndo, pptr, len, idcnt, op_msk, indent);
103527bfbee1SPeter Avalos if (more_pd > 0) {
103627bfbee1SPeter Avalos int consumed = len - more_pd;
103727bfbee1SPeter Avalos pptr += consumed;
103827bfbee1SPeter Avalos len = more_pd;
103927bfbee1SPeter Avalos /* XXX: Argh, recurse some more */
1040411677aeSAaron LI return recpdoptlv_print(ndo, pptr, len, op_msk, indent+1);
104127bfbee1SPeter Avalos } else
104227bfbee1SPeter Avalos return 0;
104327bfbee1SPeter Avalos
104427bfbee1SPeter Avalos trunc:
1045*ed775ee7SAntonio Huete Jimenez nd_print_trunc(ndo);
104627bfbee1SPeter Avalos return -1;
104727bfbee1SPeter Avalos }
104827bfbee1SPeter Avalos
1049411677aeSAaron LI static int
genoptlv_print(netdissect_options * ndo,const u_char * pptr,u_int len,uint16_t op_msk,int indent)1050411677aeSAaron LI genoptlv_print(netdissect_options *ndo,
1051*ed775ee7SAntonio Huete Jimenez const u_char * pptr, u_int len,
1052411677aeSAaron LI uint16_t op_msk, int indent)
105327bfbee1SPeter Avalos {
1054411677aeSAaron LI const struct forces_tlv *pdtlv = (const struct forces_tlv *)pptr;
1055411677aeSAaron LI uint16_t type;
1056*ed775ee7SAntonio Huete Jimenez u_int tlvl;
1057411677aeSAaron LI u_int invtlv;
105827bfbee1SPeter Avalos char *ib = indent_pr(indent, 0);
105927bfbee1SPeter Avalos
1060*ed775ee7SAntonio Huete Jimenez type = GET_BE_U_2(pdtlv->type);
1061*ed775ee7SAntonio Huete Jimenez tlvl = GET_BE_U_2(pdtlv->length);
1062*ed775ee7SAntonio Huete Jimenez invtlv = tlv_valid(tlvl, len);
1063*ed775ee7SAntonio Huete Jimenez ND_PRINT("genoptlvprint - %s TLV type 0x%x len %u\n",
1064*ed775ee7SAntonio Huete Jimenez tok2str(ForCES_TLV, NULL, type), type, tlvl);
106527bfbee1SPeter Avalos if (!invtlv) {
106627bfbee1SPeter Avalos /*
106727bfbee1SPeter Avalos * At this point, tlv_valid() has ensured that the TLV
106827bfbee1SPeter Avalos * length is large enough but not too large (it doesn't
106927bfbee1SPeter Avalos * go past the end of the containing TLV).
107027bfbee1SPeter Avalos */
1071*ed775ee7SAntonio Huete Jimenez const u_char *dp = (const u_char *) TLV_DATA(pdtlv);
1072*ed775ee7SAntonio Huete Jimenez
107327bfbee1SPeter Avalos if (!ttlv_valid(type)) {
1074*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s TLV type 0x%x len %u\n",
107527bfbee1SPeter Avalos tok2str(ForCES_TLV_err, NULL, invtlv), type,
1076*ed775ee7SAntonio Huete Jimenez tlvl);
107727bfbee1SPeter Avalos return -1;
107827bfbee1SPeter Avalos }
1079411677aeSAaron LI if (ndo->ndo_vflag >= 3)
1080*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s%s, length %u (data length %u Bytes)",
108127bfbee1SPeter Avalos ib, tok2str(ForCES_TLV, NULL, type),
1082*ed775ee7SAntonio Huete Jimenez tlvl, tlvl - TLV_HDRL);
108327bfbee1SPeter Avalos
1084*ed775ee7SAntonio Huete Jimenez return pdata_print(ndo, dp, tlvl - TLV_HDRL, op_msk, indent + 1);
108527bfbee1SPeter Avalos } else {
1086*ed775ee7SAntonio Huete Jimenez ND_PRINT("\t\t\tInvalid ForCES TLV type=%x", type);
108727bfbee1SPeter Avalos return -1;
108827bfbee1SPeter Avalos }
108927bfbee1SPeter Avalos }
109027bfbee1SPeter Avalos
1091411677aeSAaron LI static int
recpdoptlv_print(netdissect_options * ndo,const u_char * pptr,u_int len,uint16_t op_msk,int indent)1092411677aeSAaron LI recpdoptlv_print(netdissect_options *ndo,
1093*ed775ee7SAntonio Huete Jimenez const u_char * pptr, u_int len,
1094411677aeSAaron LI uint16_t op_msk, int indent)
109527bfbee1SPeter Avalos {
1096411677aeSAaron LI const struct forces_tlv *pdtlv = (const struct forces_tlv *)pptr;
109727bfbee1SPeter Avalos
109827bfbee1SPeter Avalos while (len != 0) {
1099*ed775ee7SAntonio Huete Jimenez uint16_t type, tlvl;
1100*ed775ee7SAntonio Huete Jimenez u_int invtlv;
1101*ed775ee7SAntonio Huete Jimenez char *ib;
1102*ed775ee7SAntonio Huete Jimenez const u_char *dp;
1103*ed775ee7SAntonio Huete Jimenez
1104*ed775ee7SAntonio Huete Jimenez tlvl = GET_BE_U_2(pdtlv->length);
1105*ed775ee7SAntonio Huete Jimenez invtlv = tlv_valid(tlvl, len);
110627bfbee1SPeter Avalos if (invtlv) {
110727bfbee1SPeter Avalos break;
110827bfbee1SPeter Avalos }
110927bfbee1SPeter Avalos
111027bfbee1SPeter Avalos /*
111127bfbee1SPeter Avalos * At this point, tlv_valid() has ensured that the TLV
111227bfbee1SPeter Avalos * length is large enough but not too large (it doesn't
111327bfbee1SPeter Avalos * go past the end of the containing TLV).
111427bfbee1SPeter Avalos */
111527bfbee1SPeter Avalos ib = indent_pr(indent, 0);
1116*ed775ee7SAntonio Huete Jimenez type = GET_BE_U_2(pdtlv->type);
1117411677aeSAaron LI dp = (const u_char *) TLV_DATA(pdtlv);
111827bfbee1SPeter Avalos
1119411677aeSAaron LI if (ndo->ndo_vflag >= 3)
1120*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s%s, length %u (data encapsulated %u Bytes)",
112127bfbee1SPeter Avalos ib, tok2str(ForCES_TLV, NULL, type),
1122*ed775ee7SAntonio Huete Jimenez tlvl,
1123*ed775ee7SAntonio Huete Jimenez tlvl - TLV_HDRL);
112427bfbee1SPeter Avalos
1125*ed775ee7SAntonio Huete Jimenez if (pdata_print(ndo, dp, tlvl - TLV_HDRL, op_msk, indent + 1) == -1)
11266263709fSPeter Avalos return -1;
112727bfbee1SPeter Avalos pdtlv = GO_NXT_TLV(pdtlv, len);
112827bfbee1SPeter Avalos }
112927bfbee1SPeter Avalos
113027bfbee1SPeter Avalos if (len) {
1131*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\t\tMessy PATHDATA TLV header, type (0x%x)\n\t\texcess of %u Bytes ",
1132*ed775ee7SAntonio Huete Jimenez GET_BE_U_2(pdtlv->type),
1133*ed775ee7SAntonio Huete Jimenez len - GET_BE_U_2(pdtlv->length));
113427bfbee1SPeter Avalos return -1;
113527bfbee1SPeter Avalos }
113627bfbee1SPeter Avalos
113727bfbee1SPeter Avalos return 0;
113827bfbee1SPeter Avalos }
113927bfbee1SPeter Avalos
1140411677aeSAaron LI static int
invoptlv_print(netdissect_options * ndo,const u_char * pptr,u_int len,uint16_t op_msk _U_,int indent)1141411677aeSAaron LI invoptlv_print(netdissect_options *ndo,
1142*ed775ee7SAntonio Huete Jimenez const u_char * pptr, u_int len,
1143411677aeSAaron LI uint16_t op_msk _U_, int indent)
114427bfbee1SPeter Avalos {
114527bfbee1SPeter Avalos char *ib = indent_pr(indent, 1);
114627bfbee1SPeter Avalos
1147411677aeSAaron LI if (ndo->ndo_vflag >= 3) {
1148*ed775ee7SAntonio Huete Jimenez ND_PRINT("%sData[", ib + 1);
1149*ed775ee7SAntonio Huete Jimenez hex_print(ndo, ib, pptr, len);
1150*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s]\n", ib);
115127bfbee1SPeter Avalos }
115227bfbee1SPeter Avalos return -1;
115327bfbee1SPeter Avalos }
115427bfbee1SPeter Avalos
1155411677aeSAaron LI static int
otlv_print(netdissect_options * ndo,const struct forces_tlv * otlv,uint16_t op_msk _U_,int indent)1156411677aeSAaron LI otlv_print(netdissect_options *ndo,
1157411677aeSAaron LI const struct forces_tlv *otlv, uint16_t op_msk _U_, int indent)
115827bfbee1SPeter Avalos {
115927bfbee1SPeter Avalos int rc = 0;
1160*ed775ee7SAntonio Huete Jimenez const u_char *dp = (const u_char *) TLV_DATA(otlv);
1161411677aeSAaron LI uint16_t type;
1162*ed775ee7SAntonio Huete Jimenez u_int tll;
116327bfbee1SPeter Avalos char *ib = indent_pr(indent, 0);
116427bfbee1SPeter Avalos const struct optlv_h *ops;
116527bfbee1SPeter Avalos
116627bfbee1SPeter Avalos /*
1167*ed775ee7SAntonio Huete Jimenez * lfbselect_print() has ensured that GET_BE_U_2(otlv->length)
116827bfbee1SPeter Avalos * >= TLV_HDRL.
116927bfbee1SPeter Avalos */
1170*ed775ee7SAntonio Huete Jimenez type = GET_BE_U_2(otlv->type);
1171*ed775ee7SAntonio Huete Jimenez tll = GET_BE_U_2(otlv->length) - TLV_HDRL;
117227bfbee1SPeter Avalos ops = get_forces_optlv_h(type);
1173411677aeSAaron LI if (ndo->ndo_vflag >= 3) {
1174*ed775ee7SAntonio Huete Jimenez ND_PRINT("%sOper TLV %s(0x%x) length %u\n", ib, ops->s, type,
1175*ed775ee7SAntonio Huete Jimenez GET_BE_U_2(otlv->length));
117627bfbee1SPeter Avalos }
117727bfbee1SPeter Avalos /* rest of ops must at least have 12B {pathinfo} */
117827bfbee1SPeter Avalos if (tll < OP_MIN_SIZ) {
1179*ed775ee7SAntonio Huete Jimenez ND_PRINT("\t\tOper TLV %s(0x%x) length %u\n", ops->s, type,
1180*ed775ee7SAntonio Huete Jimenez GET_BE_U_2(otlv->length));
1181*ed775ee7SAntonio Huete Jimenez ND_PRINT("\t\tTruncated data size %u minimum required %u\n", tll,
1182*ed775ee7SAntonio Huete Jimenez OP_MIN_SIZ);
1183411677aeSAaron LI return invoptlv_print(ndo, dp, tll, ops->op_msk, indent);
118427bfbee1SPeter Avalos
118527bfbee1SPeter Avalos }
118627bfbee1SPeter Avalos
1187411677aeSAaron LI /* XXX - do anything with ops->flags? */
1188411677aeSAaron LI if(ops->print) {
1189411677aeSAaron LI rc = ops->print(ndo, dp, tll, ops->op_msk, indent + 1);
1190411677aeSAaron LI }
119127bfbee1SPeter Avalos return rc;
119227bfbee1SPeter Avalos }
119327bfbee1SPeter Avalos
119427bfbee1SPeter Avalos #define ASTDLN 4
119527bfbee1SPeter Avalos #define ASTMCD 255
1196411677aeSAaron LI static int
asttlv_print(netdissect_options * ndo,const u_char * pptr,u_int len,uint16_t op_msk _U_,int indent)1197411677aeSAaron LI asttlv_print(netdissect_options *ndo,
1198*ed775ee7SAntonio Huete Jimenez const u_char * pptr, u_int len,
1199411677aeSAaron LI uint16_t op_msk _U_, int indent)
120027bfbee1SPeter Avalos {
1201411677aeSAaron LI uint32_t rescode;
120227bfbee1SPeter Avalos u_int dlen;
120327bfbee1SPeter Avalos char *ib = indent_pr(indent, 0);
120427bfbee1SPeter Avalos
120527bfbee1SPeter Avalos /*
120627bfbee1SPeter Avalos * forces_type_print() has ensured that len (the TLV length)
120727bfbee1SPeter Avalos * >= TLV_HDRL.
120827bfbee1SPeter Avalos */
120927bfbee1SPeter Avalos dlen = len - TLV_HDRL;
121027bfbee1SPeter Avalos if (dlen != ASTDLN) {
1211*ed775ee7SAntonio Huete Jimenez ND_PRINT("illegal ASTresult-TLV: %u bytes!\n", dlen);
121227bfbee1SPeter Avalos return -1;
121327bfbee1SPeter Avalos }
1214*ed775ee7SAntonio Huete Jimenez rescode = GET_BE_U_4(pptr);
121527bfbee1SPeter Avalos if (rescode > ASTMCD) {
1216*ed775ee7SAntonio Huete Jimenez ND_PRINT("illegal ASTresult result code: %u!\n", rescode);
121727bfbee1SPeter Avalos return -1;
121827bfbee1SPeter Avalos }
121927bfbee1SPeter Avalos
1220411677aeSAaron LI if (ndo->ndo_vflag >= 3) {
1221*ed775ee7SAntonio Huete Jimenez ND_PRINT("Teardown reason:\n%s", ib);
122227bfbee1SPeter Avalos switch (rescode) {
122327bfbee1SPeter Avalos case 0:
1224*ed775ee7SAntonio Huete Jimenez ND_PRINT("Normal Teardown");
122527bfbee1SPeter Avalos break;
122627bfbee1SPeter Avalos case 1:
1227*ed775ee7SAntonio Huete Jimenez ND_PRINT("Loss of Heartbeats");
122827bfbee1SPeter Avalos break;
122927bfbee1SPeter Avalos case 2:
1230*ed775ee7SAntonio Huete Jimenez ND_PRINT("Out of bandwidth");
123127bfbee1SPeter Avalos break;
123227bfbee1SPeter Avalos case 3:
1233*ed775ee7SAntonio Huete Jimenez ND_PRINT("Out of Memory");
123427bfbee1SPeter Avalos break;
123527bfbee1SPeter Avalos case 4:
1236*ed775ee7SAntonio Huete Jimenez ND_PRINT("Application Crash");
123727bfbee1SPeter Avalos break;
123827bfbee1SPeter Avalos default:
1239*ed775ee7SAntonio Huete Jimenez ND_PRINT("Unknown Teardown reason");
124027bfbee1SPeter Avalos break;
124127bfbee1SPeter Avalos }
1242*ed775ee7SAntonio Huete Jimenez ND_PRINT("(%x)\n%s", rescode, ib);
124327bfbee1SPeter Avalos }
124427bfbee1SPeter Avalos return 0;
124527bfbee1SPeter Avalos }
124627bfbee1SPeter Avalos
124727bfbee1SPeter Avalos #define ASRDLN 4
124827bfbee1SPeter Avalos #define ASRMCD 3
1249411677aeSAaron LI static int
asrtlv_print(netdissect_options * ndo,const u_char * pptr,u_int len,uint16_t op_msk _U_,int indent)1250411677aeSAaron LI asrtlv_print(netdissect_options *ndo,
1251*ed775ee7SAntonio Huete Jimenez const u_char * pptr, u_int len,
1252411677aeSAaron LI uint16_t op_msk _U_, int indent)
125327bfbee1SPeter Avalos {
1254411677aeSAaron LI uint32_t rescode;
125527bfbee1SPeter Avalos u_int dlen;
125627bfbee1SPeter Avalos char *ib = indent_pr(indent, 0);
125727bfbee1SPeter Avalos
125827bfbee1SPeter Avalos /*
125927bfbee1SPeter Avalos * forces_type_print() has ensured that len (the TLV length)
126027bfbee1SPeter Avalos * >= TLV_HDRL.
126127bfbee1SPeter Avalos */
126227bfbee1SPeter Avalos dlen = len - TLV_HDRL;
126327bfbee1SPeter Avalos if (dlen != ASRDLN) { /* id, instance, oper tlv */
1264*ed775ee7SAntonio Huete Jimenez ND_PRINT("illegal ASRresult-TLV: %u bytes!\n", dlen);
126527bfbee1SPeter Avalos return -1;
126627bfbee1SPeter Avalos }
1267*ed775ee7SAntonio Huete Jimenez rescode = GET_BE_U_4(pptr);
126827bfbee1SPeter Avalos
126927bfbee1SPeter Avalos if (rescode > ASRMCD) {
1270*ed775ee7SAntonio Huete Jimenez ND_PRINT("illegal ASRresult result code: %u!\n", rescode);
127127bfbee1SPeter Avalos return -1;
127227bfbee1SPeter Avalos }
127327bfbee1SPeter Avalos
1274411677aeSAaron LI if (ndo->ndo_vflag >= 3) {
1275*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n%s", ib);
127627bfbee1SPeter Avalos switch (rescode) {
127727bfbee1SPeter Avalos case 0:
1278*ed775ee7SAntonio Huete Jimenez ND_PRINT("Success ");
127927bfbee1SPeter Avalos break;
128027bfbee1SPeter Avalos case 1:
1281*ed775ee7SAntonio Huete Jimenez ND_PRINT("FE ID invalid ");
128227bfbee1SPeter Avalos break;
128327bfbee1SPeter Avalos case 2:
1284*ed775ee7SAntonio Huete Jimenez ND_PRINT("permission denied ");
128527bfbee1SPeter Avalos break;
128627bfbee1SPeter Avalos default:
1287*ed775ee7SAntonio Huete Jimenez ND_PRINT("Unknown ");
128827bfbee1SPeter Avalos break;
128927bfbee1SPeter Avalos }
1290*ed775ee7SAntonio Huete Jimenez ND_PRINT("(%x)\n%s", rescode, ib);
129127bfbee1SPeter Avalos }
129227bfbee1SPeter Avalos return 0;
129327bfbee1SPeter Avalos }
129427bfbee1SPeter Avalos
1295411677aeSAaron LI #if 0
129627bfbee1SPeter Avalos /*
129727bfbee1SPeter Avalos * XXX - not used.
129827bfbee1SPeter Avalos */
1299411677aeSAaron LI static int
1300411677aeSAaron LI gentltlv_print(netdissect_options *ndo,
1301*ed775ee7SAntonio Huete Jimenez const u_char * pptr _U_, u_int len,
1302411677aeSAaron LI uint16_t op_msk _U_, int indent _U_)
130327bfbee1SPeter Avalos {
130427bfbee1SPeter Avalos u_int dlen = len - TLV_HDRL;
130527bfbee1SPeter Avalos
130627bfbee1SPeter Avalos if (dlen < 4) { /* at least 32 bits must exist */
1307*ed775ee7SAntonio Huete Jimenez ND_PRINT("truncated TLV: %u bytes missing! ", 4 - dlen);
130827bfbee1SPeter Avalos return -1;
130927bfbee1SPeter Avalos }
131027bfbee1SPeter Avalos return 0;
131127bfbee1SPeter Avalos }
1312411677aeSAaron LI #endif
131327bfbee1SPeter Avalos
131427bfbee1SPeter Avalos #define RD_MIN 8
1315411677aeSAaron LI
1316411677aeSAaron LI static int
print_metailv(netdissect_options * ndo,const u_char * pptr,uint16_t op_msk _U_,int indent)1317411677aeSAaron LI print_metailv(netdissect_options *ndo,
1318*ed775ee7SAntonio Huete Jimenez const u_char * pptr, uint16_t op_msk _U_, int indent)
131927bfbee1SPeter Avalos {
132027bfbee1SPeter Avalos u_int rlen;
132127bfbee1SPeter Avalos char *ib = indent_pr(indent, 0);
132227bfbee1SPeter Avalos /* XXX: check header length */
1323411677aeSAaron LI const struct forces_ilv *ilv = (const struct forces_ilv *)pptr;
132427bfbee1SPeter Avalos
132527bfbee1SPeter Avalos /*
132627bfbee1SPeter Avalos * print_metatlv() has ensured that len (what remains in the
132727bfbee1SPeter Avalos * ILV) >= ILV_HDRL.
132827bfbee1SPeter Avalos */
1329*ed775ee7SAntonio Huete Jimenez rlen = GET_BE_U_4(ilv->length) - ILV_HDRL;
1330*ed775ee7SAntonio Huete Jimenez ND_PRINT("%sMetaID 0x%x length %u\n", ib, GET_BE_U_4(ilv->type),
1331*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(ilv->length));
1332411677aeSAaron LI if (ndo->ndo_vflag >= 3) {
1333*ed775ee7SAntonio Huete Jimenez hex_print(ndo, "\t\t[", ILV_DATA(ilv), rlen);
1334*ed775ee7SAntonio Huete Jimenez ND_PRINT(" ]\n");
1335411677aeSAaron LI }
133627bfbee1SPeter Avalos return 0;
133727bfbee1SPeter Avalos }
133827bfbee1SPeter Avalos
1339411677aeSAaron LI static int
print_metatlv(netdissect_options * ndo,const u_char * pptr,u_int len,uint16_t op_msk _U_,int indent)1340411677aeSAaron LI print_metatlv(netdissect_options *ndo,
1341*ed775ee7SAntonio Huete Jimenez const u_char * pptr, u_int len,
1342411677aeSAaron LI uint16_t op_msk _U_, int indent)
134327bfbee1SPeter Avalos {
134427bfbee1SPeter Avalos u_int dlen;
134527bfbee1SPeter Avalos char *ib = indent_pr(indent, 0);
134627bfbee1SPeter Avalos u_int rlen;
1347411677aeSAaron LI const struct forces_ilv *ilv = (const struct forces_ilv *)pptr;
134827bfbee1SPeter Avalos int invilv;
134927bfbee1SPeter Avalos
135027bfbee1SPeter Avalos /*
135127bfbee1SPeter Avalos * redirect_print() has ensured that len (what remains in the
135227bfbee1SPeter Avalos * TLV) >= TLV_HDRL.
135327bfbee1SPeter Avalos */
135427bfbee1SPeter Avalos dlen = len - TLV_HDRL;
135527bfbee1SPeter Avalos rlen = dlen;
1356*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n%s METADATA length %u\n", ib, rlen);
135727bfbee1SPeter Avalos while (rlen != 0) {
1358*ed775ee7SAntonio Huete Jimenez invilv = ilv_valid(ndo, ilv, rlen);
1359411677aeSAaron LI if (invilv) {
136027bfbee1SPeter Avalos break;
1361411677aeSAaron LI }
136227bfbee1SPeter Avalos
136327bfbee1SPeter Avalos /*
136427bfbee1SPeter Avalos * At this point, ilv_valid() has ensured that the ILV
136527bfbee1SPeter Avalos * length is large enough but not too large (it doesn't
136627bfbee1SPeter Avalos * go past the end of the containing TLV).
136727bfbee1SPeter Avalos */
1368411677aeSAaron LI print_metailv(ndo, (const u_char *) ilv, 0, indent + 1);
136927bfbee1SPeter Avalos ilv = GO_NXT_ILV(ilv, rlen);
137027bfbee1SPeter Avalos }
137127bfbee1SPeter Avalos
137227bfbee1SPeter Avalos return 0;
137327bfbee1SPeter Avalos }
137427bfbee1SPeter Avalos
1375411677aeSAaron LI
1376411677aeSAaron LI static int
print_reddata(netdissect_options * ndo,const u_char * pptr,u_int len,uint16_t op_msk _U_,int indent)1377411677aeSAaron LI print_reddata(netdissect_options *ndo,
1378*ed775ee7SAntonio Huete Jimenez const u_char * pptr, u_int len,
1379411677aeSAaron LI uint16_t op_msk _U_, int indent)
138027bfbee1SPeter Avalos {
138127bfbee1SPeter Avalos u_int dlen;
1382411677aeSAaron LI char *ib = indent_pr(indent, 0);
138327bfbee1SPeter Avalos u_int rlen;
138427bfbee1SPeter Avalos
138527bfbee1SPeter Avalos dlen = len - TLV_HDRL;
138627bfbee1SPeter Avalos rlen = dlen;
1387*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n%s Redirect Data length %u\n", ib, rlen);
138827bfbee1SPeter Avalos
1389411677aeSAaron LI if (ndo->ndo_vflag >= 3) {
1390*ed775ee7SAntonio Huete Jimenez ND_PRINT("\t\t[");
1391*ed775ee7SAntonio Huete Jimenez hex_print(ndo, "\n\t\t", pptr, rlen);
1392*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\t\t]");
139327bfbee1SPeter Avalos }
139427bfbee1SPeter Avalos
139527bfbee1SPeter Avalos return 0;
139627bfbee1SPeter Avalos }
139727bfbee1SPeter Avalos
1398411677aeSAaron LI static int
redirect_print(netdissect_options * ndo,const u_char * pptr,u_int len,uint16_t op_msk _U_,int indent)1399411677aeSAaron LI redirect_print(netdissect_options *ndo,
1400*ed775ee7SAntonio Huete Jimenez const u_char * pptr, u_int len,
1401411677aeSAaron LI uint16_t op_msk _U_, int indent)
140227bfbee1SPeter Avalos {
1403411677aeSAaron LI const struct forces_tlv *tlv = (const struct forces_tlv *)pptr;
140427bfbee1SPeter Avalos u_int dlen;
140527bfbee1SPeter Avalos u_int rlen;
1406411677aeSAaron LI u_int invtlv;
140727bfbee1SPeter Avalos
140827bfbee1SPeter Avalos /*
140927bfbee1SPeter Avalos * forces_type_print() has ensured that len (the TLV length)
141027bfbee1SPeter Avalos * >= TLV_HDRL.
141127bfbee1SPeter Avalos */
141227bfbee1SPeter Avalos dlen = len - TLV_HDRL;
141327bfbee1SPeter Avalos if (dlen <= RD_MIN) {
1414*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\t\ttruncated Redirect TLV: %u bytes missing! ",
1415*ed775ee7SAntonio Huete Jimenez RD_MIN - dlen);
141627bfbee1SPeter Avalos return -1;
141727bfbee1SPeter Avalos }
141827bfbee1SPeter Avalos
141927bfbee1SPeter Avalos rlen = dlen;
142027bfbee1SPeter Avalos indent += 1;
142127bfbee1SPeter Avalos while (rlen != 0) {
1422*ed775ee7SAntonio Huete Jimenez uint16_t type, tlvl;
1423*ed775ee7SAntonio Huete Jimenez
1424*ed775ee7SAntonio Huete Jimenez type = GET_BE_U_2(tlv->type);
1425*ed775ee7SAntonio Huete Jimenez tlvl = GET_BE_U_2(tlv->length);
1426*ed775ee7SAntonio Huete Jimenez invtlv = tlv_valid(tlvl, rlen);
1427411677aeSAaron LI if (invtlv) {
1428*ed775ee7SAntonio Huete Jimenez ND_PRINT("Bad Redirect data\n");
142927bfbee1SPeter Avalos break;
1430411677aeSAaron LI }
143127bfbee1SPeter Avalos
143227bfbee1SPeter Avalos /*
143327bfbee1SPeter Avalos * At this point, tlv_valid() has ensured that the TLV
143427bfbee1SPeter Avalos * length is large enough but not too large (it doesn't
143527bfbee1SPeter Avalos * go past the end of the containing TLV).
143627bfbee1SPeter Avalos */
1437*ed775ee7SAntonio Huete Jimenez if (type == F_TLV_METD) {
1438411677aeSAaron LI print_metatlv(ndo, (const u_char *) TLV_DATA(tlv),
1439*ed775ee7SAntonio Huete Jimenez tlvl, 0,
1440*ed775ee7SAntonio Huete Jimenez indent);
1441*ed775ee7SAntonio Huete Jimenez } else if (type == F_TLV_REDD) {
1442411677aeSAaron LI print_reddata(ndo, (const u_char *) TLV_DATA(tlv),
1443*ed775ee7SAntonio Huete Jimenez tlvl, 0,
1444*ed775ee7SAntonio Huete Jimenez indent);
144527bfbee1SPeter Avalos } else {
1446*ed775ee7SAntonio Huete Jimenez ND_PRINT("Unknown REDIRECT TLV 0x%x len %u\n",
1447*ed775ee7SAntonio Huete Jimenez type,
1448*ed775ee7SAntonio Huete Jimenez tlvl);
144927bfbee1SPeter Avalos }
145027bfbee1SPeter Avalos
145127bfbee1SPeter Avalos tlv = GO_NXT_TLV(tlv, rlen);
145227bfbee1SPeter Avalos }
145327bfbee1SPeter Avalos
145427bfbee1SPeter Avalos if (rlen) {
1455*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\t\tMessy Redirect TLV header, type (0x%x)\n\t\texcess of %u Bytes ",
1456*ed775ee7SAntonio Huete Jimenez GET_BE_U_2(tlv->type),
1457*ed775ee7SAntonio Huete Jimenez rlen - GET_BE_U_2(tlv->length));
145827bfbee1SPeter Avalos return -1;
145927bfbee1SPeter Avalos }
146027bfbee1SPeter Avalos
146127bfbee1SPeter Avalos return 0;
146227bfbee1SPeter Avalos }
146327bfbee1SPeter Avalos
146427bfbee1SPeter Avalos #define OP_OFF 8
146527bfbee1SPeter Avalos #define OP_MIN 12
146627bfbee1SPeter Avalos
1467411677aeSAaron LI static int
lfbselect_print(netdissect_options * ndo,const u_char * pptr,u_int len,uint16_t op_msk,int indent)1468411677aeSAaron LI lfbselect_print(netdissect_options *ndo,
1469*ed775ee7SAntonio Huete Jimenez const u_char * pptr, u_int len,
1470411677aeSAaron LI uint16_t op_msk, int indent)
147127bfbee1SPeter Avalos {
147227bfbee1SPeter Avalos const struct forces_lfbsh *lfbs;
147327bfbee1SPeter Avalos const struct forces_tlv *otlv;
147427bfbee1SPeter Avalos char *ib = indent_pr(indent, 0);
147527bfbee1SPeter Avalos u_int dlen;
147627bfbee1SPeter Avalos u_int rlen;
1477411677aeSAaron LI u_int invtlv;
147827bfbee1SPeter Avalos
147927bfbee1SPeter Avalos /*
148027bfbee1SPeter Avalos * forces_type_print() has ensured that len (the TLV length)
148127bfbee1SPeter Avalos * >= TLV_HDRL.
148227bfbee1SPeter Avalos */
148327bfbee1SPeter Avalos dlen = len - TLV_HDRL;
148427bfbee1SPeter Avalos if (dlen <= OP_MIN) { /* id, instance, oper tlv header .. */
1485*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\t\ttruncated lfb selector: %u bytes missing! ",
1486*ed775ee7SAntonio Huete Jimenez OP_MIN - dlen);
148727bfbee1SPeter Avalos return -1;
148827bfbee1SPeter Avalos }
148927bfbee1SPeter Avalos
149027bfbee1SPeter Avalos /*
149127bfbee1SPeter Avalos * At this point, we know that dlen > OP_MIN; OP_OFF < OP_MIN, so
149227bfbee1SPeter Avalos * we also know that it's > OP_OFF.
149327bfbee1SPeter Avalos */
149427bfbee1SPeter Avalos rlen = dlen - OP_OFF;
149527bfbee1SPeter Avalos
149627bfbee1SPeter Avalos lfbs = (const struct forces_lfbsh *)pptr;
1497*ed775ee7SAntonio Huete Jimenez ND_TCHECK_SIZE(lfbs);
1498411677aeSAaron LI if (ndo->ndo_vflag >= 3) {
1499*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n%s%s(Classid %x) instance %x\n",
1500*ed775ee7SAntonio Huete Jimenez ib,
1501*ed775ee7SAntonio Huete Jimenez tok2str(ForCES_LFBs, NULL, GET_BE_U_4(lfbs->class)),
1502*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(lfbs->class),
1503*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(lfbs->instance));
150427bfbee1SPeter Avalos }
150527bfbee1SPeter Avalos
1506411677aeSAaron LI otlv = (const struct forces_tlv *)(lfbs + 1);
150727bfbee1SPeter Avalos
150827bfbee1SPeter Avalos indent += 1;
150927bfbee1SPeter Avalos while (rlen != 0) {
1510*ed775ee7SAntonio Huete Jimenez uint16_t type, tlvl;
1511*ed775ee7SAntonio Huete Jimenez
1512*ed775ee7SAntonio Huete Jimenez type = GET_BE_U_2(otlv->type);
1513*ed775ee7SAntonio Huete Jimenez tlvl = GET_BE_U_2(otlv->length);
1514*ed775ee7SAntonio Huete Jimenez invtlv = tlv_valid(tlvl, rlen);
151527bfbee1SPeter Avalos if (invtlv)
151627bfbee1SPeter Avalos break;
151727bfbee1SPeter Avalos
151827bfbee1SPeter Avalos /*
151927bfbee1SPeter Avalos * At this point, tlv_valid() has ensured that the TLV
152027bfbee1SPeter Avalos * length is large enough but not too large (it doesn't
152127bfbee1SPeter Avalos * go past the end of the containing TLV).
152227bfbee1SPeter Avalos */
1523*ed775ee7SAntonio Huete Jimenez if (op_valid(type, op_msk)) {
1524411677aeSAaron LI otlv_print(ndo, otlv, 0, indent);
152527bfbee1SPeter Avalos } else {
1526411677aeSAaron LI if (ndo->ndo_vflag < 3)
1527*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n");
1528*ed775ee7SAntonio Huete Jimenez ND_PRINT("\t\tINValid oper-TLV type 0x%x length %u for this ForCES message\n",
1529*ed775ee7SAntonio Huete Jimenez type, tlvl);
1530411677aeSAaron LI invoptlv_print(ndo, (const u_char *)otlv, rlen, 0, indent);
153127bfbee1SPeter Avalos }
153227bfbee1SPeter Avalos otlv = GO_NXT_TLV(otlv, rlen);
153327bfbee1SPeter Avalos }
153427bfbee1SPeter Avalos
153527bfbee1SPeter Avalos if (rlen) {
1536*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\t\tMessy oper TLV header, type (0x%x)\n\t\texcess of %u Bytes ",
1537*ed775ee7SAntonio Huete Jimenez GET_BE_U_2(otlv->type),
1538*ed775ee7SAntonio Huete Jimenez rlen - GET_BE_U_2(otlv->length));
153927bfbee1SPeter Avalos return -1;
154027bfbee1SPeter Avalos }
154127bfbee1SPeter Avalos
154227bfbee1SPeter Avalos return 0;
154327bfbee1SPeter Avalos
154427bfbee1SPeter Avalos trunc:
1545*ed775ee7SAntonio Huete Jimenez nd_print_trunc(ndo);
154627bfbee1SPeter Avalos return -1;
154727bfbee1SPeter Avalos }
154827bfbee1SPeter Avalos
1549411677aeSAaron LI static int
forces_type_print(netdissect_options * ndo,const u_char * pptr,const struct forcesh * fhdr _U_,u_int mlen,const struct tom_h * tops)1550411677aeSAaron LI forces_type_print(netdissect_options *ndo,
1551*ed775ee7SAntonio Huete Jimenez const u_char * pptr, const struct forcesh *fhdr _U_,
1552*ed775ee7SAntonio Huete Jimenez u_int mlen, const struct tom_h *tops)
155327bfbee1SPeter Avalos {
155427bfbee1SPeter Avalos const struct forces_tlv *tltlv;
155527bfbee1SPeter Avalos u_int rlen;
1556411677aeSAaron LI u_int invtlv;
155727bfbee1SPeter Avalos int rc = 0;
1558*ed775ee7SAntonio Huete Jimenez u_int ttlv = 0;
155927bfbee1SPeter Avalos
156027bfbee1SPeter Avalos /*
156127bfbee1SPeter Avalos * forces_print() has already checked that mlen >= ForCES_HDRL
156227bfbee1SPeter Avalos * by calling ForCES_HLN_VALID().
156327bfbee1SPeter Avalos */
156427bfbee1SPeter Avalos rlen = mlen - ForCES_HDRL;
156527bfbee1SPeter Avalos
156627bfbee1SPeter Avalos if (rlen > TLV_HLN) {
156727bfbee1SPeter Avalos if (tops->flags & ZERO_TTLV) {
1568*ed775ee7SAntonio Huete Jimenez ND_PRINT("<0x%x>Illegal Top level TLV!\n", tops->flags);
156927bfbee1SPeter Avalos return -1;
157027bfbee1SPeter Avalos }
157127bfbee1SPeter Avalos } else {
157227bfbee1SPeter Avalos if (tops->flags & ZERO_MORE_TTLV)
157327bfbee1SPeter Avalos return 0;
157427bfbee1SPeter Avalos if (tops->flags & ONE_MORE_TTLV) {
1575*ed775ee7SAntonio Huete Jimenez ND_PRINT("\tTop level TLV Data missing!\n");
157627bfbee1SPeter Avalos return -1;
157727bfbee1SPeter Avalos }
157827bfbee1SPeter Avalos }
157927bfbee1SPeter Avalos
158027bfbee1SPeter Avalos if (tops->flags & ZERO_TTLV) {
158127bfbee1SPeter Avalos return 0;
158227bfbee1SPeter Avalos }
158327bfbee1SPeter Avalos
158427bfbee1SPeter Avalos ttlv = tops->flags >> 4;
158527bfbee1SPeter Avalos tltlv = GET_TOP_TLV(pptr);
158627bfbee1SPeter Avalos
158727bfbee1SPeter Avalos /*XXX: 15 top level tlvs will probably be fine
158827bfbee1SPeter Avalos You are nuts if you send more ;-> */
158927bfbee1SPeter Avalos while (rlen != 0) {
1590*ed775ee7SAntonio Huete Jimenez uint16_t type, tlvl;
1591*ed775ee7SAntonio Huete Jimenez
1592*ed775ee7SAntonio Huete Jimenez type = GET_BE_U_2(tltlv->type);
1593*ed775ee7SAntonio Huete Jimenez tlvl = GET_BE_U_2(tltlv->length);
1594*ed775ee7SAntonio Huete Jimenez invtlv = tlv_valid(tlvl, rlen);
159527bfbee1SPeter Avalos if (invtlv)
159627bfbee1SPeter Avalos break;
159727bfbee1SPeter Avalos
159827bfbee1SPeter Avalos /*
159927bfbee1SPeter Avalos * At this point, tlv_valid() has ensured that the TLV
160027bfbee1SPeter Avalos * length is large enough but not too large (it doesn't
160127bfbee1SPeter Avalos * go past the end of the packet).
160227bfbee1SPeter Avalos */
1603*ed775ee7SAntonio Huete Jimenez if (!ttlv_valid(type)) {
1604*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\tInvalid ForCES Top TLV type=0x%x",
1605*ed775ee7SAntonio Huete Jimenez type);
160627bfbee1SPeter Avalos return -1;
160727bfbee1SPeter Avalos }
160827bfbee1SPeter Avalos
1609411677aeSAaron LI if (ndo->ndo_vflag >= 3)
1610*ed775ee7SAntonio Huete Jimenez ND_PRINT("\t%s, length %u (data length %u Bytes)",
1611*ed775ee7SAntonio Huete Jimenez tok2str(ForCES_TLV, NULL, type),
1612*ed775ee7SAntonio Huete Jimenez tlvl,
1613*ed775ee7SAntonio Huete Jimenez tlvl - TLV_HDRL);
161427bfbee1SPeter Avalos
1615411677aeSAaron LI rc = tops->print(ndo, (const u_char *) TLV_DATA(tltlv),
1616*ed775ee7SAntonio Huete Jimenez tlvl,
1617*ed775ee7SAntonio Huete Jimenez tops->op_msk, 9);
161827bfbee1SPeter Avalos if (rc < 0) {
161927bfbee1SPeter Avalos return -1;
162027bfbee1SPeter Avalos }
162127bfbee1SPeter Avalos tltlv = GO_NXT_TLV(tltlv, rlen);
162227bfbee1SPeter Avalos ttlv--;
162327bfbee1SPeter Avalos if (ttlv <= 0)
162427bfbee1SPeter Avalos break;
162527bfbee1SPeter Avalos }
162627bfbee1SPeter Avalos /*
162727bfbee1SPeter Avalos * XXX - if ttlv != 0, does that mean that the packet was too
162827bfbee1SPeter Avalos * short, and didn't have *enough* TLVs in it?
162927bfbee1SPeter Avalos */
163027bfbee1SPeter Avalos if (rlen) {
1631*ed775ee7SAntonio Huete Jimenez ND_PRINT("\tMess TopTLV header: min %u, total %u advertised %u ",
1632*ed775ee7SAntonio Huete Jimenez TLV_HDRL, rlen, GET_BE_U_2(tltlv->length));
163327bfbee1SPeter Avalos return -1;
163427bfbee1SPeter Avalos }
163527bfbee1SPeter Avalos
163627bfbee1SPeter Avalos return 0;
163727bfbee1SPeter Avalos }
163827bfbee1SPeter Avalos
1639411677aeSAaron LI void
forces_print(netdissect_options * ndo,const u_char * pptr,u_int len)1640411677aeSAaron LI forces_print(netdissect_options *ndo,
1641*ed775ee7SAntonio Huete Jimenez const u_char * pptr, u_int len)
164227bfbee1SPeter Avalos {
164327bfbee1SPeter Avalos const struct forcesh *fhdr;
164427bfbee1SPeter Avalos u_int mlen;
1645411677aeSAaron LI uint32_t flg_raw;
1646*ed775ee7SAntonio Huete Jimenez uint8_t tom;
164727bfbee1SPeter Avalos const struct tom_h *tops;
164827bfbee1SPeter Avalos int rc = 0;
164927bfbee1SPeter Avalos
1650*ed775ee7SAntonio Huete Jimenez ndo->ndo_protocol = "forces";
165127bfbee1SPeter Avalos fhdr = (const struct forcesh *)pptr;
1652*ed775ee7SAntonio Huete Jimenez ND_TCHECK_SIZE(fhdr);
1653*ed775ee7SAntonio Huete Jimenez tom = GET_U_1(fhdr->fm_tom);
1654*ed775ee7SAntonio Huete Jimenez if (!tom_valid(tom)) {
1655*ed775ee7SAntonio Huete Jimenez ND_PRINT("Invalid ForCES message type %u\n", tom);
165627bfbee1SPeter Avalos goto error;
165727bfbee1SPeter Avalos }
165827bfbee1SPeter Avalos
165927bfbee1SPeter Avalos mlen = ForCES_BLN(fhdr);
166027bfbee1SPeter Avalos
1661*ed775ee7SAntonio Huete Jimenez tops = get_forces_tom(tom);
166227bfbee1SPeter Avalos if (tops->v == TOM_RSVD) {
1663*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\tUnknown ForCES message type=0x%x", tom);
166427bfbee1SPeter Avalos goto error;
166527bfbee1SPeter Avalos }
166627bfbee1SPeter Avalos
1667*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\tForCES %s ", tops->s);
166827bfbee1SPeter Avalos if (!ForCES_HLN_VALID(mlen, len)) {
1669*ed775ee7SAntonio Huete Jimenez ND_PRINT("Illegal ForCES pkt len - min %u, total recvd %u, advertised %u ",
1670*ed775ee7SAntonio Huete Jimenez ForCES_HDRL, len, ForCES_BLN(fhdr));
167127bfbee1SPeter Avalos goto error;
167227bfbee1SPeter Avalos }
167327bfbee1SPeter Avalos
1674*ed775ee7SAntonio Huete Jimenez flg_raw = GET_BE_U_4(pptr + 20);
1675411677aeSAaron LI if (ndo->ndo_vflag >= 1) {
1676*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\tForCES Version %u len %uB flags 0x%08x ",
1677*ed775ee7SAntonio Huete Jimenez ForCES_V(fhdr), mlen, flg_raw);
1678*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\tSrcID 0x%x(%s) DstID 0x%x(%s) Correlator 0x%" PRIx64,
167927bfbee1SPeter Avalos ForCES_SID(fhdr), ForCES_node(ForCES_SID(fhdr)),
168027bfbee1SPeter Avalos ForCES_DID(fhdr), ForCES_node(ForCES_DID(fhdr)),
1681*ed775ee7SAntonio Huete Jimenez GET_BE_U_8(fhdr->fm_cor));
168227bfbee1SPeter Avalos
168327bfbee1SPeter Avalos }
1684411677aeSAaron LI if (ndo->ndo_vflag >= 2) {
1685*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\tForCES flags:\n\t %s(0x%x), prio=%u, %s(0x%x),\n\t %s(0x%x), %s(0x%x)\n",
1686411677aeSAaron LI tok2str(ForCES_ACKs, "ACKUnknown", ForCES_ACK(fhdr)),
1687411677aeSAaron LI ForCES_ACK(fhdr),
168827bfbee1SPeter Avalos ForCES_PRI(fhdr),
1689411677aeSAaron LI tok2str(ForCES_EMs, "EMUnknown", ForCES_EM(fhdr)),
1690411677aeSAaron LI ForCES_EM(fhdr),
1691411677aeSAaron LI tok2str(ForCES_ATs, "ATUnknown", ForCES_AT(fhdr)),
1692411677aeSAaron LI ForCES_AT(fhdr),
1693411677aeSAaron LI tok2str(ForCES_TPs, "TPUnknown", ForCES_TP(fhdr)),
1694*ed775ee7SAntonio Huete Jimenez ForCES_TP(fhdr));
1695*ed775ee7SAntonio Huete Jimenez ND_PRINT("\t Extra flags: rsv(b5-7) 0x%x rsv(b13-31) 0x%x\n",
1696*ed775ee7SAntonio Huete Jimenez ForCES_RS1(fhdr), ForCES_RS2(fhdr));
169727bfbee1SPeter Avalos }
1698411677aeSAaron LI rc = forces_type_print(ndo, pptr, fhdr, mlen, tops);
169927bfbee1SPeter Avalos if (rc < 0) {
170027bfbee1SPeter Avalos error:
1701*ed775ee7SAntonio Huete Jimenez hex_print(ndo, "\n\t[", pptr, len);
1702*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\t]");
170327bfbee1SPeter Avalos return;
170427bfbee1SPeter Avalos }
170527bfbee1SPeter Avalos
1706411677aeSAaron LI if (ndo->ndo_vflag >= 4) {
1707*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\t Raw ForCES message\n\t [");
1708*ed775ee7SAntonio Huete Jimenez hex_print(ndo, "\n\t ", pptr, len);
1709*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\t ]");
171027bfbee1SPeter Avalos }
171127bfbee1SPeter Avalos return;
171227bfbee1SPeter Avalos
171327bfbee1SPeter Avalos trunc:
1714*ed775ee7SAntonio Huete Jimenez nd_print_trunc(ndo);
171527bfbee1SPeter Avalos }
1716