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