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#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
53struct 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
86struct 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
112static 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
153static 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
184static 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
196static 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 */
204static 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 */
212static 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
219static 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
245static u_int
246ldp_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
545trunc:
546    nd_trunc_longjmp(ndo);
547
548invalid:
549    return(tlv_len+4); /* Type & Length fields not included */
550}
551
552void
553ldp_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
573static u_int
574ldp_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;
703trunc:
704    nd_trunc_longjmp(ndo);
705}
706