]> The Tcpdump Group git mirrors - tcpdump/blob - print-isoclns.c
add PPP to the ISO nlpid printer
[tcpdump] / print-isoclns.c
1 /*
2 * Copyright (c) 1992, 1993, 1994, 1995, 1996
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 * Original code by Matt Thomas, Digital Equipment Corporation
22 *
23 * Extensively modified by Hannes Gredler (hannes@juniper.net) for more
24 * complete IS-IS support.
25 */
26
27 #ifndef lint
28 static const char rcsid[] _U_ =
29 "@(#) $Header: /tcpdump/master/tcpdump/print-isoclns.c,v 1.124 2004-10-19 15:27:55 hannes Exp $ (LBL)";
30 #endif
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <tcpdump-stdinc.h>
37
38 #include <stdio.h>
39 #include <string.h>
40
41 #include "interface.h"
42 #include "addrtoname.h"
43 #include "ethertype.h"
44 #include "ether.h"
45 #include "nlpid.h"
46 #include "extract.h"
47 #include "gmpls.h"
48 #include "oui.h"
49
50 #define IPV4 1 /* AFI value */
51 #define IPV6 2 /* AFI value */
52
53 /*
54 * IS-IS is defined in ISO 10589. Look there for protocol definitions.
55 */
56
57 #define SYSTEM_ID_LEN ETHER_ADDR_LEN
58 #define NODE_ID_LEN SYSTEM_ID_LEN+1
59 #define LSP_ID_LEN SYSTEM_ID_LEN+2
60 #define NSAP_MAX_LENGTH 20
61
62 #define ISIS_VERSION 1
63 #define ESIS_VERSION 1
64
65 #define ISIS_PDU_TYPE_MASK 0x1F
66 #define ESIS_PDU_TYPE_MASK 0x1F
67 #define CLNP_PDU_TYPE_MASK 0x1F
68 #define ISIS_LAN_PRIORITY_MASK 0x7F
69
70 #define ISIS_PDU_L1_LAN_IIH 15
71 #define ISIS_PDU_L2_LAN_IIH 16
72 #define ISIS_PDU_PTP_IIH 17
73 #define ISIS_PDU_L1_LSP 18
74 #define ISIS_PDU_L2_LSP 20
75 #define ISIS_PDU_L1_CSNP 24
76 #define ISIS_PDU_L2_CSNP 25
77 #define ISIS_PDU_L1_PSNP 26
78 #define ISIS_PDU_L2_PSNP 27
79
80 static struct tok isis_pdu_values[] = {
81 { ISIS_PDU_L1_LAN_IIH, "L1 Lan IIH"},
82 { ISIS_PDU_L2_LAN_IIH, "L2 Lan IIH"},
83 { ISIS_PDU_PTP_IIH, "p2p IIH"},
84 { ISIS_PDU_L1_LSP, "L1 LSP"},
85 { ISIS_PDU_L2_LSP, "L2 LSP"},
86 { ISIS_PDU_L1_CSNP, "L1 CSNP"},
87 { ISIS_PDU_L2_CSNP, "L2 CSNP"},
88 { ISIS_PDU_L1_PSNP, "L1 PSNP"},
89 { ISIS_PDU_L2_PSNP, "L2 PSNP"},
90 { 0, NULL}
91 };
92
93 /*
94 * A TLV is a tuple of a type, length and a value and is normally used for
95 * encoding information in all sorts of places. This is an enumeration of
96 * the well known types.
97 *
98 * list taken from rfc3359 plus some memory from veterans ;-)
99 */
100
101 #define ISIS_TLV_AREA_ADDR 1 /* iso10589 */
102 #define ISIS_TLV_IS_REACH 2 /* iso10589 */
103 #define ISIS_TLV_ESNEIGH 3 /* iso10589 */
104 #define ISIS_TLV_PART_DIS 4 /* iso10589 */
105 #define ISIS_TLV_PREFIX_NEIGH 5 /* iso10589 */
106 #define ISIS_TLV_ISNEIGH 6 /* iso10589 */
107 #define ISIS_TLV_ISNEIGH_VARLEN 7 /* iso10589 */
108 #define ISIS_TLV_PADDING 8 /* iso10589 */
109 #define ISIS_TLV_LSP 9 /* iso10589 */
110 #define ISIS_TLV_AUTH 10 /* iso10589, rfc3567 */
111 #define ISIS_TLV_CHECKSUM 12 /* rfc3358 */
112 #define ISIS_TLV_LSP_BUFFERSIZE 14 /* iso10589 rev2 */
113 #define ISIS_TLV_EXT_IS_REACH 22 /* draft-ietf-isis-traffic-05 */
114 #define ISIS_TLV_IS_ALIAS_ID 24 /* draft-ietf-isis-ext-lsp-frags-02 */
115 #define ISIS_TLV_DECNET_PHASE4 42
116 #define ISIS_TLV_LUCENT_PRIVATE 66
117 #define ISIS_TLV_INT_IP_REACH 128 /* rfc1195, rfc2966 */
118 #define ISIS_TLV_PROTOCOLS 129 /* rfc1195 */
119 #define ISIS_TLV_EXT_IP_REACH 130 /* rfc1195, rfc2966 */
120 #define ISIS_TLV_IDRP_INFO 131 /* rfc1195 */
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_NORTEL_PRIVATE1 176
128 #define ISIS_TLV_NORTEL_PRIVATE2 177
129 #define ISIS_TLV_RESTART_SIGNALING 211 /* draft-ietf-isis-restart-01 */
130 #define ISIS_TLV_MT_IS_REACH 222 /* draft-ietf-isis-wg-multi-topology-05 */
131 #define ISIS_TLV_MT_SUPPORTED 229 /* draft-ietf-isis-wg-multi-topology-05 */
132 #define ISIS_TLV_IP6ADDR 232 /* draft-ietf-isis-ipv6-02 */
133 #define ISIS_TLV_MT_IP_REACH 235 /* draft-ietf-isis-wg-multi-topology-05 */
134 #define ISIS_TLV_IP6_REACH 236 /* draft-ietf-isis-ipv6-02 */
135 #define ISIS_TLV_MT_IP6_REACH 237 /* draft-ietf-isis-wg-multi-topology-05 */
136 #define ISIS_TLV_PTP_ADJ 240 /* rfc3373 */
137 #define ISIS_TLV_IIH_SEQNR 241 /* draft-shen-isis-iih-sequence-00 */
138 #define ISIS_TLV_VENDOR_PRIVATE 250 /* draft-ietf-isis-experimental-tlv-01 */
139
140 static struct tok isis_tlv_values[] = {
141 { ISIS_TLV_AREA_ADDR, "Area address(es)"},
142 { ISIS_TLV_IS_REACH, "IS Reachability"},
143 { ISIS_TLV_ESNEIGH, "ES Neighbor(s)"},
144 { ISIS_TLV_PART_DIS, "Partition DIS"},
145 { ISIS_TLV_PREFIX_NEIGH, "Prefix Neighbors"},
146 { ISIS_TLV_ISNEIGH, "IS Neighbor(s)"},
147 { ISIS_TLV_ISNEIGH_VARLEN, "IS Neighbor(s) (variable length)"},
148 { ISIS_TLV_PADDING, "Padding"},
149 { ISIS_TLV_LSP, "LSP entries"},
150 { ISIS_TLV_AUTH, "Authentication"},
151 { ISIS_TLV_CHECKSUM, "Checksum"},
152 { ISIS_TLV_LSP_BUFFERSIZE, "LSP Buffersize"},
153 { ISIS_TLV_EXT_IS_REACH, "Extended IS Reachability"},
154 { ISIS_TLV_IS_ALIAS_ID, "IS Alias ID"},
155 { ISIS_TLV_DECNET_PHASE4, "DECnet Phase IV"},
156 { ISIS_TLV_LUCENT_PRIVATE, "Lucent Proprietary"},
157 { ISIS_TLV_INT_IP_REACH, "IPv4 Internal Reachability"},
158 { ISIS_TLV_PROTOCOLS, "Protocols supported"},
159 { ISIS_TLV_EXT_IP_REACH, "IPv4 External Reachability"},
160 { ISIS_TLV_IDRP_INFO, "Inter-Domain Information Type"},
161 { ISIS_TLV_IPADDR, "IPv4 Interface address(es)"},
162 { ISIS_TLV_IPAUTH, "IPv4 authentication (deprecated)"},
163 { ISIS_TLV_TE_ROUTER_ID, "Traffic Engineering Router ID"},
164 { ISIS_TLV_EXTD_IP_REACH, "Extended IPv4 Reachability"},
165 { ISIS_TLV_SHARED_RISK_GROUP, "Shared Risk Link Group"},
166 { ISIS_TLV_NORTEL_PRIVATE1, "Nortel Proprietary"},
167 { ISIS_TLV_NORTEL_PRIVATE2, "Nortel Proprietary"},
168 { ISIS_TLV_HOSTNAME, "Hostname"},
169 { ISIS_TLV_RESTART_SIGNALING, "Restart Signaling"},
170 { ISIS_TLV_MT_IS_REACH, "Multi Topology IS Reachability"},
171 { ISIS_TLV_MT_SUPPORTED, "Multi Topology"},
172 { ISIS_TLV_IP6ADDR, "IPv6 Interface address(es)"},
173 { ISIS_TLV_MT_IP_REACH, "Multi-Topology IPv4 Reachability"},
174 { ISIS_TLV_IP6_REACH, "IPv6 reachability"},
175 { ISIS_TLV_MT_IP6_REACH, "Multi-Topology IP6 Reachability"},
176 { ISIS_TLV_PTP_ADJ, "Point-to-point Adjacency State"},
177 { ISIS_TLV_IIH_SEQNR, "Hello PDU Sequence Number"},
178 { ISIS_TLV_VENDOR_PRIVATE, "Vendor Private"},
179 { 0, NULL }
180 };
181
182 #define ESIS_OPTION_PROTOCOLS 129
183 #define ESIS_OPTION_QOS_MAINTENANCE 195 /* iso9542 */
184 #define ESIS_OPTION_SECURITY 197 /* iso9542 */
185 #define ESIS_OPTION_ES_CONF_TIME 198 /* iso9542 */
186 #define ESIS_OPTION_PRIORITY 205 /* iso9542 */
187 #define ESIS_OPTION_ADDRESS_MASK 225 /* iso9542 */
188 #define ESIS_OPTION_SNPA_MASK 226 /* iso9542 */
189
190 static struct tok esis_option_values[] = {
191 { ESIS_OPTION_PROTOCOLS, "Protocols supported"},
192 { ESIS_OPTION_QOS_MAINTENANCE, "QoS Maintenance" },
193 { ESIS_OPTION_SECURITY, "Security" },
194 { ESIS_OPTION_ES_CONF_TIME, "ES Configuration Time" },
195 { ESIS_OPTION_PRIORITY, "Priority" },
196 { ESIS_OPTION_ADDRESS_MASK, "Addressk Mask" },
197 { ESIS_OPTION_SNPA_MASK, "SNPA Mask" },
198 { 0, NULL }
199 };
200
201 #define ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP 3 /* draft-ietf-isis-traffic-05 */
202 #define ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID 4 /* draft-ietf-isis-gmpls-extensions */
203 #define ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID 5 /* draft-ietf-isis-traffic-05 */
204 #define ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR 6 /* draft-ietf-isis-traffic-05 */
205 #define ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR 8 /* draft-ietf-isis-traffic-05 */
206 #define ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW 9 /* draft-ietf-isis-traffic-05 */
207 #define ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW 10 /* draft-ietf-isis-traffic-05 */
208 #define ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW 11 /* draft-ietf-isis-traffic-05 */
209 #define ISIS_SUBTLV_EXT_IS_REACH_DIFFSERV_TE 12 /* draft-ietf-tewg-diff-te-proto-06 */
210 #define ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC 18 /* draft-ietf-isis-traffic-05 */
211 #define ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE 20 /* draft-ietf-isis-gmpls-extensions */
212 #define ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR 21 /* draft-ietf-isis-gmpls-extensions */
213
214 static struct tok isis_ext_is_reach_subtlv_values[] = {
215 { ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP, "Administrative groups" },
216 { ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID, "Link Local/Remote Identifier" },
217 { ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID, "Link Remote Identifier" },
218 { ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR, "IPv4 interface address" },
219 { ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR, "IPv4 neighbor address" },
220 { ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW, "Maximum link bandwidth" },
221 { ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW, "Reservable link bandwidth" },
222 { ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW, "Unreserved bandwidth" },
223 { ISIS_SUBTLV_EXT_IS_REACH_DIFFSERV_TE, "Diffserv TE" },
224 { ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC, "Traffic Engineering Metric" },
225 { ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE, "Link Protection Type" },
226 { ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR, "Interface Switching Capability" },
227 { 250, "Reserved for cisco specific extensions" },
228 { 251, "Reserved for cisco specific extensions" },
229 { 252, "Reserved for cisco specific extensions" },
230 { 253, "Reserved for cisco specific extensions" },
231 { 254, "Reserved for cisco specific extensions" },
232 { 255, "Reserved for future expansion" },
233 { 0, NULL }
234 };
235
236 #define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32 1 /* draft-ietf-isis-admin-tags-01 */
237 #define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64 2 /* draft-ietf-isis-admin-tags-01 */
238 #define ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR 117 /* draft-ietf-isis-wg-multi-topology-05 */
239
240 static struct tok isis_ext_ip_reach_subtlv_values[] = {
241 { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32, "32-Bit Administrative tag" },
242 { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64, "64-Bit Administrative tag" },
243 { ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR, "Management Prefix Color" },
244 { 0, NULL }
245 };
246
247 #define ISIS_SUBTLV_AUTH_SIMPLE 1
248 #define ISIS_SUBTLV_AUTH_MD5 54
249 #define ISIS_SUBTLV_AUTH_MD5_LEN 16
250 #define ISIS_SUBTLV_AUTH_PRIVATE 255
251
252 static struct tok isis_subtlv_auth_values[] = {
253 { ISIS_SUBTLV_AUTH_SIMPLE, "simple text password"},
254 { ISIS_SUBTLV_AUTH_MD5, "HMAC-MD5 password"},
255 { ISIS_SUBTLV_AUTH_PRIVATE, "Routing Domain private password"},
256 { 0, NULL }
257 };
258
259 #define ISIS_SUBTLV_IDRP_RES 0
260 #define ISIS_SUBTLV_IDRP_LOCAL 1
261 #define ISIS_SUBTLV_IDRP_ASN 2
262
263 static struct tok isis_subtlv_idrp_values[] = {
264 { ISIS_SUBTLV_IDRP_RES, "Reserved"},
265 { ISIS_SUBTLV_IDRP_LOCAL, "Routing-Domain Specific"},
266 { ISIS_SUBTLV_IDRP_ASN, "AS Number Tag"},
267 { 0, NULL}
268 };
269
270 #define ISIS_MASK_LSP_OL_BIT(x) ((x)&0x4)
271 #define ISIS_MASK_LSP_ISTYPE_BITS(x) ((x)&0x3)
272 #define ISIS_MASK_LSP_PARTITION_BIT(x) ((x)&0x80)
273 #define ISIS_MASK_LSP_ATT_BITS(x) ((x)&0x78)
274 #define ISIS_MASK_LSP_ATT_ERROR_BIT(x) ((x)&0x40)
275 #define ISIS_MASK_LSP_ATT_EXPENSE_BIT(x) ((x)&0x20)
276 #define ISIS_MASK_LSP_ATT_DELAY_BIT(x) ((x)&0x10)
277 #define ISIS_MASK_LSP_ATT_DEFAULT_BIT(x) ((x)&0x8)
278
279 #define ISIS_MASK_MTID(x) ((x)&0x0fff)
280 #define ISIS_MASK_MTFLAGS(x) ((x)&0xf000)
281
282 static struct tok isis_mt_flag_values[] = {
283 { 0x4000, "sub-TLVs present"},
284 { 0x8000, "ATT bit set"},
285 { 0, NULL}
286 };
287
288 #define ISIS_MASK_TLV_EXTD_IP_UPDOWN(x) ((x)&0x80)
289 #define ISIS_MASK_TLV_EXTD_IP_SUBTLV(x) ((x)&0x40)
290
291 #define ISIS_MASK_TLV_EXTD_IP6_IE(x) ((x)&0x40)
292 #define ISIS_MASK_TLV_EXTD_IP6_SUBTLV(x) ((x)&0x20)
293
294 #define ISIS_LSP_TLV_METRIC_SUPPORTED(x) ((x)&0x80)
295 #define ISIS_LSP_TLV_METRIC_IE(x) ((x)&0x40)
296 #define ISIS_LSP_TLV_METRIC_UPDOWN(x) ((x)&0x80)
297 #define ISIS_LSP_TLV_METRIC_VALUE(x) ((x)&0x3f)
298
299 #define ISIS_MASK_TLV_SHARED_RISK_GROUP(x) ((x)&0x1)
300
301 static struct tok isis_mt_values[] = {
302 { 0, "IPv4 unicast"},
303 { 1, "In-Band Management"},
304 { 2, "IPv6 unicast"},
305 { 3, "Multicast"},
306 { 4095, "Development, Experimental or Proprietary"},
307 { 0, NULL }
308 };
309
310 static struct tok isis_iih_circuit_type_values[] = {
311 { 1, "Level 1 only"},
312 { 2, "Level 2 only"},
313 { 3, "Level 1, Level 2"},
314 { 0, NULL}
315 };
316
317 #define ISIS_LSP_TYPE_UNUSED0 0
318 #define ISIS_LSP_TYPE_LEVEL_1 1
319 #define ISIS_LSP_TYPE_UNUSED2 2
320 #define ISIS_LSP_TYPE_LEVEL_2 3
321
322 static struct tok isis_lsp_istype_values[] = {
323 { ISIS_LSP_TYPE_UNUSED0, "Unused 0x0 (invalid)"},
324 { ISIS_LSP_TYPE_LEVEL_1, "L1 IS"},
325 { ISIS_LSP_TYPE_UNUSED2, "Unused 0x2 (invalid)"},
326 { ISIS_LSP_TYPE_LEVEL_2, "L1L2 IS"},
327 { 0, NULL }
328 };
329
330 /*
331 * Katz's point to point adjacency TLV uses codes to tell us the state of
332 * the remote adjacency. Enumerate them.
333 */
334
335 #define ISIS_PTP_ADJ_UP 0
336 #define ISIS_PTP_ADJ_INIT 1
337 #define ISIS_PTP_ADJ_DOWN 2
338
339 static struct tok isis_ptp_adjancey_values[] = {
340 { ISIS_PTP_ADJ_UP, "Up" },
341 { ISIS_PTP_ADJ_INIT, "Initializing" },
342 { ISIS_PTP_ADJ_DOWN, "Down" },
343 { 0, NULL}
344 };
345
346 struct isis_tlv_ptp_adj {
347 u_int8_t adjacency_state;
348 u_int8_t extd_local_circuit_id[4];
349 u_int8_t neighbor_sysid[SYSTEM_ID_LEN];
350 u_int8_t neighbor_extd_local_circuit_id[4];
351 };
352
353 static int osi_cksum(const u_int8_t *, u_int);
354 static int clnp_print(const u_int8_t *, u_int);
355 static void esis_print(const u_int8_t *, u_int);
356 static int isis_print(const u_int8_t *, u_int);
357
358 struct isis_metric_block {
359 u_int8_t metric_default;
360 u_int8_t metric_delay;
361 u_int8_t metric_expense;
362 u_int8_t metric_error;
363 };
364
365 struct isis_tlv_is_reach {
366 struct isis_metric_block isis_metric_block;
367 u_int8_t neighbor_nodeid[NODE_ID_LEN];
368 };
369
370 struct isis_tlv_es_reach {
371 struct isis_metric_block isis_metric_block;
372 u_int8_t neighbor_sysid[SYSTEM_ID_LEN];
373 };
374
375 struct isis_tlv_ip_reach {
376 struct isis_metric_block isis_metric_block;
377 u_int8_t prefix[4];
378 u_int8_t mask[4];
379 };
380
381 static struct tok isis_is_reach_virtual_values[] = {
382 { 0, "IsNotVirtual"},
383 { 1, "IsVirtual"},
384 { 0, NULL }
385 };
386
387 static struct tok isis_restart_flag_values[] = {
388 { 0x1, "Restart Request"},
389 { 0x2, "Restart Acknowledgement"},
390 { 0, NULL }
391 };
392
393 struct isis_common_header {
394 u_int8_t nlpid;
395 u_int8_t fixed_len;
396 u_int8_t version; /* Protocol version */
397 u_int8_t id_length;
398 u_int8_t pdu_type; /* 3 MSbits are reserved */
399 u_int8_t pdu_version; /* Packet format version */
400 u_int8_t reserved;
401 u_int8_t max_area;
402 };
403
404 struct isis_iih_lan_header {
405 u_int8_t circuit_type;
406 u_int8_t source_id[SYSTEM_ID_LEN];
407 u_int8_t holding_time[2];
408 u_int8_t pdu_len[2];
409 u_int8_t priority;
410 u_int8_t lan_id[NODE_ID_LEN];
411 };
412
413 struct isis_iih_ptp_header {
414 u_int8_t circuit_type;
415 u_int8_t source_id[SYSTEM_ID_LEN];
416 u_int8_t holding_time[2];
417 u_int8_t pdu_len[2];
418 u_int8_t circuit_id;
419 };
420
421 struct isis_lsp_header {
422 u_int8_t pdu_len[2];
423 u_int8_t remaining_lifetime[2];
424 u_int8_t lsp_id[LSP_ID_LEN];
425 u_int8_t sequence_number[4];
426 u_int8_t checksum[2];
427 u_int8_t typeblock;
428 };
429
430 struct isis_csnp_header {
431 u_int8_t pdu_len[2];
432 u_int8_t source_id[NODE_ID_LEN];
433 u_int8_t start_lsp_id[LSP_ID_LEN];
434 u_int8_t end_lsp_id[LSP_ID_LEN];
435 };
436
437 struct isis_psnp_header {
438 u_int8_t pdu_len[2];
439 u_int8_t source_id[NODE_ID_LEN];
440 };
441
442 struct isis_tlv_lsp {
443 u_int8_t remaining_lifetime[2];
444 u_int8_t lsp_id[LSP_ID_LEN];
445 u_int8_t sequence_number[4];
446 u_int8_t checksum[2];
447 };
448
449 static char *
450 print_nsap(register const u_int8_t *pptr, register int nsap_length)
451 {
452 int nsap_idx;
453 static char nsap_ascii_output[sizeof("xx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xx")];
454 char *junk_buf = nsap_ascii_output;
455
456 if (nsap_length < 1 || nsap_length > NSAP_MAX_LENGTH) {
457 snprintf(nsap_ascii_output, sizeof(nsap_ascii_output),
458 "illegal length");
459 return (nsap_ascii_output);
460 }
461
462 for (nsap_idx = 0; nsap_idx < nsap_length; nsap_idx++) {
463 if (!TTEST2(*pptr, 1))
464 return (0);
465 snprintf(junk_buf,
466 sizeof(nsap_ascii_output) - (junk_buf - nsap_ascii_output),
467 "%02x", *pptr++);
468 junk_buf += strlen(junk_buf);
469 if (((nsap_idx & 1) == 0) &&
470 (nsap_idx + 1 < nsap_length)) {
471 *junk_buf++ = '.';
472 }
473 }
474 *(junk_buf) = '\0';
475 return (nsap_ascii_output);
476 }
477
478 #define ISIS_COMMON_HEADER_SIZE (sizeof(struct isis_common_header))
479 #define ISIS_IIH_LAN_HEADER_SIZE (sizeof(struct isis_iih_lan_header))
480 #define ISIS_IIH_PTP_HEADER_SIZE (sizeof(struct isis_iih_ptp_header))
481 #define ISIS_LSP_HEADER_SIZE (sizeof(struct isis_lsp_header))
482 #define ISIS_CSNP_HEADER_SIZE (sizeof(struct isis_csnp_header))
483 #define ISIS_PSNP_HEADER_SIZE (sizeof(struct isis_psnp_header))
484
485 void isoclns_print(const u_int8_t *p, u_int length, u_int caplen)
486 {
487 const struct isis_common_header *header;
488
489 header = (const struct isis_common_header *)p;
490
491 if (caplen <= 1) { /* enough bytes on the wire ? */
492 printf("|OSI");
493 return;
494 }
495
496 if (eflag)
497 printf("nlpid %s (0x%02x), ",
498 tok2str(nlpid_values,"Unknown NLPID (0x%02x)",*p),
499 *p);
500
501 switch (*p) {
502
503 case NLPID_CLNP:
504 if (!clnp_print(p, length))
505 print_unknown_data(p,"\n\t",caplen);
506 break;
507
508 case NLPID_ESIS:
509 esis_print(p, length);
510 return;
511
512 case NLPID_ISIS:
513 if (!isis_print(p, length))
514 print_unknown_data(p,"\n\t",caplen);
515 break;
516
517 case NLPID_NULLNS:
518 (void)printf(", length: %u", length);
519 break;
520
521 case NLPID_IP:
522 ip_print(p+1, length-1);
523 break;
524
525 #ifdef INET6
526 case NLPID_IP6:
527 ip6_print(p+1, length-1);
528 break;
529 #endif
530
531 case NLPID_PPP:
532 ppp_print(p+1, length-1);
533 break;
534
535 default:
536 (void)printf(", length: %u", length);
537 if (caplen > 1)
538 print_unknown_data(p,"\n\t",caplen);
539 break;
540 }
541 }
542
543 #define CLNP_PDU_ER 1
544 #define CLNP_PDU_DT 28
545 #define CLNP_PDU_MD 29
546 #define CLNP_PDU_ERQ 30
547 #define CLNP_PDU_ERP 31
548
549 static struct tok clnp_pdu_values[] = {
550 { CLNP_PDU_ER, "Error Report"},
551 { CLNP_PDU_MD, "MD"},
552 { CLNP_PDU_DT, "Data"},
553 { CLNP_PDU_ERQ, "Echo Request"},
554 { CLNP_PDU_ERP, "Echo Response"},
555 { 0, NULL }
556 };
557
558 struct clnp_header_t {
559 u_int8_t nlpid;
560 u_int8_t length_indicator;
561 u_int8_t version;
562 u_int8_t lifetime; /* units of 500ms */
563 u_int8_t type;
564 u_int8_t segment_length[2];
565 u_int8_t cksum[2];
566 };
567
568 /*
569 * clnp_print
570 * Decode CLNP packets. Return 0 on error.
571 */
572
573 static int clnp_print (const u_int8_t *pptr, u_int length)
574 {
575 const u_int8_t *optr,*source_address,*dest_address;
576 u_int li,source_address_length,dest_address_length, clnp_pdu_type;
577 const struct clnp_header_t *clnp_header;
578
579 clnp_header = (const struct clnp_header_t *) pptr;
580 li = clnp_header->length_indicator;
581 optr = pptr;
582
583 if (!eflag)
584 printf("CLNP, ");
585
586 /*
587 * Sanity checking of the header.
588 */
589
590 /* FIXME */
591
592 clnp_pdu_type = clnp_header->type & CLNP_PDU_TYPE_MASK;
593
594 pptr += sizeof(struct clnp_header_t);
595 dest_address_length = *pptr;
596 dest_address = pptr + 1;
597
598 pptr += (1 + dest_address_length);
599 source_address_length = *pptr;
600 source_address = pptr +1;
601
602 pptr += (1 + source_address_length);
603
604 if (vflag < 1) {
605 printf("%s > %s, length %u",
606 print_nsap(source_address, source_address_length),
607 print_nsap(dest_address, dest_address_length),
608 length);
609 return (1);
610 }
611 printf("length %u", length);
612
613 printf("\n\t%s PDU, hlen: %u, v: %u, lifetime: %u.%us, PDU length: %u, checksum: 0x%04x ",
614 tok2str(clnp_pdu_values,
615 "unknown (%u)",
616 clnp_pdu_type),
617 clnp_header->length_indicator,
618 clnp_header->version,
619 clnp_header->lifetime/2,
620 (clnp_header->lifetime%2)*5,
621 EXTRACT_16BITS(clnp_header->segment_length),
622 EXTRACT_16BITS(clnp_header->cksum));
623
624 /* do not attempt to verify the checksum if it is zero */
625 if (EXTRACT_16BITS(clnp_header->cksum) == 0)
626 printf("(unverified)");
627 else printf("(%s)", osi_cksum(optr, li) ? "incorrect" : "correct");
628
629 printf("\n\tsource address (length %u): %s\n\tdest address (length %u): %s",
630 source_address_length,
631 print_nsap(source_address, source_address_length),
632 dest_address_length,
633 print_nsap(dest_address, dest_address_length));
634
635 /* dump the remaining header data */
636 print_unknown_data(pptr,"\n\t",clnp_header->length_indicator-(pptr-optr));
637
638 switch (clnp_pdu_type) {
639
640 case CLNP_PDU_ER:
641 case CLNP_PDU_DT:
642 case CLNP_PDU_MD:
643 case CLNP_PDU_ERQ:
644 case CLNP_PDU_ERP:
645
646 default:
647 /* dump the PDU specific data */
648 print_unknown_data(optr+clnp_header->length_indicator,"\n\t ",length-clnp_header->length_indicator);
649
650 }
651
652 return (1);
653 }
654
655
656 #define ESIS_PDU_REDIRECT 6
657 #define ESIS_PDU_ESH 2
658 #define ESIS_PDU_ISH 4
659
660 static struct tok esis_pdu_values[] = {
661 { ESIS_PDU_REDIRECT, "redirect"},
662 { ESIS_PDU_ESH, "ESH"},
663 { ESIS_PDU_ISH, "ISH"},
664 { 0, NULL }
665 };
666
667 struct esis_header_t {
668 u_int8_t nlpid;
669 u_int8_t length_indicator;
670 u_int8_t version;
671 u_int8_t reserved;
672 u_int8_t type;
673 u_int8_t holdtime[2];
674 u_int8_t cksum[2];
675 };
676
677 static void
678 esis_print(const u_int8_t *pptr, u_int length)
679 {
680 const u_int8_t *optr;
681 u_int li,esis_pdu_type,source_address_length, source_address_number;
682 const struct esis_header_t *esis_header;
683
684 if (!eflag)
685 printf("ES-IS, ");
686
687 if (length <= 2) {
688 if (qflag)
689 printf("bad pkt!");
690 else
691 printf("no header at all!");
692 return;
693 }
694
695 esis_header = (const struct esis_header_t *) pptr;
696 li = esis_header->length_indicator;
697 optr = pptr;
698
699 /*
700 * Sanity checking of the header.
701 */
702
703 if (esis_header->nlpid != NLPID_ESIS) {
704 printf("nlpid 0x%02x packet not supported", esis_header->nlpid);
705 return;
706 }
707
708 if (esis_header->version != ESIS_VERSION) {
709 printf("version %d packet not supported", esis_header->version);
710 return;
711 }
712
713 if (li > length) {
714 printf("length indicator(%d) > PDU size (%d)!", li, length);
715 return;
716 }
717
718 if (li < sizeof(struct esis_header_t) + 2) {
719 printf("length indicator < min PDU size %d:", li);
720 while (--length != 0)
721 printf("%02X", *pptr++);
722 return;
723 }
724
725 esis_pdu_type = esis_header->type & ESIS_PDU_TYPE_MASK;
726
727 if (vflag < 1) {
728 printf("%s, length %u",
729 tok2str(esis_pdu_values,"unknown type (%u)",esis_pdu_type),
730 length);
731 return;
732 } else
733 printf("length %u\n\t%s (%u)",
734 length,
735 tok2str(esis_pdu_values,"unknown type: %u", esis_pdu_type),
736 esis_pdu_type);
737
738 printf(", v: %u%s", esis_header->version, esis_header->version == ESIS_VERSION ? "" : "unsupported" );
739 printf(", checksum: 0x%04x ", EXTRACT_16BITS(esis_header->cksum));
740 /* do not attempt to verify the checksum if it is zero */
741 if (EXTRACT_16BITS(esis_header->cksum) == 0)
742 printf("(unverified)");
743 else printf("(%s)", osi_cksum(pptr, li) ? "incorrect" : "correct");
744
745 printf(", holding time: %us, length indicator: %u",EXTRACT_16BITS(esis_header->holdtime),li);
746
747 if (vflag > 1)
748 print_unknown_data(optr,"\n\t",sizeof(struct esis_header_t));
749
750 pptr += sizeof(struct esis_header_t);
751 li -= sizeof(struct esis_header_t);
752
753 switch (esis_pdu_type) {
754 case ESIS_PDU_REDIRECT: {
755 const u_int8_t *dst, *snpa, *tptr;
756
757 dst = pptr; pptr += *pptr + 1;
758 if (pptr > snapend)
759 return;
760 printf("\n\t %s", isonsap_string(dst));
761 snpa = pptr; pptr += *pptr + 1;
762 tptr = pptr; pptr += *pptr + 1;
763 if (pptr > snapend)
764 return;
765
766 if (tptr[0] == 0)
767 printf("\n\t %s", etheraddr_string(&snpa[1]));
768 else
769 printf("\n\t %s", isonsap_string(tptr));
770 break;
771 }
772
773 case ESIS_PDU_ESH:
774 source_address_number = *pptr;
775 pptr++;
776 li--;
777
778 printf("\n\t Number of Source Addresses: %u", source_address_number);
779
780 while (source_address_number > 0) {
781 source_address_length = *pptr;
782 printf("\n\t NET (length: %u): %s",
783 source_address_length,
784 print_nsap(pptr+1, source_address_length));
785
786 pptr += source_address_length+1;
787 li -= source_address_length+1;
788 source_address_number--;
789 }
790
791 break;
792
793 case ESIS_PDU_ISH: {
794 source_address_length = *pptr;
795 printf("\n\t NET (length: %u): %s", source_address_length, print_nsap(pptr+1, source_address_length));
796 pptr += source_address_length+1;
797 li -= source_address_length +1;
798 break;
799 }
800
801 default:
802 if (vflag <= 1) {
803 if (pptr < snapend)
804 print_unknown_data(pptr,"\n\t ",snapend-pptr);
805 }
806 return;
807 }
808
809 /* now walk the options */
810 while (li >= 2) {
811 u_int op, opli;
812 const u_int8_t *tptr;
813
814 if (snapend - pptr < 2)
815 return;
816 if (li < 2) {
817 printf(", bad opts/li");
818 return;
819 }
820 op = *pptr++;
821 opli = *pptr++;
822 li -= 2;
823 if (opli > li) {
824 printf(", opt (%d) too long", op);
825 return;
826 }
827 li -= opli;
828 tptr = pptr;
829
830 if (snapend < pptr)
831 return;
832
833 printf("\n\t %s Option #%u, length %u, value: ",
834 tok2str(esis_option_values,"Unknown",op),
835 op,
836 opli);
837
838 switch (op) {
839
840 case ESIS_OPTION_ES_CONF_TIME:
841 printf("%us", EXTRACT_16BITS(tptr));
842 break;
843
844
845 case ESIS_OPTION_PROTOCOLS:
846 while (opli>0) {
847 printf("%s (0x%02x)",
848 tok2str(nlpid_values,
849 "unknown",
850 *tptr),
851 *tptr);
852 if (opli>1) /* further NPLIDs ? - put comma */
853 printf(", ");
854 tptr++;
855 opli--;
856 }
857 break;
858
859 /*
860 * FIXME those are the defined Options that lack a decoder
861 * you are welcome to contribute code ;-)
862 */
863
864 case ESIS_OPTION_QOS_MAINTENANCE:
865 case ESIS_OPTION_SECURITY:
866 case ESIS_OPTION_PRIORITY:
867 case ESIS_OPTION_ADDRESS_MASK:
868 case ESIS_OPTION_SNPA_MASK:
869
870 default:
871 print_unknown_data(tptr,"\n\t ",opli);
872 break;
873 }
874 if (vflag > 1)
875 print_unknown_data(pptr,"\n\t ",opli);
876 pptr += opli;
877 }
878 }
879
880 /* shared routine for printing system, node and lsp-ids */
881 static char *
882 isis_print_id(const u_int8_t *cp, int id_len)
883 {
884 int i;
885 static char id[sizeof("xxxx.xxxx.xxxx.yy-zz")];
886 char *pos = id;
887
888 for (i = 1; i <= SYSTEM_ID_LEN; i++) {
889 snprintf(pos, sizeof(id) - (pos - id), "%02x", *cp++);
890 pos += strlen(pos);
891 if (i == 2 || i == 4)
892 *pos++ = '.';
893 }
894 if (id_len >= NODE_ID_LEN) {
895 snprintf(pos, sizeof(id) - (pos - id), ".%02x", *cp++);
896 pos += strlen(pos);
897 }
898 if (id_len == LSP_ID_LEN)
899 snprintf(pos, sizeof(id) - (pos - id), "-%02x", *cp);
900 return (id);
901 }
902
903 /* print the 4-byte metric block which is common found in the old-style TLVs */
904 static int
905 isis_print_metric_block (const struct isis_metric_block *isis_metric_block)
906 {
907 printf(", Default Metric: %d, %s",
908 ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_default),
909 ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_default) ? "External" : "Internal");
910 if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_delay))
911 printf("\n\t\t Delay Metric: %d, %s",
912 ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_delay),
913 ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_delay) ? "External" : "Internal");
914 if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_expense))
915 printf("\n\t\t Expense Metric: %d, %s",
916 ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_expense),
917 ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_expense) ? "External" : "Internal");
918 if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_error))
919 printf("\n\t\t Error Metric: %d, %s",
920 ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_error),
921 ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_error) ? "External" : "Internal");
922
923 return(1); /* everything is ok */
924 }
925
926 static int
927 isis_print_tlv_ip_reach (const u_int8_t *cp, const char *ident, int length)
928 {
929 int prefix_len;
930 const struct isis_tlv_ip_reach *tlv_ip_reach;
931
932 tlv_ip_reach = (const struct isis_tlv_ip_reach *)cp;
933
934 while (length > 0) {
935 if ((size_t)length < sizeof(*tlv_ip_reach)) {
936 printf("short IPv4 Reachability (%d vs %lu)",
937 length,
938 (unsigned long)sizeof(*tlv_ip_reach));
939 return (0);
940 }
941
942 if (!TTEST(*tlv_ip_reach))
943 return (0);
944
945 prefix_len = mask2plen(EXTRACT_32BITS(tlv_ip_reach->mask));
946
947 if (prefix_len == -1)
948 printf("%sIPv4 prefix: %s mask %s",
949 ident,
950 ipaddr_string((tlv_ip_reach->prefix)),
951 ipaddr_string((tlv_ip_reach->mask)));
952 else
953 printf("%sIPv4 prefix: %15s/%u",
954 ident,
955 ipaddr_string((tlv_ip_reach->prefix)),
956 prefix_len);
957
958 printf(", Distribution: %s, Metric: %u, %s",
959 ISIS_LSP_TLV_METRIC_UPDOWN(tlv_ip_reach->isis_metric_block.metric_default) ? "down" : "up",
960 ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_default),
961 ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_default) ? "External" : "Internal");
962
963 if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_delay))
964 printf("%s Delay Metric: %u, %s",
965 ident,
966 ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_delay),
967 ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_delay) ? "External" : "Internal");
968
969 if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_expense))
970 printf("%s Expense Metric: %u, %s",
971 ident,
972 ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_expense),
973 ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_expense) ? "External" : "Internal");
974
975 if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_error))
976 printf("%s Error Metric: %u, %s",
977 ident,
978 ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_error),
979 ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_error) ? "External" : "Internal");
980
981 length -= sizeof(struct isis_tlv_ip_reach);
982 tlv_ip_reach++;
983 }
984 return (1);
985 }
986
987 /*
988 * this is the common IP-REACH subTLV decoder it is called
989 * from various EXTD-IP REACH TLVs (135,235,236,237)
990 */
991
992 static int
993 isis_print_ip_reach_subtlv (const u_int8_t *tptr,int subt,int subl,const char *ident) {
994
995 /* first lets see if we know the subTLVs name*/
996 printf("%s%s subTLV #%u, length: %u",
997 ident,
998 tok2str(isis_ext_ip_reach_subtlv_values,
999 "unknown",
1000 subt),
1001 subt,
1002 subl);
1003
1004 if (!TTEST2(*tptr,subl))
1005 goto trunctlv;
1006
1007 switch(subt) {
1008 case ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR: /* fall through */
1009 case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32:
1010 while (subl >= 4) {
1011 printf(", 0x%08x (=%u)",
1012 EXTRACT_32BITS(tptr),
1013 EXTRACT_32BITS(tptr));
1014 tptr+=4;
1015 subl-=4;
1016 }
1017 break;
1018 case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64:
1019 while (subl >= 8) {
1020 printf(", 0x%08x%08x",
1021 EXTRACT_32BITS(tptr),
1022 EXTRACT_32BITS(tptr+4));
1023 tptr+=8;
1024 subl-=8;
1025 }
1026 break;
1027 default:
1028 if(!print_unknown_data(tptr,"\n\t\t ",
1029 subl))
1030 return(0);
1031 break;
1032 }
1033 return(1);
1034
1035 trunctlv:
1036 printf("%spacket exceeded snapshot",ident);
1037 return(0);
1038 }
1039
1040 /*
1041 * this is the common IS-REACH subTLV decoder it is called
1042 * from isis_print_ext_is_reach()
1043 */
1044
1045 static int
1046 isis_print_is_reach_subtlv (const u_int8_t *tptr,int subt,int subl,const char *ident) {
1047
1048 int priority_level,bandwidth_constraint;
1049 union { /* int to float conversion buffer for several subTLVs */
1050 float f;
1051 u_int32_t i;
1052 } bw;
1053
1054 /* first lets see if we know the subTLVs name*/
1055 printf("%s%s subTLV #%u, length: %u",
1056 ident,
1057 tok2str(isis_ext_is_reach_subtlv_values,
1058 "unknown",
1059 subt),
1060 subt,
1061 subl);
1062
1063 if (!TTEST2(*tptr,subl))
1064 goto trunctlv;
1065
1066 switch(subt) {
1067 case ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP:
1068 case ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID:
1069 case ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID:
1070 if (subl >= 4) {
1071 printf(", 0x%08x", EXTRACT_32BITS(tptr));
1072 if (subl == 8) /* draft-ietf-isis-gmpls-extensions */
1073 printf(", 0x%08x", EXTRACT_32BITS(tptr+4));
1074 }
1075 break;
1076 case ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR:
1077 case ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR:
1078 if (subl >= 4)
1079 printf(", %s", ipaddr_string(tptr));
1080 break;
1081 case ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW :
1082 case ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW:
1083 if (subl >= 4) {
1084 bw.i = EXTRACT_32BITS(tptr);
1085 printf(", %.3f Mbps", bw.f*8/1000000 );
1086 }
1087 break;
1088 case ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW :
1089 if (subl >= 32) {
1090 for (priority_level = 0; priority_level < 8; priority_level++) {
1091 bw.i = EXTRACT_32BITS(tptr);
1092 printf("%s priority level %d: %.3f Mbps",
1093 ident,
1094 priority_level,
1095 bw.f*8/1000000 );
1096 tptr+=4;
1097 }
1098 }
1099 break;
1100 case ISIS_SUBTLV_EXT_IS_REACH_DIFFSERV_TE:
1101 printf("%sBandwidth Constraints Model ID: %s (%u)",
1102 ident,
1103 tok2str(diffserv_te_bc_values, "unknown", *tptr),
1104 *tptr);
1105 tptr++;
1106 /* decode BCs until the subTLV ends */
1107 for (bandwidth_constraint = 0; bandwidth_constraint < (subl-1)/4; bandwidth_constraint++) {
1108 bw.i = EXTRACT_32BITS(tptr);
1109 printf("%s Bandwidth constraint %d: %.3f Mbps",
1110 ident,
1111 bandwidth_constraint,
1112 bw.f*8/1000000 );
1113 tptr+=4;
1114 }
1115 break;
1116 case ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC:
1117 if (subl >= 3)
1118 printf(", %u", EXTRACT_24BITS(tptr));
1119 break;
1120 case ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE:
1121 if (subl >= 2) {
1122 printf(", %s, Priority %u",
1123 bittok2str(gmpls_link_prot_values, "none", *tptr),
1124 *(tptr+1));
1125 }
1126 break;
1127 case ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR:
1128 if (subl >= 36) {
1129 printf("%s Interface Switching Capability:%s",
1130 ident,
1131 tok2str(gmpls_switch_cap_values, "Unknown", *(tptr)));
1132 printf(", LSP Encoding: %s",
1133 tok2str(gmpls_encoding_values, "Unknown", *(tptr+1)));
1134 tptr+=4;
1135 printf("%s Max LSP Bandwidth:",ident);
1136 for (priority_level = 0; priority_level < 8; priority_level++) {
1137 bw.i = EXTRACT_32BITS(tptr);
1138 printf("%s priority level %d: %.3f Mbps",
1139 ident,
1140 priority_level,
1141 bw.f*8/1000000 );
1142 tptr+=4;
1143 }
1144 subl-=36;
1145 /* there is some optional stuff left to decode but this is as of yet
1146 not specified so just lets hexdump what is left */
1147 if(subl>0){
1148 if(!print_unknown_data(tptr,"\n\t\t ",
1149 subl-36))
1150 return(0);
1151 }
1152 }
1153 break;
1154 default:
1155 if(!print_unknown_data(tptr,"\n\t\t ",
1156 subl))
1157 return(0);
1158 break;
1159 }
1160 return(1);
1161
1162 trunctlv:
1163 printf("%spacket exceeded snapshot",ident);
1164 return(0);
1165 }
1166
1167
1168 /*
1169 * this is the common IS-REACH decoder it is called
1170 * from various EXTD-IS REACH style TLVs (22,24,222)
1171 */
1172
1173 static int
1174 isis_print_ext_is_reach (const u_int8_t *tptr,const char *ident, int tlv_type) {
1175
1176 char ident_buffer[20];
1177 int subtlv_type,subtlv_len,subtlv_sum_len;
1178 int proc_bytes = 0; /* how many bytes did we process ? */
1179
1180 if (!TTEST2(*tptr, NODE_ID_LEN))
1181 return(0);
1182
1183 printf("%sIS Neighbor: %s", ident, isis_print_id(tptr, NODE_ID_LEN));
1184 tptr+=(NODE_ID_LEN);
1185
1186 if (tlv_type != ISIS_TLV_IS_ALIAS_ID) { /* the Alias TLV Metric field is implicit 0 */
1187 if (!TTEST2(*tptr, 3)) /* and is therefore skipped */
1188 return(0);
1189 printf(", Metric: %d",EXTRACT_24BITS(tptr));
1190 tptr+=3;
1191 }
1192
1193 if (!TTEST2(*tptr, 1))
1194 return(0);
1195 subtlv_sum_len=*(tptr++); /* read out subTLV length */
1196 proc_bytes=NODE_ID_LEN+3+1;
1197 printf(", %ssub-TLVs present",subtlv_sum_len ? "" : "no ");
1198 if (subtlv_sum_len) {
1199 printf(" (%u)",subtlv_sum_len);
1200 while (subtlv_sum_len>0) {
1201 if (!TTEST2(*tptr,2))
1202 return(0);
1203 subtlv_type=*(tptr++);
1204 subtlv_len=*(tptr++);
1205 /* prepend the ident string */
1206 snprintf(ident_buffer, sizeof(ident_buffer), "%s ",ident);
1207 if(!isis_print_is_reach_subtlv(tptr,subtlv_type,subtlv_len,ident_buffer))
1208 return(0);
1209 tptr+=subtlv_len;
1210 subtlv_sum_len-=(subtlv_len+2);
1211 proc_bytes+=(subtlv_len+2);
1212 }
1213 }
1214 return(proc_bytes);
1215 }
1216
1217 /*
1218 * this is the common Multi Topology ID decoder
1219 * it is called from various MT-TLVs (222,229,235,237)
1220 */
1221
1222 static int
1223 isis_print_mtid (const u_int8_t *tptr,const char *ident) {
1224
1225 if (!TTEST2(*tptr, 2))
1226 return(0);
1227
1228 printf("%s%s",
1229 ident,
1230 tok2str(isis_mt_values,
1231 "Reserved for IETF Consensus",
1232 ISIS_MASK_MTID(EXTRACT_16BITS(tptr))));
1233
1234 printf(" Topology (0x%03x), Flags: [%s]",
1235 ISIS_MASK_MTID(EXTRACT_16BITS(tptr)),
1236 bittok2str(isis_mt_flag_values, "none",ISIS_MASK_MTFLAGS(EXTRACT_16BITS(tptr))));
1237
1238 return(2);
1239 }
1240
1241 /*
1242 * this is the common extended IP reach decoder
1243 * it is called from TLVs (135,235,236,237)
1244 * we process the TLV and optional subTLVs and return
1245 * the amount of processed bytes
1246 */
1247
1248 static int
1249 isis_print_extd_ip_reach (const u_int8_t *tptr, const char *ident, u_int16_t afi) {
1250
1251 char ident_buffer[20];
1252 u_int8_t prefix[16]; /* shared copy buffer for IPv4 and IPv6 prefixes */
1253 u_int metric, status_byte, bit_length, byte_length, sublen, processed, subtlvtype, subtlvlen;
1254
1255 if (!TTEST2(*tptr, 4))
1256 return (0);
1257 metric = EXTRACT_32BITS(tptr);
1258 processed=4;
1259 tptr+=4;
1260
1261 if (afi == IPV4) {
1262 if (!TTEST2(*tptr, 1)) /* fetch status byte */
1263 return (0);
1264 status_byte=*(tptr++);
1265 bit_length = status_byte&0x3f;
1266 processed++;
1267 #ifdef INET6
1268 } else if (afi == IPV6) {
1269 if (!TTEST2(*tptr, 1)) /* fetch status & prefix_len byte */
1270 return (0);
1271 status_byte=*(tptr++);
1272 bit_length=*(tptr++);
1273 processed+=2;
1274 #endif
1275 } else
1276 return (0); /* somebody is fooling us */
1277
1278 byte_length = (bit_length + 7) / 8; /* prefix has variable length encoding */
1279
1280 if (!TTEST2(*tptr, byte_length))
1281 return (0);
1282 memset(prefix, 0, 16); /* clear the copy buffer */
1283 memcpy(prefix,tptr,byte_length); /* copy as much as is stored in the TLV */
1284 tptr+=byte_length;
1285 processed+=byte_length;
1286
1287 if (afi == IPV4)
1288 printf("%sIPv4 prefix: %15s/%u",
1289 ident,
1290 ipaddr_string(prefix),
1291 bit_length);
1292 #ifdef INET6
1293 if (afi == IPV6)
1294 printf("%sIPv6 prefix: %s/%u",
1295 ident,
1296 ip6addr_string(prefix),
1297 bit_length);
1298 #endif
1299
1300 printf(", Distribution: %s, Metric: %u",
1301 ISIS_MASK_TLV_EXTD_IP_UPDOWN(status_byte) ? "down" : "up",
1302 metric);
1303
1304 if (afi == IPV4 && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
1305 printf(", sub-TLVs present");
1306 #ifdef INET6
1307 if (afi == IPV6)
1308 printf(", %s%s",
1309 ISIS_MASK_TLV_EXTD_IP6_IE(status_byte) ? "External" : "Internal",
1310 ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) ? ", sub-TLVs present" : "");
1311 #endif
1312
1313 if ((ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte) && afi == IPV4) ||
1314 (ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) && afi == IPV6)) {
1315 /* assume that one prefix can hold more
1316 than one subTLV - therefore the first byte must reflect
1317 the aggregate bytecount of the subTLVs for this prefix
1318 */
1319 if (!TTEST2(*tptr, 1))
1320 return (0);
1321 sublen=*(tptr++);
1322 processed+=sublen+1;
1323 printf(" (%u)",sublen); /* print out subTLV length */
1324
1325 while (sublen>0) {
1326 if (!TTEST2(*tptr,2))
1327 return (0);
1328 subtlvtype=*(tptr++);
1329 subtlvlen=*(tptr++);
1330 /* prepend the ident string */
1331 snprintf(ident_buffer, sizeof(ident_buffer), "%s ",ident);
1332 if(!isis_print_ip_reach_subtlv(tptr,subtlvtype,subtlvlen,ident_buffer))
1333 return(0);
1334 tptr+=subtlvlen;
1335 sublen-=(subtlvlen+2);
1336 }
1337 }
1338 return (processed);
1339 }
1340
1341 /*
1342 * isis_print
1343 * Decode IS-IS packets. Return 0 on error.
1344 */
1345
1346 static int isis_print (const u_int8_t *p, u_int length)
1347 {
1348 const struct isis_common_header *isis_header;
1349
1350 const struct isis_iih_lan_header *header_iih_lan;
1351 const struct isis_iih_ptp_header *header_iih_ptp;
1352 const struct isis_lsp_header *header_lsp;
1353 const struct isis_csnp_header *header_csnp;
1354 const struct isis_psnp_header *header_psnp;
1355
1356 const struct isis_tlv_lsp *tlv_lsp;
1357 const struct isis_tlv_ptp_adj *tlv_ptp_adj;
1358 const struct isis_tlv_is_reach *tlv_is_reach;
1359 const struct isis_tlv_es_reach *tlv_es_reach;
1360
1361 u_int8_t pdu_type, max_area, id_length, tlv_type, tlv_len, tmp, alen, lan_alen, prefix_len;
1362 u_int8_t ext_is_len, ext_ip_len, mt_len;
1363 const u_int8_t *optr, *pptr, *tptr;
1364 u_short packet_len,pdu_len;
1365 u_int i,vendor_id;
1366
1367 packet_len=length;
1368 optr = p; /* initialize the _o_riginal pointer to the packet start -
1369 need it for parsing the checksum TLV */
1370 isis_header = (const struct isis_common_header *)p;
1371 TCHECK(*isis_header);
1372 pptr = p+(ISIS_COMMON_HEADER_SIZE);
1373 header_iih_lan = (const struct isis_iih_lan_header *)pptr;
1374 header_iih_ptp = (const struct isis_iih_ptp_header *)pptr;
1375 header_lsp = (const struct isis_lsp_header *)pptr;
1376 header_csnp = (const struct isis_csnp_header *)pptr;
1377 header_psnp = (const struct isis_psnp_header *)pptr;
1378
1379 if (!eflag)
1380 printf("IS-IS, ");
1381
1382 /*
1383 * Sanity checking of the header.
1384 */
1385
1386 if (isis_header->version != ISIS_VERSION) {
1387 printf("version %d packet not supported", isis_header->version);
1388 return (0);
1389 }
1390
1391 if ((isis_header->id_length != SYSTEM_ID_LEN) && (isis_header->id_length != 0)) {
1392 printf("system ID length of %d is not supported",
1393 isis_header->id_length);
1394 return (0);
1395 }
1396
1397 if (isis_header->pdu_version != ISIS_VERSION) {
1398 printf("version %d packet not supported", isis_header->pdu_version);
1399 return (0);
1400 }
1401
1402 max_area = isis_header->max_area;
1403 switch(max_area) {
1404 case 0:
1405 max_area = 3; /* silly shit */
1406 break;
1407 case 255:
1408 printf("bad packet -- 255 areas");
1409 return (0);
1410 default:
1411 break;
1412 }
1413
1414 id_length = isis_header->id_length;
1415 switch(id_length) {
1416 case 0:
1417 id_length = 6; /* silly shit again */
1418 break;
1419 case 1: /* 1-8 are valid sys-ID lenghts */
1420 case 2:
1421 case 3:
1422 case 4:
1423 case 5:
1424 case 6:
1425 case 7:
1426 case 8:
1427 break;
1428 case 255:
1429 id_length = 0; /* entirely useless */
1430 break;
1431 default:
1432 break;
1433 }
1434
1435 /* toss any non 6-byte sys-ID len PDUs */
1436 if (id_length != 6 ) {
1437 printf("bad packet -- illegal sys-ID length (%u)", id_length);
1438 return (0);
1439 }
1440
1441 pdu_type=isis_header->pdu_type;
1442
1443 /* in non-verbose mode print the basic PDU Type plus PDU specific brief information*/
1444 if (vflag < 1) {
1445 printf("%s", tok2str(isis_pdu_values,"unknown PDU-Type %u",pdu_type));
1446
1447 switch (pdu_type) {
1448
1449 case ISIS_PDU_L1_LAN_IIH:
1450 case ISIS_PDU_L2_LAN_IIH:
1451 printf(", src-id %s",
1452 isis_print_id(header_iih_lan->source_id,SYSTEM_ID_LEN));
1453 printf(", lan-id %s, prio %u",
1454 isis_print_id(header_iih_lan->lan_id,NODE_ID_LEN),
1455 header_iih_lan->priority);
1456 break;
1457 case ISIS_PDU_PTP_IIH:
1458 printf(", src-id %s", isis_print_id(header_iih_ptp->source_id,SYSTEM_ID_LEN));
1459 break;
1460 case ISIS_PDU_L1_LSP:
1461 case ISIS_PDU_L2_LSP:
1462 printf(", lsp-id %s, seq 0x%08x, lifetime %5us",
1463 isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
1464 EXTRACT_32BITS(header_lsp->sequence_number),
1465 EXTRACT_16BITS(header_lsp->remaining_lifetime));
1466 break;
1467 case ISIS_PDU_L1_CSNP:
1468 case ISIS_PDU_L2_CSNP:
1469 printf(", src-id %s", isis_print_id(header_csnp->source_id,NODE_ID_LEN));
1470 break;
1471 case ISIS_PDU_L1_PSNP:
1472 case ISIS_PDU_L2_PSNP:
1473 printf(", src-id %s", isis_print_id(header_psnp->source_id,NODE_ID_LEN));
1474 break;
1475
1476 }
1477 printf(", length %u", length);
1478
1479 return(1);
1480 }
1481
1482 /* ok they seem to want to know everything - lets fully decode it */
1483 printf(", length: %u",length);
1484
1485 printf("\n\t%s, hlen: %u, v: %u, pdu-v: %u, sys-id-len: %u (%u), max-area: %u (%u)",
1486 tok2str(isis_pdu_values,
1487 "unknown, type %u",
1488 pdu_type),
1489 isis_header->fixed_len,
1490 isis_header->version,
1491 isis_header->pdu_version,
1492 id_length,
1493 isis_header->id_length,
1494 max_area,
1495 isis_header->max_area);
1496
1497 if (vflag > 1) {
1498 if(!print_unknown_data(optr,"\n\t",8)) /* provide the _o_riginal pointer */
1499 return(0); /* for optionally debugging the common header */
1500 }
1501
1502 switch (pdu_type) {
1503
1504 case ISIS_PDU_L1_LAN_IIH:
1505 case ISIS_PDU_L2_LAN_IIH:
1506 if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE)) {
1507 printf(", bogus fixed header length %u should be %lu",
1508 isis_header->fixed_len, (unsigned long)ISIS_IIH_LAN_HEADER_SIZE);
1509 return (0);
1510 }
1511
1512 pdu_len=EXTRACT_16BITS(header_iih_lan->pdu_len);
1513 if (packet_len>pdu_len) {
1514 packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1515 length=pdu_len;
1516 }
1517
1518 TCHECK(*header_iih_lan);
1519 printf("\n\t source-id: %s, holding time: %us, Flags: [%s]",
1520 isis_print_id(header_iih_lan->source_id,SYSTEM_ID_LEN),
1521 EXTRACT_16BITS(header_iih_lan->holding_time),
1522 tok2str(isis_iih_circuit_type_values,
1523 "unknown circuit type 0x%02x",
1524 header_iih_lan->circuit_type));
1525
1526 printf("\n\t lan-id: %s, Priority: %u, PDU length: %u",
1527 isis_print_id(header_iih_lan->lan_id, NODE_ID_LEN),
1528 (header_iih_lan->priority) & ISIS_LAN_PRIORITY_MASK,
1529 pdu_len);
1530
1531 if (vflag > 1) {
1532 if(!print_unknown_data(pptr,"\n\t ",ISIS_IIH_LAN_HEADER_SIZE))
1533 return(0);
1534 }
1535
1536 packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
1537 pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
1538 break;
1539
1540 case ISIS_PDU_PTP_IIH:
1541 if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE)) {
1542 printf(", bogus fixed header length %u should be %lu",
1543 isis_header->fixed_len, (unsigned long)ISIS_IIH_PTP_HEADER_SIZE);
1544 return (0);
1545 }
1546
1547 pdu_len=EXTRACT_16BITS(header_iih_ptp->pdu_len);
1548 if (packet_len>pdu_len) {
1549 packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1550 length=pdu_len;
1551 }
1552
1553 TCHECK(*header_iih_ptp);
1554 printf("\n\t source-id: %s, holding time: %us, Flags: [%s]",
1555 isis_print_id(header_iih_ptp->source_id,SYSTEM_ID_LEN),
1556 EXTRACT_16BITS(header_iih_ptp->holding_time),
1557 tok2str(isis_iih_circuit_type_values,
1558 "unknown circuit type 0x%02x",
1559 header_iih_ptp->circuit_type));
1560
1561 printf("\n\t circuit-id: 0x%02x, PDU length: %u",
1562 header_iih_ptp->circuit_id,
1563 pdu_len);
1564
1565 if (vflag > 1) {
1566 if(!print_unknown_data(pptr,"\n\t ",ISIS_IIH_PTP_HEADER_SIZE))
1567 return(0);
1568 }
1569
1570 packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
1571 pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
1572 break;
1573
1574 case ISIS_PDU_L1_LSP:
1575 case ISIS_PDU_L2_LSP:
1576 if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE)) {
1577 printf(", bogus fixed header length %u should be %lu",
1578 isis_header->fixed_len, (unsigned long)ISIS_LSP_HEADER_SIZE);
1579 return (0);
1580 }
1581
1582 pdu_len=EXTRACT_16BITS(header_lsp->pdu_len);
1583 if (packet_len>pdu_len) {
1584 packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1585 length=pdu_len;
1586 }
1587
1588 TCHECK(*header_lsp);
1589 printf("\n\t lsp-id: %s, seq: 0x%08x, lifetime: %5us\n\t chksum: 0x%04x",
1590 isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
1591 EXTRACT_32BITS(header_lsp->sequence_number),
1592 EXTRACT_16BITS(header_lsp->remaining_lifetime),
1593 EXTRACT_16BITS(header_lsp->checksum));
1594
1595 /* if this is a purge do not attempt to verify the checksum */
1596 if ( EXTRACT_16BITS(header_lsp->remaining_lifetime) == 0 &&
1597 EXTRACT_16BITS(header_lsp->checksum) == 0)
1598 printf(" (purged)");
1599 else
1600 /* verify the checksum -
1601 * checking starts at the lsp-id field at byte position [12]
1602 * hence the length needs to be reduced by 12 bytes */
1603 printf(" (%s)", (osi_cksum((u_int8_t *)header_lsp->lsp_id, length-12)) ? "incorrect" : "correct");
1604
1605 printf(", PDU length: %u, Flags: [ %s",
1606 pdu_len,
1607 ISIS_MASK_LSP_OL_BIT(header_lsp->typeblock) ? "Overload bit set, " : "");
1608
1609 if (ISIS_MASK_LSP_ATT_BITS(header_lsp->typeblock)) {
1610 printf("%s", ISIS_MASK_LSP_ATT_DEFAULT_BIT(header_lsp->typeblock) ? "default " : "");
1611 printf("%s", ISIS_MASK_LSP_ATT_DELAY_BIT(header_lsp->typeblock) ? "delay " : "");
1612 printf("%s", ISIS_MASK_LSP_ATT_EXPENSE_BIT(header_lsp->typeblock) ? "expense " : "");
1613 printf("%s", ISIS_MASK_LSP_ATT_ERROR_BIT(header_lsp->typeblock) ? "error " : "");
1614 printf("ATT bit set, ");
1615 }
1616 printf("%s", ISIS_MASK_LSP_PARTITION_BIT(header_lsp->typeblock) ? "P bit set, " : "");
1617 printf("%s ]", tok2str(isis_lsp_istype_values,"Unknown(0x%x)",ISIS_MASK_LSP_ISTYPE_BITS(header_lsp->typeblock)));
1618
1619 if (vflag > 1) {
1620 if(!print_unknown_data(pptr,"\n\t ",ISIS_LSP_HEADER_SIZE))
1621 return(0);
1622 }
1623
1624 packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
1625 pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
1626 break;
1627
1628 case ISIS_PDU_L1_CSNP:
1629 case ISIS_PDU_L2_CSNP:
1630 if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE)) {
1631 printf(", bogus fixed header length %u should be %lu",
1632 isis_header->fixed_len, (unsigned long)ISIS_CSNP_HEADER_SIZE);
1633 return (0);
1634 }
1635
1636 pdu_len=EXTRACT_16BITS(header_csnp->pdu_len);
1637 if (packet_len>pdu_len) {
1638 packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1639 length=pdu_len;
1640 }
1641
1642 TCHECK(*header_csnp);
1643 printf("\n\t source-id: %s, PDU length: %u",
1644 isis_print_id(header_csnp->source_id, NODE_ID_LEN),
1645 pdu_len);
1646 printf("\n\t start lsp-id: %s",
1647 isis_print_id(header_csnp->start_lsp_id, LSP_ID_LEN));
1648 printf("\n\t end lsp-id: %s",
1649 isis_print_id(header_csnp->end_lsp_id, LSP_ID_LEN));
1650
1651 if (vflag > 1) {
1652 if(!print_unknown_data(pptr,"\n\t ",ISIS_CSNP_HEADER_SIZE))
1653 return(0);
1654 }
1655
1656 packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
1657 pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
1658 break;
1659
1660 case ISIS_PDU_L1_PSNP:
1661 case ISIS_PDU_L2_PSNP:
1662 if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE)) {
1663 printf("- bogus fixed header length %u should be %lu",
1664 isis_header->fixed_len, (unsigned long)ISIS_PSNP_HEADER_SIZE);
1665 return (0);
1666 }
1667
1668 pdu_len=EXTRACT_16BITS(header_psnp->pdu_len);
1669 if (packet_len>pdu_len) {
1670 packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1671 length=pdu_len;
1672 }
1673
1674 TCHECK(*header_psnp);
1675 printf("\n\t source-id: %s, PDU length: %u",
1676 isis_print_id(header_psnp->source_id, NODE_ID_LEN),
1677 pdu_len);
1678
1679 if (vflag > 1) {
1680 if(!print_unknown_data(pptr,"\n\t ",ISIS_PSNP_HEADER_SIZE))
1681 return(0);
1682 }
1683
1684 packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
1685 pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
1686 break;
1687
1688 default:
1689 if(!print_unknown_data(pptr,"\n\t ",length))
1690 return(0);
1691 return (0);
1692 }
1693
1694 /*
1695 * Now print the TLV's.
1696 */
1697
1698 while (packet_len >= 2) {
1699 if (pptr == snapend) {
1700 return (1);
1701 }
1702
1703 if (!TTEST2(*pptr, 2)) {
1704 printf("\n\t\t packet exceeded snapshot (%ld) bytes",
1705 (long)(pptr-snapend));
1706 return (1);
1707 }
1708 tlv_type = *pptr++;
1709 tlv_len = *pptr++;
1710 tmp =tlv_len; /* copy temporary len & pointer to packet data */
1711 tptr = pptr;
1712 packet_len -= 2;
1713 if (tlv_len > packet_len) {
1714 break;
1715 }
1716
1717 /* first lets see if we know the TLVs name*/
1718 printf("\n\t %s TLV #%u, length: %u",
1719 tok2str(isis_tlv_values,
1720 "unknown",
1721 tlv_type),
1722 tlv_type,
1723 tlv_len);
1724
1725 /* now check if we have a decoder otherwise do a hexdump at the end*/
1726 switch (tlv_type) {
1727 case ISIS_TLV_AREA_ADDR:
1728 if (!TTEST2(*tptr, 1))
1729 goto trunctlv;
1730 alen = *tptr++;
1731 while (tmp && alen < tmp) {
1732 printf("\n\t Area address (length: %u): %s",
1733 alen,
1734 print_nsap(tptr, alen));
1735 tptr += alen;
1736 tmp -= alen + 1;
1737 if (tmp==0) /* if this is the last area address do not attemt a boundary check */
1738 break;
1739 if (!TTEST2(*tptr, 1))
1740 goto trunctlv;
1741 alen = *tptr++;
1742 }
1743 break;
1744 case ISIS_TLV_ISNEIGH:
1745 while (tmp >= ETHER_ADDR_LEN) {
1746 if (!TTEST2(*tptr, ETHER_ADDR_LEN))
1747 goto trunctlv;
1748 printf("\n\t SNPA: %s",isis_print_id(tptr,ETHER_ADDR_LEN));
1749 tmp -= ETHER_ADDR_LEN;
1750 tptr += ETHER_ADDR_LEN;
1751 }
1752 break;
1753
1754 case ISIS_TLV_ISNEIGH_VARLEN:
1755 if (!TTEST2(*tptr, 1))
1756 goto trunctlv;
1757 lan_alen = *tptr++; /* LAN adress length */
1758 tmp --;
1759 printf("\n\t LAN address length %u bytes ",lan_alen);
1760 while (tmp >= lan_alen) {
1761 if (!TTEST2(*tptr, lan_alen))
1762 goto trunctlv;
1763 printf("\n\t\tIS Neighbor: %s",isis_print_id(tptr,lan_alen));
1764 tmp -= lan_alen;
1765 tptr +=lan_alen;
1766 }
1767 break;
1768
1769 case ISIS_TLV_PADDING:
1770 break;
1771
1772 case ISIS_TLV_MT_IS_REACH:
1773 while (tmp >= 2+NODE_ID_LEN+3+1) {
1774 mt_len = isis_print_mtid(tptr, "\n\t ");
1775 if (mt_len == 0) /* did something go wrong ? */
1776 goto trunctlv;
1777 tptr+=mt_len;
1778 tmp-=mt_len;
1779
1780 ext_is_len = isis_print_ext_is_reach(tptr,"\n\t ",tlv_type);
1781 if (ext_is_len == 0) /* did something go wrong ? */
1782 goto trunctlv;
1783
1784 tmp-=ext_is_len;
1785 tptr+=ext_is_len;
1786 }
1787 break;
1788
1789 case ISIS_TLV_IS_ALIAS_ID:
1790 while (tmp >= NODE_ID_LEN+1) { /* is it worth attempting a decode ? */
1791 ext_is_len = isis_print_ext_is_reach(tptr,"\n\t ",tlv_type);
1792 if (ext_is_len == 0) /* did something go wrong ? */
1793 goto trunctlv;
1794 tmp-=ext_is_len;
1795 tptr+=ext_is_len;
1796 }
1797 break;
1798
1799 case ISIS_TLV_EXT_IS_REACH:
1800 while (tmp >= NODE_ID_LEN+3+1) { /* is it worth attempting a decode ? */
1801 ext_is_len = isis_print_ext_is_reach(tptr,"\n\t ",tlv_type);
1802 if (ext_is_len == 0) /* did something go wrong ? */
1803 goto trunctlv;
1804 tmp-=ext_is_len;
1805 tptr+=ext_is_len;
1806 }
1807 break;
1808 case ISIS_TLV_IS_REACH:
1809 if (!TTEST2(*tptr,1)) /* check if there is one byte left to read out the virtual flag */
1810 goto trunctlv;
1811 printf("\n\t %s",
1812 tok2str(isis_is_reach_virtual_values,
1813 "bogus virtual flag 0x%02x",
1814 *tptr++));
1815 tlv_is_reach = (const struct isis_tlv_is_reach *)tptr;
1816 while (tmp >= sizeof(struct isis_tlv_is_reach)) {
1817 if (!TTEST(*tlv_is_reach))
1818 goto trunctlv;
1819 printf("\n\t IS Neighbor: %s",
1820 isis_print_id(tlv_is_reach->neighbor_nodeid, NODE_ID_LEN));
1821 isis_print_metric_block(&tlv_is_reach->isis_metric_block);
1822 tmp -= sizeof(struct isis_tlv_is_reach);
1823 tlv_is_reach++;
1824 }
1825 break;
1826
1827 case ISIS_TLV_ESNEIGH:
1828 tlv_es_reach = (const struct isis_tlv_es_reach *)tptr;
1829 while (tmp >= sizeof(struct isis_tlv_es_reach)) {
1830 if (!TTEST(*tlv_es_reach))
1831 goto trunctlv;
1832 printf("\n\t ES Neighbor: %s",
1833 isis_print_id(tlv_es_reach->neighbor_sysid,SYSTEM_ID_LEN));
1834 isis_print_metric_block(&tlv_es_reach->isis_metric_block);
1835 tmp -= sizeof(struct isis_tlv_es_reach);
1836 tlv_es_reach++;
1837 }
1838 break;
1839
1840 /* those two TLVs share the same format */
1841 case ISIS_TLV_INT_IP_REACH:
1842 case ISIS_TLV_EXT_IP_REACH:
1843 if (!isis_print_tlv_ip_reach(pptr, "\n\t ", tlv_len))
1844 return (1);
1845 break;
1846
1847 case ISIS_TLV_EXTD_IP_REACH:
1848 while (tmp>0) {
1849 ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t ", IPV4);
1850 if (ext_ip_len == 0) /* did something go wrong ? */
1851 goto trunctlv;
1852 tptr+=ext_ip_len;
1853 tmp-=ext_ip_len;
1854 }
1855 break;
1856
1857 case ISIS_TLV_MT_IP_REACH:
1858 while (tmp>0) {
1859 mt_len = isis_print_mtid(tptr, "\n\t ");
1860 if (mt_len == 0) /* did something go wrong ? */
1861 goto trunctlv;
1862 tptr+=mt_len;
1863 tmp-=mt_len;
1864
1865 ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t ", IPV4);
1866 if (ext_ip_len == 0) /* did something go wrong ? */
1867 goto trunctlv;
1868 tptr+=ext_ip_len;
1869 tmp-=ext_ip_len;
1870 }
1871 break;
1872
1873 #ifdef INET6
1874 case ISIS_TLV_IP6_REACH:
1875 while (tmp>0) {
1876 ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t ", IPV6);
1877 if (ext_ip_len == 0) /* did something go wrong ? */
1878 goto trunctlv;
1879 tptr+=ext_ip_len;
1880 tmp-=ext_ip_len;
1881 }
1882 break;
1883
1884 case ISIS_TLV_MT_IP6_REACH:
1885 while (tmp>0) {
1886 mt_len = isis_print_mtid(tptr, "\n\t ");
1887 if (mt_len == 0) /* did something go wrong ? */
1888 goto trunctlv;
1889 tptr+=mt_len;
1890 tmp-=mt_len;
1891
1892 ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t ", IPV6);
1893 if (ext_ip_len == 0) /* did something go wrong ? */
1894 goto trunctlv;
1895 tptr+=ext_ip_len;
1896 tmp-=ext_ip_len;
1897 }
1898 break;
1899
1900 case ISIS_TLV_IP6ADDR:
1901 while (tmp>0) {
1902 if (!TTEST2(*tptr, 16))
1903 goto trunctlv;
1904
1905 printf("\n\t IPv6 interface address: %s",
1906 ip6addr_string(tptr));
1907
1908 tptr += 16;
1909 tmp -= 16;
1910 }
1911 break;
1912 #endif
1913 case ISIS_TLV_AUTH:
1914 if (!TTEST2(*tptr, 1))
1915 goto trunctlv;
1916
1917 printf("\n\t %s: ",
1918 tok2str(isis_subtlv_auth_values,
1919 "unknown Authentication type 0x%02x",
1920 *tptr));
1921
1922 switch (*tptr) {
1923 case ISIS_SUBTLV_AUTH_SIMPLE:
1924 for(i=1;i<tlv_len;i++) {
1925 if (!TTEST2(*(tptr+i), 1))
1926 goto trunctlv;
1927 printf("%c",*(tptr+i));
1928 }
1929 break;
1930 case ISIS_SUBTLV_AUTH_MD5:
1931 for(i=1;i<tlv_len;i++) {
1932 if (!TTEST2(*(tptr+i), 1))
1933 goto trunctlv;
1934 printf("%02x",*(tptr+i));
1935 }
1936 if (tlv_len != ISIS_SUBTLV_AUTH_MD5_LEN+1)
1937 printf(", (malformed subTLV) ");
1938 break;
1939 case ISIS_SUBTLV_AUTH_PRIVATE:
1940 default:
1941 if(!print_unknown_data(tptr+1,"\n\t\t ",tlv_len-1))
1942 return(0);
1943 break;
1944 }
1945 break;
1946
1947 case ISIS_TLV_PTP_ADJ:
1948 tlv_ptp_adj = (const struct isis_tlv_ptp_adj *)tptr;
1949 if(tmp>=1) {
1950 if (!TTEST2(*tptr, 1))
1951 goto trunctlv;
1952 printf("\n\t Adjacency State: %s (%u)",
1953 tok2str(isis_ptp_adjancey_values, "unknown", *tptr),
1954 *tptr);
1955 tmp--;
1956 }
1957 if(tmp>sizeof(tlv_ptp_adj->extd_local_circuit_id)) {
1958 if (!TTEST2(tlv_ptp_adj->extd_local_circuit_id,
1959 sizeof(tlv_ptp_adj->extd_local_circuit_id)))
1960 goto trunctlv;
1961 printf("\n\t Extended Local circuit-ID: 0x%08x",
1962 EXTRACT_32BITS(tlv_ptp_adj->extd_local_circuit_id));
1963 tmp-=sizeof(tlv_ptp_adj->extd_local_circuit_id);
1964 }
1965 if(tmp>=SYSTEM_ID_LEN) {
1966 if (!TTEST2(tlv_ptp_adj->neighbor_sysid, SYSTEM_ID_LEN))
1967 goto trunctlv;
1968 printf("\n\t Neighbor System-ID: %s",
1969 isis_print_id(tlv_ptp_adj->neighbor_sysid,SYSTEM_ID_LEN));
1970 tmp-=SYSTEM_ID_LEN;
1971 }
1972 if(tmp>=sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)) {
1973 if (!TTEST2(tlv_ptp_adj->neighbor_extd_local_circuit_id,
1974 sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)))
1975 goto trunctlv;
1976 printf("\n\t Neighbor Extended Local circuit-ID: 0x%08x",
1977 EXTRACT_32BITS(tlv_ptp_adj->neighbor_extd_local_circuit_id));
1978 }
1979 break;
1980
1981 case ISIS_TLV_PROTOCOLS:
1982 printf("\n\t NLPID(s): ");
1983 while (tmp>0) {
1984 if (!TTEST2(*(tptr), 1))
1985 goto trunctlv;
1986 printf("%s (0x%02x)",
1987 tok2str(nlpid_values,
1988 "unknown",
1989 *tptr),
1990 *tptr);
1991 if (tmp>1) /* further NPLIDs ? - put comma */
1992 printf(", ");
1993 tptr++;
1994 tmp--;
1995 }
1996 break;
1997
1998 case ISIS_TLV_TE_ROUTER_ID:
1999 if (!TTEST2(*pptr, 4))
2000 goto trunctlv;
2001 printf("\n\t Traffic Engineering Router ID: %s", ipaddr_string(pptr));
2002 break;
2003
2004 case ISIS_TLV_IPADDR:
2005 while (tmp>0) {
2006 if (!TTEST2(*tptr, 4))
2007 goto trunctlv;
2008 printf("\n\t IPv4 interface address: %s", ipaddr_string(tptr));
2009 tptr += 4;
2010 tmp -= 4;
2011 }
2012 break;
2013
2014 case ISIS_TLV_HOSTNAME:
2015 printf("\n\t Hostname: ");
2016 while (tmp>0) {
2017 if (!TTEST2(*tptr, 1))
2018 goto trunctlv;
2019 printf("%c",*tptr++);
2020 tmp--;
2021 }
2022 break;
2023
2024 case ISIS_TLV_SHARED_RISK_GROUP:
2025 if (!TTEST2(*tptr, NODE_ID_LEN))
2026 goto trunctlv;
2027 printf("\n\t IS Neighbor: %s", isis_print_id(tptr, NODE_ID_LEN));
2028 tptr+=(NODE_ID_LEN);
2029 tmp-=(NODE_ID_LEN);
2030
2031 if (!TTEST2(*tptr, 1))
2032 goto trunctlv;
2033 printf(", Flags: [%s]", ISIS_MASK_TLV_SHARED_RISK_GROUP(*tptr++) ? "numbered" : "unnumbered");
2034 tmp--;
2035
2036 if (!TTEST2(*tptr,4))
2037 goto trunctlv;
2038 printf("\n\t IPv4 interface address: %s", ipaddr_string(tptr));
2039 tptr+=4;
2040 tmp-=4;
2041
2042 if (!TTEST2(*tptr,4))
2043 goto trunctlv;
2044 printf("\n\t IPv4 neighbor address: %s", ipaddr_string(tptr));
2045 tptr+=4;
2046 tmp-=4;
2047
2048 while (tmp>0) {
2049 if (!TTEST2(*tptr, 4))
2050 goto trunctlv;
2051 printf("\n\t Link-ID: 0x%08x", EXTRACT_32BITS(tptr));
2052 tptr+=4;
2053 tmp-=4;
2054 }
2055 break;
2056
2057 case ISIS_TLV_LSP:
2058 tlv_lsp = (const struct isis_tlv_lsp *)tptr;
2059 while(tmp>0) {
2060 if (!TTEST((tlv_lsp->lsp_id)[LSP_ID_LEN-1]))
2061 goto trunctlv;
2062 printf("\n\t lsp-id: %s",
2063 isis_print_id(tlv_lsp->lsp_id, LSP_ID_LEN));
2064 if (!TTEST2(tlv_lsp->sequence_number, 4))
2065 goto trunctlv;
2066 printf(", seq: 0x%08x",EXTRACT_32BITS(tlv_lsp->sequence_number));
2067 if (!TTEST2(tlv_lsp->remaining_lifetime, 2))
2068 goto trunctlv;
2069 printf(", lifetime: %5ds",EXTRACT_16BITS(tlv_lsp->remaining_lifetime));
2070 if (!TTEST2(tlv_lsp->checksum, 2))
2071 goto trunctlv;
2072 printf(", chksum: 0x%04x",EXTRACT_16BITS(tlv_lsp->checksum));
2073 tmp-=sizeof(struct isis_tlv_lsp);
2074 tlv_lsp++;
2075 }
2076 break;
2077
2078 case ISIS_TLV_CHECKSUM:
2079 if (!TTEST2(*tptr, 2))
2080 goto trunctlv;
2081 printf("\n\t checksum: 0x%04x ", EXTRACT_16BITS(tptr));
2082 /* do not attempt to verify the checksum if it is zero
2083 * most likely a HMAC-MD5 TLV is also present and
2084 * to avoid conflicts the checksum TLV is zeroed.
2085 * see rfc3358 for details
2086 */
2087 if (EXTRACT_16BITS(tptr) == 0)
2088 printf("(unverified)");
2089 else printf("(%s)", osi_cksum(optr, length) ? "incorrect" : "correct");
2090 break;
2091
2092 case ISIS_TLV_MT_SUPPORTED:
2093 while (tmp>1) {
2094 /* length can only be a multiple of 2, otherwise there is
2095 something broken -> so decode down until length is 1 */
2096 if (tmp!=1) {
2097 mt_len = isis_print_mtid(tptr, "\n\t ");
2098 if (mt_len == 0) /* did something go wrong ? */
2099 goto trunctlv;
2100 tptr+=mt_len;
2101 tmp-=mt_len;
2102 } else {
2103 printf("\n\t malformed MT-ID");
2104 break;
2105 }
2106 }
2107 break;
2108
2109 case ISIS_TLV_RESTART_SIGNALING:
2110 if (!TTEST2(*tptr, 3))
2111 goto trunctlv;
2112 printf("\n\t Flags [%s], Remaining holding time %us",
2113 bittok2str(isis_restart_flag_values, "none", *tptr),
2114 EXTRACT_16BITS(tptr+1));
2115 tptr+=3;
2116 break;
2117
2118 case ISIS_TLV_IDRP_INFO:
2119 if (!TTEST2(*tptr, 1))
2120 goto trunctlv;
2121 printf("\n\t Inter-Domain Information Type: %s",
2122 tok2str(isis_subtlv_idrp_values,
2123 "Unknown (0x%02x)",
2124 *tptr));
2125 switch (*tptr++) {
2126 case ISIS_SUBTLV_IDRP_ASN:
2127 if (!TTEST2(*tptr, 2)) /* fetch AS number */
2128 goto trunctlv;
2129 printf("AS Number: %u",EXTRACT_16BITS(tptr));
2130 break;
2131 case ISIS_SUBTLV_IDRP_LOCAL:
2132 case ISIS_SUBTLV_IDRP_RES:
2133 default:
2134 if(!print_unknown_data(tptr,"\n\t ",tlv_len-1))
2135 return(0);
2136 break;
2137 }
2138 break;
2139
2140 case ISIS_TLV_LSP_BUFFERSIZE:
2141 if (!TTEST2(*tptr, 2))
2142 goto trunctlv;
2143 printf("\n\t LSP Buffersize: %u",EXTRACT_16BITS(tptr));
2144 break;
2145
2146 case ISIS_TLV_PART_DIS:
2147 while (tmp >= SYSTEM_ID_LEN) {
2148 if (!TTEST2(*tptr, SYSTEM_ID_LEN))
2149 goto trunctlv;
2150 printf("\n\t %s",isis_print_id(tptr,SYSTEM_ID_LEN));
2151 tptr+=SYSTEM_ID_LEN;
2152 tmp-=SYSTEM_ID_LEN;
2153 }
2154 break;
2155
2156 case ISIS_TLV_PREFIX_NEIGH:
2157 if (!TTEST2(*tptr, sizeof(struct isis_metric_block)))
2158 goto trunctlv;
2159 printf("\n\t Metric Block");
2160 isis_print_metric_block((const struct isis_metric_block *)tptr);
2161 tptr+=sizeof(struct isis_metric_block);
2162 tmp-=sizeof(struct isis_metric_block);
2163
2164 while(tmp>0) {
2165 if (!TTEST2(*tptr, 1))
2166 goto trunctlv;
2167 prefix_len=*tptr++; /* read out prefix length in semioctets*/
2168 tmp--;
2169 if (!TTEST2(*tptr, prefix_len/2))
2170 goto trunctlv;
2171 printf("\n\t\tAddress: %s/%u",
2172 print_nsap(tptr,prefix_len/2),
2173 prefix_len*4);
2174 tptr+=prefix_len/2;
2175 tmp-=prefix_len/2;
2176 }
2177 break;
2178
2179 case ISIS_TLV_IIH_SEQNR:
2180 if (!TTEST2(*tptr, 4)) /* check if four bytes are on the wire */
2181 goto trunctlv;
2182 printf("\n\t Sequence number: %u", EXTRACT_32BITS(tptr) );
2183 break;
2184
2185 case ISIS_TLV_VENDOR_PRIVATE:
2186 if (!TTEST2(*tptr, 3)) /* check if enough byte for a full oui */
2187 goto trunctlv;
2188 vendor_id = EXTRACT_24BITS(tptr);
2189 printf("\n\t Vendor: %s (%u)",
2190 tok2str(oui_values,"Unknown",vendor_id),
2191 vendor_id);
2192 tptr+=3;
2193 tmp-=3;
2194 if (tmp > 0) /* hexdump the rest */
2195 if(!print_unknown_data(tptr,"\n\t\t",tmp))
2196 return(0);
2197 break;
2198 /*
2199 * FIXME those are the defined TLVs that lack a decoder
2200 * you are welcome to contribute code ;-)
2201 */
2202
2203 case ISIS_TLV_DECNET_PHASE4:
2204 case ISIS_TLV_LUCENT_PRIVATE:
2205 case ISIS_TLV_IPAUTH:
2206 case ISIS_TLV_NORTEL_PRIVATE1:
2207 case ISIS_TLV_NORTEL_PRIVATE2:
2208
2209 default:
2210 if (vflag <= 1) {
2211 if(!print_unknown_data(pptr,"\n\t\t",tlv_len))
2212 return(0);
2213 }
2214 break;
2215 }
2216 /* do we want to see an additionally hexdump ? */
2217 if (vflag> 1) {
2218 if(!print_unknown_data(pptr,"\n\t ",tlv_len))
2219 return(0);
2220 }
2221
2222 pptr += tlv_len;
2223 packet_len -= tlv_len;
2224 }
2225
2226 if (packet_len != 0) {
2227 printf("\n\t %u straggler bytes", packet_len);
2228 }
2229 return (1);
2230
2231 trunc:
2232 fputs("[|isis]", stdout);
2233 return (1);
2234
2235 trunctlv:
2236 printf("\n\t\t packet exceeded snapshot");
2237 return(1);
2238 }
2239
2240 /*
2241 * Verify the checksum. See 8473-1, Appendix C, section C.4.
2242 */
2243
2244 static int
2245 osi_cksum(const u_int8_t *tptr, u_int len)
2246 {
2247 int32_t c0 = 0, c1 = 0;
2248
2249 while ((int)--len >= 0) {
2250 c0 += *tptr++;
2251 c0 %= 255;
2252 c1 += c0;
2253 c1 %= 255;
2254 }
2255 return (c0 | c1);
2256 }