print-ldp.c revision 1.11 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 * Original code by Hannes Gredler (hannes (at) gredler.at)
14 * and Steinar Haug (sthaug (at) nethelp.no)
15 */
16
17 #include <sys/cdefs.h>
18 #ifndef lint
19 __RCSID("$NetBSD: print-ldp.c,v 1.11 2023/08/17 20:19:40 christos Exp $");
20 #endif
21
22 /* \summary: Label Distribution Protocol (LDP) printer */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include "netdissect-stdinc.h"
29
30 #include "netdissect.h"
31 #include "extract.h"
32 #include "addrtoname.h"
33
34 #include "l2vpn.h"
35 #include "af.h"
36
37
38 /*
39 * ldp common header
40 *
41 * 0 1 2 3
42 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
43 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 * | Version | PDU Length |
45 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46 * | LDP Identifier |
47 * + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48 * | |
49 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50 *
51 */
52
53 struct ldp_common_header {
54 nd_uint16_t version;
55 nd_uint16_t pdu_length;
56 nd_ipv4 lsr_id;
57 nd_uint16_t label_space;
58 };
59
60 #define LDP_VERSION 1
61
62 /*
63 * ldp message header
64 *
65 * 0 1 2 3
66 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
67 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
68 * |U| Message Type | Message Length |
69 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
70 * | Message ID |
71 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
72 * | |
73 * + +
74 * | Mandatory Parameters |
75 * + +
76 * | |
77 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
78 * | |
79 * + +
80 * | Optional Parameters |
81 * + +
82 * | |
83 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
84 */
85
86 struct ldp_msg_header {
87 nd_uint16_t type;
88 nd_uint16_t length;
89 nd_uint32_t id;
90 };
91
92 #define LDP_MASK_MSG_TYPE(x) ((x)&0x7fff)
93 #define LDP_MASK_U_BIT(x) ((x)&0x8000)
94
95 #define LDP_MSG_NOTIF 0x0001
96 #define LDP_MSG_HELLO 0x0100
97 #define LDP_MSG_INIT 0x0200
98 #define LDP_MSG_KEEPALIVE 0x0201
99 #define LDP_MSG_ADDRESS 0x0300
100 #define LDP_MSG_ADDRESS_WITHDRAW 0x0301
101 #define LDP_MSG_LABEL_MAPPING 0x0400
102 #define LDP_MSG_LABEL_REQUEST 0x0401
103 #define LDP_MSG_LABEL_WITHDRAW 0x0402
104 #define LDP_MSG_LABEL_RELEASE 0x0403
105 #define LDP_MSG_LABEL_ABORT_REQUEST 0x0404
106
107 #define LDP_VENDOR_PRIVATE_MIN 0x3e00
108 #define LDP_VENDOR_PRIVATE_MAX 0x3eff
109 #define LDP_EXPERIMENTAL_MIN 0x3f00
110 #define LDP_EXPERIMENTAL_MAX 0x3fff
111
112 static const struct tok ldp_msg_values[] = {
113 { LDP_MSG_NOTIF, "Notification" },
114 { LDP_MSG_HELLO, "Hello" },
115 { LDP_MSG_INIT, "Initialization" },
116 { LDP_MSG_KEEPALIVE, "Keepalive" },
117 { LDP_MSG_ADDRESS, "Address" },
118 { LDP_MSG_ADDRESS_WITHDRAW, "Address Withdraw" },
119 { LDP_MSG_LABEL_MAPPING, "Label Mapping" },
120 { LDP_MSG_LABEL_REQUEST, "Label Request" },
121 { LDP_MSG_LABEL_WITHDRAW, "Label Withdraw" },
122 { LDP_MSG_LABEL_RELEASE, "Label Release" },
123 { LDP_MSG_LABEL_ABORT_REQUEST, "Label Abort Request" },
124 { 0, NULL}
125 };
126
127 #define LDP_MASK_TLV_TYPE(x) ((x)&0x3fff)
128 #define LDP_MASK_F_BIT(x) ((x)&0x4000)
129
130 #define LDP_TLV_FEC 0x0100
131 #define LDP_TLV_ADDRESS_LIST 0x0101
132 #define LDP_TLV_ADDRESS_LIST_AFNUM_LEN 2
133 #define LDP_TLV_HOP_COUNT 0x0103
134 #define LDP_TLV_PATH_VECTOR 0x0104
135 #define LDP_TLV_GENERIC_LABEL 0x0200
136 #define LDP_TLV_ATM_LABEL 0x0201
137 #define LDP_TLV_FR_LABEL 0x0202
138 #define LDP_TLV_STATUS 0x0300
139 #define LDP_TLV_EXTD_STATUS 0x0301
140 #define LDP_TLV_RETURNED_PDU 0x0302
141 #define LDP_TLV_RETURNED_MSG 0x0303
142 #define LDP_TLV_COMMON_HELLO 0x0400
143 #define LDP_TLV_IPV4_TRANSPORT_ADDR 0x0401
144 #define LDP_TLV_CONFIG_SEQ_NUMBER 0x0402
145 #define LDP_TLV_IPV6_TRANSPORT_ADDR 0x0403
146 #define LDP_TLV_COMMON_SESSION 0x0500
147 #define LDP_TLV_ATM_SESSION_PARM 0x0501
148 #define LDP_TLV_FR_SESSION_PARM 0x0502
149 #define LDP_TLV_FT_SESSION 0x0503
150 #define LDP_TLV_LABEL_REQUEST_MSG_ID 0x0600
151 #define LDP_TLV_MTU 0x0601 /* rfc 3988 */
152
153 static const struct tok ldp_tlv_values[] = {
154 { LDP_TLV_FEC, "FEC" },
155 { LDP_TLV_ADDRESS_LIST, "Address List" },
156 { LDP_TLV_HOP_COUNT, "Hop Count" },
157 { LDP_TLV_PATH_VECTOR, "Path Vector" },
158 { LDP_TLV_GENERIC_LABEL, "Generic Label" },
159 { LDP_TLV_ATM_LABEL, "ATM Label" },
160 { LDP_TLV_FR_LABEL, "Frame-Relay Label" },
161 { LDP_TLV_STATUS, "Status" },
162 { LDP_TLV_EXTD_STATUS, "Extended Status" },
163 { LDP_TLV_RETURNED_PDU, "Returned PDU" },
164 { LDP_TLV_RETURNED_MSG, "Returned Message" },
165 { LDP_TLV_COMMON_HELLO, "Common Hello Parameters" },
166 { LDP_TLV_IPV4_TRANSPORT_ADDR, "IPv4 Transport Address" },
167 { LDP_TLV_CONFIG_SEQ_NUMBER, "Configuration Sequence Number" },
168 { LDP_TLV_IPV6_TRANSPORT_ADDR, "IPv6 Transport Address" },
169 { LDP_TLV_COMMON_SESSION, "Common Session Parameters" },
170 { LDP_TLV_ATM_SESSION_PARM, "ATM Session Parameters" },
171 { LDP_TLV_FR_SESSION_PARM, "Frame-Relay Session Parameters" },
172 { LDP_TLV_FT_SESSION, "Fault-Tolerant Session Parameters" },
173 { LDP_TLV_LABEL_REQUEST_MSG_ID, "Label Request Message ID" },
174 { LDP_TLV_MTU, "MTU" },
175 { 0, NULL}
176 };
177
178 #define LDP_FEC_WILDCARD 0x01
179 #define LDP_FEC_PREFIX 0x02
180 #define LDP_FEC_HOSTADDRESS 0x03
181 /* From RFC 4906; should probably be updated to RFC 4447 (e.g., VC -> PW) */
182 #define LDP_FEC_MARTINI_VC 0x80
183
184 static const struct tok ldp_fec_values[] = {
185 { LDP_FEC_WILDCARD, "Wildcard" },
186 { LDP_FEC_PREFIX, "Prefix" },
187 { LDP_FEC_HOSTADDRESS, "Host address" },
188 { LDP_FEC_MARTINI_VC, "Martini VC" },
189 { 0, NULL}
190 };
191
192 #define LDP_FEC_MARTINI_IFPARM_MTU 0x01
193 #define LDP_FEC_MARTINI_IFPARM_DESC 0x03
194 #define LDP_FEC_MARTINI_IFPARM_VCCV 0x0c
195
196 static const struct tok ldp_fec_martini_ifparm_values[] = {
197 { LDP_FEC_MARTINI_IFPARM_MTU, "MTU" },
198 { LDP_FEC_MARTINI_IFPARM_DESC, "Description" },
199 { LDP_FEC_MARTINI_IFPARM_VCCV, "VCCV" },
200 { 0, NULL}
201 };
202
203 /* draft-ietf-pwe3-vccv-04.txt */
204 static const struct tok ldp_fec_martini_ifparm_vccv_cc_values[] = {
205 { 0x01, "PWE3 control word" },
206 { 0x02, "MPLS Router Alert Label" },
207 { 0x04, "MPLS inner label TTL = 1" },
208 { 0, NULL}
209 };
210
211 /* draft-ietf-pwe3-vccv-04.txt */
212 static const struct tok ldp_fec_martini_ifparm_vccv_cv_values[] = {
213 { 0x01, "ICMP Ping" },
214 { 0x02, "LSP Ping" },
215 { 0x04, "BFD" },
216 { 0, NULL}
217 };
218
219 static u_int ldp_pdu_print(netdissect_options *, const u_char *);
220
221 /*
222 * ldp tlv header
223 *
224 * 0 1 2 3
225 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
226 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
227 * |U|F| Type | Length |
228 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
229 * | |
230 * | Value |
231 * ~ ~
232 * | |
233 * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
234 * | |
235 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
236 */
237
238 #define TLV_TCHECK(minlen) \
239 if (tlv_tlen < minlen) { \
240 ND_PRINT(" [tlv length %u < %u]", tlv_tlen, minlen); \
241 nd_print_invalid(ndo); \
242 goto invalid; \
243 }
244
245 static u_int
246 ldp_tlv_print(netdissect_options *ndo,
247 const u_char *tptr,
248 u_int msg_tlen)
249 {
250 struct ldp_tlv_header {
251 nd_uint16_t type;
252 nd_uint16_t length;
253 };
254
255 const struct ldp_tlv_header *ldp_tlv_header;
256 u_short tlv_type,tlv_len,tlv_tlen,af,ft_flags;
257 u_char fec_type;
258 u_int ui,vc_info_len, vc_info_tlv_type, vc_info_tlv_len,idx;
259 char buf[100];
260 int i;
261
262 ldp_tlv_header = (const struct ldp_tlv_header *)tptr;
263 ND_TCHECK_SIZE(ldp_tlv_header);
264 tlv_len=GET_BE_U_2(ldp_tlv_header->length);
265 if (tlv_len + 4U > msg_tlen) {
266 ND_PRINT("\n\t\t TLV contents go past end of message");
267 return 0;
268 }
269 tlv_tlen=tlv_len;
270 tlv_type=LDP_MASK_TLV_TYPE(GET_BE_U_2(ldp_tlv_header->type));
271
272 /* FIXME vendor private / experimental check */
273 ND_PRINT("\n\t %s TLV (0x%04x), length: %u, Flags: [%s and %s forward if unknown]",
274 tok2str(ldp_tlv_values,
275 "Unknown",
276 tlv_type),
277 tlv_type,
278 tlv_len,
279 LDP_MASK_U_BIT(GET_BE_U_2(ldp_tlv_header->type)) ? "continue processing" : "ignore",
280 LDP_MASK_F_BIT(GET_BE_U_2(ldp_tlv_header->type)) ? "do" : "don't");
281
282 tptr+=sizeof(struct ldp_tlv_header);
283
284 switch(tlv_type) {
285
286 case LDP_TLV_COMMON_HELLO:
287 TLV_TCHECK(4);
288 ND_PRINT("\n\t Hold Time: %us, Flags: [%s Hello%s]",
289 GET_BE_U_2(tptr),
290 (GET_BE_U_2(tptr + 2)&0x8000) ? "Targeted" : "Link",
291 (GET_BE_U_2(tptr + 2)&0x4000) ? ", Request for targeted Hellos" : "");
292 break;
293
294 case LDP_TLV_IPV4_TRANSPORT_ADDR:
295 TLV_TCHECK(4);
296 ND_PRINT("\n\t IPv4 Transport Address: %s", GET_IPADDR_STRING(tptr));
297 break;
298 case LDP_TLV_IPV6_TRANSPORT_ADDR:
299 TLV_TCHECK(16);
300 ND_PRINT("\n\t IPv6 Transport Address: %s", GET_IP6ADDR_STRING(tptr));
301 break;
302 case LDP_TLV_CONFIG_SEQ_NUMBER:
303 TLV_TCHECK(4);
304 ND_PRINT("\n\t Sequence Number: %u", GET_BE_U_4(tptr));
305 break;
306
307 case LDP_TLV_ADDRESS_LIST:
308 TLV_TCHECK(LDP_TLV_ADDRESS_LIST_AFNUM_LEN);
309 af = GET_BE_U_2(tptr);
310 tptr+=LDP_TLV_ADDRESS_LIST_AFNUM_LEN;
311 tlv_tlen -= LDP_TLV_ADDRESS_LIST_AFNUM_LEN;
312 ND_PRINT("\n\t Address Family: %s, addresses",
313 tok2str(af_values, "Unknown (%u)", af));
314 switch (af) {
315 case AFNUM_INET:
316 while(tlv_tlen >= sizeof(nd_ipv4)) {
317 ND_PRINT(" %s", GET_IPADDR_STRING(tptr));
318 tlv_tlen-=sizeof(nd_ipv4);
319 tptr+=sizeof(nd_ipv4);
320 }
321 break;
322 case AFNUM_INET6:
323 while(tlv_tlen >= sizeof(nd_ipv6)) {
324 ND_PRINT(" %s", GET_IP6ADDR_STRING(tptr));
325 tlv_tlen-=sizeof(nd_ipv6);
326 tptr+=sizeof(nd_ipv6);
327 }
328 break;
329 default:
330 /* unknown AF */
331 break;
332 }
333 break;
334
335 case LDP_TLV_COMMON_SESSION:
336 TLV_TCHECK(8);
337 ND_PRINT("\n\t Version: %u, Keepalive: %us, Flags: [Downstream %s, Loop Detection %s]",
338 GET_BE_U_2(tptr), GET_BE_U_2(tptr + 2),
339 (GET_BE_U_2(tptr + 6)&0x8000) ? "On Demand" : "Unsolicited",
340 (GET_BE_U_2(tptr + 6)&0x4000) ? "Enabled" : "Disabled"
341 );
342 break;
343
344 case LDP_TLV_FEC:
345 TLV_TCHECK(1);
346 fec_type = GET_U_1(tptr);
347 ND_PRINT("\n\t %s FEC (0x%02x)",
348 tok2str(ldp_fec_values, "Unknown", fec_type),
349 fec_type);
350
351 tptr+=1;
352 tlv_tlen-=1;
353 switch(fec_type) {
354
355 case LDP_FEC_WILDCARD:
356 break;
357 case LDP_FEC_PREFIX:
358 TLV_TCHECK(2);
359 af = GET_BE_U_2(tptr);
360 tptr+=2;
361 tlv_tlen-=2;
362 if (af == AFNUM_INET) {
363 i=decode_prefix4(ndo, tptr, tlv_tlen, buf, sizeof(buf));
364 if (i == -2)
365 goto trunc;
366 if (i == -3)
367 ND_PRINT(": IPv4 prefix (goes past end of TLV)");
368 else if (i == -1)
369 ND_PRINT(": IPv4 prefix (invalid length)");
370 else
371 ND_PRINT(": IPv4 prefix %s", buf);
372 }
373 else if (af == AFNUM_INET6) {
374 i=decode_prefix6(ndo, tptr, tlv_tlen, buf, sizeof(buf));
375 if (i == -2)
376 goto trunc;
377 if (i == -3)
378 ND_PRINT(": IPv4 prefix (goes past end of TLV)");
379 else if (i == -1)
380 ND_PRINT(": IPv6 prefix (invalid length)");
381 else
382 ND_PRINT(": IPv6 prefix %s", buf);
383 }
384 else
385 ND_PRINT(": Address family %u prefix", af);
386 break;
387 case LDP_FEC_HOSTADDRESS:
388 break;
389 case LDP_FEC_MARTINI_VC:
390 /*
391 * We assume the type was supposed to be one of the MPLS
392 * Pseudowire Types.
393 */
394 TLV_TCHECK(7);
395 vc_info_len = GET_U_1(tptr + 2);
396
397 /*
398 * According to RFC 4908, the VC info Length field can be zero,
399 * in which case not only are there no interface parameters,
400 * there's no VC ID.
401 */
402 if (vc_info_len == 0) {
403 ND_PRINT(": %s, %scontrol word, group-ID %u, VC-info-length: %u",
404 tok2str(mpls_pw_types_values, "Unknown", GET_BE_U_2(tptr)&0x7fff),
405 GET_BE_U_2(tptr)&0x8000 ? "" : "no ",
406 GET_BE_U_4(tptr + 3),
407 vc_info_len);
408 break;
409 }
410
411 /* Make sure we have the VC ID as well */
412 TLV_TCHECK(11);
413 ND_PRINT(": %s, %scontrol word, group-ID %u, VC-ID %u, VC-info-length: %u",
414 tok2str(mpls_pw_types_values, "Unknown", GET_BE_U_2(tptr)&0x7fff),
415 GET_BE_U_2(tptr)&0x8000 ? "" : "no ",
416 GET_BE_U_4(tptr + 3),
417 GET_BE_U_4(tptr + 7),
418 vc_info_len);
419 if (vc_info_len < 4) {
420 /* minimum 4, for the VC ID */
421 ND_PRINT(" (invalid, < 4");
422 return(tlv_len+4); /* Type & Length fields not included */
423 }
424 vc_info_len -= 4; /* subtract out the VC ID, giving the length of the interface parameters */
425
426 /* Skip past the fixed information and the VC ID */
427 tptr+=11;
428 tlv_tlen-=11;
429 TLV_TCHECK(vc_info_len);
430
431 while (vc_info_len > 2) {
432 vc_info_tlv_type = GET_U_1(tptr);
433 vc_info_tlv_len = GET_U_1(tptr + 1);
434 if (vc_info_tlv_len < 2)
435 break;
436 if (vc_info_len < vc_info_tlv_len)
437 break;
438
439 ND_PRINT("\n\t\tInterface Parameter: %s (0x%02x), len %u",
440 tok2str(ldp_fec_martini_ifparm_values,"Unknown",vc_info_tlv_type),
441 vc_info_tlv_type,
442 vc_info_tlv_len);
443
444 switch(vc_info_tlv_type) {
445 case LDP_FEC_MARTINI_IFPARM_MTU:
446 ND_PRINT(": %u", GET_BE_U_2(tptr + 2));
447 break;
448
449 case LDP_FEC_MARTINI_IFPARM_DESC:
450 ND_PRINT(": ");
451 for (idx = 2; idx < vc_info_tlv_len; idx++)
452 fn_print_char(ndo, GET_U_1(tptr + idx));
453 break;
454
455 case LDP_FEC_MARTINI_IFPARM_VCCV:
456 ND_PRINT("\n\t\t Control Channels (0x%02x) = [%s]",
457 GET_U_1((tptr + 2)),
458 bittok2str(ldp_fec_martini_ifparm_vccv_cc_values, "none", GET_U_1((tptr + 2))));
459 ND_PRINT("\n\t\t CV Types (0x%02x) = [%s]",
460 GET_U_1((tptr + 3)),
461 bittok2str(ldp_fec_martini_ifparm_vccv_cv_values, "none", GET_U_1((tptr + 3))));
462 break;
463
464 default:
465 print_unknown_data(ndo, tptr+2, "\n\t\t ", vc_info_tlv_len-2);
466 break;
467 }
468
469 vc_info_len -= vc_info_tlv_len;
470 tptr += vc_info_tlv_len;
471 }
472 break;
473 }
474
475 break;
476
477 case LDP_TLV_GENERIC_LABEL:
478 TLV_TCHECK(4);
479 ND_PRINT("\n\t Label: %u", GET_BE_U_4(tptr) & 0xfffff);
480 break;
481
482 case LDP_TLV_STATUS:
483 TLV_TCHECK(8);
484 ui = GET_BE_U_4(tptr);
485 tptr+=4;
486 ND_PRINT("\n\t Status: 0x%02x, Flags: [%s and %s forward]",
487 ui&0x3fffffff,
488 ui&0x80000000 ? "Fatal error" : "Advisory Notification",
489 ui&0x40000000 ? "do" : "don't");
490 ui = GET_BE_U_4(tptr);
491 tptr+=4;
492 if (ui)
493 ND_PRINT(", causing Message ID: 0x%08x", ui);
494 break;
495
496 case LDP_TLV_FT_SESSION:
497 TLV_TCHECK(12);
498 ft_flags = GET_BE_U_2(tptr);
499 ND_PRINT("\n\t Flags: [%sReconnect, %sSave State, %sAll-Label Protection, %s Checkpoint, %sRe-Learn State]",
500 ft_flags&0x8000 ? "" : "No ",
501 ft_flags&0x8 ? "" : "Don't ",
502 ft_flags&0x4 ? "" : "No ",
503 ft_flags&0x2 ? "Sequence Numbered Label" : "All Labels",
504 ft_flags&0x1 ? "" : "Don't ");
505 /* 16 bits (FT Flags) + 16 bits (Reserved) */
506 tptr+=4;
507 ui = GET_BE_U_4(tptr);
508 if (ui)
509 ND_PRINT(", Reconnect Timeout: %ums", ui);
510 tptr+=4;
511 ui = GET_BE_U_4(tptr);
512 if (ui)
513 ND_PRINT(", Recovery Time: %ums", ui);
514 break;
515
516 case LDP_TLV_MTU:
517 TLV_TCHECK(2);
518 ND_PRINT("\n\t MTU: %u", GET_BE_U_2(tptr));
519 break;
520
521
522 /*
523 * FIXME those are the defined TLVs that lack a decoder
524 * you are welcome to contribute code ;-)
525 */
526
527 case LDP_TLV_HOP_COUNT:
528 case LDP_TLV_PATH_VECTOR:
529 case LDP_TLV_ATM_LABEL:
530 case LDP_TLV_FR_LABEL:
531 case LDP_TLV_EXTD_STATUS:
532 case LDP_TLV_RETURNED_PDU:
533 case LDP_TLV_RETURNED_MSG:
534 case LDP_TLV_ATM_SESSION_PARM:
535 case LDP_TLV_FR_SESSION_PARM:
536 case LDP_TLV_LABEL_REQUEST_MSG_ID:
537
538 default:
539 if (ndo->ndo_vflag <= 1)
540 print_unknown_data(ndo, tptr, "\n\t ", tlv_tlen);
541 break;
542 }
543 return(tlv_len+4); /* Type & Length fields not included */
544
545 trunc:
546 nd_trunc_longjmp(ndo);
547
548 invalid:
549 return(tlv_len+4); /* Type & Length fields not included */
550 }
551
552 void
553 ldp_print(netdissect_options *ndo,
554 const u_char *pptr, u_int len)
555 {
556 u_int processed;
557
558 ndo->ndo_protocol = "ldp";
559 while (len > (sizeof(struct ldp_common_header) + sizeof(struct ldp_msg_header))) {
560 processed = ldp_pdu_print(ndo, pptr);
561 if (processed == 0)
562 return;
563 if (len < processed) {
564 ND_PRINT(" [remaining length %u < %u]", len, processed);
565 nd_print_invalid(ndo);
566 break;
567 }
568 len -= processed;
569 pptr += processed;
570 }
571 }
572
573 static u_int
574 ldp_pdu_print(netdissect_options *ndo,
575 const u_char *pptr)
576 {
577 const struct ldp_common_header *ldp_com_header;
578 const struct ldp_msg_header *ldp_msg_header;
579 const u_char *tptr,*msg_tptr;
580 u_short tlen;
581 u_short pdu_len,msg_len,msg_type;
582 u_int msg_tlen;
583 int hexdump,processed;
584
585 ldp_com_header = (const struct ldp_common_header *)pptr;
586 ND_TCHECK_SIZE(ldp_com_header);
587
588 /*
589 * Sanity checking of the header.
590 */
591 if (GET_BE_U_2(ldp_com_header->version) != LDP_VERSION) {
592 ND_PRINT("%sLDP version %u packet not supported",
593 (ndo->ndo_vflag < 1) ? "" : "\n\t",
594 GET_BE_U_2(ldp_com_header->version));
595 return 0;
596 }
597
598 pdu_len = GET_BE_U_2(ldp_com_header->pdu_length);
599 if (pdu_len < sizeof(struct ldp_common_header)-4) {
600 /* length too short */
601 ND_PRINT("%sLDP, pdu-length: %u (too short, < %zu)",
602 (ndo->ndo_vflag < 1) ? "" : "\n\t",
603 pdu_len,
604 sizeof(struct ldp_common_header)-4);
605 return 0;
606 }
607
608 /* print the LSR-ID, label-space & length */
609 ND_PRINT("%sLDP, Label-Space-ID: %s:%u, pdu-length: %u",
610 (ndo->ndo_vflag < 1) ? "" : "\n\t",
611 GET_IPADDR_STRING(ldp_com_header->lsr_id),
612 GET_BE_U_2(ldp_com_header->label_space),
613 pdu_len);
614
615 /* bail out if non-verbose */
616 if (ndo->ndo_vflag < 1)
617 return 0;
618
619 /* ok they seem to want to know everything - lets fully decode it */
620 tptr = pptr + sizeof(struct ldp_common_header);
621 tlen = pdu_len - (sizeof(struct ldp_common_header)-4); /* Type & Length fields not included */
622
623 while(tlen>0) {
624 /* did we capture enough for fully decoding the msg header ? */
625 ND_TCHECK_LEN(tptr, sizeof(struct ldp_msg_header));
626
627 ldp_msg_header = (const struct ldp_msg_header *)tptr;
628 msg_len=GET_BE_U_2(ldp_msg_header->length);
629 msg_type=LDP_MASK_MSG_TYPE(GET_BE_U_2(ldp_msg_header->type));
630
631 if (msg_len < sizeof(struct ldp_msg_header)-4) {
632 /* length too short */
633 /* FIXME vendor private / experimental check */
634 ND_PRINT("\n\t %s Message (0x%04x), length: %u (too short, < %zu)",
635 tok2str(ldp_msg_values,
636 "Unknown",
637 msg_type),
638 msg_type,
639 msg_len,
640 sizeof(struct ldp_msg_header)-4);
641 return 0;
642 }
643
644 /* FIXME vendor private / experimental check */
645 ND_PRINT("\n\t %s Message (0x%04x), length: %u, Message ID: 0x%08x, Flags: [%s if unknown]",
646 tok2str(ldp_msg_values,
647 "Unknown",
648 msg_type),
649 msg_type,
650 msg_len,
651 GET_BE_U_4(ldp_msg_header->id),
652 LDP_MASK_U_BIT(GET_BE_U_2(ldp_msg_header->type)) ? "continue processing" : "ignore");
653
654 msg_tptr=tptr+sizeof(struct ldp_msg_header);
655 msg_tlen=msg_len-(sizeof(struct ldp_msg_header)-4); /* Type & Length fields not included */
656
657 /* did we capture enough for fully decoding the message ? */
658 ND_TCHECK_LEN(tptr, msg_len);
659 hexdump=FALSE;
660
661 switch(msg_type) {
662
663 case LDP_MSG_NOTIF:
664 case LDP_MSG_HELLO:
665 case LDP_MSG_INIT:
666 case LDP_MSG_KEEPALIVE:
667 case LDP_MSG_ADDRESS:
668 case LDP_MSG_LABEL_MAPPING:
669 case LDP_MSG_ADDRESS_WITHDRAW:
670 case LDP_MSG_LABEL_WITHDRAW:
671 while(msg_tlen >= 4) {
672 processed = ldp_tlv_print(ndo, msg_tptr, msg_tlen);
673 if (processed == 0)
674 break;
675 msg_tlen-=processed;
676 msg_tptr+=processed;
677 }
678 break;
679
680 /*
681 * FIXME those are the defined messages that lack a decoder
682 * you are welcome to contribute code ;-)
683 */
684
685 case LDP_MSG_LABEL_REQUEST:
686 case LDP_MSG_LABEL_RELEASE:
687 case LDP_MSG_LABEL_ABORT_REQUEST:
688
689 default:
690 if (ndo->ndo_vflag <= 1)
691 print_unknown_data(ndo, msg_tptr, "\n\t ", msg_tlen);
692 break;
693 }
694 /* do we want to see an additionally hexdump ? */
695 if (ndo->ndo_vflag > 1 || hexdump==TRUE)
696 print_unknown_data(ndo, tptr+sizeof(struct ldp_msg_header), "\n\t ",
697 msg_len);
698
699 tptr += msg_len+4;
700 tlen -= msg_len+4;
701 }
702 return pdu_len+4;
703 trunc:
704 nd_trunc_longjmp(ndo);
705 }
706