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