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