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