2 * IS-IS Rout(e)ing protocol - isis_pdu.c
5 * Copyright (C) 2001,2002 Sampo Saaristo
6 * Tampere University of Technology
7 * Institute of Communications Engineering
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)
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
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.
38 #include "isisd/dict.h"
39 #include "isisd/include-netbsd/iso.h"
40 #include "isisd/isis_constants.h"
41 #include "isisd/isis_common.h"
42 #include "isisd/isis_adjacency.h"
43 #include "isisd/isis_circuit.h"
44 #include "isisd/isis_network.h"
45 #include "isisd/isis_misc.h"
46 #include "isisd/isis_dr.h"
47 #include "isisd/isis_flags.h"
48 #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"
57 extern struct thread_master
*master
;
58 extern struct isis
*isis
;
60 #define ISIS_MINIMUM_FIXED_HDR_LEN 15
61 #define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */
67 /* Utility mask array. */
68 static u_char maskbit
[] = {
69 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
77 * Compares two sets of area addresses
80 area_match (struct list
*left
, struct list
*right
)
82 struct area_addr
*addr1
, *addr2
;
83 struct listnode
*node1
, *nnode1
;
84 struct listnode
*node2
, *nnode2
;
86 for (ALL_LIST_ELEMENTS (left
, node1
, nnode1
, addr1
))
88 for (ALL_LIST_ELEMENTS (right
, node2
, nnode2
, addr2
))
90 if (addr1
->addr_len
== addr2
->addr_len
&&
91 !memcmp (addr1
->area_addr
, addr2
->area_addr
, (int) addr1
->addr_len
))
96 return 0; /* mismatch */
100 * Check if ip2 is in the ip1's network (function like Prefix.h:prefix_match() )
101 * param ip1 the IS interface ip address structure
102 * param ip2 the IIH's ip address
103 * return 0 the IIH's IP is not in the IS's subnetwork
104 * 1 the IIH's IP is in the IS's subnetwork
107 ip_same_subnet (struct prefix_ipv4
*ip1
, struct in_addr
*ip2
)
109 u_char
*addr1
, *addr2
;
110 int shift
, offset
, offsetloop
;
113 addr1
= (u_char
*) & ip1
->prefix
.s_addr
;
114 addr2
= (u_char
*) & ip2
->s_addr
;
115 len
= ip1
->prefixlen
;
118 offsetloop
= offset
= len
/ PNBBY
;
121 if (addr1
[offsetloop
] != addr2
[offsetloop
])
125 if (maskbit
[shift
] & (addr1
[offset
] ^ addr2
[offset
]))
128 return 1; /* match */
132 * Compares two set of ip addresses
133 * param left the local interface's ip addresses
134 * param right the iih interface's ip address
139 ip_match (struct list
*left
, struct list
*right
)
141 struct prefix_ipv4
*ip1
;
143 struct listnode
*node1
, *nnode1
;
144 struct listnode
*node2
, *nnode2
;
146 if ((left
== NULL
) || (right
== NULL
))
149 for (ALL_LIST_ELEMENTS (left
, node1
, nnode1
, ip1
))
151 for (ALL_LIST_ELEMENTS (right
, node2
, nnode2
, ip2
))
153 if (ip_same_subnet (ip1
, ip2
))
155 return 1; /* match */
164 * Checks whether we should accept a PDU of given level
167 accept_level (int level
, int circuit_t
)
169 int retval
= ((circuit_t
& level
) == level
); /* simple approach */
175 authentication_check (struct isis_passwd
*one
, struct isis_passwd
*theother
)
177 if (one
->type
!= theother
->type
)
179 zlog_warn ("Unsupported authentication type %d", theother
->type
);
180 return 1; /* Auth fail (different authentication types) */
184 case ISIS_PASSWD_TYPE_CLEARTXT
:
185 if (one
->len
!= theother
->len
)
186 return 1; /* Auth fail () - passwd len mismatch */
187 return memcmp (one
->passwd
, theother
->passwd
, one
->len
);
190 zlog_warn ("Unsupported authentication type");
193 return 0; /* Auth pass */
197 * Processing helper functions
200 tlvs_to_adj_nlpids (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
203 struct nlpids
*tlv_nlpids
;
208 tlv_nlpids
= tlvs
->nlpids
;
210 adj
->nlpids
.count
= tlv_nlpids
->count
;
212 for (i
= 0; i
< tlv_nlpids
->count
; i
++)
214 adj
->nlpids
.nlpids
[i
] = tlv_nlpids
->nlpids
[i
];
220 del_ip_addr (void *val
)
222 XFREE (MTYPE_ISIS_TMP
, val
);
226 tlvs_to_adj_ipv4_addrs (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
228 struct listnode
*node
, *nnode
;
229 struct in_addr
*ipv4_addr
, *malloced
;
233 adj
->ipv4_addrs
->del
= del_ip_addr
;
234 list_delete (adj
->ipv4_addrs
);
236 adj
->ipv4_addrs
= list_new ();
237 if (tlvs
->ipv4_addrs
)
239 for (ALL_LIST_ELEMENTS (tlvs
->ipv4_addrs
, node
, nnode
, ipv4_addr
))
241 malloced
= XMALLOC (MTYPE_ISIS_TMP
, sizeof (struct in_addr
));
242 memcpy (malloced
, ipv4_addr
, sizeof (struct in_addr
));
243 listnode_add (adj
->ipv4_addrs
, malloced
);
250 tlvs_to_adj_ipv6_addrs (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
252 struct listnode
*node
, *nnode
;
253 struct in6_addr
*ipv6_addr
, *malloced
;
257 adj
->ipv6_addrs
->del
= del_ip_addr
;
258 list_delete (adj
->ipv6_addrs
);
260 adj
->ipv6_addrs
= list_new ();
261 if (tlvs
->ipv6_addrs
)
263 for (ALL_LIST_ELEMENTS (tlvs
->ipv6_addrs
, node
, nnode
, ipv6_addr
))
265 malloced
= XMALLOC (MTYPE_ISIS_TMP
, sizeof (struct in6_addr
));
266 memcpy (malloced
, ipv6_addr
, sizeof (struct in6_addr
));
267 listnode_add (adj
->ipv6_addrs
, malloced
);
272 #endif /* HAVE_IPV6 */
281 * Section 8.2.5 - Receiving point-to-point IIH PDUs
285 process_p2p_hello (struct isis_circuit
*circuit
)
287 int retval
= ISIS_OK
;
288 struct isis_p2p_hello_hdr
*hdr
;
289 struct isis_adjacency
*adj
;
290 u_int32_t expected
= 0, found
;
293 if ((stream_get_endp (circuit
->rcv_stream
) -
294 stream_get_getp (circuit
->rcv_stream
)) < ISIS_P2PHELLO_HDRLEN
)
296 zlog_warn ("Packet too short");
300 /* 8.2.5.1 PDU acceptance tests */
302 /* 8.2.5.1 a) external domain untrue */
303 /* FIXME: not useful at all? */
305 /* 8.2.5.1 b) ID Length mismatch */
306 /* checked at the handle_pdu */
308 /* 8.2.5.2 IIH PDU Processing */
310 /* 8.2.5.2 a) 1) Maximum Area Addresses */
311 /* Already checked, and can also be ommited */
316 hdr
= (struct isis_p2p_hello_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
317 circuit
->rcv_stream
->getp
+= ISIS_P2PHELLO_HDRLEN
;
319 /* hdr.circuit_t = stream_getc (stream);
320 stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN);
321 hdr.hold_time = stream_getw (stream);
322 hdr.pdu_len = stream_getw (stream);
323 hdr.local_id = stream_getc (stream); */
326 * My interpertation of the ISO, if no adj exists we will create one for
330 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
332 zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
333 " cir id %02d, length %d",
334 circuit
->area
->area_tag
, circuit
->interface
->name
,
335 circuit_t2string (circuit
->circuit_is_type
),
336 circuit
->circuit_id
, ntohs (hdr
->pdu_len
));
339 adj
= circuit
->u
.p2p
.neighbor
;
342 adj
= isis_new_adj (hdr
->source_id
, (u_char
*) " ", 0, circuit
);
345 circuit
->u
.p2p
.neighbor
= adj
;
346 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
347 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
350 /* 8.2.6 Monitoring point-to-point adjacencies */
351 adj
->hold_time
= ntohs (hdr
->hold_time
);
352 adj
->last_upd
= time (NULL
);
355 * Lets get the TLVS now
357 expected
|= TLVFLAG_AREA_ADDRS
;
358 expected
|= TLVFLAG_AUTH_INFO
;
359 expected
|= TLVFLAG_NLPID
;
360 expected
|= TLVFLAG_IPV4_ADDR
;
361 expected
|= TLVFLAG_IPV6_ADDR
;
363 retval
= parse_tlvs (circuit
->area
->area_tag
,
364 STREAM_PNT (circuit
->rcv_stream
),
365 ntohs (hdr
->pdu_len
) - ISIS_P2PHELLO_HDRLEN
366 - ISIS_FIXED_HDR_LEN
, &expected
, &found
, &tlvs
);
368 if (retval
> ISIS_WARNING
)
374 /* 8.2.5.1 c) Authentication */
375 if (circuit
->passwd
.type
)
377 if (!(found
& TLVFLAG_AUTH_INFO
) ||
378 authentication_check (&circuit
->passwd
, &tlvs
.auth_info
))
380 isis_event_auth_failure (circuit
->area
->area_tag
,
381 "P2P hello authentication failure",
387 /* we do this now because the adj may not survive till the end... */
389 /* we need to copy addresses to the adj */
390 tlvs_to_adj_ipv4_addrs (&tlvs
, adj
);
393 tlvs_to_adj_ipv6_addrs (&tlvs
, adj
);
394 #endif /* HAVE_IPV6 */
396 /* lets take care of the expiry */
397 THREAD_TIMER_OFF (adj
->t_expire
);
398 THREAD_TIMER_ON (master
, adj
->t_expire
, isis_adj_expire
, adj
,
399 (long) adj
->hold_time
);
401 /* 8.2.5.2 a) a match was detected */
402 if (area_match (circuit
->area
->area_addrs
, tlvs
.area_addrs
))
404 /* 8.2.5.2 a) 2) If the system is L1 - table 5 */
405 if (circuit
->area
->is_type
== IS_LEVEL_1
)
407 switch (hdr
->circuit_t
)
410 case IS_LEVEL_1_AND_2
:
411 if (adj
->adj_state
!= ISIS_ADJ_UP
)
413 /* (4) adj state up */
414 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
415 /* (5) adj usage level 1 */
416 adj
->adj_usage
= ISIS_ADJ_LEVEL1
;
418 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
424 if (adj
->adj_state
!= ISIS_ADJ_UP
)
426 /* (7) reject - wrong system type event */
427 zlog_warn ("wrongSystemType");
428 return ISIS_WARNING
; /* Reject */
430 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
432 /* (6) down - wrong system */
433 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
439 /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */
440 if (circuit
->area
->is_type
== IS_LEVEL_1_AND_2
)
442 switch (hdr
->circuit_t
)
445 if (adj
->adj_state
!= ISIS_ADJ_UP
)
447 /* (6) adj state up */
448 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
449 /* (7) adj usage level 1 */
450 adj
->adj_usage
= ISIS_ADJ_LEVEL1
;
452 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
456 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
457 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
459 /* (8) down - wrong system */
460 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
464 if (adj
->adj_state
!= ISIS_ADJ_UP
)
466 /* (6) adj state up */
467 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
468 /* (9) adj usage level 2 */
469 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
471 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1
) ||
472 (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
))
474 /* (8) down - wrong system */
475 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
477 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
482 case IS_LEVEL_1_AND_2
:
483 if (adj
->adj_state
!= ISIS_ADJ_UP
)
485 /* (6) adj state up */
486 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
487 /* (10) adj usage level 1 */
488 adj
->adj_usage
= ISIS_ADJ_LEVEL1AND2
;
490 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1
) ||
491 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
493 /* (8) down - wrong system */
494 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
496 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
504 /* 8.2.5.2 a) 4) If the system is L2 - table 7 */
505 if (circuit
->area
->is_type
== IS_LEVEL_2
)
507 switch (hdr
->circuit_t
)
510 if (adj
->adj_state
!= ISIS_ADJ_UP
)
512 /* (5) reject - wrong system type event */
513 zlog_warn ("wrongSystemType");
514 return ISIS_WARNING
; /* Reject */
516 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
517 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
519 /* (6) down - wrong system */
520 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
523 case IS_LEVEL_1_AND_2
:
525 if (adj
->adj_state
!= ISIS_ADJ_UP
)
527 /* (7) adj state up */
528 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
529 /* (8) adj usage level 2 */
530 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
532 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
534 /* (6) down - wrong system */
535 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
537 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
545 /* 8.2.5.2 b) if no match was detected */
548 if (circuit
->area
->is_type
== IS_LEVEL_1
)
550 /* 8.2.5.2 b) 1) is_type L1 and adj is not up */
551 if (adj
->adj_state
!= ISIS_ADJ_UP
)
553 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch");
554 /* 8.2.5.2 b) 2)is_type L1 and adj is up */
558 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
559 "Down - Area Mismatch");
562 /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */
565 switch (hdr
->circuit_t
)
568 if (adj
->adj_state
!= ISIS_ADJ_UP
)
570 /* (6) reject - Area Mismatch event */
571 zlog_warn ("AreaMismatch");
572 return ISIS_WARNING
; /* Reject */
574 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
576 /* (7) down - area mismatch */
577 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch");
580 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
581 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
583 /* (7) down - wrong system */
584 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
587 case IS_LEVEL_1_AND_2
:
589 if (adj
->adj_state
!= ISIS_ADJ_UP
)
591 /* (8) adj state up */
592 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
593 /* (9) adj usage level 2 */
594 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
596 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
598 /* (7) down - wrong system */
599 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
601 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
603 if (hdr
->circuit_t
== IS_LEVEL_2
)
605 /* (7) down - wrong system */
606 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
611 /* (7) down - area mismatch */
612 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
616 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
624 /* 8.2.5.2 c) if the action was up - comparing circuit IDs */
625 /* FIXME - Missing parts */
627 /* some of my own understanding of the ISO, why the heck does
628 * it not say what should I change the system_type to...
630 switch (adj
->adj_usage
)
632 case ISIS_ADJ_LEVEL1
:
633 adj
->sys_type
= ISIS_SYSTYPE_L1_IS
;
635 case ISIS_ADJ_LEVEL2
:
636 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
638 case ISIS_ADJ_LEVEL1AND2
:
639 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
642 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
646 adj
->circuit_t
= hdr
->circuit_t
;
647 adj
->level
= hdr
->circuit_t
;
655 * Process IS-IS LAN Level 1/2 Hello PDU
658 process_lan_hello (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
660 int retval
= ISIS_OK
;
661 struct isis_lan_hello_hdr hdr
;
662 struct isis_adjacency
*adj
;
663 u_int32_t expected
= 0, found
;
666 struct listnode
*node
, *nnode
;
668 if ((stream_get_endp (circuit
->rcv_stream
) -
669 stream_get_getp (circuit
->rcv_stream
)) < ISIS_LANHELLO_HDRLEN
)
671 zlog_warn ("Packet too short");
675 if (circuit
->ext_domain
)
677 zlog_debug ("level %d LAN Hello received over circuit with "
678 "externalDomain = true", level
);
682 if (!accept_level (level
, circuit
->circuit_is_type
))
684 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
686 zlog_debug ("ISIS-Adj (%s): Interface level mismatch, %s",
687 circuit
->area
->area_tag
, circuit
->interface
->name
);
693 /* Cisco's debug message compatability */
694 if (!accept_level (level
, circuit
->area
->is_type
))
696 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
698 zlog_debug ("ISIS-Adj (%s): is type mismatch",
699 circuit
->area
->area_tag
);
707 hdr
.circuit_t
= stream_getc (circuit
->rcv_stream
);
708 stream_get (hdr
.source_id
, circuit
->rcv_stream
, ISIS_SYS_ID_LEN
);
709 hdr
.hold_time
= stream_getw (circuit
->rcv_stream
);
710 hdr
.pdu_len
= stream_getw (circuit
->rcv_stream
);
711 hdr
.prio
= stream_getc (circuit
->rcv_stream
);
712 stream_get (hdr
.lan_id
, circuit
->rcv_stream
, ISIS_SYS_ID_LEN
+ 1);
714 if (hdr
.circuit_t
!= IS_LEVEL_1
&& hdr
.circuit_t
!= IS_LEVEL_2
&&
715 hdr
.circuit_t
!= IS_LEVEL_1_AND_2
)
717 zlog_warn ("Level %d LAN Hello with Circuit Type %d", level
,
724 expected
|= TLVFLAG_AUTH_INFO
;
725 expected
|= TLVFLAG_AREA_ADDRS
;
726 expected
|= TLVFLAG_LAN_NEIGHS
;
727 expected
|= TLVFLAG_NLPID
;
728 expected
|= TLVFLAG_IPV4_ADDR
;
729 expected
|= TLVFLAG_IPV6_ADDR
;
731 retval
= parse_tlvs (circuit
->area
->area_tag
,
732 STREAM_PNT (circuit
->rcv_stream
),
733 hdr
.pdu_len
- ISIS_LANHELLO_HDRLEN
-
734 ISIS_FIXED_HDR_LEN
, &expected
, &found
, &tlvs
);
736 if (retval
> ISIS_WARNING
)
738 zlog_warn ("parse_tlvs() failed");
742 if (!(found
& TLVFLAG_AREA_ADDRS
))
744 zlog_warn ("No Area addresses TLV in Level %d LAN IS to IS hello",
746 retval
= ISIS_WARNING
;
750 if (circuit
->passwd
.type
)
752 if (!(found
& TLVFLAG_AUTH_INFO
) ||
753 authentication_check (&circuit
->passwd
, &tlvs
.auth_info
))
755 isis_event_auth_failure (circuit
->area
->area_tag
,
756 "LAN hello authentication failure",
758 retval
= ISIS_WARNING
;
764 * Accept the level 1 adjacency only if a match between local and
765 * remote area addresses is found
767 if (level
== 1 && !area_match (circuit
->area
->area_addrs
, tlvs
.area_addrs
))
769 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
771 zlog_debug ("ISIS-Adj (%s): Area mismatch, level %d IIH on %s",
772 circuit
->area
->area_tag
, level
,
773 circuit
->interface
->name
);
780 * it's own IIH PDU - discard silently
782 if (!memcmp (circuit
->u
.bc
.snpa
, ssnpa
, ETH_ALEN
))
784 zlog_debug ("ISIS-Adj (%s): it's own IIH PDU - discarded",
785 circuit
->area
->area_tag
);
792 * check if it's own interface ip match iih ip addrs
794 if (!(found
& TLVFLAG_IPV4_ADDR
)
795 || !ip_match (circuit
->ip_addrs
, tlvs
.ipv4_addrs
))
798 ("ISIS-Adj: No usable IP interface addresses in LAN IIH from %s\n",
799 circuit
->interface
->name
);
800 retval
= ISIS_WARNING
;
804 adj
= isis_adj_lookup (hdr
.source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
810 adj
= isis_new_adj (hdr
.source_id
, ssnpa
, level
, circuit
);
818 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
822 adj
->sys_type
= ISIS_SYSTYPE_L1_IS
;
826 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
828 list_delete_all_node (circuit
->u
.bc
.lan_neighs
[level
- 1]);
829 isis_adj_build_neigh_list (circuit
->u
.bc
.adjdb
[level
- 1],
830 circuit
->u
.bc
.lan_neighs
[level
- 1]);
833 if(adj
->dis_record
[level
-1].dis
==ISIS_IS_DIS
)
837 if (memcmp (circuit
->u
.bc
.l1_desig_is
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1))
839 thread_add_event (master
, isis_event_dis_status_change
, circuit
, 0);
840 memcpy (&circuit
->u
.bc
.l1_desig_is
, hdr
.lan_id
,
841 ISIS_SYS_ID_LEN
+ 1);
845 if (memcmp (circuit
->u
.bc
.l2_desig_is
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1))
847 thread_add_event (master
, isis_event_dis_status_change
, circuit
, 0);
848 memcpy (&circuit
->u
.bc
.l2_desig_is
, hdr
.lan_id
,
849 ISIS_SYS_ID_LEN
+ 1);
854 adj
->hold_time
= hdr
.hold_time
;
855 adj
->last_upd
= time (NULL
);
856 adj
->prio
[level
- 1] = hdr
.prio
;
858 memcpy (adj
->lanid
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1);
860 /* which protocol are spoken ??? */
861 if (found
& TLVFLAG_NLPID
)
862 tlvs_to_adj_nlpids (&tlvs
, adj
);
864 /* we need to copy addresses to the adj */
865 if (found
& TLVFLAG_IPV4_ADDR
)
866 tlvs_to_adj_ipv4_addrs (&tlvs
, adj
);
869 if (found
& TLVFLAG_IPV6_ADDR
)
870 tlvs_to_adj_ipv6_addrs (&tlvs
, adj
);
871 #endif /* HAVE_IPV6 */
873 adj
->circuit_t
= hdr
.circuit_t
;
875 /* lets take care of the expiry */
876 THREAD_TIMER_OFF (adj
->t_expire
);
877 THREAD_TIMER_ON (master
, adj
->t_expire
, isis_adj_expire
, adj
,
878 (long) adj
->hold_time
);
881 * If the snpa for this circuit is found from LAN Neighbours TLV
882 * we have two-way communication -> adjacency can be put to state "up"
885 if (found
& TLVFLAG_LAN_NEIGHS
)
887 if (adj
->adj_state
!= ISIS_ADJ_UP
)
889 for (ALL_LIST_ELEMENTS (tlvs
.lan_neighs
, node
, nnode
, snpa
))
890 if (!memcmp (snpa
, circuit
->u
.bc
.snpa
, ETH_ALEN
))
892 isis_adj_state_change (adj
, ISIS_ADJ_UP
,
893 "own SNPA found in LAN Neighbours TLV");
899 /* DEBUG_ADJ_PACKETS */
900 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
902 /* FIXME: is this place right? fix missing info */
903 zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "
904 "cirID %u, length %ld",
905 circuit
->area
->area_tag
,
906 level
, snpa_print (ssnpa
), circuit
->interface
->name
,
907 circuit_t2string (circuit
->circuit_is_type
),
908 circuit
->circuit_id
, stream_get_endp (circuit
->rcv_stream
));
917 * Process Level 1/2 Link State
919 * Section 7.3.15.1 - Action on receipt of a link state PDU
922 process_lsp (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
924 struct isis_link_state_hdr
*hdr
;
925 struct isis_adjacency
*adj
= NULL
;
926 struct isis_lsp
*lsp
, *lsp0
= NULL
;
927 int retval
= ISIS_OK
, comp
= 0;
928 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
929 struct isis_passwd
*passwd
;
931 /* Sanity check - FIXME: move to correct place */
932 if ((stream_get_endp (circuit
->rcv_stream
) -
933 stream_get_getp (circuit
->rcv_stream
)) < ISIS_LSP_HDR_LEN
)
935 zlog_warn ("Packet too short");
939 /* Reference the header */
940 hdr
= (struct isis_link_state_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
942 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
944 zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "
945 "lifetime %us, len %lu, on %s",
946 circuit
->area
->area_tag
,
948 rawlspid_print (hdr
->lsp_id
),
949 ntohl (hdr
->seq_num
),
950 ntohs (hdr
->checksum
),
951 ntohs (hdr
->rem_lifetime
),
952 circuit
->rcv_stream
->endp
, circuit
->interface
->name
);
955 assert (ntohs (hdr
->pdu_len
) > ISIS_LSP_HDR_LEN
);
957 /* Checksum sanity check - FIXME: move to correct place */
958 /* 12 = sysid+pdu+remtime */
959 if (iso_csum_verify (STREAM_PNT (circuit
->rcv_stream
) + 4,
960 ntohs (hdr
->pdu_len
) - 12, &hdr
->checksum
))
962 zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
963 circuit
->area
->area_tag
,
964 rawlspid_print (hdr
->lsp_id
), ntohs (hdr
->checksum
));
969 /* 7.3.15.1 a) 1 - external domain circuit will discard lsps */
970 if (circuit
->ext_domain
)
973 ("ISIS-Upd (%s): LSP %s received at level %d over circuit with "
974 "externalDomain = true", circuit
->area
->area_tag
,
975 rawlspid_print (hdr
->lsp_id
), level
);
980 /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
981 if (!accept_level (level
, circuit
->circuit_is_type
))
983 zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of"
985 circuit
->area
->area_tag
,
986 rawlspid_print (hdr
->lsp_id
),
987 level
, circuit_t2string (circuit
->circuit_is_type
));
992 /* 7.3.15.1 a) 4 - need to make sure IDLength matches */
994 /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */
996 /* 7.3.15.1 a) 7 - password check */
997 (level
== ISIS_LEVEL1
) ? (passwd
= &circuit
->area
->area_passwd
) :
998 (passwd
= &circuit
->area
->domain_passwd
);
1001 if (isis_lsp_authinfo_check (circuit
->rcv_stream
, circuit
->area
,
1002 ntohs (hdr
->pdu_len
), passwd
))
1004 isis_event_auth_failure (circuit
->area
->area_tag
,
1005 "LSP authentication failure", hdr
->lsp_id
);
1006 return ISIS_WARNING
;
1009 /* Find the LSP in our database and compare it to this Link State header */
1010 lsp
= lsp_search (hdr
->lsp_id
, circuit
->area
->lspdb
[level
- 1]);
1012 comp
= lsp_compare (circuit
->area
->area_tag
, lsp
, hdr
->seq_num
,
1013 hdr
->checksum
, hdr
->rem_lifetime
);
1014 if (lsp
&& (lsp
->own_lsp
1015 #ifdef TOPOLOGY_GENERATE
1016 || lsp
->from_topology
1017 #endif /* TOPOLOGY_GENERATE */
1021 /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level */
1022 /* for broadcast circuits, snpa should be compared */
1023 /* FIXME : Point To Point */
1025 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1027 adj
= isis_adj_lookup_snpa (ssnpa
, circuit
->u
.bc
.adjdb
[level
- 1]);
1030 zlog_debug ("(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, "
1031 "lifetime %us on %s",
1032 circuit
->area
->area_tag
,
1033 rawlspid_print (hdr
->lsp_id
),
1034 ntohl (hdr
->seq_num
),
1035 ntohs (hdr
->checksum
),
1036 ntohs (hdr
->rem_lifetime
), circuit
->interface
->name
);
1037 return ISIS_WARNING
; /* Silently discard */
1041 /* for non broadcast, we just need to find same level adj */
1044 /* If no adj, or no sharing of level */
1045 if (!circuit
->u
.p2p
.neighbor
)
1047 return ISIS_OK
; /* Silently discard */
1051 if (((level
== 1) &&
1052 (circuit
->u
.p2p
.neighbor
->adj_usage
== ISIS_ADJ_LEVEL2
)) ||
1054 (circuit
->u
.p2p
.neighbor
->adj_usage
== ISIS_ADJ_LEVEL1
)))
1055 return ISIS_WARNING
; /* Silently discard */
1059 /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */
1061 /* 7.3.15.1 a) 8 - Passwords for level 2 - not implemented */
1063 /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented FIXME: do it */
1065 /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */
1066 if (hdr
->rem_lifetime
== 0)
1070 /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't save */
1071 /* only needed on explicit update, eg - p2p */
1072 if (circuit
->circ_type
== CIRCUIT_T_P2P
)
1073 ack_lsp (hdr
, circuit
, level
);
1074 return retval
; /* FIXME: do we need a purge? */
1078 if (memcmp (hdr
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
1080 /* LSP by some other system -> do 7.3.16.4 b) */
1081 /* 7.3.16.4 b) 1) */
1082 if (comp
== LSP_NEWER
)
1084 lsp_update (lsp
, hdr
, circuit
->rcv_stream
, circuit
->area
);
1086 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1088 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1090 ISIS_FLAGS_CLEAR_ALL (lsp
->SSNflags
); /* FIXME: OTHER than c */
1092 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1093 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1095 } /* 7.3.16.4 b) 2) */
1096 else if (comp
== LSP_EQUAL
)
1099 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1101 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1102 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1103 } /* 7.3.16.4 b) 3) */
1106 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1107 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1112 /* our own LSP -> 7.3.16.4 c) */
1113 if (LSP_PSEUDO_ID (lsp
->lsp_header
->lsp_id
) !=
1115 || (LSP_PSEUDO_ID (lsp
->lsp_header
->lsp_id
) ==
1117 && circuit
->u
.bc
.is_dr
[level
- 1] == 1))
1119 lsp
->lsp_header
->seq_num
= htonl (ntohl (hdr
->seq_num
) + 1);
1120 zlog_debug ("LSP LEN: %d", ntohs (lsp
->lsp_header
->pdu_len
));
1121 iso_csum_create (STREAM_DATA (lsp
->pdu
) + 12,
1122 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
1123 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1125 ("ISIS-Upd (%s): (1) re-originating LSP %s new seq 0x%08x",
1126 circuit
->area
->area_tag
, rawlspid_print (hdr
->lsp_id
),
1127 ntohl (lsp
->lsp_header
->seq_num
));
1128 lsp
->lsp_header
->rem_lifetime
=
1130 (circuit
->area
->max_lsp_lifetime
[level
- 1],
1135 /* Got purge for own pseudo-lsp, and we are not DR */
1136 lsp_purge_dr (lsp
->lsp_header
->lsp_id
, circuit
, level
);
1142 /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a
1144 if (memcmp (hdr
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
) == 0)
1148 /* 7.3.16.4: initiate a purge */
1149 lsp_purge_non_exist (hdr
, circuit
->area
);
1152 /* 7.3.15.1 d) - If this is our own lsp and we have it */
1154 /* In 7.3.16.1, If an Intermediate system R somewhere in the domain
1155 * has information that the current sequence number for source S is
1156 * "greater" than that held by S, ... */
1158 else if (ntohl (hdr
->seq_num
) > ntohl (lsp
->lsp_header
->seq_num
))
1161 lsp
->lsp_header
->seq_num
= htonl (ntohl (hdr
->seq_num
) + 1);
1163 iso_csum_create (STREAM_DATA (lsp
->pdu
) + 12,
1164 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
1166 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1168 ("ISIS-Upd (%s): (2) re-originating LSP %s new seq 0x%08x",
1169 circuit
->area
->area_tag
, rawlspid_print (hdr
->lsp_id
),
1170 ntohl (lsp
->lsp_header
->seq_num
));
1171 lsp
->lsp_header
->rem_lifetime
=
1173 (circuit
->area
->max_lsp_lifetime
[level
- 1],
1179 /* 7.3.15.1 e) - This lsp originated on another system */
1181 /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */
1182 if ((!lsp
|| comp
== LSP_NEWER
))
1187 #ifdef EXTREME_DEBUG
1188 zlog_debug ("level %d number is - %ld", level
,
1189 circuit
->area
->lspdb
[level
- 1]->dict_nodecount
);
1190 #endif /* EXTREME DEBUG */
1191 lsp_search_and_destroy (hdr
->lsp_id
,
1192 circuit
->area
->lspdb
[level
- 1]);
1193 /* exists, so we overwrite */
1194 #ifdef EXTREME_DEBUG
1195 zlog_debug ("level %d number is - %ld", level
,
1196 circuit
->area
->lspdb
[level
- 1]->dict_nodecount
);
1197 #endif /* EXTREME DEBUG */
1200 * If this lsp is a frag, need to see if we have zero lsp present
1202 if (LSP_FRAGMENT (hdr
->lsp_id
) != 0)
1204 memcpy (lspid
, hdr
->lsp_id
, ISIS_SYS_ID_LEN
+ 1);
1205 LSP_FRAGMENT (lspid
) = 0;
1206 lsp0
= lsp_search (lspid
, circuit
->area
->lspdb
[level
- 1]);
1209 zlog_debug ("Got lsp frag, while zero lsp not database");
1214 lsp_new_from_stream_ptr (circuit
->rcv_stream
,
1215 ntohs (hdr
->pdu_len
), lsp0
,
1219 lsp_insert (lsp
, circuit
->area
->lspdb
[level
- 1]);
1221 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1223 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1226 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1227 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1230 /* 7.3.15.1 e) 2) LSP equal to the one in db */
1231 else if (comp
== LSP_EQUAL
)
1233 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1234 lsp_update (lsp
, hdr
, circuit
->rcv_stream
, circuit
->area
);
1235 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1237 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1240 /* 7.3.15.1 e) 3) LSP older than the one in db */
1243 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1244 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1253 * Process Sequence Numbers
1255 * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU
1259 process_snp (int snp_type
, int level
, struct isis_circuit
*circuit
,
1262 int retval
= ISIS_OK
;
1264 char typechar
= ' ';
1266 struct isis_adjacency
*adj
;
1267 struct isis_complete_seqnum_hdr
*chdr
= NULL
;
1268 struct isis_partial_seqnum_hdr
*phdr
= NULL
;
1269 uint32_t found
= 0, expected
= 0;
1270 struct isis_lsp
*lsp
;
1271 struct lsp_entry
*entry
;
1272 struct listnode
*node
, *nnode
;
1273 struct listnode
*node2
, *nnode2
;
1275 struct list
*lsp_list
= NULL
;
1276 struct isis_passwd
*passwd
;
1278 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1280 /* getting the header info */
1283 (struct isis_complete_seqnum_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
1284 circuit
->rcv_stream
->getp
+= ISIS_CSNP_HDRLEN
;
1285 len
= ntohs (chdr
->pdu_len
);
1286 if (len
< ISIS_CSNP_HDRLEN
)
1288 zlog_warn ("Received a CSNP with bogus length!");
1296 (struct isis_partial_seqnum_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
1297 circuit
->rcv_stream
->getp
+= ISIS_PSNP_HDRLEN
;
1298 len
= ntohs (phdr
->pdu_len
);
1299 if (len
< ISIS_PSNP_HDRLEN
)
1301 zlog_warn ("Received a CSNP with bogus length!");
1306 /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */
1307 if (circuit
->ext_domain
)
1310 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1311 "skipping: circuit externalDomain = true",
1312 circuit
->area
->area_tag
,
1313 level
, typechar
, circuit
->interface
->name
);
1318 /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
1319 if (!accept_level (level
, circuit
->circuit_is_type
))
1322 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1323 "skipping: circuit type %s does not match level %d",
1324 circuit
->area
->area_tag
,
1327 circuit
->interface
->name
,
1328 circuit_t2string (circuit
->circuit_is_type
), level
);
1333 /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */
1334 if ((snp_type
== ISIS_SNP_PSNP_FLAG
) &&
1335 (circuit
->circ_type
== CIRCUIT_T_BROADCAST
))
1337 if (!circuit
->u
.bc
.is_dr
[level
- 1])
1340 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
1341 "skipping: we are not the DIS",
1342 circuit
->area
->area_tag
,
1344 typechar
, snpa_print (ssnpa
), circuit
->interface
->name
);
1350 /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */
1352 /* 7.3.15.2 a) 6 - maximum area match, can be ommited since we only use 3
1353 * - already checked */
1355 /* 7.3.15.2 a) 7 - Must check that we have an adjacency of the same level */
1356 /* for broadcast circuits, snpa should be compared */
1357 /* FIXME : Do we need to check SNPA? */
1358 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1360 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1363 isis_adj_lookup (chdr
->source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
1367 /* a psnp on a broadcast, how lovely of Juniper :) */
1369 isis_adj_lookup (phdr
->source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
1372 return ISIS_OK
; /* Silently discard */
1376 if (!circuit
->u
.p2p
.neighbor
)
1377 return ISIS_OK
; /* Silently discard */
1380 /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */
1382 /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */
1384 memset (&tlvs
, 0, sizeof (struct tlvs
));
1387 expected
|= TLVFLAG_LSP_ENTRIES
;
1388 expected
|= TLVFLAG_AUTH_INFO
;
1389 retval
= parse_tlvs (circuit
->area
->area_tag
,
1390 STREAM_PNT (circuit
->rcv_stream
),
1391 len
- circuit
->rcv_stream
->getp
,
1392 &expected
, &found
, &tlvs
);
1394 if (retval
> ISIS_WARNING
)
1396 zlog_warn ("something went very wrong processing SNP");
1402 passwd
= &circuit
->area
->area_passwd
;
1404 passwd
= &circuit
->area
->domain_passwd
;
1406 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_RECV
))
1410 if (!(found
& TLVFLAG_AUTH_INFO
) ||
1411 authentication_check (passwd
, &tlvs
.auth_info
))
1413 isis_event_auth_failure (circuit
->area
->area_tag
,
1414 "SNP authentication" " failure",
1415 phdr
? phdr
->source_id
: chdr
->source_id
);
1421 /* debug isis snp-packets */
1422 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
1424 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s",
1425 circuit
->area
->area_tag
,
1427 typechar
, snpa_print (ssnpa
), circuit
->interface
->name
);
1428 if (tlvs
.lsp_entries
)
1430 for (ALL_LIST_ELEMENTS (tlvs
.lsp_entries
, node
, nnode
, entry
))
1432 zlog_debug ("ISIS-Snp (%s): %cSNP entry %s, seq 0x%08x,"
1433 " cksum 0x%04x, lifetime %us",
1434 circuit
->area
->area_tag
,
1436 rawlspid_print (entry
->lsp_id
),
1437 ntohl (entry
->seq_num
),
1438 ntohs (entry
->checksum
), ntohs (entry
->rem_lifetime
));
1443 /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */
1444 if (tlvs
.lsp_entries
)
1446 for (ALL_LIST_ELEMENTS (tlvs
.lsp_entries
, node
, nnode
, entry
))
1448 lsp
= lsp_search (entry
->lsp_id
, circuit
->area
->lspdb
[level
- 1]);
1449 own_lsp
= !memcmp (entry
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1452 /* 7.3.15.2 b) 1) is this LSP newer */
1453 cmp
= lsp_compare (circuit
->area
->area_tag
, lsp
, entry
->seq_num
,
1454 entry
->checksum
, entry
->rem_lifetime
);
1455 /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */
1456 if (cmp
== LSP_EQUAL
)
1458 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1459 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1460 /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
1462 else if (cmp
== LSP_OLDER
)
1464 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1465 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1469 /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM
1473 lsp_inc_seqnum (lsp
, ntohl (entry
->seq_num
));
1474 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1478 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1479 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1480 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1486 /* 7.3.15.2 b) 5) if it was not found, and all of those are not 0,
1487 * insert it and set SSN on it */
1488 if (entry
->rem_lifetime
&& entry
->checksum
&& entry
->seq_num
&&
1489 memcmp (entry
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
1491 lsp
= lsp_new (entry
->lsp_id
, ntohs (entry
->rem_lifetime
),
1492 0, 0, entry
->checksum
, level
);
1493 lsp_insert (lsp
, circuit
->area
->lspdb
[level
- 1]);
1494 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1500 /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported */
1501 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1504 * Build a list from our own LSP db bounded with start_ and stop_lsp_id
1506 lsp_list
= list_new ();
1507 lsp_build_list_nonzero_ht (chdr
->start_lsp_id
, chdr
->stop_lsp_id
,
1508 lsp_list
, circuit
->area
->lspdb
[level
- 1]);
1510 /* Fixme: Find a better solution */
1511 if (tlvs
.lsp_entries
)
1513 for (ALL_LIST_ELEMENTS (tlvs
.lsp_entries
, node
, nnode
, entry
))
1515 for (ALL_LIST_ELEMENTS (lsp_list
, node2
, nnode2
, lsp
))
1517 if (lsp_id_cmp (lsp
->lsp_header
->lsp_id
, entry
->lsp_id
) == 0)
1519 list_delete_node (lsp_list
, node2
);
1525 /* on remaining LSPs we set SRM (neighbor knew not of) */
1526 for (ALL_LIST_ELEMENTS (lsp_list
, node2
, nnode2
, lsp
))
1528 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1531 list_free (lsp_list
);
1539 process_csnp (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
1541 /* Sanity check - FIXME: move to correct place */
1542 if ((stream_get_endp (circuit
->rcv_stream
) -
1543 stream_get_getp (circuit
->rcv_stream
)) < ISIS_CSNP_HDRLEN
)
1545 zlog_warn ("Packet too short ( < %d)", ISIS_CSNP_HDRLEN
);
1546 return ISIS_WARNING
;
1549 return process_snp (ISIS_SNP_CSNP_FLAG
, level
, circuit
, ssnpa
);
1553 process_psnp (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
1555 if ((stream_get_endp (circuit
->rcv_stream
) -
1556 stream_get_getp (circuit
->rcv_stream
)) < ISIS_PSNP_HDRLEN
)
1558 zlog_warn ("Packet too short");
1559 return ISIS_WARNING
;
1562 return process_snp (ISIS_SNP_PSNP_FLAG
, level
, circuit
, ssnpa
);
1568 * Section 8.2.2 - Receiving ISH PDUs by an intermediate system
1569 * FIXME: sample packet dump, need to figure 0x81 - looks like NLPid
1570 * 0x82 0x15 0x01 0x00 0x04 0x01 0x2c 0x59
1571 * 0x38 0x08 0x47 0x00 0x01 0x00 0x02 0x00
1572 * 0x03 0x00 0x81 0x01 0xcc
1575 process_is_hello (struct isis_circuit
*circuit
)
1577 struct isis_adjacency
*adj
;
1578 int retval
= ISIS_OK
;
1582 /* In this point in time we are not yet able to handle is_hellos
1583 * on lan - Sorry juniper...
1585 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1588 neigh_len
= stream_getc (circuit
->rcv_stream
);
1589 sysid
= STREAM_PNT (circuit
->rcv_stream
) + neigh_len
- 1 - ISIS_SYS_ID_LEN
;
1590 adj
= circuit
->u
.p2p
.neighbor
;
1594 adj
= isis_new_adj (sysid
, (u_char
*) " ", 0, circuit
);
1598 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
1599 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
1600 circuit
->u
.p2p
.neighbor
= adj
;
1603 if ((adj
->adj_state
== ISIS_ADJ_UP
) && memcmp (adj
->sysid
, sysid
,
1606 /* 8.2.2 a) 1) FIXME: adjStateChange(down) event */
1607 /* 8.2.2 a) 2) delete the adj */
1608 XFREE (MTYPE_ISIS_ADJACENCY
, adj
);
1609 /* 8.2.2 a) 3) create a new adj */
1610 adj
= isis_new_adj (sysid
, (u_char
*) " ", 0, circuit
);
1615 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
1616 /* 8.2.2 a) 3) ii */
1617 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
1618 /* 8.2.2 a) 4) quite meaningless */
1620 /* 8.2.2 b) ignore on condition */
1621 if ((adj
->adj_state
== ISIS_ADJ_INITIALIZING
) &&
1622 (adj
->sys_type
== ISIS_SYSTYPE_IS
))
1628 /* 8.2.2 c) respond with a p2p IIH */
1629 send_hello (circuit
, 1);
1631 /* 8.2.2 d) type is IS */
1632 adj
->sys_type
= ISIS_SYSTYPE_IS
;
1633 /* 8.2.2 e) FIXME: Circuit type of? */
1643 isis_handle_pdu (struct isis_circuit
*circuit
, u_char
* ssnpa
)
1645 struct isis_fixed_hdr
*hdr
;
1646 struct esis_fixed_hdr
*esis_hdr
;
1648 int retval
= ISIS_OK
;
1651 * Let's first read data from stream to the header
1653 hdr
= (struct isis_fixed_hdr
*) STREAM_DATA (circuit
->rcv_stream
);
1655 if ((hdr
->idrp
!= ISO10589_ISIS
) && (hdr
->idrp
!= ISO9542_ESIS
))
1657 zlog_warn ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr
->idrp
);
1661 /* now we need to know if this is an ISO 9542 packet and
1662 * take real good care of it, waaa!
1664 if (hdr
->idrp
== ISO9542_ESIS
)
1666 esis_hdr
= (struct esis_fixed_hdr
*) STREAM_DATA (circuit
->rcv_stream
);
1667 stream_set_getp (circuit
->rcv_stream
, ESIS_FIXED_HDR_LEN
);
1668 /* FIXME: Need to do some acceptence tests */
1669 /* example length... */
1670 switch (esis_hdr
->pdu_type
)
1676 zlog_debug ("AN ISH PDU!!");
1677 retval
= process_is_hello (circuit
);
1686 stream_set_getp (circuit
->rcv_stream
, ISIS_FIXED_HDR_LEN
);
1689 * and then process it
1692 if (hdr
->length
< ISIS_MINIMUM_FIXED_HDR_LEN
)
1694 zlog_err ("Fixed header length = %d", hdr
->length
);
1698 if (hdr
->version1
!= 1)
1700 zlog_warn ("Unsupported ISIS version %u", hdr
->version1
);
1701 return ISIS_WARNING
;
1704 if ((hdr
->id_len
!= 0) && (hdr
->id_len
!= ISIS_SYS_ID_LEN
))
1707 ("IDFieldLengthMismatch: ID Length field in a received PDU %u, "
1708 "while the parameter for this IS is %u", hdr
->id_len
,
1713 if (hdr
->version2
!= 1)
1715 zlog_warn ("Unsupported ISIS version %u", hdr
->version2
);
1716 return ISIS_WARNING
;
1719 if ((hdr
->max_area_addrs
!= 0)
1720 && (hdr
->max_area_addrs
!= isis
->max_area_addrs
))
1722 zlog_err ("maximumAreaAddressesMismatch: maximumAreaAdresses in a "
1723 "received PDU %u while the parameter for this IS is %u",
1724 hdr
->max_area_addrs
, isis
->max_area_addrs
);
1728 switch (hdr
->pdu_type
)
1731 retval
= process_lan_hello (ISIS_LEVEL1
, circuit
, ssnpa
);
1734 retval
= process_lan_hello (ISIS_LEVEL2
, circuit
, ssnpa
);
1737 retval
= process_p2p_hello (circuit
);
1740 retval
= process_lsp (ISIS_LEVEL1
, circuit
, ssnpa
);
1743 retval
= process_lsp (ISIS_LEVEL2
, circuit
, ssnpa
);
1745 case L1_COMPLETE_SEQ_NUM
:
1746 retval
= process_csnp (ISIS_LEVEL1
, circuit
, ssnpa
);
1748 case L2_COMPLETE_SEQ_NUM
:
1749 retval
= process_csnp (ISIS_LEVEL2
, circuit
, ssnpa
);
1751 case L1_PARTIAL_SEQ_NUM
:
1752 retval
= process_psnp (ISIS_LEVEL1
, circuit
, ssnpa
);
1754 case L2_PARTIAL_SEQ_NUM
:
1755 retval
= process_psnp (ISIS_LEVEL2
, circuit
, ssnpa
);
1766 isis_receive (struct thread
*thread
)
1768 struct isis_circuit
*circuit
;
1769 u_char ssnpa
[ETH_ALEN
];
1775 circuit
= THREAD_ARG (thread
);
1778 if (circuit
->rcv_stream
== NULL
)
1779 circuit
->rcv_stream
= stream_new (ISO_MTU (circuit
));
1781 stream_reset (circuit
->rcv_stream
);
1783 retval
= circuit
->rx (circuit
, ssnpa
);
1784 circuit
->t_read
= NULL
;
1786 if (retval
== ISIS_OK
)
1787 retval
= isis_handle_pdu (circuit
, ssnpa
);
1790 * prepare for next packet.
1792 THREAD_READ_ON (master
, circuit
->t_read
, isis_receive
, circuit
,
1800 isis_receive (struct thread
*thread
)
1802 struct isis_circuit
*circuit
;
1803 u_char ssnpa
[ETH_ALEN
];
1809 circuit
= THREAD_ARG (thread
);
1812 circuit
->t_read
= NULL
;
1814 if (circuit
->rcv_stream
== NULL
)
1815 circuit
->rcv_stream
= stream_new (ISO_MTU (circuit
));
1817 stream_reset (circuit
->rcv_stream
);
1819 retval
= circuit
->rx (circuit
, ssnpa
);
1821 if (retval
== ISIS_OK
)
1822 retval
= isis_handle_pdu (circuit
, ssnpa
);
1825 * prepare for next packet.
1827 circuit
->t_read
= thread_add_timer_msec (master
, isis_receive
, circuit
,
1829 (circuit
->area
->circuit_list
) *
1837 /* filling of the fixed isis header */
1839 fill_fixed_hdr (struct isis_fixed_hdr
*hdr
, u_char pdu_type
)
1841 memset (hdr
, 0, sizeof (struct isis_fixed_hdr
));
1843 hdr
->idrp
= ISO10589_ISIS
;
1849 hdr
->length
= ISIS_LANHELLO_HDRLEN
;
1852 hdr
->length
= ISIS_P2PHELLO_HDRLEN
;
1856 hdr
->length
= ISIS_LSP_HDR_LEN
;
1858 case L1_COMPLETE_SEQ_NUM
:
1859 case L2_COMPLETE_SEQ_NUM
:
1860 hdr
->length
= ISIS_CSNP_HDRLEN
;
1862 case L1_PARTIAL_SEQ_NUM
:
1863 case L2_PARTIAL_SEQ_NUM
:
1864 hdr
->length
= ISIS_PSNP_HDRLEN
;
1867 zlog_warn ("fill_fixed_hdr(): unknown pdu type %d", pdu_type
);
1870 hdr
->length
+= ISIS_FIXED_HDR_LEN
;
1871 hdr
->pdu_type
= pdu_type
;
1873 hdr
->id_len
= 0; /* ISIS_SYS_ID_LEN - 0==6 */
1875 hdr
->max_area_addrs
= 0; /* isis->max_area_addrs - 0==3 */
1882 fill_fixed_hdr_andstream (struct isis_fixed_hdr
*hdr
, u_char pdu_type
,
1883 struct stream
*stream
)
1885 fill_fixed_hdr (hdr
, pdu_type
);
1887 stream_putc (stream
, hdr
->idrp
);
1888 stream_putc (stream
, hdr
->length
);
1889 stream_putc (stream
, hdr
->version1
);
1890 stream_putc (stream
, hdr
->id_len
);
1891 stream_putc (stream
, hdr
->pdu_type
);
1892 stream_putc (stream
, hdr
->version2
);
1893 stream_putc (stream
, hdr
->reserved
);
1894 stream_putc (stream
, hdr
->max_area_addrs
);
1900 send_hello (struct isis_circuit
*circuit
, int level
)
1902 struct isis_fixed_hdr fixed_hdr
;
1903 struct isis_lan_hello_hdr hello_hdr
;
1904 struct isis_p2p_hello_hdr p2p_hello_hdr
;
1907 unsigned long len_pointer
, length
;
1910 if (circuit
->interface
->mtu
== 0)
1912 zlog_warn ("circuit has zero MTU");
1913 return ISIS_WARNING
;
1916 if (!circuit
->snd_stream
)
1917 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
1919 stream_reset (circuit
->snd_stream
);
1921 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1923 fill_fixed_hdr_andstream (&fixed_hdr
, L1_LAN_HELLO
,
1924 circuit
->snd_stream
);
1926 fill_fixed_hdr_andstream (&fixed_hdr
, L2_LAN_HELLO
,
1927 circuit
->snd_stream
);
1929 fill_fixed_hdr_andstream (&fixed_hdr
, P2P_HELLO
, circuit
->snd_stream
);
1932 * Fill LAN Level 1 or 2 Hello PDU header
1934 memset (&hello_hdr
, 0, sizeof (struct isis_lan_hello_hdr
));
1935 interval
= circuit
->hello_multiplier
[level
- 1] *
1936 circuit
->hello_interval
[level
- 1];
1937 if (interval
> USHRT_MAX
)
1938 interval
= USHRT_MAX
;
1939 hello_hdr
.circuit_t
= circuit
->circuit_is_type
;
1940 memcpy (hello_hdr
.source_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1941 hello_hdr
.hold_time
= htons ((u_int16_t
) interval
);
1943 hello_hdr
.pdu_len
= 0; /* Update the PDU Length later */
1944 len_pointer
= stream_get_endp (circuit
->snd_stream
) + 3 + ISIS_SYS_ID_LEN
;
1946 /* copy the shared part of the hello to the p2p hello if needed */
1947 if (circuit
->circ_type
== CIRCUIT_T_P2P
)
1949 memcpy (&p2p_hello_hdr
, &hello_hdr
, 5 + ISIS_SYS_ID_LEN
);
1950 p2p_hello_hdr
.local_id
= circuit
->circuit_id
;
1951 /* FIXME: need better understanding */
1952 stream_put (circuit
->snd_stream
, &p2p_hello_hdr
, ISIS_P2PHELLO_HDRLEN
);
1956 hello_hdr
.prio
= circuit
->u
.bc
.priority
[level
- 1];
1957 if (level
== 1 && circuit
->u
.bc
.l1_desig_is
)
1959 memcpy (hello_hdr
.lan_id
, circuit
->u
.bc
.l1_desig_is
,
1960 ISIS_SYS_ID_LEN
+ 1);
1962 else if (level
== 2 && circuit
->u
.bc
.l2_desig_is
)
1964 memcpy (hello_hdr
.lan_id
, circuit
->u
.bc
.l2_desig_is
,
1965 ISIS_SYS_ID_LEN
+ 1);
1967 stream_put (circuit
->snd_stream
, &hello_hdr
, ISIS_LANHELLO_HDRLEN
);
1971 * Then the variable length part
1973 /* add circuit password */
1974 if (circuit
->passwd
.type
)
1975 if (tlv_add_authinfo (circuit
->passwd
.type
, circuit
->passwd
.len
,
1976 circuit
->passwd
.passwd
, circuit
->snd_stream
))
1977 return ISIS_WARNING
;
1978 /* Area Addresses TLV */
1979 assert (circuit
->area
);
1980 if (circuit
->area
->area_addrs
&& circuit
->area
->area_addrs
->count
> 0)
1981 if (tlv_add_area_addrs (circuit
->area
->area_addrs
, circuit
->snd_stream
))
1982 return ISIS_WARNING
;
1984 /* LAN Neighbors TLV */
1985 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1987 if (level
== 1 && circuit
->u
.bc
.lan_neighs
[0]->count
> 0)
1988 if (tlv_add_lan_neighs (circuit
->u
.bc
.lan_neighs
[0],
1989 circuit
->snd_stream
))
1990 return ISIS_WARNING
;
1991 if (level
== 2 && circuit
->u
.bc
.lan_neighs
[1]->count
> 0)
1992 if (tlv_add_lan_neighs (circuit
->u
.bc
.lan_neighs
[1],
1993 circuit
->snd_stream
))
1994 return ISIS_WARNING
;
1997 /* Protocols Supported TLV */
1998 if (circuit
->nlpids
.count
> 0)
1999 if (tlv_add_nlpid (&circuit
->nlpids
, circuit
->snd_stream
))
2000 return ISIS_WARNING
;
2001 /* IP interface Address TLV */
2002 if (circuit
->ip_router
&& circuit
->ip_addrs
&& circuit
->ip_addrs
->count
> 0)
2003 if (tlv_add_ip_addrs (circuit
->ip_addrs
, circuit
->snd_stream
))
2004 return ISIS_WARNING
;
2007 /* IPv6 Interface Address TLV */
2008 if (circuit
->ipv6_router
&& circuit
->ipv6_link
&&
2009 circuit
->ipv6_link
->count
> 0)
2010 if (tlv_add_ipv6_addrs (circuit
->ipv6_link
, circuit
->snd_stream
))
2011 return ISIS_WARNING
;
2012 #endif /* HAVE_IPV6 */
2014 if (circuit
->u
.bc
.pad_hellos
)
2015 if (tlv_add_padding (circuit
->snd_stream
))
2016 return ISIS_WARNING
;
2018 length
= stream_get_endp (circuit
->snd_stream
);
2019 /* Update PDU length */
2020 stream_putw_at (circuit
->snd_stream
, len_pointer
, (u_int16_t
) length
);
2022 retval
= circuit
->tx (circuit
, level
);
2024 zlog_warn ("sending of LAN Level %d Hello failed", level
);
2026 /* DEBUG_ADJ_PACKETS */
2027 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
2029 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
2031 zlog_debug ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %ld",
2032 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
2033 STREAM_SIZE (circuit
->snd_stream
));
2037 zlog_debug ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld",
2038 circuit
->area
->area_tag
, circuit
->interface
->name
,
2039 STREAM_SIZE (circuit
->snd_stream
));
2047 send_lan_hello (struct isis_circuit
*circuit
, int level
)
2049 return send_hello (circuit
, level
);
2053 send_lan_l1_hello (struct thread
*thread
)
2055 struct isis_circuit
*circuit
;
2058 circuit
= THREAD_ARG (thread
);
2060 circuit
->u
.bc
.t_send_lan_hello
[0] = NULL
;
2062 if (circuit
->u
.bc
.run_dr_elect
[0])
2063 retval
= isis_dr_elect (circuit
, 1);
2065 retval
= send_lan_hello (circuit
, 1);
2067 /* set next timer thread */
2068 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_send_lan_hello
[0],
2069 send_lan_l1_hello
, circuit
,
2070 isis_jitter (circuit
->hello_interval
[0], IIH_JITTER
));
2076 send_lan_l2_hello (struct thread
*thread
)
2078 struct isis_circuit
*circuit
;
2081 circuit
= THREAD_ARG (thread
);
2083 circuit
->u
.bc
.t_send_lan_hello
[1] = NULL
;
2085 if (circuit
->u
.bc
.run_dr_elect
[1])
2086 retval
= isis_dr_elect (circuit
, 2);
2088 retval
= send_lan_hello (circuit
, 2);
2090 /* set next timer thread */
2091 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_send_lan_hello
[1],
2092 send_lan_l2_hello
, circuit
,
2093 isis_jitter (circuit
->hello_interval
[1], IIH_JITTER
));
2099 send_p2p_hello (struct thread
*thread
)
2101 struct isis_circuit
*circuit
;
2103 circuit
= THREAD_ARG (thread
);
2105 circuit
->u
.p2p
.t_send_p2p_hello
= NULL
;
2107 send_hello (circuit
, 1);
2109 /* set next timer thread */
2110 THREAD_TIMER_ON (master
, circuit
->u
.p2p
.t_send_p2p_hello
, send_p2p_hello
,
2111 circuit
, isis_jitter (circuit
->hello_interval
[1],
2118 build_csnp (int level
, u_char
* start
, u_char
* stop
, struct list
*lsps
,
2119 struct isis_circuit
*circuit
)
2121 struct isis_fixed_hdr fixed_hdr
;
2122 struct isis_passwd
*passwd
;
2123 int retval
= ISIS_OK
;
2128 fill_fixed_hdr_andstream (&fixed_hdr
, L1_COMPLETE_SEQ_NUM
,
2129 circuit
->snd_stream
);
2131 fill_fixed_hdr_andstream (&fixed_hdr
, L2_COMPLETE_SEQ_NUM
,
2132 circuit
->snd_stream
);
2135 * Fill Level 1 or 2 Complete Sequence Numbers header
2138 lenp
= stream_get_endp (circuit
->snd_stream
);
2139 stream_putw (circuit
->snd_stream
, 0); /* PDU length - when we know it */
2140 /* no need to send the source here, it is always us if we csnp */
2141 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2142 /* with zero circuit id - ref 9.10, 9.11 */
2143 stream_putc (circuit
->snd_stream
, 0x00);
2145 stream_put (circuit
->snd_stream
, start
, ISIS_SYS_ID_LEN
+ 2);
2146 stream_put (circuit
->snd_stream
, stop
, ISIS_SYS_ID_LEN
+ 2);
2152 passwd
= &circuit
->area
->area_passwd
;
2154 passwd
= &circuit
->area
->domain_passwd
;
2156 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
))
2158 retval
= tlv_add_authinfo (passwd
->type
, passwd
->len
,
2159 passwd
->passwd
, circuit
->snd_stream
);
2161 if (!retval
&& lsps
)
2163 retval
= tlv_add_lsp_entries (lsps
, circuit
->snd_stream
);
2165 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
2166 assert (length
>= ISIS_CSNP_HDRLEN
);
2167 /* Update PU length */
2168 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2174 * FIXME: support multiple CSNPs
2178 send_csnp (struct isis_circuit
*circuit
, int level
)
2180 int retval
= ISIS_OK
;
2181 u_char start
[ISIS_SYS_ID_LEN
+ 2];
2182 u_char stop
[ISIS_SYS_ID_LEN
+ 2];
2183 struct list
*list
= NULL
;
2184 struct listnode
*node
, *nnode
;
2185 struct isis_lsp
*lsp
;
2187 memset (start
, 0x00, ISIS_SYS_ID_LEN
+ 2);
2188 memset (stop
, 0xff, ISIS_SYS_ID_LEN
+ 2);
2190 if (circuit
->area
->lspdb
[level
- 1] &&
2191 dict_count (circuit
->area
->lspdb
[level
- 1]) > 0)
2194 lsp_build_list (start
, stop
, list
, circuit
->area
->lspdb
[level
- 1]);
2196 if (circuit
->snd_stream
== NULL
)
2197 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
2199 stream_reset (circuit
->snd_stream
);
2201 retval
= build_csnp (level
, start
, stop
, list
, circuit
);
2203 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2205 zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld",
2206 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
2207 STREAM_SIZE (circuit
->snd_stream
));
2208 for (ALL_LIST_ELEMENTS (list
, node
, nnode
, lsp
))
2210 zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x,"
2211 " cksum 0x%04x, lifetime %us",
2212 circuit
->area
->area_tag
,
2213 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2214 ntohl (lsp
->lsp_header
->seq_num
),
2215 ntohs (lsp
->lsp_header
->checksum
),
2216 ntohs (lsp
->lsp_header
->rem_lifetime
));
2222 if (retval
== ISIS_OK
)
2223 retval
= circuit
->tx (circuit
, level
);
2229 send_l1_csnp (struct thread
*thread
)
2231 struct isis_circuit
*circuit
;
2232 int retval
= ISIS_OK
;
2234 circuit
= THREAD_ARG (thread
);
2237 circuit
->t_send_csnp
[0] = NULL
;
2239 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
&& circuit
->u
.bc
.is_dr
[0])
2241 send_csnp (circuit
, 1);
2243 /* set next timer thread */
2244 THREAD_TIMER_ON (master
, circuit
->t_send_csnp
[0], send_l1_csnp
, circuit
,
2245 isis_jitter (circuit
->csnp_interval
[0], CSNP_JITTER
));
2251 send_l2_csnp (struct thread
*thread
)
2253 struct isis_circuit
*circuit
;
2254 int retval
= ISIS_OK
;
2256 circuit
= THREAD_ARG (thread
);
2259 circuit
->t_send_csnp
[1] = NULL
;
2261 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
&& circuit
->u
.bc
.is_dr
[1])
2263 send_csnp (circuit
, 2);
2265 /* set next timer thread */
2266 THREAD_TIMER_ON (master
, circuit
->t_send_csnp
[1], send_l2_csnp
, circuit
,
2267 isis_jitter (circuit
->csnp_interval
[1], CSNP_JITTER
));
2273 build_psnp (int level
, struct isis_circuit
*circuit
, struct list
*lsps
)
2275 struct isis_fixed_hdr fixed_hdr
;
2279 struct isis_lsp
*lsp
;
2280 struct isis_passwd
*passwd
;
2281 struct listnode
*node
, *nnode
;
2284 fill_fixed_hdr_andstream (&fixed_hdr
, L1_PARTIAL_SEQ_NUM
,
2285 circuit
->snd_stream
);
2287 fill_fixed_hdr_andstream (&fixed_hdr
, L2_PARTIAL_SEQ_NUM
,
2288 circuit
->snd_stream
);
2291 * Fill Level 1 or 2 Partial Sequence Numbers header
2293 lenp
= stream_get_endp (circuit
->snd_stream
);
2294 stream_putw (circuit
->snd_stream
, 0); /* PDU length - when we know it */
2295 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2296 stream_putc (circuit
->snd_stream
, circuit
->idx
);
2303 passwd
= &circuit
->area
->area_passwd
;
2305 passwd
= &circuit
->area
->domain_passwd
;
2307 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
))
2309 retval
= tlv_add_authinfo (passwd
->type
, passwd
->len
,
2310 passwd
->passwd
, circuit
->snd_stream
);
2312 if (!retval
&& lsps
)
2314 retval
= tlv_add_lsp_entries (lsps
, circuit
->snd_stream
);
2317 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2319 for (ALL_LIST_ELEMENTS (lsps
, node
, nnode
, lsp
))
2321 zlog_debug ("ISIS-Snp (%s): PSNP entry %s, seq 0x%08x,"
2322 " cksum 0x%04x, lifetime %us",
2323 circuit
->area
->area_tag
,
2324 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2325 ntohl (lsp
->lsp_header
->seq_num
),
2326 ntohs (lsp
->lsp_header
->checksum
),
2327 ntohs (lsp
->lsp_header
->rem_lifetime
));
2331 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
2332 assert (length
>= ISIS_PSNP_HDRLEN
);
2333 /* Update PDU length */
2334 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2340 * 7.3.15.4 action on expiration of partial SNP interval
2344 send_psnp (int level
, struct isis_circuit
*circuit
)
2346 int retval
= ISIS_OK
;
2347 struct isis_lsp
*lsp
;
2348 struct list
*list
= NULL
;
2349 struct listnode
*node
, *nnode
;
2351 if ((circuit
->circ_type
== CIRCUIT_T_BROADCAST
&&
2352 !circuit
->u
.bc
.is_dr
[level
- 1]) ||
2353 circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
2356 if (circuit
->area
->lspdb
[level
- 1] &&
2357 dict_count (circuit
->area
->lspdb
[level
- 1]) > 0)
2360 lsp_build_list_ssn (circuit
, list
, circuit
->area
->lspdb
[level
- 1]);
2362 if (listcount (list
) > 0)
2364 if (circuit
->snd_stream
== NULL
)
2365 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
2367 stream_reset (circuit
->snd_stream
);
2370 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2371 zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld",
2372 circuit
->area
->area_tag
, level
,
2373 circuit
->interface
->name
,
2374 STREAM_SIZE (circuit
->snd_stream
));
2376 retval
= build_psnp (level
, circuit
, list
);
2377 if (retval
== ISIS_OK
)
2378 retval
= circuit
->tx (circuit
, level
);
2380 if (retval
== ISIS_OK
)
2383 * sending succeeded, we can clear SSN flags of this circuit
2384 * for the LSPs in list
2386 for (ALL_LIST_ELEMENTS (list
, node
, nnode
, lsp
))
2387 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
2398 send_l1_psnp (struct thread
*thread
)
2401 struct isis_circuit
*circuit
;
2402 int retval
= ISIS_OK
;
2404 circuit
= THREAD_ARG (thread
);
2407 circuit
->t_send_psnp
[0] = NULL
;
2409 send_psnp (1, circuit
);
2410 /* set next timer thread */
2411 THREAD_TIMER_ON (master
, circuit
->t_send_psnp
[0], send_l1_psnp
, circuit
,
2412 isis_jitter (circuit
->psnp_interval
[0], PSNP_JITTER
));
2418 * 7.3.15.4 action on expiration of partial SNP interval
2422 send_l2_psnp (struct thread
*thread
)
2424 struct isis_circuit
*circuit
;
2425 int retval
= ISIS_OK
;
2427 circuit
= THREAD_ARG (thread
);
2430 circuit
->t_send_psnp
[1] = NULL
;
2432 send_psnp (2, circuit
);
2434 /* set next timer thread */
2435 THREAD_TIMER_ON (master
, circuit
->t_send_psnp
[1], send_l2_psnp
, circuit
,
2436 isis_jitter (circuit
->psnp_interval
[1], PSNP_JITTER
));
2441 /* FIXME: Not used any more? */
2443 build_link_state (struct isis_lsp *lsp, struct isis_circuit *circuit,
2444 struct stream *stream)
2446 unsigned long length;
2448 stream_put (stream, lsp->pdu, ntohs (lsp->lsp_header->pdu_len));
2449 length = stream_get_endp (stream);
2455 * ISO 10589 - 7.3.14.3
2458 send_lsp (struct thread
*thread
)
2460 struct isis_circuit
*circuit
;
2461 struct isis_lsp
*lsp
;
2462 struct listnode
*node
;
2465 circuit
= THREAD_ARG (thread
);
2468 if (circuit
->state
== C_STATE_UP
)
2470 lsp
= listgetdata ((node
= listhead (circuit
->lsp_queue
)));
2473 * Do not send if levels do not match
2475 if (!(lsp
->level
& circuit
->circuit_is_type
))
2479 * Do not send if we do not have adjacencies in state up on the circuit
2481 if (circuit
->upadjcount
[lsp
->level
- 1] == 0)
2483 /* only send if it needs sending */
2484 if ((time (NULL
) - lsp
->last_sent
) >=
2485 circuit
->area
->lsp_gen_interval
[lsp
->level
- 1])
2488 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
2491 ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
2492 " lifetime %us on %s", circuit
->area
->area_tag
, lsp
->level
,
2493 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2494 ntohl (lsp
->lsp_header
->seq_num
),
2495 ntohs (lsp
->lsp_header
->checksum
),
2496 ntohs (lsp
->lsp_header
->rem_lifetime
),
2497 circuit
->interface
->name
);
2499 /* copy our lsp to the send buffer */
2500 circuit
->snd_stream
->getp
= lsp
->pdu
->getp
;
2501 circuit
->snd_stream
->endp
= lsp
->pdu
->endp
;
2502 memcpy (circuit
->snd_stream
->data
, lsp
->pdu
->data
, lsp
->pdu
->endp
);
2504 retval
= circuit
->tx (circuit
, lsp
->level
);
2507 * If the sending succeeded, we can del the lsp from circuits
2510 if (retval
== ISIS_OK
)
2512 list_delete_node (circuit
->lsp_queue
, node
);
2515 * On broadcast circuits also the SRMflag can be cleared
2517 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
2518 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
2520 if (flags_any_set (lsp
->SRMflags
) == 0)
2523 * need to remember when we were last sent
2525 lsp
->last_sent
= time (NULL
);
2530 zlog_debug ("sending of level %d link state failed", lsp
->level
);
2535 /* my belief is that if it wasn't his time, the lsp can be removed
2539 list_delete_node (circuit
->lsp_queue
, node
);
2543 * If there are still LSPs send next one after lsp-interval (33 msecs)
2545 if (listcount (circuit
->lsp_queue
) > 0)
2546 thread_add_timer (master
, send_lsp
, circuit
, 1);
2554 ack_lsp (struct isis_link_state_hdr
*hdr
, struct isis_circuit
*circuit
,
2560 struct isis_fixed_hdr fixed_hdr
;
2562 if (!circuit
->snd_stream
)
2563 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
2565 stream_reset (circuit
->snd_stream
);
2567 // fill_llc_hdr (stream);
2569 fill_fixed_hdr_andstream (&fixed_hdr
, L1_PARTIAL_SEQ_NUM
,
2570 circuit
->snd_stream
);
2572 fill_fixed_hdr_andstream (&fixed_hdr
, L2_PARTIAL_SEQ_NUM
,
2573 circuit
->snd_stream
);
2576 lenp
= stream_get_endp (circuit
->snd_stream
);
2577 stream_putw (circuit
->snd_stream
, 0); /* PDU length */
2578 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2579 stream_putc (circuit
->snd_stream
, circuit
->idx
);
2580 stream_putc (circuit
->snd_stream
, 9); /* code */
2581 stream_putc (circuit
->snd_stream
, 16); /* len */
2583 stream_putw (circuit
->snd_stream
, ntohs (hdr
->rem_lifetime
));
2584 stream_put (circuit
->snd_stream
, hdr
->lsp_id
, ISIS_SYS_ID_LEN
+ 2);
2585 stream_putl (circuit
->snd_stream
, ntohl (hdr
->seq_num
));
2586 stream_putw (circuit
->snd_stream
, ntohs (hdr
->checksum
));
2588 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
2589 /* Update PDU length */
2590 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2592 retval
= circuit
->tx (circuit
, level
);
2599 * ISH PDU Processing
2603 * Let's first check if the local and remote system have any common area
2606 if (area_match (tlvs
.area_addrs
, isis
->man_area_addrs
) == 0)
2608 if (circuit
->circuit_t
== IS_LEVEL_2
)
2610 /* do as in table 8 (p. 40) */
2611 switch (circuit_type
)
2614 if (adj
->adj_state
!= ISIS_ADJ_UP
)
2617 zlog_warn ("areaMismatch");
2618 retval
= ISIS_WARNING
;
2620 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
2622 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch",
2625 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
||
2626 adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
2628 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System",
2633 if (adj
->adj_state
!= ISIS_ADJ_UP
)
2635 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
,
2637 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
2639 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
||
2640 adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
2642 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System",
2645 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
2650 case IS_LEVEL_1_AND_2
:
2651 if (adj
->adj_state
!= ISIS_ADJ_UP
)
2653 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
,
2655 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
2657 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
2659 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System",
2662 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
2664 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch",
2667 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
2677 isis_delete_adj (adj
, circuit
->adjdb
);
2678 zlog_warn ("areaMismatch");
2679 return ISIS_WARNING
;