1/*
2 * Copyright (c) 1992, 1993, 1994, 1995, 1996
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 * Original code by Matt Thomas, Digital Equipment Corporation
22 *
23 * Extensively modified by Hannes Gredler (hannes@gredler.at) for more
24 * complete IS-IS & CLNP support.
25 */
26
27/* \summary: ISO CLNS, ESIS, and ISIS printer */
28
29/*
30 * specification:
31 *
32 * CLNP: ISO 8473 (respective ITU version is at https://www.itu.int/rec/T-REC-X.233/en/)
33 * ES-IS: ISO 9542
34 * IS-IS: ISO 10589
35 */
36
37#ifdef HAVE_CONFIG_H
38#include <config.h>
39#endif
40
41#include "netdissect-stdinc.h"
42
43#include <string.h>
44
45#include "netdissect.h"
46#include "addrtoname.h"
47#include "nlpid.h"
48#include "extract.h"
49#include "gmpls.h"
50#include "oui.h"
51#include "signature.h"
52
53
54/*
55 * IS-IS is defined in ISO 10589.  Look there for protocol definitions.
56 */
57
58#define SYSTEM_ID_LEN	MAC_ADDR_LEN
59#define NODE_ID_LEN     (SYSTEM_ID_LEN+1)
60#define LSP_ID_LEN      (SYSTEM_ID_LEN+2)
61
62#define ISIS_VERSION	1
63#define ESIS_VERSION	1
64#define CLNP_VERSION	1
65
66#define ISIS_PDU_TYPE_MASK      0x1F
67#define ESIS_PDU_TYPE_MASK      0x1F
68#define CLNP_PDU_TYPE_MASK      0x1F
69#define CLNP_FLAG_MASK          0xE0
70#define ISIS_LAN_PRIORITY_MASK  0x7F
71
72#define ISIS_PDU_L1_LAN_IIH	15
73#define ISIS_PDU_L2_LAN_IIH	16
74#define ISIS_PDU_PTP_IIH	17
75#define ISIS_PDU_L1_LSP		18
76#define ISIS_PDU_L2_LSP		20
77#define ISIS_PDU_L1_CSNP	24
78#define ISIS_PDU_L2_CSNP	25
79#define ISIS_PDU_L1_PSNP        26
80#define ISIS_PDU_L2_PSNP        27
81
82static const struct tok isis_pdu_values[] = {
83    { ISIS_PDU_L1_LAN_IIH,       "L1 Lan IIH"},
84    { ISIS_PDU_L2_LAN_IIH,       "L2 Lan IIH"},
85    { ISIS_PDU_PTP_IIH,          "p2p IIH"},
86    { ISIS_PDU_L1_LSP,           "L1 LSP"},
87    { ISIS_PDU_L2_LSP,           "L2 LSP"},
88    { ISIS_PDU_L1_CSNP,          "L1 CSNP"},
89    { ISIS_PDU_L2_CSNP,          "L2 CSNP"},
90    { ISIS_PDU_L1_PSNP,          "L1 PSNP"},
91    { ISIS_PDU_L2_PSNP,          "L2 PSNP"},
92    { 0, NULL}
93};
94
95/*
96 * A TLV is a tuple of a type, length and a value and is normally used for
97 * encoding information in all sorts of places.  This is an enumeration of
98 * the well known types.
99 *
100 * list taken from rfc3359 plus some memory from veterans ;-)
101 */
102
103#define ISIS_TLV_AREA_ADDR           1   /* iso10589 */
104#define ISIS_TLV_IS_REACH            2   /* iso10589 */
105#define ISIS_TLV_ESNEIGH             3   /* iso10589 */
106#define ISIS_TLV_PART_DIS            4   /* iso10589 */
107#define ISIS_TLV_PREFIX_NEIGH        5   /* iso10589 */
108#define ISIS_TLV_ISNEIGH             6   /* iso10589 */
109#define ISIS_TLV_INSTANCE_ID         7   /* rfc8202 */
110#define ISIS_TLV_PADDING             8   /* iso10589 */
111#define ISIS_TLV_LSP                 9   /* iso10589 */
112#define ISIS_TLV_AUTH                10  /* iso10589, rfc3567 */
113#define ISIS_TLV_CHECKSUM            12  /* rfc3358 */
114#define ISIS_TLV_CHECKSUM_MINLEN 2
115#define ISIS_TLV_POI                 13  /* rfc6232 */
116#define ISIS_TLV_LSP_BUFFERSIZE      14  /* iso10589 rev2 */
117#define ISIS_TLV_EXT_IS_REACH        22  /* rfc5305 */
118#define ISIS_TLV_IS_ALIAS_ID         24  /* rfc5311 */
119#define ISIS_TLV_DECNET_PHASE4       42
120#define ISIS_TLV_LUCENT_PRIVATE      66
121#define ISIS_TLV_INT_IP_REACH        128 /* rfc1195, rfc2966 */
122#define ISIS_TLV_PROTOCOLS           129 /* rfc1195 */
123#define ISIS_TLV_EXT_IP_REACH        130 /* rfc1195, rfc2966 */
124#define ISIS_TLV_IDRP_INFO           131 /* rfc1195 */
125#define ISIS_TLV_IPADDR              132 /* rfc1195 */
126#define ISIS_TLV_IPAUTH              133 /* rfc1195 */
127#define ISIS_TLV_TE_ROUTER_ID        134 /* rfc5305 */
128#define ISIS_TLV_EXTD_IP_REACH       135 /* rfc5305 */
129#define ISIS_TLV_HOSTNAME            137 /* rfc2763 */
130#define ISIS_TLV_SHARED_RISK_GROUP   138 /* draft-ietf-isis-gmpls-extensions */
131#define ISIS_TLV_MT_PORT_CAP         143 /* rfc6165 */
132#define ISIS_TLV_MT_CAPABILITY       144 /* rfc6329 */
133#define ISIS_TLV_NORTEL_PRIVATE1     176
134#define ISIS_TLV_NORTEL_PRIVATE2     177
135#define ISIS_TLV_RESTART_SIGNALING   211 /* rfc3847 */
136#define ISIS_TLV_RESTART_SIGNALING_FLAGLEN 1
137#define ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN 2
138#define ISIS_TLV_MT_IS_REACH         222 /* draft-ietf-isis-wg-multi-topology-05 */
139#define ISIS_TLV_MT_SUPPORTED        229 /* draft-ietf-isis-wg-multi-topology-05 */
140#define ISIS_TLV_IP6ADDR             232 /* draft-ietf-isis-ipv6-02 */
141#define ISIS_TLV_MT_IP_REACH         235 /* draft-ietf-isis-wg-multi-topology-05 */
142#define ISIS_TLV_IP6_REACH           236 /* draft-ietf-isis-ipv6-02 */
143#define ISIS_TLV_MT_IP6_REACH        237 /* draft-ietf-isis-wg-multi-topology-05 */
144#define ISIS_TLV_PTP_ADJ             240 /* rfc3373 */
145#define ISIS_TLV_IIH_SEQNR           241 /* draft-shen-isis-iih-sequence-00 */
146#define ISIS_TLV_ROUTER_CAPABILITY   242 /* rfc7981 */
147#define ISIS_TLV_VENDOR_PRIVATE      250 /* draft-ietf-isis-experimental-tlv-01 */
148#define ISIS_TLV_VENDOR_PRIVATE_MINLEN 3
149
150static const struct tok isis_tlv_values[] = {
151    { ISIS_TLV_AREA_ADDR,	   "Area address(es)"},
152    { ISIS_TLV_IS_REACH,           "IS Reachability"},
153    { ISIS_TLV_ESNEIGH,            "ES Neighbor(s)"},
154    { ISIS_TLV_PART_DIS,           "Partition DIS"},
155    { ISIS_TLV_PREFIX_NEIGH,       "Prefix Neighbors"},
156    { ISIS_TLV_ISNEIGH,            "IS Neighbor(s)"},
157    { ISIS_TLV_INSTANCE_ID,        "Instance Identifier"},
158    { ISIS_TLV_PADDING,            "Padding"},
159    { ISIS_TLV_LSP,                "LSP entries"},
160    { ISIS_TLV_AUTH,               "Authentication"},
161    { ISIS_TLV_CHECKSUM,           "Checksum"},
162    { ISIS_TLV_POI,                "Purge Originator Identifier"},
163    { ISIS_TLV_LSP_BUFFERSIZE,     "LSP Buffersize"},
164    { ISIS_TLV_EXT_IS_REACH,       "Extended IS Reachability"},
165    { ISIS_TLV_IS_ALIAS_ID,        "IS Alias ID"},
166    { ISIS_TLV_DECNET_PHASE4,      "DECnet Phase IV"},
167    { ISIS_TLV_LUCENT_PRIVATE,     "Lucent Proprietary"},
168    { ISIS_TLV_INT_IP_REACH,       "IPv4 Internal Reachability"},
169    { ISIS_TLV_PROTOCOLS,          "Protocols supported"},
170    { ISIS_TLV_EXT_IP_REACH,       "IPv4 External Reachability"},
171    { ISIS_TLV_IDRP_INFO,          "Inter-Domain Information Type"},
172    { ISIS_TLV_IPADDR,             "IPv4 Interface address(es)"},
173    { ISIS_TLV_IPAUTH,             "IPv4 authentication (deprecated)"},
174    { ISIS_TLV_TE_ROUTER_ID,       "Traffic Engineering Router ID"},
175    { ISIS_TLV_EXTD_IP_REACH,      "Extended IPv4 Reachability"},
176    { ISIS_TLV_SHARED_RISK_GROUP,  "Shared Risk Link Group"},
177    { ISIS_TLV_MT_PORT_CAP,        "Multi-Topology-Aware Port Capability"},
178    { ISIS_TLV_MT_CAPABILITY,      "Multi-Topology Capability"},
179    { ISIS_TLV_NORTEL_PRIVATE1,    "Nortel Proprietary"},
180    { ISIS_TLV_NORTEL_PRIVATE2,    "Nortel Proprietary"},
181    { ISIS_TLV_HOSTNAME,           "Hostname"},
182    { ISIS_TLV_RESTART_SIGNALING,  "Restart Signaling"},
183    { ISIS_TLV_MT_IS_REACH,        "Multi Topology IS Reachability"},
184    { ISIS_TLV_MT_SUPPORTED,       "Multi Topology"},
185    { ISIS_TLV_IP6ADDR,            "IPv6 Interface address(es)"},
186    { ISIS_TLV_MT_IP_REACH,        "Multi-Topology IPv4 Reachability"},
187    { ISIS_TLV_IP6_REACH,          "IPv6 reachability"},
188    { ISIS_TLV_MT_IP6_REACH,       "Multi-Topology IP6 Reachability"},
189    { ISIS_TLV_PTP_ADJ,            "Point-to-point Adjacency State"},
190    { ISIS_TLV_IIH_SEQNR,          "Hello PDU Sequence Number"},
191    { ISIS_TLV_ROUTER_CAPABILITY,  "IS-IS Router Capability"},
192    { ISIS_TLV_VENDOR_PRIVATE,     "Vendor Private"},
193    { 0, NULL }
194};
195
196#define ESIS_OPTION_PROTOCOLS        129
197#define ESIS_OPTION_QOS_MAINTENANCE  195 /* iso9542 */
198#define ESIS_OPTION_SECURITY         197 /* iso9542 */
199#define ESIS_OPTION_ES_CONF_TIME     198 /* iso9542 */
200#define ESIS_OPTION_PRIORITY         205 /* iso9542 */
201#define ESIS_OPTION_ADDRESS_MASK     225 /* iso9542 */
202#define ESIS_OPTION_SNPA_MASK        226 /* iso9542 */
203
204static const struct tok esis_option_values[] = {
205    { ESIS_OPTION_PROTOCOLS,       "Protocols supported"},
206    { ESIS_OPTION_QOS_MAINTENANCE, "QoS Maintenance" },
207    { ESIS_OPTION_SECURITY,        "Security" },
208    { ESIS_OPTION_ES_CONF_TIME,    "ES Configuration Time" },
209    { ESIS_OPTION_PRIORITY,        "Priority" },
210    { ESIS_OPTION_ADDRESS_MASK,    "Addressk Mask" },
211    { ESIS_OPTION_SNPA_MASK,       "SNPA Mask" },
212    { 0, NULL }
213};
214
215#define CLNP_OPTION_DISCARD_REASON   193
216#define CLNP_OPTION_QOS_MAINTENANCE  195 /* iso8473 */
217#define CLNP_OPTION_SECURITY         197 /* iso8473 */
218#define CLNP_OPTION_SOURCE_ROUTING   200 /* iso8473 */
219#define CLNP_OPTION_ROUTE_RECORDING  203 /* iso8473 */
220#define CLNP_OPTION_PADDING          204 /* iso8473 */
221#define CLNP_OPTION_PRIORITY         205 /* iso8473 */
222
223static const struct tok clnp_option_values[] = {
224    { CLNP_OPTION_DISCARD_REASON,  "Discard Reason"},
225    { CLNP_OPTION_PRIORITY,        "Priority"},
226    { CLNP_OPTION_QOS_MAINTENANCE, "QoS Maintenance"},
227    { CLNP_OPTION_SECURITY, "Security"},
228    { CLNP_OPTION_SOURCE_ROUTING, "Source Routing"},
229    { CLNP_OPTION_ROUTE_RECORDING, "Route Recording"},
230    { CLNP_OPTION_PADDING, "Padding"},
231    { 0, NULL }
232};
233
234static const struct tok clnp_option_rfd_class_values[] = {
235    { 0x0, "General"},
236    { 0x8, "Address"},
237    { 0x9, "Source Routeing"},
238    { 0xa, "Lifetime"},
239    { 0xb, "PDU Discarded"},
240    { 0xc, "Reassembly"},
241    { 0, NULL }
242};
243
244static const struct tok clnp_option_rfd_general_values[] = {
245    { 0x0, "Reason not specified"},
246    { 0x1, "Protocol procedure error"},
247    { 0x2, "Incorrect checksum"},
248    { 0x3, "PDU discarded due to congestion"},
249    { 0x4, "Header syntax error (cannot be parsed)"},
250    { 0x5, "Segmentation needed but not permitted"},
251    { 0x6, "Incomplete PDU received"},
252    { 0x7, "Duplicate option"},
253    { 0, NULL }
254};
255
256static const struct tok clnp_option_rfd_address_values[] = {
257    { 0x0, "Destination address unreachable"},
258    { 0x1, "Destination address unknown"},
259    { 0, NULL }
260};
261
262static const struct tok clnp_option_rfd_source_routeing_values[] = {
263    { 0x0, "Unspecified source routeing error"},
264    { 0x1, "Syntax error in source routeing field"},
265    { 0x2, "Unknown address in source routeing field"},
266    { 0x3, "Path not acceptable"},
267    { 0, NULL }
268};
269
270static const struct tok clnp_option_rfd_lifetime_values[] = {
271    { 0x0, "Lifetime expired while data unit in transit"},
272    { 0x1, "Lifetime expired during reassembly"},
273    { 0, NULL }
274};
275
276static const struct tok clnp_option_rfd_pdu_discard_values[] = {
277    { 0x0, "Unsupported option not specified"},
278    { 0x1, "Unsupported protocol version"},
279    { 0x2, "Unsupported security option"},
280    { 0x3, "Unsupported source routeing option"},
281    { 0x4, "Unsupported recording of route option"},
282    { 0, NULL }
283};
284
285static const struct tok clnp_option_rfd_reassembly_values[] = {
286    { 0x0, "Reassembly interference"},
287    { 0, NULL }
288};
289
290/* array of 16 error-classes */
291static const struct tok *clnp_option_rfd_error_class[] = {
292    clnp_option_rfd_general_values,
293    NULL,
294    NULL,
295    NULL,
296    NULL,
297    NULL,
298    NULL,
299    NULL,
300    clnp_option_rfd_address_values,
301    clnp_option_rfd_source_routeing_values,
302    clnp_option_rfd_lifetime_values,
303    clnp_option_rfd_pdu_discard_values,
304    clnp_option_rfd_reassembly_values,
305    NULL,
306    NULL,
307    NULL
308};
309
310#define CLNP_OPTION_OPTION_QOS_MASK 0x3f
311#define CLNP_OPTION_SCOPE_MASK      0xc0
312#define CLNP_OPTION_SCOPE_SA_SPEC   0x40
313#define CLNP_OPTION_SCOPE_DA_SPEC   0x80
314#define CLNP_OPTION_SCOPE_GLOBAL    0xc0
315
316static const struct tok clnp_option_scope_values[] = {
317    { CLNP_OPTION_SCOPE_SA_SPEC, "Source Address Specific"},
318    { CLNP_OPTION_SCOPE_DA_SPEC, "Destination Address Specific"},
319    { CLNP_OPTION_SCOPE_GLOBAL, "Globally unique"},
320    { 0, NULL }
321};
322
323static const struct tok clnp_option_sr_rr_values[] = {
324    { 0x0, "partial"},
325    { 0x1, "complete"},
326    { 0, NULL }
327};
328
329static const struct tok clnp_option_sr_rr_string_values[] = {
330    { CLNP_OPTION_SOURCE_ROUTING, "source routing"},
331    { CLNP_OPTION_ROUTE_RECORDING, "recording of route in progress"},
332    { 0, NULL }
333};
334
335static const struct tok clnp_option_qos_global_values[] = {
336    { 0x20, "reserved"},
337    { 0x10, "sequencing vs. delay"},
338    { 0x08, "congested"},
339    { 0x04, "delay vs. cost"},
340    { 0x02, "error vs. delay"},
341    { 0x01, "error vs. cost"},
342    { 0, NULL }
343};
344
345static const struct tok isis_tlv_router_capability_flags[] = {
346    { 0x01, "S bit"},
347    { 0x02, "D bit"},
348    { 0, NULL }
349};
350
351#define ISIS_SUBTLV_ROUTER_CAP_SR 2 /* rfc 8667 */
352
353static const struct tok isis_router_capability_subtlv_values[] = {
354    { ISIS_SUBTLV_ROUTER_CAP_SR, "SR-Capabilities"},
355    { 0, NULL }
356};
357
358static const struct tok isis_router_capability_sr_flags[] = {
359    { 0x80, "ipv4"},
360    { 0x40, "ipv6"},
361    { 0, NULL }
362};
363
364#define ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP           3 /* rfc5305 */
365#define ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID  4 /* rfc4205 */
366#define ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID        5 /* rfc5305 */
367#define ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR        6 /* rfc5305 */
368#define ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR    8 /* rfc5305 */
369#define ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW           9 /* rfc5305 */
370#define ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW        10 /* rfc5305 */
371#define ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW        11 /* rfc4124 */
372#define ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD   12 /* draft-ietf-tewg-diff-te-proto-06 */
373#define ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC            18 /* rfc5305 */
374#define ISIS_SUBTLV_EXT_IS_REACH_LINK_ATTRIBUTE       19 /* draft-ietf-isis-link-attr-01 */
375#define ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE 20 /* rfc4205 */
376#define ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR    21 /* rfc4205 */
377#define ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS       22 /* rfc4124 */
378#define ISIS_SUBTLV_EXT_IS_REACH_LAN_ADJ_SEGMENT_ID   32 /* rfc8667 */
379
380#define ISIS_SUBTLV_SPB_METRIC                        29 /* rfc6329 */
381
382static const struct tok isis_ext_is_reach_subtlv_values[] = {
383    { ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP,            "Administrative groups" },
384    { ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID,   "Link Local/Remote Identifier" },
385    { ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID,         "Link Remote Identifier" },
386    { ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR,         "IPv4 interface address" },
387    { ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR,     "IPv4 neighbor address" },
388    { ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW,            "Maximum link bandwidth" },
389    { ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW,          "Reservable link bandwidth" },
390    { ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW,          "Unreserved bandwidth" },
391    { ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC,              "Traffic Engineering Metric" },
392    { ISIS_SUBTLV_EXT_IS_REACH_LINK_ATTRIBUTE,         "Link Attribute" },
393    { ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE,   "Link Protection Type" },
394    { ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR,      "Interface Switching Capability" },
395    { ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD,     "Bandwidth Constraints (old)" },
396    { ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS,         "Bandwidth Constraints" },
397    { ISIS_SUBTLV_EXT_IS_REACH_LAN_ADJ_SEGMENT_ID,     "LAN Adjacency Segment Identifier" },
398    { ISIS_SUBTLV_SPB_METRIC,                          "SPB Metric" },
399    { 250,                                             "Reserved for cisco specific extensions" },
400    { 251,                                             "Reserved for cisco specific extensions" },
401    { 252,                                             "Reserved for cisco specific extensions" },
402    { 253,                                             "Reserved for cisco specific extensions" },
403    { 254,                                             "Reserved for cisco specific extensions" },
404    { 255,                                             "Reserved for future expansion" },
405    { 0, NULL }
406};
407
408#define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32          1 /* draft-ietf-isis-admin-tags-01 */
409#define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64          2 /* draft-ietf-isis-admin-tags-01 */
410#define ISIS_SUBTLV_EXTD_IP_REACH_PREFIX_SID           3 /* rfc8667 */
411#define ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR  117 /* draft-ietf-isis-wg-multi-topology-05 */
412
413static const struct tok isis_ext_ip_reach_subtlv_values[] = {
414    { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32,           "32-Bit Administrative tag" },
415    { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64,           "64-Bit Administrative tag" },
416    { ISIS_SUBTLV_EXTD_IP_REACH_PREFIX_SID,            "Prefix SID" },
417    { ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR,     "Management Prefix Color" },
418    { 0, NULL }
419};
420
421#define ISIS_PREFIX_SID_FLAG_R 0x80 /* rfc 8667 */
422#define ISIS_PREFIX_SID_FLAG_N 0x40 /* rfc 8667 */
423#define ISIS_PREFIX_SID_FLAG_P 0x20 /* rfc 8667 */
424#define ISIS_PREFIX_SID_FLAG_E 0x10 /* rfc 8667 */
425#define ISIS_PREFIX_SID_FLAG_V 0x08 /* rfc 8667 */
426#define ISIS_PREFIX_SID_FLAG_L 0x04 /* rfc 8667 */
427
428static const struct tok prefix_sid_flag_values[] = {
429    { ISIS_PREFIX_SID_FLAG_R, "Readvertisement"},
430    { ISIS_PREFIX_SID_FLAG_N, "Node"},
431    { ISIS_PREFIX_SID_FLAG_P, "No-PHP"},
432    { ISIS_PREFIX_SID_FLAG_E, "Explicit NULL"},
433    { ISIS_PREFIX_SID_FLAG_V, "Value"},
434    { ISIS_PREFIX_SID_FLAG_L, "Local"},
435    { 0, NULL}
436};
437
438
439/* rfc 8667 */
440static const struct tok prefix_sid_algo_values[] = {
441    { 0, "SPF"},
442    { 1, "strict-SPF"},
443    { 0, NULL}
444};
445
446static const struct tok isis_subtlv_link_attribute_values[] = {
447    { 0x01, "Local Protection Available" },
448    { 0x02, "Link excluded from local protection path" },
449    { 0x04, "Local maintenance required"},
450    { 0, NULL }
451};
452
453static const struct tok isis_lan_adj_sid_flag_values[] = {
454    { 0x80, "Address family IPv6" },
455    { 0x40, "Backup" },
456    { 0x20, "Value" },
457    { 0x10, "Local significance" },
458    { 0x08, "Set of adjacencies" },
459    { 0x04, "Persistent" },
460    { 0, NULL }
461};
462
463#define ISIS_SUBTLV_AUTH_SIMPLE        1
464#define ISIS_SUBTLV_AUTH_GENERIC       3 /* rfc 5310 */
465#define ISIS_SUBTLV_AUTH_MD5          54
466#define ISIS_SUBTLV_AUTH_MD5_LEN      16
467#define ISIS_SUBTLV_AUTH_PRIVATE     255
468
469static const struct tok isis_subtlv_auth_values[] = {
470    { ISIS_SUBTLV_AUTH_SIMPLE,	"simple text password"},
471    { ISIS_SUBTLV_AUTH_GENERIC, "Generic Crypto key-id"},
472    { ISIS_SUBTLV_AUTH_MD5,	"HMAC-MD5 password"},
473    { ISIS_SUBTLV_AUTH_PRIVATE,	"Routing Domain private password"},
474    { 0, NULL }
475};
476
477#define ISIS_SUBTLV_IDRP_RES           0
478#define ISIS_SUBTLV_IDRP_LOCAL         1
479#define ISIS_SUBTLV_IDRP_ASN           2
480
481static const struct tok isis_subtlv_idrp_values[] = {
482    { ISIS_SUBTLV_IDRP_RES,         "Reserved"},
483    { ISIS_SUBTLV_IDRP_LOCAL,       "Routing-Domain Specific"},
484    { ISIS_SUBTLV_IDRP_ASN,         "AS Number Tag"},
485    { 0, NULL}
486};
487
488#define ISIS_SUBTLV_SPB_MCID          4
489#define ISIS_SUBTLV_SPB_DIGEST        5
490#define ISIS_SUBTLV_SPB_BVID          6
491
492#define ISIS_SUBTLV_SPB_INSTANCE      1
493#define ISIS_SUBTLV_SPBM_SI           3
494
495#define ISIS_SPB_MCID_LEN                         51
496#define ISIS_SUBTLV_SPB_MCID_MIN_LEN              102
497#define ISIS_SUBTLV_SPB_DIGEST_MIN_LEN            33
498#define ISIS_SUBTLV_SPB_BVID_MIN_LEN              6
499#define ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN          19
500#define ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN   8
501
502static const struct tok isis_mt_port_cap_subtlv_values[] = {
503    { ISIS_SUBTLV_SPB_MCID,           "SPB MCID" },
504    { ISIS_SUBTLV_SPB_DIGEST,         "SPB Digest" },
505    { ISIS_SUBTLV_SPB_BVID,           "SPB BVID" },
506    { 0, NULL }
507};
508
509static const struct tok isis_mt_capability_subtlv_values[] = {
510    { ISIS_SUBTLV_SPB_INSTANCE,      "SPB Instance" },
511    { ISIS_SUBTLV_SPBM_SI,      "SPBM Service Identifier and Unicast Address" },
512    { 0, NULL }
513};
514
515struct isis_spb_mcid {
516  nd_uint8_t  format_id;
517  nd_byte     name[32];
518  nd_uint16_t revision_lvl;
519  nd_byte     digest[16];
520};
521
522struct isis_subtlv_spb_mcid {
523  struct isis_spb_mcid mcid;
524  struct isis_spb_mcid aux_mcid;
525};
526
527struct isis_subtlv_spb_instance {
528  nd_byte     cist_root_id[8];
529  nd_uint32_t cist_external_root_path_cost;
530  nd_uint16_t bridge_priority;
531  nd_uint32_t spsourceid;
532  nd_uint8_t  no_of_trees;
533};
534
535#define CLNP_SEGMENT_PART  0x80
536#define CLNP_MORE_SEGMENTS 0x40
537#define CLNP_REQUEST_ER    0x20
538
539static const struct tok clnp_flag_values[] = {
540    { CLNP_SEGMENT_PART, "Segmentation permitted"},
541    { CLNP_MORE_SEGMENTS, "more Segments"},
542    { CLNP_REQUEST_ER, "request Error Report"},
543    { 0, NULL}
544};
545
546#define ISIS_MASK_LSP_OL_BIT(x)            (GET_U_1(x)&0x4)
547#define ISIS_MASK_LSP_ISTYPE_BITS(x)       (GET_U_1(x)&0x3)
548#define ISIS_MASK_LSP_PARTITION_BIT(x)     (GET_U_1(x)&0x80)
549#define ISIS_MASK_LSP_ATT_BITS(x)          (GET_U_1(x)&0x78)
550#define ISIS_MASK_LSP_ATT_ERROR_BIT(x)     (GET_U_1(x)&0x40)
551#define ISIS_MASK_LSP_ATT_EXPENSE_BIT(x)   (GET_U_1(x)&0x20)
552#define ISIS_MASK_LSP_ATT_DELAY_BIT(x)     (GET_U_1(x)&0x10)
553#define ISIS_MASK_LSP_ATT_DEFAULT_BIT(x)   (GET_U_1(x)&0x8)
554
555#define ISIS_MASK_MTID(x)                  ((x)&0x0fff)
556#define ISIS_MASK_MTFLAGS(x)               ((x)&0xf000)
557
558static const struct tok isis_mt_flag_values[] = {
559    { 0x4000,                  "ATT bit set"},
560    { 0x8000,                  "Overload bit set"},
561    { 0, NULL}
562};
563
564#define ISIS_MASK_TLV_EXTD_IP_UPDOWN(x)     ((x)&0x80)
565#define ISIS_MASK_TLV_EXTD_IP_SUBTLV(x)     ((x)&0x40)
566
567#define ISIS_MASK_TLV_EXTD_IP6_IE(x)        ((x)&0x40)
568#define ISIS_MASK_TLV_EXTD_IP6_SUBTLV(x)    ((x)&0x20)
569
570#define ISIS_LSP_TLV_METRIC_SUPPORTED(x)   (GET_U_1(x)&0x80)
571#define ISIS_LSP_TLV_METRIC_IE(x)          (GET_U_1(x)&0x40)
572#define ISIS_LSP_TLV_METRIC_UPDOWN(x)      (GET_U_1(x)&0x80)
573#define ISIS_LSP_TLV_METRIC_VALUE(x)	   (GET_U_1(x)&0x3f)
574
575#define ISIS_MASK_TLV_SHARED_RISK_GROUP(x) ((x)&0x1)
576
577static const struct tok isis_mt_values[] = {
578    { 0,    "IPv4 unicast"},
579    { 1,    "In-Band Management"},
580    { 2,    "IPv6 unicast"},
581    { 3,    "Multicast"},
582    { 4095, "Development, Experimental or Proprietary"},
583    { 0, NULL }
584};
585
586static const struct tok isis_iih_circuit_type_values[] = {
587    { 1,    "Level 1 only"},
588    { 2,    "Level 2 only"},
589    { 3,    "Level 1, Level 2"},
590    { 0, NULL}
591};
592
593#define ISIS_LSP_TYPE_UNUSED0   0
594#define ISIS_LSP_TYPE_LEVEL_1   1
595#define ISIS_LSP_TYPE_UNUSED2   2
596#define ISIS_LSP_TYPE_LEVEL_2   3
597
598static const struct tok isis_lsp_istype_values[] = {
599    { ISIS_LSP_TYPE_UNUSED0,	"Unused 0x0 (invalid)"},
600    { ISIS_LSP_TYPE_LEVEL_1,	"L1 IS"},
601    { ISIS_LSP_TYPE_UNUSED2,	"Unused 0x2 (invalid)"},
602    { ISIS_LSP_TYPE_LEVEL_2,	"L2 IS"},
603    { 0, NULL }
604};
605
606/*
607 * Katz's point to point adjacency TLV uses codes to tell us the state of
608 * the remote adjacency.  Enumerate them.
609 */
610
611#define ISIS_PTP_ADJ_UP   0
612#define ISIS_PTP_ADJ_INIT 1
613#define ISIS_PTP_ADJ_DOWN 2
614
615static const struct tok isis_ptp_adjancey_values[] = {
616    { ISIS_PTP_ADJ_UP,    "Up" },
617    { ISIS_PTP_ADJ_INIT,  "Initializing" },
618    { ISIS_PTP_ADJ_DOWN,  "Down" },
619    { 0, NULL}
620};
621
622struct isis_tlv_ptp_adj {
623    nd_uint8_t  adjacency_state;
624    nd_uint32_t extd_local_circuit_id;
625    nd_byte     neighbor_sysid[SYSTEM_ID_LEN];
626    nd_uint32_t neighbor_extd_local_circuit_id;
627};
628
629static void osi_print_cksum(netdissect_options *, const uint8_t *pptr,
630			    uint16_t checksum, int checksum_offset, u_int length);
631static int clnp_print(netdissect_options *, const uint8_t *, u_int);
632static void esis_print(netdissect_options *, const uint8_t *, u_int);
633static int isis_print(netdissect_options *, const uint8_t *, u_int);
634
635struct isis_metric_block {
636    nd_uint8_t metric_default;
637    nd_uint8_t metric_delay;
638    nd_uint8_t metric_expense;
639    nd_uint8_t metric_error;
640};
641
642struct isis_tlv_is_reach {
643    struct isis_metric_block isis_metric_block;
644    nd_byte neighbor_nodeid[NODE_ID_LEN];
645};
646
647struct isis_tlv_es_reach {
648    struct isis_metric_block isis_metric_block;
649    nd_byte neighbor_sysid[SYSTEM_ID_LEN];
650};
651
652struct isis_tlv_ip_reach {
653    struct isis_metric_block isis_metric_block;
654    nd_ipv4 prefix;
655    nd_ipv4 mask;
656};
657
658static const struct tok isis_is_reach_virtual_values[] = {
659    { 0,    "IsNotVirtual"},
660    { 1,    "IsVirtual"},
661    { 0, NULL }
662};
663
664static const struct tok isis_restart_flag_values[] = {
665    { 0x1,  "Restart Request"},
666    { 0x2,  "Restart Acknowledgement"},
667    { 0x4,  "Suppress adjacency advertisement"},
668    { 0, NULL }
669};
670
671struct isis_common_header {
672    nd_uint8_t nlpid;
673    nd_uint8_t fixed_len;
674    nd_uint8_t version;			/* Protocol version */
675    nd_uint8_t id_length;
676    nd_uint8_t pdu_type;		/* 3 MSbits are reserved */
677    nd_uint8_t pdu_version;		/* Packet format version */
678    nd_byte reserved;
679    nd_uint8_t max_area;
680};
681
682struct isis_iih_lan_header {
683    nd_uint8_t  circuit_type;
684    nd_byte     source_id[SYSTEM_ID_LEN];
685    nd_uint16_t holding_time;
686    nd_uint16_t pdu_len;
687    nd_uint8_t  priority;
688    nd_byte     lan_id[NODE_ID_LEN];
689};
690
691struct isis_iih_ptp_header {
692    nd_uint8_t  circuit_type;
693    nd_byte     source_id[SYSTEM_ID_LEN];
694    nd_uint16_t holding_time;
695    nd_uint16_t pdu_len;
696    nd_uint8_t  circuit_id;
697};
698
699struct isis_lsp_header {
700    nd_uint16_t pdu_len;
701    nd_uint16_t remaining_lifetime;
702    nd_byte     lsp_id[LSP_ID_LEN];
703    nd_uint32_t sequence_number;
704    nd_uint16_t checksum;
705    nd_uint8_t  typeblock;
706};
707
708struct isis_csnp_header {
709    nd_uint16_t pdu_len;
710    nd_byte     source_id[NODE_ID_LEN];
711    nd_byte     start_lsp_id[LSP_ID_LEN];
712    nd_byte     end_lsp_id[LSP_ID_LEN];
713};
714
715struct isis_psnp_header {
716    nd_uint16_t pdu_len;
717    nd_byte     source_id[NODE_ID_LEN];
718};
719
720struct isis_tlv_lsp {
721    nd_uint16_t remaining_lifetime;
722    nd_byte     lsp_id[LSP_ID_LEN];
723    nd_uint32_t sequence_number;
724    nd_uint16_t checksum;
725};
726
727#define ISIS_COMMON_HEADER_SIZE (sizeof(struct isis_common_header))
728#define ISIS_IIH_LAN_HEADER_SIZE (sizeof(struct isis_iih_lan_header))
729#define ISIS_IIH_PTP_HEADER_SIZE (sizeof(struct isis_iih_ptp_header))
730#define ISIS_LSP_HEADER_SIZE (sizeof(struct isis_lsp_header))
731#define ISIS_CSNP_HEADER_SIZE (sizeof(struct isis_csnp_header))
732#define ISIS_PSNP_HEADER_SIZE (sizeof(struct isis_psnp_header))
733
734void
735isoclns_print(netdissect_options *ndo, const u_char *p, u_int length)
736{
737	ndo->ndo_protocol = "isoclns";
738
739	if (ndo->ndo_eflag)
740		ND_PRINT("OSI NLPID %s (0x%02x): ",
741			 tok2str(nlpid_values, "Unknown", GET_U_1(p)),
742			 GET_U_1(p));
743
744	switch (GET_U_1(p)) {
745
746	case NLPID_CLNP:
747		if (!clnp_print(ndo, p, length))
748			print_unknown_data(ndo, p, "\n\t", length);
749		break;
750
751	case NLPID_ESIS:
752		esis_print(ndo, p, length);
753		return;
754
755	case NLPID_ISIS:
756		if (!isis_print(ndo, p, length))
757			print_unknown_data(ndo, p, "\n\t", length);
758		break;
759
760	case NLPID_NULLNS:
761		ND_PRINT("%slength: %u", ndo->ndo_eflag ? "" : ", ", length);
762		break;
763
764	case NLPID_Q933:
765		q933_print(ndo, p + 1, length - 1);
766		break;
767
768	case NLPID_IP:
769		ip_print(ndo, p + 1, length - 1);
770		break;
771
772	case NLPID_IP6:
773		ip6_print(ndo, p + 1, length - 1);
774		break;
775
776	case NLPID_PPP:
777		ppp_print(ndo, p + 1, length - 1);
778		break;
779
780	default:
781		if (!ndo->ndo_eflag)
782			ND_PRINT("OSI NLPID 0x%02x unknown", GET_U_1(p));
783		ND_PRINT("%slength: %u", ndo->ndo_eflag ? "" : ", ", length);
784		if (length > 1)
785			print_unknown_data(ndo, p, "\n\t", length);
786		break;
787	}
788}
789
790#define	CLNP_PDU_ER	 1
791#define	CLNP_PDU_DT	28
792#define	CLNP_PDU_MD	29
793#define	CLNP_PDU_ERQ	30
794#define	CLNP_PDU_ERP	31
795
796static const struct tok clnp_pdu_values[] = {
797    { CLNP_PDU_ER,  "Error Report"},
798    { CLNP_PDU_MD,  "MD"},
799    { CLNP_PDU_DT,  "Data"},
800    { CLNP_PDU_ERQ, "Echo Request"},
801    { CLNP_PDU_ERP, "Echo Response"},
802    { 0, NULL }
803};
804
805struct clnp_header_t {
806    nd_uint8_t  nlpid;
807    nd_uint8_t  length_indicator;
808    nd_uint8_t  version;
809    nd_uint8_t  lifetime; /* units of 500ms */
810    nd_uint8_t  type;
811    nd_uint16_t segment_length;
812    nd_uint16_t cksum;
813};
814
815struct clnp_segment_header_t {
816    nd_uint16_t data_unit_id;
817    nd_uint16_t segment_offset;
818    nd_uint16_t total_length;
819};
820
821/*
822 * clnp_print
823 * Decode CLNP packets.  Return 0 on error.
824 */
825
826static int
827clnp_print(netdissect_options *ndo,
828           const uint8_t *pptr, u_int length)
829{
830	const uint8_t *optr,*source_address,*dest_address;
831        u_int li,li_remaining,tlen,nsap_offset,source_address_length,dest_address_length, clnp_pdu_type, clnp_flags;
832	const struct clnp_header_t *clnp_header;
833	const struct clnp_segment_header_t *clnp_segment_header;
834        uint8_t rfd_error,rfd_error_major,rfd_error_minor;
835
836	ndo->ndo_protocol = "clnp";
837	clnp_header = (const struct clnp_header_t *) pptr;
838        ND_TCHECK_SIZE(clnp_header);
839
840        li = GET_U_1(clnp_header->length_indicator);
841        li_remaining = li;
842        optr = pptr;
843
844        if (!ndo->ndo_eflag)
845            nd_print_protocol_caps(ndo);
846
847        /*
848         * Sanity checking of the header.
849         */
850
851        if (GET_U_1(clnp_header->version) != CLNP_VERSION) {
852            ND_PRINT("version %u packet not supported",
853                     GET_U_1(clnp_header->version));
854            return (0);
855        }
856
857	if (li > length) {
858            ND_PRINT(" length indicator(%u) > PDU size (%u)!", li, length);
859            return (0);
860	}
861
862        if (li < sizeof(struct clnp_header_t)) {
863            ND_PRINT(" length indicator %u < min PDU size:", li);
864            while (pptr < ndo->ndo_snapend) {
865                ND_PRINT("%02X", GET_U_1(pptr));
866                pptr++;
867            }
868            return (0);
869        }
870
871        /* FIXME further header sanity checking */
872
873        clnp_pdu_type = GET_U_1(clnp_header->type) & CLNP_PDU_TYPE_MASK;
874        clnp_flags = GET_U_1(clnp_header->type) & CLNP_FLAG_MASK;
875
876        pptr += sizeof(struct clnp_header_t);
877        li_remaining -= sizeof(struct clnp_header_t);
878
879        if (li_remaining < 1) {
880            ND_PRINT("li < size of fixed part of CLNP header and addresses");
881            return (0);
882        }
883        dest_address_length = GET_U_1(pptr);
884        pptr += 1;
885        li_remaining -= 1;
886        if (li_remaining < dest_address_length) {
887            ND_PRINT("li < size of fixed part of CLNP header and addresses");
888            return (0);
889        }
890        ND_TCHECK_LEN(pptr, dest_address_length);
891        dest_address = pptr;
892        pptr += dest_address_length;
893        li_remaining -= dest_address_length;
894
895        if (li_remaining < 1) {
896            ND_PRINT("li < size of fixed part of CLNP header and addresses");
897            return (0);
898        }
899        source_address_length = GET_U_1(pptr);
900        pptr += 1;
901        li_remaining -= 1;
902        if (li_remaining < source_address_length) {
903            ND_PRINT("li < size of fixed part of CLNP header and addresses");
904            return (0);
905        }
906        ND_TCHECK_LEN(pptr, source_address_length);
907        source_address = pptr;
908        pptr += source_address_length;
909        li_remaining -= source_address_length;
910
911        if (ndo->ndo_vflag < 1) {
912            ND_PRINT("%s%s > %s, %s, length %u",
913                   ndo->ndo_eflag ? "" : ", ",
914                   GET_ISONSAP_STRING(source_address, source_address_length),
915                   GET_ISONSAP_STRING(dest_address, dest_address_length),
916                   tok2str(clnp_pdu_values,"unknown (%u)",clnp_pdu_type),
917                   length);
918            return (1);
919        }
920        ND_PRINT("%slength %u", ndo->ndo_eflag ? "" : ", ", length);
921
922        ND_PRINT("\n\t%s PDU, hlen: %u, v: %u, lifetime: %u.%us, Segment PDU length: %u, checksum: 0x%04x",
923               tok2str(clnp_pdu_values, "unknown (%u)",clnp_pdu_type),
924               GET_U_1(clnp_header->length_indicator),
925               GET_U_1(clnp_header->version),
926               GET_U_1(clnp_header->lifetime)/2,
927               (GET_U_1(clnp_header->lifetime)%2)*5,
928               GET_BE_U_2(clnp_header->segment_length),
929               GET_BE_U_2(clnp_header->cksum));
930
931        osi_print_cksum(ndo, optr, GET_BE_U_2(clnp_header->cksum), 7,
932                        GET_U_1(clnp_header->length_indicator));
933
934        ND_PRINT("\n\tFlags [%s]",
935               bittok2str(clnp_flag_values, "none", clnp_flags));
936
937        ND_PRINT("\n\tsource address (length %u): %s\n\tdest   address (length %u): %s",
938               source_address_length,
939               GET_ISONSAP_STRING(source_address, source_address_length),
940               dest_address_length,
941               GET_ISONSAP_STRING(dest_address, dest_address_length));
942
943        if (clnp_flags & CLNP_SEGMENT_PART) {
944                if (li_remaining < sizeof(struct clnp_segment_header_t)) {
945                    ND_PRINT("li < size of fixed part of CLNP header, addresses, and segment part");
946                    return (0);
947                }
948		clnp_segment_header = (const struct clnp_segment_header_t *) pptr;
949                ND_TCHECK_SIZE(clnp_segment_header);
950                ND_PRINT("\n\tData Unit ID: 0x%04x, Segment Offset: %u, Total PDU Length: %u",
951                       GET_BE_U_2(clnp_segment_header->data_unit_id),
952                       GET_BE_U_2(clnp_segment_header->segment_offset),
953                       GET_BE_U_2(clnp_segment_header->total_length));
954                pptr+=sizeof(struct clnp_segment_header_t);
955                li_remaining-=sizeof(struct clnp_segment_header_t);
956        }
957
958        /* now walk the options */
959        while (li_remaining != 0) {
960            u_int op, opli;
961            const uint8_t *tptr;
962
963            if (li_remaining < 2) {
964                ND_PRINT(", bad opts/li");
965                return (0);
966            }
967            op = GET_U_1(pptr);
968            opli = GET_U_1(pptr + 1);
969            pptr += 2;
970            li_remaining -= 2;
971            if (opli > li_remaining) {
972                ND_PRINT(", opt (%u) too long", op);
973                return (0);
974            }
975            ND_TCHECK_LEN(pptr, opli);
976            li_remaining -= opli;
977            tptr = pptr;
978            tlen = opli;
979
980            ND_PRINT("\n\t  %s Option #%u, length %u, value: ",
981                   tok2str(clnp_option_values,"Unknown",op),
982                   op,
983                   opli);
984
985            /*
986             * We've already checked that the entire option is present
987             * in the captured packet with the ND_TCHECK_LEN() call.
988             * Therefore, we don't need to do ND_TCHECK()/ND_TCHECK_LEN()
989             * checks.
990             * We do, however, need to check tlen, to make sure we
991             * don't run past the end of the option.
992	     */
993            switch (op) {
994
995
996            case CLNP_OPTION_ROUTE_RECORDING: /* those two options share the format */
997            case CLNP_OPTION_SOURCE_ROUTING:
998                    if (tlen < 2) {
999                            ND_PRINT(", bad opt len");
1000                            return (0);
1001                    }
1002                    ND_PRINT("%s %s",
1003                           tok2str(clnp_option_sr_rr_values,"Unknown",GET_U_1(tptr)),
1004                           tok2str(clnp_option_sr_rr_string_values, "Unknown Option %u", op));
1005                    nsap_offset=GET_U_1(tptr + 1);
1006                    if (nsap_offset == 0) {
1007                            ND_PRINT(" Bad NSAP offset (0)");
1008                            break;
1009                    }
1010                    nsap_offset-=1; /* offset to nsap list */
1011                    if (nsap_offset > tlen) {
1012                            ND_PRINT(" Bad NSAP offset (past end of option)");
1013                            break;
1014                    }
1015                    tptr+=nsap_offset;
1016                    tlen-=nsap_offset;
1017                    while (tlen > 0) {
1018                            source_address_length=GET_U_1(tptr);
1019                            if (tlen < source_address_length+1) {
1020                                    ND_PRINT("\n\t    NSAP address goes past end of option");
1021                                    break;
1022                            }
1023                            if (source_address_length > 0) {
1024                                    source_address=(tptr+1);
1025                                    ND_PRINT("\n\t    NSAP address (length %u): %s",
1026                                           source_address_length,
1027                                           GET_ISONSAP_STRING(source_address, source_address_length));
1028                            }
1029                            tlen-=source_address_length+1;
1030                    }
1031                    break;
1032
1033            case CLNP_OPTION_PRIORITY:
1034                    if (tlen < 1) {
1035                            ND_PRINT(", bad opt len");
1036                            return (0);
1037                    }
1038                    ND_PRINT("0x%1x", GET_U_1(tptr)&0x0f);
1039                    break;
1040
1041            case CLNP_OPTION_QOS_MAINTENANCE:
1042                    if (tlen < 1) {
1043                            ND_PRINT(", bad opt len");
1044                            return (0);
1045                    }
1046                    ND_PRINT("\n\t    Format Code: %s",
1047                           tok2str(clnp_option_scope_values, "Reserved", GET_U_1(tptr) & CLNP_OPTION_SCOPE_MASK));
1048
1049                    if ((GET_U_1(tptr)&CLNP_OPTION_SCOPE_MASK) == CLNP_OPTION_SCOPE_GLOBAL)
1050                            ND_PRINT("\n\t    QoS Flags [%s]",
1051                                   bittok2str(clnp_option_qos_global_values,
1052                                              "none",
1053                                              GET_U_1(tptr)&CLNP_OPTION_OPTION_QOS_MASK));
1054                    break;
1055
1056            case CLNP_OPTION_SECURITY:
1057                    if (tlen < 2) {
1058                            ND_PRINT(", bad opt len");
1059                            return (0);
1060                    }
1061                    ND_PRINT("\n\t    Format Code: %s, Security-Level %u",
1062                           tok2str(clnp_option_scope_values,"Reserved",GET_U_1(tptr)&CLNP_OPTION_SCOPE_MASK),
1063                           GET_U_1(tptr + 1));
1064                    break;
1065
1066            case CLNP_OPTION_DISCARD_REASON:
1067                if (tlen < 1) {
1068                        ND_PRINT(", bad opt len");
1069                        return (0);
1070                }
1071                rfd_error = GET_U_1(tptr);
1072                rfd_error_major = (rfd_error&0xf0) >> 4;
1073                rfd_error_minor = rfd_error&0x0f;
1074                ND_PRINT("\n\t    Class: %s Error (0x%01x), %s (0x%01x)",
1075                       tok2str(clnp_option_rfd_class_values,"Unknown",rfd_error_major),
1076                       rfd_error_major,
1077                       tok2str(clnp_option_rfd_error_class[rfd_error_major],"Unknown",rfd_error_minor),
1078                       rfd_error_minor);
1079                break;
1080
1081            case CLNP_OPTION_PADDING:
1082                    ND_PRINT("padding data");
1083                break;
1084
1085                /*
1086                 * FIXME those are the defined Options that lack a decoder
1087                 * you are welcome to contribute code ;-)
1088                 */
1089
1090            default:
1091                print_unknown_data(ndo, tptr, "\n\t  ", opli);
1092                break;
1093            }
1094            if (ndo->ndo_vflag > 1)
1095                print_unknown_data(ndo, pptr, "\n\t  ", opli);
1096            pptr += opli;
1097        }
1098
1099        switch (clnp_pdu_type) {
1100
1101        case    CLNP_PDU_ER: /* fall through */
1102        case	CLNP_PDU_ERP:
1103            if (GET_U_1(pptr) == NLPID_CLNP) {
1104                ND_PRINT("\n\t-----original packet-----\n\t");
1105                /* FIXME recursion protection */
1106                clnp_print(ndo, pptr, length - li);
1107                break;
1108            }
1109
1110        /* The cases above break from the switch block if they see and print
1111         * a CLNP header in the Data part. For an Error Report PDU this is
1112         * described in Section 7.9.6 of ITU X.233 (1997 E), also known as
1113         * ISO/IEC 8473-1:1998(E). It is not clear why in this code the same
1114         * applies to an Echo Response PDU, as the standard does not specify
1115         * the contents -- could be a proprietary extension or a bug. In either
1116         * case, if the Data part does not contain a CLNP header, its structure
1117         * is considered unknown and the decoding falls through to print the
1118         * contents as-is.
1119         */
1120        ND_FALL_THROUGH;
1121
1122        case	CLNP_PDU_DT:
1123        case	CLNP_PDU_MD:
1124        case	CLNP_PDU_ERQ:
1125
1126        default:
1127            /* dump the PDU specific data */
1128            if (length > ND_BYTES_BETWEEN(pptr, optr)) {
1129                ND_PRINT("\n\t  undecoded non-header data, length %u", length-li);
1130                print_unknown_data(ndo, pptr, "\n\t  ", length - ND_BYTES_BETWEEN(pptr, optr));
1131            }
1132        }
1133
1134        return (1);
1135
1136 trunc:
1137    nd_print_trunc(ndo);
1138    return (1);
1139
1140}
1141
1142
1143#define	ESIS_PDU_REDIRECT	6
1144#define	ESIS_PDU_ESH	        2
1145#define	ESIS_PDU_ISH	        4
1146
1147static const struct tok esis_pdu_values[] = {
1148    { ESIS_PDU_REDIRECT, "redirect"},
1149    { ESIS_PDU_ESH,      "ESH"},
1150    { ESIS_PDU_ISH,      "ISH"},
1151    { 0, NULL }
1152};
1153
1154struct esis_header_t {
1155	nd_uint8_t  nlpid;
1156	nd_uint8_t  length_indicator;
1157	nd_uint8_t  version;
1158	nd_byte     reserved;
1159	nd_uint8_t  type;
1160	nd_uint16_t holdtime;
1161	nd_uint16_t cksum;
1162};
1163
1164static void
1165esis_print(netdissect_options *ndo,
1166           const uint8_t *pptr, u_int length)
1167{
1168	const uint8_t *optr;
1169	u_int li, version, esis_pdu_type, source_address_length, source_address_number;
1170	const struct esis_header_t *esis_header;
1171
1172	ndo->ndo_protocol = "esis";
1173	if (!ndo->ndo_eflag)
1174		ND_PRINT("ES-IS");
1175
1176	if (length <= 2) {
1177		ND_PRINT(ndo->ndo_qflag ? "bad pkt!" : "no header at all!");
1178		return;
1179	}
1180
1181	esis_header = (const struct esis_header_t *) pptr;
1182        ND_TCHECK_SIZE(esis_header);
1183        li = GET_U_1(esis_header->length_indicator);
1184        optr = pptr;
1185
1186        /*
1187         * Sanity checking of the header.
1188         */
1189
1190        if (GET_U_1(esis_header->nlpid) != NLPID_ESIS) {
1191            ND_PRINT(" nlpid 0x%02x packet not supported",
1192		     GET_U_1(esis_header->nlpid));
1193            return;
1194        }
1195
1196        version = GET_U_1(esis_header->version);
1197        if (version != ESIS_VERSION) {
1198            ND_PRINT(" version %u packet not supported", version);
1199            return;
1200        }
1201
1202	if (li > length) {
1203            ND_PRINT(" length indicator(%u) > PDU size (%u)!", li, length);
1204            return;
1205	}
1206
1207	if (li < sizeof(struct esis_header_t) + 2) {
1208            ND_PRINT(" length indicator %u < min PDU size:", li);
1209            while (pptr < ndo->ndo_snapend) {
1210                ND_PRINT("%02X", GET_U_1(pptr));
1211                pptr++;
1212            }
1213            return;
1214	}
1215
1216        esis_pdu_type = GET_U_1(esis_header->type) & ESIS_PDU_TYPE_MASK;
1217
1218        if (ndo->ndo_vflag < 1) {
1219            ND_PRINT("%s%s, length %u",
1220                   ndo->ndo_eflag ? "" : ", ",
1221                   tok2str(esis_pdu_values,"unknown type (%u)",esis_pdu_type),
1222                   length);
1223            return;
1224        } else
1225            ND_PRINT("%slength %u\n\t%s (%u)",
1226                   ndo->ndo_eflag ? "" : ", ",
1227                   length,
1228                   tok2str(esis_pdu_values,"unknown type: %u", esis_pdu_type),
1229                   esis_pdu_type);
1230
1231        ND_PRINT(", v: %u%s", version, version == ESIS_VERSION ? "" : "unsupported" );
1232        ND_PRINT(", checksum: 0x%04x", GET_BE_U_2(esis_header->cksum));
1233
1234        osi_print_cksum(ndo, pptr, GET_BE_U_2(esis_header->cksum), 7,
1235                        li);
1236
1237        ND_PRINT(", holding time: %us, length indicator: %u",
1238                  GET_BE_U_2(esis_header->holdtime), li);
1239
1240        if (ndo->ndo_vflag > 1)
1241            print_unknown_data(ndo, optr, "\n\t", sizeof(struct esis_header_t));
1242
1243	pptr += sizeof(struct esis_header_t);
1244	li -= sizeof(struct esis_header_t);
1245
1246	switch (esis_pdu_type) {
1247	case ESIS_PDU_REDIRECT: {
1248		const uint8_t *dst, *snpa, *neta;
1249		u_int dstl, snpal, netal;
1250
1251		ND_TCHECK_1(pptr);
1252		if (li < 1) {
1253			ND_PRINT(", bad redirect/li");
1254			return;
1255		}
1256		dstl = GET_U_1(pptr);
1257		pptr++;
1258		li--;
1259		ND_TCHECK_LEN(pptr, dstl);
1260		if (li < dstl) {
1261			ND_PRINT(", bad redirect/li");
1262			return;
1263		}
1264		dst = pptr;
1265		pptr += dstl;
1266                li -= dstl;
1267		ND_PRINT("\n\t  %s", GET_ISONSAP_STRING(dst, dstl));
1268
1269		ND_TCHECK_1(pptr);
1270		if (li < 1) {
1271			ND_PRINT(", bad redirect/li");
1272			return;
1273		}
1274		snpal = GET_U_1(pptr);
1275		pptr++;
1276		li--;
1277		ND_TCHECK_LEN(pptr, snpal);
1278		if (li < snpal) {
1279			ND_PRINT(", bad redirect/li");
1280			return;
1281		}
1282		snpa = pptr;
1283		pptr += snpal;
1284                li -= snpal;
1285		ND_TCHECK_1(pptr);
1286		if (li < 1) {
1287			ND_PRINT(", bad redirect/li");
1288			return;
1289		}
1290		netal = GET_U_1(pptr);
1291		pptr++;
1292		ND_TCHECK_LEN(pptr, netal);
1293		if (li < netal) {
1294			ND_PRINT(", bad redirect/li");
1295			return;
1296		}
1297		neta = pptr;
1298		pptr += netal;
1299                li -= netal;
1300
1301		if (snpal == MAC_ADDR_LEN)
1302			ND_PRINT("\n\t  SNPA (length: %u): %s",
1303			       snpal,
1304			       GET_ETHERADDR_STRING(snpa));
1305		else
1306			ND_PRINT("\n\t  SNPA (length: %u): %s",
1307			       snpal,
1308			       GET_LINKADDR_STRING(snpa, LINKADDR_OTHER, snpal));
1309		if (netal != 0)
1310			ND_PRINT("\n\t  NET (length: %u) %s",
1311			       netal,
1312			       GET_ISONSAP_STRING(neta, netal));
1313		break;
1314	}
1315
1316	case ESIS_PDU_ESH:
1317            ND_TCHECK_1(pptr);
1318            if (li < 1) {
1319                ND_PRINT(", bad esh/li");
1320                return;
1321            }
1322            source_address_number = GET_U_1(pptr);
1323            pptr++;
1324            li--;
1325
1326            ND_PRINT("\n\t  Number of Source Addresses: %u", source_address_number);
1327
1328            while (source_address_number > 0) {
1329                ND_TCHECK_1(pptr);
1330		if (li < 1) {
1331                    ND_PRINT(", bad esh/li");
1332		    return;
1333		}
1334                source_address_length = GET_U_1(pptr);
1335                pptr++;
1336		li--;
1337
1338                ND_TCHECK_LEN(pptr, source_address_length);
1339		if (li < source_address_length) {
1340                    ND_PRINT(", bad esh/li");
1341		    return;
1342		}
1343                ND_PRINT("\n\t  NET (length: %u): %s",
1344                       source_address_length,
1345                       GET_ISONSAP_STRING(pptr, source_address_length));
1346                pptr += source_address_length;
1347                li -= source_address_length;
1348                source_address_number--;
1349            }
1350
1351            break;
1352
1353	case ESIS_PDU_ISH: {
1354            ND_TCHECK_1(pptr);
1355            if (li < 1) {
1356                ND_PRINT(", bad ish/li");
1357                return;
1358            }
1359            source_address_length = GET_U_1(pptr);
1360            pptr++;
1361            li--;
1362            ND_TCHECK_LEN(pptr, source_address_length);
1363            if (li < source_address_length) {
1364                ND_PRINT(", bad ish/li");
1365                return;
1366            }
1367            ND_PRINT("\n\t  NET (length: %u): %s", source_address_length, GET_ISONSAP_STRING(pptr, source_address_length));
1368            pptr += source_address_length;
1369            li -= source_address_length;
1370            break;
1371	}
1372
1373	default:
1374		if (ndo->ndo_vflag <= 1) {
1375			/*
1376			 * If there's at least one byte to print, print
1377			 * it/them.
1378			 */
1379			if (ND_TTEST_LEN(pptr, 1))
1380				print_unknown_data(ndo, pptr, "\n\t  ", ND_BYTES_AVAILABLE_AFTER(pptr));
1381		}
1382		return;
1383	}
1384
1385        /* now walk the options */
1386        while (li != 0) {
1387            u_int op, opli;
1388            const uint8_t *tptr;
1389
1390            if (li < 2) {
1391                ND_PRINT(", bad opts/li");
1392                return;
1393            }
1394            op = GET_U_1(pptr);
1395            opli = GET_U_1(pptr + 1);
1396            pptr += 2;
1397            li -= 2;
1398            if (opli > li) {
1399                ND_PRINT(", opt (%u) too long", op);
1400                return;
1401            }
1402            li -= opli;
1403            tptr = pptr;
1404
1405            ND_PRINT("\n\t  %s Option #%u, length %u, value: ",
1406                   tok2str(esis_option_values,"Unknown",op),
1407                   op,
1408                   opli);
1409
1410            switch (op) {
1411
1412            case ESIS_OPTION_ES_CONF_TIME:
1413                if (opli == 2) {
1414                    ND_TCHECK_2(pptr);
1415                    ND_PRINT("%us", GET_BE_U_2(tptr));
1416                } else
1417                    ND_PRINT("(bad length)");
1418                break;
1419
1420            case ESIS_OPTION_PROTOCOLS:
1421                while (opli>0) {
1422                    ND_PRINT("%s (0x%02x)",
1423                           tok2str(nlpid_values,
1424                                   "unknown",
1425                                   GET_U_1(tptr)),
1426                           GET_U_1(tptr));
1427                    if (opli>1) /* further NPLIDs ? - put comma */
1428                        ND_PRINT(", ");
1429                    tptr++;
1430                    opli--;
1431                }
1432                break;
1433
1434                /*
1435                 * FIXME those are the defined Options that lack a decoder
1436                 * you are welcome to contribute code ;-)
1437                 */
1438
1439            case ESIS_OPTION_QOS_MAINTENANCE:
1440            case ESIS_OPTION_SECURITY:
1441            case ESIS_OPTION_PRIORITY:
1442            case ESIS_OPTION_ADDRESS_MASK:
1443            case ESIS_OPTION_SNPA_MASK:
1444
1445            default:
1446                print_unknown_data(ndo, tptr, "\n\t  ", opli);
1447                break;
1448            }
1449            if (ndo->ndo_vflag > 1)
1450                print_unknown_data(ndo, pptr, "\n\t  ", opli);
1451            pptr += opli;
1452        }
1453        return;
1454
1455trunc:
1456	nd_print_trunc(ndo);
1457}
1458
1459static void
1460isis_print_mcid(netdissect_options *ndo,
1461                const struct isis_spb_mcid *mcid)
1462{
1463  int i;
1464
1465  ND_TCHECK_SIZE(mcid);
1466  ND_PRINT("ID: %u, Name: ", GET_U_1(mcid->format_id));
1467
1468  nd_printjnp(ndo, mcid->name, sizeof(mcid->name));
1469
1470  ND_PRINT("\n\t              Lvl: %u", GET_BE_U_2(mcid->revision_lvl));
1471
1472  ND_PRINT(", Digest: ");
1473
1474  for(i=0;i<16;i++)
1475    ND_PRINT("%.2x ", mcid->digest[i]);
1476  return;
1477
1478trunc:
1479  nd_print_trunc(ndo);
1480}
1481
1482static int
1483isis_print_mt_port_cap_subtlv(netdissect_options *ndo,
1484                              const uint8_t *tptr, u_int len)
1485{
1486  u_int stlv_type, stlv_len;
1487  const struct isis_subtlv_spb_mcid *subtlv_spb_mcid;
1488  int i;
1489
1490  while (len > 2)
1491  {
1492    stlv_type = GET_U_1(tptr);
1493    stlv_len  = GET_U_1(tptr + 1);
1494
1495    /* first lets see if we know the subTLVs name*/
1496    ND_PRINT("\n\t       %s subTLV #%u, length: %u",
1497               tok2str(isis_mt_port_cap_subtlv_values, "unknown", stlv_type),
1498               stlv_type,
1499               stlv_len);
1500
1501    tptr += 2;
1502    /*len -= TLV_TYPE_LEN_OFFSET;*/
1503    len -= 2;
1504
1505    /* Make sure the subTLV fits within the space left */
1506    if (len < stlv_len)
1507      goto subtlv_too_long;
1508    /* Make sure the entire subTLV is in the captured data */
1509    ND_TCHECK_LEN(tptr, stlv_len);
1510
1511    switch (stlv_type)
1512    {
1513      case ISIS_SUBTLV_SPB_MCID:
1514      {
1515	if (stlv_len < ISIS_SUBTLV_SPB_MCID_MIN_LEN)
1516          goto subtlv_too_short;
1517
1518        subtlv_spb_mcid = (const struct isis_subtlv_spb_mcid *)tptr;
1519
1520        ND_PRINT("\n\t         MCID: ");
1521        isis_print_mcid(ndo, &(subtlv_spb_mcid->mcid));
1522
1523          /*tptr += SPB_MCID_MIN_LEN;
1524            len -= SPB_MCID_MIN_LEN; */
1525
1526        ND_PRINT("\n\t         AUX-MCID: ");
1527        isis_print_mcid(ndo, &(subtlv_spb_mcid->aux_mcid));
1528
1529          /*tptr += SPB_MCID_MIN_LEN;
1530            len -= SPB_MCID_MIN_LEN; */
1531        tptr += ISIS_SUBTLV_SPB_MCID_MIN_LEN;
1532        len -= ISIS_SUBTLV_SPB_MCID_MIN_LEN;
1533        stlv_len -= ISIS_SUBTLV_SPB_MCID_MIN_LEN;
1534
1535        break;
1536      }
1537
1538      case ISIS_SUBTLV_SPB_DIGEST:
1539      {
1540        if (stlv_len < ISIS_SUBTLV_SPB_DIGEST_MIN_LEN)
1541          goto subtlv_too_short;
1542
1543        ND_PRINT("\n\t        RES: %u V: %u A: %u D: %u",
1544                        (GET_U_1(tptr) >> 5),
1545                        ((GET_U_1(tptr) >> 4) & 0x01),
1546                        ((GET_U_1(tptr) >> 2) & 0x03),
1547                        (GET_U_1(tptr) & 0x03));
1548
1549        tptr++;
1550
1551        ND_PRINT("\n\t         Digest: ");
1552
1553        for(i=1;i<=8; i++)
1554        {
1555            ND_PRINT("%08x ", GET_BE_U_4(tptr));
1556            if (i%4 == 0 && i != 8)
1557              ND_PRINT("\n\t                 ");
1558            tptr += 4;
1559        }
1560
1561        len -= ISIS_SUBTLV_SPB_DIGEST_MIN_LEN;
1562        stlv_len -= ISIS_SUBTLV_SPB_DIGEST_MIN_LEN;
1563
1564        break;
1565      }
1566
1567      case ISIS_SUBTLV_SPB_BVID:
1568      {
1569        while (stlv_len != 0)
1570        {
1571          if (stlv_len < 4)
1572            goto subtlv_too_short;
1573          ND_PRINT("\n\t           ECT: %08x",
1574                      GET_BE_U_4(tptr));
1575
1576          tptr += 4;
1577          len -= 4;
1578          stlv_len -= 4;
1579
1580          if (stlv_len < 2)
1581            goto subtlv_too_short;
1582          ND_PRINT(" BVID: %u, U:%01x M:%01x ",
1583                     (GET_BE_U_2(tptr) >> 4) ,
1584                     (GET_BE_U_2(tptr) >> 3) & 0x01,
1585                     (GET_BE_U_2(tptr) >> 2) & 0x01);
1586
1587          tptr += 2;
1588          len -= 2;
1589          stlv_len -= 2;
1590        }
1591
1592        break;
1593      }
1594
1595      default:
1596        break;
1597    }
1598    tptr += stlv_len;
1599    len -= stlv_len;
1600  }
1601  return (0);
1602
1603trunc:
1604  nd_print_trunc(ndo);
1605  return (1);
1606
1607subtlv_too_long:
1608  ND_PRINT(" (> containing TLV length)");
1609  return (1);
1610
1611subtlv_too_short:
1612  ND_PRINT(" (too short)");
1613  return (1);
1614}
1615
1616static int
1617isis_print_mt_capability_subtlv(netdissect_options *ndo,
1618                                const uint8_t *tptr, u_int len)
1619{
1620  u_int stlv_type, stlv_len, treecount;
1621
1622  while (len > 2)
1623  {
1624    stlv_type = GET_U_1(tptr);
1625    stlv_len  = GET_U_1(tptr + 1);
1626    tptr += 2;
1627    len -= 2;
1628
1629    /* first lets see if we know the subTLVs name*/
1630    ND_PRINT("\n\t      %s subTLV #%u, length: %u",
1631               tok2str(isis_mt_capability_subtlv_values, "unknown", stlv_type),
1632               stlv_type,
1633               stlv_len);
1634
1635    /* Make sure the subTLV fits within the space left */
1636    if (len < stlv_len)
1637      goto subtlv_too_long;
1638    /* Make sure the entire subTLV is in the captured data */
1639    ND_TCHECK_LEN(tptr, stlv_len);
1640
1641    switch (stlv_type)
1642    {
1643      case ISIS_SUBTLV_SPB_INSTANCE:
1644          if (stlv_len < ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN)
1645            goto subtlv_too_short;
1646
1647          ND_PRINT("\n\t        CIST Root-ID: %08x", GET_BE_U_4(tptr));
1648          tptr += 4;
1649          ND_PRINT(" %08x", GET_BE_U_4(tptr));
1650          tptr += 4;
1651          ND_PRINT(", Path Cost: %08x", GET_BE_U_4(tptr));
1652          tptr += 4;
1653          ND_PRINT(", Prio: %u", GET_BE_U_2(tptr));
1654          tptr += 2;
1655          ND_PRINT("\n\t        RES: %u",
1656                    GET_BE_U_2(tptr) >> 5);
1657          ND_PRINT(", V: %u",
1658                    (GET_BE_U_2(tptr) >> 4) & 0x0001);
1659          ND_PRINT(", SPSource-ID: %u",
1660                    (GET_BE_U_4(tptr) & 0x000fffff));
1661          tptr += 4;
1662          ND_PRINT(", No of Trees: %x", GET_U_1(tptr));
1663
1664          treecount = GET_U_1(tptr);
1665          tptr++;
1666
1667          len -= ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN;
1668          stlv_len -= ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN;
1669
1670          while (treecount)
1671          {
1672            if (stlv_len < ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN)
1673              goto trunc;
1674
1675            ND_PRINT("\n\t         U:%u, M:%u, A:%u, RES:%u",
1676                      GET_U_1(tptr) >> 7,
1677                      (GET_U_1(tptr) >> 6) & 0x01,
1678                      (GET_U_1(tptr) >> 5) & 0x01,
1679                      (GET_U_1(tptr) & 0x1f));
1680
1681            tptr++;
1682
1683            ND_PRINT(", ECT: %08x", GET_BE_U_4(tptr));
1684
1685            tptr += 4;
1686
1687            ND_PRINT(", BVID: %u, SPVID: %u",
1688                      (GET_BE_U_3(tptr) >> 12) & 0x000fff,
1689                      GET_BE_U_3(tptr) & 0x000fff);
1690
1691            tptr += 3;
1692            len -= ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN;
1693            stlv_len -= ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN;
1694            treecount--;
1695          }
1696
1697          break;
1698
1699      case ISIS_SUBTLV_SPBM_SI:
1700          if (stlv_len < 8)
1701            goto trunc;
1702
1703          ND_PRINT("\n\t        BMAC: %08x", GET_BE_U_4(tptr));
1704          tptr += 4;
1705          ND_PRINT("%04x", GET_BE_U_2(tptr));
1706          tptr += 2;
1707
1708          ND_PRINT(", RES: %u, VID: %u", GET_BE_U_2(tptr) >> 12,
1709                    (GET_BE_U_2(tptr)) & 0x0fff);
1710
1711          tptr += 2;
1712          len -= 8;
1713          stlv_len -= 8;
1714
1715          while (stlv_len >= 4) {
1716            ND_PRINT("\n\t        T: %u, R: %u, RES: %u, ISID: %u",
1717                    (GET_BE_U_4(tptr) >> 31),
1718                    (GET_BE_U_4(tptr) >> 30) & 0x01,
1719                    (GET_BE_U_4(tptr) >> 24) & 0x03f,
1720                    (GET_BE_U_4(tptr)) & 0x0ffffff);
1721
1722            tptr += 4;
1723            len -= 4;
1724            stlv_len -= 4;
1725          }
1726
1727        break;
1728
1729      default:
1730        break;
1731    }
1732    tptr += stlv_len;
1733    len -= stlv_len;
1734  }
1735  return (0);
1736
1737trunc:
1738  nd_print_trunc(ndo);
1739  return (1);
1740
1741subtlv_too_long:
1742  ND_PRINT(" (> containing TLV length)");
1743  return (1);
1744
1745subtlv_too_short:
1746  ND_PRINT(" (too short)");
1747  return (1);
1748}
1749
1750/* shared routine for printing system, node and lsp-ids */
1751static char *
1752isis_print_id(netdissect_options *ndo, const uint8_t *cp, u_int id_len)
1753{
1754    u_int i;
1755    static char id[sizeof("xxxx.xxxx.xxxx.yy-zz")];
1756    char *pos = id;
1757    u_int sysid_len;
1758
1759    sysid_len = SYSTEM_ID_LEN;
1760    if (sysid_len > id_len)
1761        sysid_len = id_len;
1762    for (i = 1; i <= sysid_len; i++) {
1763        snprintf(pos, sizeof(id) - (pos - id), "%02x", GET_U_1(cp));
1764	cp++;
1765	pos += strlen(pos);
1766	if (i == 2 || i == 4)
1767	    *pos++ = '.';
1768	}
1769    if (id_len >= NODE_ID_LEN) {
1770        snprintf(pos, sizeof(id) - (pos - id), ".%02x", GET_U_1(cp));
1771	cp++;
1772	pos += strlen(pos);
1773    }
1774    if (id_len == LSP_ID_LEN)
1775        snprintf(pos, sizeof(id) - (pos - id), "-%02x", GET_U_1(cp));
1776    return (id);
1777}
1778
1779/* print the 4-byte metric block which is common found in the old-style TLVs */
1780static int
1781isis_print_metric_block(netdissect_options *ndo,
1782                        const struct isis_metric_block *isis_metric_block)
1783{
1784    ND_PRINT(", Default Metric: %u, %s",
1785           ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_default),
1786           ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_default) ? "External" : "Internal");
1787    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_delay))
1788        ND_PRINT("\n\t\t  Delay Metric: %u, %s",
1789               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_delay),
1790               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_delay) ? "External" : "Internal");
1791    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_expense))
1792        ND_PRINT("\n\t\t  Expense Metric: %u, %s",
1793               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_expense),
1794               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_expense) ? "External" : "Internal");
1795    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_error))
1796        ND_PRINT("\n\t\t  Error Metric: %u, %s",
1797               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_error),
1798               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_error) ? "External" : "Internal");
1799
1800    return(1); /* everything is ok */
1801}
1802
1803static int
1804isis_print_tlv_ip_reach(netdissect_options *ndo,
1805                        const uint8_t *cp, const char *ident, u_int length)
1806{
1807	int prefix_len;
1808	const struct isis_tlv_ip_reach *tlv_ip_reach;
1809
1810	tlv_ip_reach = (const struct isis_tlv_ip_reach *)cp;
1811
1812	while (length > 0) {
1813		if ((size_t)length < sizeof(*tlv_ip_reach)) {
1814			ND_PRINT("short IPv4 Reachability (%u vs %zu)",
1815                               length,
1816                               sizeof(*tlv_ip_reach));
1817			return (0);
1818		}
1819
1820		ND_TCHECK_SIZE(tlv_ip_reach);
1821
1822		prefix_len = mask2plen(GET_IPV4_TO_HOST_ORDER(tlv_ip_reach->mask));
1823
1824		if (prefix_len == -1)
1825			ND_PRINT("%sIPv4 prefix: %s mask %s",
1826                               ident,
1827			       GET_IPADDR_STRING(tlv_ip_reach->prefix),
1828			       GET_IPADDR_STRING(tlv_ip_reach->mask));
1829		else
1830			ND_PRINT("%sIPv4 prefix: %15s/%u",
1831                               ident,
1832			       GET_IPADDR_STRING(tlv_ip_reach->prefix),
1833			       prefix_len);
1834
1835		ND_PRINT(", Distribution: %s, Metric: %u, %s",
1836                       ISIS_LSP_TLV_METRIC_UPDOWN(tlv_ip_reach->isis_metric_block.metric_default) ? "down" : "up",
1837                       ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_default),
1838                       ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_default) ? "External" : "Internal");
1839
1840		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_delay))
1841                    ND_PRINT("%s  Delay Metric: %u, %s",
1842                           ident,
1843                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_delay),
1844                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_delay) ? "External" : "Internal");
1845
1846		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_expense))
1847                    ND_PRINT("%s  Expense Metric: %u, %s",
1848                           ident,
1849                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_expense),
1850                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_expense) ? "External" : "Internal");
1851
1852		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_error))
1853                    ND_PRINT("%s  Error Metric: %u, %s",
1854                           ident,
1855                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_error),
1856                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_error) ? "External" : "Internal");
1857
1858		length -= sizeof(struct isis_tlv_ip_reach);
1859		tlv_ip_reach++;
1860	}
1861	return (1);
1862trunc:
1863	return 0;
1864}
1865
1866/*
1867 * this is the common IP-REACH subTLV decoder it is called
1868 * from various EXTD-IP REACH TLVs (135,235,236,237)
1869 */
1870
1871static int
1872isis_print_ip_reach_subtlv(netdissect_options *ndo,
1873                           const uint8_t *tptr, u_int subt, u_int subl,
1874                           const char *ident)
1875{
1876    /* first lets see if we know the subTLVs name*/
1877    ND_PRINT("%s%s subTLV #%u, length: %u",
1878              ident, tok2str(isis_ext_ip_reach_subtlv_values, "unknown", subt),
1879              subt, subl);
1880
1881    ND_TCHECK_LEN(tptr, subl);
1882
1883    switch(subt) {
1884    case ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR: /* fall through */
1885    case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32:
1886        while (subl >= 4) {
1887	    ND_PRINT(", 0x%08x (=%u)",
1888		   GET_BE_U_4(tptr),
1889		   GET_BE_U_4(tptr));
1890	    tptr+=4;
1891	    subl-=4;
1892	}
1893	break;
1894    case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64:
1895        while (subl >= 8) {
1896	    ND_PRINT(", 0x%08x%08x",
1897		   GET_BE_U_4(tptr),
1898		   GET_BE_U_4(tptr + 4));
1899	    tptr+=8;
1900	    subl-=8;
1901	}
1902	break;
1903    case ISIS_SUBTLV_EXTD_IP_REACH_PREFIX_SID:
1904	{
1905	    uint8_t algo, flags;
1906	    uint32_t sid;
1907
1908	    flags = GET_U_1(tptr);
1909	    algo = GET_U_1(tptr+1);
1910
1911	    if (flags & ISIS_PREFIX_SID_FLAG_V) {
1912	        if (subl < 5)
1913	            goto trunc;
1914		sid = GET_BE_U_3(tptr+2);
1915		tptr+=5;
1916		subl-=5;
1917	    } else {
1918	        if (subl < 6)
1919	            goto trunc;
1920		sid = GET_BE_U_4(tptr+2);
1921		tptr+=6;
1922		subl-=6;
1923	    }
1924
1925	    ND_PRINT(", Flags [%s], Algo %s (%u), %s %u",
1926		     bittok2str(prefix_sid_flag_values, "None", flags),
1927		     tok2str(prefix_sid_algo_values, "Unknown", algo), algo,
1928		     flags & ISIS_PREFIX_SID_FLAG_V ? "label" : "index",
1929		     sid);
1930	}
1931	break;
1932    default:
1933	if (!print_unknown_data(ndo, tptr, "\n\t\t    ", subl))
1934	  return(0);
1935	break;
1936    }
1937    return(1);
1938
1939trunc:
1940    nd_print_trunc(ndo);
1941    return(0);
1942}
1943
1944/*
1945 * this is the common IS-REACH decoder it is called
1946 * from various EXTD-IS REACH style TLVs (22,24,222)
1947 */
1948
1949static int
1950isis_print_ext_is_reach(netdissect_options *ndo,
1951                        const uint8_t *tptr, const char *ident, u_int tlv_type,
1952                        u_int tlv_remaining)
1953{
1954    char ident_buffer[20];
1955    u_int subtlv_type,subtlv_len,subtlv_sum_len;
1956    int proc_bytes = 0; /* how many bytes did we process ? */
1957    u_int te_class,priority_level,gmpls_switch_cap;
1958    union { /* int to float conversion buffer for several subTLVs */
1959        float f;
1960        uint32_t i;
1961    } bw;
1962
1963    ND_TCHECK_LEN(tptr, NODE_ID_LEN);
1964    if (tlv_remaining < NODE_ID_LEN)
1965        return(0);
1966
1967    ND_PRINT("%sIS Neighbor: %s", ident, isis_print_id(ndo, tptr, NODE_ID_LEN));
1968    tptr+=NODE_ID_LEN;
1969    tlv_remaining-=NODE_ID_LEN;
1970    proc_bytes+=NODE_ID_LEN;
1971
1972    if (tlv_type != ISIS_TLV_IS_ALIAS_ID) { /* the Alias TLV Metric field is implicit 0 */
1973        ND_TCHECK_3(tptr);
1974	if (tlv_remaining < 3)
1975	    return(0);
1976	ND_PRINT(", Metric: %u", GET_BE_U_3(tptr));
1977	tptr+=3;
1978	tlv_remaining-=3;
1979	proc_bytes+=3;
1980    }
1981
1982    ND_TCHECK_1(tptr);
1983    if (tlv_remaining < 1)
1984        return(0);
1985    subtlv_sum_len=GET_U_1(tptr); /* read out subTLV length */
1986    tptr++;
1987    tlv_remaining--;
1988    proc_bytes++;
1989    ND_PRINT(", %ssub-TLVs present",subtlv_sum_len ? "" : "no ");
1990    if (subtlv_sum_len) {
1991        ND_PRINT(" (%u)", subtlv_sum_len);
1992        /* prepend the indent string */
1993        snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
1994        ident = ident_buffer;
1995        while (subtlv_sum_len != 0) {
1996            ND_TCHECK_2(tptr);
1997            if (tlv_remaining < 2) {
1998                ND_PRINT("%sRemaining data in TLV shorter than a subTLV header",ident);
1999                proc_bytes += tlv_remaining;
2000                break;
2001            }
2002            if (subtlv_sum_len < 2) {
2003                ND_PRINT("%sRemaining data in subTLVs shorter than a subTLV header",ident);
2004                proc_bytes += subtlv_sum_len;
2005                break;
2006            }
2007            subtlv_type=GET_U_1(tptr);
2008            subtlv_len=GET_U_1(tptr + 1);
2009            tptr += 2;
2010            tlv_remaining -= 2;
2011            subtlv_sum_len -= 2;
2012            proc_bytes += 2;
2013            ND_PRINT("%s%s subTLV #%u, length: %u",
2014                      ident, tok2str(isis_ext_is_reach_subtlv_values, "unknown", subtlv_type),
2015                      subtlv_type, subtlv_len);
2016
2017            if (subtlv_sum_len < subtlv_len) {
2018                ND_PRINT(" (remaining data in subTLVs shorter than the current subTLV)");
2019                proc_bytes += subtlv_sum_len;
2020                break;
2021            }
2022
2023            if (tlv_remaining < subtlv_len) {
2024                ND_PRINT(" (> remaining tlv length)");
2025                proc_bytes += tlv_remaining;
2026                break;
2027            }
2028
2029            ND_TCHECK_LEN(tptr, subtlv_len);
2030
2031            switch(subtlv_type) {
2032            case ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP:
2033            case ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID:
2034            case ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID:
2035                if (subtlv_len >= 4) {
2036                    ND_PRINT(", 0x%08x", GET_BE_U_4(tptr));
2037                    if (subtlv_len == 8) /* rfc4205 */
2038                        ND_PRINT(", 0x%08x", GET_BE_U_4(tptr + 4));
2039                }
2040                break;
2041            case ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR:
2042            case ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR:
2043                if (subtlv_len >= sizeof(nd_ipv4))
2044                    ND_PRINT(", %s", GET_IPADDR_STRING(tptr));
2045                break;
2046            case ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW :
2047            case ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW:
2048                if (subtlv_len >= 4) {
2049                    bw.i = GET_BE_U_4(tptr);
2050                    ND_PRINT(", %.3f Mbps", bw.f * 8 / 1000000);
2051                }
2052                break;
2053            case ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW :
2054                if (subtlv_len >= 32) {
2055                    for (te_class = 0; te_class < 8; te_class++) {
2056                        bw.i = GET_BE_U_4(tptr);
2057                        ND_PRINT("%s  TE-Class %u: %.3f Mbps",
2058                                  ident,
2059                                  te_class,
2060                                  bw.f * 8 / 1000000);
2061                        tptr += 4;
2062                        subtlv_len -= 4;
2063                        subtlv_sum_len -= 4;
2064                        proc_bytes += 4;
2065                    }
2066                }
2067                break;
2068            case ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS: /* fall through */
2069            case ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD:
2070                if (subtlv_len == 0)
2071                    break;
2072                ND_PRINT("%sBandwidth Constraints Model ID: %s (%u)",
2073                          ident,
2074                          tok2str(diffserv_te_bc_values, "unknown", GET_U_1(tptr)),
2075                          GET_U_1(tptr));
2076                tptr++;
2077                subtlv_len--;
2078                subtlv_sum_len--;
2079                proc_bytes++;
2080                /* decode BCs until the subTLV ends */
2081                for (te_class = 0; subtlv_len != 0; te_class++) {
2082                    if (subtlv_len < 4)
2083                        break;
2084                    bw.i = GET_BE_U_4(tptr);
2085                    ND_PRINT("%s  Bandwidth constraint CT%u: %.3f Mbps",
2086                              ident,
2087                              te_class,
2088                              bw.f * 8 / 1000000);
2089                    tptr += 4;
2090                    subtlv_len -= 4;
2091                    subtlv_sum_len -= 4;
2092                    proc_bytes += 4;
2093                }
2094                break;
2095            case ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC:
2096                if (subtlv_len >= 3)
2097                    ND_PRINT(", %u", GET_BE_U_3(tptr));
2098                break;
2099            case ISIS_SUBTLV_EXT_IS_REACH_LINK_ATTRIBUTE:
2100                if (subtlv_len == 2) {
2101                    ND_PRINT(", [ %s ] (0x%04x)",
2102                              bittok2str(isis_subtlv_link_attribute_values,
2103                                         "Unknown",
2104                                         GET_BE_U_2(tptr)),
2105                              GET_BE_U_2(tptr));
2106                }
2107                break;
2108            case ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE:
2109                if (subtlv_len >= 2) {
2110                    ND_PRINT(", %s, Priority %u",
2111                              bittok2str(gmpls_link_prot_values, "none", GET_U_1(tptr)),
2112                              GET_U_1(tptr + 1));
2113                }
2114                break;
2115            case ISIS_SUBTLV_SPB_METRIC:
2116                if (subtlv_len >= 6) {
2117                    ND_PRINT(", LM: %u", GET_BE_U_3(tptr));
2118                    tptr += 3;
2119                    subtlv_len -= 3;
2120                    subtlv_sum_len -= 3;
2121                    proc_bytes += 3;
2122                    ND_PRINT(", P: %u", GET_U_1(tptr));
2123                    tptr++;
2124                    subtlv_len--;
2125                    subtlv_sum_len--;
2126                    proc_bytes++;
2127                    ND_PRINT(", P-ID: %u", GET_BE_U_2(tptr));
2128                }
2129                break;
2130            case ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR:
2131                if (subtlv_len >= 36) {
2132                    gmpls_switch_cap = GET_U_1(tptr);
2133                    ND_PRINT("%s  Interface Switching Capability:%s",
2134                              ident,
2135                              tok2str(gmpls_switch_cap_values, "Unknown", gmpls_switch_cap));
2136                    ND_PRINT(", LSP Encoding: %s",
2137                              tok2str(gmpls_encoding_values, "Unknown", GET_U_1((tptr + 1))));
2138                    tptr += 4;
2139                    subtlv_len -= 4;
2140                    subtlv_sum_len -= 4;
2141                    proc_bytes += 4;
2142                    ND_PRINT("%s  Max LSP Bandwidth:", ident);
2143                    for (priority_level = 0; priority_level < 8; priority_level++) {
2144                        bw.i = GET_BE_U_4(tptr);
2145                        ND_PRINT("%s    priority level %u: %.3f Mbps",
2146                                  ident,
2147                                  priority_level,
2148                                  bw.f * 8 / 1000000);
2149                        tptr += 4;
2150                        subtlv_len -= 4;
2151                        subtlv_sum_len -= 4;
2152                        proc_bytes += 4;
2153                    }
2154                    switch (gmpls_switch_cap) {
2155                    case GMPLS_PSC1:
2156                    case GMPLS_PSC2:
2157                    case GMPLS_PSC3:
2158                    case GMPLS_PSC4:
2159                        if (subtlv_len < 6)
2160                            break;
2161                        bw.i = GET_BE_U_4(tptr);
2162                        ND_PRINT("%s  Min LSP Bandwidth: %.3f Mbps", ident, bw.f * 8 / 1000000);
2163                        ND_PRINT("%s  Interface MTU: %u", ident,
2164                                 GET_BE_U_2(tptr + 4));
2165                        break;
2166                    case GMPLS_TSC:
2167                        if (subtlv_len < 8)
2168                            break;
2169                        bw.i = GET_BE_U_4(tptr);
2170                        ND_PRINT("%s  Min LSP Bandwidth: %.3f Mbps", ident, bw.f * 8 / 1000000);
2171                        ND_PRINT("%s  Indication %s", ident,
2172                                  tok2str(gmpls_switch_cap_tsc_indication_values, "Unknown (%u)", GET_U_1((tptr + 4))));
2173                        break;
2174                    default:
2175                        /* there is some optional stuff left to decode but this is as of yet
2176                           not specified so just lets hexdump what is left */
2177                        if (subtlv_len != 0) {
2178                            if (!print_unknown_data(ndo, tptr, "\n\t\t    ", subtlv_len))
2179                                return(0);
2180                        }
2181                    }
2182                }
2183                break;
2184            case ISIS_SUBTLV_EXT_IS_REACH_LAN_ADJ_SEGMENT_ID:
2185                if (subtlv_len >= 8) {
2186                    ND_PRINT("%s  Flags: [%s]", ident,
2187                              bittok2str(isis_lan_adj_sid_flag_values,
2188                                         "none",
2189                                         GET_U_1(tptr)));
2190                    int vflag = (GET_U_1(tptr) & 0x20) ? 1:0;
2191                    int lflag = (GET_U_1(tptr) & 0x10) ? 1:0;
2192                    tptr++;
2193                    subtlv_len--;
2194                    subtlv_sum_len--;
2195                    proc_bytes++;
2196                    ND_PRINT("%s  Weight: %u", ident, GET_U_1(tptr));
2197                    tptr++;
2198                    subtlv_len--;
2199                    subtlv_sum_len--;
2200                    proc_bytes++;
2201                    if(subtlv_len>=SYSTEM_ID_LEN) {
2202                        ND_TCHECK_LEN(tptr, SYSTEM_ID_LEN);
2203                        ND_PRINT("%s  Neighbor System-ID: %s", ident,
2204                            isis_print_id(ndo, tptr, SYSTEM_ID_LEN));
2205                    }
2206                    /* RFC 8667 section 2.2.2 */
2207                    /* if V-flag is set to 1 and L-flag is set to 1 ==> 3 octet label */
2208                    /* if V-flag is set to 0 and L-flag is set to 0 ==> 4 octet index */
2209                    if (vflag && lflag) {
2210                        ND_PRINT("%s  Label: %u",
2211                                  ident, GET_BE_U_3(tptr+SYSTEM_ID_LEN));
2212                    } else if ((!vflag) && (!lflag)) {
2213                        ND_PRINT("%s  Index: %u",
2214                                  ident, GET_BE_U_4(tptr+SYSTEM_ID_LEN));
2215                    } else
2216                        nd_print_invalid(ndo);
2217                }
2218                break;
2219            default:
2220                if (!print_unknown_data(ndo, tptr, "\n\t\t    ", subtlv_len))
2221                    return(0);
2222                break;
2223            }
2224
2225            tptr += subtlv_len;
2226            tlv_remaining -= subtlv_len;
2227            subtlv_sum_len -= subtlv_len;
2228            proc_bytes += subtlv_len;
2229        }
2230    }
2231    return(proc_bytes);
2232
2233trunc:
2234    return(0);
2235}
2236
2237/*
2238 * this is the common Multi Topology ID decoder
2239 * it is called from various MT-TLVs (222,229,235,237)
2240 */
2241
2242static uint8_t
2243isis_print_mtid(netdissect_options *ndo,
2244                const uint8_t *tptr, const char *ident, u_int tlv_remaining)
2245{
2246    if (tlv_remaining < 2)
2247        goto trunc;
2248
2249    ND_PRINT("%s%s",
2250           ident,
2251           tok2str(isis_mt_values,
2252                   "Reserved for IETF Consensus",
2253                   ISIS_MASK_MTID(GET_BE_U_2(tptr))));
2254
2255    ND_PRINT(" Topology (0x%03x), Flags: [%s]",
2256           ISIS_MASK_MTID(GET_BE_U_2(tptr)),
2257           bittok2str(isis_mt_flag_values, "none",ISIS_MASK_MTFLAGS(GET_BE_U_2(tptr))));
2258
2259    return(2);
2260trunc:
2261    return 0;
2262}
2263
2264/*
2265 * this is the common extended IP reach decoder
2266 * it is called from TLVs (135,235,236,237)
2267 * we process the TLV and optional subTLVs and return
2268 * the amount of processed bytes
2269 */
2270
2271static u_int
2272isis_print_extd_ip_reach(netdissect_options *ndo,
2273                         const uint8_t *tptr, const char *ident, uint16_t afi)
2274{
2275    char ident_buffer[20];
2276    uint8_t prefix[sizeof(nd_ipv6)]; /* shared copy buffer for IPv4 and IPv6 prefixes */
2277    u_int metric, status_byte, bit_length, byte_length, sublen, processed, subtlvtype, subtlvlen;
2278
2279    metric = GET_BE_U_4(tptr);
2280    processed=4;
2281    tptr+=4;
2282
2283    if (afi == AF_INET) {
2284        status_byte=GET_U_1(tptr);
2285        tptr++;
2286        bit_length = status_byte&0x3f;
2287        if (bit_length > 32) {
2288            ND_PRINT("%sIPv4 prefix: bad bit length %u",
2289                   ident,
2290                   bit_length);
2291            return (0);
2292        }
2293        processed++;
2294    } else if (afi == AF_INET6) {
2295        status_byte=GET_U_1(tptr);
2296        bit_length=GET_U_1(tptr + 1);
2297        if (bit_length > 128) {
2298            ND_PRINT("%sIPv6 prefix: bad bit length %u",
2299                   ident,
2300                   bit_length);
2301            return (0);
2302        }
2303        tptr+=2;
2304        processed+=2;
2305    } else
2306        return (0); /* somebody is fooling us */
2307
2308    byte_length = (bit_length + 7) / 8; /* prefix has variable length encoding */
2309
2310    memset(prefix, 0, sizeof(prefix));   /* clear the copy buffer */
2311    GET_CPY_BYTES(prefix,tptr,byte_length);    /* copy as much as is stored in the TLV */
2312    tptr+=byte_length;
2313    processed+=byte_length;
2314
2315    if (afi == AF_INET)
2316        ND_PRINT("%sIPv4 prefix: %15s/%u",
2317               ident,
2318               ipaddr_string(ndo, prefix), /* local buffer, not packet data; don't use GET_IPADDR_STRING() */
2319               bit_length);
2320    else if (afi == AF_INET6)
2321        ND_PRINT("%sIPv6 prefix: %s/%u",
2322               ident,
2323               ip6addr_string(ndo, prefix), /* local buffer, not packet data; don't use GET_IP6ADDR_STRING() */
2324               bit_length);
2325
2326    ND_PRINT(", Distribution: %s, Metric: %u",
2327           ISIS_MASK_TLV_EXTD_IP_UPDOWN(status_byte) ? "down" : "up",
2328           metric);
2329
2330    if (afi == AF_INET && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
2331        ND_PRINT(", sub-TLVs present");
2332    else if (afi == AF_INET6)
2333        ND_PRINT(", %s%s",
2334               ISIS_MASK_TLV_EXTD_IP6_IE(status_byte) ? "External" : "Internal",
2335               ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) ? ", sub-TLVs present" : "");
2336
2337    if ((afi == AF_INET  && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
2338     || (afi == AF_INET6 && ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte))
2339            ) {
2340        /* assume that one prefix can hold more
2341           than one subTLV - therefore the first byte must reflect
2342           the aggregate bytecount of the subTLVs for this prefix
2343        */
2344        sublen=GET_U_1(tptr);
2345        tptr++;
2346        processed+=sublen+1;
2347        ND_PRINT(" (%u)", sublen);   /* print out subTLV length */
2348
2349        while (sublen>0) {
2350            subtlvtype=GET_U_1(tptr);
2351            subtlvlen=GET_U_1(tptr + 1);
2352            tptr+=2;
2353            /* prepend the indent string */
2354            snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
2355            if (!isis_print_ip_reach_subtlv(ndo, tptr, subtlvtype, subtlvlen, ident_buffer))
2356                return(0);
2357            tptr+=subtlvlen;
2358            sublen-=(subtlvlen+2);
2359        }
2360    }
2361    return (processed);
2362}
2363
2364static void
2365isis_print_router_cap_subtlv(netdissect_options *ndo, const uint8_t *tptr, uint8_t tlen)
2366{
2367    uint8_t subt, subl;
2368
2369    while (tlen >= 2) {
2370	subt = GET_U_1(tptr);
2371	subl = GET_U_1(tptr+1);
2372	tlen -= 2;
2373	tptr += 2;
2374
2375	/* first lets see if we know the subTLVs name*/
2376	ND_PRINT("\n\t\t%s subTLV #%u, length: %u",
2377              tok2str(isis_router_capability_subtlv_values, "unknown", subt),
2378              subt, subl);
2379
2380	/*
2381	 * Boundary check.
2382	 */
2383	if (subl > tlen) {
2384	    break;
2385	}
2386	ND_TCHECK_LEN(tptr, subl);
2387
2388	switch (subt) {
2389	case ISIS_SUBTLV_ROUTER_CAP_SR:
2390	    {
2391		uint8_t flags, sid_tlen, sid_type, sid_len;
2392		uint32_t range;
2393		const uint8_t *sid_ptr;
2394
2395		flags = GET_U_1(tptr);
2396		range = GET_BE_U_3(tptr+1);
2397		ND_PRINT(", Flags [%s], Range %u",
2398			 bittok2str(isis_router_capability_sr_flags, "None", flags),
2399			 range);
2400		sid_ptr = tptr + 4;
2401		sid_tlen = subl - 4;
2402
2403		while (sid_tlen >= 5) {
2404		    sid_type = GET_U_1(sid_ptr);
2405		    sid_len = GET_U_1(sid_ptr+1);
2406		    sid_tlen -= 2;
2407		    sid_ptr += 2;
2408
2409		    /*
2410		     * Boundary check.
2411		     */
2412		    if (sid_len > sid_tlen) {
2413			break;
2414		    }
2415
2416		    switch (sid_type) {
2417		    case 1:
2418			if (sid_len == 3) {
2419			    ND_PRINT(", SID value %u", GET_BE_U_3(sid_ptr));
2420			} else if (sid_len == 4) {
2421			    ND_PRINT(", SID value %u", GET_BE_U_4(sid_ptr));
2422			} else {
2423			    ND_PRINT(", Unknown SID length%u", sid_len);
2424			}
2425			break;
2426		    default:
2427			print_unknown_data(ndo, sid_ptr, "\n\t\t  ", sid_len);
2428		    }
2429
2430		    sid_ptr += sid_len;
2431		    sid_tlen -= sid_len;
2432		}
2433	    }
2434	    break;
2435	default:
2436	    print_unknown_data(ndo, tptr, "\n\t\t", subl);
2437	    break;
2438	}
2439
2440	tlen -= subl;
2441	tptr += subl;
2442    }
2443 trunc:
2444    return;
2445}
2446
2447/*
2448 * Clear checksum and lifetime prior to signature verification.
2449 */
2450static void
2451isis_clear_checksum_lifetime(void *header)
2452{
2453    struct isis_lsp_header *header_lsp = (struct isis_lsp_header *) header;
2454
2455    header_lsp->checksum[0] = 0;
2456    header_lsp->checksum[1] = 0;
2457    header_lsp->remaining_lifetime[0] = 0;
2458    header_lsp->remaining_lifetime[1] = 0;
2459}
2460
2461/*
2462 * isis_print
2463 * Decode IS-IS packets.  Return 0 on error.
2464 */
2465
2466#define INVALID_OR_DECREMENT(length,decr) \
2467    if ((length) < (decr)) { \
2468        ND_PRINT(" [packet length %u < %zu]", (length), (decr)); \
2469        nd_print_invalid(ndo); \
2470        return 1; \
2471    } \
2472    length -= (decr);
2473
2474static int
2475isis_print(netdissect_options *ndo,
2476           const uint8_t *p, u_int length)
2477{
2478    const struct isis_common_header *isis_header;
2479
2480    const struct isis_iih_lan_header *header_iih_lan;
2481    const struct isis_iih_ptp_header *header_iih_ptp;
2482    const struct isis_lsp_header *header_lsp;
2483    const struct isis_csnp_header *header_csnp;
2484    const struct isis_psnp_header *header_psnp;
2485
2486    const struct isis_tlv_lsp *tlv_lsp;
2487    const struct isis_tlv_ptp_adj *tlv_ptp_adj;
2488    const struct isis_tlv_is_reach *tlv_is_reach;
2489    const struct isis_tlv_es_reach *tlv_es_reach;
2490
2491    uint8_t version, pdu_version, fixed_len;
2492    uint8_t pdu_type, pdu_max_area, max_area, pdu_id_length, id_length, tlv_type, tlv_len, tlen, alen, prefix_len;
2493    u_int ext_is_len, ext_ip_len;
2494    uint8_t mt_len;
2495    uint8_t isis_subtlv_idrp;
2496    const uint8_t *optr, *pptr, *tptr;
2497    u_int packet_len;
2498    u_short pdu_len, key_id;
2499    u_int i,vendor_id, num_vals;
2500    uint8_t auth_type;
2501    uint8_t num_system_ids;
2502    int sigcheck;
2503
2504    ndo->ndo_protocol = "isis";
2505    packet_len=length;
2506    optr = p; /* initialize the _o_riginal pointer to the packet start -
2507                 need it for parsing the checksum TLV and authentication
2508                 TLV verification */
2509    isis_header = (const struct isis_common_header *)p;
2510    ND_TCHECK_SIZE(isis_header);
2511    if (length < ISIS_COMMON_HEADER_SIZE)
2512        goto trunc;
2513    pptr = p+(ISIS_COMMON_HEADER_SIZE);
2514    header_iih_lan = (const struct isis_iih_lan_header *)pptr;
2515    header_iih_ptp = (const struct isis_iih_ptp_header *)pptr;
2516    header_lsp = (const struct isis_lsp_header *)pptr;
2517    header_csnp = (const struct isis_csnp_header *)pptr;
2518    header_psnp = (const struct isis_psnp_header *)pptr;
2519
2520    if (!ndo->ndo_eflag)
2521        ND_PRINT("IS-IS");
2522
2523    /*
2524     * Sanity checking of the header.
2525     */
2526
2527    version = GET_U_1(isis_header->version);
2528    if (version != ISIS_VERSION) {
2529	ND_PRINT("version %u packet not supported", version);
2530	return (0);
2531    }
2532
2533    pdu_id_length = GET_U_1(isis_header->id_length);
2534    if ((pdu_id_length != SYSTEM_ID_LEN) && (pdu_id_length != 0)) {
2535	ND_PRINT("system ID length of %u is not supported",
2536	       pdu_id_length);
2537	return (0);
2538    }
2539
2540    pdu_version = GET_U_1(isis_header->pdu_version);
2541    if (pdu_version != ISIS_VERSION) {
2542	ND_PRINT("version %u packet not supported", pdu_version);
2543	return (0);
2544    }
2545
2546    fixed_len = GET_U_1(isis_header->fixed_len);
2547    if (length < fixed_len) {
2548	ND_PRINT("fixed header length %u > packet length %u", fixed_len, length);
2549	return (0);
2550    }
2551
2552    if (fixed_len < ISIS_COMMON_HEADER_SIZE) {
2553	ND_PRINT("fixed header length %u < minimum header size %u", fixed_len, (u_int)ISIS_COMMON_HEADER_SIZE);
2554	return (0);
2555    }
2556
2557    pdu_max_area = GET_U_1(isis_header->max_area);
2558    switch(pdu_max_area) {
2559    case 0:
2560	max_area = 3;	 /* silly shit */
2561	break;
2562    case 255:
2563	ND_PRINT("bad packet -- 255 areas");
2564	return (0);
2565    default:
2566        max_area = pdu_max_area;
2567	break;
2568    }
2569
2570    switch(pdu_id_length) {
2571    case 0:
2572        id_length = 6;	 /* silly shit again */
2573	break;
2574    case 1:              /* 1-8 are valid sys-ID lengths */
2575    case 2:
2576    case 3:
2577    case 4:
2578    case 5:
2579    case 6:
2580    case 7:
2581    case 8:
2582        id_length = pdu_id_length;
2583        break;
2584    case 255:
2585        id_length = 0;   /* entirely useless */
2586	break;
2587    default:
2588        id_length = pdu_id_length;
2589        break;
2590    }
2591
2592    /* toss any non 6-byte sys-ID len PDUs */
2593    if (id_length != 6 ) {
2594	ND_PRINT("bad packet -- illegal sys-ID length (%u)", id_length);
2595	return (0);
2596    }
2597
2598    pdu_type = GET_U_1(isis_header->pdu_type);
2599
2600    /* in non-verbose mode print the basic PDU Type plus PDU specific brief information*/
2601    if (ndo->ndo_vflag == 0) {
2602        ND_PRINT("%s%s",
2603               ndo->ndo_eflag ? "" : ", ",
2604               tok2str(isis_pdu_values, "unknown PDU-Type %u", pdu_type));
2605    } else {
2606        /* ok they seem to want to know everything - lets fully decode it */
2607        ND_PRINT("%slength %u", ndo->ndo_eflag ? "" : ", ", length);
2608
2609        ND_PRINT("\n\t%s, hlen: %u, v: %u, pdu-v: %u, sys-id-len: %u (%u), max-area: %u (%u)",
2610               tok2str(isis_pdu_values,
2611                       "unknown, type %u",
2612                       pdu_type),
2613               fixed_len,
2614               version,
2615               pdu_version,
2616               id_length,
2617               pdu_id_length,
2618               max_area,
2619               pdu_max_area);
2620
2621        if (ndo->ndo_vflag > 1) {
2622            if (!print_unknown_data(ndo, optr, "\n\t", 8)) /* provide the _o_riginal pointer */
2623                return (0);                         /* for optionally debugging the common header */
2624        }
2625    }
2626
2627    switch (pdu_type) {
2628
2629    case ISIS_PDU_L1_LAN_IIH:
2630    case ISIS_PDU_L2_LAN_IIH:
2631        if (fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE)) {
2632            ND_PRINT(", bogus fixed header length %u should be %zu",
2633                     fixed_len, ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
2634            return (0);
2635        }
2636        ND_TCHECK_SIZE(header_iih_lan);
2637        if (length < ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE)
2638            goto trunc;
2639        if (ndo->ndo_vflag == 0) {
2640            ND_PRINT(", src-id %s",
2641                      isis_print_id(ndo, header_iih_lan->source_id, SYSTEM_ID_LEN));
2642            ND_PRINT(", lan-id %s, prio %u",
2643                      isis_print_id(ndo, header_iih_lan->lan_id,NODE_ID_LEN),
2644                      GET_U_1(header_iih_lan->priority));
2645            ND_PRINT(", length %u", length);
2646            return (1);
2647        }
2648        pdu_len=GET_BE_U_2(header_iih_lan->pdu_len);
2649        if (packet_len>pdu_len) {
2650           packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2651           length=pdu_len;
2652        }
2653
2654        ND_PRINT("\n\t  source-id: %s,  holding time: %us, Flags: [%s]",
2655                  isis_print_id(ndo, header_iih_lan->source_id,SYSTEM_ID_LEN),
2656                  GET_BE_U_2(header_iih_lan->holding_time),
2657                  tok2str(isis_iih_circuit_type_values,
2658                          "unknown circuit type 0x%02x",
2659                          GET_U_1(header_iih_lan->circuit_type)));
2660
2661        ND_PRINT("\n\t  lan-id:    %s, Priority: %u, PDU length: %u",
2662                  isis_print_id(ndo, header_iih_lan->lan_id, NODE_ID_LEN),
2663                  GET_U_1(header_iih_lan->priority) & ISIS_LAN_PRIORITY_MASK,
2664                  pdu_len);
2665
2666        if (ndo->ndo_vflag > 1) {
2667            if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_IIH_LAN_HEADER_SIZE))
2668                return (0);
2669        }
2670
2671        INVALID_OR_DECREMENT(packet_len,ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
2672        pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
2673        break;
2674
2675    case ISIS_PDU_PTP_IIH:
2676        if (fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE)) {
2677            ND_PRINT(", bogus fixed header length %u should be %zu",
2678                      fixed_len, ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
2679            return (0);
2680        }
2681        ND_TCHECK_SIZE(header_iih_ptp);
2682        if (length < ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE)
2683            goto trunc;
2684        if (ndo->ndo_vflag == 0) {
2685            ND_PRINT(", src-id %s", isis_print_id(ndo, header_iih_ptp->source_id, SYSTEM_ID_LEN));
2686            ND_PRINT(", length %u", length);
2687            return (1);
2688        }
2689        pdu_len=GET_BE_U_2(header_iih_ptp->pdu_len);
2690        if (packet_len>pdu_len) {
2691            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2692            length=pdu_len;
2693        }
2694
2695        ND_PRINT("\n\t  source-id: %s, holding time: %us, Flags: [%s]",
2696                  isis_print_id(ndo, header_iih_ptp->source_id,SYSTEM_ID_LEN),
2697                  GET_BE_U_2(header_iih_ptp->holding_time),
2698                  tok2str(isis_iih_circuit_type_values,
2699                          "unknown circuit type 0x%02x",
2700                          GET_U_1(header_iih_ptp->circuit_type)));
2701
2702        ND_PRINT("\n\t  circuit-id: 0x%02x, PDU length: %u",
2703                  GET_U_1(header_iih_ptp->circuit_id),
2704                  pdu_len);
2705
2706        if (ndo->ndo_vflag > 1) {
2707            if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_IIH_PTP_HEADER_SIZE))
2708                return (0);
2709        }
2710        INVALID_OR_DECREMENT(packet_len,ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
2711        pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
2712        break;
2713
2714    case ISIS_PDU_L1_LSP:
2715    case ISIS_PDU_L2_LSP:
2716        if (fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE)) {
2717            ND_PRINT(", bogus fixed header length %u should be %zu",
2718                   fixed_len, ISIS_LSP_HEADER_SIZE);
2719            return (0);
2720        }
2721        ND_TCHECK_SIZE(header_lsp);
2722        if (length < ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE)
2723            goto trunc;
2724        if (ndo->ndo_vflag == 0) {
2725            ND_PRINT(", lsp-id %s, seq 0x%08x, lifetime %5us",
2726                      isis_print_id(ndo, header_lsp->lsp_id, LSP_ID_LEN),
2727                      GET_BE_U_4(header_lsp->sequence_number),
2728                      GET_BE_U_2(header_lsp->remaining_lifetime));
2729            ND_PRINT(", length %u", length);
2730            return (1);
2731        }
2732        pdu_len=GET_BE_U_2(header_lsp->pdu_len);
2733        if (packet_len>pdu_len) {
2734            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2735            length=pdu_len;
2736        }
2737
2738        ND_PRINT("\n\t  lsp-id: %s, seq: 0x%08x, lifetime: %5us\n\t  chksum: 0x%04x",
2739               isis_print_id(ndo, header_lsp->lsp_id, LSP_ID_LEN),
2740               GET_BE_U_4(header_lsp->sequence_number),
2741               GET_BE_U_2(header_lsp->remaining_lifetime),
2742               GET_BE_U_2(header_lsp->checksum));
2743
2744        osi_print_cksum(ndo, (const uint8_t *)header_lsp->lsp_id,
2745                        GET_BE_U_2(header_lsp->checksum),
2746                        12, length-12);
2747
2748        ND_PRINT(", PDU length: %u, Flags: [ %s",
2749               pdu_len,
2750               ISIS_MASK_LSP_OL_BIT(header_lsp->typeblock) ? "Overload bit set, " : "");
2751
2752        if (ISIS_MASK_LSP_ATT_BITS(header_lsp->typeblock)) {
2753            ND_PRINT("%s", ISIS_MASK_LSP_ATT_DEFAULT_BIT(header_lsp->typeblock) ? "default " : "");
2754            ND_PRINT("%s", ISIS_MASK_LSP_ATT_DELAY_BIT(header_lsp->typeblock) ? "delay " : "");
2755            ND_PRINT("%s", ISIS_MASK_LSP_ATT_EXPENSE_BIT(header_lsp->typeblock) ? "expense " : "");
2756            ND_PRINT("%s", ISIS_MASK_LSP_ATT_ERROR_BIT(header_lsp->typeblock) ? "error " : "");
2757            ND_PRINT("ATT bit set, ");
2758        }
2759        ND_PRINT("%s", ISIS_MASK_LSP_PARTITION_BIT(header_lsp->typeblock) ? "P bit set, " : "");
2760        ND_PRINT("%s ]", tok2str(isis_lsp_istype_values, "Unknown(0x%x)",
2761                  ISIS_MASK_LSP_ISTYPE_BITS(header_lsp->typeblock)));
2762
2763        if (ndo->ndo_vflag > 1) {
2764            if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_LSP_HEADER_SIZE))
2765                return (0);
2766        }
2767
2768        INVALID_OR_DECREMENT(packet_len,ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
2769        pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
2770        break;
2771
2772    case ISIS_PDU_L1_CSNP:
2773    case ISIS_PDU_L2_CSNP:
2774        if (fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE)) {
2775            ND_PRINT(", bogus fixed header length %u should be %zu",
2776                      fixed_len, ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
2777            return (0);
2778        }
2779        ND_TCHECK_SIZE(header_csnp);
2780        if (length < ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE)
2781            goto trunc;
2782        if (ndo->ndo_vflag == 0) {
2783            ND_PRINT(", src-id %s", isis_print_id(ndo, header_csnp->source_id, NODE_ID_LEN));
2784            ND_PRINT(", length %u", length);
2785            return (1);
2786        }
2787        pdu_len=GET_BE_U_2(header_csnp->pdu_len);
2788        if (packet_len>pdu_len) {
2789            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2790            length=pdu_len;
2791        }
2792
2793        ND_PRINT("\n\t  source-id:    %s, PDU length: %u",
2794               isis_print_id(ndo, header_csnp->source_id, NODE_ID_LEN),
2795               pdu_len);
2796        ND_PRINT("\n\t  start lsp-id: %s",
2797               isis_print_id(ndo, header_csnp->start_lsp_id, LSP_ID_LEN));
2798        ND_PRINT("\n\t  end lsp-id:   %s",
2799               isis_print_id(ndo, header_csnp->end_lsp_id, LSP_ID_LEN));
2800
2801        if (ndo->ndo_vflag > 1) {
2802            if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_CSNP_HEADER_SIZE))
2803                return (0);
2804        }
2805
2806        INVALID_OR_DECREMENT(packet_len,ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
2807        pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
2808        break;
2809
2810    case ISIS_PDU_L1_PSNP:
2811    case ISIS_PDU_L2_PSNP:
2812        if (fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE)) {
2813            ND_PRINT("- bogus fixed header length %u should be %zu",
2814                   fixed_len, ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
2815            return (0);
2816        }
2817        ND_TCHECK_SIZE(header_psnp);
2818        if (length < ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE)
2819            goto trunc;
2820        if (ndo->ndo_vflag == 0) {
2821            ND_PRINT(", src-id %s", isis_print_id(ndo, header_psnp->source_id, NODE_ID_LEN));
2822            ND_PRINT(", length %u", length);
2823            return (1);
2824        }
2825        pdu_len=GET_BE_U_2(header_psnp->pdu_len);
2826        if (packet_len>pdu_len) {
2827            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2828            length=pdu_len;
2829        }
2830
2831        ND_PRINT("\n\t  source-id:    %s, PDU length: %u",
2832               isis_print_id(ndo, header_psnp->source_id, NODE_ID_LEN),
2833               pdu_len);
2834
2835        if (ndo->ndo_vflag > 1) {
2836            if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_PSNP_HEADER_SIZE))
2837                return (0);
2838        }
2839
2840        INVALID_OR_DECREMENT(packet_len,ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
2841        pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
2842        break;
2843
2844    default:
2845        if (ndo->ndo_vflag == 0) {
2846            ND_PRINT(", length %u", length);
2847            return (1);
2848        }
2849	(void)print_unknown_data(ndo, pptr, "\n\t  ", length);
2850	return (0);
2851    }
2852
2853    /*
2854     * Now print the TLV's.
2855     */
2856
2857    while (packet_len > 0) {
2858	ND_TCHECK_2(pptr);
2859	if (packet_len < 2)
2860	    goto trunc;
2861	tlv_type = GET_U_1(pptr);
2862	tlv_len = GET_U_1(pptr + 1);
2863	pptr += 2;
2864	packet_len -= 2;
2865        tlen = tlv_len; /* copy temporary len & pointer to packet data */
2866        tptr = pptr;
2867
2868        /* first lets see if we know the TLVs name*/
2869	ND_PRINT("\n\t    %s TLV #%u, length: %u",
2870               tok2str(isis_tlv_values,
2871                       "unknown",
2872                       tlv_type),
2873               tlv_type,
2874               tlv_len);
2875
2876	if (packet_len < tlv_len)
2877	    goto trunc;
2878
2879        /* now check if we have a decoder otherwise do a hexdump at the end*/
2880	switch (tlv_type) {
2881	case ISIS_TLV_AREA_ADDR:
2882	    while (tlen != 0) {
2883		alen = GET_U_1(tptr);
2884		tptr++;
2885		tlen--;
2886		if (tlen < alen)
2887		    goto tlv_trunc;
2888		ND_PRINT("\n\t      Area address (length: %u): %s",
2889                       alen,
2890                       GET_ISONSAP_STRING(tptr, alen));
2891		tptr += alen;
2892		tlen -= alen;
2893	    }
2894	    break;
2895	case ISIS_TLV_ISNEIGH:
2896	    while (tlen != 0) {
2897		if (tlen < MAC_ADDR_LEN)
2898		    goto tlv_trunc;
2899                ND_TCHECK_LEN(tptr, MAC_ADDR_LEN);
2900                ND_PRINT("\n\t      SNPA: %s", isis_print_id(ndo, tptr, MAC_ADDR_LEN));
2901                tlen -= MAC_ADDR_LEN;
2902                tptr += MAC_ADDR_LEN;
2903	    }
2904	    break;
2905
2906        case ISIS_TLV_INSTANCE_ID:
2907            if (tlen < 4)
2908                goto tlv_trunc;
2909            num_vals = (tlen-2)/2;
2910            ND_PRINT("\n\t      Instance ID: %u, ITIDs(%u)%s ",
2911                     GET_BE_U_2(tptr), num_vals,
2912                     num_vals ? ":" : "");
2913            tptr += 2;
2914            tlen -= 2;
2915            for (i=0; i < num_vals; i++) {
2916                ND_PRINT("%u", GET_BE_U_2(tptr));
2917                if (i < (num_vals - 1)) {
2918                   ND_PRINT(", ");
2919                }
2920                tptr += 2;
2921                tlen -= 2;
2922            }
2923            break;
2924
2925	case ISIS_TLV_PADDING:
2926	    break;
2927
2928        case ISIS_TLV_MT_IS_REACH:
2929            mt_len = isis_print_mtid(ndo, tptr, "\n\t      ", tlen);
2930            if (mt_len == 0) /* did something go wrong ? */
2931                goto trunc;
2932            tptr+=mt_len;
2933            tlen-=mt_len;
2934            while (tlen != 0) {
2935                ext_is_len = isis_print_ext_is_reach(ndo, tptr, "\n\t      ", tlv_type, tlen);
2936                if (ext_is_len == 0) /* did something go wrong ? */
2937                    goto trunc;
2938                if (tlen < ext_is_len) {
2939                    ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_is_len);
2940                    nd_print_invalid(ndo);
2941                    break;
2942                }
2943                tlen-=(uint8_t)ext_is_len;
2944                tptr+=(uint8_t)ext_is_len;
2945            }
2946            break;
2947
2948        case ISIS_TLV_IS_ALIAS_ID:
2949	    while (tlen != 0) {
2950	        ext_is_len = isis_print_ext_is_reach(ndo, tptr, "\n\t      ", tlv_type, tlen);
2951		if (ext_is_len == 0) /* did something go wrong ? */
2952	            goto trunc;
2953                if (tlen < ext_is_len) {
2954                    ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_is_len);
2955                    nd_print_invalid(ndo);
2956                    break;
2957                }
2958		tlen-=(uint8_t)ext_is_len;
2959		tptr+=(uint8_t)ext_is_len;
2960	    }
2961	    break;
2962
2963        case ISIS_TLV_EXT_IS_REACH:
2964            while (tlen != 0) {
2965                ext_is_len = isis_print_ext_is_reach(ndo, tptr, "\n\t      ", tlv_type, tlen);
2966                if (ext_is_len == 0) /* did something go wrong ? */
2967                    goto trunc;
2968                if (tlen < ext_is_len) {
2969                    ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_is_len);
2970                    nd_print_invalid(ndo);
2971                    break;
2972                }
2973                tlen-=(uint8_t)ext_is_len;
2974                tptr+=(uint8_t)ext_is_len;
2975            }
2976            break;
2977        case ISIS_TLV_IS_REACH:
2978            if (tlen < 1)
2979                goto tlv_trunc;
2980            ND_PRINT("\n\t      %s",
2981                   tok2str(isis_is_reach_virtual_values,
2982                           "bogus virtual flag 0x%02x",
2983                           GET_U_1(tptr)));
2984	    tptr++;
2985	    tlen--;
2986	    tlv_is_reach = (const struct isis_tlv_is_reach *)tptr;
2987            while (tlen != 0) {
2988                if (tlen < sizeof(struct isis_tlv_is_reach))
2989                    goto tlv_trunc;
2990		ND_TCHECK_SIZE(tlv_is_reach);
2991		ND_PRINT("\n\t      IS Neighbor: %s",
2992		       isis_print_id(ndo, tlv_is_reach->neighbor_nodeid, NODE_ID_LEN));
2993		isis_print_metric_block(ndo, &tlv_is_reach->isis_metric_block);
2994		tlen -= sizeof(struct isis_tlv_is_reach);
2995		tlv_is_reach++;
2996	    }
2997            break;
2998
2999        case ISIS_TLV_ESNEIGH:
3000	    tlv_es_reach = (const struct isis_tlv_es_reach *)tptr;
3001            while (tlen != 0) {
3002                if (tlen < sizeof(struct isis_tlv_es_reach))
3003                    goto tlv_trunc;
3004		ND_TCHECK_SIZE(tlv_es_reach);
3005		ND_PRINT("\n\t      ES Neighbor: %s",
3006                       isis_print_id(ndo, tlv_es_reach->neighbor_sysid, SYSTEM_ID_LEN));
3007		isis_print_metric_block(ndo, &tlv_es_reach->isis_metric_block);
3008		tlen -= sizeof(struct isis_tlv_es_reach);
3009		tlv_es_reach++;
3010	    }
3011            break;
3012
3013            /* those two TLVs share the same format */
3014	case ISIS_TLV_INT_IP_REACH:
3015	case ISIS_TLV_EXT_IP_REACH:
3016		if (!isis_print_tlv_ip_reach(ndo, pptr, "\n\t      ", tlv_len))
3017			return (1);
3018		break;
3019
3020	case ISIS_TLV_EXTD_IP_REACH:
3021	    while (tlen != 0) {
3022                ext_ip_len = isis_print_extd_ip_reach(ndo, tptr, "\n\t      ", AF_INET);
3023                if (ext_ip_len == 0) /* did something go wrong ? */
3024                    goto trunc;
3025                if (tlen < ext_ip_len) {
3026                    ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_ip_len);
3027                    nd_print_invalid(ndo);
3028                    break;
3029                }
3030                tlen-=(uint8_t)ext_ip_len;
3031                tptr+=(uint8_t)ext_ip_len;
3032            }
3033            break;
3034
3035        case ISIS_TLV_MT_IP_REACH:
3036            mt_len = isis_print_mtid(ndo, tptr, "\n\t      ", tlen);
3037            if (mt_len == 0) { /* did something go wrong ? */
3038                goto trunc;
3039            }
3040            tptr+=mt_len;
3041            tlen-=mt_len;
3042
3043            while (tlen != 0) {
3044                ext_ip_len = isis_print_extd_ip_reach(ndo, tptr, "\n\t      ", AF_INET);
3045                if (ext_ip_len == 0) /* did something go wrong ? */
3046                    goto trunc;
3047                if (tlen < ext_ip_len) {
3048                    ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_ip_len);
3049                    nd_print_invalid(ndo);
3050                    break;
3051                }
3052                tlen-=(uint8_t)ext_ip_len;
3053                tptr+=(uint8_t)ext_ip_len;
3054            }
3055            break;
3056
3057	case ISIS_TLV_IP6_REACH:
3058            while (tlen != 0) {
3059                ext_ip_len = isis_print_extd_ip_reach(ndo, tptr, "\n\t      ", AF_INET6);
3060                if (ext_ip_len == 0) /* did something go wrong ? */
3061                    goto trunc;
3062                if (tlen < ext_ip_len) {
3063                    ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_ip_len);
3064                    nd_print_invalid(ndo);
3065                    break;
3066                }
3067                tlen-=(uint8_t)ext_ip_len;
3068                tptr+=(uint8_t)ext_ip_len;
3069            }
3070            break;
3071
3072	case ISIS_TLV_MT_IP6_REACH:
3073            mt_len = isis_print_mtid(ndo, tptr, "\n\t      ", tlen);
3074            if (mt_len == 0) { /* did something go wrong ? */
3075                goto trunc;
3076            }
3077            tptr+=mt_len;
3078            tlen-=mt_len;
3079
3080            while (tlen != 0) {
3081                ext_ip_len = isis_print_extd_ip_reach(ndo, tptr, "\n\t      ", AF_INET6);
3082                if (ext_ip_len == 0) /* did something go wrong ? */
3083                    goto trunc;
3084                if (tlen < ext_ip_len) {
3085                    ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_ip_len);
3086                    nd_print_invalid(ndo);
3087                    break;
3088                }
3089                tlen-=(uint8_t)ext_ip_len;
3090                tptr+=(uint8_t)ext_ip_len;
3091            }
3092            break;
3093
3094	case ISIS_TLV_IP6ADDR:
3095	    while (tlen != 0) {
3096                if (tlen < sizeof(nd_ipv6))
3097                    goto tlv_trunc;
3098                ND_PRINT("\n\t      IPv6 interface address: %s",
3099		       GET_IP6ADDR_STRING(tptr));
3100
3101		tptr += sizeof(nd_ipv6);
3102		tlen -= sizeof(nd_ipv6);
3103	    }
3104	    break;
3105	case ISIS_TLV_AUTH:
3106	    if (tlen < 1)
3107	        goto tlv_trunc;
3108	    auth_type = GET_U_1(tptr);
3109	    tptr++;
3110	    tlen--;
3111
3112            ND_PRINT("\n\t      %s: ",
3113                   tok2str(isis_subtlv_auth_values,
3114                           "unknown Authentication type 0x%02x",
3115                           auth_type));
3116
3117	    switch (auth_type) {
3118	    case ISIS_SUBTLV_AUTH_SIMPLE:
3119		nd_printjnp(ndo, tptr, tlen);
3120		break;
3121	    case ISIS_SUBTLV_AUTH_MD5:
3122		for(i=0;i<tlen;i++) {
3123		    ND_PRINT("%02x", GET_U_1(tptr + i));
3124		}
3125		if (tlen != ISIS_SUBTLV_AUTH_MD5_LEN)
3126                    ND_PRINT(", (invalid subTLV) ");
3127
3128                sigcheck = signature_verify(ndo, optr, length, tptr,
3129                                            isis_clear_checksum_lifetime,
3130                                            header_lsp);
3131                ND_PRINT(" (%s)", tok2str(signature_check_values, "Unknown", sigcheck));
3132
3133		break;
3134            case ISIS_SUBTLV_AUTH_GENERIC:
3135                if (tlen < 2)
3136                    goto tlv_trunc;
3137                key_id = GET_BE_U_2(tptr);
3138                ND_PRINT("%u, password: ", key_id);
3139                tptr += 2;
3140                tlen -= 2;
3141                for(i=0;i<tlen;i++) {
3142                    ND_PRINT("%02x", GET_U_1(tptr + i));
3143                }
3144                break;
3145	    case ISIS_SUBTLV_AUTH_PRIVATE:
3146	    default:
3147		if (!print_unknown_data(ndo, tptr, "\n\t\t  ", tlen))
3148		    return(0);
3149		break;
3150	    }
3151	    break;
3152
3153	case ISIS_TLV_PTP_ADJ:
3154	    tlv_ptp_adj = (const struct isis_tlv_ptp_adj *)tptr;
3155	    if(tlen>=1) {
3156		ND_PRINT("\n\t      Adjacency State: %s (%u)",
3157		       tok2str(isis_ptp_adjancey_values, "unknown", GET_U_1(tptr)),
3158		       GET_U_1(tptr));
3159		tlen--;
3160	    }
3161	    if(tlen>sizeof(tlv_ptp_adj->extd_local_circuit_id)) {
3162		ND_PRINT("\n\t      Extended Local circuit-ID: 0x%08x",
3163		       GET_BE_U_4(tlv_ptp_adj->extd_local_circuit_id));
3164		tlen-=sizeof(tlv_ptp_adj->extd_local_circuit_id);
3165	    }
3166	    if(tlen>=SYSTEM_ID_LEN) {
3167		ND_TCHECK_LEN(tlv_ptp_adj->neighbor_sysid, SYSTEM_ID_LEN);
3168		ND_PRINT("\n\t      Neighbor System-ID: %s",
3169		       isis_print_id(ndo, tlv_ptp_adj->neighbor_sysid, SYSTEM_ID_LEN));
3170		tlen-=SYSTEM_ID_LEN;
3171	    }
3172	    if(tlen>=sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)) {
3173		ND_PRINT("\n\t      Neighbor Extended Local circuit-ID: 0x%08x",
3174		       GET_BE_U_4(tlv_ptp_adj->neighbor_extd_local_circuit_id));
3175	    }
3176	    break;
3177
3178	case ISIS_TLV_PROTOCOLS:
3179	    ND_PRINT("\n\t      NLPID(s): ");
3180	    while (tlen != 0) {
3181		ND_PRINT("%s (0x%02x)",
3182                       tok2str(nlpid_values,
3183                               "unknown",
3184                               GET_U_1(tptr)),
3185                       GET_U_1(tptr));
3186		if (tlen>1) /* further NPLIDs ? - put comma */
3187		    ND_PRINT(", ");
3188                tptr++;
3189                tlen--;
3190	    }
3191	    break;
3192
3193        case ISIS_TLV_MT_PORT_CAP:
3194        {
3195            if (tlen < 2)
3196                goto tlv_trunc;
3197
3198            ND_PRINT("\n\t       RES: %u, MTID(s): %u",
3199                    (GET_BE_U_2(tptr) >> 12),
3200                    (GET_BE_U_2(tptr) & 0x0fff));
3201
3202            tptr += 2;
3203            tlen -= 2;
3204
3205            if (tlen)
3206                isis_print_mt_port_cap_subtlv(ndo, tptr, tlen);
3207
3208            break;
3209        }
3210
3211        case ISIS_TLV_MT_CAPABILITY:
3212            if (tlen < 2)
3213                goto tlv_trunc;
3214
3215            ND_PRINT("\n\t      O: %u, RES: %u, MTID(s): %u",
3216                      (GET_BE_U_2(tptr) >> 15) & 0x01,
3217                      (GET_BE_U_2(tptr) >> 12) & 0x07,
3218                      GET_BE_U_2(tptr) & 0x0fff);
3219
3220            tptr += 2;
3221            tlen -= 2;
3222
3223            if (tlen)
3224                isis_print_mt_capability_subtlv(ndo, tptr, tlen);
3225
3226            break;
3227
3228	case ISIS_TLV_TE_ROUTER_ID:
3229	    if (tlen < sizeof(nd_ipv4))
3230	        goto tlv_trunc;
3231	    ND_PRINT("\n\t      Traffic Engineering Router ID: %s", GET_IPADDR_STRING(pptr));
3232	    break;
3233
3234	case ISIS_TLV_IPADDR:
3235	    while (tlen != 0) {
3236                if (tlen < sizeof(nd_ipv4))
3237                    goto tlv_trunc;
3238		ND_PRINT("\n\t      IPv4 interface address: %s", GET_IPADDR_STRING(tptr));
3239		tptr += sizeof(nd_ipv4);
3240		tlen -= sizeof(nd_ipv4);
3241	    }
3242	    break;
3243
3244	case ISIS_TLV_HOSTNAME:
3245	    ND_PRINT("\n\t      Hostname: ");
3246	    nd_printjnp(ndo, tptr, tlen);
3247	    break;
3248
3249	case ISIS_TLV_SHARED_RISK_GROUP:
3250	    if (tlen < NODE_ID_LEN)
3251	        break;
3252	    ND_TCHECK_LEN(tptr, NODE_ID_LEN);
3253	    ND_PRINT("\n\t      IS Neighbor: %s", isis_print_id(ndo, tptr, NODE_ID_LEN));
3254	    tptr+=NODE_ID_LEN;
3255	    tlen-=NODE_ID_LEN;
3256
3257	    if (tlen < 1)
3258	        break;
3259	    ND_PRINT(", Flags: [%s]",
3260                     ISIS_MASK_TLV_SHARED_RISK_GROUP(GET_U_1(tptr)) ? "numbered" : "unnumbered");
3261	    tptr++;
3262	    tlen--;
3263
3264	    if (tlen < sizeof(nd_ipv4))
3265	        break;
3266	    ND_PRINT("\n\t      IPv4 interface address: %s", GET_IPADDR_STRING(tptr));
3267	    tptr+=sizeof(nd_ipv4);
3268	    tlen-=sizeof(nd_ipv4);
3269
3270	    if (tlen < sizeof(nd_ipv4))
3271	        break;
3272	    ND_PRINT("\n\t      IPv4 neighbor address: %s", GET_IPADDR_STRING(tptr));
3273	    tptr+=sizeof(nd_ipv4);
3274	    tlen-=sizeof(nd_ipv4);
3275
3276	    while (tlen != 0) {
3277		if (tlen < 4)
3278		    goto tlv_trunc;
3279                ND_PRINT("\n\t      Link-ID: 0x%08x", GET_BE_U_4(tptr));
3280                tptr+=4;
3281                tlen-=4;
3282	    }
3283	    break;
3284
3285	case ISIS_TLV_LSP:
3286	    tlv_lsp = (const struct isis_tlv_lsp *)tptr;
3287	    while (tlen != 0) {
3288		if (tlen < sizeof(struct isis_tlv_lsp))
3289		    goto tlv_trunc;
3290		ND_TCHECK_1(tlv_lsp->lsp_id + LSP_ID_LEN - 1);
3291		ND_PRINT("\n\t      lsp-id: %s",
3292                       isis_print_id(ndo, tlv_lsp->lsp_id, LSP_ID_LEN));
3293		ND_PRINT(", seq: 0x%08x",
3294                         GET_BE_U_4(tlv_lsp->sequence_number));
3295		ND_PRINT(", lifetime: %5ds",
3296                         GET_BE_U_2(tlv_lsp->remaining_lifetime));
3297		ND_PRINT(", chksum: 0x%04x", GET_BE_U_2(tlv_lsp->checksum));
3298		tlen-=sizeof(struct isis_tlv_lsp);
3299		tlv_lsp++;
3300	    }
3301	    break;
3302
3303	case ISIS_TLV_CHECKSUM:
3304	    if (tlen < ISIS_TLV_CHECKSUM_MINLEN)
3305	        break;
3306	    ND_TCHECK_LEN(tptr, ISIS_TLV_CHECKSUM_MINLEN);
3307	    ND_PRINT("\n\t      checksum: 0x%04x ", GET_BE_U_2(tptr));
3308            /* do not attempt to verify the checksum if it is zero
3309             * most likely a HMAC-MD5 TLV is also present and
3310             * to avoid conflicts the checksum TLV is zeroed.
3311             * see rfc3358 for details
3312             */
3313            osi_print_cksum(ndo, optr, GET_BE_U_2(tptr), (int)(tptr-optr),
3314                            length);
3315	    break;
3316
3317	case ISIS_TLV_POI:
3318	    if (tlen < 1)
3319	        goto tlv_trunc;
3320	    num_system_ids = GET_U_1(tptr);
3321	    tptr++;
3322	    tlen--;
3323	    if (num_system_ids == 0) {
3324		/* Not valid */
3325		ND_PRINT(" No system IDs supplied");
3326	    } else {
3327		if (tlen < SYSTEM_ID_LEN)
3328		    goto tlv_trunc;
3329		ND_TCHECK_LEN(tptr, SYSTEM_ID_LEN);
3330		ND_PRINT("\n\t      Purge Originator System-ID: %s",
3331		       isis_print_id(ndo, tptr, SYSTEM_ID_LEN));
3332		tptr += SYSTEM_ID_LEN;
3333		tlen -= SYSTEM_ID_LEN;
3334
3335		if (num_system_ids > 1) {
3336		    if (tlen < SYSTEM_ID_LEN)
3337			goto tlv_trunc;
3338		    ND_TCHECK_LEN(tptr, SYSTEM_ID_LEN);
3339		    ND_TCHECK_LEN(tptr, 2 * SYSTEM_ID_LEN + 1);
3340		    ND_PRINT("\n\t      Received from System-ID: %s",
3341			   isis_print_id(ndo, tptr, SYSTEM_ID_LEN));
3342		}
3343	    }
3344	    break;
3345
3346	case ISIS_TLV_MT_SUPPORTED:
3347	    while (tlen != 0) {
3348		/* length can only be a multiple of 2, otherwise there is
3349		   something broken -> so decode down until length is 1 */
3350		if (tlen!=1) {
3351                    mt_len = isis_print_mtid(ndo, tptr, "\n\t      ", tlen);
3352                    if (mt_len == 0) /* did something go wrong ? */
3353                        goto trunc;
3354                    tptr+=mt_len;
3355                    tlen-=mt_len;
3356		} else {
3357		    ND_PRINT("\n\t      invalid MT-ID");
3358		    break;
3359		}
3360	    }
3361	    break;
3362
3363	case ISIS_TLV_RESTART_SIGNALING:
3364            /* first attempt to decode the flags */
3365            if (tlen < ISIS_TLV_RESTART_SIGNALING_FLAGLEN)
3366                break;
3367            ND_TCHECK_LEN(tptr, ISIS_TLV_RESTART_SIGNALING_FLAGLEN);
3368            ND_PRINT("\n\t      Flags [%s]",
3369                   bittok2str(isis_restart_flag_values, "none", GET_U_1(tptr)));
3370            tptr+=ISIS_TLV_RESTART_SIGNALING_FLAGLEN;
3371            tlen-=ISIS_TLV_RESTART_SIGNALING_FLAGLEN;
3372
3373            /* is there anything other than the flags field? */
3374            if (tlen == 0)
3375                break;
3376
3377            if (tlen < ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN)
3378                break;
3379            ND_TCHECK_LEN(tptr, ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN);
3380
3381            ND_PRINT(", Remaining holding time %us", GET_BE_U_2(tptr));
3382            tptr+=ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN;
3383            tlen-=ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN;
3384
3385            /* is there an additional sysid field present ?*/
3386            if (tlen == SYSTEM_ID_LEN) {
3387                    ND_TCHECK_LEN(tptr, SYSTEM_ID_LEN);
3388                    ND_PRINT(", for %s", isis_print_id(ndo, tptr,SYSTEM_ID_LEN));
3389            }
3390	    break;
3391
3392        case ISIS_TLV_IDRP_INFO:
3393	    if (tlen < 1)
3394	        break;
3395            isis_subtlv_idrp = GET_U_1(tptr);
3396            ND_PRINT("\n\t      Inter-Domain Information Type: %s",
3397                   tok2str(isis_subtlv_idrp_values,
3398                           "Unknown (0x%02x)",
3399                           isis_subtlv_idrp));
3400            tptr++;
3401            tlen--;
3402            switch (isis_subtlv_idrp) {
3403            case ISIS_SUBTLV_IDRP_ASN:
3404                if (tlen < 2)
3405                    goto tlv_trunc;
3406                ND_PRINT("AS Number: %u", GET_BE_U_2(tptr));
3407                break;
3408            case ISIS_SUBTLV_IDRP_LOCAL:
3409            case ISIS_SUBTLV_IDRP_RES:
3410            default:
3411                if (!print_unknown_data(ndo, tptr, "\n\t      ", tlen))
3412                    return(0);
3413                break;
3414            }
3415            break;
3416
3417        case ISIS_TLV_LSP_BUFFERSIZE:
3418	    if (tlen < 2)
3419	        break;
3420            ND_PRINT("\n\t      LSP Buffersize: %u", GET_BE_U_2(tptr));
3421            break;
3422
3423        case ISIS_TLV_PART_DIS:
3424            while (tlen != 0) {
3425                if (tlen < SYSTEM_ID_LEN)
3426                    goto tlv_trunc;
3427                ND_TCHECK_LEN(tptr, SYSTEM_ID_LEN);
3428                ND_PRINT("\n\t      %s", isis_print_id(ndo, tptr, SYSTEM_ID_LEN));
3429                tptr+=SYSTEM_ID_LEN;
3430                tlen-=SYSTEM_ID_LEN;
3431            }
3432            break;
3433
3434        case ISIS_TLV_PREFIX_NEIGH:
3435	    if (tlen < sizeof(struct isis_metric_block))
3436	        break;
3437            ND_TCHECK_LEN(tptr, sizeof(struct isis_metric_block));
3438            ND_PRINT("\n\t      Metric Block");
3439            isis_print_metric_block(ndo, (const struct isis_metric_block *)tptr);
3440            tptr+=sizeof(struct isis_metric_block);
3441            tlen-=sizeof(struct isis_metric_block);
3442
3443            while (tlen != 0) {
3444                prefix_len=GET_U_1(tptr); /* read out prefix length in semioctets*/
3445                tptr++;
3446                tlen--;
3447                if (prefix_len < 2) {
3448                    ND_PRINT("\n\t\tAddress: prefix length %u < 2", prefix_len);
3449                    break;
3450                }
3451                if (tlen < prefix_len/2)
3452                    break;
3453                ND_PRINT("\n\t\tAddress: %s/%u",
3454                       GET_ISONSAP_STRING(tptr, prefix_len / 2), prefix_len * 4);
3455                tptr+=prefix_len/2;
3456                tlen-=prefix_len/2;
3457            }
3458            break;
3459
3460        case ISIS_TLV_IIH_SEQNR:
3461	    if (tlen < 4)
3462	        break;
3463            ND_PRINT("\n\t      Sequence number: %u", GET_BE_U_4(tptr));
3464            break;
3465
3466        case ISIS_TLV_ROUTER_CAPABILITY:
3467            if (tlen < 5) {
3468                ND_PRINT(" [object length %u < 5]", tlen);
3469                nd_print_invalid(ndo);
3470                break;
3471            }
3472            ND_PRINT("\n\t      Router-ID %s", GET_IPADDR_STRING(tptr));
3473            ND_PRINT(", Flags [%s]",
3474		     bittok2str(isis_tlv_router_capability_flags, "none", GET_U_1(tptr+4)));
3475
3476	    /* Optional set of sub-TLV */
3477	    if (tlen > 5) {
3478		isis_print_router_cap_subtlv(ndo, tptr+5, tlen-5);
3479	    }
3480            break;
3481
3482        case ISIS_TLV_VENDOR_PRIVATE:
3483	    if (tlen < 3)
3484	        break;
3485            vendor_id = GET_BE_U_3(tptr);
3486            ND_PRINT("\n\t      Vendor: %s (%u)",
3487                   tok2str(oui_values, "Unknown", vendor_id),
3488                   vendor_id);
3489            tptr+=3;
3490            tlen-=3;
3491            if (tlen != 0) /* hexdump the rest */
3492                if (!print_unknown_data(ndo, tptr, "\n\t\t", tlen))
3493                    return(0);
3494            break;
3495            /*
3496             * FIXME those are the defined TLVs that lack a decoder
3497             * you are welcome to contribute code ;-)
3498             */
3499
3500        case ISIS_TLV_DECNET_PHASE4:
3501        case ISIS_TLV_LUCENT_PRIVATE:
3502        case ISIS_TLV_IPAUTH:
3503        case ISIS_TLV_NORTEL_PRIVATE1:
3504        case ISIS_TLV_NORTEL_PRIVATE2:
3505
3506	default:
3507		if (ndo->ndo_vflag <= 1) {
3508			if (!print_unknown_data(ndo, pptr, "\n\t\t", tlv_len))
3509				return(0);
3510		}
3511		break;
3512	}
3513tlv_trunc:
3514        /* do we want to see an additionally hexdump ? */
3515	if (ndo->ndo_vflag> 1) {
3516		if (!print_unknown_data(ndo, pptr, "\n\t      ", tlv_len))
3517			return(0);
3518	}
3519
3520	pptr += tlv_len;
3521	packet_len -= tlv_len;
3522    }
3523
3524    if (packet_len != 0) {
3525	ND_PRINT("\n\t      %u straggler bytes", packet_len);
3526    }
3527    return (1);
3528
3529trunc:
3530    nd_print_trunc(ndo);
3531    return (1);
3532}
3533
3534static void
3535osi_print_cksum(netdissect_options *ndo, const uint8_t *pptr,
3536	        uint16_t checksum, int checksum_offset, u_int length)
3537{
3538        uint16_t calculated_checksum;
3539
3540        /* do not attempt to verify the checksum if it is zero,
3541         * if the offset is nonsense,
3542         * or the base pointer is not sane
3543         */
3544        if (!checksum
3545            || checksum_offset < 0
3546            || !ND_TTEST_2(pptr + checksum_offset)
3547            || (u_int)checksum_offset > length
3548            || !ND_TTEST_LEN(pptr, length)) {
3549                ND_PRINT(" (unverified)");
3550        } else {
3551#if 0
3552                ND_PRINT("\nosi_print_cksum: %p %d %u\n", pptr, checksum_offset, length);
3553#endif
3554                calculated_checksum = create_osi_cksum(pptr, checksum_offset, length);
3555                if (checksum == calculated_checksum) {
3556                        ND_PRINT(" (correct)");
3557                } else {
3558                        ND_PRINT(" (incorrect should be 0x%04x)", calculated_checksum);
3559                }
3560        }
3561}
3562