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
, *node2
;
85 LIST_LOOP (left
, addr1
, node1
)
87 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
))
95 return 0; /* mismatch */
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
106 ip_same_subnet (struct prefix_ipv4
*ip1
, struct in_addr
*ip2
)
108 u_char
*addr1
, *addr2
;
109 int shift
, offset
, offsetloop
;
112 addr1
= (u_char
*) & ip1
->prefix
.s_addr
;
113 addr2
= (u_char
*) & ip2
->s_addr
;
114 len
= ip1
->prefixlen
;
117 offsetloop
= offset
= len
/ PNBBY
;
120 if (addr1
[offsetloop
] != addr2
[offsetloop
])
124 if (maskbit
[shift
] & (addr1
[offset
] ^ addr2
[offset
]))
127 return 1; /* match */
131 * Compares two set of ip addresses
132 * param left the local interface's ip addresses
133 * param right the iih interface's ip address
138 ip_match (struct list
*left
, struct list
*right
)
140 struct prefix_ipv4
*ip1
;
142 struct listnode
*node1
, *node2
;
144 if ((left
== NULL
) || (right
== NULL
))
147 LIST_LOOP (left
, ip1
, node1
)
149 LIST_LOOP (right
, ip2
, node2
)
151 if (ip_same_subnet (ip1
, ip2
))
153 return 1; /* match */
162 * Checks whether we should accept a PDU of given level
165 accept_level (int level
, int circuit_t
)
167 int retval
= ((circuit_t
& level
) == level
); /* simple approach */
173 authentication_check (struct isis_passwd
*one
, struct isis_passwd
*theother
)
175 if (one
->type
!= theother
->type
)
177 zlog_warn ("Unsupported authentication type %d", theother
->type
);
178 return 1; /* Auth fail (different authentication types) */
182 case ISIS_PASSWD_TYPE_CLEARTXT
:
183 if (one
->len
!= theother
->len
)
184 return 1; /* Auth fail () - passwd len mismatch */
185 return memcmp (one
->passwd
, theother
->passwd
, one
->len
);
188 zlog_warn ("Unsupported authentication type");
191 return 0; /* Auth pass */
195 * Processing helper functions
198 tlvs_to_adj_nlpids (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
201 struct nlpids
*tlv_nlpids
;
206 tlv_nlpids
= tlvs
->nlpids
;
208 adj
->nlpids
.count
= tlv_nlpids
->count
;
210 for (i
= 0; i
< tlv_nlpids
->count
; i
++)
212 adj
->nlpids
.nlpids
[i
] = tlv_nlpids
->nlpids
[i
];
218 del_ip_addr (void *val
)
220 XFREE (MTYPE_ISIS_TMP
, val
);
224 tlvs_to_adj_ipv4_addrs (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
226 struct listnode
*node
;
227 struct in_addr
*ipv4_addr
, *malloced
;
231 adj
->ipv4_addrs
->del
= del_ip_addr
;
232 list_delete (adj
->ipv4_addrs
);
234 adj
->ipv4_addrs
= list_new ();
235 if (tlvs
->ipv4_addrs
)
237 LIST_LOOP (tlvs
->ipv4_addrs
, ipv4_addr
, node
)
239 malloced
= XMALLOC (MTYPE_ISIS_TMP
, sizeof (struct in_addr
));
240 memcpy (malloced
, ipv4_addr
, sizeof (struct in_addr
));
241 listnode_add (adj
->ipv4_addrs
, malloced
);
248 tlvs_to_adj_ipv6_addrs (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
250 struct listnode
*node
;
251 struct in6_addr
*ipv6_addr
, *malloced
;
255 adj
->ipv6_addrs
->del
= del_ip_addr
;
256 list_delete (adj
->ipv6_addrs
);
258 adj
->ipv6_addrs
= list_new ();
259 if (tlvs
->ipv6_addrs
)
261 LIST_LOOP (tlvs
->ipv6_addrs
, ipv6_addr
, node
)
263 malloced
= XMALLOC (MTYPE_ISIS_TMP
, sizeof (struct in6_addr
));
264 memcpy (malloced
, ipv6_addr
, sizeof (struct in6_addr
));
265 listnode_add (adj
->ipv6_addrs
, malloced
);
270 #endif /* HAVE_IPV6 */
279 * Section 8.2.5 - Receiving point-to-point IIH PDUs
283 process_p2p_hello (struct isis_circuit
*circuit
)
285 int retval
= ISIS_OK
;
286 struct isis_p2p_hello_hdr
*hdr
;
287 struct isis_adjacency
*adj
;
288 u_int32_t expected
= 0, found
;
291 if ((stream_get_endp (circuit
->rcv_stream
) -
292 stream_get_getp (circuit
->rcv_stream
)) < ISIS_P2PHELLO_HDRLEN
)
294 zlog_warn ("Packet too short");
298 /* 8.2.5.1 PDU acceptance tests */
300 /* 8.2.5.1 a) external domain untrue */
301 /* FIXME: not useful at all? */
303 /* 8.2.5.1 b) ID Length mismatch */
304 /* checked at the handle_pdu */
306 /* 8.2.5.2 IIH PDU Processing */
308 /* 8.2.5.2 a) 1) Maximum Area Addresses */
309 /* Already checked, and can also be ommited */
314 hdr
= (struct isis_p2p_hello_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
315 circuit
->rcv_stream
->getp
+= ISIS_P2PHELLO_HDRLEN
;
317 /* hdr.circuit_t = stream_getc (stream);
318 stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN);
319 hdr.hold_time = stream_getw (stream);
320 hdr.pdu_len = stream_getw (stream);
321 hdr.local_id = stream_getc (stream); */
324 * My interpertation of the ISO, if no adj exists we will create one for
328 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
330 zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
331 " cir id %02d, length %d",
332 circuit
->area
->area_tag
, circuit
->interface
->name
,
333 circuit_t2string (circuit
->circuit_is_type
),
334 circuit
->circuit_id
, ntohs (hdr
->pdu_len
));
337 adj
= circuit
->u
.p2p
.neighbor
;
340 adj
= isis_new_adj (hdr
->source_id
, (u_char
*) " ", 0, circuit
);
343 circuit
->u
.p2p
.neighbor
= adj
;
344 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
345 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
348 /* 8.2.6 Monitoring point-to-point adjacencies */
349 adj
->hold_time
= ntohs (hdr
->hold_time
);
350 adj
->last_upd
= time (NULL
);
353 * Lets get the TLVS now
355 expected
|= TLVFLAG_AREA_ADDRS
;
356 expected
|= TLVFLAG_AUTH_INFO
;
357 expected
|= TLVFLAG_NLPID
;
358 expected
|= TLVFLAG_IPV4_ADDR
;
359 expected
|= TLVFLAG_IPV6_ADDR
;
361 retval
= parse_tlvs (circuit
->area
->area_tag
,
362 STREAM_PNT (circuit
->rcv_stream
),
363 ntohs (hdr
->pdu_len
) - ISIS_P2PHELLO_HDRLEN
364 - ISIS_FIXED_HDR_LEN
, &expected
, &found
, &tlvs
);
366 if (retval
> ISIS_WARNING
)
372 /* 8.2.5.1 c) Authentication */
373 if (circuit
->passwd
.type
)
375 if (!(found
& TLVFLAG_AUTH_INFO
) ||
376 authentication_check (&circuit
->passwd
, &tlvs
.auth_info
))
378 isis_event_auth_failure (circuit
->area
->area_tag
,
379 "P2P hello authentication failure",
385 /* we do this now because the adj may not survive till the end... */
387 /* we need to copy addresses to the adj */
388 tlvs_to_adj_ipv4_addrs (&tlvs
, adj
);
391 tlvs_to_adj_ipv6_addrs (&tlvs
, adj
);
392 #endif /* HAVE_IPV6 */
394 /* lets take care of the expiry */
395 THREAD_TIMER_OFF (adj
->t_expire
);
396 THREAD_TIMER_ON (master
, adj
->t_expire
, isis_adj_expire
, adj
,
397 (long) adj
->hold_time
);
399 /* 8.2.5.2 a) a match was detected */
400 if (area_match (circuit
->area
->area_addrs
, tlvs
.area_addrs
))
402 /* 8.2.5.2 a) 2) If the system is L1 - table 5 */
403 if (circuit
->area
->is_type
== IS_LEVEL_1
)
405 switch (hdr
->circuit_t
)
408 case IS_LEVEL_1_AND_2
:
409 if (adj
->adj_state
!= ISIS_ADJ_UP
)
411 /* (4) adj state up */
412 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
413 /* (5) adj usage level 1 */
414 adj
->adj_usage
= ISIS_ADJ_LEVEL1
;
416 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
422 if (adj
->adj_state
!= ISIS_ADJ_UP
)
424 /* (7) reject - wrong system type event */
425 zlog_warn ("wrongSystemType");
426 return ISIS_WARNING
; /* Reject */
428 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
430 /* (6) down - wrong system */
431 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
437 /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */
438 if (circuit
->area
->is_type
== IS_LEVEL_1_AND_2
)
440 switch (hdr
->circuit_t
)
443 if (adj
->adj_state
!= ISIS_ADJ_UP
)
445 /* (6) adj state up */
446 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
447 /* (7) adj usage level 1 */
448 adj
->adj_usage
= ISIS_ADJ_LEVEL1
;
450 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
454 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
455 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
457 /* (8) down - wrong system */
458 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
462 if (adj
->adj_state
!= ISIS_ADJ_UP
)
464 /* (6) adj state up */
465 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
466 /* (9) adj usage level 2 */
467 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
469 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1
) ||
470 (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
))
472 /* (8) down - wrong system */
473 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
475 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
480 case IS_LEVEL_1_AND_2
:
481 if (adj
->adj_state
!= ISIS_ADJ_UP
)
483 /* (6) adj state up */
484 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
485 /* (10) adj usage level 1 */
486 adj
->adj_usage
= ISIS_ADJ_LEVEL1AND2
;
488 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1
) ||
489 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
491 /* (8) down - wrong system */
492 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
494 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
502 /* 8.2.5.2 a) 4) If the system is L2 - table 7 */
503 if (circuit
->area
->is_type
== IS_LEVEL_2
)
505 switch (hdr
->circuit_t
)
508 if (adj
->adj_state
!= ISIS_ADJ_UP
)
510 /* (5) reject - wrong system type event */
511 zlog_warn ("wrongSystemType");
512 return ISIS_WARNING
; /* Reject */
514 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
515 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
517 /* (6) down - wrong system */
518 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
521 case IS_LEVEL_1_AND_2
:
523 if (adj
->adj_state
!= ISIS_ADJ_UP
)
525 /* (7) adj state up */
526 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
527 /* (8) adj usage level 2 */
528 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
530 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
532 /* (6) down - wrong system */
533 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
535 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
543 /* 8.2.5.2 b) if no match was detected */
546 if (circuit
->area
->is_type
== IS_LEVEL_1
)
548 /* 8.2.5.2 b) 1) is_type L1 and adj is not up */
549 if (adj
->adj_state
!= ISIS_ADJ_UP
)
551 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch");
552 /* 8.2.5.2 b) 2)is_type L1 and adj is up */
556 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
557 "Down - Area Mismatch");
560 /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */
563 switch (hdr
->circuit_t
)
566 if (adj
->adj_state
!= ISIS_ADJ_UP
)
568 /* (6) reject - Area Mismatch event */
569 zlog_warn ("AreaMismatch");
570 return ISIS_WARNING
; /* Reject */
572 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
574 /* (7) down - area mismatch */
575 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch");
578 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
579 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
581 /* (7) down - wrong system */
582 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
585 case IS_LEVEL_1_AND_2
:
587 if (adj
->adj_state
!= ISIS_ADJ_UP
)
589 /* (8) adj state up */
590 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
591 /* (9) adj usage level 2 */
592 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
594 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
596 /* (7) down - wrong system */
597 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
599 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
601 if (hdr
->circuit_t
== IS_LEVEL_2
)
603 /* (7) down - wrong system */
604 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
609 /* (7) down - area mismatch */
610 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
614 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
622 /* 8.2.5.2 c) if the action was up - comparing circuit IDs */
623 /* FIXME - Missing parts */
625 /* some of my own understanding of the ISO, why the heck does
626 * it not say what should I change the system_type to...
628 switch (adj
->adj_usage
)
630 case ISIS_ADJ_LEVEL1
:
631 adj
->sys_type
= ISIS_SYSTYPE_L1_IS
;
633 case ISIS_ADJ_LEVEL2
:
634 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
636 case ISIS_ADJ_LEVEL1AND2
:
637 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
640 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
644 adj
->circuit_t
= hdr
->circuit_t
;
645 adj
->level
= hdr
->circuit_t
;
653 * Process IS-IS LAN Level 1/2 Hello PDU
656 process_lan_hello (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
658 int retval
= ISIS_OK
;
659 struct isis_lan_hello_hdr hdr
;
660 struct isis_adjacency
*adj
;
661 u_int32_t expected
= 0, found
;
664 struct listnode
*node
;
666 if ((stream_get_endp (circuit
->rcv_stream
) -
667 stream_get_getp (circuit
->rcv_stream
)) < ISIS_LANHELLO_HDRLEN
)
669 zlog_warn ("Packet too short");
673 if (circuit
->ext_domain
)
675 zlog_debug ("level %d LAN Hello received over circuit with "
676 "externalDomain = true", level
);
680 if (!accept_level (level
, circuit
->circuit_is_type
))
682 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
684 zlog_debug ("ISIS-Adj (%s): Interface level mismatch, %s",
685 circuit
->area
->area_tag
, circuit
->interface
->name
);
691 /* Cisco's debug message compatability */
692 if (!accept_level (level
, circuit
->area
->is_type
))
694 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
696 zlog_debug ("ISIS-Adj (%s): is type mismatch",
697 circuit
->area
->area_tag
);
705 hdr
.circuit_t
= stream_getc (circuit
->rcv_stream
);
706 stream_get (hdr
.source_id
, circuit
->rcv_stream
, ISIS_SYS_ID_LEN
);
707 hdr
.hold_time
= stream_getw (circuit
->rcv_stream
);
708 hdr
.pdu_len
= stream_getw (circuit
->rcv_stream
);
709 hdr
.prio
= stream_getc (circuit
->rcv_stream
);
710 stream_get (hdr
.lan_id
, circuit
->rcv_stream
, ISIS_SYS_ID_LEN
+ 1);
712 if (hdr
.circuit_t
!= IS_LEVEL_1
&& hdr
.circuit_t
!= IS_LEVEL_2
&&
713 hdr
.circuit_t
!= IS_LEVEL_1_AND_2
)
715 zlog_warn ("Level %d LAN Hello with Circuit Type %d", level
,
722 expected
|= TLVFLAG_AUTH_INFO
;
723 expected
|= TLVFLAG_AREA_ADDRS
;
724 expected
|= TLVFLAG_LAN_NEIGHS
;
725 expected
|= TLVFLAG_NLPID
;
726 expected
|= TLVFLAG_IPV4_ADDR
;
727 expected
|= TLVFLAG_IPV6_ADDR
;
729 retval
= parse_tlvs (circuit
->area
->area_tag
,
730 STREAM_PNT (circuit
->rcv_stream
),
731 hdr
.pdu_len
- ISIS_LANHELLO_HDRLEN
-
732 ISIS_FIXED_HDR_LEN
, &expected
, &found
, &tlvs
);
734 if (retval
> ISIS_WARNING
)
736 zlog_warn ("parse_tlvs() failed");
740 if (!(found
& TLVFLAG_AREA_ADDRS
))
742 zlog_warn ("No Area addresses TLV in Level %d LAN IS to IS hello",
744 retval
= ISIS_WARNING
;
748 if (circuit
->passwd
.type
)
750 if (!(found
& TLVFLAG_AUTH_INFO
) ||
751 authentication_check (&circuit
->passwd
, &tlvs
.auth_info
))
753 isis_event_auth_failure (circuit
->area
->area_tag
,
754 "LAN hello authentication failure",
756 retval
= ISIS_WARNING
;
762 * Accept the level 1 adjacency only if a match between local and
763 * remote area addresses is found
765 if (level
== 1 && !area_match (circuit
->area
->area_addrs
, tlvs
.area_addrs
))
767 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
769 zlog_debug ("ISIS-Adj (%s): Area mismatch, level %d IIH on %s",
770 circuit
->area
->area_tag
, level
,
771 circuit
->interface
->name
);
778 * it's own IIH PDU - discard silently
780 if (!memcmp (circuit
->u
.bc
.snpa
, ssnpa
, ETH_ALEN
))
782 zlog_debug ("ISIS-Adj (%s): it's own IIH PDU - discarded",
783 circuit
->area
->area_tag
);
790 * check if it's own interface ip match iih ip addrs
792 if (!(found
& TLVFLAG_IPV4_ADDR
)
793 || !ip_match (circuit
->ip_addrs
, tlvs
.ipv4_addrs
))
796 ("ISIS-Adj: No usable IP interface addresses in LAN IIH from %s\n",
797 circuit
->interface
->name
);
798 retval
= ISIS_WARNING
;
802 adj
= isis_adj_lookup (hdr
.source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
808 adj
= isis_new_adj (hdr
.source_id
, ssnpa
, level
, circuit
);
816 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
820 adj
->sys_type
= ISIS_SYSTYPE_L1_IS
;
824 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
826 list_delete_all_node (circuit
->u
.bc
.lan_neighs
[level
- 1]);
827 isis_adj_build_neigh_list (circuit
->u
.bc
.adjdb
[level
- 1],
828 circuit
->u
.bc
.lan_neighs
[level
- 1]);
831 if(adj
->dis_record
[level
-1].dis
==ISIS_IS_DIS
)
835 if (memcmp (circuit
->u
.bc
.l1_desig_is
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1))
837 thread_add_event (master
, isis_event_dis_status_change
, circuit
, 0);
838 memcpy (&circuit
->u
.bc
.l1_desig_is
, hdr
.lan_id
,
839 ISIS_SYS_ID_LEN
+ 1);
843 if (memcmp (circuit
->u
.bc
.l2_desig_is
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1))
845 thread_add_event (master
, isis_event_dis_status_change
, circuit
, 0);
846 memcpy (&circuit
->u
.bc
.l2_desig_is
, hdr
.lan_id
,
847 ISIS_SYS_ID_LEN
+ 1);
852 adj
->hold_time
= hdr
.hold_time
;
853 adj
->last_upd
= time (NULL
);
854 adj
->prio
[level
- 1] = hdr
.prio
;
856 memcpy (adj
->lanid
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1);
858 /* which protocol are spoken ??? */
859 if (found
& TLVFLAG_NLPID
)
860 tlvs_to_adj_nlpids (&tlvs
, adj
);
862 /* we need to copy addresses to the adj */
863 if (found
& TLVFLAG_IPV4_ADDR
)
864 tlvs_to_adj_ipv4_addrs (&tlvs
, adj
);
867 if (found
& TLVFLAG_IPV6_ADDR
)
868 tlvs_to_adj_ipv6_addrs (&tlvs
, adj
);
869 #endif /* HAVE_IPV6 */
871 adj
->circuit_t
= hdr
.circuit_t
;
873 /* lets take care of the expiry */
874 THREAD_TIMER_OFF (adj
->t_expire
);
875 THREAD_TIMER_ON (master
, adj
->t_expire
, isis_adj_expire
, adj
,
876 (long) adj
->hold_time
);
879 * If the snpa for this circuit is found from LAN Neighbours TLV
880 * we have two-way communication -> adjacency can be put to state "up"
883 if (found
& TLVFLAG_LAN_NEIGHS
)
885 if (adj
->adj_state
!= ISIS_ADJ_UP
)
887 LIST_LOOP (tlvs
.lan_neighs
, snpa
, node
)
888 if (!memcmp (snpa
, circuit
->u
.bc
.snpa
, ETH_ALEN
))
890 isis_adj_state_change (adj
, ISIS_ADJ_UP
,
891 "own SNPA found in LAN Neighbours TLV");
897 /* DEBUG_ADJ_PACKETS */
898 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
900 /* FIXME: is this place right? fix missing info */
901 zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "
902 "cirID %u, length %ld",
903 circuit
->area
->area_tag
,
904 level
, snpa_print (ssnpa
), circuit
->interface
->name
,
905 circuit_t2string (circuit
->circuit_is_type
),
906 circuit
->circuit_id
, stream_get_endp (circuit
->rcv_stream
));
915 * Process Level 1/2 Link State
917 * Section 7.3.15.1 - Action on receipt of a link state PDU
920 process_lsp (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
922 struct isis_link_state_hdr
*hdr
;
923 struct isis_adjacency
*adj
= NULL
;
924 struct isis_lsp
*lsp
, *lsp0
= NULL
;
925 int retval
= ISIS_OK
, comp
= 0;
926 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
927 struct isis_passwd
*passwd
;
929 /* Sanity check - FIXME: move to correct place */
930 if ((stream_get_endp (circuit
->rcv_stream
) -
931 stream_get_getp (circuit
->rcv_stream
)) < ISIS_LSP_HDR_LEN
)
933 zlog_warn ("Packet too short");
937 /* Reference the header */
938 hdr
= (struct isis_link_state_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
940 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
942 zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "
943 "lifetime %us, len %lu, on %s",
944 circuit
->area
->area_tag
,
946 rawlspid_print (hdr
->lsp_id
),
947 ntohl (hdr
->seq_num
),
948 ntohs (hdr
->checksum
),
949 ntohs (hdr
->rem_lifetime
),
950 circuit
->rcv_stream
->endp
, circuit
->interface
->name
);
953 assert (ntohs (hdr
->pdu_len
) > ISIS_LSP_HDR_LEN
);
955 /* Checksum sanity check - FIXME: move to correct place */
956 /* 12 = sysid+pdu+remtime */
957 if (iso_csum_verify (STREAM_PNT (circuit
->rcv_stream
) + 4,
958 ntohs (hdr
->pdu_len
) - 12, &hdr
->checksum
))
960 zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
961 circuit
->area
->area_tag
,
962 rawlspid_print (hdr
->lsp_id
), ntohs (hdr
->checksum
));
967 /* 7.3.15.1 a) 1 - external domain circuit will discard lsps */
968 if (circuit
->ext_domain
)
971 ("ISIS-Upd (%s): LSP %s received at level %d over circuit with "
972 "externalDomain = true", circuit
->area
->area_tag
,
973 rawlspid_print (hdr
->lsp_id
), level
);
978 /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
979 if (!accept_level (level
, circuit
->circuit_is_type
))
981 zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of"
983 circuit
->area
->area_tag
,
984 rawlspid_print (hdr
->lsp_id
),
985 level
, circuit_t2string (circuit
->circuit_is_type
));
990 /* 7.3.15.1 a) 4 - need to make sure IDLength matches */
992 /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */
994 /* 7.3.15.1 a) 7 - password check */
995 (level
== ISIS_LEVEL1
) ? (passwd
= &circuit
->area
->area_passwd
) :
996 (passwd
= &circuit
->area
->domain_passwd
);
999 if (isis_lsp_authinfo_check (circuit
->rcv_stream
, circuit
->area
,
1000 ntohs (hdr
->pdu_len
), passwd
))
1002 isis_event_auth_failure (circuit
->area
->area_tag
,
1003 "LSP authentication failure", hdr
->lsp_id
);
1004 return ISIS_WARNING
;
1007 /* Find the LSP in our database and compare it to this Link State header */
1008 lsp
= lsp_search (hdr
->lsp_id
, circuit
->area
->lspdb
[level
- 1]);
1010 comp
= lsp_compare (circuit
->area
->area_tag
, lsp
, hdr
->seq_num
,
1011 hdr
->checksum
, hdr
->rem_lifetime
);
1012 if (lsp
&& (lsp
->own_lsp
1013 #ifdef TOPOLOGY_GENERATE
1014 || lsp
->from_topology
1015 #endif /* TOPOLOGY_GENERATE */
1019 /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level */
1020 /* for broadcast circuits, snpa should be compared */
1021 /* FIXME : Point To Point */
1023 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1025 adj
= isis_adj_lookup_snpa (ssnpa
, circuit
->u
.bc
.adjdb
[level
- 1]);
1028 zlog_debug ("(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, "
1029 "lifetime %us on %s",
1030 circuit
->area
->area_tag
,
1031 rawlspid_print (hdr
->lsp_id
),
1032 ntohl (hdr
->seq_num
),
1033 ntohs (hdr
->checksum
),
1034 ntohs (hdr
->rem_lifetime
), circuit
->interface
->name
);
1035 return ISIS_WARNING
; /* Silently discard */
1039 /* for non broadcast, we just need to find same level adj */
1042 /* If no adj, or no sharing of level */
1043 if (!circuit
->u
.p2p
.neighbor
)
1045 return ISIS_OK
; /* Silently discard */
1049 if (((level
== 1) &&
1050 (circuit
->u
.p2p
.neighbor
->adj_usage
== ISIS_ADJ_LEVEL2
)) ||
1052 (circuit
->u
.p2p
.neighbor
->adj_usage
== ISIS_ADJ_LEVEL1
)))
1053 return ISIS_WARNING
; /* Silently discard */
1057 /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */
1059 /* 7.3.15.1 a) 8 - Passwords for level 2 - not implemented */
1061 /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented FIXME: do it */
1063 /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */
1064 if (hdr
->rem_lifetime
== 0)
1068 /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't save */
1069 /* only needed on explicit update, eg - p2p */
1070 if (circuit
->circ_type
== CIRCUIT_T_P2P
)
1071 ack_lsp (hdr
, circuit
, level
);
1072 return retval
; /* FIXME: do we need a purge? */
1076 if (memcmp (hdr
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
1078 /* LSP by some other system -> do 7.3.16.4 b) */
1079 /* 7.3.16.4 b) 1) */
1080 if (comp
== LSP_NEWER
)
1082 lsp_update (lsp
, hdr
, circuit
->rcv_stream
, circuit
->area
);
1084 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1086 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1088 ISIS_FLAGS_CLEAR_ALL (lsp
->SSNflags
); /* FIXME: OTHER than c */
1090 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1091 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1093 } /* 7.3.16.4 b) 2) */
1094 else if (comp
== LSP_EQUAL
)
1097 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1099 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1100 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1101 } /* 7.3.16.4 b) 3) */
1104 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1105 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1110 /* our own LSP -> 7.3.16.4 c) */
1111 if (LSP_PSEUDO_ID (lsp
->lsp_header
->lsp_id
) !=
1113 || (LSP_PSEUDO_ID (lsp
->lsp_header
->lsp_id
) ==
1115 && circuit
->u
.bc
.is_dr
[level
- 1] == 1))
1117 lsp
->lsp_header
->seq_num
= htonl (ntohl (hdr
->seq_num
) + 1);
1118 zlog_debug ("LSP LEN: %d", ntohs (lsp
->lsp_header
->pdu_len
));
1119 iso_csum_create (STREAM_DATA (lsp
->pdu
) + 12,
1120 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
1121 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1123 ("ISIS-Upd (%s): (1) re-originating LSP %s new seq 0x%08x",
1124 circuit
->area
->area_tag
, rawlspid_print (hdr
->lsp_id
),
1125 ntohl (lsp
->lsp_header
->seq_num
));
1126 lsp
->lsp_header
->rem_lifetime
=
1128 (circuit
->area
->max_lsp_lifetime
[level
- 1],
1133 /* Got purge for own pseudo-lsp, and we are not DR */
1134 lsp_purge_dr (lsp
->lsp_header
->lsp_id
, circuit
, level
);
1140 /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a
1142 if (memcmp (hdr
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
) == 0)
1146 /* 7.3.16.4: initiate a purge */
1147 lsp_purge_non_exist (hdr
, circuit
->area
);
1150 /* 7.3.15.1 d) - If this is our own lsp and we have it */
1152 /* In 7.3.16.1, If an Intermediate system R somewhere in the domain
1153 * has information that the current sequence number for source S is
1154 * "greater" than that held by S, ... */
1156 else if (ntohl (hdr
->seq_num
) > ntohl (lsp
->lsp_header
->seq_num
))
1159 lsp
->lsp_header
->seq_num
= htonl (ntohl (hdr
->seq_num
) + 1);
1161 iso_csum_create (STREAM_DATA (lsp
->pdu
) + 12,
1162 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
1164 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1166 ("ISIS-Upd (%s): (2) re-originating LSP %s new seq 0x%08x",
1167 circuit
->area
->area_tag
, rawlspid_print (hdr
->lsp_id
),
1168 ntohl (lsp
->lsp_header
->seq_num
));
1169 lsp
->lsp_header
->rem_lifetime
=
1171 (circuit
->area
->max_lsp_lifetime
[level
- 1],
1177 /* 7.3.15.1 e) - This lsp originated on another system */
1179 /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */
1180 if ((!lsp
|| comp
== LSP_NEWER
))
1185 #ifdef EXTREME_DEBUG
1186 zlog_debug ("level %d number is - %ld", level
,
1187 circuit
->area
->lspdb
[level
- 1]->dict_nodecount
);
1188 #endif /* EXTREME DEBUG */
1189 lsp_search_and_destroy (hdr
->lsp_id
,
1190 circuit
->area
->lspdb
[level
- 1]);
1191 /* exists, so we overwrite */
1192 #ifdef EXTREME_DEBUG
1193 zlog_debug ("level %d number is - %ld", level
,
1194 circuit
->area
->lspdb
[level
- 1]->dict_nodecount
);
1195 #endif /* EXTREME DEBUG */
1198 * If this lsp is a frag, need to see if we have zero lsp present
1200 if (LSP_FRAGMENT (hdr
->lsp_id
) != 0)
1202 memcpy (lspid
, hdr
->lsp_id
, ISIS_SYS_ID_LEN
+ 1);
1203 LSP_FRAGMENT (lspid
) = 0;
1204 lsp0
= lsp_search (lspid
, circuit
->area
->lspdb
[level
- 1]);
1207 zlog_debug ("Got lsp frag, while zero lsp not database");
1212 lsp_new_from_stream_ptr (circuit
->rcv_stream
,
1213 ntohs (hdr
->pdu_len
), lsp0
,
1217 lsp_insert (lsp
, circuit
->area
->lspdb
[level
- 1]);
1219 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1221 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1224 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1225 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1228 /* 7.3.15.1 e) 2) LSP equal to the one in db */
1229 else if (comp
== LSP_EQUAL
)
1231 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1232 lsp_update (lsp
, hdr
, circuit
->rcv_stream
, circuit
->area
);
1233 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1235 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1238 /* 7.3.15.1 e) 3) LSP older than the one in db */
1241 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1242 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1251 * Process Sequence Numbers
1253 * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU
1257 process_snp (int snp_type
, int level
, struct isis_circuit
*circuit
,
1260 int retval
= ISIS_OK
;
1262 char typechar
= ' ';
1264 struct isis_adjacency
*adj
;
1265 struct isis_complete_seqnum_hdr
*chdr
= NULL
;
1266 struct isis_partial_seqnum_hdr
*phdr
= NULL
;
1267 uint32_t found
= 0, expected
= 0;
1268 struct isis_lsp
*lsp
;
1269 struct lsp_entry
*entry
;
1270 struct listnode
*node
, *node2
;
1272 struct list
*lsp_list
= NULL
;
1273 struct isis_passwd
*passwd
;
1275 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1277 /* getting the header info */
1280 (struct isis_complete_seqnum_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
1281 circuit
->rcv_stream
->getp
+= ISIS_CSNP_HDRLEN
;
1282 len
= ntohs (chdr
->pdu_len
);
1283 if (len
< ISIS_CSNP_HDRLEN
)
1285 zlog_warn ("Received a CSNP with bogus length!");
1293 (struct isis_partial_seqnum_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
1294 circuit
->rcv_stream
->getp
+= ISIS_PSNP_HDRLEN
;
1295 len
= ntohs (phdr
->pdu_len
);
1296 if (len
< ISIS_PSNP_HDRLEN
)
1298 zlog_warn ("Received a CSNP with bogus length!");
1303 /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */
1304 if (circuit
->ext_domain
)
1307 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1308 "skipping: circuit externalDomain = true",
1309 circuit
->area
->area_tag
,
1310 level
, typechar
, circuit
->interface
->name
);
1315 /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
1316 if (!accept_level (level
, circuit
->circuit_is_type
))
1319 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1320 "skipping: circuit type %s does not match level %d",
1321 circuit
->area
->area_tag
,
1324 circuit
->interface
->name
,
1325 circuit_t2string (circuit
->circuit_is_type
), level
);
1330 /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */
1331 if ((snp_type
== ISIS_SNP_PSNP_FLAG
) &&
1332 (circuit
->circ_type
== CIRCUIT_T_BROADCAST
))
1334 if (!circuit
->u
.bc
.is_dr
[level
- 1])
1337 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
1338 "skipping: we are not the DIS",
1339 circuit
->area
->area_tag
,
1341 typechar
, snpa_print (ssnpa
), circuit
->interface
->name
);
1347 /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */
1349 /* 7.3.15.2 a) 6 - maximum area match, can be ommited since we only use 3
1350 * - already checked */
1352 /* 7.3.15.2 a) 7 - Must check that we have an adjacency of the same level */
1353 /* for broadcast circuits, snpa should be compared */
1354 /* FIXME : Do we need to check SNPA? */
1355 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1357 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1360 isis_adj_lookup (chdr
->source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
1364 /* a psnp on a broadcast, how lovely of Juniper :) */
1366 isis_adj_lookup (phdr
->source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
1369 return ISIS_OK
; /* Silently discard */
1373 if (!circuit
->u
.p2p
.neighbor
)
1374 return ISIS_OK
; /* Silently discard */
1377 /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */
1379 /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */
1381 memset (&tlvs
, 0, sizeof (struct tlvs
));
1384 expected
|= TLVFLAG_LSP_ENTRIES
;
1385 expected
|= TLVFLAG_AUTH_INFO
;
1386 retval
= parse_tlvs (circuit
->area
->area_tag
,
1387 STREAM_PNT (circuit
->rcv_stream
),
1388 len
- circuit
->rcv_stream
->getp
,
1389 &expected
, &found
, &tlvs
);
1391 if (retval
> ISIS_WARNING
)
1393 zlog_warn ("something went very wrong processing SNP");
1399 passwd
= &circuit
->area
->area_passwd
;
1401 passwd
= &circuit
->area
->domain_passwd
;
1403 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_RECV
))
1407 if (!(found
& TLVFLAG_AUTH_INFO
) ||
1408 authentication_check (passwd
, &tlvs
.auth_info
))
1410 isis_event_auth_failure (circuit
->area
->area_tag
,
1411 "SNP authentication" " failure",
1412 phdr
? phdr
->source_id
: chdr
->source_id
);
1418 /* debug isis snp-packets */
1419 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
1421 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s",
1422 circuit
->area
->area_tag
,
1424 typechar
, snpa_print (ssnpa
), circuit
->interface
->name
);
1425 if (tlvs
.lsp_entries
)
1427 LIST_LOOP (tlvs
.lsp_entries
, entry
, node
)
1429 zlog_debug ("ISIS-Snp (%s): %cSNP entry %s, seq 0x%08x,"
1430 " cksum 0x%04x, lifetime %us",
1431 circuit
->area
->area_tag
,
1433 rawlspid_print (entry
->lsp_id
),
1434 ntohl (entry
->seq_num
),
1435 ntohs (entry
->checksum
), ntohs (entry
->rem_lifetime
));
1440 /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */
1441 if (tlvs
.lsp_entries
)
1443 LIST_LOOP (tlvs
.lsp_entries
, entry
, node
)
1445 lsp
= lsp_search (entry
->lsp_id
, circuit
->area
->lspdb
[level
- 1]);
1446 own_lsp
= !memcmp (entry
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1449 /* 7.3.15.2 b) 1) is this LSP newer */
1450 cmp
= lsp_compare (circuit
->area
->area_tag
, lsp
, entry
->seq_num
,
1451 entry
->checksum
, entry
->rem_lifetime
);
1452 /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */
1453 if (cmp
== LSP_EQUAL
)
1455 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1456 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1457 /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
1459 else if (cmp
== LSP_OLDER
)
1461 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1462 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1466 /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM
1470 lsp_inc_seqnum (lsp
, ntohl (entry
->seq_num
));
1471 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1475 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1476 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1477 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1483 /* 7.3.15.2 b) 5) if it was not found, and all of those are not 0,
1484 * insert it and set SSN on it */
1485 if (entry
->rem_lifetime
&& entry
->checksum
&& entry
->seq_num
&&
1486 memcmp (entry
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
1488 lsp
= lsp_new (entry
->lsp_id
, ntohs (entry
->rem_lifetime
),
1489 0, 0, entry
->checksum
, level
);
1490 lsp_insert (lsp
, circuit
->area
->lspdb
[level
- 1]);
1491 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1497 /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported */
1498 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1501 * Build a list from our own LSP db bounded with start_ and stop_lsp_id
1503 lsp_list
= list_new ();
1504 lsp_build_list_nonzero_ht (chdr
->start_lsp_id
, chdr
->stop_lsp_id
,
1505 lsp_list
, circuit
->area
->lspdb
[level
- 1]);
1507 /* Fixme: Find a better solution */
1508 if (tlvs
.lsp_entries
)
1510 LIST_LOOP (tlvs
.lsp_entries
, entry
, node
)
1512 LIST_LOOP (lsp_list
, lsp
, node2
)
1514 if (lsp_id_cmp (lsp
->lsp_header
->lsp_id
, entry
->lsp_id
) == 0)
1516 list_delete_node (lsp_list
, node2
);
1522 /* on remaining LSPs we set SRM (neighbor knew not of) */
1523 LIST_LOOP (lsp_list
, lsp
, node2
)
1525 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1528 list_free (lsp_list
);
1536 process_csnp (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
1538 /* Sanity check - FIXME: move to correct place */
1539 if ((stream_get_endp (circuit
->rcv_stream
) -
1540 stream_get_getp (circuit
->rcv_stream
)) < ISIS_CSNP_HDRLEN
)
1542 zlog_warn ("Packet too short ( < %d)", ISIS_CSNP_HDRLEN
);
1543 return ISIS_WARNING
;
1546 return process_snp (ISIS_SNP_CSNP_FLAG
, level
, circuit
, ssnpa
);
1550 process_psnp (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
1552 if ((stream_get_endp (circuit
->rcv_stream
) -
1553 stream_get_getp (circuit
->rcv_stream
)) < ISIS_PSNP_HDRLEN
)
1555 zlog_warn ("Packet too short");
1556 return ISIS_WARNING
;
1559 return process_snp (ISIS_SNP_PSNP_FLAG
, level
, circuit
, ssnpa
);
1565 * Section 8.2.2 - Receiving ISH PDUs by an intermediate system
1566 * FIXME: sample packet dump, need to figure 0x81 - looks like NLPid
1567 * 0x82 0x15 0x01 0x00 0x04 0x01 0x2c 0x59
1568 * 0x38 0x08 0x47 0x00 0x01 0x00 0x02 0x00
1569 * 0x03 0x00 0x81 0x01 0xcc
1572 process_is_hello (struct isis_circuit
*circuit
)
1574 struct isis_adjacency
*adj
;
1575 int retval
= ISIS_OK
;
1579 /* In this point in time we are not yet able to handle is_hellos
1580 * on lan - Sorry juniper...
1582 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1585 neigh_len
= stream_getc (circuit
->rcv_stream
);
1586 sysid
= STREAM_PNT (circuit
->rcv_stream
) + neigh_len
- 1 - ISIS_SYS_ID_LEN
;
1587 adj
= circuit
->u
.p2p
.neighbor
;
1591 adj
= isis_new_adj (sysid
, (u_char
*) " ", 0, circuit
);
1595 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
1596 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
1597 circuit
->u
.p2p
.neighbor
= adj
;
1600 if ((adj
->adj_state
== ISIS_ADJ_UP
) && memcmp (adj
->sysid
, sysid
,
1603 /* 8.2.2 a) 1) FIXME: adjStateChange(down) event */
1604 /* 8.2.2 a) 2) delete the adj */
1605 XFREE (MTYPE_ISIS_ADJACENCY
, adj
);
1606 /* 8.2.2 a) 3) create a new adj */
1607 adj
= isis_new_adj (sysid
, (u_char
*) " ", 0, circuit
);
1612 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
1613 /* 8.2.2 a) 3) ii */
1614 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
1615 /* 8.2.2 a) 4) quite meaningless */
1617 /* 8.2.2 b) ignore on condition */
1618 if ((adj
->adj_state
== ISIS_ADJ_INITIALIZING
) &&
1619 (adj
->sys_type
== ISIS_SYSTYPE_IS
))
1625 /* 8.2.2 c) respond with a p2p IIH */
1626 send_hello (circuit
, 1);
1628 /* 8.2.2 d) type is IS */
1629 adj
->sys_type
= ISIS_SYSTYPE_IS
;
1630 /* 8.2.2 e) FIXME: Circuit type of? */
1640 isis_handle_pdu (struct isis_circuit
*circuit
, u_char
* ssnpa
)
1642 struct isis_fixed_hdr
*hdr
;
1643 struct esis_fixed_hdr
*esis_hdr
;
1645 int retval
= ISIS_OK
;
1648 * Let's first read data from stream to the header
1650 hdr
= (struct isis_fixed_hdr
*) STREAM_DATA (circuit
->rcv_stream
);
1652 if ((hdr
->idrp
!= ISO10589_ISIS
) && (hdr
->idrp
!= ISO9542_ESIS
))
1654 zlog_warn ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr
->idrp
);
1658 /* now we need to know if this is an ISO 9542 packet and
1659 * take real good care of it, waaa!
1661 if (hdr
->idrp
== ISO9542_ESIS
)
1663 esis_hdr
= (struct esis_fixed_hdr
*) STREAM_DATA (circuit
->rcv_stream
);
1664 stream_set_getp (circuit
->rcv_stream
, ESIS_FIXED_HDR_LEN
);
1665 /* FIXME: Need to do some acceptence tests */
1666 /* example length... */
1667 switch (esis_hdr
->pdu_type
)
1673 zlog_debug ("AN ISH PDU!!");
1674 retval
= process_is_hello (circuit
);
1683 stream_set_getp (circuit
->rcv_stream
, ISIS_FIXED_HDR_LEN
);
1686 * and then process it
1689 if (hdr
->length
< ISIS_MINIMUM_FIXED_HDR_LEN
)
1691 zlog_err ("Fixed header length = %d", hdr
->length
);
1695 if (hdr
->version1
!= 1)
1697 zlog_warn ("Unsupported ISIS version %u", hdr
->version1
);
1698 return ISIS_WARNING
;
1701 if ((hdr
->id_len
!= 0) && (hdr
->id_len
!= ISIS_SYS_ID_LEN
))
1704 ("IDFieldLengthMismatch: ID Length field in a received PDU %u, "
1705 "while the parameter for this IS is %u", hdr
->id_len
,
1710 if (hdr
->version2
!= 1)
1712 zlog_warn ("Unsupported ISIS version %u", hdr
->version2
);
1713 return ISIS_WARNING
;
1716 if ((hdr
->max_area_addrs
!= 0)
1717 && (hdr
->max_area_addrs
!= isis
->max_area_addrs
))
1719 zlog_err ("maximumAreaAddressesMismatch: maximumAreaAdresses in a "
1720 "received PDU %u while the parameter for this IS is %u",
1721 hdr
->max_area_addrs
, isis
->max_area_addrs
);
1725 switch (hdr
->pdu_type
)
1728 retval
= process_lan_hello (ISIS_LEVEL1
, circuit
, ssnpa
);
1731 retval
= process_lan_hello (ISIS_LEVEL2
, circuit
, ssnpa
);
1734 retval
= process_p2p_hello (circuit
);
1737 retval
= process_lsp (ISIS_LEVEL1
, circuit
, ssnpa
);
1740 retval
= process_lsp (ISIS_LEVEL2
, circuit
, ssnpa
);
1742 case L1_COMPLETE_SEQ_NUM
:
1743 retval
= process_csnp (ISIS_LEVEL1
, circuit
, ssnpa
);
1745 case L2_COMPLETE_SEQ_NUM
:
1746 retval
= process_csnp (ISIS_LEVEL2
, circuit
, ssnpa
);
1748 case L1_PARTIAL_SEQ_NUM
:
1749 retval
= process_psnp (ISIS_LEVEL1
, circuit
, ssnpa
);
1751 case L2_PARTIAL_SEQ_NUM
:
1752 retval
= process_psnp (ISIS_LEVEL2
, circuit
, ssnpa
);
1763 isis_receive (struct thread
*thread
)
1765 struct isis_circuit
*circuit
;
1766 u_char ssnpa
[ETH_ALEN
];
1772 circuit
= THREAD_ARG (thread
);
1775 if (circuit
->rcv_stream
== NULL
)
1776 circuit
->rcv_stream
= stream_new (ISO_MTU (circuit
));
1778 stream_reset (circuit
->rcv_stream
);
1780 retval
= circuit
->rx (circuit
, ssnpa
);
1781 circuit
->t_read
= NULL
;
1783 if (retval
== ISIS_OK
)
1784 retval
= isis_handle_pdu (circuit
, ssnpa
);
1787 * prepare for next packet.
1789 THREAD_READ_ON (master
, circuit
->t_read
, isis_receive
, circuit
,
1797 isis_receive (struct thread
*thread
)
1799 struct isis_circuit
*circuit
;
1800 u_char ssnpa
[ETH_ALEN
];
1806 circuit
= THREAD_ARG (thread
);
1809 circuit
->t_read
= NULL
;
1811 if (circuit
->rcv_stream
== NULL
)
1812 circuit
->rcv_stream
= stream_new (ISO_MTU (circuit
));
1814 stream_reset (circuit
->rcv_stream
);
1816 retval
= circuit
->rx (circuit
, ssnpa
);
1818 if (retval
== ISIS_OK
)
1819 retval
= isis_handle_pdu (circuit
, ssnpa
);
1822 * prepare for next packet.
1824 circuit
->t_read
= thread_add_timer_msec (master
, isis_receive
, circuit
,
1826 (circuit
->area
->circuit_list
) *
1834 /* filling of the fixed isis header */
1836 fill_fixed_hdr (struct isis_fixed_hdr
*hdr
, u_char pdu_type
)
1838 memset (hdr
, 0, sizeof (struct isis_fixed_hdr
));
1840 hdr
->idrp
= ISO10589_ISIS
;
1846 hdr
->length
= ISIS_LANHELLO_HDRLEN
;
1849 hdr
->length
= ISIS_P2PHELLO_HDRLEN
;
1853 hdr
->length
= ISIS_LSP_HDR_LEN
;
1855 case L1_COMPLETE_SEQ_NUM
:
1856 case L2_COMPLETE_SEQ_NUM
:
1857 hdr
->length
= ISIS_CSNP_HDRLEN
;
1859 case L1_PARTIAL_SEQ_NUM
:
1860 case L2_PARTIAL_SEQ_NUM
:
1861 hdr
->length
= ISIS_PSNP_HDRLEN
;
1864 zlog_warn ("fill_fixed_hdr(): unknown pdu type %d", pdu_type
);
1867 hdr
->length
+= ISIS_FIXED_HDR_LEN
;
1868 hdr
->pdu_type
= pdu_type
;
1870 hdr
->id_len
= 0; /* ISIS_SYS_ID_LEN - 0==6 */
1872 hdr
->max_area_addrs
= 0; /* isis->max_area_addrs - 0==3 */
1879 fill_fixed_hdr_andstream (struct isis_fixed_hdr
*hdr
, u_char pdu_type
,
1880 struct stream
*stream
)
1882 fill_fixed_hdr (hdr
, pdu_type
);
1884 stream_putc (stream
, hdr
->idrp
);
1885 stream_putc (stream
, hdr
->length
);
1886 stream_putc (stream
, hdr
->version1
);
1887 stream_putc (stream
, hdr
->id_len
);
1888 stream_putc (stream
, hdr
->pdu_type
);
1889 stream_putc (stream
, hdr
->version2
);
1890 stream_putc (stream
, hdr
->reserved
);
1891 stream_putc (stream
, hdr
->max_area_addrs
);
1897 send_hello (struct isis_circuit
*circuit
, int level
)
1899 struct isis_fixed_hdr fixed_hdr
;
1900 struct isis_lan_hello_hdr hello_hdr
;
1901 struct isis_p2p_hello_hdr p2p_hello_hdr
;
1904 unsigned long len_pointer
, length
;
1907 if (circuit
->interface
->mtu
== 0)
1909 zlog_warn ("circuit has zero MTU");
1910 return ISIS_WARNING
;
1913 if (!circuit
->snd_stream
)
1914 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
1916 stream_reset (circuit
->snd_stream
);
1918 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1920 fill_fixed_hdr_andstream (&fixed_hdr
, L1_LAN_HELLO
,
1921 circuit
->snd_stream
);
1923 fill_fixed_hdr_andstream (&fixed_hdr
, L2_LAN_HELLO
,
1924 circuit
->snd_stream
);
1926 fill_fixed_hdr_andstream (&fixed_hdr
, P2P_HELLO
, circuit
->snd_stream
);
1929 * Fill LAN Level 1 or 2 Hello PDU header
1931 memset (&hello_hdr
, 0, sizeof (struct isis_lan_hello_hdr
));
1932 interval
= circuit
->hello_multiplier
[level
- 1] *
1933 circuit
->hello_interval
[level
- 1];
1934 if (interval
> USHRT_MAX
)
1935 interval
= USHRT_MAX
;
1936 hello_hdr
.circuit_t
= circuit
->circuit_is_type
;
1937 memcpy (hello_hdr
.source_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1938 hello_hdr
.hold_time
= htons ((u_int16_t
) interval
);
1940 hello_hdr
.pdu_len
= 0; /* Update the PDU Length later */
1941 len_pointer
= stream_get_putp (circuit
->snd_stream
) + 3 + ISIS_SYS_ID_LEN
;
1943 /* copy the shared part of the hello to the p2p hello if needed */
1944 if (circuit
->circ_type
== CIRCUIT_T_P2P
)
1946 memcpy (&p2p_hello_hdr
, &hello_hdr
, 5 + ISIS_SYS_ID_LEN
);
1947 p2p_hello_hdr
.local_id
= circuit
->circuit_id
;
1948 /* FIXME: need better understanding */
1949 stream_put (circuit
->snd_stream
, &p2p_hello_hdr
, ISIS_P2PHELLO_HDRLEN
);
1953 hello_hdr
.prio
= circuit
->u
.bc
.priority
[level
- 1];
1954 if (level
== 1 && circuit
->u
.bc
.l1_desig_is
)
1956 memcpy (hello_hdr
.lan_id
, circuit
->u
.bc
.l1_desig_is
,
1957 ISIS_SYS_ID_LEN
+ 1);
1959 else if (level
== 2 && circuit
->u
.bc
.l2_desig_is
)
1961 memcpy (hello_hdr
.lan_id
, circuit
->u
.bc
.l2_desig_is
,
1962 ISIS_SYS_ID_LEN
+ 1);
1964 stream_put (circuit
->snd_stream
, &hello_hdr
, ISIS_LANHELLO_HDRLEN
);
1968 * Then the variable length part
1970 /* add circuit password */
1971 if (circuit
->passwd
.type
)
1972 if (tlv_add_authinfo (circuit
->passwd
.type
, circuit
->passwd
.len
,
1973 circuit
->passwd
.passwd
, circuit
->snd_stream
))
1974 return ISIS_WARNING
;
1975 /* Area Addresses TLV */
1976 assert (circuit
->area
);
1977 if (circuit
->area
->area_addrs
&& circuit
->area
->area_addrs
->count
> 0)
1978 if (tlv_add_area_addrs (circuit
->area
->area_addrs
, circuit
->snd_stream
))
1979 return ISIS_WARNING
;
1981 /* LAN Neighbors TLV */
1982 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1984 if (level
== 1 && circuit
->u
.bc
.lan_neighs
[0]->count
> 0)
1985 if (tlv_add_lan_neighs (circuit
->u
.bc
.lan_neighs
[0],
1986 circuit
->snd_stream
))
1987 return ISIS_WARNING
;
1988 if (level
== 2 && circuit
->u
.bc
.lan_neighs
[1]->count
> 0)
1989 if (tlv_add_lan_neighs (circuit
->u
.bc
.lan_neighs
[1],
1990 circuit
->snd_stream
))
1991 return ISIS_WARNING
;
1994 /* Protocols Supported TLV */
1995 if (circuit
->nlpids
.count
> 0)
1996 if (tlv_add_nlpid (&circuit
->nlpids
, circuit
->snd_stream
))
1997 return ISIS_WARNING
;
1998 /* IP interface Address TLV */
1999 if (circuit
->ip_router
&& circuit
->ip_addrs
&& circuit
->ip_addrs
->count
> 0)
2000 if (tlv_add_ip_addrs (circuit
->ip_addrs
, circuit
->snd_stream
))
2001 return ISIS_WARNING
;
2004 /* IPv6 Interface Address TLV */
2005 if (circuit
->ipv6_router
&& circuit
->ipv6_link
&&
2006 circuit
->ipv6_link
->count
> 0)
2007 if (tlv_add_ipv6_addrs (circuit
->ipv6_link
, circuit
->snd_stream
))
2008 return ISIS_WARNING
;
2009 #endif /* HAVE_IPV6 */
2011 if (circuit
->u
.bc
.pad_hellos
)
2012 if (tlv_add_padding (circuit
->snd_stream
))
2013 return ISIS_WARNING
;
2015 length
= stream_get_putp (circuit
->snd_stream
);
2016 /* Update PDU length */
2017 stream_putw_at (circuit
->snd_stream
, len_pointer
, (u_int16_t
) length
);
2019 retval
= circuit
->tx (circuit
, level
);
2021 zlog_warn ("sending of LAN Level %d Hello failed", level
);
2023 /* DEBUG_ADJ_PACKETS */
2024 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
2026 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
2028 zlog_debug ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %ld",
2029 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
2030 STREAM_SIZE (circuit
->snd_stream
));
2034 zlog_debug ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld",
2035 circuit
->area
->area_tag
, circuit
->interface
->name
,
2036 STREAM_SIZE (circuit
->snd_stream
));
2044 send_lan_hello (struct isis_circuit
*circuit
, int level
)
2046 return send_hello (circuit
, level
);
2050 send_lan_l1_hello (struct thread
*thread
)
2052 struct isis_circuit
*circuit
;
2055 circuit
= THREAD_ARG (thread
);
2057 circuit
->u
.bc
.t_send_lan_hello
[0] = NULL
;
2059 if (circuit
->u
.bc
.run_dr_elect
[0])
2060 retval
= isis_dr_elect (circuit
, 1);
2062 retval
= send_lan_hello (circuit
, 1);
2064 /* set next timer thread */
2065 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_send_lan_hello
[0],
2066 send_lan_l1_hello
, circuit
,
2067 isis_jitter (circuit
->hello_interval
[0], IIH_JITTER
));
2073 send_lan_l2_hello (struct thread
*thread
)
2075 struct isis_circuit
*circuit
;
2078 circuit
= THREAD_ARG (thread
);
2080 circuit
->u
.bc
.t_send_lan_hello
[1] = NULL
;
2082 if (circuit
->u
.bc
.run_dr_elect
[1])
2083 retval
= isis_dr_elect (circuit
, 2);
2085 retval
= send_lan_hello (circuit
, 2);
2087 /* set next timer thread */
2088 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_send_lan_hello
[1],
2089 send_lan_l2_hello
, circuit
,
2090 isis_jitter (circuit
->hello_interval
[1], IIH_JITTER
));
2096 send_p2p_hello (struct thread
*thread
)
2098 struct isis_circuit
*circuit
;
2100 circuit
= THREAD_ARG (thread
);
2102 circuit
->u
.p2p
.t_send_p2p_hello
= NULL
;
2104 send_hello (circuit
, 1);
2106 /* set next timer thread */
2107 THREAD_TIMER_ON (master
, circuit
->u
.p2p
.t_send_p2p_hello
, send_p2p_hello
,
2108 circuit
, isis_jitter (circuit
->hello_interval
[1],
2115 build_csnp (int level
, u_char
* start
, u_char
* stop
, struct list
*lsps
,
2116 struct isis_circuit
*circuit
)
2118 struct isis_fixed_hdr fixed_hdr
;
2119 struct isis_passwd
*passwd
;
2120 int retval
= ISIS_OK
;
2125 fill_fixed_hdr_andstream (&fixed_hdr
, L1_COMPLETE_SEQ_NUM
,
2126 circuit
->snd_stream
);
2128 fill_fixed_hdr_andstream (&fixed_hdr
, L2_COMPLETE_SEQ_NUM
,
2129 circuit
->snd_stream
);
2132 * Fill Level 1 or 2 Complete Sequence Numbers header
2135 lenp
= stream_get_putp (circuit
->snd_stream
);
2136 stream_putw (circuit
->snd_stream
, 0); /* PDU length - when we know it */
2137 /* no need to send the source here, it is always us if we csnp */
2138 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2139 /* with zero circuit id - ref 9.10, 9.11 */
2140 stream_putc (circuit
->snd_stream
, 0x00);
2142 stream_put (circuit
->snd_stream
, start
, ISIS_SYS_ID_LEN
+ 2);
2143 stream_put (circuit
->snd_stream
, stop
, ISIS_SYS_ID_LEN
+ 2);
2149 passwd
= &circuit
->area
->area_passwd
;
2151 passwd
= &circuit
->area
->domain_passwd
;
2153 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
))
2155 retval
= tlv_add_authinfo (passwd
->type
, passwd
->len
,
2156 passwd
->passwd
, circuit
->snd_stream
);
2158 if (!retval
&& lsps
)
2160 retval
= tlv_add_lsp_entries (lsps
, circuit
->snd_stream
);
2162 length
= (u_int16_t
) stream_get_putp (circuit
->snd_stream
);
2163 assert (length
>= ISIS_CSNP_HDRLEN
);
2164 /* Update PU length */
2165 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2171 * FIXME: support multiple CSNPs
2175 send_csnp (struct isis_circuit
*circuit
, int level
)
2177 int retval
= ISIS_OK
;
2178 u_char start
[ISIS_SYS_ID_LEN
+ 2];
2179 u_char stop
[ISIS_SYS_ID_LEN
+ 2];
2180 struct list
*list
= NULL
;
2181 struct listnode
*node
;
2182 struct isis_lsp
*lsp
;
2184 memset (start
, 0x00, ISIS_SYS_ID_LEN
+ 2);
2185 memset (stop
, 0xff, ISIS_SYS_ID_LEN
+ 2);
2187 if (circuit
->area
->lspdb
[level
- 1] &&
2188 dict_count (circuit
->area
->lspdb
[level
- 1]) > 0)
2191 lsp_build_list (start
, stop
, list
, circuit
->area
->lspdb
[level
- 1]);
2193 if (circuit
->snd_stream
== NULL
)
2194 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
2196 stream_reset (circuit
->snd_stream
);
2198 retval
= build_csnp (level
, start
, stop
, list
, circuit
);
2200 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2202 zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld",
2203 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
2204 STREAM_SIZE (circuit
->snd_stream
));
2205 LIST_LOOP (list
, lsp
, node
)
2207 zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x,"
2208 " cksum 0x%04x, lifetime %us",
2209 circuit
->area
->area_tag
,
2210 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2211 ntohl (lsp
->lsp_header
->seq_num
),
2212 ntohs (lsp
->lsp_header
->checksum
),
2213 ntohs (lsp
->lsp_header
->rem_lifetime
));
2219 if (retval
== ISIS_OK
)
2220 retval
= circuit
->tx (circuit
, level
);
2226 send_l1_csnp (struct thread
*thread
)
2228 struct isis_circuit
*circuit
;
2229 int retval
= ISIS_OK
;
2231 circuit
= THREAD_ARG (thread
);
2234 circuit
->t_send_csnp
[0] = NULL
;
2236 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
&& circuit
->u
.bc
.is_dr
[0])
2238 send_csnp (circuit
, 1);
2240 /* set next timer thread */
2241 THREAD_TIMER_ON (master
, circuit
->t_send_csnp
[0], send_l1_csnp
, circuit
,
2242 isis_jitter (circuit
->csnp_interval
[0], CSNP_JITTER
));
2248 send_l2_csnp (struct thread
*thread
)
2250 struct isis_circuit
*circuit
;
2251 int retval
= ISIS_OK
;
2253 circuit
= THREAD_ARG (thread
);
2256 circuit
->t_send_csnp
[1] = NULL
;
2258 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
&& circuit
->u
.bc
.is_dr
[1])
2260 send_csnp (circuit
, 2);
2262 /* set next timer thread */
2263 THREAD_TIMER_ON (master
, circuit
->t_send_csnp
[1], send_l2_csnp
, circuit
,
2264 isis_jitter (circuit
->csnp_interval
[1], CSNP_JITTER
));
2270 build_psnp (int level
, struct isis_circuit
*circuit
, struct list
*lsps
)
2272 struct isis_fixed_hdr fixed_hdr
;
2276 struct isis_lsp
*lsp
;
2277 struct isis_passwd
*passwd
;
2278 struct listnode
*node
;
2281 fill_fixed_hdr_andstream (&fixed_hdr
, L1_PARTIAL_SEQ_NUM
,
2282 circuit
->snd_stream
);
2284 fill_fixed_hdr_andstream (&fixed_hdr
, L2_PARTIAL_SEQ_NUM
,
2285 circuit
->snd_stream
);
2288 * Fill Level 1 or 2 Partial Sequence Numbers header
2290 lenp
= stream_get_putp (circuit
->snd_stream
);
2291 stream_putw (circuit
->snd_stream
, 0); /* PDU length - when we know it */
2292 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2293 stream_putc (circuit
->snd_stream
, circuit
->idx
);
2300 passwd
= &circuit
->area
->area_passwd
;
2302 passwd
= &circuit
->area
->domain_passwd
;
2304 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
))
2306 retval
= tlv_add_authinfo (passwd
->type
, passwd
->len
,
2307 passwd
->passwd
, circuit
->snd_stream
);
2309 if (!retval
&& lsps
)
2311 retval
= tlv_add_lsp_entries (lsps
, circuit
->snd_stream
);
2314 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2316 LIST_LOOP (lsps
, lsp
, node
)
2318 zlog_debug ("ISIS-Snp (%s): PSNP entry %s, seq 0x%08x,"
2319 " cksum 0x%04x, lifetime %us",
2320 circuit
->area
->area_tag
,
2321 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2322 ntohl (lsp
->lsp_header
->seq_num
),
2323 ntohs (lsp
->lsp_header
->checksum
),
2324 ntohs (lsp
->lsp_header
->rem_lifetime
));
2328 length
= (u_int16_t
) stream_get_putp (circuit
->snd_stream
);
2329 assert (length
>= ISIS_PSNP_HDRLEN
);
2330 /* Update PDU length */
2331 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2337 * 7.3.15.4 action on expiration of partial SNP interval
2341 send_psnp (int level
, struct isis_circuit
*circuit
)
2343 int retval
= ISIS_OK
;
2344 struct isis_lsp
*lsp
;
2345 struct list
*list
= NULL
;
2346 struct listnode
*node
;
2348 if ((circuit
->circ_type
== CIRCUIT_T_BROADCAST
&&
2349 !circuit
->u
.bc
.is_dr
[level
- 1]) ||
2350 circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
2353 if (circuit
->area
->lspdb
[level
- 1] &&
2354 dict_count (circuit
->area
->lspdb
[level
- 1]) > 0)
2357 lsp_build_list_ssn (circuit
, list
, circuit
->area
->lspdb
[level
- 1]);
2359 if (listcount (list
) > 0)
2361 if (circuit
->snd_stream
== NULL
)
2362 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
2364 stream_reset (circuit
->snd_stream
);
2367 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2368 zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld",
2369 circuit
->area
->area_tag
, level
,
2370 circuit
->interface
->name
,
2371 STREAM_SIZE (circuit
->snd_stream
));
2373 retval
= build_psnp (level
, circuit
, list
);
2374 if (retval
== ISIS_OK
)
2375 retval
= circuit
->tx (circuit
, level
);
2377 if (retval
== ISIS_OK
)
2380 * sending succeeded, we can clear SSN flags of this circuit
2381 * for the LSPs in list
2383 for (node
= listhead (list
); node
; nextnode (node
))
2385 lsp
= getdata (node
);
2386 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
));
2442 build_link_state (struct isis_lsp
*lsp
, struct isis_circuit
*circuit
,
2443 struct stream
*stream
)
2445 unsigned long length
;
2447 stream_put (stream
, lsp
->pdu
, ntohs (lsp
->lsp_header
->pdu_len
));
2448 length
= stream_get_putp (stream
);
2454 * ISO 10589 - 7.3.14.3
2457 send_lsp (struct thread
*thread
)
2459 struct isis_circuit
*circuit
;
2460 struct isis_lsp
*lsp
;
2461 struct listnode
*node
;
2464 circuit
= THREAD_ARG (thread
);
2467 if (circuit
->state
== C_STATE_UP
)
2469 node
= listhead (circuit
->lsp_queue
);
2472 lsp
= getdata (node
);
2475 * Do not send if levels do not match
2477 if (!(lsp
->level
& circuit
->circuit_is_type
))
2481 * Do not send if we do not have adjacencies in state up on the circuit
2483 if (circuit
->upadjcount
[lsp
->level
- 1] == 0)
2485 /* only send if it needs sending */
2486 if ((time (NULL
) - lsp
->last_sent
) >=
2487 circuit
->area
->lsp_gen_interval
[lsp
->level
- 1])
2490 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
2493 ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
2494 " lifetime %us on %s", circuit
->area
->area_tag
, lsp
->level
,
2495 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2496 ntohl (lsp
->lsp_header
->seq_num
),
2497 ntohs (lsp
->lsp_header
->checksum
),
2498 ntohs (lsp
->lsp_header
->rem_lifetime
),
2499 circuit
->interface
->name
);
2501 /* copy our lsp to the send buffer */
2502 circuit
->snd_stream
->getp
= lsp
->pdu
->getp
;
2503 circuit
->snd_stream
->putp
= lsp
->pdu
->putp
;
2504 circuit
->snd_stream
->endp
= lsp
->pdu
->endp
;
2505 memcpy (circuit
->snd_stream
->data
, lsp
->pdu
->data
, lsp
->pdu
->endp
);
2507 retval
= circuit
->tx (circuit
, lsp
->level
);
2510 * If the sending succeeded, we can del the lsp from circuits
2513 if (retval
== ISIS_OK
)
2515 list_delete_node (circuit
->lsp_queue
, node
);
2518 * On broadcast circuits also the SRMflag can be cleared
2520 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
2521 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
2523 if (flags_any_set (lsp
->SRMflags
) == 0)
2526 * need to remember when we were last sent
2528 lsp
->last_sent
= time (NULL
);
2533 zlog_debug ("sending of level %d link state failed", lsp
->level
);
2538 /* my belief is that if it wasn't his time, the lsp can be removed
2542 list_delete_node (circuit
->lsp_queue
, node
);
2546 * If there are still LSPs send next one after lsp-interval (33 msecs)
2548 if (listcount (circuit
->lsp_queue
) > 0)
2549 thread_add_timer (master
, send_lsp
, circuit
, 1);
2557 ack_lsp (struct isis_link_state_hdr
*hdr
, struct isis_circuit
*circuit
,
2563 struct isis_fixed_hdr fixed_hdr
;
2565 if (!circuit
->snd_stream
)
2566 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
2568 stream_reset (circuit
->snd_stream
);
2570 // fill_llc_hdr (stream);
2572 fill_fixed_hdr_andstream (&fixed_hdr
, L1_PARTIAL_SEQ_NUM
,
2573 circuit
->snd_stream
);
2575 fill_fixed_hdr_andstream (&fixed_hdr
, L2_PARTIAL_SEQ_NUM
,
2576 circuit
->snd_stream
);
2579 lenp
= stream_get_putp (circuit
->snd_stream
);
2580 stream_putw (circuit
->snd_stream
, 0); /* PDU length */
2581 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2582 stream_putc (circuit
->snd_stream
, circuit
->idx
);
2583 stream_putc (circuit
->snd_stream
, 9); /* code */
2584 stream_putc (circuit
->snd_stream
, 16); /* len */
2586 stream_putw (circuit
->snd_stream
, ntohs (hdr
->rem_lifetime
));
2587 stream_put (circuit
->snd_stream
, hdr
->lsp_id
, ISIS_SYS_ID_LEN
+ 2);
2588 stream_putl (circuit
->snd_stream
, ntohl (hdr
->seq_num
));
2589 stream_putw (circuit
->snd_stream
, ntohs (hdr
->checksum
));
2591 length
= (u_int16_t
) stream_get_putp (circuit
->snd_stream
);
2592 /* Update PDU length */
2593 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2595 retval
= circuit
->tx (circuit
, level
);
2602 * ISH PDU Processing
2606 * Let's first check if the local and remote system have any common area
2609 if (area_match (tlvs
.area_addrs
, isis
->man_area_addrs
) == 0)
2611 if (circuit
->circuit_t
== IS_LEVEL_2
)
2613 /* do as in table 8 (p. 40) */
2614 switch (circuit_type
)
2617 if (adj
->adj_state
!= ISIS_ADJ_UP
)
2620 zlog_warn ("areaMismatch");
2621 retval
= ISIS_WARNING
;
2623 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
2625 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch",
2628 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
||
2629 adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
2631 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System",
2636 if (adj
->adj_state
!= ISIS_ADJ_UP
)
2638 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
,
2640 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
2642 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
||
2643 adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
2645 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System",
2648 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
2653 case IS_LEVEL_1_AND_2
:
2654 if (adj
->adj_state
!= ISIS_ADJ_UP
)
2656 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
,
2658 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
2660 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
2662 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System",
2665 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
2667 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch",
2670 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
2680 isis_delete_adj (adj
, circuit
->adjdb
);
2681 zlog_warn ("areaMismatch");
2682 return ISIS_WARNING
;