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