Make "dissector_add()", "dissector_delete()", and "dissector_change()"
[obnox/wireshark/wip.git] / packet-ldp.c
1 /* packet-ldp.c
2  * Routines for LDP (RFC 3036) packet disassembly
3  *
4  * $Id: packet-ldp.c,v 1.22 2001/12/03 03:59:36 guy Exp $
5  * 
6  * Copyright (c) November 2000 by Richard Sharpe <rsharpe@ns.aus.com>
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1999 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34
35 #ifdef HAVE_NETINET_IN_H
36 #include <netinet/in.h>
37 #endif
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <ctype.h>
42 #include <time.h>
43 #include <glib.h>
44 #include <string.h>
45 #include "packet.h"
46 #include "resolv.h"
47 #include "prefs.h"
48 #include "afn.h"
49
50 #define TCP_PORT_LDP 646
51 #define UDP_PORT_LDP 646
52
53 void proto_reg_handoff_ldp(void);
54
55 static int proto_ldp = -1;
56
57 /* Delete the following if you do not use it, or add to it if you need */
58 static int hf_ldp_req = -1;
59 static int hf_ldp_rsp = -1;
60 static int hf_ldp_version = -1;
61 static int hf_ldp_pdu_len = -1;
62 static int hf_ldp_lsr = -1;
63 static int hf_ldp_ls_id = -1;
64 static int hf_ldp_msg_type = -1;
65 static int hf_ldp_msg_len = -1;
66 static int hf_ldp_msg_id = -1;
67 static int hf_ldp_tlv_value = -1;
68 static int hf_ldp_tlv_type = -1;
69 static int hf_ldp_tlv_len = -1;
70 static int hf_ldp_tlv_val_hold = -1;
71 static int hf_ldp_tlv_val_target = -1;
72 static int hf_ldp_tlv_val_request = -1;
73 static int hf_ldp_tlv_val_res = -1;
74 static int hf_ldp_tlv_config_seqno = -1;
75 static int hf_ldp_tlv_fec_wc = -1;
76 static int hf_ldp_tlv_fec_af = -1;
77 static int hf_ldp_tlv_fec_len = -1;
78 static int hf_ldp_tlv_fec_pfval = -1;
79 static int hf_ldp_tlv_generic_label = -1;
80
81 static int ett_ldp = -1;
82 static int ett_ldp_header = -1;
83 static int ett_ldp_ldpid = -1;
84 static int ett_ldp_message = -1;
85 static int ett_ldp_tlv = -1;
86 static int ett_ldp_tlv_val = -1;
87 static int ett_ldp_fec = -1;
88
89 static int tcp_port = 0;
90 static int udp_port = 0;
91
92 /* Add your functions here */
93
94 static int global_ldp_tcp_port = TCP_PORT_LDP;
95 static int global_ldp_udp_port = UDP_PORT_LDP;
96
97 /*
98  * The following define all the TLV types I know about
99  */
100
101 #define TLV_FEC                    0x0100
102 #define TLV_ADDRESS_LIST           0x0101
103 #define TLV_HOP_COUNT              0x0103
104 #define TLV_PATH_VECTOR            0x0104
105 #define TLV_GENERIC_LABEL          0x0200
106 #define TLV_ATM_LABEL              0x0201
107 #define TLV_FRAME_LABEL            0x0202
108 #define TLV_STATUS                 0x0300
109 #define TLV_EXTENDED_STATUS        0x0301
110 #define TLV_RETURNED_PDU           0x0302
111 #define TLV_RETURNED_MESSAGE       0x0303
112 #define TLV_COMMON_HELLO_PARMS     0x0400
113 #define TLV_IPV4_TRANSPORT_ADDRESS 0x0401
114 #define TLV_CONFIGURATION_SEQNO    0x0402
115 #define TLV_IPV6_TRANSPORT_ADDRESS 0x0403
116 #define TLV_COMMON_SESSION_PARMS   0x0500
117 #define TLV_ATM_SESSION_PARMS      0x0501
118 #define TLV_FRAME_RELAY_SESSION_PARMS 0x0502
119 #define TLV_LABEL_REQUEST_MESSAGE_ID 0x0600
120
121 #define TLV_VENDOR_PRIVATE_START   0x3E00
122 #define TLV_VENDOR_PROVATE_END     0x3EFF
123 #define TLV_EXPERIMENTAL_START     0x3F00
124 #define TLV_EXPERIMENTAL_END       0x3FFF
125
126 static const value_string tlv_type_names[] = { 
127   { TLV_FEC,                       "Forwarding Equivalence Classes" },
128   { TLV_ADDRESS_LIST,              "Address List"},
129   { TLV_HOP_COUNT,                 "Hop Count"},
130   { TLV_PATH_VECTOR,               "Path Vector"},
131   { TLV_GENERIC_LABEL,             "Generic Label"},
132   { TLV_ATM_LABEL,                 "Frame Label"},
133   { TLV_STATUS,                    "Status"},
134   { TLV_EXTENDED_STATUS,           "Extended Status"},
135   { TLV_RETURNED_PDU,              "Returned PDU"},
136   { TLV_RETURNED_MESSAGE,          "Returned Message"},
137   { TLV_COMMON_HELLO_PARMS,        "Common Hello Parameters"},
138   { TLV_IPV4_TRANSPORT_ADDRESS,    "IPv4 Transport Address"},
139   { TLV_CONFIGURATION_SEQNO,       "Configuration Sequence Number"},
140   { TLV_IPV6_TRANSPORT_ADDRESS,    "IPv6 Transport Address"},
141   { TLV_COMMON_SESSION_PARMS,      "Common Session Parameters"},
142   { TLV_ATM_SESSION_PARMS,         "ATM Session Parameters"},
143   { TLV_FRAME_RELAY_SESSION_PARMS, "Frame Relay Session Parameters"},
144   { TLV_LABEL_REQUEST_MESSAGE_ID,  "Label Request Message ID"},
145   { 0, NULL}
146 };
147
148 /*
149  * The following define all the message types I know about
150  */
151
152 #define LDP_NOTIFICATION       0x0001
153 #define LDP_HELLO              0x0100
154 #define LDP_INITIALIZATION     0x0200
155 #define LDP_KEEPALIVE          0x0201
156 #define LDP_ADDRESS            0x0300
157 #define LDP_ADDRESS_WITHDRAWAL 0x0301
158 #define LDP_LABEL_MAPPING      0x0400
159 #define LDP_LABEL_REQUEST      0x0401
160 #define LDP_LABEL_WITHDRAWAL   0x0402
161 #define LDP_LABEL_RELEASE      0x0403
162 #define LDP_LABEL_ABORT_REQUEST 0x0404
163 #define LDP_VENDOR_PRIVATE_START 0x3E00
164 #define LDP_VENDOR_PRIVATE_END   0x3EFF
165 #define LDP_EXPERIMENTAL_MESSAGE_START 0x3F00
166 #define LDP_EXPERIMENTAL_MESSAGE_END   0x3FFF
167
168 static const value_string ldp_message_types[] = {
169   {LDP_NOTIFICATION,             "Notification"},
170   {LDP_HELLO,                    "Hello"},
171   {LDP_INITIALIZATION,           "Initialization"},
172   {LDP_KEEPALIVE,                "Keep Alive"},
173   {LDP_ADDRESS,                  "Address"},
174   {LDP_ADDRESS_WITHDRAWAL,       "Address Withdrawal"},
175   {LDP_LABEL_MAPPING,            "Label Mapping"},
176   {LDP_LABEL_REQUEST,            "Label Request"},
177   {LDP_LABEL_WITHDRAWAL,         "Label Withdrawal"},
178   {LDP_LABEL_RELEASE,            "Label Release"},
179   {LDP_LABEL_ABORT_REQUEST,      "Label Abort Request"},
180   {0, NULL}
181 };
182
183 static const true_false_string hello_targeted_vals = {
184   "Targeted Hello",
185   "Link Hello"
186 };
187
188 static const value_string fec_types[] = {
189   {1, "Wildcard FEC"},
190   {2, "Prefix FEC"},
191   {3, "Host Address FEC"},
192   {0, NULL}
193 };
194
195 static const true_false_string hello_requested_vals = {
196   "Source requests periodic hellos",
197   "Source does not request periodic hellos"
198 };
199
200 /* Dissect the common hello params */
201
202 void dissect_tlv_common_hello_parms(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem)
203 {
204   proto_tree *ti = NULL, *val_tree = NULL;
205
206   if (tree) {
207
208     ti = proto_tree_add_item(tree, hf_ldp_tlv_value, tvb, offset, rem,
209                              FALSE);
210
211     val_tree = proto_item_add_subtree(ti, ett_ldp_tlv_val);
212
213     proto_tree_add_item(val_tree, hf_ldp_tlv_val_hold, tvb, offset, 2, FALSE);
214
215     proto_tree_add_boolean(val_tree, hf_ldp_tlv_val_target, tvb, offset + 2, 2, FALSE);
216     proto_tree_add_boolean(val_tree, hf_ldp_tlv_val_request, tvb, offset + 2, 2, FALSE);
217     proto_tree_add_item(val_tree, hf_ldp_tlv_val_res, tvb, offset + 2, 2, FALSE);
218   }
219
220 }
221
222 /* Dissect a TLV and return the number of bytes consumed ... */
223
224 int dissect_tlv(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem)
225 {
226   guint16 message = tvb_get_ntohs(tvb, offset),
227           length = tvb_get_ntohs(tvb, offset + 2),
228           pad = 0, fec_len = 0;
229   proto_tree *ti = NULL, *tlv_tree = NULL;
230
231   /* Hmmm, check for illegal alignment padding */
232
233   if (message == 0x00) {
234
235     proto_tree_add_text(tree, tvb, offset, 2, "Illegal Padding: %04X", message);
236     offset += 2; pad = 2;
237     message = tvb_get_ntohs(tvb, offset);
238     length = tvb_get_ntohs(tvb, offset + 2);
239
240   }
241
242   length = MIN(length, rem);  /* Don't go haywire if a problem ... */
243
244   if (tree) {
245
246     /* FIXME: Account for vendor and special messages */
247
248     ti = proto_tree_add_text(tree, tvb, offset, length + 4, "%s",
249                              val_to_str(message, tlv_type_names, "Unknown TLV type (0x%04X)"));
250
251     tlv_tree = proto_item_add_subtree(ti, ett_ldp_tlv);
252
253     proto_tree_add_item(tlv_tree, hf_ldp_tlv_type, tvb, offset, 2, FALSE);
254
255     proto_tree_add_item(tlv_tree, hf_ldp_tlv_len, tvb, offset + 2, 2, FALSE);
256
257     switch (message) {
258
259     case TLV_FEC:  /* Process an FEC */
260
261       offset += 4;  /* Skip the TLV header */
262
263       fec_len = length;
264
265       while (fec_len > 0) {
266         proto_tree *fec_tree = NULL;
267         guint prefix_len_octets, prefix_len, prefix;  
268
269
270         switch (tvb_get_guint8(tvb, offset)) {
271         case 1:   /* Wild Card */
272
273           proto_tree_add_item(tlv_tree, hf_ldp_tlv_fec_wc, tvb, offset, 4, FALSE);
274           fec_len -= 4;
275
276           offset += 4;
277
278           break;
279
280         case 2:   /* Prefix    */
281
282           /* Add a subtree for this ... */
283
284           ti = proto_tree_add_text(tlv_tree, tvb, offset, 8, "Prefix FEC Element");
285
286           fec_tree = proto_item_add_subtree(ti, ett_ldp_fec);
287
288           proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_wc, tvb, offset, 1, FALSE);
289
290           offset += 1;
291
292           /* XXX - the address family length should be extracted and used to
293              dissect the prefix field. */
294           proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_af, tvb, offset, 2, FALSE);
295           offset += 2;
296
297           prefix_len = tvb_get_guint8(tvb, offset);
298           proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_len, tvb, offset, 1, FALSE);
299
300           offset += 1;
301           /* This is IPv4 specific. Should do IPv6 according to AF*/
302           prefix_len_octets = MIN( (prefix_len+7)/8 , 4 );
303           if (prefix_len > 32) {
304             proto_tree_add_text(fec_tree, tvb, offset, 0,
305             "Invalid prefix %u length, guessing 32", prefix_len);
306             prefix_len_octets = 4;
307           }
308           switch (prefix_len_octets){
309             case (0): /*prefix_length=0*/
310               prefix = 0;
311               break;
312             case (1): /*1<=prefix_length<=8*/
313               prefix = tvb_get_guint8(tvb, offset);
314               break;
315             case (2): /*9<=prefix_length<=16*/
316               prefix = tvb_get_letohs(tvb, offset);
317               break;
318             case (3): /*17<=prefix_length<=24*/
319               prefix = tvb_get_letoh24(tvb, offset);
320               break;
321             case (4): /*25<=prefix_length<=32*/
322               prefix = tvb_get_letohl(tvb, offset);
323               break;
324             default: /*prefix_length>32*/
325               g_assert_not_reached();
326               prefix = 0;
327               break;
328           }
329           proto_tree_add_ipv4(fec_tree, hf_ldp_tlv_fec_pfval, tvb, 
330                               offset, prefix_len_octets, prefix);
331           fec_len -= 4+prefix_len_octets;
332           break;
333
334         case 3:   /* Host address */
335
336           /* XXX - write me. */
337
338           fec_len -= 8;
339
340           offset += 8;
341
342           break;
343
344         default:  /* Unknown */
345
346           /* XXX - do all FEC's have a length that's a multiple of 4? */
347           /* Hmmm, don't think so. Will check. RJS. */
348
349           fec_len -= 4;
350
351           offset += 4;
352
353           break;
354
355         }
356
357       }
358
359       break;;
360
361     case TLV_GENERIC_LABEL:
362
363       proto_tree_add_item(tlv_tree, hf_ldp_tlv_generic_label, tvb, offset + 4, 4, FALSE);
364
365       break;
366
367     case TLV_COMMON_HELLO_PARMS:
368
369       dissect_tlv_common_hello_parms(tvb, offset + 4, tlv_tree, length);
370       break;
371
372     case TLV_CONFIGURATION_SEQNO:
373
374       proto_tree_add_item(tlv_tree, hf_ldp_tlv_config_seqno, tvb, offset + 4, 4, FALSE);
375       break;
376
377     default:
378       proto_tree_add_item(tlv_tree, hf_ldp_tlv_value, tvb, offset + 4, 
379                            length, FALSE);
380
381       break;
382     }
383
384   }
385
386   return length + pad + 4;  /* Length of the value field + header */
387
388 }
389
390 /* 
391  * Each of these routines dissect the relevant messages, but the msg header 
392  * has already been dissected.
393  */
394
395 void
396 dissect_ldp_notification(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length)
397 {
398   guint rem = length, cc = 0;
399
400   while (rem > 0) {
401
402     rem -= (cc = dissect_tlv(tvb, offset, tree, rem));
403     offset += cc;
404
405   }
406
407 }
408
409 /* Dissect a Hello Message ... */
410 void
411 dissect_ldp_hello(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length)
412 {
413   guint rem = length, cc = 0;
414
415   while (rem > 0) {
416
417     rem -= (cc = dissect_tlv(tvb, offset, tree, rem));
418     offset += cc;
419
420   }
421
422 }
423
424 void
425 dissect_ldp_initialization(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length)
426 {
427   guint rem = length, cc = 0;
428
429   while (rem > 0) {
430
431     rem -= (cc = dissect_tlv(tvb, offset, tree, rem));
432     offset += cc;
433
434   }
435
436 }
437
438 void
439 dissect_ldp_keepalive(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length)
440 {
441   guint rem = length, cc = 0;
442
443   while (rem > 0) {
444
445     rem -= (cc = dissect_tlv(tvb, offset, tree, rem));
446     offset += cc;
447
448   }
449
450 }
451
452 void
453 dissect_ldp_address(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length)
454 {
455   guint rem = length, cc = 0;
456
457   while (rem > 0) {
458
459     rem -= (cc = dissect_tlv(tvb, offset, tree, rem));
460     offset += cc;
461
462   }
463
464 }
465
466 void
467 dissect_ldp_address_withdrawal(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length)
468 {
469   guint rem = length, cc = 0;
470
471   while (rem > 0) {
472
473     rem -= (cc = dissect_tlv(tvb, offset, tree, rem));
474     offset += cc;
475
476   }
477
478 }
479
480 void
481 dissect_ldp_label_mapping(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length)
482 {
483   guint rem = length, cc = 0;
484
485   while (rem > 0) {
486
487     rem -= (cc = dissect_tlv(tvb, offset, tree, rem));
488     offset += cc;
489
490   }
491
492 }
493
494 void
495 dissect_ldp_label_request(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length)
496 {
497   guint rem = length, cc = 0;
498
499   while (rem > 0) {
500
501     rem -= (cc = dissect_tlv(tvb, offset, tree, rem));
502     offset += cc;
503
504   }
505
506 }
507
508 void
509 dissect_ldp_label_withdrawal(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length)
510 {
511   guint rem = length, cc = 0;
512
513   while (rem > 0) {
514
515     rem -= (cc = dissect_tlv(tvb, offset, tree, rem));
516     offset += cc;
517
518   }
519
520 }
521
522 void
523 dissect_ldp_label_release(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length)
524 {
525   guint rem = length, cc = 0;
526
527   while (rem > 0) {
528
529     rem -= (cc = dissect_tlv(tvb, offset, tree, rem));
530     offset += cc;
531
532   }
533
534 }
535
536 void
537 dissect_ldp_label_abort_request(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length)
538 {
539   guint rem = length, cc = 0;
540
541   while (rem > 0) {
542
543     rem -= (cc = dissect_tlv(tvb, offset, tree, rem));
544     offset += cc;
545
546   }
547
548 }
549
550 static int
551 dissect_ldp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
552 {
553   proto_tree     *ldp_tree = NULL, *hdr_tree = NULL, *ldpid_tree = NULL;
554   proto_item     *ldp_item = NULL, *hdr_item = NULL, *ldpid_item = NULL;
555   int            msg_cnt = 0;
556   guint16        ldp_message = 0;
557   guint          pdu_len;
558
559   if (check_col(pinfo->fd, COL_INFO))
560     col_clear(pinfo->fd, COL_INFO);
561
562   if (tree) {  /* Build the tree info ..., this is wrong! FIXME */
563
564     ldp_item = proto_tree_add_item(tree, proto_ldp, tvb, offset,
565                                    tvb_length_remaining(tvb, offset), FALSE);
566     ldp_tree = proto_item_add_subtree(ldp_item, ett_ldp);
567
568   }
569
570   /* Dissect LDP Header */
571
572   hdr_item = proto_tree_add_text(ldp_tree, tvb, offset, 10, "Header");
573
574   hdr_tree = proto_item_add_subtree(hdr_item, ett_ldp_header);
575
576   proto_tree_add_item(hdr_tree, hf_ldp_version, tvb, offset, 2, FALSE);
577
578   offset += 2;
579
580   proto_tree_add_item(hdr_tree, hf_ldp_pdu_len, tvb, offset, 2, FALSE);
581   pdu_len = tvb_get_ntohs(tvb, offset);
582   proto_item_set_len(ldp_item, pdu_len + 2);
583
584   /*
585    * XXX - do TCP reassembly, to handle LDP PDUs that cross TCP segment
586    * boundaries.
587    */
588
589   offset += 2;
590
591   if (pdu_len < 6) {
592     /*
593      * PDU is too short to hold the LDP identifier.
594      */
595     proto_tree_add_text(hdr_tree, tvb, offset, pdu_len,
596         "PDU too short (%u bytes, should be at least 6) for LDP Identifier",
597         pdu_len);
598     offset += pdu_len;
599     return offset;
600   }
601
602   ldpid_item = proto_tree_add_text(hdr_tree, tvb, offset, 6, "LDP Identifier");
603
604   ldpid_tree = proto_item_add_subtree(ldpid_item, ett_ldp_ldpid);
605
606   proto_tree_add_item(ldpid_tree, hf_ldp_lsr, tvb, offset, 4, FALSE);
607
608   offset += 4;
609   pdu_len -= 4;
610
611   proto_tree_add_item(ldpid_tree, hf_ldp_ls_id, tvb, offset, 2, FALSE);
612
613   offset += 2;
614   pdu_len -= 2;
615
616   while (pdu_len > 0) { /* Dissect LDP TLV */
617
618     guint msg_len;
619
620     ldp_message = tvb_get_ntohs(tvb, offset) & 0x7FFF; /* Get the message type */
621
622     msg_len = tvb_get_ntohs(tvb, offset + 2);
623
624     if (check_col(pinfo->fd, COL_INFO)) {  /* Check the type ... */
625
626       if (msg_cnt > 0) 
627         col_append_fstr(pinfo->fd, COL_INFO, ", %s",
628                         val_to_str(ldp_message, ldp_message_types, "Unknown Message (0x%04X)"));
629       else
630         col_add_fstr(pinfo->fd, COL_INFO, "%s", 
631                      val_to_str(ldp_message, ldp_message_types, "Unknown Message (0x%04X)"));
632         
633     }
634
635     msg_cnt++;
636
637     if (tree) {
638
639       proto_tree *ti = NULL, *msg_tree = NULL;
640
641       /* FIXME: Account for vendor and experimental messages */
642
643       ti = proto_tree_add_text(ldp_tree, tvb, offset, msg_len + 4, "%s",
644                                val_to_str(ldp_message, ldp_message_types, "Unknown Message (0x%04X)"));
645
646       msg_tree = proto_item_add_subtree(ti, ett_ldp_message);
647         
648       proto_tree_add_item(msg_tree, hf_ldp_msg_type, tvb, offset, 2, FALSE);
649
650       proto_tree_add_item(msg_tree, hf_ldp_msg_len, tvb, offset + 2, 2, FALSE);
651
652       if (msg_len < 4) {
653         proto_tree_add_text(msg_tree, tvb, offset + 4, msg_len,
654             "Message too short (%u bytes, should be at least 4) for Message ID",
655             msg_len);
656         goto next;
657       }
658
659       proto_tree_add_item(msg_tree, hf_ldp_msg_id, tvb, offset + 4, 4, FALSE);
660
661       if (msg_len == 4) {
662         /* Nothing past the message ID */
663         goto next;
664       }
665
666       switch (ldp_message) {
667
668       case LDP_NOTIFICATION:
669
670         dissect_ldp_notification(tvb, offset + 8, pinfo, msg_tree, msg_len - 4); 
671
672         break;
673
674       case LDP_HELLO:
675
676         dissect_ldp_hello(tvb, offset + 8, pinfo, msg_tree, msg_len - 4);
677
678         break;
679
680       case LDP_INITIALIZATION:
681
682         dissect_ldp_initialization(tvb, offset + 8, pinfo, msg_tree, msg_len - 4);
683
684         break;
685
686       case LDP_KEEPALIVE:
687
688         dissect_ldp_keepalive(tvb, offset + 8, pinfo, msg_tree, msg_len - 4);
689           
690         break;
691
692       case LDP_ADDRESS:
693
694         dissect_ldp_address(tvb, offset + 8, pinfo, msg_tree, msg_len - 4);
695
696         break;
697
698       case LDP_ADDRESS_WITHDRAWAL:
699
700         dissect_ldp_address_withdrawal(tvb, offset + 8, pinfo, msg_tree, msg_len - 4);
701
702         break;
703
704       case LDP_LABEL_MAPPING:
705
706         dissect_ldp_label_mapping(tvb, offset + 8, pinfo, msg_tree, msg_len - 4);
707
708         break;
709
710       case LDP_LABEL_REQUEST:
711
712         dissect_ldp_label_request(tvb, offset + 8, pinfo, msg_tree, msg_len - 4);
713
714         break;
715
716       case LDP_LABEL_WITHDRAWAL:
717
718         dissect_ldp_label_withdrawal(tvb, offset + 8, pinfo, msg_tree, msg_len - 4);
719
720         break;
721
722       case LDP_LABEL_RELEASE:
723
724         dissect_ldp_label_release(tvb, offset + 8, pinfo, msg_tree, msg_len - 4);
725
726         break;
727
728       case LDP_LABEL_ABORT_REQUEST:
729
730         dissect_ldp_label_abort_request(tvb, offset + 8, pinfo, msg_tree, msg_len - 4);
731
732         break;
733
734       default:
735
736         /* Some sort of unknown message, treat as undissected data */
737         proto_tree_add_text(msg_tree, tvb, offset + 8, msg_len - 4,
738                             "Message data"); 
739
740         break;
741
742       }
743     
744     }
745
746 next:
747     offset += msg_len + 4;
748     pdu_len -= msg_len + 4;
749
750   }
751   return offset;
752 }
753
754 static void
755 dissect_ldp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
756 {
757   if (check_col(pinfo->fd, COL_PROTOCOL))
758     col_add_str(pinfo->fd, COL_PROTOCOL, "LDP");
759
760   dissect_ldp_pdu(tvb, 0, pinfo, tree);
761 }
762
763 static void
764 dissect_ldp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
765 {
766   int            offset = 0;
767
768   if (check_col(pinfo->fd, COL_PROTOCOL))
769     col_add_str(pinfo->fd, COL_PROTOCOL, "LDP");
770
771   while (tvb_reported_length_remaining(tvb, offset) > 0) /* Dissect LDP PDUs */
772     offset = dissect_ldp_pdu(tvb, offset, pinfo, tree);
773 }
774
775 /* Register all the bits needed with the filtering engine */
776
777 void 
778 proto_register_ldp(void)
779 {
780   static hf_register_info hf[] = {
781     { &hf_ldp_req,
782       /* Change the following to the type you need */
783       { "Request", "ldp.req", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
784
785     { &hf_ldp_rsp,
786       { "Response", "ldp.rsp", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
787
788     { &hf_ldp_version,
789       { "Version", "ldp.hdr.version", FT_UINT16, BASE_DEC, NULL, 0x0, "LDP Version Number", HFILL }},
790
791     { &hf_ldp_pdu_len,
792       { "PDU Length", "ldp.hdr.pdu_len", FT_UINT16, BASE_DEC, NULL, 0x0, "LDP PDU Length", HFILL }},
793
794     { &hf_ldp_lsr,
795       { "LSR ID", "ldp.hdr.ldpid.lsr", FT_UINT32, BASE_HEX, NULL, 0x0, "LDP Label Space Router ID", HFILL }},
796
797     { &hf_ldp_ls_id,
798       { "Label Space ID", "ldp.hdr.ldpid.lsid", FT_UINT16, BASE_HEX, NULL, 0x0, "LDP Label Space ID", HFILL }},
799
800     { &hf_ldp_msg_type,
801       { "Message Type", "ldp.msg.type", FT_UINT16, BASE_HEX, VALS(ldp_message_types), 0x0, "LDP message type", HFILL }},
802
803     { &hf_ldp_msg_len,
804       { "Message Length", "ldp.msg.len", FT_UINT16, BASE_DEC, NULL, 0x0, "LDP Message Length (excluding message type and len)", HFILL }},
805
806     { &hf_ldp_msg_id, 
807       { "Message ID", "ldp.msg.id", FT_UINT32, BASE_HEX, NULL, 0x0, "LDP Message ID", HFILL }},
808
809     { &hf_ldp_tlv_type, 
810       { "TLV Type", "ldp.msg.tlv.type", FT_UINT16, BASE_HEX, VALS(tlv_type_names), 0x0, "TLV Type Field", HFILL }},
811
812     { &hf_ldp_tlv_len,
813       {"TLV Length", "ldp.msg.tlv.len", FT_UINT16, BASE_DEC, NULL, 0x0, "TLV Length Field", HFILL }},
814
815     { &hf_ldp_tlv_value,
816       { "TLV Value", "ldp.msg.tlv.value", FT_BYTES, BASE_NONE, NULL, 0x0, "TLV Value Bytes", HFILL }},
817
818     { &hf_ldp_tlv_val_hold,
819       { "Hold Time", "ldp.msg.tlv.hello.hold", FT_UINT16, BASE_DEC, NULL, 0x0, "Hello Common Parameters Hold Time", HFILL }},
820
821     { &hf_ldp_tlv_val_target,
822       { "Targeted Hello", "ldp.msg.tlv.hello.targeted", FT_BOOLEAN, 8, TFS(&hello_targeted_vals), 0x80, "Hello Common Parameters Targeted Bit", HFILL }},
823
824     { &hf_ldp_tlv_val_request,
825       { "Hello Requested", "ldp,msg.tlv.hello.requested", FT_BOOLEAN, 8, TFS(&hello_requested_vals), 0x40, "Hello Common Parameters Hello Requested Bit", HFILL }},
826  
827     { &hf_ldp_tlv_val_res,
828       { "Reserved", "ldp.msg.tlv.hello.res", FT_UINT16, BASE_HEX, NULL, 0x3FFF, "Hello Common Parameters Reserved Field", HFILL }},
829
830     { &hf_ldp_tlv_config_seqno,
831       { "Configuration Sequence Number", "ldp.msg.tlv.hello.cnf_seqno", FT_UINT32, BASE_HEX, NULL, 0x0, "Hello COnfiguration Sequence Number", HFILL }},
832
833     { &hf_ldp_tlv_fec_wc,
834       { "FEC Element Type", "ldp.msg.tlv.fec.type", FT_UINT8, BASE_DEC, VALS(fec_types), 0x0, "Forwarding Equivalence Class Element Types", HFILL }},
835
836     { &hf_ldp_tlv_fec_af,
837       { "FEC Element Address Type", "ldp.msg.tlv.fec.af", FT_UINT16, BASE_DEC, VALS(afn_vals), 0x0, "Forwarding Equivalence Class Element Address Family", HFILL }},
838
839     { &hf_ldp_tlv_fec_len,
840       { "FEC Element Length", "ldp.msg.tlv.fec.len", FT_UINT8, BASE_DEC, NULL, 0x0, "Forwarding Equivalence Class Element Length", HFILL }},
841
842     { &hf_ldp_tlv_fec_pfval,
843       { "FEC Element Prefix Value", "ldp.msg.tlv.fec.pfval", FT_IPv4, BASE_DEC, NULL, 0x0, "Forwarding Equivalence Class Element Prefix", HFILL }},
844
845     { &hf_ldp_tlv_generic_label,
846       { "Generic Label", "ldp.msg.tlv.label", FT_UINT32, BASE_HEX, NULL, 0x0, "Label Mapping Generic Label", HFILL }},
847
848   };
849   static gint *ett[] = {
850     &ett_ldp,
851     &ett_ldp_header,
852     &ett_ldp_ldpid,
853     &ett_ldp_message,
854     &ett_ldp_tlv,
855     &ett_ldp_tlv_val,
856     &ett_ldp_fec,
857   };
858   module_t *ldp_module; 
859
860   proto_ldp = proto_register_protocol("Label Distribution Protocol",
861                                        "LDP", "ldp");
862
863   proto_register_field_array(proto_ldp, hf, array_length(hf));
864   proto_register_subtree_array(ett, array_length(ett));
865
866   /* Register our configuration options for , particularly our port */
867
868   ldp_module = prefs_register_protocol(proto_ldp, proto_reg_handoff_ldp);
869
870   prefs_register_uint_preference(ldp_module, "tcp.port", "LDP TCP Port",
871                                  "Set the port for  messages (if other"
872                                  " than the default of 646)",
873                                  10, &global_ldp_tcp_port);
874
875   prefs_register_uint_preference(ldp_module, "udp.port", "LDP UDP Port",
876                                  "Set the port for  messages (if other"
877                                  " than the default of 646)",
878                                  10, &global_ldp_udp_port);
879
880 }
881
882 /* The registration hand-off routine */
883 void
884 proto_reg_handoff_ldp(void)
885 {
886   static int ldp_prefs_initialized = FALSE;
887   static dissector_handle_t ldp_tcp_handle, ldp_handle;
888
889   if (!ldp_prefs_initialized) {
890
891     ldp_tcp_handle = create_dissector_handle(dissect_ldp_tcp, proto_ldp);
892     ldp_handle = create_dissector_handle(dissect_ldp, proto_ldp);
893
894     ldp_prefs_initialized = TRUE;
895
896   }
897   else {
898
899     dissector_delete("tcp.port", tcp_port, ldp_tcp_handle);
900     dissector_delete("udp.port", udp_port, ldp_handle);
901
902   }
903
904   /* Set our port number for future use */
905
906   tcp_port = global_ldp_tcp_port;
907   udp_port = global_ldp_udp_port;
908
909   dissector_add("tcp.port", global_ldp_tcp_port, ldp_tcp_handle);
910   dissector_add("udp.port", global_ldp_udp_port, ldp_handle);
911
912 }