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