blob: fe943bbaa82bf92507eb1055db43f5e39df443a1 [file] [log] [blame]
jardineb5d44e2003-12-23 08:09:43 +00001/*
2 * IS-IS Rout(e)ing protocol - isis_pdu.c
3 * PDU processing
4 *
5 * Copyright (C) 2001,2002 Sampo Saaristo
6 * Tampere University of Technology
7 * Institute of Communications Engineering
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public Licenseas published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
12 * any later version.
13 *
14 * This program is distributed in the hope that it will be useful,but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
jardineb5d44e2003-12-23 08:09:43 +000024#include <zebra.h>
jardineb5d44e2003-12-23 08:09:43 +000025
26#include "memory.h"
27#include "thread.h"
28#include "linklist.h"
29#include "log.h"
30#include "stream.h"
31#include "vty.h"
Josh Bailey3f045a02012-03-24 08:35:20 -070032#include "hash.h"
jardineb5d44e2003-12-23 08:09:43 +000033#include "prefix.h"
34#include "if.h"
Jingjing Duan6a270cd2008-08-13 19:09:10 +010035#include "checksum.h"
Josh Bailey3f045a02012-03-24 08:35:20 -070036#include "md5.h"
jardineb5d44e2003-12-23 08:09:43 +000037
38#include "isisd/dict.h"
39#include "isisd/include-netbsd/iso.h"
40#include "isisd/isis_constants.h"
41#include "isisd/isis_common.h"
Josh Bailey3f045a02012-03-24 08:35:20 -070042#include "isisd/isis_flags.h"
jardineb5d44e2003-12-23 08:09:43 +000043#include "isisd/isis_adjacency.h"
44#include "isisd/isis_circuit.h"
45#include "isisd/isis_network.h"
46#include "isisd/isis_misc.h"
47#include "isisd/isis_dr.h"
jardineb5d44e2003-12-23 08:09:43 +000048#include "isisd/isis_tlv.h"
49#include "isisd/isisd.h"
50#include "isisd/isis_dynhn.h"
51#include "isisd/isis_lsp.h"
52#include "isisd/isis_pdu.h"
53#include "isisd/iso_checksum.h"
54#include "isisd/isis_csm.h"
55#include "isisd/isis_events.h"
56
jardineb5d44e2003-12-23 08:09:43 +000057#define ISIS_MINIMUM_FIXED_HDR_LEN 15
hassof390d2c2004-09-10 20:48:21 +000058#define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */
jardineb5d44e2003-12-23 08:09:43 +000059
60#ifndef PNBBY
61#define PNBBY 8
62#endif /* PNBBY */
63
64/* Utility mask array. */
Stephen Hemminger2d362d12009-12-21 12:54:58 +030065static const u_char maskbit[] = {
jardineb5d44e2003-12-23 08:09:43 +000066 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
67};
68
69/*
70 * HELPER FUNCS
71 */
72
73/*
74 * Compares two sets of area addresses
75 */
hassof390d2c2004-09-10 20:48:21 +000076static int
jardineb5d44e2003-12-23 08:09:43 +000077area_match (struct list *left, struct list *right)
78{
79 struct area_addr *addr1, *addr2;
hasso3fdb2dd2005-09-28 18:45:54 +000080 struct listnode *node1, *node2;
jardineb5d44e2003-12-23 08:09:43 +000081
hasso3fdb2dd2005-09-28 18:45:54 +000082 for (ALL_LIST_ELEMENTS_RO (left, node1, addr1))
hassof390d2c2004-09-10 20:48:21 +000083 {
hasso3fdb2dd2005-09-28 18:45:54 +000084 for (ALL_LIST_ELEMENTS_RO (right, node2, addr2))
hassof390d2c2004-09-10 20:48:21 +000085 {
86 if (addr1->addr_len == addr2->addr_len &&
87 !memcmp (addr1->area_addr, addr2->area_addr, (int) addr1->addr_len))
88 return 1; /* match */
jardineb5d44e2003-12-23 08:09:43 +000089 }
90 }
91
hassof390d2c2004-09-10 20:48:21 +000092 return 0; /* mismatch */
jardineb5d44e2003-12-23 08:09:43 +000093}
94
95/*
96 * Check if ip2 is in the ip1's network (function like Prefix.h:prefix_match() )
97 * param ip1 the IS interface ip address structure
98 * param ip2 the IIH's ip address
99 * return 0 the IIH's IP is not in the IS's subnetwork
100 * 1 the IIH's IP is in the IS's subnetwork
101 */
hasso92365882005-01-18 13:53:33 +0000102static int
hassof390d2c2004-09-10 20:48:21 +0000103ip_same_subnet (struct prefix_ipv4 *ip1, struct in_addr *ip2)
jardineb5d44e2003-12-23 08:09:43 +0000104{
105 u_char *addr1, *addr2;
hasso53c997c2004-09-15 16:21:59 +0000106 int shift, offset, offsetloop;
jardineb5d44e2003-12-23 08:09:43 +0000107 int len;
hassof390d2c2004-09-10 20:48:21 +0000108
109 addr1 = (u_char *) & ip1->prefix.s_addr;
110 addr2 = (u_char *) & ip2->s_addr;
jardineb5d44e2003-12-23 08:09:43 +0000111 len = ip1->prefixlen;
112
113 shift = len % PNBBY;
hasso53c997c2004-09-15 16:21:59 +0000114 offsetloop = offset = len / PNBBY;
jardineb5d44e2003-12-23 08:09:43 +0000115
hasso53c997c2004-09-15 16:21:59 +0000116 while (offsetloop--)
117 if (addr1[offsetloop] != addr2[offsetloop])
118 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000119
hassof390d2c2004-09-10 20:48:21 +0000120 if (shift)
hasso53c997c2004-09-15 16:21:59 +0000121 if (maskbit[shift] & (addr1[offset] ^ addr2[offset]))
122 return 0;
hassof390d2c2004-09-10 20:48:21 +0000123
124 return 1; /* match */
jardineb5d44e2003-12-23 08:09:43 +0000125}
126
jardineb5d44e2003-12-23 08:09:43 +0000127/*
128 * Compares two set of ip addresses
129 * param left the local interface's ip addresses
130 * param right the iih interface's ip address
131 * return 0 no match;
132 * 1 match;
133 */
hassof390d2c2004-09-10 20:48:21 +0000134static int
jardineb5d44e2003-12-23 08:09:43 +0000135ip_match (struct list *left, struct list *right)
136{
137 struct prefix_ipv4 *ip1;
138 struct in_addr *ip2;
hasso3fdb2dd2005-09-28 18:45:54 +0000139 struct listnode *node1, *node2;
jardineb5d44e2003-12-23 08:09:43 +0000140
hassoe082ac12004-09-27 18:13:57 +0000141 if ((left == NULL) || (right == NULL))
142 return 0;
143
hasso3fdb2dd2005-09-28 18:45:54 +0000144 for (ALL_LIST_ELEMENTS_RO (left, node1, ip1))
hassof390d2c2004-09-10 20:48:21 +0000145 {
hasso3fdb2dd2005-09-28 18:45:54 +0000146 for (ALL_LIST_ELEMENTS_RO (right, node2, ip2))
hassof390d2c2004-09-10 20:48:21 +0000147 {
148 if (ip_same_subnet (ip1, ip2))
149 {
150 return 1; /* match */
151 }
jardineb5d44e2003-12-23 08:09:43 +0000152 }
hassof390d2c2004-09-10 20:48:21 +0000153
jardineb5d44e2003-12-23 08:09:43 +0000154 }
155 return 0;
156}
157
158/*
159 * Checks whether we should accept a PDU of given level
160 */
161static int
162accept_level (int level, int circuit_t)
163{
hassof390d2c2004-09-10 20:48:21 +0000164 int retval = ((circuit_t & level) == level); /* simple approach */
jardineb5d44e2003-12-23 08:09:43 +0000165
166 return retval;
167}
168
Josh Bailey3f045a02012-03-24 08:35:20 -0700169/*
170 * Verify authentication information
171 * Support cleartext and HMAC MD5 authentication
172 */
173static int
174authentication_check (struct isis_passwd *remote, struct isis_passwd *local,
175 struct stream *stream, uint32_t auth_tlv_offset)
jardineb5d44e2003-12-23 08:09:43 +0000176{
Josh Bailey3f045a02012-03-24 08:35:20 -0700177 unsigned char digest[ISIS_AUTH_MD5_SIZE];
178
179 /* Auth fail () - passwd type mismatch */
180 if (local->type != remote->type)
181 return ISIS_ERROR;
182
183 switch (local->type)
184 {
185 /* No authentication required */
186 case ISIS_PASSWD_TYPE_UNUSED:
187 break;
188
189 /* Cleartext (ISO 10589) */
hassof390d2c2004-09-10 20:48:21 +0000190 case ISIS_PASSWD_TYPE_CLEARTXT:
Josh Bailey3f045a02012-03-24 08:35:20 -0700191 /* Auth fail () - passwd len mismatch */
192 if (remote->len != local->len)
193 return ISIS_ERROR;
194 return memcmp (local->passwd, remote->passwd, local->len);
195
196 /* HMAC MD5 (RFC 3567) */
197 case ISIS_PASSWD_TYPE_HMAC_MD5:
198 /* Auth fail () - passwd len mismatch */
199 if (remote->len != ISIS_AUTH_MD5_SIZE)
200 return ISIS_ERROR;
201 /* Set the authentication value to 0 before the check */
202 memset (STREAM_DATA (stream) + auth_tlv_offset + 3, 0,
203 ISIS_AUTH_MD5_SIZE);
204 /* Compute the digest */
205 hmac_md5 (STREAM_DATA (stream), stream_get_endp (stream),
206 (unsigned char *) &(local->passwd), local->len,
207 (caddr_t) &digest);
208 /* Copy back the authentication value after the check */
209 memcpy (STREAM_DATA (stream) + auth_tlv_offset + 3,
210 remote->passwd, ISIS_AUTH_MD5_SIZE);
211 return memcmp (digest, remote->passwd, ISIS_AUTH_MD5_SIZE);
212
hassof390d2c2004-09-10 20:48:21 +0000213 default:
Josh Bailey3f045a02012-03-24 08:35:20 -0700214 zlog_err ("Unsupported authentication type");
215 return ISIS_ERROR;
216 }
217
218 /* Authentication pass when no authentication is configured */
219 return ISIS_OK;
220}
221
222static int
223lsp_authentication_check (struct stream *stream, struct isis_area *area,
224 int level, struct isis_passwd *passwd)
225{
226 struct isis_link_state_hdr *hdr;
227 uint32_t expected = 0, found = 0, auth_tlv_offset = 0;
228 uint16_t checksum, rem_lifetime;
229 struct tlvs tlvs;
230 int retval = ISIS_OK;
231
232 hdr = (struct isis_link_state_hdr *) (STREAM_PNT (stream));
233 expected |= TLVFLAG_AUTH_INFO;
234 auth_tlv_offset = stream_get_getp (stream) + ISIS_LSP_HDR_LEN;
235 retval = parse_tlvs (area->area_tag, STREAM_PNT (stream) + ISIS_LSP_HDR_LEN,
236 ntohs (hdr->pdu_len) - ISIS_FIXED_HDR_LEN -
237 ISIS_LSP_HDR_LEN,
238 &expected, &found, &tlvs, &auth_tlv_offset);
239
240 if (retval != ISIS_OK)
241 {
242 zlog_err ("ISIS-Upd (%s): Parse failed L%d LSP %s, seq 0x%08x, "
243 "cksum 0x%04x, lifetime %us, len %u",
244 area->area_tag, level, rawlspid_print (hdr->lsp_id),
245 ntohl (hdr->seq_num), ntohs (hdr->checksum),
246 ntohs (hdr->rem_lifetime), ntohs (hdr->pdu_len));
247 if ((isis->debugs & DEBUG_UPDATE_PACKETS) &&
248 (isis->debugs & DEBUG_PACKET_DUMP))
249 zlog_dump_data (STREAM_DATA (stream), stream_get_endp (stream));
250 return retval;
hassof390d2c2004-09-10 20:48:21 +0000251 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700252
253 if (!(found & TLVFLAG_AUTH_INFO))
254 {
255 zlog_err ("No authentication tlv in LSP");
256 return ISIS_ERROR;
257 }
258
259 if (tlvs.auth_info.type != ISIS_PASSWD_TYPE_CLEARTXT &&
260 tlvs.auth_info.type != ISIS_PASSWD_TYPE_HMAC_MD5)
261 {
262 zlog_err ("Unknown authentication type in LSP");
263 return ISIS_ERROR;
264 }
265
266 /*
267 * RFC 5304 set checksum and remaining lifetime to zero before
268 * verification and reset to old values after verification.
269 */
270 checksum = hdr->checksum;
271 rem_lifetime = hdr->rem_lifetime;
272 hdr->checksum = 0;
273 hdr->rem_lifetime = 0;
274 retval = authentication_check (&tlvs.auth_info, passwd, stream,
275 auth_tlv_offset);
276 hdr->checksum = checksum;
277 hdr->rem_lifetime = rem_lifetime;
278
279 return retval;
jardineb5d44e2003-12-23 08:09:43 +0000280}
281
282/*
283 * Processing helper functions
284 */
hasso92365882005-01-18 13:53:33 +0000285static void
Josh Bailey3f045a02012-03-24 08:35:20 -0700286del_addr (void *val)
287{
288 XFREE (MTYPE_ISIS_TMP, val);
289}
290
291static void
292tlvs_to_adj_area_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
293{
294 struct listnode *node;
295 struct area_addr *area_addr, *malloced;
296
297 if (adj->area_addrs)
298 {
299 adj->area_addrs->del = del_addr;
300 list_delete (adj->area_addrs);
301 }
302 adj->area_addrs = list_new ();
303 if (tlvs->area_addrs)
304 {
305 for (ALL_LIST_ELEMENTS_RO (tlvs->area_addrs, node, area_addr))
306 {
307 malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct area_addr));
308 memcpy (malloced, area_addr, sizeof (struct area_addr));
309 listnode_add (adj->area_addrs, malloced);
310 }
311 }
312}
313
314static void
hassof390d2c2004-09-10 20:48:21 +0000315tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj)
jardineb5d44e2003-12-23 08:09:43 +0000316{
317 int i;
318 struct nlpids *tlv_nlpids;
319
hassof390d2c2004-09-10 20:48:21 +0000320 if (tlvs->nlpids)
321 {
jardineb5d44e2003-12-23 08:09:43 +0000322
hassof390d2c2004-09-10 20:48:21 +0000323 tlv_nlpids = tlvs->nlpids;
jardineb5d44e2003-12-23 08:09:43 +0000324
hassof390d2c2004-09-10 20:48:21 +0000325 adj->nlpids.count = tlv_nlpids->count;
jardineb5d44e2003-12-23 08:09:43 +0000326
hassof390d2c2004-09-10 20:48:21 +0000327 for (i = 0; i < tlv_nlpids->count; i++)
328 {
329 adj->nlpids.nlpids[i] = tlv_nlpids->nlpids[i];
330 }
jardineb5d44e2003-12-23 08:09:43 +0000331 }
jardineb5d44e2003-12-23 08:09:43 +0000332}
333
hasso92365882005-01-18 13:53:33 +0000334static void
hassof390d2c2004-09-10 20:48:21 +0000335tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
jardineb5d44e2003-12-23 08:09:43 +0000336{
hasso3fdb2dd2005-09-28 18:45:54 +0000337 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000338 struct in_addr *ipv4_addr, *malloced;
339
hassof390d2c2004-09-10 20:48:21 +0000340 if (adj->ipv4_addrs)
341 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700342 adj->ipv4_addrs->del = del_addr;
hassof390d2c2004-09-10 20:48:21 +0000343 list_delete (adj->ipv4_addrs);
jardineb5d44e2003-12-23 08:09:43 +0000344 }
hassof390d2c2004-09-10 20:48:21 +0000345 adj->ipv4_addrs = list_new ();
346 if (tlvs->ipv4_addrs)
347 {
hasso3fdb2dd2005-09-28 18:45:54 +0000348 for (ALL_LIST_ELEMENTS_RO (tlvs->ipv4_addrs, node, ipv4_addr))
hassof390d2c2004-09-10 20:48:21 +0000349 {
350 malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in_addr));
351 memcpy (malloced, ipv4_addr, sizeof (struct in_addr));
352 listnode_add (adj->ipv4_addrs, malloced);
353 }
354 }
jardineb5d44e2003-12-23 08:09:43 +0000355}
356
357#ifdef HAVE_IPV6
hasso92365882005-01-18 13:53:33 +0000358static void
hassof390d2c2004-09-10 20:48:21 +0000359tlvs_to_adj_ipv6_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
jardineb5d44e2003-12-23 08:09:43 +0000360{
hasso3fdb2dd2005-09-28 18:45:54 +0000361 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000362 struct in6_addr *ipv6_addr, *malloced;
363
hassof390d2c2004-09-10 20:48:21 +0000364 if (adj->ipv6_addrs)
365 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700366 adj->ipv6_addrs->del = del_addr;
hassof390d2c2004-09-10 20:48:21 +0000367 list_delete (adj->ipv6_addrs);
jardineb5d44e2003-12-23 08:09:43 +0000368 }
hassof390d2c2004-09-10 20:48:21 +0000369 adj->ipv6_addrs = list_new ();
370 if (tlvs->ipv6_addrs)
371 {
hasso3fdb2dd2005-09-28 18:45:54 +0000372 for (ALL_LIST_ELEMENTS_RO (tlvs->ipv6_addrs, node, ipv6_addr))
hassof390d2c2004-09-10 20:48:21 +0000373 {
374 malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in6_addr));
375 memcpy (malloced, ipv6_addr, sizeof (struct in6_addr));
376 listnode_add (adj->ipv6_addrs, malloced);
377 }
378 }
jardineb5d44e2003-12-23 08:09:43 +0000379
380}
381#endif /* HAVE_IPV6 */
382
jardineb5d44e2003-12-23 08:09:43 +0000383/*
384 * RECEIVE SIDE
385 */
386
387/*
388 * Process P2P IIH
389 * ISO - 10589
390 * Section 8.2.5 - Receiving point-to-point IIH PDUs
391 *
392 */
393static int
394process_p2p_hello (struct isis_circuit *circuit)
395{
396 int retval = ISIS_OK;
397 struct isis_p2p_hello_hdr *hdr;
398 struct isis_adjacency *adj;
Josh Bailey3f045a02012-03-24 08:35:20 -0700399 u_int32_t expected = 0, found = 0, auth_tlv_offset = 0;
jardineb5d44e2003-12-23 08:09:43 +0000400 struct tlvs tlvs;
401
Josh Bailey3f045a02012-03-24 08:35:20 -0700402 if (isis->debugs & DEBUG_ADJ_PACKETS)
403 {
404 zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH on %s, cirType %s, cirID %u",
405 circuit->area->area_tag, circuit->interface->name,
406 circuit_t2string (circuit->is_type), circuit->circuit_id);
407 if (isis->debugs & DEBUG_PACKET_DUMP)
408 zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
409 stream_get_endp (circuit->rcv_stream));
410 }
411
412 if (circuit->circ_type != CIRCUIT_T_P2P)
413 {
414 zlog_warn ("p2p hello on non p2p circuit");
415 return ISIS_WARNING;
416 }
417
hassof390d2c2004-09-10 20:48:21 +0000418 if ((stream_get_endp (circuit->rcv_stream) -
419 stream_get_getp (circuit->rcv_stream)) < ISIS_P2PHELLO_HDRLEN)
420 {
421 zlog_warn ("Packet too short");
422 return ISIS_WARNING;
423 }
jardineb5d44e2003-12-23 08:09:43 +0000424
425 /* 8.2.5.1 PDU acceptance tests */
426
427 /* 8.2.5.1 a) external domain untrue */
428 /* FIXME: not useful at all? */
429
430 /* 8.2.5.1 b) ID Length mismatch */
431 /* checked at the handle_pdu */
432
433 /* 8.2.5.2 IIH PDU Processing */
434
435 /* 8.2.5.2 a) 1) Maximum Area Addresses */
436 /* Already checked, and can also be ommited */
437
438 /*
439 * Get the header
440 */
hassof390d2c2004-09-10 20:48:21 +0000441 hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream);
Josh Bailey3f045a02012-03-24 08:35:20 -0700442 stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN);
jardineb5d44e2003-12-23 08:09:43 +0000443
444 /* hdr.circuit_t = stream_getc (stream);
hassof390d2c2004-09-10 20:48:21 +0000445 stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN);
446 hdr.hold_time = stream_getw (stream);
447 hdr.pdu_len = stream_getw (stream);
448 hdr.local_id = stream_getc (stream); */
jardineb5d44e2003-12-23 08:09:43 +0000449
Josh Bailey3f045a02012-03-24 08:35:20 -0700450 if (ntohs (hdr->pdu_len) > ISO_MTU(circuit))
hassof390d2c2004-09-10 20:48:21 +0000451 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700452 zlog_warn ("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with "
453 "invalid pdu length %d",
454 circuit->area->area_tag, circuit->interface->name,
455 ntohs (hdr->pdu_len));
456 return ISIS_WARNING;
hassof390d2c2004-09-10 20:48:21 +0000457 }
jardineb5d44e2003-12-23 08:09:43 +0000458
jardineb5d44e2003-12-23 08:09:43 +0000459 /*
460 * Lets get the TLVS now
461 */
462 expected |= TLVFLAG_AREA_ADDRS;
463 expected |= TLVFLAG_AUTH_INFO;
464 expected |= TLVFLAG_NLPID;
465 expected |= TLVFLAG_IPV4_ADDR;
466 expected |= TLVFLAG_IPV6_ADDR;
467
Josh Bailey3f045a02012-03-24 08:35:20 -0700468 auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
jardineb5d44e2003-12-23 08:09:43 +0000469 retval = parse_tlvs (circuit->area->area_tag,
470 STREAM_PNT (circuit->rcv_stream),
hassof390d2c2004-09-10 20:48:21 +0000471 ntohs (hdr->pdu_len) - ISIS_P2PHELLO_HDRLEN
Josh Bailey3f045a02012-03-24 08:35:20 -0700472 - ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs,
473 &auth_tlv_offset);
jardineb5d44e2003-12-23 08:09:43 +0000474
hassof390d2c2004-09-10 20:48:21 +0000475 if (retval > ISIS_WARNING)
476 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700477 zlog_warn ("parse_tlvs() failed");
hassof390d2c2004-09-10 20:48:21 +0000478 free_tlvs (&tlvs);
479 return retval;
480 };
jardineb5d44e2003-12-23 08:09:43 +0000481
Josh Bailey3f045a02012-03-24 08:35:20 -0700482 if (!(found & TLVFLAG_AREA_ADDRS))
483 {
484 zlog_warn ("No Area addresses TLV in P2P IS to IS hello");
485 free_tlvs (&tlvs);
486 return ISIS_WARNING;
487 }
488
jardineb5d44e2003-12-23 08:09:43 +0000489 /* 8.2.5.1 c) Authentication */
hassof390d2c2004-09-10 20:48:21 +0000490 if (circuit->passwd.type)
491 {
492 if (!(found & TLVFLAG_AUTH_INFO) ||
Josh Bailey3f045a02012-03-24 08:35:20 -0700493 authentication_check (&tlvs.auth_info, &circuit->passwd,
494 circuit->rcv_stream, auth_tlv_offset))
495 {
496 isis_event_auth_failure (circuit->area->area_tag,
497 "P2P hello authentication failure",
498 hdr->source_id);
499 free_tlvs (&tlvs);
500 return ISIS_OK;
501 }
jardineb5d44e2003-12-23 08:09:43 +0000502 }
jardineb5d44e2003-12-23 08:09:43 +0000503
Josh Bailey3f045a02012-03-24 08:35:20 -0700504 /*
505 * check if it's own interface ip match iih ip addrs
506 */
507 if ((found & TLVFLAG_IPV4_ADDR) == 0 ||
508 ip_match (circuit->ip_addrs, tlvs.ipv4_addrs) == 0)
509 {
510 zlog_warn ("ISIS-Adj: No usable IP interface addresses "
511 "in LAN IIH from %s\n", circuit->interface->name);
512 free_tlvs (&tlvs);
513 return ISIS_WARNING;
514 }
515
516 /*
517 * My interpertation of the ISO, if no adj exists we will create one for
518 * the circuit
519 */
520 adj = circuit->u.p2p.neighbor;
521 if (!adj || adj->level != hdr->circuit_t)
522 {
523 if (!adj)
524 {
525 adj = isis_new_adj (hdr->source_id, NULL, hdr->circuit_t, circuit);
526 if (adj == NULL)
527 return ISIS_ERROR;
528 }
529 else
530 {
531 adj->level = hdr->circuit_t;
532 }
533 circuit->u.p2p.neighbor = adj;
534 isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
535 adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
536 }
537
538 /* 8.2.6 Monitoring point-to-point adjacencies */
539 adj->hold_time = ntohs (hdr->hold_time);
540 adj->last_upd = time (NULL);
541
jardineb5d44e2003-12-23 08:09:43 +0000542 /* we do this now because the adj may not survive till the end... */
Josh Bailey3f045a02012-03-24 08:35:20 -0700543 tlvs_to_adj_area_addrs (&tlvs, adj);
544
545 /* which protocol are spoken ??? */
546 if (found & TLVFLAG_NLPID)
547 tlvs_to_adj_nlpids (&tlvs, adj);
jardineb5d44e2003-12-23 08:09:43 +0000548
549 /* we need to copy addresses to the adj */
Josh Bailey3f045a02012-03-24 08:35:20 -0700550 if (found & TLVFLAG_IPV4_ADDR)
551 tlvs_to_adj_ipv4_addrs (&tlvs, adj);
jardineb5d44e2003-12-23 08:09:43 +0000552
553#ifdef HAVE_IPV6
Josh Bailey3f045a02012-03-24 08:35:20 -0700554 if (found & TLVFLAG_IPV6_ADDR)
555 tlvs_to_adj_ipv6_addrs (&tlvs, adj);
jardineb5d44e2003-12-23 08:09:43 +0000556#endif /* HAVE_IPV6 */
557
558 /* lets take care of the expiry */
hassof390d2c2004-09-10 20:48:21 +0000559 THREAD_TIMER_OFF (adj->t_expire);
560 THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
561 (long) adj->hold_time);
jardineb5d44e2003-12-23 08:09:43 +0000562
563 /* 8.2.5.2 a) a match was detected */
hassof390d2c2004-09-10 20:48:21 +0000564 if (area_match (circuit->area->area_addrs, tlvs.area_addrs))
565 {
566 /* 8.2.5.2 a) 2) If the system is L1 - table 5 */
567 if (circuit->area->is_type == IS_LEVEL_1)
568 {
569 switch (hdr->circuit_t)
570 {
571 case IS_LEVEL_1:
572 case IS_LEVEL_1_AND_2:
573 if (adj->adj_state != ISIS_ADJ_UP)
574 {
575 /* (4) adj state up */
576 isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
577 /* (5) adj usage level 1 */
578 adj->adj_usage = ISIS_ADJ_LEVEL1;
579 }
580 else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
581 {
582 ; /* accept */
583 }
584 break;
585 case IS_LEVEL_2:
586 if (adj->adj_state != ISIS_ADJ_UP)
587 {
588 /* (7) reject - wrong system type event */
589 zlog_warn ("wrongSystemType");
Josh Bailey3f045a02012-03-24 08:35:20 -0700590 free_tlvs (&tlvs);
hassof390d2c2004-09-10 20:48:21 +0000591 return ISIS_WARNING; /* Reject */
592 }
593 else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
594 {
595 /* (6) down - wrong system */
596 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
597 }
598 break;
599 }
600 }
jardineb5d44e2003-12-23 08:09:43 +0000601
hassof390d2c2004-09-10 20:48:21 +0000602 /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */
603 if (circuit->area->is_type == IS_LEVEL_1_AND_2)
604 {
605 switch (hdr->circuit_t)
606 {
607 case IS_LEVEL_1:
608 if (adj->adj_state != ISIS_ADJ_UP)
609 {
610 /* (6) adj state up */
611 isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
612 /* (7) adj usage level 1 */
613 adj->adj_usage = ISIS_ADJ_LEVEL1;
614 }
615 else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
616 {
617 ; /* accept */
618 }
619 else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
620 (adj->adj_usage == ISIS_ADJ_LEVEL2))
621 {
622 /* (8) down - wrong system */
623 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
624 }
625 break;
626 case IS_LEVEL_2:
627 if (adj->adj_state != ISIS_ADJ_UP)
628 {
629 /* (6) adj state up */
630 isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
631 /* (9) adj usage level 2 */
632 adj->adj_usage = ISIS_ADJ_LEVEL2;
633 }
634 else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) ||
635 (adj->adj_usage == ISIS_ADJ_LEVEL1AND2))
636 {
637 /* (8) down - wrong system */
638 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
639 }
640 else if (adj->adj_usage == ISIS_ADJ_LEVEL2)
641 {
642 ; /* Accept */
643 }
644 break;
645 case IS_LEVEL_1_AND_2:
646 if (adj->adj_state != ISIS_ADJ_UP)
647 {
648 /* (6) adj state up */
649 isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
650 /* (10) adj usage level 1 */
651 adj->adj_usage = ISIS_ADJ_LEVEL1AND2;
652 }
653 else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) ||
654 (adj->adj_usage == ISIS_ADJ_LEVEL2))
655 {
656 /* (8) down - wrong system */
657 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
658 }
659 else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
660 {
661 ; /* Accept */
662 }
663 break;
664 }
665 }
jardineb5d44e2003-12-23 08:09:43 +0000666
hassof390d2c2004-09-10 20:48:21 +0000667 /* 8.2.5.2 a) 4) If the system is L2 - table 7 */
668 if (circuit->area->is_type == IS_LEVEL_2)
669 {
670 switch (hdr->circuit_t)
671 {
672 case IS_LEVEL_1:
673 if (adj->adj_state != ISIS_ADJ_UP)
674 {
675 /* (5) reject - wrong system type event */
676 zlog_warn ("wrongSystemType");
Josh Bailey3f045a02012-03-24 08:35:20 -0700677 free_tlvs (&tlvs);
hassof390d2c2004-09-10 20:48:21 +0000678 return ISIS_WARNING; /* Reject */
679 }
680 else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
681 (adj->adj_usage == ISIS_ADJ_LEVEL2))
682 {
683 /* (6) down - wrong system */
684 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
685 }
686 break;
687 case IS_LEVEL_1_AND_2:
688 case IS_LEVEL_2:
689 if (adj->adj_state != ISIS_ADJ_UP)
690 {
691 /* (7) adj state up */
692 isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
693 /* (8) adj usage level 2 */
694 adj->adj_usage = ISIS_ADJ_LEVEL2;
695 }
696 else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
697 {
698 /* (6) down - wrong system */
699 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
700 }
701 else if (adj->adj_usage == ISIS_ADJ_LEVEL2)
702 {
703 ; /* Accept */
704 }
705 break;
706 }
707 }
jardineb5d44e2003-12-23 08:09:43 +0000708 }
jardineb5d44e2003-12-23 08:09:43 +0000709 /* 8.2.5.2 b) if no match was detected */
Josh Bailey3f045a02012-03-24 08:35:20 -0700710 else if (listcount (circuit->area->area_addrs) > 0)
jardineb5d44e2003-12-23 08:09:43 +0000711 {
hassof390d2c2004-09-10 20:48:21 +0000712 if (circuit->area->is_type == IS_LEVEL_1)
713 {
714 /* 8.2.5.2 b) 1) is_type L1 and adj is not up */
715 if (adj->adj_state != ISIS_ADJ_UP)
716 {
717 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
718 /* 8.2.5.2 b) 2)is_type L1 and adj is up */
719 }
720 else
721 {
722 isis_adj_state_change (adj, ISIS_ADJ_DOWN,
723 "Down - Area Mismatch");
724 }
725 }
726 /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */
727 else
728 {
729 switch (hdr->circuit_t)
730 {
731 case IS_LEVEL_1:
732 if (adj->adj_state != ISIS_ADJ_UP)
733 {
734 /* (6) reject - Area Mismatch event */
735 zlog_warn ("AreaMismatch");
Josh Bailey3f045a02012-03-24 08:35:20 -0700736 free_tlvs (&tlvs);
hassof390d2c2004-09-10 20:48:21 +0000737 return ISIS_WARNING; /* Reject */
738 }
739 else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
740 {
741 /* (7) down - area mismatch */
742 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
jardineb5d44e2003-12-23 08:09:43 +0000743
hassof390d2c2004-09-10 20:48:21 +0000744 }
745 else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
746 (adj->adj_usage == ISIS_ADJ_LEVEL2))
747 {
748 /* (7) down - wrong system */
749 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
750 }
751 break;
752 case IS_LEVEL_1_AND_2:
753 case IS_LEVEL_2:
754 if (adj->adj_state != ISIS_ADJ_UP)
755 {
756 /* (8) adj state up */
757 isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
758 /* (9) adj usage level 2 */
759 adj->adj_usage = ISIS_ADJ_LEVEL2;
760 }
761 else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
762 {
763 /* (7) down - wrong system */
764 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
765 }
766 else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
767 {
768 if (hdr->circuit_t == IS_LEVEL_2)
769 {
770 /* (7) down - wrong system */
771 isis_adj_state_change (adj, ISIS_ADJ_DOWN,
772 "Wrong System");
773 }
774 else
775 {
776 /* (7) down - area mismatch */
777 isis_adj_state_change (adj, ISIS_ADJ_DOWN,
778 "Area Mismatch");
779 }
780 }
781 else if (adj->adj_usage == ISIS_ADJ_LEVEL2)
782 {
783 ; /* Accept */
784 }
785 break;
786 }
787 }
jardineb5d44e2003-12-23 08:09:43 +0000788 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700789 else
790 {
791 /* down - area mismatch */
792 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
793 }
jardineb5d44e2003-12-23 08:09:43 +0000794 /* 8.2.5.2 c) if the action was up - comparing circuit IDs */
795 /* FIXME - Missing parts */
796
jardineb5d44e2003-12-23 08:09:43 +0000797 /* some of my own understanding of the ISO, why the heck does
798 * it not say what should I change the system_type to...
799 */
hassof390d2c2004-09-10 20:48:21 +0000800 switch (adj->adj_usage)
801 {
jardineb5d44e2003-12-23 08:09:43 +0000802 case ISIS_ADJ_LEVEL1:
803 adj->sys_type = ISIS_SYSTYPE_L1_IS;
804 break;
805 case ISIS_ADJ_LEVEL2:
806 adj->sys_type = ISIS_SYSTYPE_L2_IS;
807 break;
808 case ISIS_ADJ_LEVEL1AND2:
809 adj->sys_type = ISIS_SYSTYPE_L2_IS;
810 break;
811 case ISIS_ADJ_NONE:
812 adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
813 break;
hassof390d2c2004-09-10 20:48:21 +0000814 }
jardineb5d44e2003-12-23 08:09:43 +0000815
816 adj->circuit_t = hdr->circuit_t;
Josh Bailey3f045a02012-03-24 08:35:20 -0700817
818 if (isis->debugs & DEBUG_ADJ_PACKETS)
819 {
820 zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
821 " cir id %02d, length %d",
822 circuit->area->area_tag, circuit->interface->name,
823 circuit_t2string (circuit->is_type),
824 circuit->circuit_id, ntohs (hdr->pdu_len));
825 }
jardineb5d44e2003-12-23 08:09:43 +0000826
827 free_tlvs (&tlvs);
828
829 return retval;
830}
831
jardineb5d44e2003-12-23 08:09:43 +0000832/*
833 * Process IS-IS LAN Level 1/2 Hello PDU
834 */
hassof390d2c2004-09-10 20:48:21 +0000835static int
836process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
jardineb5d44e2003-12-23 08:09:43 +0000837{
838 int retval = ISIS_OK;
839 struct isis_lan_hello_hdr hdr;
840 struct isis_adjacency *adj;
Josh Bailey3f045a02012-03-24 08:35:20 -0700841 u_int32_t expected = 0, found = 0, auth_tlv_offset = 0;
jardineb5d44e2003-12-23 08:09:43 +0000842 struct tlvs tlvs;
843 u_char *snpa;
hasso3fdb2dd2005-09-28 18:45:54 +0000844 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000845
Josh Bailey3f045a02012-03-24 08:35:20 -0700846 if (isis->debugs & DEBUG_ADJ_PACKETS)
847 {
848 zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH on %s, cirType %s, "
849 "cirID %u",
850 circuit->area->area_tag, level, circuit->interface->name,
851 circuit_t2string (circuit->is_type), circuit->circuit_id);
852 if (isis->debugs & DEBUG_PACKET_DUMP)
853 zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
854 stream_get_endp (circuit->rcv_stream));
855 }
856
857 if (circuit->circ_type != CIRCUIT_T_BROADCAST)
858 {
859 zlog_warn ("lan hello on non broadcast circuit");
860 return ISIS_WARNING;
861 }
862
hassof390d2c2004-09-10 20:48:21 +0000863 if ((stream_get_endp (circuit->rcv_stream) -
864 stream_get_getp (circuit->rcv_stream)) < ISIS_LANHELLO_HDRLEN)
865 {
866 zlog_warn ("Packet too short");
867 return ISIS_WARNING;
jardineb5d44e2003-12-23 08:09:43 +0000868 }
hassof390d2c2004-09-10 20:48:21 +0000869
870 if (circuit->ext_domain)
871 {
hasso529d65b2004-12-24 00:14:50 +0000872 zlog_debug ("level %d LAN Hello received over circuit with "
873 "externalDomain = true", level);
hassof390d2c2004-09-10 20:48:21 +0000874 return ISIS_WARNING;
875 }
876
Josh Bailey3f045a02012-03-24 08:35:20 -0700877 if (!accept_level (level, circuit->is_type))
hassof390d2c2004-09-10 20:48:21 +0000878 {
879 if (isis->debugs & DEBUG_ADJ_PACKETS)
880 {
hasso529d65b2004-12-24 00:14:50 +0000881 zlog_debug ("ISIS-Adj (%s): Interface level mismatch, %s",
882 circuit->area->area_tag, circuit->interface->name);
hassof390d2c2004-09-10 20:48:21 +0000883 }
884 return ISIS_WARNING;
885 }
jardineb5d44e2003-12-23 08:09:43 +0000886
887#if 0
888 /* Cisco's debug message compatability */
hassof390d2c2004-09-10 20:48:21 +0000889 if (!accept_level (level, circuit->area->is_type))
890 {
891 if (isis->debugs & DEBUG_ADJ_PACKETS)
892 {
hasso529d65b2004-12-24 00:14:50 +0000893 zlog_debug ("ISIS-Adj (%s): is type mismatch",
894 circuit->area->area_tag);
hassof390d2c2004-09-10 20:48:21 +0000895 }
896 return ISIS_WARNING;
jardineb5d44e2003-12-23 08:09:43 +0000897 }
jardineb5d44e2003-12-23 08:09:43 +0000898#endif
899 /*
900 * Fill the header
901 */
902 hdr.circuit_t = stream_getc (circuit->rcv_stream);
903 stream_get (hdr.source_id, circuit->rcv_stream, ISIS_SYS_ID_LEN);
904 hdr.hold_time = stream_getw (circuit->rcv_stream);
hassof390d2c2004-09-10 20:48:21 +0000905 hdr.pdu_len = stream_getw (circuit->rcv_stream);
906 hdr.prio = stream_getc (circuit->rcv_stream);
jardineb5d44e2003-12-23 08:09:43 +0000907 stream_get (hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1);
908
Josh Bailey3f045a02012-03-24 08:35:20 -0700909 if (hdr.pdu_len > ISO_MTU(circuit))
hassof390d2c2004-09-10 20:48:21 +0000910 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700911 zlog_warn ("ISIS-Adj (%s): Rcvd LAN IIH from (%s) with "
912 "invalid pdu length %d",
913 circuit->area->area_tag, circuit->interface->name,
914 hdr.pdu_len);
915 hdr.pdu_len = stream_get_endp (circuit->rcv_stream);
916 }
917
918 if (hdr.circuit_t != IS_LEVEL_1 &&
919 hdr.circuit_t != IS_LEVEL_2 &&
920 hdr.circuit_t != IS_LEVEL_1_AND_2 &&
921 (level & hdr.circuit_t) == 0)
922 {
923 zlog_err ("Level %d LAN Hello with Circuit Type %d", level,
924 hdr.circuit_t);
hassof390d2c2004-09-10 20:48:21 +0000925 return ISIS_ERROR;
926 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700927
jardineb5d44e2003-12-23 08:09:43 +0000928 /*
929 * Then get the tlvs
930 */
931 expected |= TLVFLAG_AUTH_INFO;
932 expected |= TLVFLAG_AREA_ADDRS;
933 expected |= TLVFLAG_LAN_NEIGHS;
934 expected |= TLVFLAG_NLPID;
935 expected |= TLVFLAG_IPV4_ADDR;
936 expected |= TLVFLAG_IPV6_ADDR;
937
Josh Bailey3f045a02012-03-24 08:35:20 -0700938 auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
jardineb5d44e2003-12-23 08:09:43 +0000939 retval = parse_tlvs (circuit->area->area_tag,
Josh Bailey3f045a02012-03-24 08:35:20 -0700940 STREAM_PNT (circuit->rcv_stream),
941 hdr.pdu_len - ISIS_LANHELLO_HDRLEN - ISIS_FIXED_HDR_LEN,
942 &expected, &found, &tlvs,
943 &auth_tlv_offset);
jardineb5d44e2003-12-23 08:09:43 +0000944
hassof390d2c2004-09-10 20:48:21 +0000945 if (retval > ISIS_WARNING)
946 {
947 zlog_warn ("parse_tlvs() failed");
948 goto out;
949 }
jardineb5d44e2003-12-23 08:09:43 +0000950
hassof390d2c2004-09-10 20:48:21 +0000951 if (!(found & TLVFLAG_AREA_ADDRS))
952 {
953 zlog_warn ("No Area addresses TLV in Level %d LAN IS to IS hello",
954 level);
jardineb5d44e2003-12-23 08:09:43 +0000955 retval = ISIS_WARNING;
956 goto out;
957 }
hassof390d2c2004-09-10 20:48:21 +0000958
Josh Bailey3f045a02012-03-24 08:35:20 -0700959 /* Verify authentication, either cleartext of HMAC MD5 */
hassof390d2c2004-09-10 20:48:21 +0000960 if (circuit->passwd.type)
961 {
962 if (!(found & TLVFLAG_AUTH_INFO) ||
Josh Bailey3f045a02012-03-24 08:35:20 -0700963 authentication_check (&tlvs.auth_info, &circuit->passwd,
964 circuit->rcv_stream, auth_tlv_offset))
965 {
966 isis_event_auth_failure (circuit->area->area_tag,
967 "LAN hello authentication failure",
968 hdr.source_id);
969 retval = ISIS_WARNING;
970 goto out;
971 }
hassof390d2c2004-09-10 20:48:21 +0000972 }
jardineb5d44e2003-12-23 08:09:43 +0000973
974 /*
975 * Accept the level 1 adjacency only if a match between local and
976 * remote area addresses is found
977 */
Josh Bailey3f045a02012-03-24 08:35:20 -0700978 if (listcount (circuit->area->area_addrs) == 0 ||
979 (level == IS_LEVEL_1 &&
980 area_match (circuit->area->area_addrs, tlvs.area_addrs) == 0))
hassof390d2c2004-09-10 20:48:21 +0000981 {
982 if (isis->debugs & DEBUG_ADJ_PACKETS)
983 {
hasso529d65b2004-12-24 00:14:50 +0000984 zlog_debug ("ISIS-Adj (%s): Area mismatch, level %d IIH on %s",
985 circuit->area->area_tag, level,
986 circuit->interface->name);
hassof390d2c2004-09-10 20:48:21 +0000987 }
988 retval = ISIS_OK;
989 goto out;
jardineb5d44e2003-12-23 08:09:43 +0000990 }
jardineb5d44e2003-12-23 08:09:43 +0000991
992 /*
993 * it's own IIH PDU - discard silently
hassof390d2c2004-09-10 20:48:21 +0000994 */
995 if (!memcmp (circuit->u.bc.snpa, ssnpa, ETH_ALEN))
996 {
hasso529d65b2004-12-24 00:14:50 +0000997 zlog_debug ("ISIS-Adj (%s): it's own IIH PDU - discarded",
998 circuit->area->area_tag);
jardineb5d44e2003-12-23 08:09:43 +0000999
hassof390d2c2004-09-10 20:48:21 +00001000 retval = ISIS_OK;
1001 goto out;
1002 }
jardineb5d44e2003-12-23 08:09:43 +00001003
1004 /*
1005 * check if it's own interface ip match iih ip addrs
1006 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001007 if ((found & TLVFLAG_IPV4_ADDR) == 0 ||
1008 ip_match (circuit->ip_addrs, tlvs.ipv4_addrs) == 0)
hassof390d2c2004-09-10 20:48:21 +00001009 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001010 zlog_debug ("ISIS-Adj: No usable IP interface addresses "
1011 "in LAN IIH from %s\n", circuit->interface->name);
hassof390d2c2004-09-10 20:48:21 +00001012 retval = ISIS_WARNING;
1013 goto out;
1014 }
jardineb5d44e2003-12-23 08:09:43 +00001015
1016 adj = isis_adj_lookup (hdr.source_id, circuit->u.bc.adjdb[level - 1]);
Josh Bailey3f045a02012-03-24 08:35:20 -07001017 if ((adj == NULL) || (memcmp(adj->snpa, ssnpa, ETH_ALEN)) ||
1018 (adj->level != level))
hassof390d2c2004-09-10 20:48:21 +00001019 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001020 if (!adj)
1021 {
1022 /*
1023 * Do as in 8.4.2.5
1024 */
1025 adj = isis_new_adj (hdr.source_id, ssnpa, level, circuit);
1026 if (adj == NULL)
1027 {
1028 retval = ISIS_ERROR;
1029 goto out;
1030 }
1031 }
1032 else
1033 {
1034 if (ssnpa) {
1035 memcpy (adj->snpa, ssnpa, 6);
1036 } else {
1037 memset (adj->snpa, ' ', 6);
1038 }
1039 adj->level = level;
1040 }
hassof390d2c2004-09-10 20:48:21 +00001041 isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
jardineb5d44e2003-12-23 08:09:43 +00001042
Josh Bailey3f045a02012-03-24 08:35:20 -07001043 if (level == IS_LEVEL_1)
1044 adj->sys_type = ISIS_SYSTYPE_L1_IS;
hassof390d2c2004-09-10 20:48:21 +00001045 else
Josh Bailey3f045a02012-03-24 08:35:20 -07001046 adj->sys_type = ISIS_SYSTYPE_L2_IS;
hassof390d2c2004-09-10 20:48:21 +00001047 list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
1048 isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
Josh Bailey3f045a02012-03-24 08:35:20 -07001049 circuit->u.bc.lan_neighs[level - 1]);
jardineb5d44e2003-12-23 08:09:43 +00001050 }
jardineb5d44e2003-12-23 08:09:43 +00001051
hassoa211d652004-09-20 14:55:29 +00001052 if(adj->dis_record[level-1].dis==ISIS_IS_DIS)
1053 switch (level)
1054 {
1055 case 1:
1056 if (memcmp (circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1))
1057 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001058 thread_add_event (master, isis_event_dis_status_change, circuit, 0);
hasso64a7afd2004-09-14 11:05:13 +00001059 memcpy (&circuit->u.bc.l1_desig_is, hdr.lan_id,
1060 ISIS_SYS_ID_LEN + 1);
hassoa211d652004-09-20 14:55:29 +00001061 }
1062 break;
1063 case 2:
1064 if (memcmp (circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1))
1065 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001066 thread_add_event (master, isis_event_dis_status_change, circuit, 0);
hasso64a7afd2004-09-14 11:05:13 +00001067 memcpy (&circuit->u.bc.l2_desig_is, hdr.lan_id,
1068 ISIS_SYS_ID_LEN + 1);
hassoa211d652004-09-20 14:55:29 +00001069 }
1070 break;
1071 }
jardineb5d44e2003-12-23 08:09:43 +00001072
1073 adj->hold_time = hdr.hold_time;
hassof390d2c2004-09-10 20:48:21 +00001074 adj->last_upd = time (NULL);
1075 adj->prio[level - 1] = hdr.prio;
jardineb5d44e2003-12-23 08:09:43 +00001076
1077 memcpy (adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
1078
Josh Bailey3f045a02012-03-24 08:35:20 -07001079 tlvs_to_adj_area_addrs (&tlvs, adj);
1080
jardineb5d44e2003-12-23 08:09:43 +00001081 /* which protocol are spoken ??? */
hassof390d2c2004-09-10 20:48:21 +00001082 if (found & TLVFLAG_NLPID)
jardineb5d44e2003-12-23 08:09:43 +00001083 tlvs_to_adj_nlpids (&tlvs, adj);
1084
1085 /* we need to copy addresses to the adj */
hassof390d2c2004-09-10 20:48:21 +00001086 if (found & TLVFLAG_IPV4_ADDR)
jardineb5d44e2003-12-23 08:09:43 +00001087 tlvs_to_adj_ipv4_addrs (&tlvs, adj);
1088
1089#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +00001090 if (found & TLVFLAG_IPV6_ADDR)
jardineb5d44e2003-12-23 08:09:43 +00001091 tlvs_to_adj_ipv6_addrs (&tlvs, adj);
1092#endif /* HAVE_IPV6 */
1093
1094 adj->circuit_t = hdr.circuit_t;
1095
1096 /* lets take care of the expiry */
hassof390d2c2004-09-10 20:48:21 +00001097 THREAD_TIMER_OFF (adj->t_expire);
1098 THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
Josh Bailey3f045a02012-03-24 08:35:20 -07001099 (long) adj->hold_time);
jardineb5d44e2003-12-23 08:09:43 +00001100
1101 /*
1102 * If the snpa for this circuit is found from LAN Neighbours TLV
1103 * we have two-way communication -> adjacency can be put to state "up"
1104 */
1105
hassof390d2c2004-09-10 20:48:21 +00001106 if (found & TLVFLAG_LAN_NEIGHS)
Josh Bailey3f045a02012-03-24 08:35:20 -07001107 {
1108 if (adj->adj_state != ISIS_ADJ_UP)
hassof390d2c2004-09-10 20:48:21 +00001109 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001110 for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa))
1111 {
1112 if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))
1113 {
1114 isis_adj_state_change (adj, ISIS_ADJ_UP,
1115 "own SNPA found in LAN Neighbours TLV");
1116 }
1117 }
jardineb5d44e2003-12-23 08:09:43 +00001118 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001119 else
1120 {
1121 int found = 0;
1122 for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa))
1123 if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))
1124 {
1125 found = 1;
1126 break;
1127 }
1128 if (found == 0)
1129 isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING,
1130 "own SNPA not found in LAN Neighbours TLV");
1131 }
1132 }
1133 else if (adj->adj_state == ISIS_ADJ_UP)
1134 {
1135 isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING,
1136 "no LAN Neighbours TLV found");
1137 }
jardineb5d44e2003-12-23 08:09:43 +00001138
hassof390d2c2004-09-10 20:48:21 +00001139out:
hassof390d2c2004-09-10 20:48:21 +00001140 if (isis->debugs & DEBUG_ADJ_PACKETS)
1141 {
hasso529d65b2004-12-24 00:14:50 +00001142 zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "
1143 "cirID %u, length %ld",
1144 circuit->area->area_tag,
1145 level, snpa_print (ssnpa), circuit->interface->name,
Josh Bailey3f045a02012-03-24 08:35:20 -07001146 circuit_t2string (circuit->is_type),
hasso29e50b22005-09-01 18:18:47 +00001147 circuit->circuit_id,
Josh Bailey3f045a02012-03-24 08:35:20 -07001148 stream_get_endp (circuit->rcv_stream));
hassof390d2c2004-09-10 20:48:21 +00001149 }
jardineb5d44e2003-12-23 08:09:43 +00001150
1151 free_tlvs (&tlvs);
1152
1153 return retval;
1154}
1155
1156/*
1157 * Process Level 1/2 Link State
1158 * ISO - 10589
1159 * Section 7.3.15.1 - Action on receipt of a link state PDU
hassof390d2c2004-09-10 20:48:21 +00001160 */
1161static int
1162process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)
jardineb5d44e2003-12-23 08:09:43 +00001163{
1164 struct isis_link_state_hdr *hdr;
1165 struct isis_adjacency *adj = NULL;
1166 struct isis_lsp *lsp, *lsp0 = NULL;
1167 int retval = ISIS_OK, comp = 0;
1168 u_char lspid[ISIS_SYS_ID_LEN + 2];
1169 struct isis_passwd *passwd;
1170
Josh Bailey3f045a02012-03-24 08:35:20 -07001171 if (isis->debugs & DEBUG_UPDATE_PACKETS)
1172 {
1173 zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP on %s, cirType %s, cirID %u",
1174 circuit->area->area_tag, level, circuit->interface->name,
1175 circuit_t2string (circuit->is_type), circuit->circuit_id);
1176 if (isis->debugs & DEBUG_PACKET_DUMP)
1177 zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
1178 stream_get_endp (circuit->rcv_stream));
1179 }
1180
hassof390d2c2004-09-10 20:48:21 +00001181 if ((stream_get_endp (circuit->rcv_stream) -
1182 stream_get_getp (circuit->rcv_stream)) < ISIS_LSP_HDR_LEN)
1183 {
1184 zlog_warn ("Packet too short");
1185 return ISIS_WARNING;
1186 }
jardineb5d44e2003-12-23 08:09:43 +00001187
1188 /* Reference the header */
hassof390d2c2004-09-10 20:48:21 +00001189 hdr = (struct isis_link_state_hdr *) STREAM_PNT (circuit->rcv_stream);
jardineb5d44e2003-12-23 08:09:43 +00001190
hassof390d2c2004-09-10 20:48:21 +00001191 if (isis->debugs & DEBUG_UPDATE_PACKETS)
1192 {
hasso529d65b2004-12-24 00:14:50 +00001193 zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "
Josh Bailey3f045a02012-03-24 08:35:20 -07001194 "lifetime %us, len %u, on %s",
hasso529d65b2004-12-24 00:14:50 +00001195 circuit->area->area_tag,
1196 level,
1197 rawlspid_print (hdr->lsp_id),
1198 ntohl (hdr->seq_num),
1199 ntohs (hdr->checksum),
1200 ntohs (hdr->rem_lifetime),
Josh Bailey3f045a02012-03-24 08:35:20 -07001201 ntohs (hdr->pdu_len),
paul15935e92005-05-03 09:27:23 +00001202 circuit->interface->name);
hassof390d2c2004-09-10 20:48:21 +00001203 }
jardineb5d44e2003-12-23 08:09:43 +00001204
Josh Bailey3f045a02012-03-24 08:35:20 -07001205 if (ntohs (hdr->pdu_len) <= ISIS_LSP_HDR_LEN ||
1206 ntohs (hdr->pdu_len) > ISO_MTU(circuit))
1207 {
1208 zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP length %d",
1209 circuit->area->area_tag,
1210 rawlspid_print (hdr->lsp_id), ntohs (hdr->pdu_len));
1211
1212 return ISIS_WARNING;
1213 }
jardineb5d44e2003-12-23 08:09:43 +00001214
1215 /* Checksum sanity check - FIXME: move to correct place */
1216 /* 12 = sysid+pdu+remtime */
hassof390d2c2004-09-10 20:48:21 +00001217 if (iso_csum_verify (STREAM_PNT (circuit->rcv_stream) + 4,
1218 ntohs (hdr->pdu_len) - 12, &hdr->checksum))
1219 {
hasso529d65b2004-12-24 00:14:50 +00001220 zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
1221 circuit->area->area_tag,
1222 rawlspid_print (hdr->lsp_id), ntohs (hdr->checksum));
jardineb5d44e2003-12-23 08:09:43 +00001223
hassof390d2c2004-09-10 20:48:21 +00001224 return ISIS_WARNING;
1225 }
jardineb5d44e2003-12-23 08:09:43 +00001226
1227 /* 7.3.15.1 a) 1 - external domain circuit will discard lsps */
hassof390d2c2004-09-10 20:48:21 +00001228 if (circuit->ext_domain)
1229 {
hasso529d65b2004-12-24 00:14:50 +00001230 zlog_debug
hassof390d2c2004-09-10 20:48:21 +00001231 ("ISIS-Upd (%s): LSP %s received at level %d over circuit with "
1232 "externalDomain = true", circuit->area->area_tag,
1233 rawlspid_print (hdr->lsp_id), level);
jardineb5d44e2003-12-23 08:09:43 +00001234
hassof390d2c2004-09-10 20:48:21 +00001235 return ISIS_WARNING;
1236 }
jardineb5d44e2003-12-23 08:09:43 +00001237
1238 /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
Josh Bailey3f045a02012-03-24 08:35:20 -07001239 if (!accept_level (level, circuit->is_type))
hassof390d2c2004-09-10 20:48:21 +00001240 {
hasso529d65b2004-12-24 00:14:50 +00001241 zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of"
1242 " type %s",
1243 circuit->area->area_tag,
1244 rawlspid_print (hdr->lsp_id),
Josh Bailey3f045a02012-03-24 08:35:20 -07001245 level, circuit_t2string (circuit->is_type));
jardineb5d44e2003-12-23 08:09:43 +00001246
hassof390d2c2004-09-10 20:48:21 +00001247 return ISIS_WARNING;
1248 }
jardineb5d44e2003-12-23 08:09:43 +00001249
1250 /* 7.3.15.1 a) 4 - need to make sure IDLength matches */
1251
1252 /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */
1253
1254 /* 7.3.15.1 a) 7 - password check */
Josh Bailey3f045a02012-03-24 08:35:20 -07001255 (level == IS_LEVEL_1) ? (passwd = &circuit->area->area_passwd) :
1256 (passwd = &circuit->area->domain_passwd);
hassof390d2c2004-09-10 20:48:21 +00001257 if (passwd->type)
1258 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001259 if (lsp_authentication_check (circuit->rcv_stream, circuit->area,
1260 level, passwd))
hassof390d2c2004-09-10 20:48:21 +00001261 {
1262 isis_event_auth_failure (circuit->area->area_tag,
1263 "LSP authentication failure", hdr->lsp_id);
1264 return ISIS_WARNING;
1265 }
jardineb5d44e2003-12-23 08:09:43 +00001266 }
jardineb5d44e2003-12-23 08:09:43 +00001267 /* Find the LSP in our database and compare it to this Link State header */
1268 lsp = lsp_search (hdr->lsp_id, circuit->area->lspdb[level - 1]);
1269 if (lsp)
hassof390d2c2004-09-10 20:48:21 +00001270 comp = lsp_compare (circuit->area->area_tag, lsp, hdr->seq_num,
1271 hdr->checksum, hdr->rem_lifetime);
1272 if (lsp && (lsp->own_lsp
jardineb5d44e2003-12-23 08:09:43 +00001273#ifdef TOPOLOGY_GENERATE
hassof390d2c2004-09-10 20:48:21 +00001274 || lsp->from_topology
jardineb5d44e2003-12-23 08:09:43 +00001275#endif /* TOPOLOGY_GENERATE */
hassof390d2c2004-09-10 20:48:21 +00001276 ))
jardineb5d44e2003-12-23 08:09:43 +00001277 goto dontcheckadj;
1278
1279 /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level */
1280 /* for broadcast circuits, snpa should be compared */
jardineb5d44e2003-12-23 08:09:43 +00001281
hassof390d2c2004-09-10 20:48:21 +00001282 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
1283 {
1284 adj = isis_adj_lookup_snpa (ssnpa, circuit->u.bc.adjdb[level - 1]);
1285 if (!adj)
1286 {
hasso529d65b2004-12-24 00:14:50 +00001287 zlog_debug ("(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, "
1288 "lifetime %us on %s",
1289 circuit->area->area_tag,
1290 rawlspid_print (hdr->lsp_id),
1291 ntohl (hdr->seq_num),
1292 ntohs (hdr->checksum),
1293 ntohs (hdr->rem_lifetime), circuit->interface->name);
hassof390d2c2004-09-10 20:48:21 +00001294 return ISIS_WARNING; /* Silently discard */
1295 }
jardineb5d44e2003-12-23 08:09:43 +00001296 }
jardineb5d44e2003-12-23 08:09:43 +00001297 /* for non broadcast, we just need to find same level adj */
hassof390d2c2004-09-10 20:48:21 +00001298 else
1299 {
1300 /* If no adj, or no sharing of level */
1301 if (!circuit->u.p2p.neighbor)
1302 {
1303 return ISIS_OK; /* Silently discard */
1304 }
1305 else
1306 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001307 if (((level == IS_LEVEL_1) &&
hassof390d2c2004-09-10 20:48:21 +00001308 (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL2)) ||
Josh Bailey3f045a02012-03-24 08:35:20 -07001309 ((level == IS_LEVEL_2) &&
hassof390d2c2004-09-10 20:48:21 +00001310 (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL1)))
1311 return ISIS_WARNING; /* Silently discard */
Josh Bailey3f045a02012-03-24 08:35:20 -07001312 adj = circuit->u.p2p.neighbor;
hassof390d2c2004-09-10 20:48:21 +00001313 }
jardineb5d44e2003-12-23 08:09:43 +00001314 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001315
hassof390d2c2004-09-10 20:48:21 +00001316dontcheckadj:
jardineb5d44e2003-12-23 08:09:43 +00001317 /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */
1318
1319 /* 7.3.15.1 a) 8 - Passwords for level 2 - not implemented */
1320
hassof390d2c2004-09-10 20:48:21 +00001321 /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented FIXME: do it */
jardineb5d44e2003-12-23 08:09:43 +00001322
hassof390d2c2004-09-10 20:48:21 +00001323 /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */
1324 if (hdr->rem_lifetime == 0)
1325 {
1326 if (!lsp)
1327 {
1328 /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't save */
1329 /* only needed on explicit update, eg - p2p */
1330 if (circuit->circ_type == CIRCUIT_T_P2P)
1331 ack_lsp (hdr, circuit, level);
1332 return retval; /* FIXME: do we need a purge? */
1333 }
1334 else
1335 {
1336 if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN))
1337 {
1338 /* LSP by some other system -> do 7.3.16.4 b) */
1339 /* 7.3.16.4 b) 1) */
1340 if (comp == LSP_NEWER)
1341 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001342 lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
hassof390d2c2004-09-10 20:48:21 +00001343 /* ii */
Josh Bailey3f045a02012-03-24 08:35:20 -07001344 lsp_set_all_srmflags (lsp);
hassof390d2c2004-09-10 20:48:21 +00001345 /* iii */
1346 ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
1347 /* v */
1348 ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags); /* FIXME: OTHER than c */
1349 /* iv */
1350 if (circuit->circ_type != CIRCUIT_T_BROADCAST)
1351 ISIS_SET_FLAG (lsp->SSNflags, circuit);
jardineb5d44e2003-12-23 08:09:43 +00001352
hassof390d2c2004-09-10 20:48:21 +00001353 } /* 7.3.16.4 b) 2) */
1354 else if (comp == LSP_EQUAL)
1355 {
1356 /* i */
1357 ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
1358 /* ii */
1359 if (circuit->circ_type != CIRCUIT_T_BROADCAST)
1360 ISIS_SET_FLAG (lsp->SSNflags, circuit);
1361 } /* 7.3.16.4 b) 3) */
1362 else
1363 {
1364 ISIS_SET_FLAG (lsp->SRMflags, circuit);
1365 ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
1366 }
1367 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001368 else if (lsp->lsp_header->rem_lifetime != 0)
1369 {
1370 /* our own LSP -> 7.3.16.4 c) */
1371 if (comp == LSP_NEWER)
1372 {
1373 lsp_inc_seqnum (lsp, ntohl (hdr->seq_num));
1374 lsp_set_all_srmflags (lsp);
1375 }
1376 else
1377 {
1378 ISIS_SET_FLAG (lsp->SRMflags, circuit);
1379 ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
1380 }
1381 if (isis->debugs & DEBUG_UPDATE_PACKETS)
1382 zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new "
1383 "seq 0x%08x", circuit->area->area_tag,
1384 rawlspid_print (hdr->lsp_id),
1385 ntohl (lsp->lsp_header->seq_num));
1386 }
hassof390d2c2004-09-10 20:48:21 +00001387 }
1388 return retval;
jardineb5d44e2003-12-23 08:09:43 +00001389 }
jardineb5d44e2003-12-23 08:09:43 +00001390 /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a
1391 * purge */
hassof390d2c2004-09-10 20:48:21 +00001392 if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN) == 0)
1393 {
1394 if (!lsp)
1395 {
1396 /* 7.3.16.4: initiate a purge */
1397 lsp_purge_non_exist (hdr, circuit->area);
1398 return ISIS_OK;
1399 }
1400 /* 7.3.15.1 d) - If this is our own lsp and we have it */
1401
1402 /* In 7.3.16.1, If an Intermediate system R somewhere in the domain
1403 * has information that the current sequence number for source S is
1404 * "greater" than that held by S, ... */
1405
1406 else if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num))
1407 {
1408 /* 7.3.16.1 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001409 lsp_inc_seqnum (lsp, ntohl (hdr->seq_num));
1410 lsp_set_all_srmflags (lsp);
hassoc89c05d2005-09-04 21:36:36 +00001411 if (isis->debugs & DEBUG_UPDATE_PACKETS)
1412 zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq "
1413 "0x%08x", circuit->area->area_tag,
1414 rawlspid_print (hdr->lsp_id),
1415 ntohl (lsp->lsp_header->seq_num));
hassof390d2c2004-09-10 20:48:21 +00001416 }
jardineb5d44e2003-12-23 08:09:43 +00001417 }
hassof390d2c2004-09-10 20:48:21 +00001418 else
1419 {
1420 /* 7.3.15.1 e) - This lsp originated on another system */
jardineb5d44e2003-12-23 08:09:43 +00001421
hassof390d2c2004-09-10 20:48:21 +00001422 /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */
1423 if ((!lsp || comp == LSP_NEWER))
1424 {
hassof390d2c2004-09-10 20:48:21 +00001425 /*
1426 * If this lsp is a frag, need to see if we have zero lsp present
1427 */
1428 if (LSP_FRAGMENT (hdr->lsp_id) != 0)
1429 {
1430 memcpy (lspid, hdr->lsp_id, ISIS_SYS_ID_LEN + 1);
1431 LSP_FRAGMENT (lspid) = 0;
1432 lsp0 = lsp_search (lspid, circuit->area->lspdb[level - 1]);
1433 if (!lsp0)
1434 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001435 zlog_debug ("Got lsp frag, while zero lsp not in database");
hassof390d2c2004-09-10 20:48:21 +00001436 return ISIS_OK;
1437 }
1438 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001439 /* i */
1440 if (!lsp)
1441 {
1442 lsp = lsp_new_from_stream_ptr (circuit->rcv_stream,
1443 ntohs (hdr->pdu_len), lsp0,
1444 circuit->area, level);
1445 lsp_insert (lsp, circuit->area->lspdb[level - 1]);
1446 }
1447 else /* exists, so we overwrite */
1448 {
1449 lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
1450 }
hassof390d2c2004-09-10 20:48:21 +00001451 /* ii */
Josh Bailey3f045a02012-03-24 08:35:20 -07001452 lsp_set_all_srmflags (lsp);
hassof390d2c2004-09-10 20:48:21 +00001453 /* iii */
1454 ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
jardineb5d44e2003-12-23 08:09:43 +00001455
hassof390d2c2004-09-10 20:48:21 +00001456 /* iv */
1457 if (circuit->circ_type != CIRCUIT_T_BROADCAST)
1458 ISIS_SET_FLAG (lsp->SSNflags, circuit);
1459 /* FIXME: v) */
1460 }
1461 /* 7.3.15.1 e) 2) LSP equal to the one in db */
1462 else if (comp == LSP_EQUAL)
1463 {
1464 ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
Josh Bailey3f045a02012-03-24 08:35:20 -07001465 lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
hassof390d2c2004-09-10 20:48:21 +00001466 if (circuit->circ_type != CIRCUIT_T_BROADCAST)
Josh Bailey3f045a02012-03-24 08:35:20 -07001467 ISIS_SET_FLAG (lsp->SSNflags, circuit);
hassof390d2c2004-09-10 20:48:21 +00001468 }
1469 /* 7.3.15.1 e) 3) LSP older than the one in db */
1470 else
1471 {
1472 ISIS_SET_FLAG (lsp->SRMflags, circuit);
1473 ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
1474 }
jardineb5d44e2003-12-23 08:09:43 +00001475 }
jardineb5d44e2003-12-23 08:09:43 +00001476 return retval;
1477}
1478
1479/*
1480 * Process Sequence Numbers
1481 * ISO - 10589
1482 * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU
1483 */
1484
hasso92365882005-01-18 13:53:33 +00001485static int
hassof390d2c2004-09-10 20:48:21 +00001486process_snp (int snp_type, int level, struct isis_circuit *circuit,
1487 u_char * ssnpa)
jardineb5d44e2003-12-23 08:09:43 +00001488{
1489 int retval = ISIS_OK;
1490 int cmp, own_lsp;
1491 char typechar = ' ';
Josh Bailey3f045a02012-03-24 08:35:20 -07001492 unsigned int len;
jardineb5d44e2003-12-23 08:09:43 +00001493 struct isis_adjacency *adj;
1494 struct isis_complete_seqnum_hdr *chdr = NULL;
1495 struct isis_partial_seqnum_hdr *phdr = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07001496 uint32_t found = 0, expected = 0, auth_tlv_offset = 0;
jardineb5d44e2003-12-23 08:09:43 +00001497 struct isis_lsp *lsp;
1498 struct lsp_entry *entry;
paul1eb8ef22005-04-07 07:30:20 +00001499 struct listnode *node, *nnode;
1500 struct listnode *node2, *nnode2;
jardineb5d44e2003-12-23 08:09:43 +00001501 struct tlvs tlvs;
1502 struct list *lsp_list = NULL;
1503 struct isis_passwd *passwd;
1504
hassof390d2c2004-09-10 20:48:21 +00001505 if (snp_type == ISIS_SNP_CSNP_FLAG)
1506 {
1507 /* getting the header info */
1508 typechar = 'C';
1509 chdr =
1510 (struct isis_complete_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream);
1511 circuit->rcv_stream->getp += ISIS_CSNP_HDRLEN;
1512 len = ntohs (chdr->pdu_len);
Josh Bailey3f045a02012-03-24 08:35:20 -07001513 if (len < ISIS_CSNP_HDRLEN || len > ISO_MTU(circuit))
hassof390d2c2004-09-10 20:48:21 +00001514 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001515 zlog_warn ("Received a CSNP with bogus length %d", len);
hassof390d2c2004-09-10 20:48:21 +00001516 return ISIS_OK;
1517 }
jardineb5d44e2003-12-23 08:09:43 +00001518 }
hassof390d2c2004-09-10 20:48:21 +00001519 else
1520 {
1521 typechar = 'P';
1522 phdr =
1523 (struct isis_partial_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream);
1524 circuit->rcv_stream->getp += ISIS_PSNP_HDRLEN;
1525 len = ntohs (phdr->pdu_len);
Josh Bailey3f045a02012-03-24 08:35:20 -07001526 if (len < ISIS_PSNP_HDRLEN || len > ISO_MTU(circuit))
hassof390d2c2004-09-10 20:48:21 +00001527 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001528 zlog_warn ("Received a CSNP with bogus length %d", len);
hassof390d2c2004-09-10 20:48:21 +00001529 return ISIS_OK;
1530 }
jardineb5d44e2003-12-23 08:09:43 +00001531 }
jardineb5d44e2003-12-23 08:09:43 +00001532
1533 /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */
hassof390d2c2004-09-10 20:48:21 +00001534 if (circuit->ext_domain)
1535 {
jardineb5d44e2003-12-23 08:09:43 +00001536
hasso529d65b2004-12-24 00:14:50 +00001537 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1538 "skipping: circuit externalDomain = true",
1539 circuit->area->area_tag,
1540 level, typechar, circuit->interface->name);
jardineb5d44e2003-12-23 08:09:43 +00001541
1542 return ISIS_OK;
1543 }
hassof390d2c2004-09-10 20:48:21 +00001544
1545 /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
Josh Bailey3f045a02012-03-24 08:35:20 -07001546 if (!accept_level (level, circuit->is_type))
hassof390d2c2004-09-10 20:48:21 +00001547 {
1548
hasso529d65b2004-12-24 00:14:50 +00001549 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1550 "skipping: circuit type %s does not match level %d",
1551 circuit->area->area_tag,
1552 level,
1553 typechar,
1554 circuit->interface->name,
Josh Bailey3f045a02012-03-24 08:35:20 -07001555 circuit_t2string (circuit->is_type), level);
hassof390d2c2004-09-10 20:48:21 +00001556
1557 return ISIS_OK;
1558 }
1559
1560 /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */
1561 if ((snp_type == ISIS_SNP_PSNP_FLAG) &&
Josh Bailey3f045a02012-03-24 08:35:20 -07001562 (circuit->circ_type == CIRCUIT_T_BROADCAST) &&
1563 (!circuit->u.bc.is_dr[level - 1]))
hassof390d2c2004-09-10 20:48:21 +00001564 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001565 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
1566 "skipping: we are not the DIS",
1567 circuit->area->area_tag,
1568 level,
1569 typechar, snpa_print (ssnpa), circuit->interface->name);
hassof390d2c2004-09-10 20:48:21 +00001570
Josh Bailey3f045a02012-03-24 08:35:20 -07001571 return ISIS_OK;
hassof390d2c2004-09-10 20:48:21 +00001572 }
jardineb5d44e2003-12-23 08:09:43 +00001573
1574 /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */
1575
1576 /* 7.3.15.2 a) 6 - maximum area match, can be ommited since we only use 3
1577 * - already checked */
1578
1579 /* 7.3.15.2 a) 7 - Must check that we have an adjacency of the same level */
1580 /* for broadcast circuits, snpa should be compared */
1581 /* FIXME : Do we need to check SNPA? */
hassof390d2c2004-09-10 20:48:21 +00001582 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
1583 {
1584 if (snp_type == ISIS_SNP_CSNP_FLAG)
1585 {
1586 adj =
1587 isis_adj_lookup (chdr->source_id, circuit->u.bc.adjdb[level - 1]);
1588 }
1589 else
1590 {
1591 /* a psnp on a broadcast, how lovely of Juniper :) */
1592 adj =
1593 isis_adj_lookup (phdr->source_id, circuit->u.bc.adjdb[level - 1]);
1594 }
1595 if (!adj)
1596 return ISIS_OK; /* Silently discard */
jardineb5d44e2003-12-23 08:09:43 +00001597 }
hassof390d2c2004-09-10 20:48:21 +00001598 else
1599 {
1600 if (!circuit->u.p2p.neighbor)
Josh Bailey3f045a02012-03-24 08:35:20 -07001601 {
1602 zlog_warn ("no p2p neighbor on circuit %s", circuit->interface->name);
1603 return ISIS_OK; /* Silently discard */
1604 }
hassof390d2c2004-09-10 20:48:21 +00001605 }
jardineb5d44e2003-12-23 08:09:43 +00001606
1607 /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */
1608
1609 /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */
1610
1611 memset (&tlvs, 0, sizeof (struct tlvs));
1612
1613 /* parse the SNP */
1614 expected |= TLVFLAG_LSP_ENTRIES;
1615 expected |= TLVFLAG_AUTH_INFO;
Josh Bailey3f045a02012-03-24 08:35:20 -07001616
1617 auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
jardineb5d44e2003-12-23 08:09:43 +00001618 retval = parse_tlvs (circuit->area->area_tag,
hassof390d2c2004-09-10 20:48:21 +00001619 STREAM_PNT (circuit->rcv_stream),
jardineb5d44e2003-12-23 08:09:43 +00001620 len - circuit->rcv_stream->getp,
Josh Bailey3f045a02012-03-24 08:35:20 -07001621 &expected, &found, &tlvs, &auth_tlv_offset);
jardineb5d44e2003-12-23 08:09:43 +00001622
hassof390d2c2004-09-10 20:48:21 +00001623 if (retval > ISIS_WARNING)
1624 {
1625 zlog_warn ("something went very wrong processing SNP");
1626 free_tlvs (&tlvs);
1627 return retval;
1628 }
jardineb5d44e2003-12-23 08:09:43 +00001629
Josh Bailey3f045a02012-03-24 08:35:20 -07001630 if (level == IS_LEVEL_1)
hasso1cbc5622005-01-01 10:29:51 +00001631 passwd = &circuit->area->area_passwd;
1632 else
1633 passwd = &circuit->area->domain_passwd;
1634
1635 if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV))
hassof390d2c2004-09-10 20:48:21 +00001636 {
hasso1cbc5622005-01-01 10:29:51 +00001637 if (passwd->type)
Josh Bailey3f045a02012-03-24 08:35:20 -07001638 {
1639 if (!(found & TLVFLAG_AUTH_INFO) ||
1640 authentication_check (&tlvs.auth_info, passwd,
1641 circuit->rcv_stream, auth_tlv_offset))
1642 {
1643 isis_event_auth_failure (circuit->area->area_tag,
1644 "SNP authentication" " failure",
1645 phdr ? phdr->source_id :
1646 chdr->source_id);
1647 free_tlvs (&tlvs);
1648 return ISIS_OK;
1649 }
1650 }
hassof390d2c2004-09-10 20:48:21 +00001651 }
jardineb5d44e2003-12-23 08:09:43 +00001652
1653 /* debug isis snp-packets */
hassof390d2c2004-09-10 20:48:21 +00001654 if (isis->debugs & DEBUG_SNP_PACKETS)
1655 {
hasso529d65b2004-12-24 00:14:50 +00001656 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s",
1657 circuit->area->area_tag,
1658 level,
1659 typechar, snpa_print (ssnpa), circuit->interface->name);
hassof390d2c2004-09-10 20:48:21 +00001660 if (tlvs.lsp_entries)
1661 {
hasso3fdb2dd2005-09-28 18:45:54 +00001662 for (ALL_LIST_ELEMENTS_RO (tlvs.lsp_entries, node, entry))
hassof390d2c2004-09-10 20:48:21 +00001663 {
hasso529d65b2004-12-24 00:14:50 +00001664 zlog_debug ("ISIS-Snp (%s): %cSNP entry %s, seq 0x%08x,"
1665 " cksum 0x%04x, lifetime %us",
1666 circuit->area->area_tag,
1667 typechar,
1668 rawlspid_print (entry->lsp_id),
1669 ntohl (entry->seq_num),
1670 ntohs (entry->checksum), ntohs (entry->rem_lifetime));
hassof390d2c2004-09-10 20:48:21 +00001671 }
1672 }
jardineb5d44e2003-12-23 08:09:43 +00001673 }
jardineb5d44e2003-12-23 08:09:43 +00001674
1675 /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */
hassof390d2c2004-09-10 20:48:21 +00001676 if (tlvs.lsp_entries)
1677 {
hasso3fdb2dd2005-09-28 18:45:54 +00001678 for (ALL_LIST_ELEMENTS_RO (tlvs.lsp_entries, node, entry))
hassof390d2c2004-09-10 20:48:21 +00001679 {
1680 lsp = lsp_search (entry->lsp_id, circuit->area->lspdb[level - 1]);
1681 own_lsp = !memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
1682 if (lsp)
1683 {
1684 /* 7.3.15.2 b) 1) is this LSP newer */
1685 cmp = lsp_compare (circuit->area->area_tag, lsp, entry->seq_num,
1686 entry->checksum, entry->rem_lifetime);
1687 /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */
1688 if (cmp == LSP_EQUAL)
1689 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001690 /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */
1691 ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
hassof390d2c2004-09-10 20:48:21 +00001692 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001693 /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
hassof390d2c2004-09-10 20:48:21 +00001694 else if (cmp == LSP_OLDER)
1695 {
1696 ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
1697 ISIS_SET_FLAG (lsp->SRMflags, circuit);
1698 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001699 /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM on p2p */
hassof390d2c2004-09-10 20:48:21 +00001700 else
1701 {
hassof390d2c2004-09-10 20:48:21 +00001702 if (own_lsp)
1703 {
1704 lsp_inc_seqnum (lsp, ntohl (entry->seq_num));
1705 ISIS_SET_FLAG (lsp->SRMflags, circuit);
1706 }
1707 else
1708 {
1709 ISIS_SET_FLAG (lsp->SSNflags, circuit);
Josh Bailey3f045a02012-03-24 08:35:20 -07001710 /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */
1711 ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
hassof390d2c2004-09-10 20:48:21 +00001712 }
1713 }
1714 }
1715 else
1716 {
1717 /* 7.3.15.2 b) 5) if it was not found, and all of those are not 0,
1718 * insert it and set SSN on it */
1719 if (entry->rem_lifetime && entry->checksum && entry->seq_num &&
1720 memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN))
1721 {
1722 lsp = lsp_new (entry->lsp_id, ntohs (entry->rem_lifetime),
1723 0, 0, entry->checksum, level);
Josh Bailey3f045a02012-03-24 08:35:20 -07001724 lsp->area = circuit->area;
hassof390d2c2004-09-10 20:48:21 +00001725 lsp_insert (lsp, circuit->area->lspdb[level - 1]);
Josh Bailey3f045a02012-03-24 08:35:20 -07001726 ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags);
hassof390d2c2004-09-10 20:48:21 +00001727 ISIS_SET_FLAG (lsp->SSNflags, circuit);
1728 }
1729 }
jardineb5d44e2003-12-23 08:09:43 +00001730 }
1731 }
jardineb5d44e2003-12-23 08:09:43 +00001732
1733 /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported */
hassof390d2c2004-09-10 20:48:21 +00001734 if (snp_type == ISIS_SNP_CSNP_FLAG)
1735 {
1736 /*
Josh Bailey3f045a02012-03-24 08:35:20 -07001737 * Build a list from our own LSP db bounded with
1738 * start_lsp_id and stop_lsp_id
hassof390d2c2004-09-10 20:48:21 +00001739 */
1740 lsp_list = list_new ();
1741 lsp_build_list_nonzero_ht (chdr->start_lsp_id, chdr->stop_lsp_id,
1742 lsp_list, circuit->area->lspdb[level - 1]);
jardineb5d44e2003-12-23 08:09:43 +00001743
hassof390d2c2004-09-10 20:48:21 +00001744 /* Fixme: Find a better solution */
1745 if (tlvs.lsp_entries)
1746 {
paul1eb8ef22005-04-07 07:30:20 +00001747 for (ALL_LIST_ELEMENTS (tlvs.lsp_entries, node, nnode, entry))
hassof390d2c2004-09-10 20:48:21 +00001748 {
paul1eb8ef22005-04-07 07:30:20 +00001749 for (ALL_LIST_ELEMENTS (lsp_list, node2, nnode2, lsp))
hassof390d2c2004-09-10 20:48:21 +00001750 {
1751 if (lsp_id_cmp (lsp->lsp_header->lsp_id, entry->lsp_id) == 0)
1752 {
1753 list_delete_node (lsp_list, node2);
1754 break;
1755 }
1756 }
1757 }
1758 }
1759 /* on remaining LSPs we set SRM (neighbor knew not of) */
hasso3fdb2dd2005-09-28 18:45:54 +00001760 for (ALL_LIST_ELEMENTS_RO (lsp_list, node, lsp))
hassof390d2c2004-09-10 20:48:21 +00001761 ISIS_SET_FLAG (lsp->SRMflags, circuit);
hassof390d2c2004-09-10 20:48:21 +00001762 /* lets free it */
Josh Bailey3f045a02012-03-24 08:35:20 -07001763 list_delete (lsp_list);
1764
jardineb5d44e2003-12-23 08:09:43 +00001765 }
jardineb5d44e2003-12-23 08:09:43 +00001766
1767 free_tlvs (&tlvs);
1768 return retval;
1769}
1770
hasso92365882005-01-18 13:53:33 +00001771static int
hassof390d2c2004-09-10 20:48:21 +00001772process_csnp (int level, struct isis_circuit *circuit, u_char * ssnpa)
jardineb5d44e2003-12-23 08:09:43 +00001773{
Josh Bailey3f045a02012-03-24 08:35:20 -07001774 if (isis->debugs & DEBUG_SNP_PACKETS)
1775 {
1776 zlog_debug ("ISIS-Snp (%s): Rcvd L%d CSNP on %s, cirType %s, cirID %u",
1777 circuit->area->area_tag, level, circuit->interface->name,
1778 circuit_t2string (circuit->is_type), circuit->circuit_id);
1779 if (isis->debugs & DEBUG_PACKET_DUMP)
1780 zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
1781 stream_get_endp (circuit->rcv_stream));
1782 }
1783
jardineb5d44e2003-12-23 08:09:43 +00001784 /* Sanity check - FIXME: move to correct place */
hassof390d2c2004-09-10 20:48:21 +00001785 if ((stream_get_endp (circuit->rcv_stream) -
1786 stream_get_getp (circuit->rcv_stream)) < ISIS_CSNP_HDRLEN)
1787 {
1788 zlog_warn ("Packet too short ( < %d)", ISIS_CSNP_HDRLEN);
1789 return ISIS_WARNING;
1790 }
jardineb5d44e2003-12-23 08:09:43 +00001791
1792 return process_snp (ISIS_SNP_CSNP_FLAG, level, circuit, ssnpa);
1793}
1794
hasso92365882005-01-18 13:53:33 +00001795static int
hassof390d2c2004-09-10 20:48:21 +00001796process_psnp (int level, struct isis_circuit *circuit, u_char * ssnpa)
jardineb5d44e2003-12-23 08:09:43 +00001797{
Josh Bailey3f045a02012-03-24 08:35:20 -07001798 if (isis->debugs & DEBUG_SNP_PACKETS)
1799 {
1800 zlog_debug ("ISIS-Snp (%s): Rcvd L%d PSNP on %s, cirType %s, cirID %u",
1801 circuit->area->area_tag, level, circuit->interface->name,
1802 circuit_t2string (circuit->is_type), circuit->circuit_id);
1803 if (isis->debugs & DEBUG_PACKET_DUMP)
1804 zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
1805 stream_get_endp (circuit->rcv_stream));
1806 }
1807
hassof390d2c2004-09-10 20:48:21 +00001808 if ((stream_get_endp (circuit->rcv_stream) -
1809 stream_get_getp (circuit->rcv_stream)) < ISIS_PSNP_HDRLEN)
1810 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001811 zlog_warn ("Packet too short ( < %d)", ISIS_PSNP_HDRLEN);
hassof390d2c2004-09-10 20:48:21 +00001812 return ISIS_WARNING;
1813 }
jardineb5d44e2003-12-23 08:09:43 +00001814
1815 return process_snp (ISIS_SNP_PSNP_FLAG, level, circuit, ssnpa);
1816}
1817
jardineb5d44e2003-12-23 08:09:43 +00001818/*
1819 * Process ISH
1820 * ISO - 10589
1821 * Section 8.2.2 - Receiving ISH PDUs by an intermediate system
1822 * FIXME: sample packet dump, need to figure 0x81 - looks like NLPid
hassof390d2c2004-09-10 20:48:21 +00001823 * 0x82 0x15 0x01 0x00 0x04 0x01 0x2c 0x59
1824 * 0x38 0x08 0x47 0x00 0x01 0x00 0x02 0x00
1825 * 0x03 0x00 0x81 0x01 0xcc
jardineb5d44e2003-12-23 08:09:43 +00001826 */
hasso92365882005-01-18 13:53:33 +00001827static int
jardineb5d44e2003-12-23 08:09:43 +00001828process_is_hello (struct isis_circuit *circuit)
1829{
1830 struct isis_adjacency *adj;
1831 int retval = ISIS_OK;
1832 u_char neigh_len;
1833 u_char *sysid;
1834
Josh Bailey3f045a02012-03-24 08:35:20 -07001835 if (isis->debugs & DEBUG_ADJ_PACKETS)
1836 {
1837 zlog_debug ("ISIS-Adj (%s): Rcvd ISH on %s, cirType %s, cirID %u",
1838 circuit->area->area_tag, circuit->interface->name,
1839 circuit_t2string (circuit->is_type), circuit->circuit_id);
1840 if (isis->debugs & DEBUG_PACKET_DUMP)
1841 zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
1842 stream_get_endp (circuit->rcv_stream));
1843 }
1844
jardineb5d44e2003-12-23 08:09:43 +00001845 /* In this point in time we are not yet able to handle is_hellos
1846 * on lan - Sorry juniper...
1847 */
1848 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
1849 return retval;
1850
1851 neigh_len = stream_getc (circuit->rcv_stream);
hassof390d2c2004-09-10 20:48:21 +00001852 sysid = STREAM_PNT (circuit->rcv_stream) + neigh_len - 1 - ISIS_SYS_ID_LEN;
jardineb5d44e2003-12-23 08:09:43 +00001853 adj = circuit->u.p2p.neighbor;
hassof390d2c2004-09-10 20:48:21 +00001854 if (!adj)
1855 {
1856 /* 8.2.2 */
Paul Jakma41b36e92006-12-08 01:09:50 +00001857 adj = isis_new_adj (sysid, NULL, 0, circuit);
hassof390d2c2004-09-10 20:48:21 +00001858 if (adj == NULL)
1859 return ISIS_ERROR;
jardineb5d44e2003-12-23 08:09:43 +00001860
hassof390d2c2004-09-10 20:48:21 +00001861 isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
1862 adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
1863 circuit->u.p2p.neighbor = adj;
1864 }
1865 /* 8.2.2 a) */
1866 if ((adj->adj_state == ISIS_ADJ_UP) && memcmp (adj->sysid, sysid,
1867 ISIS_SYS_ID_LEN))
1868 {
1869 /* 8.2.2 a) 1) FIXME: adjStateChange(down) event */
1870 /* 8.2.2 a) 2) delete the adj */
1871 XFREE (MTYPE_ISIS_ADJACENCY, adj);
1872 /* 8.2.2 a) 3) create a new adj */
Paul Jakma41b36e92006-12-08 01:09:50 +00001873 adj = isis_new_adj (sysid, NULL, 0, circuit);
hassof390d2c2004-09-10 20:48:21 +00001874 if (adj == NULL)
1875 return ISIS_ERROR;
jardineb5d44e2003-12-23 08:09:43 +00001876
hassof390d2c2004-09-10 20:48:21 +00001877 /* 8.2.2 a) 3) i */
1878 isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
1879 /* 8.2.2 a) 3) ii */
1880 adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
1881 /* 8.2.2 a) 4) quite meaningless */
1882 }
jardineb5d44e2003-12-23 08:09:43 +00001883 /* 8.2.2 b) ignore on condition */
hassof390d2c2004-09-10 20:48:21 +00001884 if ((adj->adj_state == ISIS_ADJ_INITIALIZING) &&
1885 (adj->sys_type == ISIS_SYSTYPE_IS))
1886 {
1887 /* do nothing */
1888 }
1889 else
1890 {
1891 /* 8.2.2 c) respond with a p2p IIH */
1892 send_hello (circuit, 1);
1893 }
jardineb5d44e2003-12-23 08:09:43 +00001894 /* 8.2.2 d) type is IS */
hassof390d2c2004-09-10 20:48:21 +00001895 adj->sys_type = ISIS_SYSTYPE_IS;
jardineb5d44e2003-12-23 08:09:43 +00001896 /* 8.2.2 e) FIXME: Circuit type of? */
1897
jardineb5d44e2003-12-23 08:09:43 +00001898 return retval;
1899}
1900
jardineb5d44e2003-12-23 08:09:43 +00001901/*
1902 * PDU Dispatcher
1903 */
1904
hasso92365882005-01-18 13:53:33 +00001905static int
hassof390d2c2004-09-10 20:48:21 +00001906isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa)
jardineb5d44e2003-12-23 08:09:43 +00001907{
jardineb5d44e2003-12-23 08:09:43 +00001908 struct isis_fixed_hdr *hdr;
jardineb5d44e2003-12-23 08:09:43 +00001909
hassof390d2c2004-09-10 20:48:21 +00001910 int retval = ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00001911
1912 /*
1913 * Let's first read data from stream to the header
1914 */
hassof390d2c2004-09-10 20:48:21 +00001915 hdr = (struct isis_fixed_hdr *) STREAM_DATA (circuit->rcv_stream);
jardineb5d44e2003-12-23 08:09:43 +00001916
hassof390d2c2004-09-10 20:48:21 +00001917 if ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS))
1918 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001919 zlog_err ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp);
hassof390d2c2004-09-10 20:48:21 +00001920 return ISIS_ERROR;
1921 }
jardineb5d44e2003-12-23 08:09:43 +00001922
1923 /* now we need to know if this is an ISO 9542 packet and
1924 * take real good care of it, waaa!
1925 */
hassof390d2c2004-09-10 20:48:21 +00001926 if (hdr->idrp == ISO9542_ESIS)
1927 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001928 zlog_err ("No support for ES-IS packet IDRP=%02x", hdr->idrp);
1929 return ISIS_ERROR;
hassof390d2c2004-09-10 20:48:21 +00001930 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001931 stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN);
1932
jardineb5d44e2003-12-23 08:09:43 +00001933 /*
1934 * and then process it
1935 */
1936
hassof390d2c2004-09-10 20:48:21 +00001937 if (hdr->length < ISIS_MINIMUM_FIXED_HDR_LEN)
1938 {
1939 zlog_err ("Fixed header length = %d", hdr->length);
1940 return ISIS_ERROR;
1941 }
jardineb5d44e2003-12-23 08:09:43 +00001942
hassof390d2c2004-09-10 20:48:21 +00001943 if (hdr->version1 != 1)
1944 {
1945 zlog_warn ("Unsupported ISIS version %u", hdr->version1);
1946 return ISIS_WARNING;
1947 }
jardineb5d44e2003-12-23 08:09:43 +00001948 /* either 6 or 0 */
hassof390d2c2004-09-10 20:48:21 +00001949 if ((hdr->id_len != 0) && (hdr->id_len != ISIS_SYS_ID_LEN))
1950 {
1951 zlog_err
1952 ("IDFieldLengthMismatch: ID Length field in a received PDU %u, "
1953 "while the parameter for this IS is %u", hdr->id_len,
1954 ISIS_SYS_ID_LEN);
1955 return ISIS_ERROR;
1956 }
jardineb5d44e2003-12-23 08:09:43 +00001957
hassof390d2c2004-09-10 20:48:21 +00001958 if (hdr->version2 != 1)
1959 {
1960 zlog_warn ("Unsupported ISIS version %u", hdr->version2);
1961 return ISIS_WARNING;
1962 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001963
1964 if (circuit->is_passive)
1965 {
1966 zlog_warn ("Received ISIS PDU on passive circuit %s",
1967 circuit->interface->name);
1968 return ISIS_WARNING;
1969 }
1970
jardineb5d44e2003-12-23 08:09:43 +00001971 /* either 3 or 0 */
hassof390d2c2004-09-10 20:48:21 +00001972 if ((hdr->max_area_addrs != 0)
1973 && (hdr->max_area_addrs != isis->max_area_addrs))
1974 {
1975 zlog_err ("maximumAreaAddressesMismatch: maximumAreaAdresses in a "
1976 "received PDU %u while the parameter for this IS is %u",
1977 hdr->max_area_addrs, isis->max_area_addrs);
1978 return ISIS_ERROR;
1979 }
jardineb5d44e2003-12-23 08:09:43 +00001980
hassof390d2c2004-09-10 20:48:21 +00001981 switch (hdr->pdu_type)
1982 {
1983 case L1_LAN_HELLO:
1984 retval = process_lan_hello (ISIS_LEVEL1, circuit, ssnpa);
1985 break;
1986 case L2_LAN_HELLO:
1987 retval = process_lan_hello (ISIS_LEVEL2, circuit, ssnpa);
1988 break;
1989 case P2P_HELLO:
1990 retval = process_p2p_hello (circuit);
1991 break;
1992 case L1_LINK_STATE:
1993 retval = process_lsp (ISIS_LEVEL1, circuit, ssnpa);
1994 break;
1995 case L2_LINK_STATE:
1996 retval = process_lsp (ISIS_LEVEL2, circuit, ssnpa);
1997 break;
1998 case L1_COMPLETE_SEQ_NUM:
1999 retval = process_csnp (ISIS_LEVEL1, circuit, ssnpa);
2000 break;
2001 case L2_COMPLETE_SEQ_NUM:
2002 retval = process_csnp (ISIS_LEVEL2, circuit, ssnpa);
2003 break;
2004 case L1_PARTIAL_SEQ_NUM:
2005 retval = process_psnp (ISIS_LEVEL1, circuit, ssnpa);
2006 break;
2007 case L2_PARTIAL_SEQ_NUM:
2008 retval = process_psnp (ISIS_LEVEL2, circuit, ssnpa);
2009 break;
2010 default:
2011 return ISIS_ERROR;
2012 }
jardineb5d44e2003-12-23 08:09:43 +00002013
2014 return retval;
2015}
2016
jardineb5d44e2003-12-23 08:09:43 +00002017#ifdef GNU_LINUX
2018int
2019isis_receive (struct thread *thread)
2020{
jardineb5d44e2003-12-23 08:09:43 +00002021 struct isis_circuit *circuit;
2022 u_char ssnpa[ETH_ALEN];
2023 int retval;
2024
2025 /*
2026 * Get the circuit
2027 */
2028 circuit = THREAD_ARG (thread);
2029 assert (circuit);
2030
2031 if (circuit->rcv_stream == NULL)
hassof390d2c2004-09-10 20:48:21 +00002032 circuit->rcv_stream = stream_new (ISO_MTU (circuit));
jardineb5d44e2003-12-23 08:09:43 +00002033 else
2034 stream_reset (circuit->rcv_stream);
2035
2036 retval = circuit->rx (circuit, ssnpa);
hassof390d2c2004-09-10 20:48:21 +00002037 circuit->t_read = NULL;
jardineb5d44e2003-12-23 08:09:43 +00002038
2039 if (retval == ISIS_OK)
2040 retval = isis_handle_pdu (circuit, ssnpa);
2041
2042 /*
2043 * prepare for next packet.
2044 */
Josh Bailey3f045a02012-03-24 08:35:20 -07002045 if (!circuit->is_passive)
2046 {
2047 THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit,
2048 circuit->fd);
2049 }
jardineb5d44e2003-12-23 08:09:43 +00002050
2051 return retval;
2052}
2053
2054#else
2055int
2056isis_receive (struct thread *thread)
2057{
jardineb5d44e2003-12-23 08:09:43 +00002058 struct isis_circuit *circuit;
2059 u_char ssnpa[ETH_ALEN];
2060 int retval;
2061
2062 /*
2063 * Get the circuit
2064 */
2065 circuit = THREAD_ARG (thread);
2066 assert (circuit);
2067
hassof390d2c2004-09-10 20:48:21 +00002068 circuit->t_read = NULL;
jardineb5d44e2003-12-23 08:09:43 +00002069
2070 if (circuit->rcv_stream == NULL)
hassof390d2c2004-09-10 20:48:21 +00002071 circuit->rcv_stream = stream_new (ISO_MTU (circuit));
jardineb5d44e2003-12-23 08:09:43 +00002072 else
2073 stream_reset (circuit->rcv_stream);
2074
2075 retval = circuit->rx (circuit, ssnpa);
2076
2077 if (retval == ISIS_OK)
2078 retval = isis_handle_pdu (circuit, ssnpa);
2079
2080 /*
2081 * prepare for next packet.
2082 */
Josh Bailey3f045a02012-03-24 08:35:20 -07002083 if (!circuit->is_passive)
2084 {
2085 circuit->t_read = thread_add_timer_msec (master, isis_receive, circuit,
2086 listcount
2087 (circuit->area->circuit_list) *
2088 100);
2089 }
jardineb5d44e2003-12-23 08:09:43 +00002090
2091 return retval;
2092}
2093
2094#endif
2095
2096 /* filling of the fixed isis header */
2097void
2098fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type)
2099{
2100 memset (hdr, 0, sizeof (struct isis_fixed_hdr));
2101
2102 hdr->idrp = ISO10589_ISIS;
2103
hassof390d2c2004-09-10 20:48:21 +00002104 switch (pdu_type)
2105 {
2106 case L1_LAN_HELLO:
2107 case L2_LAN_HELLO:
2108 hdr->length = ISIS_LANHELLO_HDRLEN;
2109 break;
2110 case P2P_HELLO:
2111 hdr->length = ISIS_P2PHELLO_HDRLEN;
2112 break;
2113 case L1_LINK_STATE:
2114 case L2_LINK_STATE:
2115 hdr->length = ISIS_LSP_HDR_LEN;
2116 break;
2117 case L1_COMPLETE_SEQ_NUM:
2118 case L2_COMPLETE_SEQ_NUM:
2119 hdr->length = ISIS_CSNP_HDRLEN;
2120 break;
2121 case L1_PARTIAL_SEQ_NUM:
2122 case L2_PARTIAL_SEQ_NUM:
2123 hdr->length = ISIS_PSNP_HDRLEN;
2124 break;
2125 default:
2126 zlog_warn ("fill_fixed_hdr(): unknown pdu type %d", pdu_type);
2127 return;
2128 }
jardineb5d44e2003-12-23 08:09:43 +00002129 hdr->length += ISIS_FIXED_HDR_LEN;
2130 hdr->pdu_type = pdu_type;
2131 hdr->version1 = 1;
hassof390d2c2004-09-10 20:48:21 +00002132 hdr->id_len = 0; /* ISIS_SYS_ID_LEN - 0==6 */
jardineb5d44e2003-12-23 08:09:43 +00002133 hdr->version2 = 1;
hassof390d2c2004-09-10 20:48:21 +00002134 hdr->max_area_addrs = 0; /* isis->max_area_addrs - 0==3 */
jardineb5d44e2003-12-23 08:09:43 +00002135}
2136
jardineb5d44e2003-12-23 08:09:43 +00002137/*
2138 * SEND SIDE
2139 */
hasso92365882005-01-18 13:53:33 +00002140static void
jardineb5d44e2003-12-23 08:09:43 +00002141fill_fixed_hdr_andstream (struct isis_fixed_hdr *hdr, u_char pdu_type,
hassof390d2c2004-09-10 20:48:21 +00002142 struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +00002143{
hassof390d2c2004-09-10 20:48:21 +00002144 fill_fixed_hdr (hdr, pdu_type);
jardineb5d44e2003-12-23 08:09:43 +00002145
2146 stream_putc (stream, hdr->idrp);
2147 stream_putc (stream, hdr->length);
2148 stream_putc (stream, hdr->version1);
2149 stream_putc (stream, hdr->id_len);
2150 stream_putc (stream, hdr->pdu_type);
2151 stream_putc (stream, hdr->version2);
2152 stream_putc (stream, hdr->reserved);
2153 stream_putc (stream, hdr->max_area_addrs);
2154
2155 return;
2156}
2157
jardineb5d44e2003-12-23 08:09:43 +00002158int
2159send_hello (struct isis_circuit *circuit, int level)
2160{
2161 struct isis_fixed_hdr fixed_hdr;
2162 struct isis_lan_hello_hdr hello_hdr;
2163 struct isis_p2p_hello_hdr p2p_hello_hdr;
Josh Bailey3f045a02012-03-24 08:35:20 -07002164 unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
2165 unsigned long len_pointer, length, auth_tlv_offset = 0;
jardineb5d44e2003-12-23 08:09:43 +00002166 u_int32_t interval;
jardineb5d44e2003-12-23 08:09:43 +00002167 int retval;
2168
Josh Bailey3f045a02012-03-24 08:35:20 -07002169 if (circuit->is_passive)
2170 return ISIS_OK;
2171
hassof390d2c2004-09-10 20:48:21 +00002172 if (circuit->interface->mtu == 0)
2173 {
2174 zlog_warn ("circuit has zero MTU");
2175 return ISIS_WARNING;
2176 }
jardineb5d44e2003-12-23 08:09:43 +00002177
2178 if (!circuit->snd_stream)
hassof390d2c2004-09-10 20:48:21 +00002179 circuit->snd_stream = stream_new (ISO_MTU (circuit));
jardineb5d44e2003-12-23 08:09:43 +00002180 else
2181 stream_reset (circuit->snd_stream);
2182
2183 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
Josh Bailey3f045a02012-03-24 08:35:20 -07002184 if (level == IS_LEVEL_1)
hassof390d2c2004-09-10 20:48:21 +00002185 fill_fixed_hdr_andstream (&fixed_hdr, L1_LAN_HELLO,
2186 circuit->snd_stream);
jardineb5d44e2003-12-23 08:09:43 +00002187 else
hassof390d2c2004-09-10 20:48:21 +00002188 fill_fixed_hdr_andstream (&fixed_hdr, L2_LAN_HELLO,
2189 circuit->snd_stream);
jardineb5d44e2003-12-23 08:09:43 +00002190 else
hassof390d2c2004-09-10 20:48:21 +00002191 fill_fixed_hdr_andstream (&fixed_hdr, P2P_HELLO, circuit->snd_stream);
jardineb5d44e2003-12-23 08:09:43 +00002192
2193 /*
2194 * Fill LAN Level 1 or 2 Hello PDU header
2195 */
2196 memset (&hello_hdr, 0, sizeof (struct isis_lan_hello_hdr));
hassof390d2c2004-09-10 20:48:21 +00002197 interval = circuit->hello_multiplier[level - 1] *
jardineb5d44e2003-12-23 08:09:43 +00002198 circuit->hello_interval[level - 1];
2199 if (interval > USHRT_MAX)
2200 interval = USHRT_MAX;
Josh Bailey3f045a02012-03-24 08:35:20 -07002201 hello_hdr.circuit_t = circuit->is_type;
jardineb5d44e2003-12-23 08:09:43 +00002202 memcpy (hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN);
hassof390d2c2004-09-10 20:48:21 +00002203 hello_hdr.hold_time = htons ((u_int16_t) interval);
jardineb5d44e2003-12-23 08:09:43 +00002204
hassof390d2c2004-09-10 20:48:21 +00002205 hello_hdr.pdu_len = 0; /* Update the PDU Length later */
paul9985f832005-02-09 15:51:56 +00002206 len_pointer = stream_get_endp (circuit->snd_stream) + 3 + ISIS_SYS_ID_LEN;
jardineb5d44e2003-12-23 08:09:43 +00002207
2208 /* copy the shared part of the hello to the p2p hello if needed */
hassof390d2c2004-09-10 20:48:21 +00002209 if (circuit->circ_type == CIRCUIT_T_P2P)
2210 {
2211 memcpy (&p2p_hello_hdr, &hello_hdr, 5 + ISIS_SYS_ID_LEN);
2212 p2p_hello_hdr.local_id = circuit->circuit_id;
2213 /* FIXME: need better understanding */
2214 stream_put (circuit->snd_stream, &p2p_hello_hdr, ISIS_P2PHELLO_HDRLEN);
jardineb5d44e2003-12-23 08:09:43 +00002215 }
hassof390d2c2004-09-10 20:48:21 +00002216 else
2217 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002218 hello_hdr.prio = circuit->priority[level - 1];
2219 if (level == IS_LEVEL_1)
hassof390d2c2004-09-10 20:48:21 +00002220 {
2221 memcpy (hello_hdr.lan_id, circuit->u.bc.l1_desig_is,
2222 ISIS_SYS_ID_LEN + 1);
2223 }
Josh Bailey3f045a02012-03-24 08:35:20 -07002224 else if (level == IS_LEVEL_2)
hassof390d2c2004-09-10 20:48:21 +00002225 {
2226 memcpy (hello_hdr.lan_id, circuit->u.bc.l2_desig_is,
2227 ISIS_SYS_ID_LEN + 1);
2228 }
2229 stream_put (circuit->snd_stream, &hello_hdr, ISIS_LANHELLO_HDRLEN);
2230 }
jardineb5d44e2003-12-23 08:09:43 +00002231
2232 /*
Josh Bailey3f045a02012-03-24 08:35:20 -07002233 * Then the variable length part.
jardineb5d44e2003-12-23 08:09:43 +00002234 */
Josh Bailey3f045a02012-03-24 08:35:20 -07002235
jardineb5d44e2003-12-23 08:09:43 +00002236 /* add circuit password */
Josh Bailey3f045a02012-03-24 08:35:20 -07002237 switch (circuit->passwd.type)
2238 {
2239 /* Cleartext */
2240 case ISIS_PASSWD_TYPE_CLEARTXT:
2241 if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len,
2242 circuit->passwd.passwd, circuit->snd_stream))
2243 return ISIS_WARNING;
2244 break;
2245
2246 /* HMAC MD5 */
2247 case ISIS_PASSWD_TYPE_HMAC_MD5:
2248 /* Remember where TLV is written so we can later overwrite the MD5 hash */
2249 auth_tlv_offset = stream_get_endp (circuit->snd_stream);
2250 memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
2251 if (tlv_add_authinfo (circuit->passwd.type, ISIS_AUTH_MD5_SIZE,
2252 hmac_md5_hash, circuit->snd_stream))
2253 return ISIS_WARNING;
2254 break;
2255
2256 default:
2257 break;
2258 }
2259
jardineb5d44e2003-12-23 08:09:43 +00002260 /* Area Addresses TLV */
Josh Bailey3f045a02012-03-24 08:35:20 -07002261 if (listcount (circuit->area->area_addrs) == 0)
2262 return ISIS_WARNING;
2263 if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream))
2264 return ISIS_WARNING;
jardineb5d44e2003-12-23 08:09:43 +00002265
2266 /* LAN Neighbors TLV */
hassof390d2c2004-09-10 20:48:21 +00002267 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
2268 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002269 if (level == IS_LEVEL_1 && circuit->u.bc.lan_neighs[0] &&
2270 listcount (circuit->u.bc.lan_neighs[0]) > 0)
hassof390d2c2004-09-10 20:48:21 +00002271 if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0],
2272 circuit->snd_stream))
2273 return ISIS_WARNING;
Josh Bailey3f045a02012-03-24 08:35:20 -07002274 if (level == IS_LEVEL_2 && circuit->u.bc.lan_neighs[1] &&
2275 listcount (circuit->u.bc.lan_neighs[1]) > 0)
hassof390d2c2004-09-10 20:48:21 +00002276 if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1],
2277 circuit->snd_stream))
2278 return ISIS_WARNING;
2279 }
jardineb5d44e2003-12-23 08:09:43 +00002280
2281 /* Protocols Supported TLV */
hassof390d2c2004-09-10 20:48:21 +00002282 if (circuit->nlpids.count > 0)
jardineb5d44e2003-12-23 08:09:43 +00002283 if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream))
2284 return ISIS_WARNING;
2285 /* IP interface Address TLV */
Josh Bailey3f045a02012-03-24 08:35:20 -07002286 if (circuit->ip_router && circuit->ip_addrs &&
2287 listcount (circuit->ip_addrs) > 0)
jardineb5d44e2003-12-23 08:09:43 +00002288 if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream))
2289 return ISIS_WARNING;
2290
hassof390d2c2004-09-10 20:48:21 +00002291#ifdef HAVE_IPV6
jardineb5d44e2003-12-23 08:09:43 +00002292 /* IPv6 Interface Address TLV */
hassof390d2c2004-09-10 20:48:21 +00002293 if (circuit->ipv6_router && circuit->ipv6_link &&
Josh Bailey3f045a02012-03-24 08:35:20 -07002294 listcount (circuit->ipv6_link) > 0)
jardineb5d44e2003-12-23 08:09:43 +00002295 if (tlv_add_ipv6_addrs (circuit->ipv6_link, circuit->snd_stream))
2296 return ISIS_WARNING;
2297#endif /* HAVE_IPV6 */
2298
Josh Bailey3f045a02012-03-24 08:35:20 -07002299 if (circuit->pad_hellos)
jardineb5d44e2003-12-23 08:09:43 +00002300 if (tlv_add_padding (circuit->snd_stream))
2301 return ISIS_WARNING;
2302
paul9985f832005-02-09 15:51:56 +00002303 length = stream_get_endp (circuit->snd_stream);
jardineb5d44e2003-12-23 08:09:43 +00002304 /* Update PDU length */
hassof390d2c2004-09-10 20:48:21 +00002305 stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t) length);
jardineb5d44e2003-12-23 08:09:43 +00002306
Josh Bailey3f045a02012-03-24 08:35:20 -07002307 /* For HMAC MD5 we need to compute the md5 hash and store it */
2308 if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
2309 {
2310 hmac_md5 (STREAM_DATA (circuit->snd_stream),
2311 stream_get_endp (circuit->snd_stream),
2312 (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len,
2313 (caddr_t) &hmac_md5_hash);
2314 /* Copy the hash into the stream */
2315 memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
2316 hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
2317 }
jardineb5d44e2003-12-23 08:09:43 +00002318
hassof390d2c2004-09-10 20:48:21 +00002319 if (isis->debugs & DEBUG_ADJ_PACKETS)
2320 {
2321 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
2322 {
hasso529d65b2004-12-24 00:14:50 +00002323 zlog_debug ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %ld",
2324 circuit->area->area_tag, level, circuit->interface->name,
hasso29e50b22005-09-01 18:18:47 +00002325 /* FIXME: use %z when we stop supporting old compilers. */
Josh Bailey3f045a02012-03-24 08:35:20 -07002326 length);
hassof390d2c2004-09-10 20:48:21 +00002327 }
2328 else
2329 {
hasso529d65b2004-12-24 00:14:50 +00002330 zlog_debug ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld",
2331 circuit->area->area_tag, circuit->interface->name,
hasso29e50b22005-09-01 18:18:47 +00002332 /* FIXME: use %z when we stop supporting old compilers. */
Josh Bailey3f045a02012-03-24 08:35:20 -07002333 length);
hassof390d2c2004-09-10 20:48:21 +00002334 }
Josh Bailey3f045a02012-03-24 08:35:20 -07002335 if (isis->debugs & DEBUG_PACKET_DUMP)
2336 zlog_dump_data (STREAM_DATA (circuit->snd_stream),
2337 stream_get_endp (circuit->snd_stream));
jardineb5d44e2003-12-23 08:09:43 +00002338 }
jardineb5d44e2003-12-23 08:09:43 +00002339
Josh Bailey3f045a02012-03-24 08:35:20 -07002340 retval = circuit->tx (circuit, level);
2341 if (retval != ISIS_OK)
2342 zlog_err ("ISIS-Adj (%s): Send L%d IIH on %s failed",
2343 circuit->area->area_tag, level, circuit->interface->name);
jardineb5d44e2003-12-23 08:09:43 +00002344
Josh Bailey3f045a02012-03-24 08:35:20 -07002345 return retval;
jardineb5d44e2003-12-23 08:09:43 +00002346}
2347
2348int
2349send_lan_l1_hello (struct thread *thread)
2350{
jardineb5d44e2003-12-23 08:09:43 +00002351 struct isis_circuit *circuit;
2352 int retval;
2353
2354 circuit = THREAD_ARG (thread);
2355 assert (circuit);
2356 circuit->u.bc.t_send_lan_hello[0] = NULL;
2357
2358 if (circuit->u.bc.run_dr_elect[0])
hassof390d2c2004-09-10 20:48:21 +00002359 retval = isis_dr_elect (circuit, 1);
jardineb5d44e2003-12-23 08:09:43 +00002360
Josh Bailey3f045a02012-03-24 08:35:20 -07002361 retval = send_hello (circuit, 1);
jardineb5d44e2003-12-23 08:09:43 +00002362
2363 /* set next timer thread */
hassof390d2c2004-09-10 20:48:21 +00002364 THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0],
2365 send_lan_l1_hello, circuit,
2366 isis_jitter (circuit->hello_interval[0], IIH_JITTER));
jardineb5d44e2003-12-23 08:09:43 +00002367
2368 return retval;
2369}
2370
2371int
2372send_lan_l2_hello (struct thread *thread)
2373{
2374 struct isis_circuit *circuit;
2375 int retval;
2376
2377 circuit = THREAD_ARG (thread);
2378 assert (circuit);
2379 circuit->u.bc.t_send_lan_hello[1] = NULL;
2380
2381 if (circuit->u.bc.run_dr_elect[1])
2382 retval = isis_dr_elect (circuit, 2);
2383
Josh Bailey3f045a02012-03-24 08:35:20 -07002384 retval = send_hello (circuit, 2);
jardineb5d44e2003-12-23 08:09:43 +00002385
hassof390d2c2004-09-10 20:48:21 +00002386 /* set next timer thread */
2387 THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[1],
2388 send_lan_l2_hello, circuit,
2389 isis_jitter (circuit->hello_interval[1], IIH_JITTER));
jardineb5d44e2003-12-23 08:09:43 +00002390
2391 return retval;
2392}
2393
2394int
2395send_p2p_hello (struct thread *thread)
2396{
2397 struct isis_circuit *circuit;
2398
2399 circuit = THREAD_ARG (thread);
2400 assert (circuit);
2401 circuit->u.p2p.t_send_p2p_hello = NULL;
2402
hassof390d2c2004-09-10 20:48:21 +00002403 send_hello (circuit, 1);
jardineb5d44e2003-12-23 08:09:43 +00002404
hassof390d2c2004-09-10 20:48:21 +00002405 /* set next timer thread */
2406 THREAD_TIMER_ON (master, circuit->u.p2p.t_send_p2p_hello, send_p2p_hello,
2407 circuit, isis_jitter (circuit->hello_interval[1],
2408 IIH_JITTER));
jardineb5d44e2003-12-23 08:09:43 +00002409
2410 return ISIS_OK;
2411}
2412
hasso92365882005-01-18 13:53:33 +00002413static int
hassof390d2c2004-09-10 20:48:21 +00002414build_csnp (int level, u_char * start, u_char * stop, struct list *lsps,
2415 struct isis_circuit *circuit)
jardineb5d44e2003-12-23 08:09:43 +00002416{
2417 struct isis_fixed_hdr fixed_hdr;
2418 struct isis_passwd *passwd;
jardineb5d44e2003-12-23 08:09:43 +00002419 unsigned long lenp;
2420 u_int16_t length;
Josh Bailey3f045a02012-03-24 08:35:20 -07002421 unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
2422 unsigned long auth_tlv_offset = 0;
2423 int retval = ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00002424
Josh Bailey3f045a02012-03-24 08:35:20 -07002425 if (circuit->snd_stream == NULL)
2426 circuit->snd_stream = stream_new (ISO_MTU (circuit));
2427 else
2428 stream_reset (circuit->snd_stream);
2429
2430 if (level == IS_LEVEL_1)
hassof390d2c2004-09-10 20:48:21 +00002431 fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM,
2432 circuit->snd_stream);
jardineb5d44e2003-12-23 08:09:43 +00002433 else
hassof390d2c2004-09-10 20:48:21 +00002434 fill_fixed_hdr_andstream (&fixed_hdr, L2_COMPLETE_SEQ_NUM,
2435 circuit->snd_stream);
jardineb5d44e2003-12-23 08:09:43 +00002436
2437 /*
2438 * Fill Level 1 or 2 Complete Sequence Numbers header
2439 */
2440
paul9985f832005-02-09 15:51:56 +00002441 lenp = stream_get_endp (circuit->snd_stream);
hassof390d2c2004-09-10 20:48:21 +00002442 stream_putw (circuit->snd_stream, 0); /* PDU length - when we know it */
jardineb5d44e2003-12-23 08:09:43 +00002443 /* no need to send the source here, it is always us if we csnp */
2444 stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
2445 /* with zero circuit id - ref 9.10, 9.11 */
2446 stream_putc (circuit->snd_stream, 0x00);
2447
2448 stream_put (circuit->snd_stream, start, ISIS_SYS_ID_LEN + 2);
2449 stream_put (circuit->snd_stream, stop, ISIS_SYS_ID_LEN + 2);
2450
2451 /*
2452 * And TLVs
2453 */
Josh Bailey3f045a02012-03-24 08:35:20 -07002454 if (level == IS_LEVEL_1)
jardineb5d44e2003-12-23 08:09:43 +00002455 passwd = &circuit->area->area_passwd;
2456 else
2457 passwd = &circuit->area->domain_passwd;
2458
hasso1cbc5622005-01-01 10:29:51 +00002459 if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
Josh Bailey3f045a02012-03-24 08:35:20 -07002460 {
2461 switch (passwd->type)
hassof390d2c2004-09-10 20:48:21 +00002462 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002463 /* Cleartext */
2464 case ISIS_PASSWD_TYPE_CLEARTXT:
2465 if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len,
2466 passwd->passwd, circuit->snd_stream))
2467 return ISIS_WARNING;
2468 break;
2469
2470 /* HMAC MD5 */
2471 case ISIS_PASSWD_TYPE_HMAC_MD5:
2472 /* Remember where TLV is written so we can later overwrite the MD5 hash */
2473 auth_tlv_offset = stream_get_endp (circuit->snd_stream);
2474 memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
2475 if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE,
2476 hmac_md5_hash, circuit->snd_stream))
2477 return ISIS_WARNING;
2478 break;
2479
2480 default:
2481 break;
hassof390d2c2004-09-10 20:48:21 +00002482 }
Josh Bailey3f045a02012-03-24 08:35:20 -07002483 }
2484
2485 retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
2486 if (retval != ISIS_OK)
2487 return retval;
2488
paul9985f832005-02-09 15:51:56 +00002489 length = (u_int16_t) stream_get_endp (circuit->snd_stream);
jardineb5d44e2003-12-23 08:09:43 +00002490 /* Update PU length */
2491 stream_putw_at (circuit->snd_stream, lenp, length);
2492
Josh Bailey3f045a02012-03-24 08:35:20 -07002493 /* For HMAC MD5 we need to compute the md5 hash and store it */
2494 if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) &&
2495 passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5)
2496 {
2497 hmac_md5 (STREAM_DATA (circuit->snd_stream),
2498 stream_get_endp(circuit->snd_stream),
2499 (unsigned char *) &passwd->passwd, passwd->len,
2500 (caddr_t) &hmac_md5_hash);
2501 /* Copy the hash into the stream */
2502 memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
2503 hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
2504 }
2505
jardineb5d44e2003-12-23 08:09:43 +00002506 return retval;
2507}
2508
2509/*
Josh Bailey3f045a02012-03-24 08:35:20 -07002510 * Count the maximum number of lsps that can be accomodated by a given size.
2511 */
2512static uint16_t
2513get_max_lsp_count (uint16_t size)
2514{
2515 uint16_t tlv_count;
2516 uint16_t lsp_count;
2517 uint16_t remaining_size;
2518
2519 /* First count the full size TLVs */
2520 tlv_count = size / MAX_LSP_ENTRIES_TLV_SIZE;
2521 lsp_count = tlv_count * (MAX_LSP_ENTRIES_TLV_SIZE / LSP_ENTRIES_LEN);
2522
2523 /* The last TLV, if any */
2524 remaining_size = size % MAX_LSP_ENTRIES_TLV_SIZE;
2525 if (remaining_size - 2 >= LSP_ENTRIES_LEN)
2526 lsp_count += (remaining_size - 2) / LSP_ENTRIES_LEN;
2527
2528 return lsp_count;
2529}
2530
2531/*
2532 * Calculate the length of Authentication Info. TLV.
2533 */
2534static uint16_t
2535auth_tlv_length (int level, struct isis_circuit *circuit)
2536{
2537 struct isis_passwd *passwd;
2538 uint16_t length;
2539
2540 if (level == IS_LEVEL_1)
2541 passwd = &circuit->area->area_passwd;
2542 else
2543 passwd = &circuit->area->domain_passwd;
2544
2545 /* Also include the length of TLV header */
2546 length = AUTH_INFO_HDRLEN;
2547 if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
2548 {
2549 switch (passwd->type)
2550 {
2551 /* Cleartext */
2552 case ISIS_PASSWD_TYPE_CLEARTXT:
2553 length += passwd->len;
2554 break;
2555
2556 /* HMAC MD5 */
2557 case ISIS_PASSWD_TYPE_HMAC_MD5:
2558 length += ISIS_AUTH_MD5_SIZE;
2559 break;
2560
2561 default:
2562 break;
2563 }
2564 }
2565
2566 return length;
2567}
2568
2569/*
2570 * Calculate the maximum number of lsps that can be accomodated in a CSNP/PSNP.
2571 */
2572static uint16_t
2573max_lsps_per_snp (int snp_type, int level, struct isis_circuit *circuit)
2574{
2575 int snp_hdr_len;
2576 int auth_tlv_len;
2577 uint16_t lsp_count;
2578
2579 snp_hdr_len = ISIS_FIXED_HDR_LEN;
2580 if (snp_type == ISIS_SNP_CSNP_FLAG)
2581 snp_hdr_len += ISIS_CSNP_HDRLEN;
2582 else
2583 snp_hdr_len += ISIS_PSNP_HDRLEN;
2584
2585 auth_tlv_len = auth_tlv_length (level, circuit);
2586 lsp_count = get_max_lsp_count (
2587 stream_get_size (circuit->snd_stream) - snp_hdr_len - auth_tlv_len);
2588}
2589
2590/*
jardineb5d44e2003-12-23 08:09:43 +00002591 * FIXME: support multiple CSNPs
2592 */
2593
2594int
2595send_csnp (struct isis_circuit *circuit, int level)
2596{
jardineb5d44e2003-12-23 08:09:43 +00002597 u_char start[ISIS_SYS_ID_LEN + 2];
2598 u_char stop[ISIS_SYS_ID_LEN + 2];
2599 struct list *list = NULL;
hasso3fdb2dd2005-09-28 18:45:54 +00002600 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00002601 struct isis_lsp *lsp;
Josh Bailey3f045a02012-03-24 08:35:20 -07002602 u_char num_lsps, loop = 1;
2603 int i, retval = ISIS_OK;
2604
2605 if (circuit->area->lspdb[level - 1] == NULL ||
2606 dict_count (circuit->area->lspdb[level - 1]) == 0)
2607 return retval;
jardineb5d44e2003-12-23 08:09:43 +00002608
hassof390d2c2004-09-10 20:48:21 +00002609 memset (start, 0x00, ISIS_SYS_ID_LEN + 2);
jardineb5d44e2003-12-23 08:09:43 +00002610 memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
2611
Josh Bailey3f045a02012-03-24 08:35:20 -07002612 num_lsps = max_lsps_per_snp (ISIS_SNP_CSNP_FLAG, level, circuit);
2613
2614 while (loop)
hassof390d2c2004-09-10 20:48:21 +00002615 {
2616 list = list_new ();
Josh Bailey3f045a02012-03-24 08:35:20 -07002617 lsp_build_list (start, stop, num_lsps, list,
2618 circuit->area->lspdb[level - 1]);
2619 /*
2620 * Update the stop lsp_id before encoding this CSNP.
2621 */
2622 if (listcount (list) < num_lsps)
2623 {
2624 memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
2625 }
hassof390d2c2004-09-10 20:48:21 +00002626 else
Josh Bailey3f045a02012-03-24 08:35:20 -07002627 {
2628 node = listtail (list);
2629 lsp = listgetdata (node);
2630 memcpy (stop, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
2631 }
jardineb5d44e2003-12-23 08:09:43 +00002632
hassof390d2c2004-09-10 20:48:21 +00002633 retval = build_csnp (level, start, stop, list, circuit);
Josh Bailey3f045a02012-03-24 08:35:20 -07002634 if (retval != ISIS_OK)
2635 {
2636 zlog_err ("ISIS-Snp (%s): Build L%d CSNP on %s failed",
2637 circuit->area->area_tag, level, circuit->interface->name);
2638 list_delete (list);
2639 return retval;
2640 }
jardineb5d44e2003-12-23 08:09:43 +00002641
hassof390d2c2004-09-10 20:48:21 +00002642 if (isis->debugs & DEBUG_SNP_PACKETS)
Josh Bailey3f045a02012-03-24 08:35:20 -07002643 {
2644 zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld",
2645 circuit->area->area_tag, level, circuit->interface->name,
2646 stream_get_endp (circuit->snd_stream));
2647 for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
2648 {
2649 zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x,"
2650 " cksum 0x%04x, lifetime %us",
2651 circuit->area->area_tag,
2652 rawlspid_print (lsp->lsp_header->lsp_id),
2653 ntohl (lsp->lsp_header->seq_num),
2654 ntohs (lsp->lsp_header->checksum),
2655 ntohs (lsp->lsp_header->rem_lifetime));
2656 }
2657 if (isis->debugs & DEBUG_PACKET_DUMP)
2658 zlog_dump_data (STREAM_DATA (circuit->snd_stream),
2659 stream_get_endp (circuit->snd_stream));
2660 }
hassof390d2c2004-09-10 20:48:21 +00002661
Josh Bailey3f045a02012-03-24 08:35:20 -07002662 retval = circuit->tx (circuit, level);
2663 if (retval != ISIS_OK)
2664 {
2665 zlog_err ("ISIS-Snp (%s): Send L%d CSNP on %s failed",
2666 circuit->area->area_tag, level,
2667 circuit->interface->name);
2668 list_delete (list);
2669 return retval;
2670 }
2671
2672 /*
2673 * Start lsp_id of the next CSNP should be one plus the
2674 * stop lsp_id in this current CSNP.
2675 */
2676 memcpy (start, stop, ISIS_SYS_ID_LEN + 2);
2677 loop = 0;
2678 for (i = ISIS_SYS_ID_LEN + 1; i >= 0; --i)
2679 {
2680 if (start[i] < (u_char)0xff)
2681 {
2682 start[i] += 1;
2683 loop = 1;
2684 break;
2685 }
2686 }
2687 memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
hassof390d2c2004-09-10 20:48:21 +00002688 list_delete (list);
jardineb5d44e2003-12-23 08:09:43 +00002689 }
Josh Bailey3f045a02012-03-24 08:35:20 -07002690
jardineb5d44e2003-12-23 08:09:43 +00002691 return retval;
2692}
2693
2694int
2695send_l1_csnp (struct thread *thread)
2696{
2697 struct isis_circuit *circuit;
2698 int retval = ISIS_OK;
2699
2700 circuit = THREAD_ARG (thread);
2701 assert (circuit);
2702
2703 circuit->t_send_csnp[0] = NULL;
2704
hassof390d2c2004-09-10 20:48:21 +00002705 if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[0])
2706 {
2707 send_csnp (circuit, 1);
2708 }
jardineb5d44e2003-12-23 08:09:43 +00002709 /* set next timer thread */
hassof390d2c2004-09-10 20:48:21 +00002710 THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit,
2711 isis_jitter (circuit->csnp_interval[0], CSNP_JITTER));
jardineb5d44e2003-12-23 08:09:43 +00002712
2713 return retval;
2714}
2715
2716int
2717send_l2_csnp (struct thread *thread)
2718{
2719 struct isis_circuit *circuit;
2720 int retval = ISIS_OK;
2721
2722 circuit = THREAD_ARG (thread);
2723 assert (circuit);
2724
2725 circuit->t_send_csnp[1] = NULL;
2726
hassof390d2c2004-09-10 20:48:21 +00002727 if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[1])
2728 {
2729 send_csnp (circuit, 2);
2730 }
jardineb5d44e2003-12-23 08:09:43 +00002731 /* set next timer thread */
hassof390d2c2004-09-10 20:48:21 +00002732 THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit,
2733 isis_jitter (circuit->csnp_interval[1], CSNP_JITTER));
hassod70f99e2004-02-11 20:26:31 +00002734
jardineb5d44e2003-12-23 08:09:43 +00002735 return retval;
2736}
2737
hasso92365882005-01-18 13:53:33 +00002738static int
jardineb5d44e2003-12-23 08:09:43 +00002739build_psnp (int level, struct isis_circuit *circuit, struct list *lsps)
2740{
2741 struct isis_fixed_hdr fixed_hdr;
2742 unsigned long lenp;
2743 u_int16_t length;
jardineb5d44e2003-12-23 08:09:43 +00002744 struct isis_lsp *lsp;
2745 struct isis_passwd *passwd;
hasso3fdb2dd2005-09-28 18:45:54 +00002746 struct listnode *node;
Josh Bailey3f045a02012-03-24 08:35:20 -07002747 unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
2748 unsigned long auth_tlv_offset = 0;
2749 int retval = ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00002750
Josh Bailey3f045a02012-03-24 08:35:20 -07002751 if (circuit->snd_stream == NULL)
2752 circuit->snd_stream = stream_new (ISO_MTU (circuit));
2753 else
2754 stream_reset (circuit->snd_stream);
2755
2756 if (level == IS_LEVEL_1)
hassof390d2c2004-09-10 20:48:21 +00002757 fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
2758 circuit->snd_stream);
jardineb5d44e2003-12-23 08:09:43 +00002759 else
2760 fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM,
hassof390d2c2004-09-10 20:48:21 +00002761 circuit->snd_stream);
jardineb5d44e2003-12-23 08:09:43 +00002762
2763 /*
2764 * Fill Level 1 or 2 Partial Sequence Numbers header
2765 */
paul9985f832005-02-09 15:51:56 +00002766 lenp = stream_get_endp (circuit->snd_stream);
hassof390d2c2004-09-10 20:48:21 +00002767 stream_putw (circuit->snd_stream, 0); /* PDU length - when we know it */
jardineb5d44e2003-12-23 08:09:43 +00002768 stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
2769 stream_putc (circuit->snd_stream, circuit->idx);
2770
2771 /*
2772 * And TLVs
2773 */
2774
Josh Bailey3f045a02012-03-24 08:35:20 -07002775 if (level == IS_LEVEL_1)
jardineb5d44e2003-12-23 08:09:43 +00002776 passwd = &circuit->area->area_passwd;
2777 else
2778 passwd = &circuit->area->domain_passwd;
2779
hasso1cbc5622005-01-01 10:29:51 +00002780 if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
Josh Bailey3f045a02012-03-24 08:35:20 -07002781 {
2782 switch (passwd->type)
hassof390d2c2004-09-10 20:48:21 +00002783 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002784 /* Cleartext */
2785 case ISIS_PASSWD_TYPE_CLEARTXT:
2786 if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len,
2787 passwd->passwd, circuit->snd_stream))
2788 return ISIS_WARNING;
2789 break;
2790
2791 /* HMAC MD5 */
2792 case ISIS_PASSWD_TYPE_HMAC_MD5:
2793 /* Remember where TLV is written so we can later overwrite the MD5 hash */
2794 auth_tlv_offset = stream_get_endp (circuit->snd_stream);
2795 memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
2796 if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE,
2797 hmac_md5_hash, circuit->snd_stream))
2798 return ISIS_WARNING;
2799 break;
2800
2801 default:
2802 break;
jardineb5d44e2003-12-23 08:09:43 +00002803 }
Josh Bailey3f045a02012-03-24 08:35:20 -07002804 }
2805
2806 retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
2807 if (retval != ISIS_OK)
2808 return retval;
jardineb5d44e2003-12-23 08:09:43 +00002809
hassof390d2c2004-09-10 20:48:21 +00002810 if (isis->debugs & DEBUG_SNP_PACKETS)
2811 {
hasso3fdb2dd2005-09-28 18:45:54 +00002812 for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp))
hassof390d2c2004-09-10 20:48:21 +00002813 {
hasso529d65b2004-12-24 00:14:50 +00002814 zlog_debug ("ISIS-Snp (%s): PSNP entry %s, seq 0x%08x,"
2815 " cksum 0x%04x, lifetime %us",
2816 circuit->area->area_tag,
2817 rawlspid_print (lsp->lsp_header->lsp_id),
2818 ntohl (lsp->lsp_header->seq_num),
2819 ntohs (lsp->lsp_header->checksum),
2820 ntohs (lsp->lsp_header->rem_lifetime));
hassof390d2c2004-09-10 20:48:21 +00002821 }
2822 }
2823
paul9985f832005-02-09 15:51:56 +00002824 length = (u_int16_t) stream_get_endp (circuit->snd_stream);
jardineb5d44e2003-12-23 08:09:43 +00002825 /* Update PDU length */
2826 stream_putw_at (circuit->snd_stream, lenp, length);
2827
Josh Bailey3f045a02012-03-24 08:35:20 -07002828 /* For HMAC MD5 we need to compute the md5 hash and store it */
2829 if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) &&
2830 passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5)
2831 {
2832 hmac_md5 (STREAM_DATA (circuit->snd_stream),
2833 stream_get_endp(circuit->snd_stream),
2834 (unsigned char *) &passwd->passwd, passwd->len,
2835 (caddr_t) &hmac_md5_hash);
2836 /* Copy the hash into the stream */
2837 memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
2838 hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
2839 }
2840
jardineb5d44e2003-12-23 08:09:43 +00002841 return ISIS_OK;
2842}
2843
2844/*
2845 * 7.3.15.4 action on expiration of partial SNP interval
2846 * level 1
2847 */
hasso92365882005-01-18 13:53:33 +00002848static int
jardineb5d44e2003-12-23 08:09:43 +00002849send_psnp (int level, struct isis_circuit *circuit)
2850{
jardineb5d44e2003-12-23 08:09:43 +00002851 struct isis_lsp *lsp;
2852 struct list *list = NULL;
hasso3fdb2dd2005-09-28 18:45:54 +00002853 struct listnode *node;
Josh Bailey3f045a02012-03-24 08:35:20 -07002854 u_char num_lsps;
2855 int retval = ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00002856
Josh Bailey3f045a02012-03-24 08:35:20 -07002857 if (circuit->circ_type == CIRCUIT_T_BROADCAST &&
2858 circuit->u.bc.is_dr[level - 1])
2859 return ISIS_OK;
2860
2861 if (circuit->area->lspdb[level - 1] == NULL ||
2862 dict_count (circuit->area->lspdb[level - 1]) == 0)
2863 return ISIS_OK;
2864
2865 num_lsps = max_lsps_per_snp (ISIS_SNP_PSNP_FLAG, level, circuit);
2866
2867 while (1)
hassof390d2c2004-09-10 20:48:21 +00002868 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002869 list = list_new ();
2870 lsp_build_list_ssn (circuit, num_lsps, list,
2871 circuit->area->lspdb[level - 1]);
jardineb5d44e2003-12-23 08:09:43 +00002872
Josh Bailey3f045a02012-03-24 08:35:20 -07002873 if (listcount (list) == 0)
2874 {
2875 list_delete (list);
2876 return ISIS_OK;
2877 }
jardineb5d44e2003-12-23 08:09:43 +00002878
Josh Bailey3f045a02012-03-24 08:35:20 -07002879 retval = build_psnp (level, circuit, list);
2880 if (retval != ISIS_OK)
2881 {
2882 zlog_err ("ISIS-Snp (%s): Build L%d PSNP on %s failed",
2883 circuit->area->area_tag, level, circuit->interface->name);
2884 list_delete (list);
2885 return retval;
2886 }
jardineb5d44e2003-12-23 08:09:43 +00002887
Josh Bailey3f045a02012-03-24 08:35:20 -07002888 if (isis->debugs & DEBUG_SNP_PACKETS)
2889 {
2890 zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld",
2891 circuit->area->area_tag, level,
2892 circuit->interface->name,
2893 stream_get_endp (circuit->snd_stream));
2894 if (isis->debugs & DEBUG_PACKET_DUMP)
2895 zlog_dump_data (STREAM_DATA (circuit->snd_stream),
2896 stream_get_endp (circuit->snd_stream));
2897 }
jardineb5d44e2003-12-23 08:09:43 +00002898
Josh Bailey3f045a02012-03-24 08:35:20 -07002899 retval = circuit->tx (circuit, level);
2900 if (retval != ISIS_OK)
2901 {
2902 zlog_err ("ISIS-Snp (%s): Send L%d PSNP on %s failed",
2903 circuit->area->area_tag, level,
2904 circuit->interface->name);
2905 list_delete (list);
2906 return retval;
2907 }
jardineb5d44e2003-12-23 08:09:43 +00002908
Josh Bailey3f045a02012-03-24 08:35:20 -07002909 /*
2910 * sending succeeded, we can clear SSN flags of this circuit
2911 * for the LSPs in list
2912 */
2913 for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
2914 ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
2915 list_delete (list);
jardineb5d44e2003-12-23 08:09:43 +00002916 }
jardineb5d44e2003-12-23 08:09:43 +00002917
2918 return retval;
2919}
2920
2921int
2922send_l1_psnp (struct thread *thread)
2923{
2924
2925 struct isis_circuit *circuit;
2926 int retval = ISIS_OK;
2927
2928 circuit = THREAD_ARG (thread);
2929 assert (circuit);
2930
2931 circuit->t_send_psnp[0] = NULL;
2932
2933 send_psnp (1, circuit);
2934 /* set next timer thread */
hassof390d2c2004-09-10 20:48:21 +00002935 THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
2936 isis_jitter (circuit->psnp_interval[0], PSNP_JITTER));
jardineb5d44e2003-12-23 08:09:43 +00002937
2938 return retval;
2939}
2940
2941/*
2942 * 7.3.15.4 action on expiration of partial SNP interval
2943 * level 2
2944 */
2945int
2946send_l2_psnp (struct thread *thread)
2947{
jardineb5d44e2003-12-23 08:09:43 +00002948 struct isis_circuit *circuit;
2949 int retval = ISIS_OK;
2950
2951 circuit = THREAD_ARG (thread);
2952 assert (circuit);
2953
2954 circuit->t_send_psnp[1] = NULL;
2955
2956 send_psnp (2, circuit);
2957
2958 /* set next timer thread */
hassof390d2c2004-09-10 20:48:21 +00002959 THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
2960 isis_jitter (circuit->psnp_interval[1], PSNP_JITTER));
jardineb5d44e2003-12-23 08:09:43 +00002961
2962 return retval;
2963}
2964
jardineb5d44e2003-12-23 08:09:43 +00002965/*
2966 * ISO 10589 - 7.3.14.3
2967 */
2968int
2969send_lsp (struct thread *thread)
2970{
2971 struct isis_circuit *circuit;
2972 struct isis_lsp *lsp;
2973 struct listnode *node;
Josh Bailey3f045a02012-03-24 08:35:20 -07002974 int retval = ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00002975
2976 circuit = THREAD_ARG (thread);
2977 assert (circuit);
2978
Josh Bailey3f045a02012-03-24 08:35:20 -07002979 if (circuit->state != C_STATE_UP || circuit->is_passive == 1)
2980 {
2981 return retval;
2982 }
2983
2984 lsp = listgetdata ((node = listhead (circuit->lsp_queue)));
2985
2986 /*
2987 * Do not send if levels do not match
2988 */
2989 if (!(lsp->level & circuit->is_type))
hassof390d2c2004-09-10 20:48:21 +00002990 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002991 list_delete_node (circuit->lsp_queue, node);
2992 return retval;
hassof390d2c2004-09-10 20:48:21 +00002993 }
jardineb5d44e2003-12-23 08:09:43 +00002994
Josh Bailey3f045a02012-03-24 08:35:20 -07002995 /*
2996 * Do not send if we do not have adjacencies in state up on the circuit
2997 */
2998 if (circuit->upadjcount[lsp->level - 1] == 0)
2999 {
3000 list_delete_node (circuit->lsp_queue, node);
3001 return retval;
3002 }
3003
3004 /* copy our lsp to the send buffer */
3005 stream_copy (circuit->snd_stream, lsp->pdu);
3006
3007 if (isis->debugs & DEBUG_UPDATE_PACKETS)
3008 {
3009 zlog_debug
3010 ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
3011 " lifetime %us on %s", circuit->area->area_tag, lsp->level,
3012 rawlspid_print (lsp->lsp_header->lsp_id),
3013 ntohl (lsp->lsp_header->seq_num),
3014 ntohs (lsp->lsp_header->checksum),
3015 ntohs (lsp->lsp_header->rem_lifetime),
3016 circuit->interface->name);
3017 if (isis->debugs & DEBUG_PACKET_DUMP)
3018 zlog_dump_data (STREAM_DATA (circuit->snd_stream),
3019 stream_get_endp (circuit->snd_stream));
3020 }
3021
3022 retval = circuit->tx (circuit, lsp->level);
3023 if (retval != ISIS_OK)
3024 {
3025 zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed",
3026 circuit->area->area_tag, lsp->level,
3027 circuit->interface->name);
3028 return retval;
3029 }
3030
3031 /*
3032 * If the sending succeeded, we can del the lsp from circuits
3033 * lsp_queue
3034 */
3035 list_delete_node (circuit->lsp_queue, node);
3036
3037 /* Set the last-cleared time if the queue is empty. */
3038 /* TODO: Is is possible that new lsps keep being added to the queue
3039 * that the queue is never empty? */
3040 if (list_isempty (circuit->lsp_queue))
3041 circuit->lsp_queue_last_cleared = time (NULL);
3042
3043 /*
3044 * On broadcast circuits also the SRMflag can be cleared
3045 */
3046 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
3047 ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
3048
jardineb5d44e2003-12-23 08:09:43 +00003049 return retval;
hassof390d2c2004-09-10 20:48:21 +00003050}
jardineb5d44e2003-12-23 08:09:43 +00003051
3052int
hassof390d2c2004-09-10 20:48:21 +00003053ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit,
3054 int level)
jardineb5d44e2003-12-23 08:09:43 +00003055{
3056 unsigned long lenp;
3057 int retval;
3058 u_int16_t length;
3059 struct isis_fixed_hdr fixed_hdr;
3060
3061 if (!circuit->snd_stream)
hassof390d2c2004-09-10 20:48:21 +00003062 circuit->snd_stream = stream_new (ISO_MTU (circuit));
jardineb5d44e2003-12-23 08:09:43 +00003063 else
3064 stream_reset (circuit->snd_stream);
3065
Josh Bailey3f045a02012-03-24 08:35:20 -07003066 // fill_llc_hdr (stream);
3067 if (level == IS_LEVEL_1)
hassof390d2c2004-09-10 20:48:21 +00003068 fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
3069 circuit->snd_stream);
jardineb5d44e2003-12-23 08:09:43 +00003070 else
hassof390d2c2004-09-10 20:48:21 +00003071 fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM,
3072 circuit->snd_stream);
jardineb5d44e2003-12-23 08:09:43 +00003073
3074
paul9985f832005-02-09 15:51:56 +00003075 lenp = stream_get_endp (circuit->snd_stream);
hassof390d2c2004-09-10 20:48:21 +00003076 stream_putw (circuit->snd_stream, 0); /* PDU length */
3077 stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
jardineb5d44e2003-12-23 08:09:43 +00003078 stream_putc (circuit->snd_stream, circuit->idx);
hassof390d2c2004-09-10 20:48:21 +00003079 stream_putc (circuit->snd_stream, 9); /* code */
3080 stream_putc (circuit->snd_stream, 16); /* len */
jardineb5d44e2003-12-23 08:09:43 +00003081
hassof390d2c2004-09-10 20:48:21 +00003082 stream_putw (circuit->snd_stream, ntohs (hdr->rem_lifetime));
3083 stream_put (circuit->snd_stream, hdr->lsp_id, ISIS_SYS_ID_LEN + 2);
3084 stream_putl (circuit->snd_stream, ntohl (hdr->seq_num));
3085 stream_putw (circuit->snd_stream, ntohs (hdr->checksum));
jardineb5d44e2003-12-23 08:09:43 +00003086
paul9985f832005-02-09 15:51:56 +00003087 length = (u_int16_t) stream_get_endp (circuit->snd_stream);
jardineb5d44e2003-12-23 08:09:43 +00003088 /* Update PDU length */
3089 stream_putw_at (circuit->snd_stream, lenp, length);
3090
3091 retval = circuit->tx (circuit, level);
Josh Bailey3f045a02012-03-24 08:35:20 -07003092 if (retval != ISIS_OK)
3093 zlog_err ("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed",
3094 circuit->area->area_tag, level,
3095 circuit->interface->name);
jardineb5d44e2003-12-23 08:09:43 +00003096
3097 return retval;
3098}