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