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.
37 #include "isisd/dict.h"
38 #include "isisd/include-netbsd/iso.h"
39 #include "isisd/isis_constants.h"
40 #include "isisd/isis_common.h"
41 #include "isisd/isis_adjacency.h"
42 #include "isisd/isis_circuit.h"
43 #include "isisd/isis_network.h"
44 #include "isisd/isis_misc.h"
45 #include "isisd/isis_dr.h"
46 #include "isisd/isis_flags.h"
47 #include "isisd/isis_tlv.h"
48 #include "isisd/isisd.h"
49 #include "isisd/isis_dynhn.h"
50 #include "isisd/isis_lsp.h"
51 #include "isisd/isis_pdu.h"
52 #include "isisd/iso_checksum.h"
53 #include "isisd/isis_csm.h"
54 #include "isisd/isis_events.h"
56 extern struct thread_master
*master
;
57 extern struct isis
*isis
;
59 #define ISIS_MINIMUM_FIXED_HDR_LEN 15
60 #define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */
66 /* Utility mask array. */
67 static u_char maskbit
[] = {
68 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
76 * Compares two sets of area addresses
79 area_match (struct list
*left
, struct list
*right
)
81 struct area_addr
*addr1
, *addr2
;
82 struct listnode
*node1
, *node2
;
84 for (ALL_LIST_ELEMENTS_RO (left
, node1
, addr1
))
86 for (ALL_LIST_ELEMENTS_RO (right
, node2
, addr2
))
88 if (addr1
->addr_len
== addr2
->addr_len
&&
89 !memcmp (addr1
->area_addr
, addr2
->area_addr
, (int) addr1
->addr_len
))
94 return 0; /* mismatch */
98 * Check if ip2 is in the ip1's network (function like Prefix.h:prefix_match() )
99 * param ip1 the IS interface ip address structure
100 * param ip2 the IIH's ip address
101 * return 0 the IIH's IP is not in the IS's subnetwork
102 * 1 the IIH's IP is in the IS's subnetwork
105 ip_same_subnet (struct prefix_ipv4
*ip1
, struct in_addr
*ip2
)
107 u_char
*addr1
, *addr2
;
108 int shift
, offset
, offsetloop
;
111 addr1
= (u_char
*) & ip1
->prefix
.s_addr
;
112 addr2
= (u_char
*) & ip2
->s_addr
;
113 len
= ip1
->prefixlen
;
116 offsetloop
= offset
= len
/ PNBBY
;
119 if (addr1
[offsetloop
] != addr2
[offsetloop
])
123 if (maskbit
[shift
] & (addr1
[offset
] ^ addr2
[offset
]))
126 return 1; /* match */
130 * Compares two set of ip addresses
131 * param left the local interface's ip addresses
132 * param right the iih interface's ip address
137 ip_match (struct list
*left
, struct list
*right
)
139 struct prefix_ipv4
*ip1
;
141 struct listnode
*node1
, *node2
;
143 if ((left
== NULL
) || (right
== NULL
))
146 for (ALL_LIST_ELEMENTS_RO (left
, node1
, ip1
))
148 for (ALL_LIST_ELEMENTS_RO (right
, node2
, ip2
))
150 if (ip_same_subnet (ip1
, ip2
))
152 return 1; /* match */
161 * Checks whether we should accept a PDU of given level
164 accept_level (int level
, int circuit_t
)
166 int retval
= ((circuit_t
& level
) == level
); /* simple approach */
172 authentication_check (struct isis_passwd
*one
, struct isis_passwd
*theother
)
174 if (one
->type
!= theother
->type
)
176 zlog_warn ("Unsupported authentication type %d", theother
->type
);
177 return 1; /* Auth fail (different authentication types) */
181 case ISIS_PASSWD_TYPE_CLEARTXT
:
182 if (one
->len
!= theother
->len
)
183 return 1; /* Auth fail () - passwd len mismatch */
184 return memcmp (one
->passwd
, theother
->passwd
, one
->len
);
187 zlog_warn ("Unsupported authentication type");
190 return 0; /* Auth pass */
194 * Processing helper functions
197 tlvs_to_adj_nlpids (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
200 struct nlpids
*tlv_nlpids
;
205 tlv_nlpids
= tlvs
->nlpids
;
207 adj
->nlpids
.count
= tlv_nlpids
->count
;
209 for (i
= 0; i
< tlv_nlpids
->count
; i
++)
211 adj
->nlpids
.nlpids
[i
] = tlv_nlpids
->nlpids
[i
];
217 del_ip_addr (void *val
)
219 XFREE (MTYPE_ISIS_TMP
, val
);
223 tlvs_to_adj_ipv4_addrs (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
225 struct listnode
*node
;
226 struct in_addr
*ipv4_addr
, *malloced
;
230 adj
->ipv4_addrs
->del
= del_ip_addr
;
231 list_delete (adj
->ipv4_addrs
);
233 adj
->ipv4_addrs
= list_new ();
234 if (tlvs
->ipv4_addrs
)
236 for (ALL_LIST_ELEMENTS_RO (tlvs
->ipv4_addrs
, node
, ipv4_addr
))
238 malloced
= XMALLOC (MTYPE_ISIS_TMP
, sizeof (struct in_addr
));
239 memcpy (malloced
, ipv4_addr
, sizeof (struct in_addr
));
240 listnode_add (adj
->ipv4_addrs
, malloced
);
247 tlvs_to_adj_ipv6_addrs (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
249 struct listnode
*node
;
250 struct in6_addr
*ipv6_addr
, *malloced
;
254 adj
->ipv6_addrs
->del
= del_ip_addr
;
255 list_delete (adj
->ipv6_addrs
);
257 adj
->ipv6_addrs
= list_new ();
258 if (tlvs
->ipv6_addrs
)
260 for (ALL_LIST_ELEMENTS_RO (tlvs
->ipv6_addrs
, node
, ipv6_addr
))
262 malloced
= XMALLOC (MTYPE_ISIS_TMP
, sizeof (struct in6_addr
));
263 memcpy (malloced
, ipv6_addr
, sizeof (struct in6_addr
));
264 listnode_add (adj
->ipv6_addrs
, malloced
);
269 #endif /* HAVE_IPV6 */
278 * Section 8.2.5 - Receiving point-to-point IIH PDUs
282 process_p2p_hello (struct isis_circuit
*circuit
)
284 int retval
= ISIS_OK
;
285 struct isis_p2p_hello_hdr
*hdr
;
286 struct isis_adjacency
*adj
;
287 u_int32_t expected
= 0, found
;
290 if ((stream_get_endp (circuit
->rcv_stream
) -
291 stream_get_getp (circuit
->rcv_stream
)) < ISIS_P2PHELLO_HDRLEN
)
293 zlog_warn ("Packet too short");
297 /* 8.2.5.1 PDU acceptance tests */
299 /* 8.2.5.1 a) external domain untrue */
300 /* FIXME: not useful at all? */
302 /* 8.2.5.1 b) ID Length mismatch */
303 /* checked at the handle_pdu */
305 /* 8.2.5.2 IIH PDU Processing */
307 /* 8.2.5.2 a) 1) Maximum Area Addresses */
308 /* Already checked, and can also be ommited */
313 hdr
= (struct isis_p2p_hello_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
314 circuit
->rcv_stream
->getp
+= ISIS_P2PHELLO_HDRLEN
;
316 /* hdr.circuit_t = stream_getc (stream);
317 stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN);
318 hdr.hold_time = stream_getw (stream);
319 hdr.pdu_len = stream_getw (stream);
320 hdr.local_id = stream_getc (stream); */
323 * My interpertation of the ISO, if no adj exists we will create one for
327 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
329 zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
330 " cir id %02d, length %d",
331 circuit
->area
->area_tag
, circuit
->interface
->name
,
332 circuit_t2string (circuit
->circuit_is_type
),
333 circuit
->circuit_id
, ntohs (hdr
->pdu_len
));
336 adj
= circuit
->u
.p2p
.neighbor
;
339 adj
= isis_new_adj (hdr
->source_id
, NULL
, 0, circuit
);
342 circuit
->u
.p2p
.neighbor
= adj
;
343 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
344 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
347 /* 8.2.6 Monitoring point-to-point adjacencies */
348 adj
->hold_time
= ntohs (hdr
->hold_time
);
349 adj
->last_upd
= time (NULL
);
352 * Lets get the TLVS now
354 expected
|= TLVFLAG_AREA_ADDRS
;
355 expected
|= TLVFLAG_AUTH_INFO
;
356 expected
|= TLVFLAG_NLPID
;
357 expected
|= TLVFLAG_IPV4_ADDR
;
358 expected
|= TLVFLAG_IPV6_ADDR
;
360 retval
= parse_tlvs (circuit
->area
->area_tag
,
361 STREAM_PNT (circuit
->rcv_stream
),
362 ntohs (hdr
->pdu_len
) - ISIS_P2PHELLO_HDRLEN
363 - ISIS_FIXED_HDR_LEN
, &expected
, &found
, &tlvs
);
365 if (retval
> ISIS_WARNING
)
371 /* 8.2.5.1 c) Authentication */
372 if (circuit
->passwd
.type
)
374 if (!(found
& TLVFLAG_AUTH_INFO
) ||
375 authentication_check (&circuit
->passwd
, &tlvs
.auth_info
))
377 isis_event_auth_failure (circuit
->area
->area_tag
,
378 "P2P hello authentication failure",
384 /* we do this now because the adj may not survive till the end... */
386 /* we need to copy addresses to the adj */
387 tlvs_to_adj_ipv4_addrs (&tlvs
, adj
);
390 tlvs_to_adj_ipv6_addrs (&tlvs
, adj
);
391 #endif /* HAVE_IPV6 */
393 /* lets take care of the expiry */
394 THREAD_TIMER_OFF (adj
->t_expire
);
395 THREAD_TIMER_ON (master
, adj
->t_expire
, isis_adj_expire
, adj
,
396 (long) adj
->hold_time
);
398 /* 8.2.5.2 a) a match was detected */
399 if (area_match (circuit
->area
->area_addrs
, tlvs
.area_addrs
))
401 /* 8.2.5.2 a) 2) If the system is L1 - table 5 */
402 if (circuit
->area
->is_type
== IS_LEVEL_1
)
404 switch (hdr
->circuit_t
)
407 case IS_LEVEL_1_AND_2
:
408 if (adj
->adj_state
!= ISIS_ADJ_UP
)
410 /* (4) adj state up */
411 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
412 /* (5) adj usage level 1 */
413 adj
->adj_usage
= ISIS_ADJ_LEVEL1
;
415 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
421 if (adj
->adj_state
!= ISIS_ADJ_UP
)
423 /* (7) reject - wrong system type event */
424 zlog_warn ("wrongSystemType");
425 return ISIS_WARNING
; /* Reject */
427 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
429 /* (6) down - wrong system */
430 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
436 /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */
437 if (circuit
->area
->is_type
== IS_LEVEL_1_AND_2
)
439 switch (hdr
->circuit_t
)
442 if (adj
->adj_state
!= ISIS_ADJ_UP
)
444 /* (6) adj state up */
445 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
446 /* (7) adj usage level 1 */
447 adj
->adj_usage
= ISIS_ADJ_LEVEL1
;
449 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
453 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
454 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
456 /* (8) down - wrong system */
457 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
461 if (adj
->adj_state
!= ISIS_ADJ_UP
)
463 /* (6) adj state up */
464 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
465 /* (9) adj usage level 2 */
466 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
468 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1
) ||
469 (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
))
471 /* (8) down - wrong system */
472 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
474 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
479 case IS_LEVEL_1_AND_2
:
480 if (adj
->adj_state
!= ISIS_ADJ_UP
)
482 /* (6) adj state up */
483 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
484 /* (10) adj usage level 1 */
485 adj
->adj_usage
= ISIS_ADJ_LEVEL1AND2
;
487 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1
) ||
488 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
490 /* (8) down - wrong system */
491 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
493 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
501 /* 8.2.5.2 a) 4) If the system is L2 - table 7 */
502 if (circuit
->area
->is_type
== IS_LEVEL_2
)
504 switch (hdr
->circuit_t
)
507 if (adj
->adj_state
!= ISIS_ADJ_UP
)
509 /* (5) reject - wrong system type event */
510 zlog_warn ("wrongSystemType");
511 return ISIS_WARNING
; /* Reject */
513 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
514 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
516 /* (6) down - wrong system */
517 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
520 case IS_LEVEL_1_AND_2
:
522 if (adj
->adj_state
!= ISIS_ADJ_UP
)
524 /* (7) adj state up */
525 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
526 /* (8) adj usage level 2 */
527 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
529 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
531 /* (6) down - wrong system */
532 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
534 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
542 /* 8.2.5.2 b) if no match was detected */
545 if (circuit
->area
->is_type
== IS_LEVEL_1
)
547 /* 8.2.5.2 b) 1) is_type L1 and adj is not up */
548 if (adj
->adj_state
!= ISIS_ADJ_UP
)
550 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch");
551 /* 8.2.5.2 b) 2)is_type L1 and adj is up */
555 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
556 "Down - Area Mismatch");
559 /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */
562 switch (hdr
->circuit_t
)
565 if (adj
->adj_state
!= ISIS_ADJ_UP
)
567 /* (6) reject - Area Mismatch event */
568 zlog_warn ("AreaMismatch");
569 return ISIS_WARNING
; /* Reject */
571 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
573 /* (7) down - area mismatch */
574 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch");
577 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
578 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
580 /* (7) down - wrong system */
581 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
584 case IS_LEVEL_1_AND_2
:
586 if (adj
->adj_state
!= ISIS_ADJ_UP
)
588 /* (8) adj state up */
589 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
590 /* (9) adj usage level 2 */
591 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
593 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
595 /* (7) down - wrong system */
596 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
598 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
600 if (hdr
->circuit_t
== IS_LEVEL_2
)
602 /* (7) down - wrong system */
603 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
608 /* (7) down - area mismatch */
609 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
613 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
621 /* 8.2.5.2 c) if the action was up - comparing circuit IDs */
622 /* FIXME - Missing parts */
624 /* some of my own understanding of the ISO, why the heck does
625 * it not say what should I change the system_type to...
627 switch (adj
->adj_usage
)
629 case ISIS_ADJ_LEVEL1
:
630 adj
->sys_type
= ISIS_SYSTYPE_L1_IS
;
632 case ISIS_ADJ_LEVEL2
:
633 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
635 case ISIS_ADJ_LEVEL1AND2
:
636 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
639 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
643 adj
->circuit_t
= hdr
->circuit_t
;
644 adj
->level
= hdr
->circuit_t
;
652 * Process IS-IS LAN Level 1/2 Hello PDU
655 process_lan_hello (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
657 int retval
= ISIS_OK
;
658 struct isis_lan_hello_hdr hdr
;
659 struct isis_adjacency
*adj
;
660 u_int32_t expected
= 0, found
;
663 struct listnode
*node
;
665 if ((stream_get_endp (circuit
->rcv_stream
) -
666 stream_get_getp (circuit
->rcv_stream
)) < ISIS_LANHELLO_HDRLEN
)
668 zlog_warn ("Packet too short");
672 if (circuit
->ext_domain
)
674 zlog_debug ("level %d LAN Hello received over circuit with "
675 "externalDomain = true", level
);
679 if (!accept_level (level
, circuit
->circuit_is_type
))
681 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
683 zlog_debug ("ISIS-Adj (%s): Interface level mismatch, %s",
684 circuit
->area
->area_tag
, circuit
->interface
->name
);
690 /* Cisco's debug message compatability */
691 if (!accept_level (level
, circuit
->area
->is_type
))
693 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
695 zlog_debug ("ISIS-Adj (%s): is type mismatch",
696 circuit
->area
->area_tag
);
704 hdr
.circuit_t
= stream_getc (circuit
->rcv_stream
);
705 stream_get (hdr
.source_id
, circuit
->rcv_stream
, ISIS_SYS_ID_LEN
);
706 hdr
.hold_time
= stream_getw (circuit
->rcv_stream
);
707 hdr
.pdu_len
= stream_getw (circuit
->rcv_stream
);
708 hdr
.prio
= stream_getc (circuit
->rcv_stream
);
709 stream_get (hdr
.lan_id
, circuit
->rcv_stream
, ISIS_SYS_ID_LEN
+ 1);
711 if (hdr
.circuit_t
!= IS_LEVEL_1
&& hdr
.circuit_t
!= IS_LEVEL_2
&&
712 hdr
.circuit_t
!= IS_LEVEL_1_AND_2
)
714 zlog_warn ("Level %d LAN Hello with Circuit Type %d", level
,
721 expected
|= TLVFLAG_AUTH_INFO
;
722 expected
|= TLVFLAG_AREA_ADDRS
;
723 expected
|= TLVFLAG_LAN_NEIGHS
;
724 expected
|= TLVFLAG_NLPID
;
725 expected
|= TLVFLAG_IPV4_ADDR
;
726 expected
|= TLVFLAG_IPV6_ADDR
;
728 retval
= parse_tlvs (circuit
->area
->area_tag
,
729 STREAM_PNT (circuit
->rcv_stream
),
730 hdr
.pdu_len
- ISIS_LANHELLO_HDRLEN
-
731 ISIS_FIXED_HDR_LEN
, &expected
, &found
, &tlvs
);
733 if (retval
> ISIS_WARNING
)
735 zlog_warn ("parse_tlvs() failed");
739 if (!(found
& TLVFLAG_AREA_ADDRS
))
741 zlog_warn ("No Area addresses TLV in Level %d LAN IS to IS hello",
743 retval
= ISIS_WARNING
;
747 if (circuit
->passwd
.type
)
749 if (!(found
& TLVFLAG_AUTH_INFO
) ||
750 authentication_check (&circuit
->passwd
, &tlvs
.auth_info
))
752 isis_event_auth_failure (circuit
->area
->area_tag
,
753 "LAN hello authentication failure",
755 retval
= ISIS_WARNING
;
761 * Accept the level 1 adjacency only if a match between local and
762 * remote area addresses is found
764 if (level
== 1 && !area_match (circuit
->area
->area_addrs
, tlvs
.area_addrs
))
766 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
768 zlog_debug ("ISIS-Adj (%s): Area mismatch, level %d IIH on %s",
769 circuit
->area
->area_tag
, level
,
770 circuit
->interface
->name
);
777 * it's own IIH PDU - discard silently
779 if (!memcmp (circuit
->u
.bc
.snpa
, ssnpa
, ETH_ALEN
))
781 zlog_debug ("ISIS-Adj (%s): it's own IIH PDU - discarded",
782 circuit
->area
->area_tag
);
789 * check if it's own interface ip match iih ip addrs
791 if (!(found
& TLVFLAG_IPV4_ADDR
)
792 || !ip_match (circuit
->ip_addrs
, tlvs
.ipv4_addrs
))
795 ("ISIS-Adj: No usable IP interface addresses in LAN IIH from %s\n",
796 circuit
->interface
->name
);
797 retval
= ISIS_WARNING
;
801 adj
= isis_adj_lookup (hdr
.source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
807 adj
= isis_new_adj (hdr
.source_id
, ssnpa
, level
, circuit
);
815 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
819 adj
->sys_type
= ISIS_SYSTYPE_L1_IS
;
823 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
825 list_delete_all_node (circuit
->u
.bc
.lan_neighs
[level
- 1]);
826 isis_adj_build_neigh_list (circuit
->u
.bc
.adjdb
[level
- 1],
827 circuit
->u
.bc
.lan_neighs
[level
- 1]);
830 if(adj
->dis_record
[level
-1].dis
==ISIS_IS_DIS
)
834 if (memcmp (circuit
->u
.bc
.l1_desig_is
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1))
836 thread_add_event (master
, isis_event_dis_status_change
, circuit
, 0);
837 memcpy (&circuit
->u
.bc
.l1_desig_is
, hdr
.lan_id
,
838 ISIS_SYS_ID_LEN
+ 1);
842 if (memcmp (circuit
->u
.bc
.l2_desig_is
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1))
844 thread_add_event (master
, isis_event_dis_status_change
, circuit
, 0);
845 memcpy (&circuit
->u
.bc
.l2_desig_is
, hdr
.lan_id
,
846 ISIS_SYS_ID_LEN
+ 1);
851 adj
->hold_time
= hdr
.hold_time
;
852 adj
->last_upd
= time (NULL
);
853 adj
->prio
[level
- 1] = hdr
.prio
;
855 memcpy (adj
->lanid
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1);
857 /* which protocol are spoken ??? */
858 if (found
& TLVFLAG_NLPID
)
859 tlvs_to_adj_nlpids (&tlvs
, adj
);
861 /* we need to copy addresses to the adj */
862 if (found
& TLVFLAG_IPV4_ADDR
)
863 tlvs_to_adj_ipv4_addrs (&tlvs
, adj
);
866 if (found
& TLVFLAG_IPV6_ADDR
)
867 tlvs_to_adj_ipv6_addrs (&tlvs
, adj
);
868 #endif /* HAVE_IPV6 */
870 adj
->circuit_t
= hdr
.circuit_t
;
872 /* lets take care of the expiry */
873 THREAD_TIMER_OFF (adj
->t_expire
);
874 THREAD_TIMER_ON (master
, adj
->t_expire
, isis_adj_expire
, adj
,
875 (long) adj
->hold_time
);
878 * If the snpa for this circuit is found from LAN Neighbours TLV
879 * we have two-way communication -> adjacency can be put to state "up"
882 if (found
& TLVFLAG_LAN_NEIGHS
)
884 if (adj
->adj_state
!= ISIS_ADJ_UP
)
886 for (ALL_LIST_ELEMENTS_RO (tlvs
.lan_neighs
, node
, snpa
))
887 if (!memcmp (snpa
, circuit
->u
.bc
.snpa
, ETH_ALEN
))
889 isis_adj_state_change (adj
, ISIS_ADJ_UP
,
890 "own SNPA found in LAN Neighbours TLV");
896 /* DEBUG_ADJ_PACKETS */
897 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
899 /* FIXME: is this place right? fix missing info */
900 zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "
901 "cirID %u, length %ld",
902 circuit
->area
->area_tag
,
903 level
, snpa_print (ssnpa
), circuit
->interface
->name
,
904 circuit_t2string (circuit
->circuit_is_type
),
906 /* FIXME: use %z when we stop supporting old compilers. */
907 (unsigned long) stream_get_endp (circuit
->rcv_stream
));
916 * Process Level 1/2 Link State
918 * Section 7.3.15.1 - Action on receipt of a link state PDU
921 process_lsp (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
923 struct isis_link_state_hdr
*hdr
;
924 struct isis_adjacency
*adj
= NULL
;
925 struct isis_lsp
*lsp
, *lsp0
= NULL
;
926 int retval
= ISIS_OK
, comp
= 0;
927 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
928 struct isis_passwd
*passwd
;
930 /* Sanity check - FIXME: move to correct place */
931 if ((stream_get_endp (circuit
->rcv_stream
) -
932 stream_get_getp (circuit
->rcv_stream
)) < ISIS_LSP_HDR_LEN
)
934 zlog_warn ("Packet too short");
938 /* Reference the header */
939 hdr
= (struct isis_link_state_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
941 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
943 zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "
944 "lifetime %us, len %lu, on %s",
945 circuit
->area
->area_tag
,
947 rawlspid_print (hdr
->lsp_id
),
948 ntohl (hdr
->seq_num
),
949 ntohs (hdr
->checksum
),
950 ntohs (hdr
->rem_lifetime
),
951 /* FIXME: use %z when we stop supporting old compilers. */
952 (unsigned long) stream_get_endp (circuit
->rcv_stream
),
953 circuit
->interface
->name
);
956 assert (ntohs (hdr
->pdu_len
) > ISIS_LSP_HDR_LEN
);
958 /* Checksum sanity check - FIXME: move to correct place */
959 /* 12 = sysid+pdu+remtime */
960 if (iso_csum_verify (STREAM_PNT (circuit
->rcv_stream
) + 4,
961 ntohs (hdr
->pdu_len
) - 12, &hdr
->checksum
))
963 zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
964 circuit
->area
->area_tag
,
965 rawlspid_print (hdr
->lsp_id
), ntohs (hdr
->checksum
));
970 /* 7.3.15.1 a) 1 - external domain circuit will discard lsps */
971 if (circuit
->ext_domain
)
974 ("ISIS-Upd (%s): LSP %s received at level %d over circuit with "
975 "externalDomain = true", circuit
->area
->area_tag
,
976 rawlspid_print (hdr
->lsp_id
), level
);
981 /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
982 if (!accept_level (level
, circuit
->circuit_is_type
))
984 zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of"
986 circuit
->area
->area_tag
,
987 rawlspid_print (hdr
->lsp_id
),
988 level
, circuit_t2string (circuit
->circuit_is_type
));
993 /* 7.3.15.1 a) 4 - need to make sure IDLength matches */
995 /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */
997 /* 7.3.15.1 a) 7 - password check */
998 (level
== ISIS_LEVEL1
) ? (passwd
= &circuit
->area
->area_passwd
) :
999 (passwd
= &circuit
->area
->domain_passwd
);
1002 if (isis_lsp_authinfo_check (circuit
->rcv_stream
, circuit
->area
,
1003 ntohs (hdr
->pdu_len
), passwd
))
1005 isis_event_auth_failure (circuit
->area
->area_tag
,
1006 "LSP authentication failure", hdr
->lsp_id
);
1007 return ISIS_WARNING
;
1010 /* Find the LSP in our database and compare it to this Link State header */
1011 lsp
= lsp_search (hdr
->lsp_id
, circuit
->area
->lspdb
[level
- 1]);
1013 comp
= lsp_compare (circuit
->area
->area_tag
, lsp
, hdr
->seq_num
,
1014 hdr
->checksum
, hdr
->rem_lifetime
);
1015 if (lsp
&& (lsp
->own_lsp
1016 #ifdef TOPOLOGY_GENERATE
1017 || lsp
->from_topology
1018 #endif /* TOPOLOGY_GENERATE */
1022 /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level */
1023 /* for broadcast circuits, snpa should be compared */
1024 /* FIXME : Point To Point */
1026 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1028 adj
= isis_adj_lookup_snpa (ssnpa
, circuit
->u
.bc
.adjdb
[level
- 1]);
1031 zlog_debug ("(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, "
1032 "lifetime %us on %s",
1033 circuit
->area
->area_tag
,
1034 rawlspid_print (hdr
->lsp_id
),
1035 ntohl (hdr
->seq_num
),
1036 ntohs (hdr
->checksum
),
1037 ntohs (hdr
->rem_lifetime
), circuit
->interface
->name
);
1038 return ISIS_WARNING
; /* Silently discard */
1042 /* for non broadcast, we just need to find same level adj */
1045 /* If no adj, or no sharing of level */
1046 if (!circuit
->u
.p2p
.neighbor
)
1048 return ISIS_OK
; /* Silently discard */
1052 if (((level
== 1) &&
1053 (circuit
->u
.p2p
.neighbor
->adj_usage
== ISIS_ADJ_LEVEL2
)) ||
1055 (circuit
->u
.p2p
.neighbor
->adj_usage
== ISIS_ADJ_LEVEL1
)))
1056 return ISIS_WARNING
; /* Silently discard */
1060 /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */
1062 /* 7.3.15.1 a) 8 - Passwords for level 2 - not implemented */
1064 /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented FIXME: do it */
1066 /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */
1067 if (hdr
->rem_lifetime
== 0)
1071 /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't save */
1072 /* only needed on explicit update, eg - p2p */
1073 if (circuit
->circ_type
== CIRCUIT_T_P2P
)
1074 ack_lsp (hdr
, circuit
, level
);
1075 return retval
; /* FIXME: do we need a purge? */
1079 if (memcmp (hdr
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
1081 /* LSP by some other system -> do 7.3.16.4 b) */
1082 /* 7.3.16.4 b) 1) */
1083 if (comp
== LSP_NEWER
)
1085 lsp_update (lsp
, hdr
, circuit
->rcv_stream
, circuit
->area
,
1088 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1090 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1092 ISIS_FLAGS_CLEAR_ALL (lsp
->SSNflags
); /* FIXME: OTHER than c */
1094 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1095 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1097 } /* 7.3.16.4 b) 2) */
1098 else if (comp
== LSP_EQUAL
)
1101 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1103 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1104 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1105 } /* 7.3.16.4 b) 3) */
1108 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1109 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1114 /* our own LSP -> 7.3.16.4 c) */
1115 if (LSP_PSEUDO_ID (lsp
->lsp_header
->lsp_id
) !=
1117 || (LSP_PSEUDO_ID (lsp
->lsp_header
->lsp_id
) ==
1119 && circuit
->u
.bc
.is_dr
[level
- 1] == 1))
1121 lsp
->lsp_header
->seq_num
= htonl (ntohl (hdr
->seq_num
) + 1);
1122 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1123 zlog_debug ("LSP LEN: %d",
1124 ntohs (lsp
->lsp_header
->pdu_len
));
1125 fletcher_checksum (STREAM_DATA (lsp
->pdu
) + 12,
1126 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
1127 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1128 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1129 zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new "
1130 "seq 0x%08x", circuit
->area
->area_tag
,
1131 rawlspid_print (hdr
->lsp_id
),
1132 ntohl (lsp
->lsp_header
->seq_num
));
1133 lsp
->lsp_header
->rem_lifetime
=
1135 (circuit
->area
->max_lsp_lifetime
[level
- 1],
1140 /* Got purge for own pseudo-lsp, and we are not DR */
1141 lsp_purge_dr (lsp
->lsp_header
->lsp_id
, circuit
, level
);
1147 /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a
1149 if (memcmp (hdr
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
) == 0)
1153 /* 7.3.16.4: initiate a purge */
1154 lsp_purge_non_exist (hdr
, circuit
->area
);
1157 /* 7.3.15.1 d) - If this is our own lsp and we have it */
1159 /* In 7.3.16.1, If an Intermediate system R somewhere in the domain
1160 * has information that the current sequence number for source S is
1161 * "greater" than that held by S, ... */
1163 else if (ntohl (hdr
->seq_num
) > ntohl (lsp
->lsp_header
->seq_num
))
1166 lsp
->lsp_header
->seq_num
= htonl (ntohl (hdr
->seq_num
) + 1);
1168 fletcher_checksum (STREAM_DATA (lsp
->pdu
) + 12,
1169 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
1171 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1172 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1173 zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq "
1174 "0x%08x", circuit
->area
->area_tag
,
1175 rawlspid_print (hdr
->lsp_id
),
1176 ntohl (lsp
->lsp_header
->seq_num
));
1177 lsp
->lsp_header
->rem_lifetime
=
1179 (circuit
->area
->max_lsp_lifetime
[level
- 1],
1185 /* 7.3.15.1 e) - This lsp originated on another system */
1187 /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */
1188 if ((!lsp
|| comp
== LSP_NEWER
))
1193 #ifdef EXTREME_DEBUG
1194 zlog_debug ("level %d number is - %ld", level
,
1195 circuit
->area
->lspdb
[level
- 1]->dict_nodecount
);
1196 #endif /* EXTREME DEBUG */
1197 lsp_search_and_destroy (hdr
->lsp_id
,
1198 circuit
->area
->lspdb
[level
- 1]);
1199 /* exists, so we overwrite */
1200 #ifdef EXTREME_DEBUG
1201 zlog_debug ("level %d number is - %ld", level
,
1202 circuit
->area
->lspdb
[level
- 1]->dict_nodecount
);
1203 #endif /* EXTREME DEBUG */
1206 * If this lsp is a frag, need to see if we have zero lsp present
1208 if (LSP_FRAGMENT (hdr
->lsp_id
) != 0)
1210 memcpy (lspid
, hdr
->lsp_id
, ISIS_SYS_ID_LEN
+ 1);
1211 LSP_FRAGMENT (lspid
) = 0;
1212 lsp0
= lsp_search (lspid
, circuit
->area
->lspdb
[level
- 1]);
1215 zlog_debug ("Got lsp frag, while zero lsp not database");
1220 lsp_new_from_stream_ptr (circuit
->rcv_stream
,
1221 ntohs (hdr
->pdu_len
), lsp0
,
1225 lsp_insert (lsp
, circuit
->area
->lspdb
[level
- 1]);
1227 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1229 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1232 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1233 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1236 /* 7.3.15.1 e) 2) LSP equal to the one in db */
1237 else if (comp
== LSP_EQUAL
)
1239 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1240 lsp_update (lsp
, hdr
, circuit
->rcv_stream
, circuit
->area
, level
);
1241 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1243 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1246 /* 7.3.15.1 e) 3) LSP older than the one in db */
1249 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1250 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1259 * Process Sequence Numbers
1261 * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU
1265 process_snp (int snp_type
, int level
, struct isis_circuit
*circuit
,
1268 int retval
= ISIS_OK
;
1270 char typechar
= ' ';
1272 struct isis_adjacency
*adj
;
1273 struct isis_complete_seqnum_hdr
*chdr
= NULL
;
1274 struct isis_partial_seqnum_hdr
*phdr
= NULL
;
1275 uint32_t found
= 0, expected
= 0;
1276 struct isis_lsp
*lsp
;
1277 struct lsp_entry
*entry
;
1278 struct listnode
*node
, *nnode
;
1279 struct listnode
*node2
, *nnode2
;
1281 struct list
*lsp_list
= NULL
;
1282 struct isis_passwd
*passwd
;
1284 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1286 /* getting the header info */
1289 (struct isis_complete_seqnum_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
1290 circuit
->rcv_stream
->getp
+= ISIS_CSNP_HDRLEN
;
1291 len
= ntohs (chdr
->pdu_len
);
1292 if (len
< ISIS_CSNP_HDRLEN
)
1294 zlog_warn ("Received a CSNP with bogus length!");
1302 (struct isis_partial_seqnum_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
1303 circuit
->rcv_stream
->getp
+= ISIS_PSNP_HDRLEN
;
1304 len
= ntohs (phdr
->pdu_len
);
1305 if (len
< ISIS_PSNP_HDRLEN
)
1307 zlog_warn ("Received a CSNP with bogus length!");
1312 /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */
1313 if (circuit
->ext_domain
)
1316 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1317 "skipping: circuit externalDomain = true",
1318 circuit
->area
->area_tag
,
1319 level
, typechar
, circuit
->interface
->name
);
1324 /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
1325 if (!accept_level (level
, circuit
->circuit_is_type
))
1328 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1329 "skipping: circuit type %s does not match level %d",
1330 circuit
->area
->area_tag
,
1333 circuit
->interface
->name
,
1334 circuit_t2string (circuit
->circuit_is_type
), level
);
1339 /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */
1340 if ((snp_type
== ISIS_SNP_PSNP_FLAG
) &&
1341 (circuit
->circ_type
== CIRCUIT_T_BROADCAST
))
1343 if (!circuit
->u
.bc
.is_dr
[level
- 1])
1346 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
1347 "skipping: we are not the DIS",
1348 circuit
->area
->area_tag
,
1350 typechar
, snpa_print (ssnpa
), circuit
->interface
->name
);
1356 /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */
1358 /* 7.3.15.2 a) 6 - maximum area match, can be ommited since we only use 3
1359 * - already checked */
1361 /* 7.3.15.2 a) 7 - Must check that we have an adjacency of the same level */
1362 /* for broadcast circuits, snpa should be compared */
1363 /* FIXME : Do we need to check SNPA? */
1364 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1366 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1369 isis_adj_lookup (chdr
->source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
1373 /* a psnp on a broadcast, how lovely of Juniper :) */
1375 isis_adj_lookup (phdr
->source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
1378 return ISIS_OK
; /* Silently discard */
1382 if (!circuit
->u
.p2p
.neighbor
)
1383 return ISIS_OK
; /* Silently discard */
1386 /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */
1388 /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */
1390 memset (&tlvs
, 0, sizeof (struct tlvs
));
1393 expected
|= TLVFLAG_LSP_ENTRIES
;
1394 expected
|= TLVFLAG_AUTH_INFO
;
1395 retval
= parse_tlvs (circuit
->area
->area_tag
,
1396 STREAM_PNT (circuit
->rcv_stream
),
1397 len
- circuit
->rcv_stream
->getp
,
1398 &expected
, &found
, &tlvs
);
1400 if (retval
> ISIS_WARNING
)
1402 zlog_warn ("something went very wrong processing SNP");
1408 passwd
= &circuit
->area
->area_passwd
;
1410 passwd
= &circuit
->area
->domain_passwd
;
1412 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_RECV
))
1416 if (!(found
& TLVFLAG_AUTH_INFO
) ||
1417 authentication_check (passwd
, &tlvs
.auth_info
))
1419 isis_event_auth_failure (circuit
->area
->area_tag
,
1420 "SNP authentication" " failure",
1421 phdr
? phdr
->source_id
: chdr
->source_id
);
1427 /* debug isis snp-packets */
1428 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
1430 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s",
1431 circuit
->area
->area_tag
,
1433 typechar
, snpa_print (ssnpa
), circuit
->interface
->name
);
1434 if (tlvs
.lsp_entries
)
1436 for (ALL_LIST_ELEMENTS_RO (tlvs
.lsp_entries
, node
, entry
))
1438 zlog_debug ("ISIS-Snp (%s): %cSNP entry %s, seq 0x%08x,"
1439 " cksum 0x%04x, lifetime %us",
1440 circuit
->area
->area_tag
,
1442 rawlspid_print (entry
->lsp_id
),
1443 ntohl (entry
->seq_num
),
1444 ntohs (entry
->checksum
), ntohs (entry
->rem_lifetime
));
1449 /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */
1450 if (tlvs
.lsp_entries
)
1452 for (ALL_LIST_ELEMENTS_RO (tlvs
.lsp_entries
, node
, entry
))
1454 lsp
= lsp_search (entry
->lsp_id
, circuit
->area
->lspdb
[level
- 1]);
1455 own_lsp
= !memcmp (entry
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1458 /* 7.3.15.2 b) 1) is this LSP newer */
1459 cmp
= lsp_compare (circuit
->area
->area_tag
, lsp
, entry
->seq_num
,
1460 entry
->checksum
, entry
->rem_lifetime
);
1461 /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */
1462 if (cmp
== LSP_EQUAL
)
1464 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1465 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1466 /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
1468 else if (cmp
== LSP_OLDER
)
1470 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1471 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1475 /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM
1479 lsp_inc_seqnum (lsp
, ntohl (entry
->seq_num
));
1480 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1484 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1485 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1486 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1492 /* 7.3.15.2 b) 5) if it was not found, and all of those are not 0,
1493 * insert it and set SSN on it */
1494 if (entry
->rem_lifetime
&& entry
->checksum
&& entry
->seq_num
&&
1495 memcmp (entry
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
1497 lsp
= lsp_new (entry
->lsp_id
, ntohs (entry
->rem_lifetime
),
1498 0, 0, entry
->checksum
, level
);
1499 lsp_insert (lsp
, circuit
->area
->lspdb
[level
- 1]);
1500 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1506 /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported */
1507 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1510 * Build a list from our own LSP db bounded with start_ and stop_lsp_id
1512 lsp_list
= list_new ();
1513 lsp_build_list_nonzero_ht (chdr
->start_lsp_id
, chdr
->stop_lsp_id
,
1514 lsp_list
, circuit
->area
->lspdb
[level
- 1]);
1516 /* Fixme: Find a better solution */
1517 if (tlvs
.lsp_entries
)
1519 for (ALL_LIST_ELEMENTS (tlvs
.lsp_entries
, node
, nnode
, entry
))
1521 for (ALL_LIST_ELEMENTS (lsp_list
, node2
, nnode2
, lsp
))
1523 if (lsp_id_cmp (lsp
->lsp_header
->lsp_id
, entry
->lsp_id
) == 0)
1525 list_delete_node (lsp_list
, node2
);
1531 /* on remaining LSPs we set SRM (neighbor knew not of) */
1532 for (ALL_LIST_ELEMENTS_RO (lsp_list
, node
, lsp
))
1534 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1537 list_free (lsp_list
);
1545 process_csnp (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
1547 /* Sanity check - FIXME: move to correct place */
1548 if ((stream_get_endp (circuit
->rcv_stream
) -
1549 stream_get_getp (circuit
->rcv_stream
)) < ISIS_CSNP_HDRLEN
)
1551 zlog_warn ("Packet too short ( < %d)", ISIS_CSNP_HDRLEN
);
1552 return ISIS_WARNING
;
1555 return process_snp (ISIS_SNP_CSNP_FLAG
, level
, circuit
, ssnpa
);
1559 process_psnp (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
1561 if ((stream_get_endp (circuit
->rcv_stream
) -
1562 stream_get_getp (circuit
->rcv_stream
)) < ISIS_PSNP_HDRLEN
)
1564 zlog_warn ("Packet too short");
1565 return ISIS_WARNING
;
1568 return process_snp (ISIS_SNP_PSNP_FLAG
, level
, circuit
, ssnpa
);
1574 * Section 8.2.2 - Receiving ISH PDUs by an intermediate system
1575 * FIXME: sample packet dump, need to figure 0x81 - looks like NLPid
1576 * 0x82 0x15 0x01 0x00 0x04 0x01 0x2c 0x59
1577 * 0x38 0x08 0x47 0x00 0x01 0x00 0x02 0x00
1578 * 0x03 0x00 0x81 0x01 0xcc
1581 process_is_hello (struct isis_circuit
*circuit
)
1583 struct isis_adjacency
*adj
;
1584 int retval
= ISIS_OK
;
1588 /* In this point in time we are not yet able to handle is_hellos
1589 * on lan - Sorry juniper...
1591 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1594 neigh_len
= stream_getc (circuit
->rcv_stream
);
1595 sysid
= STREAM_PNT (circuit
->rcv_stream
) + neigh_len
- 1 - ISIS_SYS_ID_LEN
;
1596 adj
= circuit
->u
.p2p
.neighbor
;
1600 adj
= isis_new_adj (sysid
, NULL
, 0, circuit
);
1604 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
1605 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
1606 circuit
->u
.p2p
.neighbor
= adj
;
1609 if ((adj
->adj_state
== ISIS_ADJ_UP
) && memcmp (adj
->sysid
, sysid
,
1612 /* 8.2.2 a) 1) FIXME: adjStateChange(down) event */
1613 /* 8.2.2 a) 2) delete the adj */
1614 XFREE (MTYPE_ISIS_ADJACENCY
, adj
);
1615 /* 8.2.2 a) 3) create a new adj */
1616 adj
= isis_new_adj (sysid
, NULL
, 0, circuit
);
1621 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
1622 /* 8.2.2 a) 3) ii */
1623 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
1624 /* 8.2.2 a) 4) quite meaningless */
1626 /* 8.2.2 b) ignore on condition */
1627 if ((adj
->adj_state
== ISIS_ADJ_INITIALIZING
) &&
1628 (adj
->sys_type
== ISIS_SYSTYPE_IS
))
1634 /* 8.2.2 c) respond with a p2p IIH */
1635 send_hello (circuit
, 1);
1637 /* 8.2.2 d) type is IS */
1638 adj
->sys_type
= ISIS_SYSTYPE_IS
;
1639 /* 8.2.2 e) FIXME: Circuit type of? */
1649 isis_handle_pdu (struct isis_circuit
*circuit
, u_char
* ssnpa
)
1651 struct isis_fixed_hdr
*hdr
;
1652 struct esis_fixed_hdr
*esis_hdr
;
1654 int retval
= ISIS_OK
;
1657 * Let's first read data from stream to the header
1659 hdr
= (struct isis_fixed_hdr
*) STREAM_DATA (circuit
->rcv_stream
);
1661 if ((hdr
->idrp
!= ISO10589_ISIS
) && (hdr
->idrp
!= ISO9542_ESIS
))
1663 zlog_warn ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr
->idrp
);
1667 /* now we need to know if this is an ISO 9542 packet and
1668 * take real good care of it, waaa!
1670 if (hdr
->idrp
== ISO9542_ESIS
)
1672 esis_hdr
= (struct esis_fixed_hdr
*) STREAM_DATA (circuit
->rcv_stream
);
1673 stream_set_getp (circuit
->rcv_stream
, ESIS_FIXED_HDR_LEN
);
1674 /* FIXME: Need to do some acceptence tests */
1675 /* example length... */
1676 switch (esis_hdr
->pdu_type
)
1682 zlog_debug ("AN ISH PDU!!");
1683 retval
= process_is_hello (circuit
);
1692 stream_set_getp (circuit
->rcv_stream
, ISIS_FIXED_HDR_LEN
);
1695 * and then process it
1698 if (hdr
->length
< ISIS_MINIMUM_FIXED_HDR_LEN
)
1700 zlog_err ("Fixed header length = %d", hdr
->length
);
1704 if (hdr
->version1
!= 1)
1706 zlog_warn ("Unsupported ISIS version %u", hdr
->version1
);
1707 return ISIS_WARNING
;
1710 if ((hdr
->id_len
!= 0) && (hdr
->id_len
!= ISIS_SYS_ID_LEN
))
1713 ("IDFieldLengthMismatch: ID Length field in a received PDU %u, "
1714 "while the parameter for this IS is %u", hdr
->id_len
,
1719 if (hdr
->version2
!= 1)
1721 zlog_warn ("Unsupported ISIS version %u", hdr
->version2
);
1722 return ISIS_WARNING
;
1725 if ((hdr
->max_area_addrs
!= 0)
1726 && (hdr
->max_area_addrs
!= isis
->max_area_addrs
))
1728 zlog_err ("maximumAreaAddressesMismatch: maximumAreaAdresses in a "
1729 "received PDU %u while the parameter for this IS is %u",
1730 hdr
->max_area_addrs
, isis
->max_area_addrs
);
1734 switch (hdr
->pdu_type
)
1737 retval
= process_lan_hello (ISIS_LEVEL1
, circuit
, ssnpa
);
1740 retval
= process_lan_hello (ISIS_LEVEL2
, circuit
, ssnpa
);
1743 retval
= process_p2p_hello (circuit
);
1746 retval
= process_lsp (ISIS_LEVEL1
, circuit
, ssnpa
);
1749 retval
= process_lsp (ISIS_LEVEL2
, circuit
, ssnpa
);
1751 case L1_COMPLETE_SEQ_NUM
:
1752 retval
= process_csnp (ISIS_LEVEL1
, circuit
, ssnpa
);
1754 case L2_COMPLETE_SEQ_NUM
:
1755 retval
= process_csnp (ISIS_LEVEL2
, circuit
, ssnpa
);
1757 case L1_PARTIAL_SEQ_NUM
:
1758 retval
= process_psnp (ISIS_LEVEL1
, circuit
, ssnpa
);
1760 case L2_PARTIAL_SEQ_NUM
:
1761 retval
= process_psnp (ISIS_LEVEL2
, circuit
, ssnpa
);
1772 isis_receive (struct thread
*thread
)
1774 struct isis_circuit
*circuit
;
1775 u_char ssnpa
[ETH_ALEN
];
1781 circuit
= THREAD_ARG (thread
);
1784 if (circuit
->rcv_stream
== NULL
)
1785 circuit
->rcv_stream
= stream_new (ISO_MTU (circuit
));
1787 stream_reset (circuit
->rcv_stream
);
1789 retval
= circuit
->rx (circuit
, ssnpa
);
1790 circuit
->t_read
= NULL
;
1792 if (retval
== ISIS_OK
)
1793 retval
= isis_handle_pdu (circuit
, ssnpa
);
1796 * prepare for next packet.
1798 THREAD_READ_ON (master
, circuit
->t_read
, isis_receive
, circuit
,
1806 isis_receive (struct thread
*thread
)
1808 struct isis_circuit
*circuit
;
1809 u_char ssnpa
[ETH_ALEN
];
1815 circuit
= THREAD_ARG (thread
);
1818 circuit
->t_read
= NULL
;
1820 if (circuit
->rcv_stream
== NULL
)
1821 circuit
->rcv_stream
= stream_new (ISO_MTU (circuit
));
1823 stream_reset (circuit
->rcv_stream
);
1825 retval
= circuit
->rx (circuit
, ssnpa
);
1827 if (retval
== ISIS_OK
)
1828 retval
= isis_handle_pdu (circuit
, ssnpa
);
1831 * prepare for next packet.
1833 circuit
->t_read
= thread_add_timer_msec (master
, isis_receive
, circuit
,
1835 (circuit
->area
->circuit_list
) *
1843 /* filling of the fixed isis header */
1845 fill_fixed_hdr (struct isis_fixed_hdr
*hdr
, u_char pdu_type
)
1847 memset (hdr
, 0, sizeof (struct isis_fixed_hdr
));
1849 hdr
->idrp
= ISO10589_ISIS
;
1855 hdr
->length
= ISIS_LANHELLO_HDRLEN
;
1858 hdr
->length
= ISIS_P2PHELLO_HDRLEN
;
1862 hdr
->length
= ISIS_LSP_HDR_LEN
;
1864 case L1_COMPLETE_SEQ_NUM
:
1865 case L2_COMPLETE_SEQ_NUM
:
1866 hdr
->length
= ISIS_CSNP_HDRLEN
;
1868 case L1_PARTIAL_SEQ_NUM
:
1869 case L2_PARTIAL_SEQ_NUM
:
1870 hdr
->length
= ISIS_PSNP_HDRLEN
;
1873 zlog_warn ("fill_fixed_hdr(): unknown pdu type %d", pdu_type
);
1876 hdr
->length
+= ISIS_FIXED_HDR_LEN
;
1877 hdr
->pdu_type
= pdu_type
;
1879 hdr
->id_len
= 0; /* ISIS_SYS_ID_LEN - 0==6 */
1881 hdr
->max_area_addrs
= 0; /* isis->max_area_addrs - 0==3 */
1888 fill_fixed_hdr_andstream (struct isis_fixed_hdr
*hdr
, u_char pdu_type
,
1889 struct stream
*stream
)
1891 fill_fixed_hdr (hdr
, pdu_type
);
1893 stream_putc (stream
, hdr
->idrp
);
1894 stream_putc (stream
, hdr
->length
);
1895 stream_putc (stream
, hdr
->version1
);
1896 stream_putc (stream
, hdr
->id_len
);
1897 stream_putc (stream
, hdr
->pdu_type
);
1898 stream_putc (stream
, hdr
->version2
);
1899 stream_putc (stream
, hdr
->reserved
);
1900 stream_putc (stream
, hdr
->max_area_addrs
);
1906 send_hello (struct isis_circuit
*circuit
, int level
)
1908 struct isis_fixed_hdr fixed_hdr
;
1909 struct isis_lan_hello_hdr hello_hdr
;
1910 struct isis_p2p_hello_hdr p2p_hello_hdr
;
1913 unsigned long len_pointer
, length
;
1916 if (circuit
->interface
->mtu
== 0)
1918 zlog_warn ("circuit has zero MTU");
1919 return ISIS_WARNING
;
1922 if (!circuit
->snd_stream
)
1923 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
1925 stream_reset (circuit
->snd_stream
);
1927 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1929 fill_fixed_hdr_andstream (&fixed_hdr
, L1_LAN_HELLO
,
1930 circuit
->snd_stream
);
1932 fill_fixed_hdr_andstream (&fixed_hdr
, L2_LAN_HELLO
,
1933 circuit
->snd_stream
);
1935 fill_fixed_hdr_andstream (&fixed_hdr
, P2P_HELLO
, circuit
->snd_stream
);
1938 * Fill LAN Level 1 or 2 Hello PDU header
1940 memset (&hello_hdr
, 0, sizeof (struct isis_lan_hello_hdr
));
1941 interval
= circuit
->hello_multiplier
[level
- 1] *
1942 circuit
->hello_interval
[level
- 1];
1943 if (interval
> USHRT_MAX
)
1944 interval
= USHRT_MAX
;
1945 hello_hdr
.circuit_t
= circuit
->circuit_is_type
;
1946 memcpy (hello_hdr
.source_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1947 hello_hdr
.hold_time
= htons ((u_int16_t
) interval
);
1949 hello_hdr
.pdu_len
= 0; /* Update the PDU Length later */
1950 len_pointer
= stream_get_endp (circuit
->snd_stream
) + 3 + ISIS_SYS_ID_LEN
;
1952 /* copy the shared part of the hello to the p2p hello if needed */
1953 if (circuit
->circ_type
== CIRCUIT_T_P2P
)
1955 memcpy (&p2p_hello_hdr
, &hello_hdr
, 5 + ISIS_SYS_ID_LEN
);
1956 p2p_hello_hdr
.local_id
= circuit
->circuit_id
;
1957 /* FIXME: need better understanding */
1958 stream_put (circuit
->snd_stream
, &p2p_hello_hdr
, ISIS_P2PHELLO_HDRLEN
);
1962 hello_hdr
.prio
= circuit
->u
.bc
.priority
[level
- 1];
1963 if (level
== 1 && circuit
->u
.bc
.l1_desig_is
)
1965 memcpy (hello_hdr
.lan_id
, circuit
->u
.bc
.l1_desig_is
,
1966 ISIS_SYS_ID_LEN
+ 1);
1968 else if (level
== 2 && circuit
->u
.bc
.l2_desig_is
)
1970 memcpy (hello_hdr
.lan_id
, circuit
->u
.bc
.l2_desig_is
,
1971 ISIS_SYS_ID_LEN
+ 1);
1973 stream_put (circuit
->snd_stream
, &hello_hdr
, ISIS_LANHELLO_HDRLEN
);
1977 * Then the variable length part
1979 /* add circuit password */
1980 if (circuit
->passwd
.type
)
1981 if (tlv_add_authinfo (circuit
->passwd
.type
, circuit
->passwd
.len
,
1982 circuit
->passwd
.passwd
, circuit
->snd_stream
))
1983 return ISIS_WARNING
;
1984 /* Area Addresses TLV */
1985 assert (circuit
->area
);
1986 if (circuit
->area
->area_addrs
&& circuit
->area
->area_addrs
->count
> 0)
1987 if (tlv_add_area_addrs (circuit
->area
->area_addrs
, circuit
->snd_stream
))
1988 return ISIS_WARNING
;
1990 /* LAN Neighbors TLV */
1991 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1993 if (level
== 1 && circuit
->u
.bc
.lan_neighs
[0]->count
> 0)
1994 if (tlv_add_lan_neighs (circuit
->u
.bc
.lan_neighs
[0],
1995 circuit
->snd_stream
))
1996 return ISIS_WARNING
;
1997 if (level
== 2 && circuit
->u
.bc
.lan_neighs
[1]->count
> 0)
1998 if (tlv_add_lan_neighs (circuit
->u
.bc
.lan_neighs
[1],
1999 circuit
->snd_stream
))
2000 return ISIS_WARNING
;
2003 /* Protocols Supported TLV */
2004 if (circuit
->nlpids
.count
> 0)
2005 if (tlv_add_nlpid (&circuit
->nlpids
, circuit
->snd_stream
))
2006 return ISIS_WARNING
;
2007 /* IP interface Address TLV */
2008 if (circuit
->ip_router
&& circuit
->ip_addrs
&& circuit
->ip_addrs
->count
> 0)
2009 if (tlv_add_ip_addrs (circuit
->ip_addrs
, circuit
->snd_stream
))
2010 return ISIS_WARNING
;
2013 /* IPv6 Interface Address TLV */
2014 if (circuit
->ipv6_router
&& circuit
->ipv6_link
&&
2015 circuit
->ipv6_link
->count
> 0)
2016 if (tlv_add_ipv6_addrs (circuit
->ipv6_link
, circuit
->snd_stream
))
2017 return ISIS_WARNING
;
2018 #endif /* HAVE_IPV6 */
2020 if (circuit
->u
.bc
.pad_hellos
)
2021 if (tlv_add_padding (circuit
->snd_stream
))
2022 return ISIS_WARNING
;
2024 length
= stream_get_endp (circuit
->snd_stream
);
2025 /* Update PDU length */
2026 stream_putw_at (circuit
->snd_stream
, len_pointer
, (u_int16_t
) length
);
2028 retval
= circuit
->tx (circuit
, level
);
2030 zlog_warn ("sending of LAN Level %d Hello failed", level
);
2032 /* DEBUG_ADJ_PACKETS */
2033 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
2035 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
2037 zlog_debug ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %ld",
2038 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
2039 /* FIXME: use %z when we stop supporting old compilers. */
2040 (unsigned long) STREAM_SIZE (circuit
->snd_stream
));
2044 zlog_debug ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld",
2045 circuit
->area
->area_tag
, circuit
->interface
->name
,
2046 /* FIXME: use %z when we stop supporting old compilers. */
2047 (unsigned long) STREAM_SIZE (circuit
->snd_stream
));
2055 send_lan_hello (struct isis_circuit
*circuit
, int level
)
2057 return send_hello (circuit
, level
);
2061 send_lan_l1_hello (struct thread
*thread
)
2063 struct isis_circuit
*circuit
;
2066 circuit
= THREAD_ARG (thread
);
2068 circuit
->u
.bc
.t_send_lan_hello
[0] = NULL
;
2070 if (circuit
->u
.bc
.run_dr_elect
[0])
2071 retval
= isis_dr_elect (circuit
, 1);
2073 retval
= send_lan_hello (circuit
, 1);
2075 /* set next timer thread */
2076 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_send_lan_hello
[0],
2077 send_lan_l1_hello
, circuit
,
2078 isis_jitter (circuit
->hello_interval
[0], IIH_JITTER
));
2084 send_lan_l2_hello (struct thread
*thread
)
2086 struct isis_circuit
*circuit
;
2089 circuit
= THREAD_ARG (thread
);
2091 circuit
->u
.bc
.t_send_lan_hello
[1] = NULL
;
2093 if (circuit
->u
.bc
.run_dr_elect
[1])
2094 retval
= isis_dr_elect (circuit
, 2);
2096 retval
= send_lan_hello (circuit
, 2);
2098 /* set next timer thread */
2099 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_send_lan_hello
[1],
2100 send_lan_l2_hello
, circuit
,
2101 isis_jitter (circuit
->hello_interval
[1], IIH_JITTER
));
2107 send_p2p_hello (struct thread
*thread
)
2109 struct isis_circuit
*circuit
;
2111 circuit
= THREAD_ARG (thread
);
2113 circuit
->u
.p2p
.t_send_p2p_hello
= NULL
;
2115 send_hello (circuit
, 1);
2117 /* set next timer thread */
2118 THREAD_TIMER_ON (master
, circuit
->u
.p2p
.t_send_p2p_hello
, send_p2p_hello
,
2119 circuit
, isis_jitter (circuit
->hello_interval
[1],
2126 build_csnp (int level
, u_char
* start
, u_char
* stop
, struct list
*lsps
,
2127 struct isis_circuit
*circuit
)
2129 struct isis_fixed_hdr fixed_hdr
;
2130 struct isis_passwd
*passwd
;
2131 int retval
= ISIS_OK
;
2136 fill_fixed_hdr_andstream (&fixed_hdr
, L1_COMPLETE_SEQ_NUM
,
2137 circuit
->snd_stream
);
2139 fill_fixed_hdr_andstream (&fixed_hdr
, L2_COMPLETE_SEQ_NUM
,
2140 circuit
->snd_stream
);
2143 * Fill Level 1 or 2 Complete Sequence Numbers header
2146 lenp
= stream_get_endp (circuit
->snd_stream
);
2147 stream_putw (circuit
->snd_stream
, 0); /* PDU length - when we know it */
2148 /* no need to send the source here, it is always us if we csnp */
2149 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2150 /* with zero circuit id - ref 9.10, 9.11 */
2151 stream_putc (circuit
->snd_stream
, 0x00);
2153 stream_put (circuit
->snd_stream
, start
, ISIS_SYS_ID_LEN
+ 2);
2154 stream_put (circuit
->snd_stream
, stop
, ISIS_SYS_ID_LEN
+ 2);
2160 passwd
= &circuit
->area
->area_passwd
;
2162 passwd
= &circuit
->area
->domain_passwd
;
2164 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
))
2166 retval
= tlv_add_authinfo (passwd
->type
, passwd
->len
,
2167 passwd
->passwd
, circuit
->snd_stream
);
2169 if (!retval
&& lsps
)
2171 retval
= tlv_add_lsp_entries (lsps
, circuit
->snd_stream
);
2173 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
2174 assert (length
>= ISIS_CSNP_HDRLEN
);
2175 /* Update PU length */
2176 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2182 * FIXME: support multiple CSNPs
2186 send_csnp (struct isis_circuit
*circuit
, int level
)
2188 int retval
= ISIS_OK
;
2189 u_char start
[ISIS_SYS_ID_LEN
+ 2];
2190 u_char stop
[ISIS_SYS_ID_LEN
+ 2];
2191 struct list
*list
= NULL
;
2192 struct listnode
*node
;
2193 struct isis_lsp
*lsp
;
2195 memset (start
, 0x00, ISIS_SYS_ID_LEN
+ 2);
2196 memset (stop
, 0xff, ISIS_SYS_ID_LEN
+ 2);
2198 if (circuit
->area
->lspdb
[level
- 1] &&
2199 dict_count (circuit
->area
->lspdb
[level
- 1]) > 0)
2202 lsp_build_list (start
, stop
, list
, circuit
->area
->lspdb
[level
- 1]);
2204 if (circuit
->snd_stream
== NULL
)
2205 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
2207 stream_reset (circuit
->snd_stream
);
2209 retval
= build_csnp (level
, start
, stop
, list
, circuit
);
2211 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2213 zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld",
2214 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
2215 /* FIXME: use %z when we stop supporting old compilers. */
2216 (unsigned long) STREAM_SIZE (circuit
->snd_stream
));
2217 for (ALL_LIST_ELEMENTS_RO (list
, node
, lsp
))
2219 zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x,"
2220 " cksum 0x%04x, lifetime %us",
2221 circuit
->area
->area_tag
,
2222 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2223 ntohl (lsp
->lsp_header
->seq_num
),
2224 ntohs (lsp
->lsp_header
->checksum
),
2225 ntohs (lsp
->lsp_header
->rem_lifetime
));
2231 if (retval
== ISIS_OK
)
2232 retval
= circuit
->tx (circuit
, level
);
2238 send_l1_csnp (struct thread
*thread
)
2240 struct isis_circuit
*circuit
;
2241 int retval
= ISIS_OK
;
2243 circuit
= THREAD_ARG (thread
);
2246 circuit
->t_send_csnp
[0] = NULL
;
2248 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
&& circuit
->u
.bc
.is_dr
[0])
2250 send_csnp (circuit
, 1);
2252 /* set next timer thread */
2253 THREAD_TIMER_ON (master
, circuit
->t_send_csnp
[0], send_l1_csnp
, circuit
,
2254 isis_jitter (circuit
->csnp_interval
[0], CSNP_JITTER
));
2260 send_l2_csnp (struct thread
*thread
)
2262 struct isis_circuit
*circuit
;
2263 int retval
= ISIS_OK
;
2265 circuit
= THREAD_ARG (thread
);
2268 circuit
->t_send_csnp
[1] = NULL
;
2270 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
&& circuit
->u
.bc
.is_dr
[1])
2272 send_csnp (circuit
, 2);
2274 /* set next timer thread */
2275 THREAD_TIMER_ON (master
, circuit
->t_send_csnp
[1], send_l2_csnp
, circuit
,
2276 isis_jitter (circuit
->csnp_interval
[1], CSNP_JITTER
));
2282 build_psnp (int level
, struct isis_circuit
*circuit
, struct list
*lsps
)
2284 struct isis_fixed_hdr fixed_hdr
;
2288 struct isis_lsp
*lsp
;
2289 struct isis_passwd
*passwd
;
2290 struct listnode
*node
;
2293 fill_fixed_hdr_andstream (&fixed_hdr
, L1_PARTIAL_SEQ_NUM
,
2294 circuit
->snd_stream
);
2296 fill_fixed_hdr_andstream (&fixed_hdr
, L2_PARTIAL_SEQ_NUM
,
2297 circuit
->snd_stream
);
2300 * Fill Level 1 or 2 Partial Sequence Numbers header
2302 lenp
= stream_get_endp (circuit
->snd_stream
);
2303 stream_putw (circuit
->snd_stream
, 0); /* PDU length - when we know it */
2304 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2305 stream_putc (circuit
->snd_stream
, circuit
->idx
);
2312 passwd
= &circuit
->area
->area_passwd
;
2314 passwd
= &circuit
->area
->domain_passwd
;
2316 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
))
2318 retval
= tlv_add_authinfo (passwd
->type
, passwd
->len
,
2319 passwd
->passwd
, circuit
->snd_stream
);
2321 if (!retval
&& lsps
)
2323 retval
= tlv_add_lsp_entries (lsps
, circuit
->snd_stream
);
2326 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2328 for (ALL_LIST_ELEMENTS_RO (lsps
, node
, lsp
))
2330 zlog_debug ("ISIS-Snp (%s): PSNP entry %s, seq 0x%08x,"
2331 " cksum 0x%04x, lifetime %us",
2332 circuit
->area
->area_tag
,
2333 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2334 ntohl (lsp
->lsp_header
->seq_num
),
2335 ntohs (lsp
->lsp_header
->checksum
),
2336 ntohs (lsp
->lsp_header
->rem_lifetime
));
2340 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
2341 assert (length
>= ISIS_PSNP_HDRLEN
);
2342 /* Update PDU length */
2343 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2349 * 7.3.15.4 action on expiration of partial SNP interval
2353 send_psnp (int level
, struct isis_circuit
*circuit
)
2355 int retval
= ISIS_OK
;
2356 struct isis_lsp
*lsp
;
2357 struct list
*list
= NULL
;
2358 struct listnode
*node
;
2360 if ((circuit
->circ_type
== CIRCUIT_T_BROADCAST
&&
2361 !circuit
->u
.bc
.is_dr
[level
- 1]) ||
2362 circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
2365 if (circuit
->area
->lspdb
[level
- 1] &&
2366 dict_count (circuit
->area
->lspdb
[level
- 1]) > 0)
2369 lsp_build_list_ssn (circuit
, list
, circuit
->area
->lspdb
[level
- 1]);
2371 if (listcount (list
) > 0)
2373 if (circuit
->snd_stream
== NULL
)
2374 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
2376 stream_reset (circuit
->snd_stream
);
2379 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2380 zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld",
2381 circuit
->area
->area_tag
, level
,
2382 circuit
->interface
->name
,
2383 /* FIXME: use %z when we stop supporting old
2385 (unsigned long) STREAM_SIZE (circuit
->snd_stream
));
2387 retval
= build_psnp (level
, circuit
, list
);
2388 if (retval
== ISIS_OK
)
2389 retval
= circuit
->tx (circuit
, level
);
2391 if (retval
== ISIS_OK
)
2394 * sending succeeded, we can clear SSN flags of this circuit
2395 * for the LSPs in list
2397 for (ALL_LIST_ELEMENTS_RO (list
, node
, lsp
))
2398 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
2409 send_l1_psnp (struct thread
*thread
)
2412 struct isis_circuit
*circuit
;
2413 int retval
= ISIS_OK
;
2415 circuit
= THREAD_ARG (thread
);
2418 circuit
->t_send_psnp
[0] = NULL
;
2420 send_psnp (1, circuit
);
2421 /* set next timer thread */
2422 THREAD_TIMER_ON (master
, circuit
->t_send_psnp
[0], send_l1_psnp
, circuit
,
2423 isis_jitter (circuit
->psnp_interval
[0], PSNP_JITTER
));
2429 * 7.3.15.4 action on expiration of partial SNP interval
2433 send_l2_psnp (struct thread
*thread
)
2435 struct isis_circuit
*circuit
;
2436 int retval
= ISIS_OK
;
2438 circuit
= THREAD_ARG (thread
);
2441 circuit
->t_send_psnp
[1] = NULL
;
2443 send_psnp (2, circuit
);
2445 /* set next timer thread */
2446 THREAD_TIMER_ON (master
, circuit
->t_send_psnp
[1], send_l2_psnp
, circuit
,
2447 isis_jitter (circuit
->psnp_interval
[1], PSNP_JITTER
));
2453 * ISO 10589 - 7.3.14.3
2456 send_lsp (struct thread
*thread
)
2458 struct isis_circuit
*circuit
;
2459 struct isis_lsp
*lsp
;
2460 struct listnode
*node
;
2463 circuit
= THREAD_ARG (thread
);
2466 if (circuit
->state
== C_STATE_UP
)
2468 lsp
= listgetdata ((node
= listhead (circuit
->lsp_queue
)));
2471 * Do not send if levels do not match
2473 if (!(lsp
->level
& circuit
->circuit_is_type
))
2477 * Do not send if we do not have adjacencies in state up on the circuit
2479 if (circuit
->upadjcount
[lsp
->level
- 1] == 0)
2481 /* only send if it needs sending */
2482 if ((time (NULL
) - lsp
->last_sent
) >=
2483 circuit
->area
->lsp_gen_interval
[lsp
->level
- 1])
2486 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
2489 ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
2490 " lifetime %us on %s", circuit
->area
->area_tag
, lsp
->level
,
2491 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2492 ntohl (lsp
->lsp_header
->seq_num
),
2493 ntohs (lsp
->lsp_header
->checksum
),
2494 ntohs (lsp
->lsp_header
->rem_lifetime
),
2495 circuit
->interface
->name
);
2497 /* copy our lsp to the send buffer */
2498 stream_copy (circuit
->snd_stream
, lsp
->pdu
);
2500 retval
= circuit
->tx (circuit
, lsp
->level
);
2503 * If the sending succeeded, we can del the lsp from circuits
2506 if (retval
== ISIS_OK
)
2508 list_delete_node (circuit
->lsp_queue
, node
);
2511 * On broadcast circuits also the SRMflag can be cleared
2513 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
2514 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
2516 if (flags_any_set (lsp
->SRMflags
) == 0)
2519 * need to remember when we were last sent
2521 lsp
->last_sent
= time (NULL
);
2526 zlog_debug ("sending of level %d link state failed", lsp
->level
);
2531 /* my belief is that if it wasn't his time, the lsp can be removed
2535 list_delete_node (circuit
->lsp_queue
, node
);
2539 * If there are still LSPs send next one after lsp-interval (33 msecs)
2541 if (listcount (circuit
->lsp_queue
) > 0)
2542 thread_add_timer (master
, send_lsp
, circuit
, 1);
2550 ack_lsp (struct isis_link_state_hdr
*hdr
, struct isis_circuit
*circuit
,
2556 struct isis_fixed_hdr fixed_hdr
;
2558 if (!circuit
->snd_stream
)
2559 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
2561 stream_reset (circuit
->snd_stream
);
2563 // fill_llc_hdr (stream);
2565 fill_fixed_hdr_andstream (&fixed_hdr
, L1_PARTIAL_SEQ_NUM
,
2566 circuit
->snd_stream
);
2568 fill_fixed_hdr_andstream (&fixed_hdr
, L2_PARTIAL_SEQ_NUM
,
2569 circuit
->snd_stream
);
2572 lenp
= stream_get_endp (circuit
->snd_stream
);
2573 stream_putw (circuit
->snd_stream
, 0); /* PDU length */
2574 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2575 stream_putc (circuit
->snd_stream
, circuit
->idx
);
2576 stream_putc (circuit
->snd_stream
, 9); /* code */
2577 stream_putc (circuit
->snd_stream
, 16); /* len */
2579 stream_putw (circuit
->snd_stream
, ntohs (hdr
->rem_lifetime
));
2580 stream_put (circuit
->snd_stream
, hdr
->lsp_id
, ISIS_SYS_ID_LEN
+ 2);
2581 stream_putl (circuit
->snd_stream
, ntohl (hdr
->seq_num
));
2582 stream_putw (circuit
->snd_stream
, ntohs (hdr
->checksum
));
2584 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
2585 /* Update PDU length */
2586 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2588 retval
= circuit
->tx (circuit
, level
);