Change "Home Page" to "Web Site".
[metze/wireshark/wip.git] / packet-lmp.c
1 /* packet-lmp.c
2  * Routines for LMP packet disassembly
3  *
4  * (c) Copyright Ashok Narayanan <ashokn@cisco.com>
5  *
6  * $Id: packet-lmp.c,v 1.12 2002/08/28 21:00:20 jmayer Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 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 /*
28  * LMP as a standard has shown a remarkable ability to get completely rewritten
29  * across minor versions of the draft. This file currently implements
30  * two versions of LMP; described in draft-ietf-ccamp-lmp-02.txt and
31  * draft-ietf-ccamp-lmp-03.txt. The -03 version is the default; the
32  * version being dissected can be changed from the LMP protocol preferences
33  */
34
35 #ifdef HAVE_CONFIG_H
36 # include "config.h"
37 #endif
38
39 #include <stdio.h>
40
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
44
45 #include <stdlib.h>
46 #include <string.h>
47
48 #include <glib.h>
49
50 #include <epan/tvbuff.h>
51 #include <epan/packet.h>
52 #include <prefs.h>
53 #include "in_cksum.h"
54 #include "etypes.h"
55 #include "ipproto.h"
56
57 #include "packet-ip.h"
58 #include "packet-rsvp.h"
59 #include "packet-frame.h"
60
61 static int proto_lmp = -1;
62 #define LMP_VER_DRAFT_CCAMP_02  2
63 #define LMP_VER_DRAFT_CCAMP_03  3
64 static int lmp_draft_ver = LMP_VER_DRAFT_CCAMP_03;
65
66 #define IP_PROTO_LMP 140
67
68 /*----------------------------------------------------------------------
69  * LMP message types
70  */
71 typedef enum {
72     LMP_MSG_CONFIG=1,
73     LMP_MSG_CONFIG_ACK,
74     LMP_MSG_CONFIG_NACK,
75     LMP_MSG_HELLO,
76     LMP_MSG_BEGIN_VERIFY,
77     LMP_MSG_BEGIN_VERIFY_ACK,
78     LMP_MSG_BEGIN_VERIFY_NACK,
79     LMP_MSG_END_VERIFY,
80     LMP_MSG_END_VERIFY_ACK,
81     LMP_MSG_TEST,
82     LMP_MSG_TEST_STATUS_SUCCESS,
83     LMP_MSG_TEST_STATUS_FAILURE,
84     LMP_MSG_TEST_STATUS_ACK,
85     LMP_MSG_LINK_SUMMARY,
86     LMP_MSG_LINK_SUMMARY_ACK,
87     LMP_MSG_LINK_SUMMARY_NACK,
88     LMP_MSG_CHANNEL_FAIL,
89     LMP_MSG_CHANNEL_FAIL_ACK,
90     LMP_MSG_CHANNEL_FAIL_NACK,
91     LMP_MSG_CHANNEL_STATUS,
92     LMP_MSG_CHANNEL_STATUS_ACK,
93     LMP_MSG_CHANNEL_STATUS_REQ,
94     LMP_MSG_CHANNEL_STATUS_RESP,
95 } lmp_message_types;
96
97 static value_string message_type_vals[] = {
98     {LMP_MSG_CONFIG,              "Config Message. "},
99     {LMP_MSG_CONFIG_ACK,          "ConfigAck Message. "},
100     {LMP_MSG_CONFIG_NACK,         "ConfigNack Message. "},
101     {LMP_MSG_HELLO,               "Hello Message. "},
102     {LMP_MSG_BEGIN_VERIFY,        "BeginVerify Message. "},
103     {LMP_MSG_BEGIN_VERIFY_ACK,    "BeginVerifyAck Message. "},
104     {LMP_MSG_BEGIN_VERIFY_NACK,   "BeginVerifyNack Message. "},
105     {LMP_MSG_END_VERIFY,          "EndVerifyNack Message. "},
106     {LMP_MSG_TEST,                "Test Message. "},
107     {LMP_MSG_TEST_STATUS_SUCCESS, "TestStatusSuccess Message. "},
108     {LMP_MSG_TEST_STATUS_FAILURE, "TestStatusFailure Message. "},
109     {LMP_MSG_TEST_STATUS_ACK,     "TestStatusAck Message. "},
110     {LMP_MSG_LINK_SUMMARY,        "LinkSummary Message. "},
111     {LMP_MSG_LINK_SUMMARY_ACK,    "LinkSummaryAck Message. "},
112     {LMP_MSG_LINK_SUMMARY_NACK,   "LinkSummaryNack Message. "},
113     {LMP_MSG_CHANNEL_FAIL,        "ChannelFail Message. "},
114     {LMP_MSG_CHANNEL_FAIL_ACK,    "ChannelFailAck Message. "},
115     {LMP_MSG_CHANNEL_FAIL_NACK,   "ChannelFailNack Message. "},
116     {LMP_MSG_CHANNEL_STATUS,      "ChannelStatus Message. "},
117     {LMP_MSG_CHANNEL_STATUS_ACK,  "ChannelStatusAck Message. "},
118     {LMP_MSG_CHANNEL_STATUS_REQ,  "ChannelStatusRequest Message. "},
119     {LMP_MSG_CHANNEL_STATUS_RESP, "ChannelStatusResponse Message. "},
120     {0, NULL}
121 };
122
123 /*------------------------------------------------------------------------------
124  * LMP object classes
125  */
126 typedef enum {
127     LMP_CLASS_NULL = 0,
128
129     LMP_CLASS_LOCAL_CCID,
130     LMP_CLASS_REMOTE_CCID,
131     LMP_CLASS_LOCAL_NODE_ID,
132     LMP_CLASS_REMOTE_NODE_ID,
133     LMP_CLASS_LOCAL_LINK_ID,
134     LMP_CLASS_REMOTE_LINK_ID,
135     LMP_CLASS_LOCAL_INTERFACE_ID,
136     LMP_CLASS_REMOTE_INTERFACE_ID,
137     LMP_CLASS_MESSAGE_ID,
138     LMP_CLASS_MESSAGE_ID_ACK,
139     LMP_CLASS_CONFIG,
140     LMP_CLASS_HELLO,
141     LMP_CLASS_BEGIN_VERIFY,
142     LMP_CLASS_BEGIN_VERIFY_ACK,
143     LMP_CLASS_VERIFY_ID,
144     LMP_CLASS_TE_LINK,
145     LMP_CLASS_DATA_LINK,
146     LMP_CLASS_CHANNEL_STATUS,
147     LMP_CLASS_CHANNEL_STATUS_REQUEST,
148     LMP_CLASS_ERROR,
149
150     LMP_CLASS_MAX
151 } lmp_classes;
152
153 static value_string lmp_class_vals[] = {
154
155     {LMP_CLASS_LOCAL_CCID, "LOCAL_CCID"},
156     {LMP_CLASS_REMOTE_CCID, "REMOTE_CCID"},
157     {LMP_CLASS_LOCAL_NODE_ID, "LOCAL_NODE_ID"},
158     {LMP_CLASS_REMOTE_NODE_ID, "REMOTE_NODE_ID"},
159     {LMP_CLASS_LOCAL_LINK_ID, "LOCAL_LINK_ID"},
160     {LMP_CLASS_REMOTE_LINK_ID, "REMOTE_LINK_ID"},
161     {LMP_CLASS_LOCAL_INTERFACE_ID, "LOCAL_INTERFACE_ID"},
162     {LMP_CLASS_REMOTE_INTERFACE_ID, "REMOTE_INTERFACE_ID"},
163     {LMP_CLASS_MESSAGE_ID, "MESSAGE_ID"},
164     {LMP_CLASS_MESSAGE_ID_ACK, "MESSAGE_ID_ACK"},
165     {LMP_CLASS_CONFIG, "CONFIG"},
166     {LMP_CLASS_HELLO, "HELLO"},
167     {LMP_CLASS_BEGIN_VERIFY, "BEGIN_VERIFY"},
168     {LMP_CLASS_BEGIN_VERIFY_ACK, "BEGIN_VERIFY_ACK"},
169     {LMP_CLASS_VERIFY_ID, "VERIFY_ID"},
170     {LMP_CLASS_TE_LINK, "TE_LINK"},
171     {LMP_CLASS_DATA_LINK, "DATA_LINK"},
172     {LMP_CLASS_CHANNEL_STATUS, "CHANNEL_STATUS"},
173     {LMP_CLASS_CHANNEL_STATUS_REQUEST, "CHANNEL_STATUS_REQUEST"},
174     {LMP_CLASS_ERROR, "ERROR"},
175 };
176
177 #define VALID_CLASS(class) ((class) > LMP_CLASS_NULL && (class) < LMP_CLASS_MAX)
178
179 /*------------------------------------------------------------------------------
180  * Other constants & stuff
181  */
182
183 /* Channel Status */
184 static const value_string channel_status_str[] = {
185     {1, "Signal Okay (OK)"},
186     {2, "Signal Degraded (SD)"},
187     {3, "Signal Failed (SF)"},
188 };
189 static const value_string channel_status_short_str[] = {
190     {1, "OK"},
191     {2, "SD"},
192     {3, "SF"},
193 };
194
195 /*------------------------------------------------------------------------------
196  * LMP Filter values
197  */
198
199 enum lmp_filter_keys {
200
201   /* Message types ---------------- */
202   LMPF_MSG,
203
204   LMPF_MSG_CONFIG,
205   LMPF_MSG_CONFIG_ACK,
206   LMPF_MSG_CONFIG_NACK,
207   LMPF_MSG_HELLO,
208   LMPF_MSG_BEGIN_VERIFY,
209   LMPF_MSG_BEGIN_VERIFY_ACK,
210   LMPF_MSG_BEGIN_VERIFY_NACK,
211   LMPF_MSG_END_VERIFY,
212   LMPF_MSG_END_VERIFY_ACK,
213   LMPF_MSG_TEST,
214   LMPF_MSG_TEST_STATUS_SUCCESS,
215   LMPF_MSG_TEST_STATUS_FAILURE,
216   LMPF_MSG_TEST_STATUS_ACK,
217   LMPF_MSG_LINK_SUMMARY,
218   LMPF_MSG_LINK_SUMMARY_ACK,
219   LMPF_MSG_LINK_SUMMARY_NACK,
220   LMPF_MSG_CHANNEL_FAIL,
221   LMPF_MSG_CHANNEL_FAIL_ACK,
222   LMPF_MSG_CHANNEL_FAIL_NACK,
223   LMPF_MSG_CHANNEL_STATUS,
224   LMPF_MSG_CHANNEL_STATUS_ACK,
225   LMPF_MSG_CHANNEL_STATUS_REQ,
226   LMPF_MSG_CHANNEL_STATUS_RESP,
227
228   /* LMP Message Header Fields ------------------ */
229   LMPF_HDR_FLAGS,
230   LMPF_HDR_FLAGS_CC_DOWN,
231   LMPF_HDR_FLAGS_REBOOT,
232   LMPF_HDR_FLAGS_DWDM,
233   LMPF_HDR_FLAGS_AUTHENTICATION,
234
235   /* LMP Object Class Filters -------------------- */
236   LMPF_OBJECT,
237
238   LMPF_CLASS_LOCAL_CCID,
239   LMPF_CLASS_REMOTE_CCID,
240   LMPF_CLASS_LOCAL_NODE_ID,
241   LMPF_CLASS_REMOTE_NODE_ID,
242   LMPF_CLASS_LOCAL_LINK_ID,
243   LMPF_CLASS_REMOTE_LINK_ID,
244   LMPF_CLASS_LOCAL_INTERFACE_ID,
245   LMPF_CLASS_REMOTE_INTERFACE_ID,
246   LMPF_CLASS_MESSAGE_ID,
247   LMPF_CLASS_MESSAGE_ID_ACK,
248   LMPF_CLASS_CONFIG,
249   LMPF_CLASS_HELLO,
250   LMPF_CLASS_BEGIN_VERIFY,
251   LMPF_CLASS_BEGIN_VERIFY_ACK,
252   LMPF_CLASS_VERIFY_ID,
253   LMPF_CLASS_TE_LINK,
254   LMPF_CLASS_DATA_LINK,
255   LMPF_CLASS_CHANNEL_STATUS,
256   LMPF_CLASS_CHANNEL_STATUS_REQUEST,
257   LMPF_CLASS_ERROR,
258
259   LMPF_VAL_CTYPE,
260   LMPF_VAL_LOCAL_CCID,
261   LMPF_VAL_REMOTE_CCID,
262   LMPF_VAL_LOCAL_NODE_ID,
263   LMPF_VAL_REMOTE_NODE_ID,
264   LMPF_VAL_LOCAL_LINK_ID_IPV4,
265   LMPF_VAL_LOCAL_LINK_ID_UNNUM,
266   LMPF_VAL_REMOTE_LINK_ID_IPV4,
267   LMPF_VAL_REMOTE_LINK_ID_UNNUM,
268   LMPF_VAL_LOCAL_INTERFACE_ID_IPV4,
269   LMPF_VAL_LOCAL_INTERFACE_ID_UNNUM,
270   LMPF_VAL_REMOTE_INTERFACE_ID_IPV4,
271   LMPF_VAL_REMOTE_INTERFACE_ID_UNNUM,
272   LMPF_VAL_MESSAGE_ID,
273   LMPF_VAL_MESSAGE_ID_ACK,
274   LMPF_VAL_CONFIG_HELLO,
275   LMPF_VAL_CONFIG_HELLO_DEAD,
276   LMPF_VAL_HELLO_TXSEQ,
277   LMPF_VAL_HELLO_RXSEQ,
278
279   LMPF_VAL_BEGIN_VERIFY_FLAGS,
280   LMPF_VAL_BEGIN_VERIFY_FLAGS_ALL_LINKS,
281   LMPF_VAL_BEGIN_VERIFY_FLAGS_LINK_TYPE,
282   LMPF_VAL_BEGIN_VERIFY_INTERVAL,
283   LMPF_VAL_BEGIN_VERIFY_ENCTYPE,
284   LMPF_VAL_BEGIN_VERIFY_TRANSPORT,
285   LMPF_VAL_BEGIN_VERIFY_TRANSMISSION_RATE,
286   LMPF_VAL_BEGIN_VERIFY_WAVELENGTH,
287   LMPF_VAL_VERIFY_ID,
288
289   LMPF_VAL_TE_LINK_FLAGS,
290   LMPF_VAL_TE_LINK_FLAGS_FAULT_MGMT,
291   LMPF_VAL_TE_LINK_FLAGS_LINK_VERIFY,
292   LMPF_VAL_TE_LINK_LOCAL_IPV4,
293   LMPF_VAL_TE_LINK_LOCAL_UNNUM,
294   LMPF_VAL_TE_LINK_REMOTE_IPV4,
295   LMPF_VAL_TE_LINK_REMOTE_UNNUM,
296
297   LMPF_VAL_DATA_LINK_FLAGS,
298   LMPF_VAL_DATA_LINK_FLAGS_PORT,
299   LMPF_VAL_DATA_LINK_FLAGS_ALLOCATED,
300   LMPF_VAL_DATA_LINK_LOCAL_IPV4,
301   LMPF_VAL_DATA_LINK_LOCAL_UNNUM,
302   LMPF_VAL_DATA_LINK_REMOTE_IPV4,
303   LMPF_VAL_DATA_LINK_REMOTE_UNNUM,
304   LMPF_VAL_DATA_LINK_SUBOBJ,
305   LMPF_VAL_DATA_LINK_SUBOBJ_SWITCHING_TYPE,
306   LMPF_VAL_DATA_LINK_SUBOBJ_LSP_ENCODING,
307
308   LMPF_VAL_ERROR,
309   LMPF_VAL_ERROR_VERIFY_UNSUPPORTED_LINK,
310   LMPF_VAL_ERROR_VERIFY_UNWILLING,
311   LMPF_VAL_ERROR_VERIFY_TRANSPORT,
312   LMPF_VAL_ERROR_VERIFY_TE_LINK_ID,
313   LMPF_VAL_ERROR_SUMMARY_BAD_PARAMETERS,
314   LMPF_VAL_ERROR_SUMMARY_RENEGOTIATE,
315   LMPF_VAL_ERROR_SUMMARY_BAD_REMOTE_LINK_ID,
316   LMPF_VAL_ERROR_SUMMARY_BAD_TE_LINK,
317   LMPF_VAL_ERROR_SUMMARY_BAD_DATA_LINK,
318   LMPF_VAL_ERROR_CONFIG_BAD_PARAMETERS,
319   LMPF_VAL_ERROR_CONFIG_RENEGOTIATE,
320   LMPF_VAL_ERROR_CONFIG_BAD_CCID,
321
322   LMPF_MAX,
323 };
324
325 static int lmp_filter[LMPF_MAX];
326
327 static hf_register_info lmpf_info[] = {
328
329     /* Message type number */
330     {&lmp_filter[LMPF_MSG],
331      { "Message Type", "lmp.msg", FT_UINT8, BASE_DEC, VALS(message_type_vals), 0x0,
332         "", HFILL }},
333
334     /* Message type shorthands */
335     {&lmp_filter[LMPF_MSG_CONFIG],
336      { "Config Message", "lmp.msg.config", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
337         "", HFILL }},
338
339     {&lmp_filter[LMPF_MSG_CONFIG_ACK],
340      { "ConfigAck Message", "lmp.msg.configack", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
341         "", HFILL }},
342
343     {&lmp_filter[LMPF_MSG_CONFIG_NACK],
344      { "ConfigNack Message", "lmp.msg.confignack", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
345         "", HFILL }},
346
347     {&lmp_filter[LMPF_MSG_HELLO],
348      { "HELLO Message", "lmp.msg.hello", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
349         "", HFILL }},
350
351     {&lmp_filter[LMPF_MSG_BEGIN_VERIFY],
352      { "BeginVerify Message", "lmp.msg.beginverify", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
353         "", HFILL }},
354
355     {&lmp_filter[LMPF_MSG_BEGIN_VERIFY_ACK],
356      { "BeginVerifyAck Message", "lmp.msg.beginverifyack", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
357         "", HFILL }},
358
359     {&lmp_filter[LMPF_MSG_BEGIN_VERIFY_NACK],
360      { "BeginVerifyNack Message", "lmp.msg.beginverifynack", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
361         "", HFILL }},
362
363     {&lmp_filter[LMPF_MSG_END_VERIFY],
364      { "EndVerify Message", "lmp.msg.endverify", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
365         "", HFILL }},
366
367     {&lmp_filter[LMPF_MSG_TEST],
368      { "Test Message", "lmp.msg.test", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
369         "", HFILL }},
370
371     {&lmp_filter[LMPF_MSG_TEST_STATUS_SUCCESS],
372      { "TestStatusSuccess Message", "lmp.msg.teststatussuccess", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
373         "", HFILL }},
374
375     {&lmp_filter[LMPF_MSG_TEST_STATUS_FAILURE],
376      { "TestStatusFailure Message", "lmp.msg.teststatusfailure", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
377         "", HFILL }},
378
379     {&lmp_filter[LMPF_MSG_TEST_STATUS_ACK],
380      { "TestStatusAck Message", "lmp.msg.teststatusack", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
381         "", HFILL }},
382
383     {&lmp_filter[LMPF_MSG_LINK_SUMMARY],
384      { "LinkSummary Message", "lmp.msg.linksummary", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
385         "", HFILL }},
386
387     {&lmp_filter[LMPF_MSG_LINK_SUMMARY_ACK],
388      { "LinkSummaryAck Message", "lmp.msg.linksummaryack", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
389         "", HFILL }},
390
391     {&lmp_filter[LMPF_MSG_LINK_SUMMARY_NACK],
392      { "LinkSummaryNack Message", "lmp.msg.linksummarynack", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
393         "", HFILL }},
394
395     {&lmp_filter[LMPF_MSG_CHANNEL_FAIL],
396      { "ChannelFail Message", "lmp.msg.channelfail", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
397         "", HFILL }},
398
399     {&lmp_filter[LMPF_MSG_CHANNEL_FAIL_ACK],
400      { "ChannelFailAck Message", "lmp.msg.channelfailack", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
401         "", HFILL }},
402
403     {&lmp_filter[LMPF_MSG_CHANNEL_FAIL_NACK],
404      { "ChannelFailNack Message", "lmp.msg.channelfailnack", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
405         "", HFILL }},
406
407     {&lmp_filter[LMPF_MSG_CHANNEL_STATUS],
408      { "ChannelStatus Message", "lmp.msg.channelstatus", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
409         "", HFILL }},
410
411     {&lmp_filter[LMPF_MSG_CHANNEL_STATUS_ACK],
412      { "ChannelStatusAck Message", "lmp.msg.channelstatusack", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
413         "", HFILL }},
414
415     {&lmp_filter[LMPF_MSG_CHANNEL_STATUS_REQ],
416      { "ChannelStatusRequest Message", "lmp.msg.channelstatusrequest", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
417         "", HFILL }},
418
419     {&lmp_filter[LMPF_MSG_CHANNEL_STATUS_RESP],
420      { "ChannelStatusResponse Message", "lmp.msg.channelstatusresponse", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
421         "", HFILL }},
422
423
424     /* LMP Message Header Fields ------------------- */
425
426     {&lmp_filter[LMPF_HDR_FLAGS],
427      { "LMP Header - Flags", "lmp.hdr.flags", FT_UINT8, BASE_DEC, NULL, 0x0,
428         "", HFILL }},
429
430     {&lmp_filter[LMPF_HDR_FLAGS_CC_DOWN],
431      { "ControlChannelDown", "lmp.hdr.ccdown", FT_BOOLEAN, 8, NULL, 0x01,
432         "", HFILL }},
433
434     {&lmp_filter[LMPF_HDR_FLAGS_REBOOT],
435      { "Reboot", "lmp.hdr.reboot", FT_BOOLEAN, 8, NULL, 0x02,
436         "", HFILL }},
437
438     {&lmp_filter[LMPF_HDR_FLAGS_DWDM],
439      { "DWDM Node", "lmp.hdr.dwdm", FT_BOOLEAN, 8, NULL, 0x04,
440         "", HFILL }},
441
442     {&lmp_filter[LMPF_HDR_FLAGS_AUTHENTICATION],
443      { "Authentication", "lmp.hdr.auth", FT_BOOLEAN, 8, NULL, 0x08,
444         "", HFILL }},
445
446     /* LMP object class filters ------------------------------- */
447
448     {&lmp_filter[LMPF_OBJECT],
449      { "LOCAL_CCID", "lmp.object", FT_UINT8, BASE_DEC, NULL, 0x0,
450         "", HFILL }},
451
452     {&lmp_filter[LMPF_CLASS_LOCAL_CCID],
453      { "LOCAL_CCID", "lmp.obj.local_ccid", FT_NONE, BASE_NONE, NULL, 0x0,
454         "", HFILL }},
455     {&lmp_filter[LMPF_CLASS_REMOTE_CCID],
456      { "REMOTE_CCID", "lmp.obj.remote_ccid", FT_NONE, BASE_NONE, NULL, 0x0,
457         "", HFILL }},
458
459     {&lmp_filter[LMPF_CLASS_LOCAL_NODE_ID],
460      { "LOCAL_NODE_ID", "lmp.obj.local_nodeid", FT_NONE, BASE_NONE, NULL, 0x0,
461         "", HFILL }},
462     {&lmp_filter[LMPF_CLASS_REMOTE_NODE_ID],
463      { "REMOTE_NODE_ID", "lmp.obj.remote_nodeid", FT_NONE, BASE_NONE, NULL, 0x0,
464         "", HFILL }},
465
466     {&lmp_filter[LMPF_CLASS_LOCAL_NODE_ID],
467      { "LOCAL_NODE_ID", "lmp.obj.local_nodeid", FT_NONE, BASE_NONE, NULL, 0x0,
468         "", HFILL }},
469     {&lmp_filter[LMPF_CLASS_REMOTE_NODE_ID],
470      { "REMOTE_NODE_ID", "lmp.obj.remote_nodeid", FT_NONE, BASE_NONE, NULL, 0x0,
471         "", HFILL }},
472
473     {&lmp_filter[LMPF_CLASS_LOCAL_LINK_ID],
474      { "LOCAL_LINK_ID", "lmp.obj.local_linkid", FT_NONE, BASE_NONE, NULL, 0x0,
475         "", HFILL }},
476     {&lmp_filter[LMPF_CLASS_REMOTE_LINK_ID],
477      { "REMOTE_LINK_ID", "lmp.obj.remote_linkid", FT_NONE, BASE_NONE, NULL, 0x0,
478         "", HFILL }},
479
480     {&lmp_filter[LMPF_CLASS_LOCAL_INTERFACE_ID],
481      { "LOCAL_INTERFACE_ID", "lmp.obj.local_interfaceid", FT_NONE, BASE_NONE, NULL, 0x0,
482         "", HFILL }},
483     {&lmp_filter[LMPF_CLASS_REMOTE_INTERFACE_ID],
484      { "REMOTE_INTERFACE_ID", "lmp.obj.remote_interfaceid", FT_NONE, BASE_NONE, NULL, 0x0,
485         "", HFILL }},
486
487     {&lmp_filter[LMPF_CLASS_MESSAGE_ID],
488      { "MESSAGE_ID", "lmp.obj.messageid", FT_NONE, BASE_NONE, NULL, 0x0,
489         "", HFILL }},
490     {&lmp_filter[LMPF_CLASS_MESSAGE_ID_ACK],
491      { "MESSAGE_ID_ACK", "lmp.obj.messageid_ack", FT_NONE, BASE_NONE, NULL, 0x0,
492         "", HFILL }},
493
494     {&lmp_filter[LMPF_CLASS_CONFIG],
495      { "CONFIG", "lmp.obj.config", FT_NONE, BASE_NONE, NULL, 0x0,
496         "", HFILL }},
497
498     {&lmp_filter[LMPF_CLASS_HELLO],
499      { "HELLO", "lmp.obj.hello", FT_NONE, BASE_NONE, NULL, 0x0,
500         "", HFILL }},
501
502     {&lmp_filter[LMPF_CLASS_BEGIN_VERIFY],
503      { "BEGIN_VERIFY", "lmp.obj.begin_verify", FT_NONE, BASE_NONE, NULL, 0x0,
504         "", HFILL }},
505     {&lmp_filter[LMPF_CLASS_BEGIN_VERIFY_ACK],
506      { "BEGIN_VERIFY_ACK", "lmp.obj.begin_verify_ack", FT_NONE, BASE_NONE, NULL, 0x0,
507         "", HFILL }},
508     {&lmp_filter[LMPF_CLASS_VERIFY_ID],
509      { "VERIFY_ID", "lmp.obj.verifyid", FT_NONE, BASE_NONE, NULL, 0x0,
510         "", HFILL }},
511
512     {&lmp_filter[LMPF_CLASS_TE_LINK],
513      { "TE_LINK", "lmp.obj.te_link", FT_NONE, BASE_NONE, NULL, 0x0,
514         "", HFILL }},
515     {&lmp_filter[LMPF_CLASS_DATA_LINK],
516      { "DATA_LINK", "lmp.obj.data_link", FT_NONE, BASE_NONE, NULL, 0x0,
517         "", HFILL }},
518
519     {&lmp_filter[LMPF_CLASS_CHANNEL_STATUS],
520      { "CHANNEL_STATUS", "lmp.obj.channel_status", FT_NONE, BASE_NONE, NULL, 0x0,
521         "", HFILL }},
522     {&lmp_filter[LMPF_CLASS_CHANNEL_STATUS_REQUEST],
523      { "CHANNEL_STATUS_REQUEST", "lmp.obj.channel_status_request", FT_NONE, BASE_NONE, NULL, 0x0,
524         "", HFILL }},
525
526     {&lmp_filter[LMPF_CLASS_ERROR],
527      { "ERROR", "lmp.obj.error", FT_NONE, BASE_NONE, NULL, 0x0,
528         "", HFILL }},
529
530     /* Other LMP Value Filters ------------------------------ */
531
532     {&lmp_filter[LMPF_VAL_CTYPE],
533      { "Object C-Type", "lmp.obj.ctype", FT_UINT8, BASE_DEC, NULL, 0x0,
534         "", HFILL }},
535
536     {&lmp_filter[LMPF_VAL_LOCAL_CCID],
537      { "Local CCID Value", "lmp.local_ccid", FT_UINT32, BASE_DEC, NULL, 0x0,
538         "", HFILL }},
539     {&lmp_filter[LMPF_VAL_REMOTE_CCID],
540      { "Remote CCID Value", "lmp.remote_ccid", FT_UINT32, BASE_DEC, NULL, 0x0,
541         "", HFILL }},
542
543     {&lmp_filter[LMPF_VAL_LOCAL_NODE_ID],
544      { "Local Node ID Value", "lmp.local_nodeid", FT_IPv4, BASE_NONE, NULL, 0x0,
545         "", HFILL }},
546     {&lmp_filter[LMPF_VAL_REMOTE_NODE_ID],
547      { "Remote Node ID Value", "lmp.remote_nodeid", FT_IPv4, BASE_NONE, NULL, 0x0,
548         "", HFILL }},
549
550     {&lmp_filter[LMPF_VAL_LOCAL_LINK_ID_IPV4],
551      { "Local Link ID - IPv4", "lmp.local_linkid_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0,
552         "", HFILL }},
553     {&lmp_filter[LMPF_VAL_LOCAL_LINK_ID_UNNUM],
554      { "Local Link ID - Unnumbered", "lmp.local_linkid_unnum", FT_UINT32, BASE_DEC, NULL, 0x0,
555         "", HFILL }},
556     {&lmp_filter[LMPF_VAL_REMOTE_LINK_ID_IPV4],
557      { "Remote Link ID - IPv4", "lmp.remote_linkid_ipv4", FT_UINT32, BASE_DEC, NULL, 0x0,
558         "", HFILL }},
559     {&lmp_filter[LMPF_VAL_REMOTE_LINK_ID_UNNUM],
560      { "Remote Link ID - Unnumbered", "lmp.remote_linkid_unnum", FT_UINT32, BASE_DEC, NULL, 0x0,
561         "", HFILL }},
562
563     {&lmp_filter[LMPF_VAL_LOCAL_INTERFACE_ID_IPV4],
564      { "Local Interface ID - IPv4", "lmp.local_interfaceid_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0,
565         "", HFILL }},
566     {&lmp_filter[LMPF_VAL_LOCAL_INTERFACE_ID_UNNUM],
567      { "Local Interface ID - Unnumbered", "lmp.local_interfaceid_unnum", FT_UINT32, BASE_DEC, NULL, 0x0,
568         "", HFILL }},
569     {&lmp_filter[LMPF_VAL_REMOTE_INTERFACE_ID_IPV4],
570      { "Remote Interface ID - IPv4", "lmp.remote_interfaceid_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0,
571         "", HFILL }},
572     {&lmp_filter[LMPF_VAL_REMOTE_INTERFACE_ID_UNNUM],
573      { "Remote Interface ID - Unnumbered", "lmp.remote_interfaceid_unnum", FT_UINT32, BASE_DEC, NULL, 0x0,
574         "", HFILL }},
575
576     {&lmp_filter[LMPF_VAL_MESSAGE_ID],
577      { "Message-ID Value", "lmp.messageid", FT_UINT32, BASE_DEC, NULL, 0x0,
578         "", HFILL }},
579     {&lmp_filter[LMPF_VAL_MESSAGE_ID_ACK],
580      { "Message-ID Ack Value", "lmp.messageid_ack", FT_UINT32, BASE_DEC, NULL, 0x0,
581         "", HFILL }},
582
583     {&lmp_filter[LMPF_VAL_CONFIG_HELLO],
584      { "HelloInterval", "lmp.hellointerval", FT_UINT32, BASE_DEC, NULL, 0x0,
585         "", HFILL }},
586     {&lmp_filter[LMPF_VAL_CONFIG_HELLO_DEAD],
587      { "HelloDeadInterval", "lmp.hellodeadinterval", FT_UINT32, BASE_DEC, NULL, 0x0,
588         "", HFILL }},
589
590     {&lmp_filter[LMPF_VAL_HELLO_TXSEQ],
591      { "TxSeqNum", "lmp.txseqnum", FT_UINT32, BASE_DEC, NULL, 0x0,
592         "", HFILL }},
593     {&lmp_filter[LMPF_VAL_HELLO_RXSEQ],
594      { "RxSeqNum", "lmp.rxseqnum", FT_UINT32, BASE_DEC, NULL, 0x0,
595         "", HFILL }},
596
597     {&lmp_filter[LMPF_VAL_BEGIN_VERIFY_FLAGS],
598      { "Flags", "lmp.begin_verify.flags", FT_UINT16, BASE_HEX, NULL, 0x0,
599         "", HFILL }},
600     {&lmp_filter[LMPF_VAL_BEGIN_VERIFY_FLAGS_ALL_LINKS],
601      { "Verify All Links", "lmp.begin_verify.all_links",
602        FT_BOOLEAN, 8, NULL, 0x01, "", HFILL }},
603     {&lmp_filter[LMPF_VAL_BEGIN_VERIFY_FLAGS_LINK_TYPE],
604      { "Data Link Type", "lmp.begin_verify.link_type",
605        FT_BOOLEAN, 8, NULL, 0x02, "", HFILL }},
606     {&lmp_filter[LMPF_VAL_BEGIN_VERIFY_ENCTYPE],
607      { "Encoding Type", "lmp.begin_verify.enctype", FT_UINT8, BASE_DEC, VALS(gmpls_lsp_enc_str), 0x0,
608         "", HFILL }},
609     {&lmp_filter[LMPF_VAL_VERIFY_ID],
610      { "Verify-ID", "lmp.verifyid", FT_UINT32, BASE_DEC, NULL, 0x0,
611         "", HFILL }},
612
613     {&lmp_filter[LMPF_VAL_TE_LINK_FLAGS],
614      { "TE-Link Flags", "lmp.te_link_flags", FT_UINT8, BASE_HEX, NULL, 0x0,
615         "", HFILL }},
616     {&lmp_filter[LMPF_VAL_TE_LINK_FLAGS_FAULT_MGMT],
617      { "Fault Management Supported", "lmp.te_link.fault_mgmt",
618        FT_BOOLEAN, 8, NULL, 0x01, "", HFILL }},
619     {&lmp_filter[LMPF_VAL_TE_LINK_FLAGS_LINK_VERIFY],
620      { "Link Verification Supported", "lmp.te_link.link_verify",
621        FT_BOOLEAN, 8, NULL, 0x02, "", HFILL }},
622     {&lmp_filter[LMPF_VAL_TE_LINK_LOCAL_IPV4],
623      { "TE-Link Local ID - IPv4", "lmp.te_link.local_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0,
624         "", HFILL }},
625     {&lmp_filter[LMPF_VAL_TE_LINK_LOCAL_UNNUM],
626      { "TE-Link Local ID - Unnumbered", "lmp.te_link.local_unnum", FT_UINT32, BASE_DEC, NULL, 0x0,
627         "", HFILL }},
628     {&lmp_filter[LMPF_VAL_TE_LINK_REMOTE_IPV4],
629      { "TE-Link Remote ID - IPv4", "lmp.te_link.remote_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0,
630         "", HFILL }},
631     {&lmp_filter[LMPF_VAL_TE_LINK_REMOTE_UNNUM],
632      { "TE-Link Remote ID - Unnumbered", "lmp.te_link.remote_unnum", FT_UINT32, BASE_DEC, NULL, 0x0,
633         "", HFILL }},
634
635     {&lmp_filter[LMPF_VAL_DATA_LINK_FLAGS],
636      { "Data-Link Flags", "lmp.data_link_flags", FT_UINT8, BASE_HEX, NULL, 0x0,
637         "", HFILL }},
638     {&lmp_filter[LMPF_VAL_DATA_LINK_FLAGS_PORT],
639      { "Data-Link is Individual Port", "lmp.data_link.port",
640        FT_BOOLEAN, 8, NULL, 0x01, "", HFILL }},
641     {&lmp_filter[LMPF_VAL_DATA_LINK_FLAGS_ALLOCATED],
642      { "Data-Link is Allocated", "lmp.data_link.link_verify",
643        FT_BOOLEAN, 8, NULL, 0x02, "", HFILL }},
644     {&lmp_filter[LMPF_VAL_DATA_LINK_LOCAL_IPV4],
645      { "Data-Link Local ID - IPv4", "lmp.data_link.local_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0,
646         "", HFILL }},
647     {&lmp_filter[LMPF_VAL_DATA_LINK_LOCAL_UNNUM],
648      { "Data-Link Local ID - Unnumbered", "lmp.data_link.local_unnum", FT_UINT32, BASE_DEC, NULL, 0x0,
649         "", HFILL }},
650     {&lmp_filter[LMPF_VAL_DATA_LINK_REMOTE_IPV4],
651      { "Data-Link Remote ID - IPv4", "lmp.data_link.remote_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0,
652         "", HFILL }},
653     {&lmp_filter[LMPF_VAL_DATA_LINK_REMOTE_UNNUM],
654      { "Data-Link Remote ID - Unnumbered", "lmp.data_link.remote_unnum", FT_UINT32, BASE_DEC, NULL, 0x0,
655         "", HFILL }},
656     {&lmp_filter[LMPF_VAL_DATA_LINK_SUBOBJ],
657      { "Subobject", "lmp.data_link_subobj", FT_NONE, BASE_DEC, NULL, 0x0,
658         "", HFILL }},
659     {&lmp_filter[LMPF_VAL_DATA_LINK_SUBOBJ_SWITCHING_TYPE],
660      { "Interface Switching Capability", "lmp.data_link_switching", FT_UINT8, BASE_DEC,
661        VALS(gmpls_switching_type_str), 0x0, "", HFILL }},
662     {&lmp_filter[LMPF_VAL_DATA_LINK_SUBOBJ_LSP_ENCODING],
663      { "LSP Encoding Type", "lmp.data_link_encoding", FT_UINT8, BASE_DEC,
664        VALS(gmpls_lsp_enc_str), 0x0, "", HFILL }},
665
666     {&lmp_filter[LMPF_VAL_ERROR],
667      { "Error Code", "lmp.error", FT_UINT32, BASE_HEX, NULL, 0x0,
668         "", HFILL }},
669
670     {&lmp_filter[LMPF_VAL_ERROR_VERIFY_UNSUPPORTED_LINK],
671      { "Verification - Unsupported for this TE-Link", "lmp.error.verify_unsupported_link",
672        FT_BOOLEAN, 8, NULL, 0x01, "", HFILL }},
673     {&lmp_filter[LMPF_VAL_ERROR_VERIFY_UNWILLING],
674      { "Verification - Unwilling to Verify at this time", "lmp.error.verify_unwilling",
675        FT_BOOLEAN, 8, NULL, 0x02, "", HFILL }},
676     {&lmp_filter[LMPF_VAL_ERROR_VERIFY_TRANSPORT],
677      { "Verification - Transport Unsupported", "lmp.error.verify_unsupported_transport",
678        FT_BOOLEAN, 8, NULL, 0x04, "", HFILL }},
679     {&lmp_filter[LMPF_VAL_ERROR_VERIFY_TE_LINK_ID],
680      { "Verification - TE Link ID Configuration Error", "lmp.error.verify_te_link_id",
681        FT_BOOLEAN, 8, NULL, 0x08, "", HFILL }},
682
683     {&lmp_filter[LMPF_VAL_ERROR_SUMMARY_BAD_PARAMETERS],
684      { "Summary - Unacceptable non-negotiable parameters", "lmp.error.summary_bad_params",
685        FT_BOOLEAN, 8, NULL, 0x01, "", HFILL }},
686     {&lmp_filter[LMPF_VAL_ERROR_SUMMARY_RENEGOTIATE],
687      { "Summary - Renegotiate Parametere", "lmp.error.summary_renegotiate",
688        FT_BOOLEAN, 8, NULL, 0x02, "", HFILL }},
689     {&lmp_filter[LMPF_VAL_ERROR_SUMMARY_BAD_REMOTE_LINK_ID],
690      { "Summary - Bad Remote Link ID", "lmp.error.summary_bad_remote_linkid",
691        FT_BOOLEAN, 8, NULL, 0x04, "", HFILL }},
692     {&lmp_filter[LMPF_VAL_ERROR_SUMMARY_BAD_TE_LINK],
693      { "Summary - Bad TE Link Object", "lmp.error.summary_bad_te_link",
694        FT_BOOLEAN, 8, NULL, 0x08, "", HFILL }},
695     {&lmp_filter[LMPF_VAL_ERROR_SUMMARY_BAD_DATA_LINK],
696      { "Summary - Bad Data Link Object", "lmp.error.summary_bad_data_link",
697        FT_BOOLEAN, 8, NULL, 0x10, "", HFILL }},
698
699     {&lmp_filter[LMPF_VAL_ERROR_CONFIG_BAD_PARAMETERS],
700      { "Config - Unacceptable non-negotiable parameters", "lmp.error.config_bad_params",
701        FT_BOOLEAN, 8, NULL, 0x01, "", HFILL }},
702     {&lmp_filter[LMPF_VAL_ERROR_CONFIG_RENEGOTIATE],
703      { "Config - Renegotiate Parametere", "lmp.error.config_renegotiate",
704        FT_BOOLEAN, 8, NULL, 0x02, "", HFILL }},
705     {&lmp_filter[LMPF_VAL_ERROR_CONFIG_BAD_CCID],
706      { "Config - Bad CC ID", "lmp.error.config_bad_ccid",
707        FT_BOOLEAN, 8, NULL, 0x04, "", HFILL }},
708 };
709
710 static int
711 lmp_class_to_filter_num(int class)
712 {
713     if (VALID_CLASS(class))
714         return class + LMPF_OBJECT;
715     return -1;
716 }
717
718 /*------------------------------------------------------------------------------
719  * LMP Subtrees
720  *
721  * We have two types of subtrees - a statically defined, constant set and
722  * a class set - one for each class. The static ones are before all the class ones
723  */
724 enum {
725     LMP_TREE_MAIN,
726     LMP_TREE_HEADER,
727     LMP_TREE_HEADER_FLAGS,
728     LMP_TREE_OBJECT_HEADER,
729     LMP_TREE_ERROR_FLAGS,
730     LMP_TREE_BEGIN_VERIFY_FLAGS,
731     LMP_TREE_BEGIN_VERIFY_TRANSPORT_FLAGS,
732     LMP_TREE_TE_LINK_FLAGS,
733     LMP_TREE_DATA_LINK_FLAGS,
734     LMP_TREE_DATA_LINK_SUBOBJ,
735     LMP_TREE_CHANNEL_STATUS_ID,
736
737     LMP_TREE_CLASS_START
738 };
739 #define NUM_LMP_SUBTREES (LMP_TREE_CLASS_START + LMP_CLASS_MAX)
740
741 static gint lmp_subtree[NUM_LMP_SUBTREES];
742
743 static int lmp_class_to_subtree(int class)
744 {
745     if (VALID_CLASS(class))
746         return lmp_subtree[LMP_TREE_CLASS_START + class];
747
748     return -1;
749 }
750
751 /*------------------------------------------------------------------------------
752  * Da code
753  */
754
755 static void
756 dissect_lmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
757 {
758     int offset = 0;
759     proto_tree *lmp_tree = NULL, *ti, *ti2;
760     proto_tree *lmp_header_tree;
761     proto_tree *lmp_header_flags_tree;
762     proto_tree *lmp_object_tree;
763     proto_tree *lmp_object_header_tree;
764     proto_tree *lmp_flags_tree;
765     proto_tree *lmp_subobj_tree;
766
767     guint8 version;
768     guint8 flags;
769     guint8 message_type;
770     guint16 cksum, computed_cksum;
771     vec_t cksum_vec[1];
772     int j, k, l, len;
773     int msg_length;
774     int obj_length;
775     int mylen;
776     int offset2;
777
778     if (check_col(pinfo->cinfo, COL_PROTOCOL))
779         col_set_str(pinfo->cinfo, COL_PROTOCOL, "LMP");
780     if (check_col(pinfo->cinfo, COL_INFO))
781         col_clear(pinfo->cinfo, COL_INFO);
782
783     version = (tvb_get_guint8(tvb, offset+0)) >> 4;
784     flags = tvb_get_guint8(tvb, offset+2);
785     message_type = tvb_get_guint8(tvb, offset+3);
786     if (check_col(pinfo->cinfo, COL_INFO)) {
787         col_add_str(pinfo->cinfo, COL_INFO,
788             val_to_str(message_type, message_type_vals, "Unknown (%u). "));
789     }
790
791     if (tree) {
792         msg_length = tvb_get_ntohs(tvb, offset+4);
793         ti = proto_tree_add_item(tree, proto_lmp, tvb, offset, msg_length,
794             FALSE);
795         lmp_tree = proto_item_add_subtree(ti, lmp_subtree[LMP_TREE_MAIN]);
796
797         ti = proto_tree_add_text(lmp_tree, tvb, offset, 12, "LMP Header. %s",
798                                  val_to_str(message_type, message_type_vals,
799                                             "Unknown Message (%u). "));
800         lmp_header_tree = proto_item_add_subtree(ti, lmp_subtree[LMP_TREE_HEADER]);
801
802         proto_tree_add_text(lmp_header_tree, tvb, offset, 1, "LMP Version: %u",
803                             version);
804         ti = proto_tree_add_text(lmp_header_tree, tvb, offset+2, 1, "Flags: %02x",
805                                  flags);
806         lmp_header_flags_tree = proto_item_add_subtree(ti, lmp_subtree[LMP_TREE_HEADER_FLAGS]);
807         proto_tree_add_boolean(lmp_header_flags_tree, lmp_filter[LMPF_HDR_FLAGS_CC_DOWN],
808                                tvb, offset+2, 1, flags);
809         proto_tree_add_boolean(lmp_header_flags_tree, lmp_filter[LMPF_HDR_FLAGS_REBOOT],
810                                tvb, offset+2, 1, flags);
811         proto_tree_add_boolean(lmp_header_flags_tree, lmp_filter[LMPF_HDR_FLAGS_DWDM],
812                                tvb, offset+2, 1, flags);
813         proto_tree_add_boolean(lmp_header_flags_tree, lmp_filter[LMPF_HDR_FLAGS_AUTHENTICATION],
814                                tvb, offset+2, 1, flags);
815         proto_tree_add_uint(lmp_header_tree, lmp_filter[LMPF_MSG], tvb,
816                             offset+3, 1, message_type);
817         proto_tree_add_text(lmp_header_tree, tvb, offset+4, 2, "Length: %d bytes",
818                             msg_length);
819         if (LMPF_MSG + message_type <= LMPF_MSG_CHANNEL_STATUS_RESP &&
820                        message_type > 0) {
821                 proto_tree_add_boolean_hidden(lmp_header_tree, lmp_filter[LMPF_MSG + message_type], tvb,
822                                       offset+3, 1, 1);
823         } else {
824                 proto_tree_add_protocol_format(lmp_header_tree, proto_malformed, tvb, offset+3, 1,
825                         "Invalid message type: %u", message_type);
826                 return;
827         }
828
829         cksum = tvb_get_ntohs(tvb, offset+6);
830         if (!pinfo->fragmented && (int) tvb_length(tvb) >= msg_length) {
831             /* The packet isn't part of a fragmented datagram and isn't
832                truncated, so we can checksum it. */
833             cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, msg_length);
834             cksum_vec[0].len = msg_length;
835             computed_cksum = in_cksum(&cksum_vec[0], 1);
836             if (computed_cksum == 0) {
837                 proto_tree_add_text(lmp_header_tree, tvb, offset+6, 2,
838                                     "Message Checksum: 0x%04x (correct)",
839                                     cksum);
840             } else {
841                 proto_tree_add_text(lmp_header_tree, tvb, offset+6, 2,
842                                     "Message Checksum: 0x%04x (incorrect, should be 0x%04x)",
843                                     cksum,
844                                     in_cksum_shouldbe(cksum, computed_cksum));
845             }
846         } else {
847             proto_tree_add_text(lmp_header_tree, tvb, offset+6, 2,
848                                 "Message Checksum: 0x%04x",
849                                 cksum);
850         }
851         proto_tree_add_text(lmp_header_tree, tvb, offset+8, 4,
852                             "Local Control Channel ID: %d (%s)",
853                             tvb_get_ntohl(tvb, offset+8),
854                             ip_to_str(tvb_get_ptr(tvb, offset+8, 4)));
855
856         offset += 8;
857         len = 8;
858         while (len < msg_length) {
859             guint8 class;
860             guint8 type;
861             guint8 negotiable;
862             char *object_type;
863
864             obj_length = tvb_get_ntohs(tvb, offset+2);
865             class = tvb_get_guint8(tvb, offset+1);
866             type = tvb_get_guint8(tvb, offset);
867             negotiable = (type >> 7); type &= 0x7f;
868             object_type = val_to_str(class, lmp_class_vals, "Unknown");
869             proto_tree_add_uint_hidden(lmp_tree, lmp_filter[LMPF_OBJECT], tvb,
870                                             offset, 1, class);
871             if (VALID_CLASS(class)) {
872                 ti = proto_tree_add_item(lmp_tree, lmp_filter[lmp_class_to_filter_num(class)],
873                                      tvb, offset, obj_length, FALSE);
874             } else {
875                 proto_tree_add_protocol_format(lmp_tree, proto_malformed, tvb, offset+1, 1,
876                         "Invalid class: %u", class);
877                 return;
878             }
879
880             lmp_object_tree = proto_item_add_subtree(ti, lmp_class_to_subtree(class));
881
882             ti2 = proto_tree_add_text(lmp_object_tree, tvb, offset, 4,
883                                       "Header. Class %d, C-Type %d, Length %d, %s",
884                                       class, type, obj_length,
885                                       negotiable ? "Negotiable" : "Not Negotiable");
886             lmp_object_header_tree = proto_item_add_subtree(ti2, lmp_subtree[LMP_TREE_OBJECT_HEADER]);
887             proto_tree_add_text(lmp_object_header_tree, tvb, offset, 1,
888                                 negotiable ? "Negotiable" : "Not Negotiable");
889             proto_tree_add_text(lmp_object_header_tree, tvb, offset+2, 2,
890                                 "Length: %u", obj_length);
891             proto_tree_add_text(lmp_object_header_tree, tvb, offset+1, 1,
892                                 "Object Class: %u - %s",
893                                 class, object_type);
894             proto_tree_add_item(lmp_object_header_tree, lmp_filter[LMPF_VAL_CTYPE],
895                                 tvb, offset, 1, type);
896             offset2 = offset+4;
897             mylen = obj_length - 4;
898
899             switch(class) {
900
901             case LMP_CLASS_NULL:
902                 break;
903
904             case LMP_CLASS_LOCAL_CCID:
905             case LMP_CLASS_REMOTE_CCID:
906                 switch(type) {
907                 case 1:
908                     l = (class == LMP_CLASS_LOCAL_CCID) ?
909                         LMPF_VAL_LOCAL_CCID : LMPF_VAL_REMOTE_CCID;
910                     proto_item_append_text(ti, ": %d", tvb_get_ntohl(tvb, offset2));
911                     proto_tree_add_uint(lmp_object_tree, lmp_filter[l], tvb, offset2, 4,
912                                         tvb_get_ntohl(tvb, offset2));
913                     break;
914                 default:
915                     proto_tree_add_text(lmp_object_tree, tvb, offset2, mylen,
916                                         "Data (%d bytes)", mylen);
917                     break;
918                 }
919                 break;
920
921             case LMP_CLASS_LOCAL_NODE_ID:
922             case LMP_CLASS_REMOTE_NODE_ID:
923                 switch(type) {
924                 case 1:
925                     l = (class == LMP_CLASS_LOCAL_NODE_ID) ?
926                         LMPF_VAL_LOCAL_NODE_ID : LMPF_VAL_REMOTE_NODE_ID;
927                     proto_item_append_text(ti, ": %s",
928                                            ip_to_str(tvb_get_ptr(tvb, offset2, 4)));
929                     proto_tree_add_item(lmp_object_tree, lmp_filter[l], tvb, offset2, 4,
930                                         FALSE);
931                     break;
932                 default:
933                     proto_tree_add_text(lmp_object_tree, tvb, offset2, mylen,
934                                         "Data (%d bytes)", mylen);
935                     break;
936                 }
937                 break;
938
939             case LMP_CLASS_LOCAL_LINK_ID:
940             case LMP_CLASS_REMOTE_LINK_ID:
941                 switch(type) {
942                 case 1:
943                     l = (class == LMP_CLASS_LOCAL_LINK_ID) ?
944                         LMPF_VAL_LOCAL_LINK_ID_IPV4 : LMPF_VAL_REMOTE_LINK_ID_IPV4;
945                     proto_item_append_text(ti, ": IPv4 %s",
946                                            ip_to_str(tvb_get_ptr(tvb, offset2, 4)));
947                     proto_tree_add_item(lmp_object_tree, lmp_filter[l], tvb, offset2, 4,
948                                         FALSE);
949                     break;
950                 case 2:
951                     proto_item_append_text(ti, ": IPv6 %s",
952                                            ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset2, 16)));
953                     proto_tree_add_text(lmp_object_tree, tvb, offset2, 16, "IPv6: %s",
954                                         ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset2, 16)));
955                     break;
956                 case 3:
957                     l = (class == LMP_CLASS_LOCAL_LINK_ID) ?
958                         LMPF_VAL_LOCAL_LINK_ID_UNNUM : LMPF_VAL_REMOTE_LINK_ID_UNNUM;
959                     proto_item_append_text(ti, ": Unnumbered %d", tvb_get_ntohl(tvb, offset2));
960                     proto_tree_add_item(lmp_object_tree, lmp_filter[l], tvb, offset2, 4,
961                                         FALSE);
962                     break;
963                 default:
964                     proto_tree_add_text(lmp_object_tree, tvb, offset2, mylen,
965                                         "Data (%d bytes)", mylen);
966                     break;
967                 }
968                 break;
969
970             case LMP_CLASS_LOCAL_INTERFACE_ID:
971             case LMP_CLASS_REMOTE_INTERFACE_ID:
972                 switch(type) {
973                 case 1:
974                     l = (class == LMP_CLASS_LOCAL_INTERFACE_ID) ?
975                         LMPF_VAL_LOCAL_INTERFACE_ID_IPV4 : LMPF_VAL_REMOTE_INTERFACE_ID_IPV4;
976                     proto_item_append_text(ti, ": IPv4 %s",
977                                            ip_to_str(tvb_get_ptr(tvb, offset2, 4)));
978                     proto_tree_add_item(lmp_object_tree, lmp_filter[l], tvb, offset2, 4,
979                                         FALSE);
980                     break;
981                 case 2:
982                     proto_item_append_text(ti, ": IPv6 %s",
983                                            ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset2, 16)));
984                     proto_tree_add_text(lmp_object_tree, tvb, offset2, 16, "IPv6: %s",
985                                         ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset2, 16)));
986                     break;
987                 case 3:
988                     l = (class == LMP_CLASS_LOCAL_INTERFACE_ID) ?
989                         LMPF_VAL_LOCAL_INTERFACE_ID_UNNUM : LMPF_VAL_REMOTE_INTERFACE_ID_UNNUM;
990                     proto_item_append_text(ti, ": Unnumbered %d", tvb_get_ntohl(tvb, offset2));
991                     proto_tree_add_item(lmp_object_tree, lmp_filter[l], tvb, offset2, 4,
992                                         FALSE);
993                     break;
994                 default:
995                     proto_tree_add_text(lmp_object_tree, tvb, offset2, mylen,
996                                         "Data (%d bytes)", mylen);
997                     break;
998                 }
999                 break;
1000
1001             case LMP_CLASS_MESSAGE_ID:
1002             case LMP_CLASS_MESSAGE_ID_ACK:
1003                 switch(type) {
1004                 case 1:
1005                     l = (class == LMP_CLASS_MESSAGE_ID) ?
1006                         LMPF_VAL_MESSAGE_ID : LMPF_VAL_MESSAGE_ID_ACK;
1007                     proto_item_append_text(ti, ": %d", tvb_get_ntohl(tvb, offset2));
1008                     proto_tree_add_uint(lmp_object_tree, lmp_filter[l], tvb, offset2, 4,
1009                                         tvb_get_ntohl(tvb, offset2));
1010                     break;
1011                 default:
1012                     proto_tree_add_text(lmp_object_tree, tvb, offset2, mylen,
1013                                         "Data (%d bytes)", mylen);
1014                     break;
1015                 }
1016                 break;
1017
1018             case LMP_CLASS_CONFIG:
1019                 switch(type) {
1020                 case 1:
1021                     proto_item_append_text(ti, ": HelloInterval: %d, HelloDeadInterval: %d",
1022                                            tvb_get_ntohs(tvb, offset2), tvb_get_ntohs(tvb, offset2+2));
1023                     proto_tree_add_uint(lmp_object_tree, lmp_filter[LMPF_VAL_CONFIG_HELLO],
1024                                         tvb, offset2, 2, tvb_get_ntohs(tvb, offset2));
1025                     proto_tree_add_uint(lmp_object_tree, lmp_filter[LMPF_VAL_CONFIG_HELLO_DEAD],
1026                                         tvb, offset2+2, 2, tvb_get_ntohs(tvb, offset2+2));
1027                     break;
1028                 default:
1029                     proto_tree_add_text(lmp_object_tree, tvb, offset2, mylen,
1030                                         "Data (%d bytes)", mylen);
1031                     break;
1032                 }
1033                 break;
1034
1035             case LMP_CLASS_HELLO:
1036                 switch(type) {
1037                 case 1:
1038                     proto_item_append_text(ti, ": TxSeq %d, RxSeq: %d",
1039                                            tvb_get_ntohl(tvb, offset2),
1040                                            tvb_get_ntohl(tvb, offset2+4));
1041                     proto_tree_add_uint(lmp_object_tree, lmp_filter[LMPF_VAL_HELLO_TXSEQ],
1042                                         tvb, offset2, 4, tvb_get_ntohl(tvb, offset2));
1043                     proto_tree_add_uint(lmp_object_tree, lmp_filter[LMPF_VAL_HELLO_RXSEQ],
1044                                         tvb, offset2+4, 4, tvb_get_ntohl(tvb, offset2+4));
1045                     break;
1046                 default:
1047                     proto_tree_add_text(lmp_object_tree, tvb, offset2, mylen,
1048                                         "Data (%d bytes)", mylen);
1049                     break;
1050                 }
1051                 break;
1052
1053             case LMP_CLASS_BEGIN_VERIFY:
1054                 switch(type) {
1055                 case 1:
1056                     l = tvb_get_ntohs(tvb, offset2);
1057                     ti2 = proto_tree_add_item(lmp_object_tree, lmp_filter[LMPF_VAL_BEGIN_VERIFY_FLAGS],
1058                                               tvb, offset2, 2, FALSE);
1059
1060                     lmp_flags_tree = proto_item_add_subtree(ti2, lmp_subtree[LMP_TREE_BEGIN_VERIFY_FLAGS]);
1061                     proto_tree_add_boolean(lmp_flags_tree, lmp_filter[LMPF_VAL_BEGIN_VERIFY_FLAGS_ALL_LINKS],
1062                                            tvb, offset2, 2, l);
1063                     proto_tree_add_boolean(lmp_flags_tree, lmp_filter[LMPF_VAL_BEGIN_VERIFY_FLAGS_LINK_TYPE],
1064                                            tvb, offset2, 2, l);
1065                     proto_tree_add_text(lmp_object_tree, tvb, offset2+2, 2,
1066                                         "Verify Interval: %d ms", tvb_get_ntohs(tvb, offset2+2));
1067                     proto_tree_add_text(lmp_object_tree, tvb, offset2+4, 4,
1068                                         "Number of Data Links: %d", tvb_get_ntohl(tvb, offset2+4));
1069                     proto_tree_add_item(lmp_object_tree, lmp_filter[LMPF_VAL_BEGIN_VERIFY_ENCTYPE],
1070                                         tvb, offset2+8, 1, FALSE);
1071                     proto_tree_add_text(lmp_object_tree, tvb, offset2+10, 2,
1072                                         "Verify Transport Mechanism: 0x%0x", tvb_get_ntohs(tvb, offset2+10));
1073                     proto_tree_add_text(lmp_object_tree, tvb, offset2+12, 4,
1074                                         "Transmission Rate: %.10g", tvb_get_ntohieee_float(tvb, offset2+12));
1075                     proto_tree_add_text(lmp_object_tree, tvb, offset2+16, 4,
1076                                         "Wavelength: %d", tvb_get_ntohl(tvb, offset2+4));
1077                     break;
1078                 default:
1079                     proto_tree_add_text(lmp_object_tree, tvb, offset2, mylen,
1080                                         "Data (%d bytes)", mylen);
1081                     break;
1082                 }
1083                 break;
1084
1085             case LMP_CLASS_BEGIN_VERIFY_ACK:
1086                 switch(type) {
1087                 case 1:
1088                     proto_item_append_text(ti, ": VerifyDeadInterval: %d, TransportResponse: 0x%0x",
1089                                            tvb_get_ntohs(tvb, offset2), tvb_get_ntohs(tvb, offset2+2));
1090                     proto_tree_add_text(lmp_object_tree, tvb, offset2, 2,
1091                                         "VerifyDeadInterval: %d ms", tvb_get_ntohs(tvb, offset2));
1092                     proto_tree_add_text(lmp_object_tree, tvb, offset2+2, 2,
1093                                         "Verify Transport Response: 0x%0x", tvb_get_ntohs(tvb, offset2+2));
1094                     break;
1095                 default:
1096                     proto_tree_add_text(lmp_object_tree, tvb, offset2, mylen,
1097                                         "Data (%d bytes)", mylen);
1098                     break;
1099                 }
1100                 break;
1101
1102             case LMP_CLASS_VERIFY_ID:
1103                 switch(type) {
1104                 case 1:
1105                     proto_item_append_text(ti, ": %d", tvb_get_ntohl(tvb, offset2));
1106                     proto_tree_add_uint(lmp_object_tree, lmp_filter[LMPF_VAL_VERIFY_ID], tvb, offset2, 4,
1107                                         tvb_get_ntohl(tvb, offset2));
1108                     break;
1109                 default:
1110                     proto_tree_add_text(lmp_object_tree, tvb, offset2, mylen,
1111                                         "Data (%d bytes)", mylen);
1112                     break;
1113                 }
1114                 break;
1115
1116             case LMP_CLASS_TE_LINK:
1117                 l = tvb_get_guint8(tvb, offset2);
1118                 ti2 = proto_tree_add_uint(lmp_object_tree, lmp_filter[LMPF_VAL_TE_LINK_FLAGS],
1119                                           tvb, offset2, 1, l);
1120                 proto_item_append_text(ti2, ": %s%s",
1121                                        (l&0x01) ? "Fault-Mgmt-Supported " : "",
1122                                        (l&0x02) ? "Link-Verification-Supported " : "");
1123                 lmp_flags_tree = proto_item_add_subtree(ti2, lmp_subtree[LMP_TREE_TE_LINK_FLAGS]);
1124                 proto_tree_add_boolean(lmp_flags_tree,
1125                                        lmp_filter[LMPF_VAL_TE_LINK_FLAGS_FAULT_MGMT],
1126                                        tvb, offset2, 1, l);
1127                 proto_tree_add_boolean(lmp_flags_tree,
1128                                        lmp_filter[LMPF_VAL_TE_LINK_FLAGS_LINK_VERIFY],
1129                                        tvb, offset2, 1, l);
1130                 switch(type) {
1131                 case 1:
1132                     proto_item_append_text(ti, ": IPv4: Local %s, Remote %s",
1133                                            ip_to_str(tvb_get_ptr(tvb, offset2+4, 4)),
1134                                            ip_to_str(tvb_get_ptr(tvb, offset2+8, 4)));
1135                     proto_tree_add_item(lmp_object_tree, lmp_filter[LMPF_VAL_TE_LINK_LOCAL_IPV4],
1136                                         tvb, offset2+4, 4, FALSE);
1137                     proto_tree_add_item(lmp_object_tree, lmp_filter[LMPF_VAL_TE_LINK_REMOTE_IPV4],
1138                                         tvb, offset2+8, 4, FALSE);
1139                     break;
1140                 case 2:
1141                     proto_item_append_text(ti, ": IPv6: Local %s, Remote %s",
1142                                            ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset2+4, 16)),
1143                                            ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset2+8, 16)));
1144                     proto_tree_add_text(lmp_object_tree, tvb, offset2+4, 16, "TE-Link Local ID - IPv6: %s",
1145                                         ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset2, 16)));
1146                     proto_tree_add_text(lmp_object_tree, tvb, offset2+20,16, "TE-Link Remote ID - IPv6: %s",
1147                                         ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset2+4, 16)));
1148                     break;
1149                 case 3:
1150                     proto_item_append_text(ti, ": Unnumbered: Local %d, Remote %d",
1151                                            tvb_get_ntohl(tvb, offset2+4), tvb_get_ntohl(tvb, offset2+8));
1152                     proto_tree_add_item(lmp_object_tree, lmp_filter[LMPF_VAL_TE_LINK_LOCAL_UNNUM],
1153                                         tvb, offset2+4, 4, FALSE);
1154                     proto_tree_add_item(lmp_object_tree, lmp_filter[LMPF_VAL_TE_LINK_REMOTE_UNNUM],
1155                                         tvb, offset2+8, 4, FALSE);
1156                     break;
1157                 default:
1158                     proto_tree_add_text(lmp_object_tree, tvb, offset2, mylen,
1159                                         "Data (%d bytes)", mylen);
1160                     break;
1161                 }
1162                 break;
1163
1164             case LMP_CLASS_DATA_LINK:
1165                 l = tvb_get_guint8(tvb, offset2);
1166                 ti2 = proto_tree_add_uint(lmp_object_tree, lmp_filter[LMPF_VAL_DATA_LINK_FLAGS],
1167                                           tvb, offset2, 1, l);
1168                 proto_item_append_text(ti2, ": %s%s",
1169                                        (l&0x01) ? "Interface-Type-Port " : "Interface-Type-Component-Link ",
1170                                        (l&0x02) ? "Allocated " : "Unallocated ");
1171                 lmp_flags_tree = proto_item_add_subtree(ti2, lmp_subtree[LMP_TREE_DATA_LINK_FLAGS]);
1172                 proto_tree_add_boolean(lmp_flags_tree,
1173                                        lmp_filter[LMPF_VAL_DATA_LINK_FLAGS_PORT],
1174                                        tvb, offset2, 1, l);
1175                 proto_tree_add_boolean(lmp_flags_tree,
1176                                        lmp_filter[LMPF_VAL_DATA_LINK_FLAGS_ALLOCATED],
1177                                        tvb, offset2, 1, l);
1178                 switch(type) {
1179                 case 1:
1180                     proto_item_append_text(ti, ": IPv4: Local %s, Remote %s",
1181                                            ip_to_str(tvb_get_ptr(tvb, offset2+4, 4)),
1182                                            ip_to_str(tvb_get_ptr(tvb, offset2+8, 4)));
1183                     proto_tree_add_item(lmp_object_tree, lmp_filter[LMPF_VAL_DATA_LINK_LOCAL_IPV4],
1184                                         tvb, offset2+4, 4, FALSE);
1185                     proto_tree_add_item(lmp_object_tree, lmp_filter[LMPF_VAL_DATA_LINK_REMOTE_IPV4],
1186                                         tvb, offset2+8, 4, FALSE);
1187                     l = 12;
1188                     break;
1189                 case 2:
1190                     proto_item_append_text(ti, ": IPv6: Local %s, Remote %s",
1191                                            ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset2+4, 16)),
1192                                            ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset2+8, 16)));
1193                     proto_tree_add_text(lmp_object_tree, tvb, offset2+4, 16,
1194                                         "Data-Link Local ID - IPv6: %s",
1195                                         ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset2, 16)));
1196                     proto_tree_add_text(lmp_object_tree, tvb, offset2+20,16,
1197                                         "Data-Link Remote ID - IPv6: %s",
1198                                         ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset2+4, 16)));
1199                     l = 36;
1200                     break;
1201                 case 3:
1202                     proto_item_append_text(ti, ": Unnumbered: Local %d, Remote %d",
1203                                            tvb_get_ntohl(tvb, offset2+4), tvb_get_ntohl(tvb, offset2+8));
1204                     proto_tree_add_item(lmp_object_tree, lmp_filter[LMPF_VAL_DATA_LINK_LOCAL_UNNUM],
1205                                         tvb, offset2+4, 4, FALSE);
1206                     proto_tree_add_item(lmp_object_tree, lmp_filter[LMPF_VAL_DATA_LINK_REMOTE_UNNUM],
1207                                         tvb, offset2+8, 4, FALSE);
1208                     l = 12;
1209                     break;
1210                 default:
1211                     proto_tree_add_text(lmp_object_tree, tvb, offset2, mylen,
1212                                         "Data (%d bytes)", mylen);
1213                     break;
1214                 }
1215
1216                 while (l < obj_length - 4) {
1217                     mylen = tvb_get_guint8(tvb, offset2+l+1);
1218                     ti2 = proto_tree_add_item(lmp_object_tree, lmp_filter[LMPF_VAL_DATA_LINK_SUBOBJ],
1219                                               tvb, offset2+l, mylen, FALSE);
1220                     lmp_subobj_tree = proto_item_add_subtree(ti2, lmp_subtree[LMP_TREE_DATA_LINK_SUBOBJ]);
1221                     proto_tree_add_text(lmp_subobj_tree, tvb, offset2+l, 1,
1222                                         "Subobject Type: %d", tvb_get_guint8(tvb, offset2+l));
1223                     proto_tree_add_text(lmp_subobj_tree, tvb, offset2+l+1, 1,
1224                                         "Subobject Length: %d", mylen);
1225                     switch(tvb_get_guint8(tvb, offset2+l)) {
1226                     case 1:
1227                         proto_item_set_text(ti2, "Interface Switching Capability: "
1228                                             "Switching Cap: %s, Encoding Type: %s, Min BW: %.10g, Max BW: %.10g",
1229                                             val_to_str(tvb_get_guint8(tvb, offset2+l+2),
1230                                                        gmpls_switching_type_str, "Unknown (%d)"),
1231                                             val_to_str(tvb_get_guint8(tvb, offset2+l+3),
1232                                                        gmpls_lsp_enc_str, "Unknown (%d)"),
1233                                             tvb_get_ntohieee_float(tvb, offset2+l+4),
1234                                             tvb_get_ntohieee_float(tvb, offset2+l+8));
1235                         proto_tree_add_item(lmp_subobj_tree,
1236                                             lmp_filter[LMPF_VAL_DATA_LINK_SUBOBJ_SWITCHING_TYPE],
1237                                             tvb, offset2+l+2, 1, FALSE);
1238                         proto_tree_add_item(lmp_subobj_tree,
1239                                             lmp_filter[LMPF_VAL_DATA_LINK_SUBOBJ_LSP_ENCODING],
1240                                             tvb, offset2+l+3, 1, FALSE);
1241                         proto_tree_add_text(lmp_subobj_tree, tvb, offset2+l+4, 4,
1242                                             "Minimum Reservable Bandwidth: %.10g bytes/s",
1243                                             tvb_get_ntohieee_float(tvb, offset2+l+4));
1244                         proto_tree_add_text(lmp_subobj_tree, tvb, offset2+l+8, 4,
1245                                             "Maximum Reservable Bandwidth: %.10g bytes/s",
1246                                             tvb_get_ntohieee_float(tvb, offset2+l+8));
1247                         break;
1248
1249                     case 2:
1250                         proto_item_set_text(ti2, "Wavelength: %d",
1251                                             tvb_get_ntohl(tvb, offset2+l+2));
1252                         proto_tree_add_text(lmp_subobj_tree, tvb, offset2+l+4, 4,
1253                                             "Wavelength: %d",
1254                                             tvb_get_ntohl(tvb, offset2+l+2));
1255                         break;
1256
1257                     default:
1258                         proto_tree_add_text(lmp_subobj_tree, tvb, offset2+l,
1259                                             tvb_get_guint8(tvb, offset2+l+1),
1260                                             "Data (%d bytes)", tvb_get_guint8(tvb, offset2+l+1));
1261                         break;
1262                     }
1263                     l += tvb_get_guint8(tvb, offset2+l+1);
1264                 }
1265
1266                 break;
1267
1268             case LMP_CLASS_CHANNEL_STATUS:
1269                 k = 0; j = 0;
1270                 switch(type) {
1271                 case 1:
1272                 case 3:
1273                     k = 8; break;
1274                 case 2:
1275                     k = 20; break;
1276                 }
1277                 if (!k)
1278                     break;
1279                 for (l=0; l<obj_length - 4; ) {
1280                     ti2 = proto_tree_add_text(lmp_object_tree, tvb, offset2+l, k,
1281                                               "Interface-Id");
1282                     lmp_subobj_tree = proto_item_add_subtree(ti2, lmp_subtree[LMP_TREE_CHANNEL_STATUS_ID]);
1283                     switch(type) {
1284                     case 1:
1285                         if (j < 4)
1286                             proto_item_append_text(ti, ": [IPv4-%s",
1287                                                    ip_to_str(tvb_get_ptr(tvb, offset2+l, 4)));
1288                         proto_item_append_text(ti2, ": IPv4 %s",
1289                                                ip_to_str(tvb_get_ptr(tvb, offset2+l, 4)));
1290                         proto_tree_add_text(lmp_subobj_tree, tvb, offset2+l, 4,
1291                                             "Interface ID: IPv4: %s",
1292                                             ip_to_str(tvb_get_ptr(tvb, offset2+l, 4)));
1293                         l += 4;
1294                         break;
1295                     case 2:
1296                         if (j < 4)
1297                             proto_item_append_text(ti, ": [IPv6-%s",
1298                                                    ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset2+l, 16)));
1299                         proto_item_append_text(ti2, ": IPv6 %s",
1300                                                ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset2+l, 16)));
1301                         proto_tree_add_text(lmp_subobj_tree, tvb, offset2, 16, "Interface ID: IPv6: %s",
1302                                             ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset2+l, 16)));
1303                         l += 16;
1304                         break;
1305                     case 3:
1306                         if (j < 4)
1307                             proto_item_append_text(ti, ": [Unnum-%d", tvb_get_ntohl(tvb, offset2+l));
1308                         proto_item_append_text(ti, ": Unnumbered %d", tvb_get_ntohl(tvb, offset2+l));
1309                         proto_tree_add_text(lmp_subobj_tree, tvb, offset2+l, 4,
1310                                             "Interface ID: Unnumbered: %d",
1311                                             tvb_get_ntohl(tvb, offset2+l));
1312                         l += 4;
1313                         break;
1314                     default:
1315                         proto_tree_add_text(lmp_object_tree, tvb, offset2+l, obj_length-4-l,
1316                                             "Data (%d bytes)", obj_length-4-l);
1317                         l = obj_length - 4;
1318                         break;
1319                     }
1320                     if (l == obj_length - 4) break;
1321
1322                     proto_tree_add_text(lmp_subobj_tree, tvb, offset2+l, 1,
1323                                         tvb_get_guint8(tvb, offset2+l) & 0x80 ?
1324                                         "Link Allocated - Active Monitoring" :
1325                                         "Link Not Allocated");
1326                     if (j < 4)
1327                         proto_item_append_text(ti, "-%s,%s], ",
1328                                                tvb_get_guint8(tvb, offset2+l) & 0x80 ? "Act" : "NA",
1329                                                val_to_str(tvb_get_ntohl(tvb, offset2+l) & 0x7fffffff,
1330                                                            channel_status_short_str, "UNK (%u)."));
1331                     proto_item_append_text(ti2, ": %s, ",
1332                                            tvb_get_guint8(tvb, offset2+l) & 0x80 ? "Active" : "Not Active");
1333                     proto_tree_add_text(lmp_subobj_tree, tvb, offset2+l, 4,
1334                                         "Channel Status: %s",
1335                                         val_to_str(tvb_get_ntohl(tvb, offset2+l) & 0x7fffffff,
1336                                                    channel_status_str, "Unknown (%u). "));
1337                     proto_item_append_text(ti2, val_to_str(tvb_get_ntohl(tvb, offset2+l) & 0x7fffffff,
1338                                                            channel_status_str, "Unknown (%u). "));
1339                     j++;
1340                     l += 4;
1341                     if (j==4 && l < obj_length - 4)
1342                         proto_item_append_text(ti, " ...");
1343                 }
1344                 break;
1345
1346             case LMP_CLASS_CHANNEL_STATUS_REQUEST:
1347                 for (l=0; l<obj_length - 4; ) {
1348                     switch(type) {
1349                     case 1:
1350                         proto_tree_add_text(lmp_object_tree, tvb, offset2+l, 4,
1351                                             "Interface ID: IPv4: %s",
1352                                             ip_to_str(tvb_get_ptr(tvb, offset2+l, 4)));
1353                         l += 4;
1354                         break;
1355                     case 2:
1356                         proto_tree_add_text(lmp_object_tree, tvb, offset2+l, 16, "Interface ID: IPv6: %s",
1357                                             ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset2+l,16)));
1358                         l += 16;
1359                         break;
1360                     case 3:
1361                         proto_tree_add_text(lmp_object_tree, tvb, offset2+l, 4,
1362                                             "Interface ID: Unnumbered: %d",
1363                                             tvb_get_ntohl(tvb, offset2+l));
1364                         l += 4;
1365                         break;
1366                     default:
1367                         proto_tree_add_text(lmp_object_tree, tvb, offset2+l, obj_length-4-l,
1368                                             "Data (%d bytes)", obj_length-4-l);
1369                         l = obj_length - 4;
1370                         break;
1371                     }
1372                 }
1373                 break;
1374
1375             case LMP_CLASS_ERROR:
1376                 l = tvb_get_ntohl(tvb, offset2);
1377                 ti2 = proto_tree_add_uint(lmp_object_tree, lmp_filter[LMPF_VAL_ERROR],
1378                                           tvb, offset2, 4, l);
1379
1380                 /* Errors are different in draft-02 and draft-03 */
1381                 switch(lmp_draft_ver) {
1382                 case LMP_VER_DRAFT_CCAMP_02:
1383                     switch(type) {
1384                     case 1:
1385                         proto_item_append_text(ti, ": CONFIG_ERROR: %s%s%s",
1386                                                (l&0x01) ? "Unacceptable-Params " : "",
1387                                                (l&0x02) ? "Renegotiate" : "",
1388                                                (l&0x04) ? "Bad Received CCID" : "");
1389                         lmp_flags_tree = proto_item_add_subtree(ti2, lmp_subtree[LMP_TREE_ERROR_FLAGS]);
1390                         proto_tree_add_boolean(lmp_flags_tree,
1391                                                lmp_filter[LMPF_VAL_ERROR_CONFIG_BAD_PARAMETERS],
1392                                                tvb, offset, 4, l);
1393                         proto_tree_add_boolean(lmp_flags_tree,
1394                                                lmp_filter[LMPF_VAL_ERROR_CONFIG_RENEGOTIATE],
1395                                                tvb, offset, 4, l);
1396                         proto_tree_add_boolean(lmp_flags_tree,
1397                                                lmp_filter[LMPF_VAL_ERROR_CONFIG_BAD_CCID],
1398                                                tvb, offset, 4, l);
1399                         break;
1400                     case 2:
1401                         proto_item_append_text(ti, ": BEGIN_VERIFY_ERROR: %s%s%s%s",
1402                                                (l&0x01) ? "Unsupported-Link " : "",
1403                                                (l&0x02) ? "Unwilling" : "",
1404                                                (l&0x04) ? "Unsupported-Transport" : "",
1405                                                (l&0x08) ? "TE-Link-ID" : "");
1406                         lmp_flags_tree = proto_item_add_subtree(ti2, lmp_subtree[LMP_TREE_ERROR_FLAGS]);
1407                         proto_tree_add_boolean(lmp_flags_tree,
1408                                                lmp_filter[LMPF_VAL_ERROR_VERIFY_UNSUPPORTED_LINK],
1409                                                tvb, offset, 4, l);
1410                         proto_tree_add_boolean(lmp_flags_tree,
1411                                                lmp_filter[LMPF_VAL_ERROR_VERIFY_UNWILLING],
1412                                                tvb, offset, 4, l);
1413                         proto_tree_add_boolean(lmp_flags_tree,
1414                                                lmp_filter[LMPF_VAL_ERROR_VERIFY_TRANSPORT],
1415                                                tvb, offset, 4, l);
1416                         proto_tree_add_boolean(lmp_flags_tree,
1417                                                lmp_filter[LMPF_VAL_ERROR_VERIFY_TE_LINK_ID],
1418                                                tvb, offset, 4, l);
1419                         break;
1420                     case 3:
1421                         proto_item_append_text(ti, ": LINK_SUMMARY_ERROR: %s%s%s",
1422                                                (l&0x01) ? "Unacceptable-Params " : "",
1423                                                (l&0x02) ? "Renegotiate" : "",
1424                                                (l&0x04) ? "Remote-Link-ID" : "");
1425                         lmp_flags_tree = proto_item_add_subtree(ti2, lmp_subtree[LMP_TREE_ERROR_FLAGS]);
1426                         proto_tree_add_boolean(lmp_flags_tree,
1427                                                lmp_filter[LMPF_VAL_ERROR_SUMMARY_BAD_PARAMETERS],
1428                                                tvb, offset, 4, l);
1429                         proto_tree_add_boolean(lmp_flags_tree,
1430                                                lmp_filter[LMPF_VAL_ERROR_SUMMARY_RENEGOTIATE],
1431                                                tvb, offset, 4, l);
1432                         proto_tree_add_boolean(lmp_flags_tree,
1433                                                lmp_filter[LMPF_VAL_ERROR_SUMMARY_BAD_REMOTE_LINK_ID],
1434                                                tvb, offset, 4, l);
1435                         break;
1436                     default:
1437                         proto_item_append_text(ti, ": UNKNOWN_ERROR (%d): 0x%04x", type, l);
1438                         proto_tree_add_text(lmp_object_tree, tvb, offset2, mylen,
1439                                             "Data (%d bytes)", mylen);
1440                         break;
1441                     }
1442                     break;
1443
1444                 default:
1445                 case LMP_VER_DRAFT_CCAMP_03:
1446                     switch(type) {
1447                     case 1:
1448                         proto_item_append_text(ti, ": BEGIN_VERIFY_ERROR: %s%s%s%s",
1449                                                (l&0x01) ? "Unsupported-Link " : "",
1450                                                (l&0x02) ? "Unwilling" : "",
1451                                                (l&0x04) ? "Unsupported-Transport" : "",
1452                                                (l&0x08) ? "TE-Link-ID" : "");
1453                         lmp_flags_tree = proto_item_add_subtree(ti2, lmp_subtree[LMP_TREE_ERROR_FLAGS]);
1454                         proto_tree_add_boolean(lmp_flags_tree,
1455                                                lmp_filter[LMPF_VAL_ERROR_VERIFY_UNSUPPORTED_LINK],
1456                                                tvb, offset, 4, l);
1457                         proto_tree_add_boolean(lmp_flags_tree,
1458                                                lmp_filter[LMPF_VAL_ERROR_VERIFY_UNWILLING],
1459                                                tvb, offset, 4, l);
1460                         proto_tree_add_boolean(lmp_flags_tree,
1461                                                lmp_filter[LMPF_VAL_ERROR_VERIFY_TRANSPORT],
1462                                                tvb, offset, 4, l);
1463                         proto_tree_add_boolean(lmp_flags_tree,
1464                                                lmp_filter[LMPF_VAL_ERROR_VERIFY_TE_LINK_ID],
1465                                                tvb, offset, 4, l);
1466                         break;
1467                     case 2:
1468                         proto_item_append_text(ti, ": LINK_SUMMARY_ERROR: %s%s%s%s%s",
1469                                                (l&0x01) ? "Unacceptable-Params " : "",
1470                                                (l&0x02) ? "Renegotiate" : "",
1471                                                (l&0x04) ? "Remote-Link-ID" : "",
1472                                                (l&0x08) ? "TE-Link" : "",
1473                                                (l&0x10) ? "Data-Link" : "");
1474                         lmp_flags_tree = proto_item_add_subtree(ti2, lmp_subtree[LMP_TREE_ERROR_FLAGS]);
1475                         proto_tree_add_boolean(lmp_flags_tree,
1476                                                lmp_filter[LMPF_VAL_ERROR_SUMMARY_BAD_PARAMETERS],
1477                                                tvb, offset, 4, l);
1478                         proto_tree_add_boolean(lmp_flags_tree,
1479                                                lmp_filter[LMPF_VAL_ERROR_SUMMARY_RENEGOTIATE],
1480                                                tvb, offset, 4, l);
1481                         proto_tree_add_boolean(lmp_flags_tree,
1482                                                lmp_filter[LMPF_VAL_ERROR_SUMMARY_BAD_REMOTE_LINK_ID],
1483                                                tvb, offset, 4, l);
1484                         proto_tree_add_boolean(lmp_flags_tree,
1485                                                lmp_filter[LMPF_VAL_ERROR_SUMMARY_BAD_TE_LINK],
1486                                                tvb, offset, 4, l);
1487                         proto_tree_add_boolean(lmp_flags_tree,
1488                                                lmp_filter[LMPF_VAL_ERROR_SUMMARY_BAD_DATA_LINK],
1489                                                tvb, offset, 4, l);
1490                         break;
1491                     default:
1492                         proto_item_append_text(ti, ": UNKNOWN_ERROR (%d): 0x%04x", type, l);
1493                         proto_tree_add_text(lmp_object_tree, tvb, offset2, mylen,
1494                                             "Data (%d bytes)", mylen);
1495                         break;
1496                     }
1497                     break;
1498                 }
1499                 break;
1500
1501             default :
1502                 proto_tree_add_text(lmp_object_tree, tvb, offset2, mylen,
1503                                     "Data (%d bytes)", mylen);
1504                 break;
1505
1506             }
1507
1508             offset += obj_length;
1509             len += obj_length;
1510         }
1511     }
1512 }
1513
1514 static void
1515 register_lmp_prefs (void)
1516 {
1517     module_t *lmp_module;
1518     static enum_val_t lmp_ver[] = {
1519         {"draft-ietf-ccamp-lmp-03", LMP_VER_DRAFT_CCAMP_03},
1520         {"draft-ietf-ccamp-lmp-02", LMP_VER_DRAFT_CCAMP_02},
1521         {NULL, -1}
1522     };
1523
1524     lmp_module = prefs_register_protocol(proto_lmp, NULL);
1525     prefs_register_enum_preference(
1526         lmp_module, "lmp_version",
1527         "Draft version of LMP",
1528         "Specifies the IETF CCAMP draft version of LMP to interpret",
1529         &lmp_draft_ver, lmp_ver, FALSE);
1530 }
1531
1532 void
1533 proto_register_lmp(void)
1534 {
1535     static gint *ett[NUM_LMP_SUBTREES];
1536     int i;
1537
1538     for (i=0; i<NUM_LMP_SUBTREES; i++) {
1539         lmp_subtree[i] = -1;
1540         ett[i] = &lmp_subtree[i];
1541     }
1542
1543     proto_lmp = proto_register_protocol("Link Management Protocol (LMP)",
1544                                             "LMP", "lmp");
1545     proto_register_field_array(proto_lmp, lmpf_info, array_length(lmpf_info));
1546     proto_register_subtree_array(ett, array_length(ett));
1547
1548     register_lmp_prefs();
1549 }
1550
1551 void
1552 proto_reg_handoff_lmp(void)
1553 {
1554         dissector_handle_t lmp_handle;
1555
1556         lmp_handle = create_dissector_handle(dissect_lmp, proto_lmp);
1557         dissector_add("ip.proto", IP_PROTO_LMP, lmp_handle);
1558 }