blob: 8d636b30c8d3eb5c9746ebbb0a5e90956d1cd4fc [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
24#include <stdio.h>
25#include <string.h>
26#include <zebra.h>
27#include <net/ethernet.h>
28
29#include "memory.h"
30#include "thread.h"
31#include "linklist.h"
32#include "log.h"
33#include "stream.h"
34#include "vty.h"
35#include "hash.c"
36#include "prefix.h"
37#include "if.h"
38
39#include "isisd/dict.h"
40#include "isisd/include-netbsd/iso.h"
41#include "isisd/isis_constants.h"
42#include "isisd/isis_common.h"
43#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"
48#include "isisd/isis_flags.h"
49#include "isisd/isis_tlv.h"
50#include "isisd/isisd.h"
51#include "isisd/isis_dynhn.h"
52#include "isisd/isis_lsp.h"
53#include "isisd/isis_pdu.h"
54#include "isisd/iso_checksum.h"
55#include "isisd/isis_csm.h"
56#include "isisd/isis_events.h"
57
58extern struct thread_master *master;
59extern struct isis *isis;
60
61#define ISIS_MINIMUM_FIXED_HDR_LEN 15
62#define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */
63
64#ifndef PNBBY
65#define PNBBY 8
66#endif /* PNBBY */
67
68/* Utility mask array. */
69static u_char maskbit[] =
70{
71 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
72};
73
74/*
75 * HELPER FUNCS
76 */
77
78/*
79 * Compares two sets of area addresses
80 */
81static int
82area_match (struct list *left, struct list *right)
83{
84 struct area_addr *addr1, *addr2;
85 struct listnode *node1, *node2;
86
87 LIST_LOOP (left, addr1, node1) {
88 LIST_LOOP (right, addr2, node2) {
89 if (addr1->addr_len == addr2->addr_len &&
90 !memcmp (addr1->area_addr, addr2->area_addr, (int)addr1->addr_len))
91 return 1; /* match */
92 }
93 }
94
95 return 0; /* mismatch */
96}
97
98/*
99 * Check if ip2 is in the ip1's network (function like Prefix.h:prefix_match() )
100 * param ip1 the IS interface ip address structure
101 * param ip2 the IIH's ip address
102 * return 0 the IIH's IP is not in the IS's subnetwork
103 * 1 the IIH's IP is in the IS's subnetwork
104 */
105int
106ip_same_subnet (struct prefix_ipv4 *ip1, struct in_addr *ip2)
107{
108 u_char *addr1, *addr2;
109 int shift, offset;
110 int len;
111
112 addr1 = (u_char *) &ip1->prefix.s_addr;
113 addr2 = (u_char *) &ip2->s_addr;
114 len = ip1->prefixlen;
115
116 shift = len % PNBBY;
117 offset = len / PNBBY;
118
119 while (offset--) {
120 if (addr1[offset] != addr2[offset]) {
121 return 0;
122 }
123 }
124
125 if (shift) {
126 if (maskbit[shift] & (addr1[offset] ^ addr2[offset])) {
127 return 0;
128 }
129 }
130
131 return 1; /* match */
132}
133
134
135/*
136 * Compares two set of ip addresses
137 * param left the local interface's ip addresses
138 * param right the iih interface's ip address
139 * return 0 no match;
140 * 1 match;
141 */
142static int
143ip_match (struct list *left, struct list *right)
144{
145 struct prefix_ipv4 *ip1;
146 struct in_addr *ip2;
147 struct listnode *node1, *node2;
148
149 LIST_LOOP (left, ip1, node1) {
150 LIST_LOOP (right, ip2, node2) {
151 if (ip_same_subnet(ip1, ip2)) {
152 return 1; /* match */
153 }
154 }
155
156 }
157 return 0;
158}
159
160/*
161 * Checks whether we should accept a PDU of given level
162 */
163static int
164accept_level (int level, int circuit_t)
165{
166 int retval = ((circuit_t & level) == level); /* simple approach */
167
168 return retval;
169}
170
171int
172authentication_check (struct isis_passwd *one, struct isis_passwd *theother)
173{
174 if (one->type != theother->type) {
175 zlog_warn ("Unsupported authentication type %d", theother->type );
176 return 1; /* Auth fail (different authentication types)*/
177 }
178 switch (one->type) {
179 case ISIS_PASSWD_TYPE_CLEARTXT:
180 if (one->len != theother->len)
181 return 1; /* Auth fail () - passwd len mismatch */
182 return memcmp (one->passwd, theother->passwd, one->len);
183 break;
184 default:
185 zlog_warn ("Unsupported authentication type");
186 break;
187 }
188 return 0; /* Auth pass */
189}
190
191/*
192 * Processing helper functions
193 */
194void
195tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj)
196{
197 int i;
198 struct nlpids *tlv_nlpids;
199
200 if (tlvs->nlpids) {
201
202 tlv_nlpids = tlvs->nlpids;
203
204 adj->nlpids.count = tlv_nlpids->count;
205
206 for (i=0;i<tlv_nlpids->count;i++) {
207 adj->nlpids.nlpids[i] = tlv_nlpids->nlpids[i];
208 }
209 }
210}
211
212void
213del_ip_addr (void *val)
214{
215 XFREE (MTYPE_ISIS_TMP, val);
216}
217
218void
219tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
220{
221 struct listnode *node;
222 struct in_addr *ipv4_addr, *malloced;
223
224 if (adj->ipv4_addrs) {
225 adj->ipv4_addrs->del = del_ip_addr;
226 list_delete (adj->ipv4_addrs);
227 }
228 adj->ipv4_addrs = list_new ();
229 if (tlvs->ipv4_addrs) {
230 LIST_LOOP (tlvs->ipv4_addrs, ipv4_addr, node) {
231 malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in_addr));
232 memcpy (malloced, ipv4_addr, sizeof (struct in_addr));
233 listnode_add (adj->ipv4_addrs, malloced);
234 }
235 }
236}
237
238#ifdef HAVE_IPV6
239void
240tlvs_to_adj_ipv6_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
241{
242 struct listnode *node;
243 struct in6_addr *ipv6_addr, *malloced;
244
245 if (adj->ipv6_addrs) {
246 adj->ipv6_addrs->del = del_ip_addr;
247 list_delete (adj->ipv6_addrs);
248 }
249 adj->ipv6_addrs = list_new ();
250 if (tlvs->ipv6_addrs) {
251 LIST_LOOP (tlvs->ipv6_addrs, ipv6_addr, node) {
252 malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in6_addr));
253 memcpy (malloced, ipv6_addr, sizeof (struct in6_addr));
254 listnode_add (adj->ipv6_addrs, malloced);
255 }
256 }
257
258}
259#endif /* HAVE_IPV6 */
260
261
262
263/*
264 * RECEIVE SIDE
265 */
266
267/*
268 * Process P2P IIH
269 * ISO - 10589
270 * Section 8.2.5 - Receiving point-to-point IIH PDUs
271 *
272 */
273static int
274process_p2p_hello (struct isis_circuit *circuit)
275{
276 int retval = ISIS_OK;
277 struct isis_p2p_hello_hdr *hdr;
278 struct isis_adjacency *adj;
279 u_int32_t expected = 0, found;
280 struct tlvs tlvs;
281
282 if ((stream_get_endp (circuit->rcv_stream) -
283 stream_get_getp (circuit->rcv_stream)) <
284 ISIS_P2PHELLO_HDRLEN) {
285 zlog_warn ("Packet too short");
286 return ISIS_WARNING;
287 }
288
289 /* 8.2.5.1 PDU acceptance tests */
290
291 /* 8.2.5.1 a) external domain untrue */
292 /* FIXME: not useful at all? */
293
294 /* 8.2.5.1 b) ID Length mismatch */
295 /* checked at the handle_pdu */
296
297 /* 8.2.5.2 IIH PDU Processing */
298
299 /* 8.2.5.2 a) 1) Maximum Area Addresses */
300 /* Already checked, and can also be ommited */
301
302 /*
303 * Get the header
304 */
305 hdr = (struct isis_p2p_hello_hdr*) STREAM_PNT(circuit->rcv_stream);
306 circuit->rcv_stream->getp += ISIS_P2PHELLO_HDRLEN;
307
308 /* hdr.circuit_t = stream_getc (stream);
309 stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN);
310 hdr.hold_time = stream_getw (stream);
311 hdr.pdu_len = stream_getw (stream);
312 hdr.local_id = stream_getc (stream); */
313
314 /*
315 * My interpertation of the ISO, if no adj exists we will create one for
316 * the circuit
317 */
318
319 if (isis->debugs & DEBUG_ADJ_PACKETS) {
320 zlog_info("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
321 " cir id %02d, length %d",
322 circuit->area->area_tag, circuit->interface->name,
323 circuit_t2string(circuit->circuit_is_type),
324 circuit->circuit_id,ntohs(hdr->pdu_len));
325 }
326
327 adj = circuit->u.p2p.neighbor;
328 if ( !adj ) {
329 adj = isis_new_adj (hdr->source_id," ", 0, circuit);
330 if (adj == NULL)
331 return ISIS_ERROR;
332 circuit->u.p2p.neighbor = adj;
333 isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, NULL);
334 adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
335 }
336
337 /* 8.2.6 Monitoring point-to-point adjacencies */
338 adj->hold_time = ntohs (hdr->hold_time);
339 adj->last_upd = time (NULL);
340
341 /*
342 * Lets get the TLVS now
343 */
344 expected |= TLVFLAG_AREA_ADDRS;
345 expected |= TLVFLAG_AUTH_INFO;
346 expected |= TLVFLAG_NLPID;
347 expected |= TLVFLAG_IPV4_ADDR;
348 expected |= TLVFLAG_IPV6_ADDR;
349
350 retval = parse_tlvs (circuit->area->area_tag,
351 STREAM_PNT (circuit->rcv_stream),
352 ntohs (hdr->pdu_len) - ISIS_P2PHELLO_HDRLEN
353 - ISIS_FIXED_HDR_LEN,
354 &expected,
355 &found,
356 &tlvs);
357
358 if (retval > ISIS_WARNING) {
359 free_tlvs (&tlvs);
360 return retval;
361 };
362
363 /* 8.2.5.1 c) Authentication */
364 if (circuit->passwd.type) {
365 if (!(found & TLVFLAG_AUTH_INFO) ||
366 authentication_check (&circuit->passwd, &tlvs.auth_info)) {
367 isis_event_auth_failure (circuit->area->area_tag,
368 "P2P hello authentication failure",
369 hdr->source_id);
370 return ISIS_OK;
371 }
372 }
373
374 /* we do this now because the adj may not survive till the end... */
375
376 /* we need to copy addresses to the adj */
377 tlvs_to_adj_ipv4_addrs (&tlvs,adj);
378
379#ifdef HAVE_IPV6
380 tlvs_to_adj_ipv6_addrs (&tlvs,adj);
381#endif /* HAVE_IPV6 */
382
383 /* lets take care of the expiry */
384 if(adj->t_expire) {
385 thread_cancel (adj->t_expire);
386 }
387 adj->t_expire = thread_add_timer (master, isis_adj_expire, adj,
388 (long)adj->hold_time);
389
390 /* 8.2.5.2 a) a match was detected */
391 if (area_match (circuit->area->area_addrs, tlvs.area_addrs)) {
392 /* 8.2.5.2 a) 2) If the system is L1 - table 5 */
393 if (circuit->area->is_type == IS_LEVEL_1) {
394 switch (hdr->circuit_t) {
395 case IS_LEVEL_1:
396 case IS_LEVEL_1_AND_2:
397 if (adj->adj_state != ISIS_ADJ_UP) {
398 /* (4) adj state up */
399 isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
400 /* (5) adj usage level 1 */
401 adj->adj_usage = ISIS_ADJ_LEVEL1;
402 } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
403 ; /* accept */
404 }
405 break;
406 case IS_LEVEL_2:
407 if (adj->adj_state != ISIS_ADJ_UP) {
408 /* (7) reject - wrong system type event */
409 zlog_warn ("wrongSystemType");
410 return ISIS_WARNING; /* Reject */
411 } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
412 /* (6) down - wrong system */
413 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
414 }
415 break;
416 }
417 }
418
419 /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */
420 if (circuit->area->is_type == IS_LEVEL_1_AND_2) {
421 switch (hdr->circuit_t) {
422 case IS_LEVEL_1:
423 if (adj->adj_state != ISIS_ADJ_UP) {
424 /* (6) adj state up */
425 isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
426 /* (7) adj usage level 1 */
427 adj->adj_usage = ISIS_ADJ_LEVEL1;
428 } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
429 ; /* accept */
430 } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
431 (adj->adj_usage == ISIS_ADJ_LEVEL2)) {
432 /* (8) down - wrong system */
433 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
434 }
435 break;
436 case IS_LEVEL_2:
437 if (adj->adj_state != ISIS_ADJ_UP) {
438 /* (6) adj state up */
439 isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
440 /* (9) adj usage level 2 */
441 adj->adj_usage = ISIS_ADJ_LEVEL2;
442 } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) ||
443 (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)) {
444 /* (8) down - wrong system */
445 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
446 } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) {
447 ; /* Accept */
448 }
449 break;
450 case IS_LEVEL_1_AND_2:
451 if (adj->adj_state != ISIS_ADJ_UP) {
452 /* (6) adj state up */
453 isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
454 /* (10) adj usage level 1 */
455 adj->adj_usage = ISIS_ADJ_LEVEL1AND2;
456 } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) ||
457 (adj->adj_usage == ISIS_ADJ_LEVEL2)) {
458 /* (8) down - wrong system */
459 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
460 } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) {
461 ; /* Accept */
462 }
463 break;
464 }
465 }
466
467 /* 8.2.5.2 a) 4) If the system is L2 - table 7 */
468 if (circuit->area->is_type == IS_LEVEL_2) {
469 switch (hdr->circuit_t) {
470 case IS_LEVEL_1:
471 if (adj->adj_state != ISIS_ADJ_UP) {
472 /* (5) reject - wrong system type event */
473 zlog_warn ("wrongSystemType");
474 return ISIS_WARNING; /* Reject */
475 } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
476 (adj->adj_usage == ISIS_ADJ_LEVEL2)) {
477 /* (6) down - wrong system */
478 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
479 }
480 break;
481 case IS_LEVEL_1_AND_2:
482 case IS_LEVEL_2:
483 if (adj->adj_state != ISIS_ADJ_UP) {
484 /* (7) adj state up */
485 isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
486 /* (8) adj usage level 2 */
487 adj->adj_usage = ISIS_ADJ_LEVEL2;
488 } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) {
489 /* (6) down - wrong system */
490 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
491 } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) {
492 ; /* Accept */
493 }
494 break;
495 }
496 }
497 }
498 /* 8.2.5.2 b) if no match was detected */
499 else
500 {
501 if (circuit->area->is_type == IS_LEVEL_1) {
502 /* 8.2.5.2 b) 1) is_type L1 and adj is not up */
503 if (adj->adj_state != ISIS_ADJ_UP) {
504 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
505 /* 8.2.5.2 b) 2)is_type L1 and adj is up */
506 } else {
507 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Down - Area Mismatch");
508 }
509 }
510 /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */
511 else
512 {
513 switch (hdr->circuit_t) {
514 case IS_LEVEL_1:
515 if (adj->adj_state != ISIS_ADJ_UP) {
516 /* (6) reject - Area Mismatch event */
517 zlog_warn ("AreaMismatch");
518 return ISIS_WARNING; /* Reject */
519 } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
520 /* (7) down - area mismatch */
521 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
522
523 } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
524 (adj->adj_usage == ISIS_ADJ_LEVEL2)) {
525 /* (7) down - wrong system */
526 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
527 }
528 break;
529 case IS_LEVEL_1_AND_2:
530 case IS_LEVEL_2:
531 if (adj->adj_state != ISIS_ADJ_UP) {
532 /* (8) adj state up */
533 isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
534 /* (9) adj usage level 2 */
535 adj->adj_usage = ISIS_ADJ_LEVEL2;
536 } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
537 /* (7) down - wrong system */
538 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
539 } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) {
540 if (hdr->circuit_t == IS_LEVEL_2) {
541 /* (7) down - wrong system */
542 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
543 } else {
544 /* (7) down - area mismatch */
545 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
546 }
547 } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) {
548 ; /* Accept */
549 }
550 break;
551 }
552 }
553 }
554 /* 8.2.5.2 c) if the action was up - comparing circuit IDs */
555 /* FIXME - Missing parts */
556
557
558 /* some of my own understanding of the ISO, why the heck does
559 * it not say what should I change the system_type to...
560 */
561 switch (adj->adj_usage) {
562 case ISIS_ADJ_LEVEL1:
563 adj->sys_type = ISIS_SYSTYPE_L1_IS;
564 break;
565 case ISIS_ADJ_LEVEL2:
566 adj->sys_type = ISIS_SYSTYPE_L2_IS;
567 break;
568 case ISIS_ADJ_LEVEL1AND2:
569 adj->sys_type = ISIS_SYSTYPE_L2_IS;
570 break;
571 case ISIS_ADJ_NONE:
572 adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
573 break;
574 }
575
576 adj->circuit_t = hdr->circuit_t;
577 adj->level = hdr->circuit_t;
578
579 free_tlvs (&tlvs);
580
581 return retval;
582}
583
584
585/*
586 * Process IS-IS LAN Level 1/2 Hello PDU
587 */
588static int
589process_lan_hello (int level, struct isis_circuit *circuit, u_char *ssnpa)
590{
591 int retval = ISIS_OK;
592 struct isis_lan_hello_hdr hdr;
593 struct isis_adjacency *adj;
594 u_int32_t expected = 0, found;
595 struct tlvs tlvs;
596 u_char *snpa;
597 struct listnode *node;
598
599 if ((stream_get_endp (circuit->rcv_stream) -
600 stream_get_getp (circuit->rcv_stream)) < ISIS_LANHELLO_HDRLEN) {
601 zlog_warn ("Packet too short");
602 return ISIS_WARNING;
603 }
604
605 if (circuit->ext_domain) {
606 zlog_info ("level %d LAN Hello received over circuit with "
607 "externalDomain = true", level);
608 return ISIS_WARNING;
609 }
610
611 if (!accept_level (level, circuit->circuit_is_type)) {
612 if (isis->debugs & DEBUG_ADJ_PACKETS) {
613 zlog_info ("ISIS-Adj (%s): Interface level mismatch, %s",
614 circuit->area->area_tag, circuit->interface->name);
615 }
616 return ISIS_WARNING;
617 }
618
619#if 0
620 /* Cisco's debug message compatability */
621 if (!accept_level (level, circuit->area->is_type)) {
622 if (isis->debugs & DEBUG_ADJ_PACKETS) {
623 zlog_info ("ISIS-Adj (%s): is type mismatch",
624 circuit->area->area_tag);
625 }
626 return ISIS_WARNING;
627 }
628#endif
629 /*
630 * Fill the header
631 */
632 hdr.circuit_t = stream_getc (circuit->rcv_stream);
633 stream_get (hdr.source_id, circuit->rcv_stream, ISIS_SYS_ID_LEN);
634 hdr.hold_time = stream_getw (circuit->rcv_stream);
635 hdr.pdu_len = stream_getw (circuit->rcv_stream);
636 hdr.prio = stream_getc (circuit->rcv_stream);
637 stream_get (hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1);
638
639 if (hdr.circuit_t != IS_LEVEL_1 && hdr.circuit_t != IS_LEVEL_2 &&
640 hdr.circuit_t != IS_LEVEL_1_AND_2 ) {
641 zlog_warn ("Level %d LAN Hello with Circuit Type %d", level,
642 hdr.circuit_t);
643 return ISIS_ERROR;
644 }
645 /*
646 * Then get the tlvs
647 */
648 expected |= TLVFLAG_AUTH_INFO;
649 expected |= TLVFLAG_AREA_ADDRS;
650 expected |= TLVFLAG_LAN_NEIGHS;
651 expected |= TLVFLAG_NLPID;
652 expected |= TLVFLAG_IPV4_ADDR;
653 expected |= TLVFLAG_IPV6_ADDR;
654
655 retval = parse_tlvs (circuit->area->area_tag,
656 STREAM_PNT (circuit->rcv_stream),
657 hdr.pdu_len - ISIS_LANHELLO_HDRLEN - ISIS_FIXED_HDR_LEN,
658 &expected,
659 &found,
660 &tlvs);
661
662 if (retval > ISIS_WARNING) {
663 zlog_warn ("parse_tlvs() failed");
664 goto out;
665 }
666
667 if (!(found & TLVFLAG_AREA_ADDRS)) {
668 zlog_warn ("No Area addresses TLV in Level %d LAN IS to IS hello", level);
669 retval = ISIS_WARNING;
670 goto out;
671 }
672
673 if (circuit->passwd.type) {
674 if (!(found & TLVFLAG_AUTH_INFO) ||
675 authentication_check (&circuit->passwd, &tlvs.auth_info)) {
676 isis_event_auth_failure (circuit->area->area_tag,
677 "LAN hello authentication failure",
678 hdr.source_id);
679 retval = ISIS_WARNING;
680 goto out;
681 }
682 }
683
684 /*
685 * Accept the level 1 adjacency only if a match between local and
686 * remote area addresses is found
687 */
688 if (level == 1 && !area_match (circuit->area->area_addrs, tlvs.area_addrs)) {
689 if (isis->debugs & DEBUG_ADJ_PACKETS) {
690 zlog_info ("ISIS-Adj (%s): Area mismatch, level %d IIH on %s",
691 circuit->area->area_tag, level,circuit->interface->name);
692 }
693 retval = ISIS_OK;
694 goto out;
695 }
696
697 /*
698 * it's own IIH PDU - discard silently
699 */
700 if (!memcmp (circuit->u.bc.snpa, ssnpa, ETH_ALEN)) {
701 zlog_info ("ISIS-Adj (%s): it's own IIH PDU - discarded",
702 circuit->area->area_tag);
703
704 retval = ISIS_OK;
705 goto out;
706 }
707
708 /*
709 * check if it's own interface ip match iih ip addrs
710 */
711 if (!(found & TLVFLAG_IPV4_ADDR) || !ip_match(circuit->ip_addrs, tlvs.ipv4_addrs)) {
712 zlog_info("ISIS-Adj: No usable IP interface addresses in LAN IIH from %s\n",
713 circuit->interface->name);
714 retval = ISIS_WARNING;
715 goto out;
716 }
717
718
719 adj = isis_adj_lookup (hdr.source_id, circuit->u.bc.adjdb[level - 1]);
720 if (!adj) {
721 /*
722 * Do as in 8.4.2.5
723 */
724 adj = isis_new_adj (hdr.source_id, ssnpa, level, circuit);
725 if (adj == NULL)
726 retval = ISIS_ERROR;
727 goto out;
728
729 adj->level = level;
730 isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, NULL);
731
732 if (level == 1) {
733 adj->sys_type = ISIS_SYSTYPE_L1_IS;
734 } else {
735 adj->sys_type = ISIS_SYSTYPE_L2_IS;
736 }
737 list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
738 isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
739 circuit->u.bc.lan_neighs[level - 1]);
740 }
741
742 switch (level) {
743 case 1 :
744 if (memcmp(circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1)) {
745 thread_add_event (master, isis_event_dis_status_change, circuit, 0);
746 memcpy (&circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
747 }
748 break;
749 case 2 :
750 if (memcmp (circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1)) {
751 thread_add_event (master, isis_event_dis_status_change, circuit, 0);
752 memcpy (&circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
753 }
754 break;
755 }
756
757#if 0
758 /* Old solution: believe the lan-header always
759 */
760 if (level == 1) {
761 memcpy(circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
762 } else if (level == 2) {
763 memcpy(circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
764 }
765#endif
766
767 adj->hold_time = hdr.hold_time;
768 adj->last_upd = time (NULL);
769 adj->prio[level-1] = hdr.prio;
770
771 memcpy (adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
772
773 /* which protocol are spoken ??? */
774 if (found & TLVFLAG_NLPID)
775 tlvs_to_adj_nlpids (&tlvs, adj);
776
777 /* we need to copy addresses to the adj */
778 if (found & TLVFLAG_IPV4_ADDR)
779 tlvs_to_adj_ipv4_addrs (&tlvs, adj);
780
781#ifdef HAVE_IPV6
782 if (found & TLVFLAG_IPV6_ADDR)
783 tlvs_to_adj_ipv6_addrs (&tlvs, adj);
784#endif /* HAVE_IPV6 */
785
786 adj->circuit_t = hdr.circuit_t;
787
788 /* lets take care of the expiry */
789 if (adj->t_expire) {
790 thread_cancel (adj->t_expire);
791 }
792 adj->t_expire = thread_add_timer (master, isis_adj_expire, adj,
793 (long)adj->hold_time);
794
795 /*
796 * If the snpa for this circuit is found from LAN Neighbours TLV
797 * we have two-way communication -> adjacency can be put to state "up"
798 */
799
800 if (found & TLVFLAG_LAN_NEIGHS) {
801 if (adj->adj_state != ISIS_ADJ_UP) {
802 LIST_LOOP (tlvs.lan_neighs, snpa, node)
803 if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN)) {
804 isis_adj_state_change (adj, ISIS_ADJ_UP,
805 "own SNPA found in LAN Neighbours TLV");
806 }
807 }
808 }
809
810 out:
811 /* DEBUG_ADJ_PACKETS */
812 if (isis->debugs & DEBUG_ADJ_PACKETS) {
813 /* FIXME: is this place right? fix missing info */
814 zlog_info ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "
815 "cirID %u, length %ld",
816 circuit->area->area_tag,
817 level,snpa_print(ssnpa), circuit->interface->name,
818 circuit_t2string(circuit->circuit_is_type),
819 circuit->circuit_id,
820 stream_get_endp (circuit->rcv_stream));
821 }
822
823
824 free_tlvs (&tlvs);
825
826 return retval;
827}
828
829/*
830 * Process Level 1/2 Link State
831 * ISO - 10589
832 * Section 7.3.15.1 - Action on receipt of a link state PDU
833 */
834static int
835process_lsp (int level, struct isis_circuit *circuit, u_char *ssnpa)
836{
837 struct isis_link_state_hdr *hdr;
838 struct isis_adjacency *adj = NULL;
839 struct isis_lsp *lsp, *lsp0 = NULL;
840 int retval = ISIS_OK, comp = 0;
841 u_char lspid[ISIS_SYS_ID_LEN + 2];
842 struct isis_passwd *passwd;
843
844 /* Sanity check - FIXME: move to correct place */
845 if ((stream_get_endp (circuit->rcv_stream) -
846 stream_get_getp (circuit->rcv_stream)) < ISIS_LSP_HDR_LEN ) {
847 zlog_warn ("Packet too short");
848 return ISIS_WARNING;
849 }
850
851 /* Reference the header */
852 hdr = (struct isis_link_state_hdr*)STREAM_PNT (circuit->rcv_stream);
853
854 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
855 zlog_info ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "
856 "lifetime %us, len %lu, on %s",
857 circuit->area->area_tag,
858 level,
859 rawlspid_print(hdr->lsp_id),
860 ntohl(hdr->seq_num),
861 ntohs(hdr->checksum),
862 ntohs(hdr->rem_lifetime),
863 circuit->rcv_stream->endp,
864 circuit->interface->name);
865 }
866
867 assert (ntohs (hdr->pdu_len) > ISIS_LSP_HDR_LEN);
868
869 /* Checksum sanity check - FIXME: move to correct place */
870 /* 12 = sysid+pdu+remtime */
871 if (iso_csum_verify (STREAM_PNT (circuit->rcv_stream) + 4,
872 ntohs (hdr->pdu_len) - 12, &hdr->checksum)) {
873 zlog_info ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
874 circuit->area->area_tag,
875 rawlspid_print (hdr->lsp_id),
876 ntohs(hdr->checksum));
877
878 return ISIS_WARNING;
879 }
880
881 /* 7.3.15.1 a) 1 - external domain circuit will discard lsps */
882 if (circuit->ext_domain) {
883 zlog_info ("ISIS-Upd (%s): LSP %s received at level %d over circuit with "
884 "externalDomain = true",
885 circuit->area->area_tag,
886 rawlspid_print (hdr->lsp_id),
887 level);
888
889 return ISIS_WARNING;
890 }
891
892 /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
893 if (!accept_level (level, circuit->circuit_is_type)) {
894 zlog_info ("ISIS-Upd (%s): LSP %s received at level %d over circuit of"
895 " type %s",
896 circuit->area->area_tag,
897 rawlspid_print(hdr->lsp_id),
898 level,
899 circuit_t2string (circuit->circuit_is_type));
900
901 return ISIS_WARNING;
902 }
903
904 /* 7.3.15.1 a) 4 - need to make sure IDLength matches */
905
906 /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */
907
908 /* 7.3.15.1 a) 7 - password check */
909 (level == ISIS_LEVEL1) ? (passwd = &circuit->area->area_passwd) :
910 (passwd = &circuit->area->domain_passwd);
911 if (passwd->type) {
912 if (isis_lsp_authinfo_check (circuit->rcv_stream, circuit->area,
913 ntohs (hdr->pdu_len), passwd)) {
914 isis_event_auth_failure (circuit->area->area_tag,
915 "LSP authentication failure",
916 hdr->lsp_id);
917 return ISIS_WARNING;
918 }
919 }
920 /* Find the LSP in our database and compare it to this Link State header */
921 lsp = lsp_search (hdr->lsp_id, circuit->area->lspdb[level - 1]);
922 if (lsp)
923 comp = lsp_compare (circuit->area->area_tag, lsp, hdr->seq_num,
924 hdr->checksum, hdr->rem_lifetime);
925 if (lsp && (lsp->own_lsp
926#ifdef TOPOLOGY_GENERATE
927 || lsp->from_topology
928#endif /* TOPOLOGY_GENERATE */
929 ))
930 goto dontcheckadj;
931
932 /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level */
933 /* for broadcast circuits, snpa should be compared */
934 /* FIXME : Point To Point */
935
936 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
937 adj = isis_adj_lookup_snpa (ssnpa, circuit->u.bc.adjdb[level - 1]);
938 if (!adj) {
939 zlog_info ("(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, "
940 "lifetime %us on %s",
941 circuit->area->area_tag,
942 rawlspid_print (hdr->lsp_id),
943 ntohl (hdr->seq_num),
944 ntohs (hdr->checksum),
945 ntohs (hdr->rem_lifetime),
946 circuit->interface->name);
947 return ISIS_WARNING; /* Silently discard */
948 }
949 }
950
951 /* for non broadcast, we just need to find same level adj */
952 else {
953 /* If no adj, or no sharing of level */
954 if (!circuit->u.p2p.neighbor) {
955 return ISIS_OK; /* Silently discard */
956 } else {
957 if (((level == 1) &&
958 (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL2)) ||
959 ((level == 2) &&
960 (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL1)))
961 return ISIS_WARNING; /* Silently discard */
962 }
963 }
964 dontcheckadj:
965 /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */
966
967 /* 7.3.15.1 a) 8 - Passwords for level 2 - not implemented */
968
969 /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented FIXME: do it*/
970
971
972 /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4*/
973 if (hdr->rem_lifetime == 0) {
974 if (!lsp) {
975 /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't save */
976 /* only needed on explicit update, eg - p2p */
977 if (circuit->circ_type == CIRCUIT_T_P2P)
978 ack_lsp (hdr, circuit, level);
979 return retval; /* FIXME: do we need a purge? */
980 } else {
981 if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN )) {
982 /* LSP by some other system -> do 7.3.16.4 b) */
983 /* 7.3.16.4 b) 1) */
984 if (comp == LSP_NEWER) {
985 lsp_update (lsp, hdr, circuit->rcv_stream, circuit->area);
986 /* ii */
987 ISIS_FLAGS_SET_ALL (lsp->SRMflags);
988 /* iii */
989 ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
990 /* v */
991 ISIS_FLAGS_CLEAR_ALL(lsp->SSNflags); /* FIXME: OTHER than c */
992 /* iv */
993 if (circuit->circ_type != CIRCUIT_T_BROADCAST)
994 ISIS_SET_FLAG(lsp->SSNflags, circuit);
995
996 } /* 7.3.16.4 b) 2) */
997 else if (comp == LSP_EQUAL) {
998 /* i */
999 ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
1000 /* ii*/
1001 if (circuit->circ_type != CIRCUIT_T_BROADCAST)
1002 ISIS_SET_FLAG(lsp->SSNflags, circuit);
1003 } /* 7.3.16.4 b) 3) */
1004 else {
1005 ISIS_SET_FLAG(lsp->SRMflags, circuit);
1006 ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
1007 }
1008 } else {
1009 /* our own LSP -> 7.3.16.4 c) */
1010 if (LSP_PSEUDO_ID(lsp->lsp_header->lsp_id) != circuit->circuit_id ||
1011 (LSP_PSEUDO_ID(lsp->lsp_header->lsp_id) == circuit->circuit_id &&
1012 circuit->u.bc.is_dr[level - 1] == 1) ) {
1013 lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1);
1014 zlog_info ("LSP LEN: %d", ntohs (lsp->lsp_header->pdu_len));
1015 iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
1016 ntohs (lsp->lsp_header->pdu_len) - 12, 12);
1017 ISIS_FLAGS_SET_ALL (lsp->SRMflags);
1018 zlog_info ("ISIS-Upd (%s): (1) re-originating LSP %s new seq 0x%08x",
1019 circuit->area->area_tag,
1020 rawlspid_print (hdr->lsp_id),
1021 ntohl (lsp->lsp_header->seq_num));
1022 lsp->lsp_header->rem_lifetime = htons (isis_jitter
1023 (circuit->area->
1024 max_lsp_lifetime[level-1],
1025 MAX_AGE_JITTER));
1026
1027 } else {
1028 /* Got purge for own pseudo-lsp, and we are not DR */
1029 lsp_purge_dr (lsp->lsp_header->lsp_id, circuit, level);
1030 }
1031 }
1032 }
1033 return retval;
1034 }
1035 /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a
1036 * purge */
1037 if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN ) == 0) {
1038 if (!lsp) {
1039 /* 7.3.16.4: initiate a purge */
1040 lsp_purge_non_exist (hdr, circuit->area);
1041 return ISIS_OK;
1042 }
1043 /* 7.3.15.1 d) - If this is our own lsp and we have it */
1044
1045 /* In 7.3.16.1, If an Intermediate system R somewhere in the domain
1046 * has information that the current sequence number for source S is
1047 * "greater" than that held by S, ... */
1048
1049 else if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num)) {
1050 /* 7.3.16.1 */
1051 lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1);
1052
1053 iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
1054 ntohs(lsp->lsp_header->pdu_len) - 12, 12);
1055
1056 ISIS_FLAGS_SET_ALL (lsp->SRMflags);
1057 zlog_info ("ISIS-Upd (%s): (2) re-originating LSP %s new seq 0x%08x",
1058 circuit->area->area_tag,
1059 rawlspid_print (hdr->lsp_id),
1060 ntohl (lsp->lsp_header->seq_num));
1061 lsp->lsp_header->rem_lifetime = htons (isis_jitter
1062 (circuit->
1063 area->max_lsp_lifetime[level-1],
1064 MAX_AGE_JITTER));
1065
1066 }
1067 } else {
1068 /* 7.3.15.1 e) - This lsp originated on another system */
1069
1070 /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */
1071 if ((!lsp || comp == LSP_NEWER)){
1072 /* i */
1073 if (lsp) {
1074#ifdef EXTREME_DEBUG
1075 zlog_info ("level %d number is - %ld", level,
1076 circuit->area->lspdb[level-1]->dict_nodecount);
1077#endif /* EXTREME DEBUG */
1078 lsp_search_and_destroy (hdr->lsp_id, circuit->area->lspdb[level-1]);
1079 /* exists, so we overwrite */
1080#ifdef EXTREME_DEBUG
1081 zlog_info ("level %d number is - %ld",level,
1082 circuit->area->lspdb[level-1]->dict_nodecount);
1083#endif /* EXTREME DEBUG */
1084 }
1085 /*
1086 * If this lsp is a frag, need to see if we have zero lsp present
1087 */
1088 if (LSP_FRAGMENT (hdr->lsp_id) != 0) {
1089 memcpy (lspid, hdr->lsp_id, ISIS_SYS_ID_LEN + 1);
1090 LSP_FRAGMENT (lspid) = 0;
1091 lsp0 = lsp_search (lspid, circuit->area->lspdb[level - 1]);
1092 if (!lsp0) {
1093 zlog_info ("Got lsp frag, while zero lsp not database");
1094 return ISIS_OK;
1095 }
1096 }
1097 lsp = lsp_new_from_stream_ptr (circuit->rcv_stream, ntohs (hdr->pdu_len),
1098 lsp0, circuit->area);
1099 lsp->level = level;
1100 lsp->adj = adj;
1101 lsp_insert (lsp, circuit->area->lspdb[level-1]);
1102 /* ii */
1103 ISIS_FLAGS_SET_ALL (lsp->SRMflags);
1104 /* iii */
1105 ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
1106
1107 /* iv */
1108 if (circuit->circ_type != CIRCUIT_T_BROADCAST)
1109 ISIS_SET_FLAG (lsp->SSNflags, circuit);
1110 /* FIXME: v) */
1111 }
1112 /* 7.3.15.1 e) 2) LSP equal to the one in db */
1113 else if (comp == LSP_EQUAL) {
1114 ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
1115 lsp_update (lsp, hdr, circuit->rcv_stream, circuit->area);
1116 if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
1117 ISIS_SET_FLAG (lsp->SSNflags, circuit);
1118 }
1119 }
1120 /* 7.3.15.1 e) 3) LSP older than the one in db */
1121 else {
1122 ISIS_SET_FLAG(lsp->SRMflags, circuit);
1123 ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
1124 }
1125 }
1126 if (lsp)
1127 lsp->adj = adj;
1128 return retval;
1129}
1130
1131/*
1132 * Process Sequence Numbers
1133 * ISO - 10589
1134 * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU
1135 */
1136
1137int
1138process_snp (int snp_type, int level, struct isis_circuit *circuit,
1139 u_char *ssnpa)
1140{
1141 int retval = ISIS_OK;
1142 int cmp, own_lsp;
1143 char typechar = ' ';
1144 int len;
1145 struct isis_adjacency *adj;
1146 struct isis_complete_seqnum_hdr *chdr = NULL;
1147 struct isis_partial_seqnum_hdr *phdr = NULL;
1148 uint32_t found = 0, expected = 0;
1149 struct isis_lsp *lsp;
1150 struct lsp_entry *entry;
1151 struct listnode *node,*node2;
1152 struct tlvs tlvs;
1153 struct list *lsp_list = NULL;
1154 struct isis_passwd *passwd;
1155
1156 if (snp_type == ISIS_SNP_CSNP_FLAG) {
1157 /* getting the header info */
1158 typechar = 'C';
1159 chdr = (struct isis_complete_seqnum_hdr*)STREAM_PNT(circuit->rcv_stream);
1160 circuit->rcv_stream->getp += ISIS_CSNP_HDRLEN;
1161 len = ntohs(chdr->pdu_len);
1162 if (len < ISIS_CSNP_HDRLEN) {
1163 zlog_warn ("Received a CSNP with bogus length!");
1164 return ISIS_OK;
1165 }
1166 } else {
1167 typechar = 'P';
1168 phdr = (struct isis_partial_seqnum_hdr*)STREAM_PNT(circuit->rcv_stream);
1169 circuit->rcv_stream->getp += ISIS_PSNP_HDRLEN;
1170 len = ntohs(phdr->pdu_len);
1171 if (len < ISIS_PSNP_HDRLEN) {
1172 zlog_warn ("Received a CSNP with bogus length!");
1173 return ISIS_OK;
1174 }
1175 }
1176
1177 /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */
1178 if (circuit->ext_domain) {
1179
1180 zlog_info ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1181 "skipping: circuit externalDomain = true",
1182 circuit->area->area_tag,
1183 level,
1184 typechar,
1185 circuit->interface->name);
1186
1187 return ISIS_OK;
1188 }
1189
1190 /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
1191 if (!accept_level (level, circuit->circuit_is_type)) {
1192
1193 zlog_info ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1194 "skipping: circuit type %s does not match level %d",
1195 circuit->area->area_tag,
1196 level,
1197 typechar,
1198 circuit->interface->name,
1199 circuit_t2string (circuit->circuit_is_type),
1200 level);
1201
1202 return ISIS_OK;
1203 }
1204
1205 /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */
1206 if ((snp_type == ISIS_SNP_PSNP_FLAG) &&
1207 (circuit->circ_type == CIRCUIT_T_BROADCAST)) {
1208 if (!circuit->u.bc.is_dr[level-1]) {
1209
1210 zlog_info ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
1211 "skipping: we are not the DIS",
1212 circuit->area->area_tag,
1213 level,
1214 typechar,
1215 snpa_print(ssnpa),
1216 circuit->interface->name);
1217
1218 return ISIS_OK;
1219 }
1220 }
1221
1222 /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */
1223
1224 /* 7.3.15.2 a) 6 - maximum area match, can be ommited since we only use 3
1225 * - already checked */
1226
1227 /* 7.3.15.2 a) 7 - Must check that we have an adjacency of the same level */
1228 /* for broadcast circuits, snpa should be compared */
1229 /* FIXME : Do we need to check SNPA? */
1230 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
1231 if (snp_type == ISIS_SNP_CSNP_FLAG) {
1232 adj = isis_adj_lookup (chdr->source_id, circuit->u.bc.adjdb[level - 1]);
1233 } else {
1234 /* a psnp on a broadcast, how lovely of Juniper :) */
1235 adj = isis_adj_lookup (phdr->source_id, circuit->u.bc.adjdb[level - 1]);
1236 }
1237 if (!adj)
1238 return ISIS_OK; /* Silently discard */
1239 } else {
1240 if (!circuit->u.p2p.neighbor)
1241 return ISIS_OK; /* Silently discard */
1242 }
1243
1244 /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */
1245
1246 /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */
1247
1248 memset (&tlvs, 0, sizeof (struct tlvs));
1249
1250 /* parse the SNP */
1251 expected |= TLVFLAG_LSP_ENTRIES;
1252 expected |= TLVFLAG_AUTH_INFO;
1253 retval = parse_tlvs (circuit->area->area_tag,
1254 STREAM_PNT(circuit->rcv_stream),
1255 len - circuit->rcv_stream->getp,
1256 &expected,
1257 &found,
1258 &tlvs);
1259
1260 if (retval > ISIS_WARNING) {
1261 zlog_warn ("something went very wrong processing SNP");
1262 free_tlvs (&tlvs);
1263 return retval;
1264 }
1265
1266 (level == 1) ? (passwd = &circuit->area->area_passwd) :
1267 (passwd = &circuit->area->domain_passwd);
1268 if (passwd->type) {
1269 if (!(found & TLVFLAG_AUTH_INFO) ||
1270 authentication_check (passwd, &tlvs.auth_info)) {
1271 isis_event_auth_failure (circuit->area->area_tag, "SNP authentication"
1272 " failure", phdr ?
1273 phdr->source_id : chdr->source_id);
1274 return ISIS_OK;
1275 }
1276 }
1277
1278 /* debug isis snp-packets */
1279 if (isis->debugs & DEBUG_SNP_PACKETS) {
1280 zlog_info ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s",
1281 circuit->area->area_tag,
1282 level,
1283 typechar,
1284 snpa_print(ssnpa),
1285 circuit->interface->name);
1286 if (tlvs.lsp_entries) {
1287 LIST_LOOP (tlvs.lsp_entries,entry,node) {
1288 zlog_info("ISIS-Snp (%s): %cSNP entry %s, seq 0x%08x,"
1289 " cksum 0x%04x, lifetime %us",
1290 circuit->area->area_tag,
1291 typechar,
1292 rawlspid_print (entry->lsp_id),
1293 ntohl (entry->seq_num),
1294 ntohs (entry->checksum),
1295 ntohs (entry->rem_lifetime));
1296 }
1297 }
1298 }
1299
1300 /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */
1301 if (tlvs.lsp_entries) {
1302 LIST_LOOP (tlvs.lsp_entries, entry, node) {
1303 lsp = lsp_search (entry->lsp_id, circuit->area->lspdb[level - 1]);
1304 own_lsp = !memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
1305 if (lsp) {
1306 /* 7.3.15.2 b) 1) is this LSP newer */
1307 cmp = lsp_compare (circuit->area->area_tag, lsp, entry->seq_num,
1308 entry->checksum, entry->rem_lifetime);
1309 /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */
1310 if (cmp == LSP_EQUAL) {
1311 if (circuit->circ_type != CIRCUIT_T_BROADCAST)
1312 ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
1313 /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
1314 } else if (cmp == LSP_OLDER) {
1315 ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
1316 ISIS_SET_FLAG (lsp->SRMflags, circuit);
1317 } else {
1318 /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM on p2p*/
1319 if (own_lsp) {
1320 lsp_inc_seqnum (lsp, ntohl (entry->seq_num));
1321 ISIS_SET_FLAG (lsp->SRMflags, circuit);
1322 } else {
1323 ISIS_SET_FLAG (lsp->SSNflags, circuit);
1324 if (circuit->circ_type != CIRCUIT_T_BROADCAST)
1325 ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
1326 }
1327 }
1328 } else {
1329 /* 7.3.15.2 b) 5) if it was not found, and all of those are not 0,
1330 * insert it and set SSN on it */
1331 if (entry->rem_lifetime && entry->checksum && entry->seq_num &&
1332 memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN)) {
1333 lsp = lsp_new (entry->lsp_id, ntohs (entry->rem_lifetime),
1334 0, 0, entry->checksum, level);
1335 lsp_insert (lsp, circuit->area->lspdb[level - 1]);
1336 ISIS_SET_FLAG (lsp->SSNflags, circuit);
1337 }
1338 }
1339 }
1340 }
1341
1342 /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported */
1343 if (snp_type == ISIS_SNP_CSNP_FLAG) {
1344 /*
1345 * Build a list from our own LSP db bounded with start_ and stop_lsp_id
1346 */
1347 lsp_list = list_new ();
1348 lsp_build_list_nonzero_ht (chdr->start_lsp_id, chdr->stop_lsp_id,
1349 lsp_list, circuit->area->lspdb[level - 1]);
1350
1351 /* Fixme: Find a better solution */
1352 if (tlvs.lsp_entries) {
1353 LIST_LOOP (tlvs.lsp_entries, entry, node) {
1354 LIST_LOOP (lsp_list, lsp, node2) {
1355 if (lsp_id_cmp (lsp->lsp_header->lsp_id, entry->lsp_id) == 0) {
1356 list_delete_node (lsp_list, node2);
1357 break;
1358 }
1359 }
1360 }
1361 }
1362 /* on remaining LSPs we set SRM (neighbor knew not of) */
1363 LIST_LOOP (lsp_list, lsp, node2) {
1364 ISIS_SET_FLAG (lsp->SRMflags, circuit);
1365 }
1366 /* lets free it */
1367 list_free (lsp_list);
1368 }
1369
1370 free_tlvs (&tlvs);
1371 return retval;
1372}
1373
1374int
1375process_csnp (int level, struct isis_circuit *circuit, u_char *ssnpa)
1376{
1377
1378 /* Sanity check - FIXME: move to correct place */
1379 if ((stream_get_endp (circuit->rcv_stream) -
1380 stream_get_getp (circuit->rcv_stream)) < ISIS_CSNP_HDRLEN) {
1381 zlog_warn ("Packet too short ( < %d)", ISIS_CSNP_HDRLEN);
1382 return ISIS_WARNING;
1383 }
1384
1385 return process_snp (ISIS_SNP_CSNP_FLAG, level, circuit, ssnpa);
1386}
1387
1388int
1389process_psnp (int level, struct isis_circuit *circuit, u_char *ssnpa)
1390{
1391
1392 if ((stream_get_endp (circuit->rcv_stream) -
1393 stream_get_getp (circuit->rcv_stream)) < ISIS_PSNP_HDRLEN) {
1394 zlog_warn ("Packet too short");
1395 return ISIS_WARNING;
1396 }
1397
1398 return process_snp (ISIS_SNP_PSNP_FLAG, level, circuit, ssnpa);
1399}
1400
1401
1402
1403/*
1404 * Process ISH
1405 * ISO - 10589
1406 * Section 8.2.2 - Receiving ISH PDUs by an intermediate system
1407 * FIXME: sample packet dump, need to figure 0x81 - looks like NLPid
1408 0x82 0x15 0x01 0x00 0x04 0x01 0x2c 0x59
1409 0x38 0x08 0x47 0x00 0x01 0x00 0x02 0x00
1410 0x03 0x00 0x81 0x01 0xcc
1411 */
1412int
1413process_is_hello (struct isis_circuit *circuit)
1414{
1415 struct isis_adjacency *adj;
1416 int retval = ISIS_OK;
1417 u_char neigh_len;
1418 u_char *sysid;
1419
1420 /* In this point in time we are not yet able to handle is_hellos
1421 * on lan - Sorry juniper...
1422 */
1423 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
1424 return retval;
1425
1426 neigh_len = stream_getc (circuit->rcv_stream);
1427 sysid = STREAM_PNT(circuit->rcv_stream) + neigh_len - 1 - ISIS_SYS_ID_LEN;
1428 adj = circuit->u.p2p.neighbor;
1429 if (!adj) {
1430 /* 8.2.2 */
1431 adj = isis_new_adj (sysid, " ", 0, circuit);
1432 if (adj == NULL)
1433 return ISIS_ERROR;
1434
1435 isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
1436 adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
1437 circuit->u.p2p.neighbor = adj;
1438 }
1439 /* 8.2.2 a)*/
1440 if ((adj->adj_state == ISIS_ADJ_UP) && memcmp (adj->sysid,sysid,
1441 ISIS_SYS_ID_LEN)) {
1442 /* 8.2.2 a) 1) FIXME: adjStateChange(down) event */
1443 /* 8.2.2 a) 2) delete the adj */
1444 XFREE (MTYPE_ISIS_ADJACENCY, adj);
1445 /* 8.2.2 a) 3) create a new adj */
1446 adj = isis_new_adj (sysid, " ", 0, circuit);
1447 if (adj == NULL)
1448 return ISIS_ERROR;
1449
1450 /* 8.2.2 a) 3) i */
1451 isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
1452 /* 8.2.2 a) 3) ii */
1453 adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
1454 /* 8.2.2 a) 4) quite meaningless */
1455 }
1456 /* 8.2.2 b) ignore on condition */
1457 if ((adj->adj_state == ISIS_ADJ_INITIALIZING) &&
1458 (adj->sys_type == ISIS_SYSTYPE_IS)) {
1459 /* do nothing */
1460 } else {
1461 /* 8.2.2 c) respond with a p2p IIH */
1462 send_hello (circuit, 1);
1463 }
1464 /* 8.2.2 d) type is IS */
1465 adj->sys_type = ISIS_SYSTYPE_IS;
1466 /* 8.2.2 e) FIXME: Circuit type of? */
1467
1468
1469 return retval;
1470}
1471
1472
1473/*
1474 * PDU Dispatcher
1475 */
1476
1477int
1478isis_handle_pdu (struct isis_circuit *circuit, u_char *ssnpa)
1479{
1480
1481 struct isis_fixed_hdr *hdr;
1482 struct esis_fixed_hdr *esis_hdr;
1483
1484 int retval=ISIS_OK;
1485
1486 /*
1487 * Let's first read data from stream to the header
1488 */
1489 hdr = (struct isis_fixed_hdr*)STREAM_DATA(circuit->rcv_stream);
1490
1491 if ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS)){
1492 zlog_warn ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp);
1493 return ISIS_ERROR;
1494 }
1495
1496 /* now we need to know if this is an ISO 9542 packet and
1497 * take real good care of it, waaa!
1498 */
1499 if (hdr->idrp == ISO9542_ESIS){
1500 esis_hdr = (struct esis_fixed_hdr*)STREAM_DATA(circuit->rcv_stream);
1501 stream_set_getp (circuit->rcv_stream, ESIS_FIXED_HDR_LEN);
1502 /* FIXME: Need to do some acceptence tests */
1503 /* example length... */
1504 switch (esis_hdr->pdu_type) {
1505 case ESH_PDU:
1506 /* FIXME */
1507 break;
1508 case ISH_PDU:
1509 zlog_info ("AN ISH PDU!!");
1510 retval = process_is_hello (circuit);
1511 break;
1512 default:
1513 return ISIS_ERROR;
1514 }
1515 return retval;
1516 } else {
1517 stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN);
1518 }
1519 /*
1520 * and then process it
1521 */
1522
1523 if (hdr->length < ISIS_MINIMUM_FIXED_HDR_LEN) {
1524 zlog_err ("Fixed header length = %d", hdr->length);
1525 return ISIS_ERROR;
1526 }
1527
1528 if (hdr->version1 != 1) {
1529 zlog_warn ("Unsupported ISIS version %u", hdr->version1);
1530 return ISIS_WARNING;
1531 }
1532 /* either 6 or 0 */
1533 if ((hdr->id_len != 0) && (hdr->id_len != ISIS_SYS_ID_LEN)) {
1534 zlog_err ("IDFieldLengthMismatch: ID Length field in a received PDU %u, "
1535 "while the parameter for this IS is %u", hdr->id_len,
1536 ISIS_SYS_ID_LEN);
1537 return ISIS_ERROR;
1538 }
1539
1540 if (hdr->version2 != 1) {
1541 zlog_warn ("Unsupported ISIS version %u", hdr->version2);
1542 return ISIS_WARNING;
1543 }
1544 /* either 3 or 0 */
1545 if ((hdr->max_area_addrs != 0) && (hdr->max_area_addrs != isis->max_area_addrs)) {
1546 zlog_err ("maximumAreaAddressesMismatch: maximumAreaAdresses in a "
1547 "received PDU %u while the parameter for this IS is %u",
1548 hdr->max_area_addrs, isis->max_area_addrs);
1549 return ISIS_ERROR;
1550 }
1551
1552 switch (hdr->pdu_type) {
1553 case L1_LAN_HELLO:
1554 retval = process_lan_hello (ISIS_LEVEL1, circuit, ssnpa);
1555 break;
1556 case L2_LAN_HELLO:
1557 retval = process_lan_hello (ISIS_LEVEL2, circuit, ssnpa);
1558 break;
1559 case P2P_HELLO:
1560 retval = process_p2p_hello (circuit);
1561 break;
1562 case L1_LINK_STATE:
1563 retval = process_lsp (ISIS_LEVEL1, circuit, ssnpa);
1564 break;
1565 case L2_LINK_STATE:
1566 retval = process_lsp (ISIS_LEVEL2, circuit, ssnpa);
1567 break;
1568 case L1_COMPLETE_SEQ_NUM:
1569 retval = process_csnp (ISIS_LEVEL1, circuit, ssnpa);
1570 break;
1571 case L2_COMPLETE_SEQ_NUM:
1572 retval = process_csnp (ISIS_LEVEL2, circuit, ssnpa);
1573 break;
1574 case L1_PARTIAL_SEQ_NUM:
1575 retval = process_psnp (ISIS_LEVEL1, circuit, ssnpa);
1576 break;
1577 case L2_PARTIAL_SEQ_NUM:
1578 retval = process_psnp (ISIS_LEVEL2, circuit, ssnpa);
1579 break;
1580 default:
1581 return ISIS_ERROR;
1582 }
1583
1584 return retval;
1585}
1586
1587
1588#ifdef GNU_LINUX
1589int
1590isis_receive (struct thread *thread)
1591{
1592
1593 struct isis_circuit *circuit;
1594 u_char ssnpa[ETH_ALEN];
1595 int retval;
1596
1597 /*
1598 * Get the circuit
1599 */
1600 circuit = THREAD_ARG (thread);
1601 assert (circuit);
1602
1603 if (circuit->rcv_stream == NULL)
1604 circuit->rcv_stream = stream_new (ISO_MTU(circuit));
1605 else
1606 stream_reset (circuit->rcv_stream);
1607
1608 retval = circuit->rx (circuit, ssnpa);
1609 circuit->t_read = NULL;
1610
1611 if (retval == ISIS_OK)
1612 retval = isis_handle_pdu (circuit, ssnpa);
1613
1614 /*
1615 * prepare for next packet.
1616 */
1617 circuit->t_read = thread_add_read (master, isis_receive, circuit,
1618 circuit->fd);
1619
1620 return retval;
1621}
1622
1623#else
1624int
1625isis_receive (struct thread *thread)
1626{
1627
1628 struct isis_circuit *circuit;
1629 u_char ssnpa[ETH_ALEN];
1630 int retval;
1631
1632 /*
1633 * Get the circuit
1634 */
1635 circuit = THREAD_ARG (thread);
1636 assert (circuit);
1637
1638 circuit->t_read = NULL;
1639
1640 if (circuit->rcv_stream == NULL)
1641 circuit->rcv_stream = stream_new (ISO_MTU(circuit));
1642 else
1643 stream_reset (circuit->rcv_stream);
1644
1645 retval = circuit->rx (circuit, ssnpa);
1646
1647 if (retval == ISIS_OK)
1648 retval = isis_handle_pdu (circuit, ssnpa);
1649
1650 /*
1651 * prepare for next packet.
1652 */
1653 circuit->t_read = thread_add_timer_msec (master, isis_receive, circuit,
1654 listcount
1655 (circuit->area->circuit_list)*100);
1656
1657
1658 return retval;
1659}
1660
1661#endif
1662
1663 /* filling of the fixed isis header */
1664void
1665fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type)
1666{
1667 memset (hdr, 0, sizeof (struct isis_fixed_hdr));
1668
1669 hdr->idrp = ISO10589_ISIS;
1670
1671 switch (pdu_type) {
1672 case L1_LAN_HELLO:
1673 case L2_LAN_HELLO:
1674 hdr->length = ISIS_LANHELLO_HDRLEN;
1675 break;
1676 case P2P_HELLO:
1677 hdr->length = ISIS_P2PHELLO_HDRLEN;
1678 break;
1679 case L1_LINK_STATE:
1680 case L2_LINK_STATE:
1681 hdr->length = ISIS_LSP_HDR_LEN;
1682 break;
1683 case L1_COMPLETE_SEQ_NUM:
1684 case L2_COMPLETE_SEQ_NUM:
1685 hdr->length = ISIS_CSNP_HDRLEN;
1686 break;
1687 case L1_PARTIAL_SEQ_NUM:
1688 case L2_PARTIAL_SEQ_NUM:
1689 hdr->length = ISIS_PSNP_HDRLEN;
1690 break;
1691 default:
1692 zlog_warn ("fill_fixed_hdr(): unknown pdu type %d", pdu_type);
1693 return;
1694 }
1695 hdr->length += ISIS_FIXED_HDR_LEN;
1696 hdr->pdu_type = pdu_type;
1697 hdr->version1 = 1;
1698 hdr->id_len = 0; /* ISIS_SYS_ID_LEN - 0==6 */
1699 hdr->version2 = 1;
1700 hdr->max_area_addrs = 0; /* isis->max_area_addrs - 0==3 */
1701}
1702
1703
1704/*
1705 * SEND SIDE
1706 */
1707void
1708fill_fixed_hdr_andstream (struct isis_fixed_hdr *hdr, u_char pdu_type,
1709 struct stream *stream)
1710{
1711 fill_fixed_hdr (hdr,pdu_type);
1712
1713 stream_putc (stream, hdr->idrp);
1714 stream_putc (stream, hdr->length);
1715 stream_putc (stream, hdr->version1);
1716 stream_putc (stream, hdr->id_len);
1717 stream_putc (stream, hdr->pdu_type);
1718 stream_putc (stream, hdr->version2);
1719 stream_putc (stream, hdr->reserved);
1720 stream_putc (stream, hdr->max_area_addrs);
1721
1722 return;
1723}
1724
1725
1726int
1727send_hello (struct isis_circuit *circuit, int level)
1728{
1729 struct isis_fixed_hdr fixed_hdr;
1730 struct isis_lan_hello_hdr hello_hdr;
1731 struct isis_p2p_hello_hdr p2p_hello_hdr;
1732
1733 u_int32_t interval;
1734 unsigned long len_pointer, length;
1735 int retval;
1736
1737 if (circuit->interface->mtu == 0) {
1738 zlog_warn ("circuit has zero MTU");
1739 return ISIS_WARNING;
1740 }
1741
1742 if (!circuit->snd_stream)
1743 circuit->snd_stream = stream_new (ISO_MTU(circuit));
1744 else
1745 stream_reset (circuit->snd_stream);
1746
1747 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
1748 if (level == 1)
1749 fill_fixed_hdr_andstream(&fixed_hdr, L1_LAN_HELLO, circuit->snd_stream);
1750 else
1751 fill_fixed_hdr_andstream(&fixed_hdr, L2_LAN_HELLO, circuit->snd_stream);
1752 else
1753 fill_fixed_hdr_andstream(&fixed_hdr, P2P_HELLO, circuit->snd_stream);
1754
1755 /*
1756 * Fill LAN Level 1 or 2 Hello PDU header
1757 */
1758 memset (&hello_hdr, 0, sizeof (struct isis_lan_hello_hdr));
1759 interval = circuit->hello_multiplier[level - 1] *
1760 circuit->hello_interval[level - 1];
1761 if (interval > USHRT_MAX)
1762 interval = USHRT_MAX;
1763 hello_hdr.circuit_t = circuit->circuit_is_type;
1764 memcpy (hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN);
1765 hello_hdr.hold_time = htons((u_int16_t)interval);
1766
1767 hello_hdr.pdu_len = 0; /* Update the PDU Length later */
1768 len_pointer = stream_get_putp (circuit->snd_stream) + 3 + ISIS_SYS_ID_LEN;
1769
1770
1771 /* copy the shared part of the hello to the p2p hello if needed */
1772 if (circuit->circ_type == CIRCUIT_T_P2P) {
1773 memcpy (&p2p_hello_hdr, &hello_hdr, 5 + ISIS_SYS_ID_LEN);
1774 p2p_hello_hdr.local_id = circuit->circuit_id;
1775 /* FIXME: need better understanding */
1776 stream_put (circuit->snd_stream, &p2p_hello_hdr, ISIS_P2PHELLO_HDRLEN);
1777 } else {
1778 hello_hdr.prio = circuit->u.bc.priority[level - 1];
1779 if(level == 1 && circuit->u.bc.l1_desig_is) {
1780 memcpy(hello_hdr.lan_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
1781 } else if (level == 2 && circuit->u.bc.l2_desig_is){
1782 memcpy(hello_hdr.lan_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
1783 }
1784 stream_put (circuit->snd_stream, &hello_hdr, ISIS_LANHELLO_HDRLEN);
1785 }
1786
1787 /*
1788 * Then the variable length part
1789 */
1790 /* add circuit password */
1791 if (circuit->passwd.type)
1792 if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len,
1793 circuit->passwd.passwd, circuit->snd_stream))
1794 return ISIS_WARNING;
1795 /* Area Addresses TLV */
1796 assert (circuit->area);
1797 if (circuit->area->area_addrs && circuit->area->area_addrs->count > 0)
1798 if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream))
1799 return ISIS_WARNING;
1800
1801 /* LAN Neighbors TLV */
1802 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
1803 if (level == 1 && circuit->u.bc.lan_neighs[0]->count > 0)
1804 if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0],
1805 circuit->snd_stream))
1806 return ISIS_WARNING;
1807 if (level == 2 && circuit->u.bc.lan_neighs[1]->count > 0)
1808 if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1],
1809 circuit->snd_stream))
1810 return ISIS_WARNING;
1811 }
1812
1813 /* Protocols Supported TLV */
1814 if (circuit->nlpids.count > 0)
1815 if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream))
1816 return ISIS_WARNING;
1817 /* IP interface Address TLV */
1818 if (circuit->ip_router && circuit->ip_addrs && circuit->ip_addrs->count > 0)
1819 if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream))
1820 return ISIS_WARNING;
1821
1822#ifdef HAVE_IPV6
1823 /* IPv6 Interface Address TLV */
1824 if (circuit->ipv6_router && circuit->ipv6_link &&
1825 circuit->ipv6_link->count > 0)
1826 if (tlv_add_ipv6_addrs (circuit->ipv6_link, circuit->snd_stream))
1827 return ISIS_WARNING;
1828#endif /* HAVE_IPV6 */
1829
1830 if (circuit->u.bc.pad_hellos)
1831 if (tlv_add_padding (circuit->snd_stream))
1832 return ISIS_WARNING;
1833
1834 length = stream_get_putp (circuit->snd_stream);
1835 /* Update PDU length */
1836 stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t)length);
1837
1838 retval = circuit->tx (circuit, level);
1839 if (retval)
1840 zlog_warn ("sending of LAN Level %d Hello failed", level);
1841
1842 /* DEBUG_ADJ_PACKETS */
1843 if (isis->debugs & DEBUG_ADJ_PACKETS) {
1844 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
1845 zlog_info ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %ld",
1846 circuit->area->area_tag, level, circuit->interface->name,
1847 STREAM_SIZE(circuit->snd_stream));
1848 } else {
1849 zlog_info ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld",
1850 circuit->area->area_tag, circuit->interface->name,
1851 STREAM_SIZE(circuit->snd_stream));
1852 }
1853 }
1854
1855
1856 return retval;
1857}
1858
1859int
1860send_lan_hello (struct isis_circuit *circuit, int level)
1861{
1862 return send_hello (circuit,level);
1863}
1864
1865int
1866send_lan_l1_hello (struct thread *thread)
1867{
1868
1869 struct isis_circuit *circuit;
1870 int retval;
1871
1872 circuit = THREAD_ARG (thread);
1873 assert (circuit);
1874 circuit->u.bc.t_send_lan_hello[0] = NULL;
1875
1876 if (circuit->u.bc.run_dr_elect[0])
1877 retval = isis_dr_elect (circuit, 1);
1878
1879 retval = send_lan_hello (circuit, 1);
1880
1881 /* set next timer thread */
1882 circuit->u.bc.t_send_lan_hello[0] =
1883 thread_add_timer (master, send_lan_l1_hello, circuit,
1884 isis_jitter (circuit->hello_interval[0], IIH_JITTER));
1885
1886 return retval;
1887}
1888
1889int
1890send_lan_l2_hello (struct thread *thread)
1891{
1892 struct isis_circuit *circuit;
1893 int retval;
1894
1895 circuit = THREAD_ARG (thread);
1896 assert (circuit);
1897 circuit->u.bc.t_send_lan_hello[1] = NULL;
1898
1899 if (circuit->u.bc.run_dr_elect[1])
1900 retval = isis_dr_elect (circuit, 2);
1901
1902 retval = send_lan_hello (circuit, 2);
1903
1904 /* set next timer thread*/
1905 circuit->u.bc.t_send_lan_hello[1] =
1906 thread_add_timer (master, send_lan_l2_hello, circuit,
1907 isis_jitter (circuit->hello_interval[1], IIH_JITTER));
1908
1909 return retval;
1910}
1911
1912int
1913send_p2p_hello (struct thread *thread)
1914{
1915 struct isis_circuit *circuit;
1916
1917 circuit = THREAD_ARG (thread);
1918 assert (circuit);
1919 circuit->u.p2p.t_send_p2p_hello = NULL;
1920
1921 send_hello(circuit,1);
1922
1923 /* set next timer thread*/
1924 circuit->u.p2p.t_send_p2p_hello = thread_add_timer
1925 (master, send_p2p_hello, circuit, isis_jitter (circuit->hello_interval[1],
1926 IIH_JITTER));
1927
1928 return ISIS_OK;
1929}
1930
1931int
1932build_csnp (int level, u_char *start, u_char *stop, struct list *lsps,
1933 struct isis_circuit *circuit)
1934{
1935 struct isis_fixed_hdr fixed_hdr;
1936 struct isis_passwd *passwd;
1937 int retval = ISIS_OK;
1938 unsigned long lenp;
1939 u_int16_t length;
1940
1941 if (level ==1)
1942 fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM,
1943 circuit->snd_stream);
1944 else
1945 fill_fixed_hdr_andstream (&fixed_hdr, L2_COMPLETE_SEQ_NUM,
1946 circuit->snd_stream);
1947
1948 /*
1949 * Fill Level 1 or 2 Complete Sequence Numbers header
1950 */
1951
1952 lenp = stream_get_putp (circuit->snd_stream);
1953 stream_putw (circuit->snd_stream, 0); /* PDU length - when we know it */
1954 /* no need to send the source here, it is always us if we csnp */
1955 stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
1956 /* with zero circuit id - ref 9.10, 9.11 */
1957 stream_putc (circuit->snd_stream, 0x00);
1958
1959 stream_put (circuit->snd_stream, start, ISIS_SYS_ID_LEN + 2);
1960 stream_put (circuit->snd_stream, stop, ISIS_SYS_ID_LEN + 2);
1961
1962 /*
1963 * And TLVs
1964 */
1965 if (level == 1)
1966 passwd = &circuit->area->area_passwd;
1967 else
1968 passwd = &circuit->area->domain_passwd;
1969
1970 if (passwd->type)
1971 retval = tlv_add_authinfo (passwd->type, passwd->len,
1972 passwd->passwd, circuit->snd_stream);
1973
1974 if (!retval && lsps) {
1975 retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
1976 }
1977 length = (u_int16_t)stream_get_putp (circuit->snd_stream);
1978 assert (length >= ISIS_CSNP_HDRLEN);
1979 /* Update PU length */
1980 stream_putw_at (circuit->snd_stream, lenp, length);
1981
1982 return retval;
1983}
1984
1985/*
1986 * FIXME: support multiple CSNPs
1987 */
1988
1989int
1990send_csnp (struct isis_circuit *circuit, int level)
1991{
1992 int retval = ISIS_OK;
1993 u_char start[ISIS_SYS_ID_LEN + 2];
1994 u_char stop[ISIS_SYS_ID_LEN + 2];
1995 struct list *list = NULL;
1996 struct listnode *node;
1997 struct isis_lsp *lsp;
1998
1999 memset (start,0x00, ISIS_SYS_ID_LEN + 2);
2000 memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
2001
2002 if (circuit->area->lspdb[level-1] &&
2003 dict_count (circuit->area->lspdb[level-1]) > 0) {
2004 list = list_new ();
2005 lsp_build_list (start, stop, list, circuit->area->lspdb[level-1]);
2006
2007 if (circuit->snd_stream == NULL)
2008 circuit->snd_stream = stream_new (ISO_MTU(circuit));
2009 else
2010 stream_reset (circuit->snd_stream);
2011
2012 retval = build_csnp (level, start, stop, list, circuit);
2013
2014 if (isis->debugs & DEBUG_SNP_PACKETS) {
2015 zlog_info ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld",
2016 circuit->area->area_tag, level, circuit->interface->name,
2017 STREAM_SIZE(circuit->snd_stream));
2018 LIST_LOOP (list, lsp, node) {
2019 zlog_info("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x,"
2020 " cksum 0x%04x, lifetime %us",
2021 circuit->area->area_tag,
2022 rawlspid_print (lsp->lsp_header->lsp_id),
2023 ntohl (lsp->lsp_header->seq_num),
2024 ntohs (lsp->lsp_header->checksum),
2025 ntohs (lsp->lsp_header->rem_lifetime));
2026 }
2027 }
2028
2029 list_delete (list);
2030
2031 if (retval == ISIS_OK)
2032 retval = circuit->tx (circuit, level);
2033 }
2034 return retval;
2035}
2036
2037int
2038send_l1_csnp (struct thread *thread)
2039{
2040 struct isis_circuit *circuit;
2041 int retval = ISIS_OK;
2042
2043 circuit = THREAD_ARG (thread);
2044 assert (circuit);
2045
2046 circuit->t_send_csnp[0] = NULL;
2047
2048 if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[0]) {
2049 send_csnp(circuit,1);
2050 }
2051 /* set next timer thread */
2052 circuit->t_send_csnp[0] = thread_add_timer (master,
2053 send_l1_csnp,
2054 circuit,
2055 isis_jitter
2056 (circuit->csnp_interval[0],
2057 CSNP_JITTER));
2058
2059 return retval;
2060}
2061
2062int
2063send_l2_csnp (struct thread *thread)
2064{
2065 struct isis_circuit *circuit;
2066 int retval = ISIS_OK;
2067
2068 circuit = THREAD_ARG (thread);
2069 assert (circuit);
2070
2071 circuit->t_send_csnp[1] = NULL;
2072
2073 if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[1]) {
2074 send_csnp(circuit,2);
2075 }
2076 /* set next timer thread */
2077 circuit->t_send_csnp[1] = thread_add_timer (master,
2078 send_l2_csnp,
2079 circuit,
2080 isis_jitter
2081 (circuit->csnp_interval[1],
2082 CSNP_JITTER));
2083 return retval;
2084}
2085
2086int
2087build_psnp (int level, struct isis_circuit *circuit, struct list *lsps)
2088{
2089 struct isis_fixed_hdr fixed_hdr;
2090 unsigned long lenp;
2091 u_int16_t length;
2092 int retval = 0;
2093 struct isis_lsp *lsp;
2094 struct isis_passwd *passwd;
2095 struct listnode *node;
2096
2097 if (level == 1)
2098 fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
2099 circuit->snd_stream);
2100 else
2101 fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM,
2102 circuit->snd_stream);
2103
2104 /*
2105 * Fill Level 1 or 2 Partial Sequence Numbers header
2106 */
2107 lenp = stream_get_putp (circuit->snd_stream);
2108 stream_putw (circuit->snd_stream, 0); /* PDU length - when we know it */
2109 stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
2110 stream_putc (circuit->snd_stream, circuit->idx);
2111
2112 /*
2113 * And TLVs
2114 */
2115
2116 if (level == 1)
2117 passwd = &circuit->area->area_passwd;
2118 else
2119 passwd = &circuit->area->domain_passwd;
2120
2121 if (passwd->type)
2122 retval = tlv_add_authinfo (passwd->type, passwd->len,
2123 passwd->passwd, circuit->snd_stream);
2124
2125 if (!retval && lsps) {
2126 retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
2127 }
2128
2129 if (isis->debugs & DEBUG_SNP_PACKETS) {
2130 LIST_LOOP (lsps, lsp, node) {
2131 zlog_info("ISIS-Snp (%s): PSNP entry %s, seq 0x%08x,"
2132 " cksum 0x%04x, lifetime %us",
2133 circuit->area->area_tag,
2134 rawlspid_print (lsp->lsp_header->lsp_id),
2135 ntohl (lsp->lsp_header->seq_num),
2136 ntohs (lsp->lsp_header->checksum),
2137 ntohs (lsp->lsp_header->rem_lifetime));
2138 }
2139 }
2140
2141 length = (u_int16_t)stream_get_putp (circuit->snd_stream);
2142 assert (length >= ISIS_PSNP_HDRLEN);
2143 /* Update PDU length */
2144 stream_putw_at (circuit->snd_stream, lenp, length);
2145
2146 return ISIS_OK;
2147}
2148
2149/*
2150 * 7.3.15.4 action on expiration of partial SNP interval
2151 * level 1
2152 */
2153int
2154send_psnp (int level, struct isis_circuit *circuit)
2155{
2156 int retval = ISIS_OK;
2157 struct isis_lsp *lsp;
2158 struct list *list = NULL;
2159 struct listnode *node;
2160
2161 if ((circuit->circ_type == CIRCUIT_T_BROADCAST &&
2162 !circuit->u.bc.is_dr[level - 1]) ||
2163 circuit->circ_type != CIRCUIT_T_BROADCAST) {
2164
2165 if (circuit->area->lspdb[level-1] &&
2166 dict_count (circuit->area->lspdb[level-1]) > 0) {
2167 list = list_new ();
2168 lsp_build_list_ssn (circuit, list, circuit->area->lspdb[level-1]);
2169
2170 if (listcount(list) > 0) {
2171 if (circuit->snd_stream == NULL)
2172 circuit->snd_stream = stream_new (ISO_MTU(circuit));
2173 else
2174 stream_reset (circuit->snd_stream);
2175
2176
2177 if (isis->debugs & DEBUG_SNP_PACKETS)
2178 zlog_info ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld",
2179 circuit->area->area_tag, level, circuit->interface->name,
2180 STREAM_SIZE(circuit->snd_stream));
2181
2182 retval = build_psnp (level, circuit, list);
2183 if (retval == ISIS_OK)
2184 retval = circuit->tx (circuit, level);
2185
2186 if (retval == ISIS_OK) {
2187 /*
2188 * sending succeeded, we can clear SSN flags of this circuit
2189 * for the LSPs in list
2190 */
2191 for (node = listhead (list); node; nextnode(node)) {
2192 lsp = getdata (node);
2193 ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
2194 }
2195 }
2196 }
2197 list_delete (list);
2198 }
2199 }
2200
2201 return retval;
2202}
2203
2204int
2205send_l1_psnp (struct thread *thread)
2206{
2207
2208 struct isis_circuit *circuit;
2209 int retval = ISIS_OK;
2210
2211 circuit = THREAD_ARG (thread);
2212 assert (circuit);
2213
2214 circuit->t_send_psnp[0] = NULL;
2215
2216 send_psnp (1, circuit);
2217 /* set next timer thread */
2218 circuit->t_send_psnp[0] = thread_add_timer (master,
2219 send_l1_psnp,
2220 circuit,
2221 isis_jitter
2222 (circuit->psnp_interval[0],
2223 PSNP_JITTER));
2224
2225 return retval;
2226}
2227
2228/*
2229 * 7.3.15.4 action on expiration of partial SNP interval
2230 * level 2
2231 */
2232int
2233send_l2_psnp (struct thread *thread)
2234{
2235
2236 struct isis_circuit *circuit;
2237 int retval = ISIS_OK;
2238
2239 circuit = THREAD_ARG (thread);
2240 assert (circuit);
2241
2242 circuit->t_send_psnp[1] = NULL;
2243
2244 send_psnp (2, circuit);
2245
2246 /* set next timer thread */
2247 circuit->t_send_psnp[1] = thread_add_timer (master,
2248 send_l2_psnp,
2249 circuit,
2250 isis_jitter
2251 (circuit->psnp_interval[1],
2252 PSNP_JITTER));
2253
2254 return retval;
2255}
2256
2257
2258void
2259build_link_state (struct isis_lsp *lsp, struct isis_circuit *circuit,
2260 struct stream *stream)
2261{
2262 unsigned long length;
2263
2264 stream_put (stream, lsp->pdu, ntohs(lsp->lsp_header->pdu_len));
2265 length = stream_get_putp (stream);
2266
2267 return;
2268}
2269
2270
2271/*
2272 * ISO 10589 - 7.3.14.3
2273 */
2274int
2275send_lsp (struct thread *thread)
2276{
2277 struct isis_circuit *circuit;
2278 struct isis_lsp *lsp;
2279 struct listnode *node;
2280 int retval = 0;
2281
2282 circuit = THREAD_ARG (thread);
2283 assert (circuit);
2284
2285 if (circuit->state == C_STATE_UP) {
2286 node = listhead (circuit->lsp_queue);
2287 assert (node);
2288
2289 lsp = getdata (node);
2290
2291 /*
2292 * Do not send if levels do not match
2293 */
2294 if (!(lsp->level & circuit->circuit_is_type))
2295 goto dontsend;
2296
2297 /*
2298 * Do not send if we do not have adjacencies in state up on the circuit
2299 */
2300 if (circuit->upadjcount[lsp->level - 1] == 0)
2301 goto dontsend;
2302 /* only send if it needs sending */
2303 if ((time(NULL) - lsp->last_sent) >=
2304 circuit->area->lsp_gen_interval[lsp->level-1]) {
2305
2306 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
2307 zlog_info ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
2308 " lifetime %us on %s",
2309 circuit->area->area_tag,
2310 lsp->level,
2311 rawlspid_print (lsp->lsp_header->lsp_id),
2312 ntohl(lsp->lsp_header->seq_num),
2313 ntohs(lsp->lsp_header->checksum),
2314 ntohs(lsp->lsp_header->rem_lifetime),
2315 circuit->interface->name);
2316 }
2317 /* copy our lsp to the send buffer */
2318 circuit->snd_stream->getp = lsp->pdu->getp;
2319 circuit->snd_stream->putp = lsp->pdu->putp;
2320 circuit->snd_stream->endp = lsp->pdu->endp;
2321 memcpy (circuit->snd_stream->data, lsp->pdu->data, lsp->pdu->endp);
2322
2323 retval = circuit->tx (circuit, lsp->level);
2324
2325 /*
2326 * If the sending succeeded, we can del the lsp from circuits lsp_queue
2327 */
2328 if (retval == ISIS_OK) {
2329 list_delete_node (circuit->lsp_queue, node);
2330
2331 /*
2332 * On broadcast circuits also the SRMflag can be cleared
2333 */
2334 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
2335 ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
2336
2337 if (flags_any_set (lsp->SRMflags) == 0) {
2338 /*
2339 * need to remember when we were last sent
2340 */
2341 lsp->last_sent = time (NULL);
2342 }
2343 } else {
2344 zlog_info ("sending of level %d link state failed", lsp->level);
2345 }
2346 } else {
2347 /* my belief is that if it wasn't his time, the lsp can be removed
2348 * from the queue
2349 */
2350 dontsend:
2351 list_delete_node (circuit->lsp_queue, node);
2352 }
2353#if 0
2354 /*
2355 * If there are still LSPs send next one after lsp-interval (33 msecs)
2356 */
2357 if (listcount (circuit->lsp_queue) > 0)
2358 thread_add_timer (master, send_lsp, circuit,
2359 1);
2360#endif
2361 }
2362
2363 return retval;
2364}
2365
2366int
2367ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit,
2368 int level)
2369{
2370 unsigned long lenp;
2371 int retval;
2372 u_int16_t length;
2373 struct isis_fixed_hdr fixed_hdr;
2374
2375 if (!circuit->snd_stream)
2376 circuit->snd_stream = stream_new (ISO_MTU(circuit));
2377 else
2378 stream_reset (circuit->snd_stream);
2379
2380// fill_llc_hdr (stream);
2381 if (level == 1)
2382 fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
2383 circuit->snd_stream);
2384 else
2385 fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM,
2386 circuit->snd_stream);
2387
2388
2389 lenp = stream_get_putp (circuit->snd_stream);
2390 stream_putw (circuit->snd_stream, 0); /* PDU length */
2391 stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
2392 stream_putc (circuit->snd_stream, circuit->idx);
2393 stream_putc (circuit->snd_stream, 9); /* code */
2394 stream_putc (circuit->snd_stream, 16); /* len */
2395
2396 stream_putw (circuit->snd_stream, ntohs(hdr->rem_lifetime));
2397 stream_put (circuit->snd_stream, hdr->lsp_id, ISIS_SYS_ID_LEN + 2);
2398 stream_putl (circuit->snd_stream, ntohl(hdr->seq_num));
2399 stream_putw (circuit->snd_stream, ntohs(hdr->checksum));
2400
2401 length = (u_int16_t)stream_get_putp (circuit->snd_stream);
2402 /* Update PDU length */
2403 stream_putw_at (circuit->snd_stream, lenp, length);
2404
2405 retval = circuit->tx (circuit, level);
2406
2407 return retval;
2408}
2409
2410#if 0
2411/*
2412 * ISH PDU Processing
2413 */
2414
2415
2416 /*
2417 * Let's first check if the local and remote system have any common area
2418 * addresses
2419 */
2420 if (area_match(tlvs.area_addrs, isis->man_area_addrs) == 0) {
2421 if (circuit->circuit_t == IS_LEVEL_2) {
2422 /* do as in table 8 (p. 40) */
2423 switch (circuit_type) {
2424 case IS_LEVEL_1:
2425 if (adj->adj_state != ISIS_ADJ_UP) {
2426 /* Reject */
2427 zlog_warn("areaMismatch");
2428 retval = ISIS_WARNING;
2429 } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
2430 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch",
2431 circuit->adjdb);
2432 } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2 ||
2433 adj->adj_usage == ISIS_ADJ_LEVEL2) {
2434 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System",
2435 circuit->adjdb);
2436 }
2437 break;
2438 case IS_LEVEL_2:
2439 if (adj->adj_state != ISIS_ADJ_UP) {
2440 isis_adj_state_change (adj, ISIS_ADJ_UP, NULL, circuit->adjdb);
2441 adj->adj_usage = ISIS_ADJ_LEVEL2;
2442 } else if (adj->adj_usage == ISIS_ADJ_LEVEL1 ||
2443 adj->adj_usage == ISIS_ADJ_LEVEL1AND2) {
2444 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System",
2445 circuit->adjdb);
2446 } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) {
2447 ; /* Accept */
2448 }
2449 break;
2450 case IS_LEVEL_1_AND_2:
2451 if (adj->adj_state != ISIS_ADJ_UP) {
2452 isis_adj_state_change (adj, ISIS_ADJ_UP, NULL, circuit->adjdb);
2453 adj->adj_usage = ISIS_ADJ_LEVEL2;
2454 } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
2455 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System",
2456 circuit->adjdb);
2457 } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) {
2458 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch",
2459 circuit->adjdb);
2460 } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) {
2461 ; /* Accept */
2462 }
2463 break;
2464 }
2465 goto mismatch;
2466 } else {
2467 isis_delete_adj (adj, circuit->adjdb);
2468 zlog_warn("areaMismatch");
2469 return ISIS_WARNING;
2470 }
2471 }
2472
2473mismatch:
2474#endif
2475
2476
2477
2478