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