print-lmp.c revision 356341
1/*
2 * Redistribution and use in source and binary forms, with or without
3 * modification, are permitted provided that: (1) source code
4 * distributions retain the above copyright notice and this paragraph
5 * in its entirety, and (2) distributions including binary code include
6 * the above copyright notice and this paragraph in its entirety in
7 * the documentation or other materials provided with the distribution.
8 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
9 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
10 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
11 * FOR A PARTICULAR PURPOSE.
12 *
13 * Original code by Hannes Gredler (hannes@gredler.at)
14 * Support for LMP service discovery extensions (defined by OIF UNI 1.0)
15 * added by Manu Pathak (mapathak@cisco.com), May 2005
16 */
17
18/* \summary: Link Management Protocol (LMP) printer */
19
20/* specification: RFC 4204 */
21/* OIF UNI 1.0: http://www.oiforum.com/public/documents/OIF-UNI-01.0.pdf */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include <netdissect-stdinc.h>
28
29#include "netdissect.h"
30#include "extract.h"
31#include "addrtoname.h"
32#include "gmpls.h"
33
34static const char tstr[] = " [|LMP]";
35
36/*
37 * LMP common header
38 *
39 *  0                   1                   2                   3
40 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
41 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 * | Vers  |      (Reserved)       |    Flags      |    Msg Type   |
43 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 * |          LMP Length           |          (Reserved)           |
45 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46 */
47
48struct lmp_common_header {
49    uint8_t version_res[2];
50    uint8_t flags;
51    uint8_t msg_type;
52    uint8_t length[2];
53    uint8_t reserved[2];
54};
55
56#define LMP_VERSION            1
57#define	LMP_EXTRACT_VERSION(x) (((x)&0xf0)>>4)
58
59static const struct tok lmp_header_flag_values[] = {
60    { 0x01, "Control Channel Down"},
61    { 0x02, "LMP restart"},
62    { 0, NULL}
63};
64
65static const struct tok lmp_obj_te_link_flag_values[] = {
66    { 0x01, "Fault Management Supported"},
67    { 0x02, "Link Verification Supported"},
68    { 0, NULL}
69};
70
71static const struct tok lmp_obj_data_link_flag_values[] = {
72    { 0x01, "Data Link Port"},
73    { 0x02, "Allocated for user traffic"},
74    { 0x04, "Failed link"},
75    { 0, NULL}
76};
77
78static const struct tok lmp_obj_channel_status_values[] = {
79    { 1, "Signal Okay"},
80    { 2, "Signal Degraded"},
81    { 3, "Signal Fail"},
82    { 0, NULL}
83};
84
85static const struct tok lmp_obj_begin_verify_flag_values[] = {
86    { 0x0001, "Verify all links"},
87    { 0x0002, "Data link type"},
88    { 0, NULL}
89};
90
91static const struct tok lmp_obj_begin_verify_error_values[] = {
92    { 0x01, "Link Verification Procedure Not supported"},
93    { 0x02, "Unwilling to verify"},
94    { 0x04, "Unsupported verification transport mechanism"},
95    { 0x08, "Link-Id configuration error"},
96    { 0x10, "Unknown object c-type"},
97    { 0, NULL}
98};
99
100static const struct tok lmp_obj_link_summary_error_values[] = {
101    { 0x01, "Unacceptable non-negotiable LINK-SUMMARY parameters"},
102    { 0x02, "Renegotiate LINK-SUMMARY parameters"},
103    { 0x04, "Invalid TE-LINK Object"},
104    { 0x08, "Invalid DATA-LINK Object"},
105    { 0x10, "Unknown TE-LINK Object c-type"},
106    { 0x20, "Unknown DATA-LINK Object c-type"},
107    { 0, NULL}
108};
109
110/* Service Config Supported Protocols Flags */
111static const struct tok lmp_obj_service_config_sp_flag_values[] = {
112    { 0x01, "RSVP Supported"},
113    { 0x02, "LDP Supported"},
114    { 0, NULL}
115};
116
117/* Service Config Client Port Service Attribute Transparency Flags */
118static const struct tok lmp_obj_service_config_cpsa_tp_flag_values[] = {
119    { 0x01, "Path/VC Overhead Transparency Supported"},
120    { 0x02, "Line/MS Overhead Transparency Supported"},
121    { 0x04, "Section/RS Overhead Transparency Supported"},
122    { 0, NULL}
123};
124
125/* Service Config Client Port Service Attribute Contiguous Concatenation Types Flags */
126static const struct tok lmp_obj_service_config_cpsa_cct_flag_values[] = {
127    { 0x01, "Contiguous Concatenation Types Supported"},
128    { 0, NULL}
129};
130
131/* Service Config Network Service Attributes Transparency Flags */
132static const struct tok lmp_obj_service_config_nsa_transparency_flag_values[] = {
133    { 0x01, "Standard SOH/RSOH Transparency Supported"},
134    { 0x02, "Standard LOH/MSOH Transparency Supported"},
135    { 0, NULL}
136};
137
138/* Service Config Network Service Attributes TCM Monitoring Flags */
139static const struct tok lmp_obj_service_config_nsa_tcm_flag_values[] = {
140    { 0x01, "Transparent Tandem Connection Monitoring Supported"},
141    { 0, NULL}
142};
143
144/* Network Service Attributes Network Diversity Flags */
145static const struct tok lmp_obj_service_config_nsa_network_diversity_flag_values[] = {
146    { 0x01, "Node Diversity Supported"},
147    { 0x02, "Link Diversity Supported"},
148    { 0x04, "SRLG Diversity Supported"},
149    { 0, NULL}
150};
151
152#define	LMP_MSGTYPE_CONFIG                 1
153#define	LMP_MSGTYPE_CONFIG_ACK             2
154#define	LMP_MSGTYPE_CONFIG_NACK            3
155#define	LMP_MSGTYPE_HELLO                  4
156#define	LMP_MSGTYPE_VERIFY_BEGIN           5
157#define	LMP_MSGTYPE_VERIFY_BEGIN_ACK       6
158#define	LMP_MSGTYPE_VERIFY_BEGIN_NACK      7
159#define LMP_MSGTYPE_VERIFY_END             8
160#define LMP_MSGTYPE_VERIFY_END_ACK         9
161#define LMP_MSGTYPE_TEST                  10
162#define LMP_MSGTYPE_TEST_STATUS_SUCCESS   11
163#define	LMP_MSGTYPE_TEST_STATUS_FAILURE   12
164#define	LMP_MSGTYPE_TEST_STATUS_ACK       13
165#define	LMP_MSGTYPE_LINK_SUMMARY          14
166#define	LMP_MSGTYPE_LINK_SUMMARY_ACK      15
167#define	LMP_MSGTYPE_LINK_SUMMARY_NACK     16
168#define	LMP_MSGTYPE_CHANNEL_STATUS        17
169#define	LMP_MSGTYPE_CHANNEL_STATUS_ACK    18
170#define	LMP_MSGTYPE_CHANNEL_STATUS_REQ    19
171#define	LMP_MSGTYPE_CHANNEL_STATUS_RESP   20
172/* LMP Service Discovery message types defined by UNI 1.0 */
173#define LMP_MSGTYPE_SERVICE_CONFIG        50
174#define LMP_MSGTYPE_SERVICE_CONFIG_ACK    51
175#define LMP_MSGTYPE_SERVICE_CONFIG_NACK   52
176
177static const struct tok lmp_msg_type_values[] = {
178    { LMP_MSGTYPE_CONFIG, "Config"},
179    { LMP_MSGTYPE_CONFIG_ACK, "Config ACK"},
180    { LMP_MSGTYPE_CONFIG_NACK, "Config NACK"},
181    { LMP_MSGTYPE_HELLO, "Hello"},
182    { LMP_MSGTYPE_VERIFY_BEGIN, "Begin Verify"},
183    { LMP_MSGTYPE_VERIFY_BEGIN_ACK, "Begin Verify ACK"},
184    { LMP_MSGTYPE_VERIFY_BEGIN_NACK, "Begin Verify NACK"},
185    { LMP_MSGTYPE_VERIFY_END, "End Verify"},
186    { LMP_MSGTYPE_VERIFY_END_ACK, "End Verify ACK"},
187    { LMP_MSGTYPE_TEST, "Test"},
188    { LMP_MSGTYPE_TEST_STATUS_SUCCESS, "Test Status Success"},
189    { LMP_MSGTYPE_TEST_STATUS_FAILURE, "Test Status Failure"},
190    { LMP_MSGTYPE_TEST_STATUS_ACK, "Test Status ACK"},
191    { LMP_MSGTYPE_LINK_SUMMARY, "Link Summary"},
192    { LMP_MSGTYPE_LINK_SUMMARY_ACK, "Link Summary ACK"},
193    { LMP_MSGTYPE_LINK_SUMMARY_NACK, "Link Summary NACK"},
194    { LMP_MSGTYPE_CHANNEL_STATUS, "Channel Status"},
195    { LMP_MSGTYPE_CHANNEL_STATUS_ACK, "Channel Status ACK"},
196    { LMP_MSGTYPE_CHANNEL_STATUS_REQ, "Channel Status Request"},
197    { LMP_MSGTYPE_CHANNEL_STATUS_RESP, "Channel Status Response"},
198    { LMP_MSGTYPE_SERVICE_CONFIG, "Service Config"},
199    { LMP_MSGTYPE_SERVICE_CONFIG_ACK, "Service Config ACK"},
200    { LMP_MSGTYPE_SERVICE_CONFIG_NACK, "Service Config NACK"},
201    { 0, NULL}
202};
203
204/*
205 * LMP object header
206 *
207 *  0                   1                   2                   3
208 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
209 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
210 * |N|   C-Type    |     Class     |            Length             |
211 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
212 * |                                                               |
213 * //                       (object contents)                     //
214 * |                                                               |
215 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
216 */
217
218struct lmp_object_header {
219    uint8_t ctype;
220    uint8_t class_num;
221    uint8_t length[2];
222};
223
224#define	LMP_OBJ_CC_ID                 1
225#define	LMP_OBJ_NODE_ID               2
226#define	LMP_OBJ_LINK_ID               3
227#define	LMP_OBJ_INTERFACE_ID          4
228#define	LMP_OBJ_MESSAGE_ID            5
229#define	LMP_OBJ_CONFIG                6
230#define	LMP_OBJ_HELLO                 7
231#define	LMP_OBJ_VERIFY_BEGIN          8
232#define LMP_OBJ_VERIFY_BEGIN_ACK      9
233#define LMP_OBJ_VERIFY_ID            10
234#define LMP_OBJ_TE_LINK              11
235#define LMP_OBJ_DATA_LINK            12
236#define LMP_OBJ_CHANNEL_STATUS       13
237#define LMP_OBJ_CHANNEL_STATUS_REQ   14
238#define LMP_OBJ_ERROR_CODE           20
239
240#define LMP_OBJ_SERVICE_CONFIG       51 /* defined in UNI 1.0 */
241
242static const struct tok lmp_obj_values[] = {
243    { LMP_OBJ_CC_ID, "Control Channel ID" },
244    { LMP_OBJ_NODE_ID, "Node ID" },
245    { LMP_OBJ_LINK_ID, "Link ID" },
246    { LMP_OBJ_INTERFACE_ID, "Interface ID" },
247    { LMP_OBJ_MESSAGE_ID, "Message ID" },
248    { LMP_OBJ_CONFIG, "Configuration" },
249    { LMP_OBJ_HELLO, "Hello" },
250    { LMP_OBJ_VERIFY_BEGIN, "Verify Begin" },
251    { LMP_OBJ_VERIFY_BEGIN_ACK, "Verify Begin ACK" },
252    { LMP_OBJ_VERIFY_ID, "Verify ID" },
253    { LMP_OBJ_TE_LINK, "TE Link" },
254    { LMP_OBJ_DATA_LINK, "Data Link" },
255    { LMP_OBJ_CHANNEL_STATUS, "Channel Status" },
256    { LMP_OBJ_CHANNEL_STATUS_REQ, "Channel Status Request" },
257    { LMP_OBJ_ERROR_CODE, "Error Code" },
258    { LMP_OBJ_SERVICE_CONFIG, "Service Config" },
259
260    { 0, NULL}
261};
262
263#define INT_SWITCHING_TYPE_SUBOBJ 1
264#define WAVELENGTH_SUBOBJ         2
265
266static const struct tok lmp_data_link_subobj[] = {
267    { INT_SWITCHING_TYPE_SUBOBJ, "Interface Switching Type" },
268    { WAVELENGTH_SUBOBJ        , "Wavelength" },
269    { 0, NULL}
270};
271
272#define	LMP_CTYPE_IPV4       1
273#define	LMP_CTYPE_IPV6       2
274
275#define	LMP_CTYPE_LOC        1
276#define	LMP_CTYPE_RMT        2
277#define	LMP_CTYPE_UNMD       3
278
279#define	LMP_CTYPE_IPV4_LOC   1
280#define	LMP_CTYPE_IPV4_RMT   2
281#define	LMP_CTYPE_IPV6_LOC   3
282#define	LMP_CTYPE_IPV6_RMT   4
283#define	LMP_CTYPE_UNMD_LOC   5
284#define	LMP_CTYPE_UNMD_RMT   6
285
286#define	LMP_CTYPE_1          1
287#define	LMP_CTYPE_2          2
288
289#define LMP_CTYPE_HELLO_CONFIG  1
290#define LMP_CTYPE_HELLO         1
291
292#define LMP_CTYPE_BEGIN_VERIFY_ERROR 1
293#define LMP_CTYPE_LINK_SUMMARY_ERROR 2
294
295/* C-Types for Service Config Object */
296#define LMP_CTYPE_SERVICE_CONFIG_SP                   1
297#define LMP_CTYPE_SERVICE_CONFIG_CPSA                 2
298#define LMP_CTYPE_SERVICE_CONFIG_TRANSPARENCY_TCM     3
299#define LMP_CTYPE_SERVICE_CONFIG_NETWORK_DIVERSITY    4
300
301/*
302 * Different link types allowed in the Client Port Service Attributes
303 * subobject defined for LMP Service Discovery in the UNI 1.0 spec
304 */
305#define LMP_SD_SERVICE_CONFIG_CPSA_LINK_TYPE_SDH     5 /* UNI 1.0 Sec 9.4.2 */
306#define LMP_SD_SERVICE_CONFIG_CPSA_LINK_TYPE_SONET   6 /* UNI 1.0 Sec 9.4.2 */
307
308/*
309 * the ctypes are not globally unique so for
310 * translating it to strings we build a table based
311 * on objects offsetted by the ctype
312 */
313
314static const struct tok lmp_ctype_values[] = {
315    { 256*LMP_OBJ_CC_ID+LMP_CTYPE_LOC, "Local" },
316    { 256*LMP_OBJ_CC_ID+LMP_CTYPE_RMT, "Remote" },
317    { 256*LMP_OBJ_NODE_ID+LMP_CTYPE_LOC, "Local" },
318    { 256*LMP_OBJ_NODE_ID+LMP_CTYPE_RMT, "Remote" },
319    { 256*LMP_OBJ_LINK_ID+LMP_CTYPE_IPV4_LOC, "IPv4 Local" },
320    { 256*LMP_OBJ_LINK_ID+LMP_CTYPE_IPV4_RMT, "IPv4 Remote" },
321    { 256*LMP_OBJ_LINK_ID+LMP_CTYPE_IPV6_LOC, "IPv6 Local" },
322    { 256*LMP_OBJ_LINK_ID+LMP_CTYPE_IPV6_RMT, "IPv6 Remote" },
323    { 256*LMP_OBJ_LINK_ID+LMP_CTYPE_UNMD_LOC, "Unnumbered Local" },
324    { 256*LMP_OBJ_LINK_ID+LMP_CTYPE_UNMD_RMT, "Unnumbered Remote" },
325    { 256*LMP_OBJ_INTERFACE_ID+LMP_CTYPE_IPV4_LOC, "IPv4 Local" },
326    { 256*LMP_OBJ_INTERFACE_ID+LMP_CTYPE_IPV4_RMT, "IPv4 Remote" },
327    { 256*LMP_OBJ_INTERFACE_ID+LMP_CTYPE_IPV6_LOC, "IPv6 Local" },
328    { 256*LMP_OBJ_INTERFACE_ID+LMP_CTYPE_IPV6_RMT, "IPv6 Remote" },
329    { 256*LMP_OBJ_INTERFACE_ID+LMP_CTYPE_UNMD_LOC, "Unnumbered Local" },
330    { 256*LMP_OBJ_INTERFACE_ID+LMP_CTYPE_UNMD_RMT, "Unnumbered Remote" },
331    { 256*LMP_OBJ_MESSAGE_ID+LMP_CTYPE_1, "1" },
332    { 256*LMP_OBJ_MESSAGE_ID+LMP_CTYPE_2, "2" },
333    { 256*LMP_OBJ_CONFIG+LMP_CTYPE_1, "1" },
334    { 256*LMP_OBJ_HELLO+LMP_CTYPE_1, "1" },
335    { 256*LMP_OBJ_VERIFY_BEGIN+LMP_CTYPE_1, "1" },
336    { 256*LMP_OBJ_VERIFY_BEGIN_ACK+LMP_CTYPE_1, "1" },
337    { 256*LMP_OBJ_VERIFY_ID+LMP_CTYPE_1, "1" },
338    { 256*LMP_OBJ_TE_LINK+LMP_CTYPE_IPV4, "IPv4" },
339    { 256*LMP_OBJ_TE_LINK+LMP_CTYPE_IPV6, "IPv6" },
340    { 256*LMP_OBJ_TE_LINK+LMP_CTYPE_UNMD, "Unnumbered" },
341    { 256*LMP_OBJ_DATA_LINK+LMP_CTYPE_IPV4, "IPv4" },
342    { 256*LMP_OBJ_DATA_LINK+LMP_CTYPE_IPV6, "IPv6" },
343    { 256*LMP_OBJ_DATA_LINK+LMP_CTYPE_UNMD, "Unnumbered" },
344    { 256*LMP_OBJ_CHANNEL_STATUS+LMP_CTYPE_IPV4, "IPv4" },
345    { 256*LMP_OBJ_CHANNEL_STATUS+LMP_CTYPE_IPV6, "IPv6" },
346    { 256*LMP_OBJ_CHANNEL_STATUS+LMP_CTYPE_UNMD, "Unnumbered" },
347    { 256*LMP_OBJ_CHANNEL_STATUS_REQ+LMP_CTYPE_IPV4, "IPv4" },
348    { 256*LMP_OBJ_CHANNEL_STATUS_REQ+LMP_CTYPE_IPV6, "IPv6" },
349    { 256*LMP_OBJ_CHANNEL_STATUS_REQ+LMP_CTYPE_UNMD, "Unnumbered" },
350    { 256*LMP_OBJ_ERROR_CODE+LMP_CTYPE_1, "1" },
351    { 256*LMP_OBJ_ERROR_CODE+LMP_CTYPE_2, "2" },
352    { 256*LMP_OBJ_SERVICE_CONFIG+LMP_CTYPE_SERVICE_CONFIG_SP, "1" },
353    { 256*LMP_OBJ_SERVICE_CONFIG+LMP_CTYPE_SERVICE_CONFIG_CPSA, "2" },
354    { 256*LMP_OBJ_SERVICE_CONFIG+LMP_CTYPE_SERVICE_CONFIG_TRANSPARENCY_TCM, "3" },
355    { 256*LMP_OBJ_SERVICE_CONFIG+LMP_CTYPE_SERVICE_CONFIG_NETWORK_DIVERSITY, "4" },
356    { 0, NULL}
357};
358
359static int
360lmp_print_data_link_subobjs(netdissect_options *ndo, const u_char *obj_tptr,
361                            int total_subobj_len, int offset)
362{
363    int hexdump = FALSE;
364    int subobj_type, subobj_len;
365
366    union { /* int to float conversion buffer */
367        float f;
368        uint32_t i;
369    } bw;
370
371    while (total_subobj_len > 0 && hexdump == FALSE ) {
372	ND_TCHECK_16BITS(obj_tptr + offset);
373	subobj_type = EXTRACT_8BITS(obj_tptr + offset);
374	subobj_len  = EXTRACT_8BITS(obj_tptr + offset + 1);
375	ND_PRINT((ndo, "\n\t    Subobject, Type: %s (%u), Length: %u",
376		tok2str(lmp_data_link_subobj,
377			"Unknown",
378			subobj_type),
379			subobj_type,
380			subobj_len));
381	if (subobj_len < 4) {
382	    ND_PRINT((ndo, " (too short)"));
383	    break;
384	}
385	if ((subobj_len % 4) != 0) {
386	    ND_PRINT((ndo, " (not a multiple of 4)"));
387	    break;
388	}
389	if (total_subobj_len < subobj_len) {
390	    ND_PRINT((ndo, " (goes past the end of the object)"));
391	    break;
392	}
393	switch(subobj_type) {
394	case INT_SWITCHING_TYPE_SUBOBJ:
395	    ND_TCHECK_8BITS(obj_tptr + offset + 2);
396	    ND_PRINT((ndo, "\n\t      Switching Type: %s (%u)",
397		tok2str(gmpls_switch_cap_values,
398			"Unknown",
399			EXTRACT_8BITS(obj_tptr + offset + 2)),
400			EXTRACT_8BITS(obj_tptr + offset + 2)));
401	    ND_TCHECK_8BITS(obj_tptr + offset + 3);
402	    ND_PRINT((ndo, "\n\t      Encoding Type: %s (%u)",
403		tok2str(gmpls_encoding_values,
404			"Unknown",
405			EXTRACT_8BITS(obj_tptr + offset + 3)),
406			EXTRACT_8BITS(obj_tptr + offset + 3)));
407	    ND_TCHECK_32BITS(obj_tptr + offset + 4);
408	    bw.i = EXTRACT_32BITS(obj_tptr+offset+4);
409	    ND_PRINT((ndo, "\n\t      Min Reservable Bandwidth: %.3f Mbps",
410                bw.f*8/1000000));
411	    ND_TCHECK_32BITS(obj_tptr + offset + 8);
412	    bw.i = EXTRACT_32BITS(obj_tptr+offset+8);
413	    ND_PRINT((ndo, "\n\t      Max Reservable Bandwidth: %.3f Mbps",
414                bw.f*8/1000000));
415	    break;
416	case WAVELENGTH_SUBOBJ:
417	    ND_TCHECK_32BITS(obj_tptr + offset + 4);
418	    ND_PRINT((ndo, "\n\t      Wavelength: %u",
419		EXTRACT_32BITS(obj_tptr+offset+4)));
420	    break;
421	default:
422	    /* Any Unknown Subobject ==> Exit loop */
423	    hexdump=TRUE;
424	    break;
425	}
426	total_subobj_len-=subobj_len;
427	offset+=subobj_len;
428    }
429    return (hexdump);
430trunc:
431    return -1;
432}
433
434void
435lmp_print(netdissect_options *ndo,
436          register const u_char *pptr, register u_int len)
437{
438    const struct lmp_common_header *lmp_com_header;
439    const struct lmp_object_header *lmp_obj_header;
440    const u_char *tptr,*obj_tptr;
441    u_int tlen,lmp_obj_len,lmp_obj_ctype,obj_tlen;
442    int hexdump, ret;
443    u_int offset;
444    u_int link_type;
445
446    union { /* int to float conversion buffer */
447        float f;
448        uint32_t i;
449    } bw;
450
451    tptr=pptr;
452    lmp_com_header = (const struct lmp_common_header *)pptr;
453    ND_TCHECK(*lmp_com_header);
454
455    /*
456     * Sanity checking of the header.
457     */
458    if (LMP_EXTRACT_VERSION(lmp_com_header->version_res[0]) != LMP_VERSION) {
459	ND_PRINT((ndo, "LMP version %u packet not supported",
460               LMP_EXTRACT_VERSION(lmp_com_header->version_res[0])));
461	return;
462    }
463
464    /* in non-verbose mode just lets print the basic Message Type*/
465    if (ndo->ndo_vflag < 1) {
466        ND_PRINT((ndo, "LMPv%u %s Message, length: %u",
467               LMP_EXTRACT_VERSION(lmp_com_header->version_res[0]),
468               tok2str(lmp_msg_type_values, "unknown (%u)",lmp_com_header->msg_type),
469               len));
470        return;
471    }
472
473    /* ok they seem to want to know everything - lets fully decode it */
474
475    tlen=EXTRACT_16BITS(lmp_com_header->length);
476
477    ND_PRINT((ndo, "\n\tLMPv%u, msg-type: %s, Flags: [%s], length: %u",
478           LMP_EXTRACT_VERSION(lmp_com_header->version_res[0]),
479           tok2str(lmp_msg_type_values, "unknown, type: %u",lmp_com_header->msg_type),
480           bittok2str(lmp_header_flag_values,"none",lmp_com_header->flags),
481           tlen));
482    if (tlen < sizeof(const struct lmp_common_header)) {
483        ND_PRINT((ndo, " (too short)"));
484        return;
485    }
486    if (tlen > len) {
487        ND_PRINT((ndo, " (too long)"));
488        tlen = len;
489    }
490
491    tptr+=sizeof(const struct lmp_common_header);
492    tlen-=sizeof(const struct lmp_common_header);
493
494    while(tlen>0) {
495        /* did we capture enough for fully decoding the object header ? */
496        ND_TCHECK2(*tptr, sizeof(struct lmp_object_header));
497
498        lmp_obj_header = (const struct lmp_object_header *)tptr;
499        lmp_obj_len=EXTRACT_16BITS(lmp_obj_header->length);
500        lmp_obj_ctype=(lmp_obj_header->ctype)&0x7f;
501
502        ND_PRINT((ndo, "\n\t  %s Object (%u), Class-Type: %s (%u) Flags: [%snegotiable], length: %u",
503               tok2str(lmp_obj_values,
504                       "Unknown",
505                       lmp_obj_header->class_num),
506               lmp_obj_header->class_num,
507               tok2str(lmp_ctype_values,
508                       "Unknown",
509                       ((lmp_obj_header->class_num)<<8)+lmp_obj_ctype),
510               lmp_obj_ctype,
511               (lmp_obj_header->ctype)&0x80 ? "" : "non-",
512               lmp_obj_len));
513
514        if (lmp_obj_len < 4) {
515            ND_PRINT((ndo, " (too short)"));
516            return;
517        }
518        if ((lmp_obj_len % 4) != 0) {
519            ND_PRINT((ndo, " (not a multiple of 4)"));
520            return;
521        }
522
523        obj_tptr=tptr+sizeof(struct lmp_object_header);
524        obj_tlen=lmp_obj_len-sizeof(struct lmp_object_header);
525
526        /* did we capture enough for fully decoding the object ? */
527        ND_TCHECK2(*tptr, lmp_obj_len);
528        hexdump=FALSE;
529
530        switch(lmp_obj_header->class_num) {
531
532        case LMP_OBJ_CC_ID:
533            switch(lmp_obj_ctype) {
534            case LMP_CTYPE_LOC:
535            case LMP_CTYPE_RMT:
536                if (obj_tlen != 4) {
537                    ND_PRINT((ndo, " (not correct for object)"));
538                    break;
539                }
540                ND_PRINT((ndo, "\n\t    Control Channel ID: %u (0x%08x)",
541                       EXTRACT_32BITS(obj_tptr),
542                       EXTRACT_32BITS(obj_tptr)));
543                break;
544
545            default:
546                hexdump=TRUE;
547            }
548            break;
549
550        case LMP_OBJ_LINK_ID:
551        case LMP_OBJ_INTERFACE_ID:
552            switch(lmp_obj_ctype) {
553            case LMP_CTYPE_IPV4_LOC:
554            case LMP_CTYPE_IPV4_RMT:
555                if (obj_tlen != 4) {
556                    ND_PRINT((ndo, " (not correct for object)"));
557                    break;
558                }
559                ND_PRINT((ndo, "\n\t    IPv4 Link ID: %s (0x%08x)",
560                       ipaddr_string(ndo, obj_tptr),
561                       EXTRACT_32BITS(obj_tptr)));
562                break;
563            case LMP_CTYPE_IPV6_LOC:
564            case LMP_CTYPE_IPV6_RMT:
565                if (obj_tlen != 16) {
566                    ND_PRINT((ndo, " (not correct for object)"));
567                    break;
568                }
569                ND_PRINT((ndo, "\n\t    IPv6 Link ID: %s (0x%08x)",
570                       ip6addr_string(ndo, obj_tptr),
571                       EXTRACT_32BITS(obj_tptr)));
572                break;
573            case LMP_CTYPE_UNMD_LOC:
574            case LMP_CTYPE_UNMD_RMT:
575                if (obj_tlen != 4) {
576                    ND_PRINT((ndo, " (not correct for object)"));
577                    break;
578                }
579                ND_PRINT((ndo, "\n\t    Link ID: %u (0x%08x)",
580                       EXTRACT_32BITS(obj_tptr),
581                       EXTRACT_32BITS(obj_tptr)));
582                break;
583            default:
584                hexdump=TRUE;
585            }
586            break;
587
588        case LMP_OBJ_MESSAGE_ID:
589            switch(lmp_obj_ctype) {
590            case LMP_CTYPE_1:
591                if (obj_tlen != 4) {
592                    ND_PRINT((ndo, " (not correct for object)"));
593                    break;
594                }
595                ND_PRINT((ndo, "\n\t    Message ID: %u (0x%08x)",
596                       EXTRACT_32BITS(obj_tptr),
597                       EXTRACT_32BITS(obj_tptr)));
598                break;
599            case LMP_CTYPE_2:
600                if (obj_tlen != 4) {
601                    ND_PRINT((ndo, " (not correct for object)"));
602                    break;
603                }
604                ND_PRINT((ndo, "\n\t    Message ID Ack: %u (0x%08x)",
605                       EXTRACT_32BITS(obj_tptr),
606                       EXTRACT_32BITS(obj_tptr)));
607                break;
608            default:
609                hexdump=TRUE;
610            }
611            break;
612
613        case LMP_OBJ_NODE_ID:
614            switch(lmp_obj_ctype) {
615            case LMP_CTYPE_LOC:
616            case LMP_CTYPE_RMT:
617                if (obj_tlen != 4) {
618                    ND_PRINT((ndo, " (not correct for object)"));
619                    break;
620                }
621                ND_PRINT((ndo, "\n\t    Node ID: %s (0x%08x)",
622                       ipaddr_string(ndo, obj_tptr),
623                       EXTRACT_32BITS(obj_tptr)));
624                break;
625
626            default:
627                hexdump=TRUE;
628            }
629            break;
630
631        case LMP_OBJ_CONFIG:
632            switch(lmp_obj_ctype) {
633            case LMP_CTYPE_HELLO_CONFIG:
634                if (obj_tlen != 4) {
635                    ND_PRINT((ndo, " (not correct for object)"));
636                    break;
637                }
638                ND_PRINT((ndo, "\n\t    Hello Interval: %u\n\t    Hello Dead Interval: %u",
639                       EXTRACT_16BITS(obj_tptr),
640                       EXTRACT_16BITS(obj_tptr+2)));
641                break;
642
643            default:
644                hexdump=TRUE;
645            }
646            break;
647
648        case LMP_OBJ_HELLO:
649            switch(lmp_obj_ctype) {
650	    case LMP_CTYPE_HELLO:
651                if (obj_tlen != 8) {
652                    ND_PRINT((ndo, " (not correct for object)"));
653                    break;
654                }
655                ND_PRINT((ndo, "\n\t    Tx Seq: %u, Rx Seq: %u",
656                       EXTRACT_32BITS(obj_tptr),
657                       EXTRACT_32BITS(obj_tptr+4)));
658                break;
659
660            default:
661                hexdump=TRUE;
662            }
663            break;
664
665        case LMP_OBJ_TE_LINK:
666	    switch(lmp_obj_ctype) {
667	    case LMP_CTYPE_IPV4:
668                if (obj_tlen != 12) {
669                    ND_PRINT((ndo, " (not correct for object)"));
670                    break;
671                }
672		ND_PRINT((ndo, "\n\t    Flags: [%s]",
673		    bittok2str(lmp_obj_te_link_flag_values,
674			"none",
675			EXTRACT_8BITS(obj_tptr))));
676
677		ND_PRINT((ndo, "\n\t    Local Link-ID: %s (0x%08x)"
678		       "\n\t    Remote Link-ID: %s (0x%08x)",
679                       ipaddr_string(ndo, obj_tptr+4),
680                       EXTRACT_32BITS(obj_tptr+4),
681                       ipaddr_string(ndo, obj_tptr+8),
682                       EXTRACT_32BITS(obj_tptr+8)));
683		break;
684
685	    case LMP_CTYPE_IPV6:
686                if (obj_tlen != 36) {
687                    ND_PRINT((ndo, " (not correct for object)"));
688                    break;
689                }
690		ND_PRINT((ndo, "\n\t    Flags: [%s]",
691		    bittok2str(lmp_obj_te_link_flag_values,
692			"none",
693			EXTRACT_8BITS(obj_tptr))));
694
695		ND_PRINT((ndo, "\n\t    Local Link-ID: %s (0x%08x)"
696		       "\n\t    Remote Link-ID: %s (0x%08x)",
697                       ip6addr_string(ndo, obj_tptr+4),
698                       EXTRACT_32BITS(obj_tptr+4),
699                       ip6addr_string(ndo, obj_tptr+20),
700                       EXTRACT_32BITS(obj_tptr+20)));
701                break;
702
703	    case LMP_CTYPE_UNMD:
704                if (obj_tlen != 12) {
705                    ND_PRINT((ndo, " (not correct for object)"));
706                    break;
707                }
708		ND_PRINT((ndo, "\n\t    Flags: [%s]",
709		    bittok2str(lmp_obj_te_link_flag_values,
710			"none",
711			EXTRACT_8BITS(obj_tptr))));
712
713		ND_PRINT((ndo, "\n\t    Local Link-ID: %u (0x%08x)"
714		       "\n\t    Remote Link-ID: %u (0x%08x)",
715                       EXTRACT_32BITS(obj_tptr+4),
716                       EXTRACT_32BITS(obj_tptr+4),
717                       EXTRACT_32BITS(obj_tptr+8),
718                       EXTRACT_32BITS(obj_tptr+8)));
719		break;
720
721            default:
722                hexdump=TRUE;
723            }
724            break;
725
726        case LMP_OBJ_DATA_LINK:
727	    switch(lmp_obj_ctype) {
728	    case LMP_CTYPE_IPV4:
729                if (obj_tlen < 12) {
730                    ND_PRINT((ndo, " (not correct for object)"));
731                    break;
732                }
733	        ND_PRINT((ndo, "\n\t    Flags: [%s]",
734		    bittok2str(lmp_obj_data_link_flag_values,
735			"none",
736			EXTRACT_8BITS(obj_tptr))));
737                ND_PRINT((ndo, "\n\t    Local Interface ID: %s (0x%08x)"
738                       "\n\t    Remote Interface ID: %s (0x%08x)",
739                       ipaddr_string(ndo, obj_tptr+4),
740                       EXTRACT_32BITS(obj_tptr+4),
741                       ipaddr_string(ndo, obj_tptr+8),
742                       EXTRACT_32BITS(obj_tptr+8)));
743
744		ret = lmp_print_data_link_subobjs(ndo, obj_tptr, obj_tlen - 12, 12);
745		if (ret == -1)
746		    goto trunc;
747		if (ret == TRUE)
748		    hexdump=TRUE;
749		break;
750
751	    case LMP_CTYPE_IPV6:
752                if (obj_tlen < 36) {
753                    ND_PRINT((ndo, " (not correct for object)"));
754                    break;
755                }
756	        ND_PRINT((ndo, "\n\t    Flags: [%s]",
757		    bittok2str(lmp_obj_data_link_flag_values,
758			"none",
759			EXTRACT_8BITS(obj_tptr))));
760                ND_PRINT((ndo, "\n\t    Local Interface ID: %s (0x%08x)"
761                       "\n\t    Remote Interface ID: %s (0x%08x)",
762                       ip6addr_string(ndo, obj_tptr+4),
763                       EXTRACT_32BITS(obj_tptr+4),
764                       ip6addr_string(ndo, obj_tptr+20),
765                       EXTRACT_32BITS(obj_tptr+20)));
766
767		ret = lmp_print_data_link_subobjs(ndo, obj_tptr, obj_tlen - 36, 36);
768		if (ret == -1)
769		    goto trunc;
770		if (ret == TRUE)
771		    hexdump=TRUE;
772		break;
773
774	    case LMP_CTYPE_UNMD:
775                if (obj_tlen < 12) {
776                    ND_PRINT((ndo, " (not correct for object)"));
777                    break;
778                }
779	        ND_PRINT((ndo, "\n\t    Flags: [%s]",
780		    bittok2str(lmp_obj_data_link_flag_values,
781			"none",
782			EXTRACT_8BITS(obj_tptr))));
783                ND_PRINT((ndo, "\n\t    Local Interface ID: %u (0x%08x)"
784                       "\n\t    Remote Interface ID: %u (0x%08x)",
785                       EXTRACT_32BITS(obj_tptr+4),
786                       EXTRACT_32BITS(obj_tptr+4),
787                       EXTRACT_32BITS(obj_tptr+8),
788                       EXTRACT_32BITS(obj_tptr+8)));
789
790		ret = lmp_print_data_link_subobjs(ndo, obj_tptr, obj_tlen - 12, 12);
791		if (ret == -1)
792		    goto trunc;
793		if (ret == TRUE)
794		    hexdump=TRUE;
795		break;
796
797            default:
798                hexdump=TRUE;
799            }
800            break;
801
802        case LMP_OBJ_VERIFY_BEGIN:
803	    switch(lmp_obj_ctype) {
804            case LMP_CTYPE_1:
805                if (obj_tlen != 20) {
806                    ND_PRINT((ndo, " (not correct for object)"));
807                    break;
808                }
809		ND_PRINT((ndo, "\n\t    Flags: %s",
810		bittok2str(lmp_obj_begin_verify_flag_values,
811			"none",
812			EXTRACT_16BITS(obj_tptr))));
813		ND_PRINT((ndo, "\n\t    Verify Interval: %u",
814			EXTRACT_16BITS(obj_tptr+2)));
815		ND_PRINT((ndo, "\n\t    Data links: %u",
816			EXTRACT_32BITS(obj_tptr+4)));
817                ND_PRINT((ndo, "\n\t    Encoding type: %s",
818			tok2str(gmpls_encoding_values, "Unknown", *(obj_tptr+8))));
819                ND_PRINT((ndo, "\n\t    Verify Transport Mechanism: %u (0x%x)%s",
820			EXTRACT_16BITS(obj_tptr+10),
821			EXTRACT_16BITS(obj_tptr+10),
822			EXTRACT_16BITS(obj_tptr+10)&8000 ? " (Payload test messages capable)" : ""));
823                bw.i = EXTRACT_32BITS(obj_tptr+12);
824		ND_PRINT((ndo, "\n\t    Transmission Rate: %.3f Mbps",bw.f*8/1000000));
825		ND_PRINT((ndo, "\n\t    Wavelength: %u",
826			EXTRACT_32BITS(obj_tptr+16)));
827		break;
828
829            default:
830                hexdump=TRUE;
831            }
832            break;
833
834        case LMP_OBJ_VERIFY_BEGIN_ACK:
835	    switch(lmp_obj_ctype) {
836            case LMP_CTYPE_1:
837                if (obj_tlen != 4) {
838                    ND_PRINT((ndo, " (not correct for object)"));
839                    break;
840                }
841                ND_PRINT((ndo, "\n\t    Verify Dead Interval: %u"
842                       "\n\t    Verify Transport Response: %u",
843                       EXTRACT_16BITS(obj_tptr),
844                       EXTRACT_16BITS(obj_tptr+2)));
845                break;
846
847            default:
848                hexdump=TRUE;
849            }
850            break;
851
852	case LMP_OBJ_VERIFY_ID:
853	    switch(lmp_obj_ctype) {
854            case LMP_CTYPE_1:
855                if (obj_tlen != 4) {
856                    ND_PRINT((ndo, " (not correct for object)"));
857                    break;
858                }
859                ND_PRINT((ndo, "\n\t    Verify ID: %u",
860                       EXTRACT_32BITS(obj_tptr)));
861                break;
862
863            default:
864                hexdump=TRUE;
865            }
866            break;
867
868	case LMP_OBJ_CHANNEL_STATUS:
869            switch(lmp_obj_ctype) {
870	    case LMP_CTYPE_IPV4:
871		offset = 0;
872		/* Decode pairs: <Interface_ID (4 bytes), Channel_status (4 bytes)> */
873		while (offset+8 <= obj_tlen) {
874			ND_PRINT((ndo, "\n\t    Interface ID: %s (0x%08x)",
875			ipaddr_string(ndo, obj_tptr+offset),
876			EXTRACT_32BITS(obj_tptr+offset)));
877
878			ND_PRINT((ndo, "\n\t\t    Active: %s (%u)",
879				(EXTRACT_32BITS(obj_tptr+offset+4)>>31) ?
880						"Allocated" : "Non-allocated",
881				(EXTRACT_32BITS(obj_tptr+offset+4)>>31)));
882
883			ND_PRINT((ndo, "\n\t\t    Direction: %s (%u)",
884				(EXTRACT_32BITS(obj_tptr+offset+4)>>30)&0x1 ?
885						"Transmit" : "Receive",
886				(EXTRACT_32BITS(obj_tptr+offset+4)>>30)&0x1));
887
888			ND_PRINT((ndo, "\n\t\t    Channel Status: %s (%u)",
889					tok2str(lmp_obj_channel_status_values,
890			 		"Unknown",
891					EXTRACT_32BITS(obj_tptr+offset+4)&0x3FFFFFF),
892			EXTRACT_32BITS(obj_tptr+offset+4)&0x3FFFFFF));
893			offset+=8;
894		}
895                break;
896
897	    case LMP_CTYPE_IPV6:
898		offset = 0;
899		/* Decode pairs: <Interface_ID (16 bytes), Channel_status (4 bytes)> */
900		while (offset+20 <= obj_tlen) {
901			ND_PRINT((ndo, "\n\t    Interface ID: %s (0x%08x)",
902			ip6addr_string(ndo, obj_tptr+offset),
903			EXTRACT_32BITS(obj_tptr+offset)));
904
905			ND_PRINT((ndo, "\n\t\t    Active: %s (%u)",
906				(EXTRACT_32BITS(obj_tptr+offset+16)>>31) ?
907						"Allocated" : "Non-allocated",
908				(EXTRACT_32BITS(obj_tptr+offset+16)>>31)));
909
910			ND_PRINT((ndo, "\n\t\t    Direction: %s (%u)",
911				(EXTRACT_32BITS(obj_tptr+offset+16)>>30)&0x1 ?
912						"Transmit" : "Receive",
913				(EXTRACT_32BITS(obj_tptr+offset+16)>>30)&0x1));
914
915			ND_PRINT((ndo, "\n\t\t    Channel Status: %s (%u)",
916					tok2str(lmp_obj_channel_status_values,
917					"Unknown",
918					EXTRACT_32BITS(obj_tptr+offset+16)&0x3FFFFFF),
919			EXTRACT_32BITS(obj_tptr+offset+16)&0x3FFFFFF));
920			offset+=20;
921		}
922                break;
923
924	    case LMP_CTYPE_UNMD:
925		offset = 0;
926		/* Decode pairs: <Interface_ID (4 bytes), Channel_status (4 bytes)> */
927		while (offset+8 <= obj_tlen) {
928			ND_PRINT((ndo, "\n\t    Interface ID: %u (0x%08x)",
929			EXTRACT_32BITS(obj_tptr+offset),
930			EXTRACT_32BITS(obj_tptr+offset)));
931
932			ND_PRINT((ndo, "\n\t\t    Active: %s (%u)",
933				(EXTRACT_32BITS(obj_tptr+offset+4)>>31) ?
934						"Allocated" : "Non-allocated",
935				(EXTRACT_32BITS(obj_tptr+offset+4)>>31)));
936
937			ND_PRINT((ndo, "\n\t\t    Direction: %s (%u)",
938				(EXTRACT_32BITS(obj_tptr+offset+4)>>30)&0x1 ?
939						"Transmit" : "Receive",
940				(EXTRACT_32BITS(obj_tptr+offset+4)>>30)&0x1));
941
942			ND_PRINT((ndo, "\n\t\t    Channel Status: %s (%u)",
943					tok2str(lmp_obj_channel_status_values,
944					"Unknown",
945					EXTRACT_32BITS(obj_tptr+offset+4)&0x3FFFFFF),
946			EXTRACT_32BITS(obj_tptr+offset+4)&0x3FFFFFF));
947			offset+=8;
948		}
949                break;
950
951            default:
952                hexdump=TRUE;
953            }
954            break;
955
956	case LMP_OBJ_CHANNEL_STATUS_REQ:
957            switch(lmp_obj_ctype) {
958	    case LMP_CTYPE_IPV4:
959		offset = 0;
960		while (offset+4 <= obj_tlen) {
961			ND_PRINT((ndo, "\n\t    Interface ID: %s (0x%08x)",
962			ipaddr_string(ndo, obj_tptr+offset),
963			EXTRACT_32BITS(obj_tptr+offset)));
964			offset+=4;
965		}
966                break;
967
968	    case LMP_CTYPE_IPV6:
969		offset = 0;
970		while (offset+16 <= obj_tlen) {
971			ND_PRINT((ndo, "\n\t    Interface ID: %s (0x%08x)",
972			ip6addr_string(ndo, obj_tptr+offset),
973			EXTRACT_32BITS(obj_tptr+offset)));
974			offset+=16;
975		}
976                break;
977
978	    case LMP_CTYPE_UNMD:
979		offset = 0;
980		while (offset+4 <= obj_tlen) {
981			ND_PRINT((ndo, "\n\t    Interface ID: %u (0x%08x)",
982			EXTRACT_32BITS(obj_tptr+offset),
983			EXTRACT_32BITS(obj_tptr+offset)));
984			offset+=4;
985		}
986                break;
987
988	    default:
989                hexdump=TRUE;
990            }
991            break;
992
993        case LMP_OBJ_ERROR_CODE:
994	    switch(lmp_obj_ctype) {
995            case LMP_CTYPE_BEGIN_VERIFY_ERROR:
996                if (obj_tlen != 4) {
997                    ND_PRINT((ndo, " (not correct for object)"));
998                    break;
999                }
1000		ND_PRINT((ndo, "\n\t    Error Code: %s",
1001		bittok2str(lmp_obj_begin_verify_error_values,
1002			"none",
1003			EXTRACT_32BITS(obj_tptr))));
1004                break;
1005
1006            case LMP_CTYPE_LINK_SUMMARY_ERROR:
1007                if (obj_tlen != 4) {
1008                    ND_PRINT((ndo, " (not correct for object)"));
1009                    break;
1010                }
1011		ND_PRINT((ndo, "\n\t    Error Code: %s",
1012		bittok2str(lmp_obj_link_summary_error_values,
1013			"none",
1014			EXTRACT_32BITS(obj_tptr))));
1015                break;
1016            default:
1017                hexdump=TRUE;
1018            }
1019            break;
1020
1021	case LMP_OBJ_SERVICE_CONFIG:
1022	    switch (lmp_obj_ctype) {
1023	    case LMP_CTYPE_SERVICE_CONFIG_SP:
1024                if (obj_tlen != 4) {
1025                    ND_PRINT((ndo, " (not correct for object)"));
1026                    break;
1027                }
1028		ND_PRINT((ndo, "\n\t Flags: %s",
1029		       bittok2str(lmp_obj_service_config_sp_flag_values,
1030				  "none",
1031				  EXTRACT_8BITS(obj_tptr))));
1032
1033		ND_PRINT((ndo, "\n\t  UNI Version: %u",
1034		       EXTRACT_8BITS(obj_tptr + 1)));
1035
1036		break;
1037
1038            case LMP_CTYPE_SERVICE_CONFIG_CPSA:
1039                if (obj_tlen != 16) {
1040                    ND_PRINT((ndo, " (not correct for object)"));
1041                    break;
1042                }
1043
1044		link_type = EXTRACT_8BITS(obj_tptr);
1045
1046		ND_PRINT((ndo, "\n\t Link Type: %s (%u)",
1047		       tok2str(lmp_sd_service_config_cpsa_link_type_values,
1048			       "Unknown", link_type),
1049		       link_type));
1050
1051		switch (link_type) {
1052		case LMP_SD_SERVICE_CONFIG_CPSA_LINK_TYPE_SDH:
1053		    ND_PRINT((ndo, "\n\t Signal Type: %s (%u)",
1054			   tok2str(lmp_sd_service_config_cpsa_signal_type_sdh_values,
1055				   "Unknown",
1056				   EXTRACT_8BITS(obj_tptr + 1)),
1057				   EXTRACT_8BITS(obj_tptr + 1)));
1058		    break;
1059
1060		case LMP_SD_SERVICE_CONFIG_CPSA_LINK_TYPE_SONET:
1061		    ND_PRINT((ndo, "\n\t Signal Type: %s (%u)",
1062			   tok2str(lmp_sd_service_config_cpsa_signal_type_sonet_values,
1063				   "Unknown",
1064				   EXTRACT_8BITS(obj_tptr + 1)),
1065				   EXTRACT_8BITS(obj_tptr + 1)));
1066		    break;
1067		}
1068
1069		ND_PRINT((ndo, "\n\t Transparency: %s",
1070		       bittok2str(lmp_obj_service_config_cpsa_tp_flag_values,
1071				  "none",
1072				  EXTRACT_8BITS(obj_tptr + 2))));
1073
1074		ND_PRINT((ndo, "\n\t Contiguous Concatenation Types: %s",
1075		       bittok2str(lmp_obj_service_config_cpsa_cct_flag_values,
1076				  "none",
1077				  EXTRACT_8BITS(obj_tptr + 3))));
1078
1079		ND_PRINT((ndo, "\n\t Minimum NCC: %u",
1080		       EXTRACT_16BITS(obj_tptr+4)));
1081
1082		ND_PRINT((ndo, "\n\t Maximum NCC: %u",
1083		       EXTRACT_16BITS(obj_tptr+6)));
1084
1085		ND_PRINT((ndo, "\n\t Minimum NVC:%u",
1086		       EXTRACT_16BITS(obj_tptr+8)));
1087
1088		ND_PRINT((ndo, "\n\t Maximum NVC:%u",
1089		       EXTRACT_16BITS(obj_tptr+10)));
1090
1091		ND_PRINT((ndo, "\n\t    Local Interface ID: %s (0x%08x)",
1092		       ipaddr_string(ndo, obj_tptr+12),
1093		       EXTRACT_32BITS(obj_tptr+12)));
1094
1095		break;
1096
1097	    case LMP_CTYPE_SERVICE_CONFIG_TRANSPARENCY_TCM:
1098                if (obj_tlen != 8) {
1099                    ND_PRINT((ndo, " (not correct for object)"));
1100                    break;
1101                }
1102
1103		ND_PRINT((ndo, "\n\t Transparency Flags: %s",
1104		       bittok2str(
1105			   lmp_obj_service_config_nsa_transparency_flag_values,
1106			   "none",
1107			   EXTRACT_32BITS(obj_tptr))));
1108
1109		ND_PRINT((ndo, "\n\t TCM Monitoring Flags: %s",
1110		       bittok2str(
1111			   lmp_obj_service_config_nsa_tcm_flag_values,
1112			   "none",
1113			   EXTRACT_8BITS(obj_tptr + 7))));
1114
1115		break;
1116
1117	    case LMP_CTYPE_SERVICE_CONFIG_NETWORK_DIVERSITY:
1118                if (obj_tlen != 4) {
1119                    ND_PRINT((ndo, " (not correct for object)"));
1120                    break;
1121                }
1122
1123		ND_PRINT((ndo, "\n\t Diversity: Flags: %s",
1124		       bittok2str(
1125			   lmp_obj_service_config_nsa_network_diversity_flag_values,
1126			   "none",
1127			   EXTRACT_8BITS(obj_tptr + 3))));
1128		break;
1129
1130	    default:
1131		hexdump = TRUE;
1132	    }
1133
1134	break;
1135
1136        default:
1137            if (ndo->ndo_vflag <= 1)
1138                print_unknown_data(ndo,obj_tptr,"\n\t    ",obj_tlen);
1139            break;
1140        }
1141        /* do we want to see an additionally hexdump ? */
1142        if (ndo->ndo_vflag > 1 || hexdump==TRUE)
1143            print_unknown_data(ndo,tptr+sizeof(struct lmp_object_header),"\n\t    ",
1144                               lmp_obj_len-sizeof(struct lmp_object_header));
1145
1146        tptr+=lmp_obj_len;
1147        tlen-=lmp_obj_len;
1148    }
1149    return;
1150trunc:
1151    ND_PRINT((ndo, "%s", tstr));
1152}
1153/*
1154 * Local Variables:
1155 * c-style: whitesmith
1156 * c-basic-offset: 8
1157 * End:
1158 */
1159