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.
36 #include "isisd/dict.h"
37 #include "isisd/include-netbsd/iso.h"
38 #include "isisd/isis_constants.h"
39 #include "isisd/isis_common.h"
40 #include "isisd/isis_adjacency.h"
41 #include "isisd/isis_circuit.h"
42 #include "isisd/isis_network.h"
43 #include "isisd/isis_misc.h"
44 #include "isisd/isis_dr.h"
45 #include "isisd/isis_flags.h"
46 #include "isisd/isis_tlv.h"
47 #include "isisd/isisd.h"
48 #include "isisd/isis_dynhn.h"
49 #include "isisd/isis_lsp.h"
50 #include "isisd/isis_pdu.h"
51 #include "isisd/iso_checksum.h"
52 #include "isisd/isis_csm.h"
53 #include "isisd/isis_events.h"
55 extern struct thread_master
*master
;
56 extern struct isis
*isis
;
58 #define ISIS_MINIMUM_FIXED_HDR_LEN 15
59 #define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */
65 /* Utility mask array. */
66 static u_char maskbit
[] = {
67 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
75 * Compares two sets of area addresses
78 area_match (struct list
*left
, struct list
*right
)
80 struct area_addr
*addr1
, *addr2
;
81 struct listnode
*node1
, *node2
;
83 for (ALL_LIST_ELEMENTS_RO (left
, node1
, addr1
))
85 for (ALL_LIST_ELEMENTS_RO (right
, node2
, addr2
))
87 if (addr1
->addr_len
== addr2
->addr_len
&&
88 !memcmp (addr1
->area_addr
, addr2
->area_addr
, (int) addr1
->addr_len
))
93 return 0; /* mismatch */
97 * Check if ip2 is in the ip1's network (function like Prefix.h:prefix_match() )
98 * param ip1 the IS interface ip address structure
99 * param ip2 the IIH's ip address
100 * return 0 the IIH's IP is not in the IS's subnetwork
101 * 1 the IIH's IP is in the IS's subnetwork
104 ip_same_subnet (struct prefix_ipv4
*ip1
, struct in_addr
*ip2
)
106 u_char
*addr1
, *addr2
;
107 int shift
, offset
, offsetloop
;
110 addr1
= (u_char
*) & ip1
->prefix
.s_addr
;
111 addr2
= (u_char
*) & ip2
->s_addr
;
112 len
= ip1
->prefixlen
;
115 offsetloop
= offset
= len
/ PNBBY
;
118 if (addr1
[offsetloop
] != addr2
[offsetloop
])
122 if (maskbit
[shift
] & (addr1
[offset
] ^ addr2
[offset
]))
125 return 1; /* match */
129 * Compares two set of ip addresses
130 * param left the local interface's ip addresses
131 * param right the iih interface's ip address
136 ip_match (struct list
*left
, struct list
*right
)
138 struct prefix_ipv4
*ip1
;
140 struct listnode
*node1
, *node2
;
142 if ((left
== NULL
) || (right
== NULL
))
145 for (ALL_LIST_ELEMENTS_RO (left
, node1
, ip1
))
147 for (ALL_LIST_ELEMENTS_RO (right
, node2
, ip2
))
149 if (ip_same_subnet (ip1
, ip2
))
151 return 1; /* match */
160 * Checks whether we should accept a PDU of given level
163 accept_level (int level
, int circuit_t
)
165 int retval
= ((circuit_t
& level
) == level
); /* simple approach */
171 authentication_check (struct isis_passwd
*one
, struct isis_passwd
*theother
)
173 if (one
->type
!= theother
->type
)
175 zlog_warn ("Unsupported authentication type %d", theother
->type
);
176 return 1; /* Auth fail (different authentication types) */
180 case ISIS_PASSWD_TYPE_CLEARTXT
:
181 if (one
->len
!= theother
->len
)
182 return 1; /* Auth fail () - passwd len mismatch */
183 return memcmp (one
->passwd
, theother
->passwd
, one
->len
);
186 zlog_warn ("Unsupported authentication type");
189 return 0; /* Auth pass */
193 * Processing helper functions
196 tlvs_to_adj_nlpids (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
199 struct nlpids
*tlv_nlpids
;
204 tlv_nlpids
= tlvs
->nlpids
;
206 adj
->nlpids
.count
= tlv_nlpids
->count
;
208 for (i
= 0; i
< tlv_nlpids
->count
; i
++)
210 adj
->nlpids
.nlpids
[i
] = tlv_nlpids
->nlpids
[i
];
216 del_ip_addr (void *val
)
218 XFREE (MTYPE_ISIS_TMP
, val
);
222 tlvs_to_adj_ipv4_addrs (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
224 struct listnode
*node
;
225 struct in_addr
*ipv4_addr
, *malloced
;
229 adj
->ipv4_addrs
->del
= del_ip_addr
;
230 list_delete (adj
->ipv4_addrs
);
232 adj
->ipv4_addrs
= list_new ();
233 if (tlvs
->ipv4_addrs
)
235 for (ALL_LIST_ELEMENTS_RO (tlvs
->ipv4_addrs
, node
, ipv4_addr
))
237 malloced
= XMALLOC (MTYPE_ISIS_TMP
, sizeof (struct in_addr
));
238 memcpy (malloced
, ipv4_addr
, sizeof (struct in_addr
));
239 listnode_add (adj
->ipv4_addrs
, malloced
);
246 tlvs_to_adj_ipv6_addrs (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
248 struct listnode
*node
;
249 struct in6_addr
*ipv6_addr
, *malloced
;
253 adj
->ipv6_addrs
->del
= del_ip_addr
;
254 list_delete (adj
->ipv6_addrs
);
256 adj
->ipv6_addrs
= list_new ();
257 if (tlvs
->ipv6_addrs
)
259 for (ALL_LIST_ELEMENTS_RO (tlvs
->ipv6_addrs
, node
, ipv6_addr
))
261 malloced
= XMALLOC (MTYPE_ISIS_TMP
, sizeof (struct in6_addr
));
262 memcpy (malloced
, ipv6_addr
, sizeof (struct in6_addr
));
263 listnode_add (adj
->ipv6_addrs
, malloced
);
268 #endif /* HAVE_IPV6 */
277 * Section 8.2.5 - Receiving point-to-point IIH PDUs
281 process_p2p_hello (struct isis_circuit
*circuit
)
283 int retval
= ISIS_OK
;
284 struct isis_p2p_hello_hdr
*hdr
;
285 struct isis_adjacency
*adj
;
286 u_int32_t expected
= 0, found
;
289 if ((stream_get_endp (circuit
->rcv_stream
) -
290 stream_get_getp (circuit
->rcv_stream
)) < ISIS_P2PHELLO_HDRLEN
)
292 zlog_warn ("Packet too short");
296 /* 8.2.5.1 PDU acceptance tests */
298 /* 8.2.5.1 a) external domain untrue */
299 /* FIXME: not useful at all? */
301 /* 8.2.5.1 b) ID Length mismatch */
302 /* checked at the handle_pdu */
304 /* 8.2.5.2 IIH PDU Processing */
306 /* 8.2.5.2 a) 1) Maximum Area Addresses */
307 /* Already checked, and can also be ommited */
312 hdr
= (struct isis_p2p_hello_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
313 circuit
->rcv_stream
->getp
+= ISIS_P2PHELLO_HDRLEN
;
315 /* hdr.circuit_t = stream_getc (stream);
316 stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN);
317 hdr.hold_time = stream_getw (stream);
318 hdr.pdu_len = stream_getw (stream);
319 hdr.local_id = stream_getc (stream); */
322 * My interpertation of the ISO, if no adj exists we will create one for
326 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
328 zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
329 " cir id %02d, length %d",
330 circuit
->area
->area_tag
, circuit
->interface
->name
,
331 circuit_t2string (circuit
->circuit_is_type
),
332 circuit
->circuit_id
, ntohs (hdr
->pdu_len
));
335 adj
= circuit
->u
.p2p
.neighbor
;
338 adj
= isis_new_adj (hdr
->source_id
, NULL
, 0, circuit
);
341 circuit
->u
.p2p
.neighbor
= adj
;
342 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
343 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
346 /* 8.2.6 Monitoring point-to-point adjacencies */
347 adj
->hold_time
= ntohs (hdr
->hold_time
);
348 adj
->last_upd
= time (NULL
);
351 * Lets get the TLVS now
353 expected
|= TLVFLAG_AREA_ADDRS
;
354 expected
|= TLVFLAG_AUTH_INFO
;
355 expected
|= TLVFLAG_NLPID
;
356 expected
|= TLVFLAG_IPV4_ADDR
;
357 expected
|= TLVFLAG_IPV6_ADDR
;
359 retval
= parse_tlvs (circuit
->area
->area_tag
,
360 STREAM_PNT (circuit
->rcv_stream
),
361 ntohs (hdr
->pdu_len
) - ISIS_P2PHELLO_HDRLEN
362 - ISIS_FIXED_HDR_LEN
, &expected
, &found
, &tlvs
);
364 if (retval
> ISIS_WARNING
)
370 /* 8.2.5.1 c) Authentication */
371 if (circuit
->passwd
.type
)
373 if (!(found
& TLVFLAG_AUTH_INFO
) ||
374 authentication_check (&circuit
->passwd
, &tlvs
.auth_info
))
376 isis_event_auth_failure (circuit
->area
->area_tag
,
377 "P2P hello authentication failure",
383 /* we do this now because the adj may not survive till the end... */
385 /* we need to copy addresses to the adj */
386 tlvs_to_adj_ipv4_addrs (&tlvs
, adj
);
389 tlvs_to_adj_ipv6_addrs (&tlvs
, adj
);
390 #endif /* HAVE_IPV6 */
392 /* lets take care of the expiry */
393 THREAD_TIMER_OFF (adj
->t_expire
);
394 THREAD_TIMER_ON (master
, adj
->t_expire
, isis_adj_expire
, adj
,
395 (long) adj
->hold_time
);
397 /* 8.2.5.2 a) a match was detected */
398 if (area_match (circuit
->area
->area_addrs
, tlvs
.area_addrs
))
400 /* 8.2.5.2 a) 2) If the system is L1 - table 5 */
401 if (circuit
->area
->is_type
== IS_LEVEL_1
)
403 switch (hdr
->circuit_t
)
406 case IS_LEVEL_1_AND_2
:
407 if (adj
->adj_state
!= ISIS_ADJ_UP
)
409 /* (4) adj state up */
410 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
411 /* (5) adj usage level 1 */
412 adj
->adj_usage
= ISIS_ADJ_LEVEL1
;
414 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
420 if (adj
->adj_state
!= ISIS_ADJ_UP
)
422 /* (7) reject - wrong system type event */
423 zlog_warn ("wrongSystemType");
424 return ISIS_WARNING
; /* Reject */
426 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
428 /* (6) down - wrong system */
429 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
435 /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */
436 if (circuit
->area
->is_type
== IS_LEVEL_1_AND_2
)
438 switch (hdr
->circuit_t
)
441 if (adj
->adj_state
!= ISIS_ADJ_UP
)
443 /* (6) adj state up */
444 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
445 /* (7) adj usage level 1 */
446 adj
->adj_usage
= ISIS_ADJ_LEVEL1
;
448 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
452 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
453 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
455 /* (8) down - wrong system */
456 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
460 if (adj
->adj_state
!= ISIS_ADJ_UP
)
462 /* (6) adj state up */
463 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
464 /* (9) adj usage level 2 */
465 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
467 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1
) ||
468 (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
))
470 /* (8) down - wrong system */
471 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
473 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
478 case IS_LEVEL_1_AND_2
:
479 if (adj
->adj_state
!= ISIS_ADJ_UP
)
481 /* (6) adj state up */
482 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
483 /* (10) adj usage level 1 */
484 adj
->adj_usage
= ISIS_ADJ_LEVEL1AND2
;
486 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1
) ||
487 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
489 /* (8) down - wrong system */
490 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
492 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
500 /* 8.2.5.2 a) 4) If the system is L2 - table 7 */
501 if (circuit
->area
->is_type
== IS_LEVEL_2
)
503 switch (hdr
->circuit_t
)
506 if (adj
->adj_state
!= ISIS_ADJ_UP
)
508 /* (5) reject - wrong system type event */
509 zlog_warn ("wrongSystemType");
510 return ISIS_WARNING
; /* Reject */
512 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
513 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
515 /* (6) down - wrong system */
516 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
519 case IS_LEVEL_1_AND_2
:
521 if (adj
->adj_state
!= ISIS_ADJ_UP
)
523 /* (7) adj state up */
524 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
525 /* (8) adj usage level 2 */
526 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
528 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
530 /* (6) down - wrong system */
531 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
533 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
541 /* 8.2.5.2 b) if no match was detected */
544 if (circuit
->area
->is_type
== IS_LEVEL_1
)
546 /* 8.2.5.2 b) 1) is_type L1 and adj is not up */
547 if (adj
->adj_state
!= ISIS_ADJ_UP
)
549 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch");
550 /* 8.2.5.2 b) 2)is_type L1 and adj is up */
554 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
555 "Down - Area Mismatch");
558 /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */
561 switch (hdr
->circuit_t
)
564 if (adj
->adj_state
!= ISIS_ADJ_UP
)
566 /* (6) reject - Area Mismatch event */
567 zlog_warn ("AreaMismatch");
568 return ISIS_WARNING
; /* Reject */
570 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
572 /* (7) down - area mismatch */
573 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch");
576 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
577 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
579 /* (7) down - wrong system */
580 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
583 case IS_LEVEL_1_AND_2
:
585 if (adj
->adj_state
!= ISIS_ADJ_UP
)
587 /* (8) adj state up */
588 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
589 /* (9) adj usage level 2 */
590 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
592 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
594 /* (7) down - wrong system */
595 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
597 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
599 if (hdr
->circuit_t
== IS_LEVEL_2
)
601 /* (7) down - wrong system */
602 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
607 /* (7) down - area mismatch */
608 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
612 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
620 /* 8.2.5.2 c) if the action was up - comparing circuit IDs */
621 /* FIXME - Missing parts */
623 /* some of my own understanding of the ISO, why the heck does
624 * it not say what should I change the system_type to...
626 switch (adj
->adj_usage
)
628 case ISIS_ADJ_LEVEL1
:
629 adj
->sys_type
= ISIS_SYSTYPE_L1_IS
;
631 case ISIS_ADJ_LEVEL2
:
632 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
634 case ISIS_ADJ_LEVEL1AND2
:
635 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
638 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
642 adj
->circuit_t
= hdr
->circuit_t
;
643 adj
->level
= hdr
->circuit_t
;
651 * Process IS-IS LAN Level 1/2 Hello PDU
654 process_lan_hello (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
656 int retval
= ISIS_OK
;
657 struct isis_lan_hello_hdr hdr
;
658 struct isis_adjacency
*adj
;
659 u_int32_t expected
= 0, found
;
662 struct listnode
*node
;
664 if ((stream_get_endp (circuit
->rcv_stream
) -
665 stream_get_getp (circuit
->rcv_stream
)) < ISIS_LANHELLO_HDRLEN
)
667 zlog_warn ("Packet too short");
671 if (circuit
->ext_domain
)
673 zlog_debug ("level %d LAN Hello received over circuit with "
674 "externalDomain = true", level
);
678 if (!accept_level (level
, circuit
->circuit_is_type
))
680 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
682 zlog_debug ("ISIS-Adj (%s): Interface level mismatch, %s",
683 circuit
->area
->area_tag
, circuit
->interface
->name
);
689 /* Cisco's debug message compatability */
690 if (!accept_level (level
, circuit
->area
->is_type
))
692 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
694 zlog_debug ("ISIS-Adj (%s): is type mismatch",
695 circuit
->area
->area_tag
);
703 hdr
.circuit_t
= stream_getc (circuit
->rcv_stream
);
704 stream_get (hdr
.source_id
, circuit
->rcv_stream
, ISIS_SYS_ID_LEN
);
705 hdr
.hold_time
= stream_getw (circuit
->rcv_stream
);
706 hdr
.pdu_len
= stream_getw (circuit
->rcv_stream
);
707 hdr
.prio
= stream_getc (circuit
->rcv_stream
);
708 stream_get (hdr
.lan_id
, circuit
->rcv_stream
, ISIS_SYS_ID_LEN
+ 1);
710 if (hdr
.circuit_t
!= IS_LEVEL_1
&& hdr
.circuit_t
!= IS_LEVEL_2
&&
711 hdr
.circuit_t
!= IS_LEVEL_1_AND_2
)
713 zlog_warn ("Level %d LAN Hello with Circuit Type %d", level
,
720 expected
|= TLVFLAG_AUTH_INFO
;
721 expected
|= TLVFLAG_AREA_ADDRS
;
722 expected
|= TLVFLAG_LAN_NEIGHS
;
723 expected
|= TLVFLAG_NLPID
;
724 expected
|= TLVFLAG_IPV4_ADDR
;
725 expected
|= TLVFLAG_IPV6_ADDR
;
727 retval
= parse_tlvs (circuit
->area
->area_tag
,
728 STREAM_PNT (circuit
->rcv_stream
),
729 hdr
.pdu_len
- ISIS_LANHELLO_HDRLEN
-
730 ISIS_FIXED_HDR_LEN
, &expected
, &found
, &tlvs
);
732 if (retval
> ISIS_WARNING
)
734 zlog_warn ("parse_tlvs() failed");
738 if (!(found
& TLVFLAG_AREA_ADDRS
))
740 zlog_warn ("No Area addresses TLV in Level %d LAN IS to IS hello",
742 retval
= ISIS_WARNING
;
746 if (circuit
->passwd
.type
)
748 if (!(found
& TLVFLAG_AUTH_INFO
) ||
749 authentication_check (&circuit
->passwd
, &tlvs
.auth_info
))
751 isis_event_auth_failure (circuit
->area
->area_tag
,
752 "LAN hello authentication failure",
754 retval
= ISIS_WARNING
;
760 * Accept the level 1 adjacency only if a match between local and
761 * remote area addresses is found
763 if (level
== 1 && !area_match (circuit
->area
->area_addrs
, tlvs
.area_addrs
))
765 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
767 zlog_debug ("ISIS-Adj (%s): Area mismatch, level %d IIH on %s",
768 circuit
->area
->area_tag
, level
,
769 circuit
->interface
->name
);
776 * it's own IIH PDU - discard silently
778 if (!memcmp (circuit
->u
.bc
.snpa
, ssnpa
, ETH_ALEN
))
780 zlog_debug ("ISIS-Adj (%s): it's own IIH PDU - discarded",
781 circuit
->area
->area_tag
);
788 * check if it's own interface ip match iih ip addrs
790 if (!(found
& TLVFLAG_IPV4_ADDR
)
791 || !ip_match (circuit
->ip_addrs
, tlvs
.ipv4_addrs
))
794 ("ISIS-Adj: No usable IP interface addresses in LAN IIH from %s\n",
795 circuit
->interface
->name
);
796 retval
= ISIS_WARNING
;
800 adj
= isis_adj_lookup (hdr
.source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
806 adj
= isis_new_adj (hdr
.source_id
, ssnpa
, level
, circuit
);
814 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
818 adj
->sys_type
= ISIS_SYSTYPE_L1_IS
;
822 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
824 list_delete_all_node (circuit
->u
.bc
.lan_neighs
[level
- 1]);
825 isis_adj_build_neigh_list (circuit
->u
.bc
.adjdb
[level
- 1],
826 circuit
->u
.bc
.lan_neighs
[level
- 1]);
829 if(adj
->dis_record
[level
-1].dis
==ISIS_IS_DIS
)
833 if (memcmp (circuit
->u
.bc
.l1_desig_is
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1))
835 thread_add_event (master
, isis_event_dis_status_change
, circuit
, 0);
836 memcpy (&circuit
->u
.bc
.l1_desig_is
, hdr
.lan_id
,
837 ISIS_SYS_ID_LEN
+ 1);
841 if (memcmp (circuit
->u
.bc
.l2_desig_is
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1))
843 thread_add_event (master
, isis_event_dis_status_change
, circuit
, 0);
844 memcpy (&circuit
->u
.bc
.l2_desig_is
, hdr
.lan_id
,
845 ISIS_SYS_ID_LEN
+ 1);
850 adj
->hold_time
= hdr
.hold_time
;
851 adj
->last_upd
= time (NULL
);
852 adj
->prio
[level
- 1] = hdr
.prio
;
854 memcpy (adj
->lanid
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1);
856 /* which protocol are spoken ??? */
857 if (found
& TLVFLAG_NLPID
)
858 tlvs_to_adj_nlpids (&tlvs
, adj
);
860 /* we need to copy addresses to the adj */
861 if (found
& TLVFLAG_IPV4_ADDR
)
862 tlvs_to_adj_ipv4_addrs (&tlvs
, adj
);
865 if (found
& TLVFLAG_IPV6_ADDR
)
866 tlvs_to_adj_ipv6_addrs (&tlvs
, adj
);
867 #endif /* HAVE_IPV6 */
869 adj
->circuit_t
= hdr
.circuit_t
;
871 /* lets take care of the expiry */
872 THREAD_TIMER_OFF (adj
->t_expire
);
873 THREAD_TIMER_ON (master
, adj
->t_expire
, isis_adj_expire
, adj
,
874 (long) adj
->hold_time
);
877 * If the snpa for this circuit is found from LAN Neighbours TLV
878 * we have two-way communication -> adjacency can be put to state "up"
881 if (found
& TLVFLAG_LAN_NEIGHS
)
883 if (adj
->adj_state
!= ISIS_ADJ_UP
)
885 for (ALL_LIST_ELEMENTS_RO (tlvs
.lan_neighs
, node
, snpa
))
886 if (!memcmp (snpa
, circuit
->u
.bc
.snpa
, ETH_ALEN
))
888 isis_adj_state_change (adj
, ISIS_ADJ_UP
,
889 "own SNPA found in LAN Neighbours TLV");
895 /* DEBUG_ADJ_PACKETS */
896 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
898 /* FIXME: is this place right? fix missing info */
899 zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "
900 "cirID %u, length %ld",
901 circuit
->area
->area_tag
,
902 level
, snpa_print (ssnpa
), circuit
->interface
->name
,
903 circuit_t2string (circuit
->circuit_is_type
),
905 /* FIXME: use %z when we stop supporting old compilers. */
906 (unsigned long) 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 /* FIXME: use %z when we stop supporting old compilers. */
951 (unsigned long) stream_get_endp (circuit
->rcv_stream
),
952 circuit
->interface
->name
);
955 assert (ntohs (hdr
->pdu_len
) > ISIS_LSP_HDR_LEN
);
957 /* Checksum sanity check - FIXME: move to correct place */
958 /* 12 = sysid+pdu+remtime */
959 if (iso_csum_verify (STREAM_PNT (circuit
->rcv_stream
) + 4,
960 ntohs (hdr
->pdu_len
) - 12, &hdr
->checksum
))
962 zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
963 circuit
->area
->area_tag
,
964 rawlspid_print (hdr
->lsp_id
), ntohs (hdr
->checksum
));
969 /* 7.3.15.1 a) 1 - external domain circuit will discard lsps */
970 if (circuit
->ext_domain
)
973 ("ISIS-Upd (%s): LSP %s received at level %d over circuit with "
974 "externalDomain = true", circuit
->area
->area_tag
,
975 rawlspid_print (hdr
->lsp_id
), level
);
980 /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
981 if (!accept_level (level
, circuit
->circuit_is_type
))
983 zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of"
985 circuit
->area
->area_tag
,
986 rawlspid_print (hdr
->lsp_id
),
987 level
, circuit_t2string (circuit
->circuit_is_type
));
992 /* 7.3.15.1 a) 4 - need to make sure IDLength matches */
994 /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */
996 /* 7.3.15.1 a) 7 - password check */
997 (level
== ISIS_LEVEL1
) ? (passwd
= &circuit
->area
->area_passwd
) :
998 (passwd
= &circuit
->area
->domain_passwd
);
1001 if (isis_lsp_authinfo_check (circuit
->rcv_stream
, circuit
->area
,
1002 ntohs (hdr
->pdu_len
), passwd
))
1004 isis_event_auth_failure (circuit
->area
->area_tag
,
1005 "LSP authentication failure", hdr
->lsp_id
);
1006 return ISIS_WARNING
;
1009 /* Find the LSP in our database and compare it to this Link State header */
1010 lsp
= lsp_search (hdr
->lsp_id
, circuit
->area
->lspdb
[level
- 1]);
1012 comp
= lsp_compare (circuit
->area
->area_tag
, lsp
, hdr
->seq_num
,
1013 hdr
->checksum
, hdr
->rem_lifetime
);
1014 if (lsp
&& (lsp
->own_lsp
1015 #ifdef TOPOLOGY_GENERATE
1016 || lsp
->from_topology
1017 #endif /* TOPOLOGY_GENERATE */
1021 /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level */
1022 /* for broadcast circuits, snpa should be compared */
1023 /* FIXME : Point To Point */
1025 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1027 adj
= isis_adj_lookup_snpa (ssnpa
, circuit
->u
.bc
.adjdb
[level
- 1]);
1030 zlog_debug ("(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, "
1031 "lifetime %us on %s",
1032 circuit
->area
->area_tag
,
1033 rawlspid_print (hdr
->lsp_id
),
1034 ntohl (hdr
->seq_num
),
1035 ntohs (hdr
->checksum
),
1036 ntohs (hdr
->rem_lifetime
), circuit
->interface
->name
);
1037 return ISIS_WARNING
; /* Silently discard */
1041 /* for non broadcast, we just need to find same level adj */
1044 /* If no adj, or no sharing of level */
1045 if (!circuit
->u
.p2p
.neighbor
)
1047 return ISIS_OK
; /* Silently discard */
1051 if (((level
== 1) &&
1052 (circuit
->u
.p2p
.neighbor
->adj_usage
== ISIS_ADJ_LEVEL2
)) ||
1054 (circuit
->u
.p2p
.neighbor
->adj_usage
== ISIS_ADJ_LEVEL1
)))
1055 return ISIS_WARNING
; /* Silently discard */
1059 /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */
1061 /* 7.3.15.1 a) 8 - Passwords for level 2 - not implemented */
1063 /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented FIXME: do it */
1065 /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */
1066 if (hdr
->rem_lifetime
== 0)
1070 /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't save */
1071 /* only needed on explicit update, eg - p2p */
1072 if (circuit
->circ_type
== CIRCUIT_T_P2P
)
1073 ack_lsp (hdr
, circuit
, level
);
1074 return retval
; /* FIXME: do we need a purge? */
1078 if (memcmp (hdr
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
1080 /* LSP by some other system -> do 7.3.16.4 b) */
1081 /* 7.3.16.4 b) 1) */
1082 if (comp
== LSP_NEWER
)
1084 lsp_update (lsp
, hdr
, circuit
->rcv_stream
, circuit
->area
,
1087 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1089 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1091 ISIS_FLAGS_CLEAR_ALL (lsp
->SSNflags
); /* FIXME: OTHER than c */
1093 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1094 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1096 } /* 7.3.16.4 b) 2) */
1097 else if (comp
== LSP_EQUAL
)
1100 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1102 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1103 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1104 } /* 7.3.16.4 b) 3) */
1107 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1108 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1113 /* our own LSP -> 7.3.16.4 c) */
1114 if (LSP_PSEUDO_ID (lsp
->lsp_header
->lsp_id
) !=
1116 || (LSP_PSEUDO_ID (lsp
->lsp_header
->lsp_id
) ==
1118 && circuit
->u
.bc
.is_dr
[level
- 1] == 1))
1120 lsp
->lsp_header
->seq_num
= htonl (ntohl (hdr
->seq_num
) + 1);
1121 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1122 zlog_debug ("LSP LEN: %d",
1123 ntohs (lsp
->lsp_header
->pdu_len
));
1124 iso_csum_create (STREAM_DATA (lsp
->pdu
) + 12,
1125 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
1126 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1127 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1128 zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new "
1129 "seq 0x%08x", circuit
->area
->area_tag
,
1130 rawlspid_print (hdr
->lsp_id
),
1131 ntohl (lsp
->lsp_header
->seq_num
));
1132 lsp
->lsp_header
->rem_lifetime
=
1134 (circuit
->area
->max_lsp_lifetime
[level
- 1],
1139 /* Got purge for own pseudo-lsp, and we are not DR */
1140 lsp_purge_dr (lsp
->lsp_header
->lsp_id
, circuit
, level
);
1146 /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a
1148 if (memcmp (hdr
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
) == 0)
1152 /* 7.3.16.4: initiate a purge */
1153 lsp_purge_non_exist (hdr
, circuit
->area
);
1156 /* 7.3.15.1 d) - If this is our own lsp and we have it */
1158 /* In 7.3.16.1, If an Intermediate system R somewhere in the domain
1159 * has information that the current sequence number for source S is
1160 * "greater" than that held by S, ... */
1162 else if (ntohl (hdr
->seq_num
) > ntohl (lsp
->lsp_header
->seq_num
))
1165 lsp
->lsp_header
->seq_num
= htonl (ntohl (hdr
->seq_num
) + 1);
1167 iso_csum_create (STREAM_DATA (lsp
->pdu
) + 12,
1168 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
1170 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1171 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1172 zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq "
1173 "0x%08x", circuit
->area
->area_tag
,
1174 rawlspid_print (hdr
->lsp_id
),
1175 ntohl (lsp
->lsp_header
->seq_num
));
1176 lsp
->lsp_header
->rem_lifetime
=
1178 (circuit
->area
->max_lsp_lifetime
[level
- 1],
1184 /* 7.3.15.1 e) - This lsp originated on another system */
1186 /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */
1187 if ((!lsp
|| comp
== LSP_NEWER
))
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 */
1196 lsp_search_and_destroy (hdr
->lsp_id
,
1197 circuit
->area
->lspdb
[level
- 1]);
1198 /* exists, so we overwrite */
1199 #ifdef EXTREME_DEBUG
1200 zlog_debug ("level %d number is - %ld", level
,
1201 circuit
->area
->lspdb
[level
- 1]->dict_nodecount
);
1202 #endif /* EXTREME DEBUG */
1205 * If this lsp is a frag, need to see if we have zero lsp present
1207 if (LSP_FRAGMENT (hdr
->lsp_id
) != 0)
1209 memcpy (lspid
, hdr
->lsp_id
, ISIS_SYS_ID_LEN
+ 1);
1210 LSP_FRAGMENT (lspid
) = 0;
1211 lsp0
= lsp_search (lspid
, circuit
->area
->lspdb
[level
- 1]);
1214 zlog_debug ("Got lsp frag, while zero lsp not database");
1219 lsp_new_from_stream_ptr (circuit
->rcv_stream
,
1220 ntohs (hdr
->pdu_len
), lsp0
,
1224 lsp_insert (lsp
, circuit
->area
->lspdb
[level
- 1]);
1226 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1228 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1231 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1232 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1235 /* 7.3.15.1 e) 2) LSP equal to the one in db */
1236 else if (comp
== LSP_EQUAL
)
1238 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1239 lsp_update (lsp
, hdr
, circuit
->rcv_stream
, circuit
->area
, level
);
1240 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1242 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1245 /* 7.3.15.1 e) 3) LSP older than the one in db */
1248 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1249 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1258 * Process Sequence Numbers
1260 * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU
1264 process_snp (int snp_type
, int level
, struct isis_circuit
*circuit
,
1267 int retval
= ISIS_OK
;
1269 char typechar
= ' ';
1271 struct isis_adjacency
*adj
;
1272 struct isis_complete_seqnum_hdr
*chdr
= NULL
;
1273 struct isis_partial_seqnum_hdr
*phdr
= NULL
;
1274 uint32_t found
= 0, expected
= 0;
1275 struct isis_lsp
*lsp
;
1276 struct lsp_entry
*entry
;
1277 struct listnode
*node
, *nnode
;
1278 struct listnode
*node2
, *nnode2
;
1280 struct list
*lsp_list
= NULL
;
1281 struct isis_passwd
*passwd
;
1283 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1285 /* getting the header info */
1288 (struct isis_complete_seqnum_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
1289 circuit
->rcv_stream
->getp
+= ISIS_CSNP_HDRLEN
;
1290 len
= ntohs (chdr
->pdu_len
);
1291 if (len
< ISIS_CSNP_HDRLEN
)
1293 zlog_warn ("Received a CSNP with bogus length!");
1301 (struct isis_partial_seqnum_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
1302 circuit
->rcv_stream
->getp
+= ISIS_PSNP_HDRLEN
;
1303 len
= ntohs (phdr
->pdu_len
);
1304 if (len
< ISIS_PSNP_HDRLEN
)
1306 zlog_warn ("Received a CSNP with bogus length!");
1311 /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */
1312 if (circuit
->ext_domain
)
1315 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1316 "skipping: circuit externalDomain = true",
1317 circuit
->area
->area_tag
,
1318 level
, typechar
, circuit
->interface
->name
);
1323 /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
1324 if (!accept_level (level
, circuit
->circuit_is_type
))
1327 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1328 "skipping: circuit type %s does not match level %d",
1329 circuit
->area
->area_tag
,
1332 circuit
->interface
->name
,
1333 circuit_t2string (circuit
->circuit_is_type
), level
);
1338 /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */
1339 if ((snp_type
== ISIS_SNP_PSNP_FLAG
) &&
1340 (circuit
->circ_type
== CIRCUIT_T_BROADCAST
))
1342 if (!circuit
->u
.bc
.is_dr
[level
- 1])
1345 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
1346 "skipping: we are not the DIS",
1347 circuit
->area
->area_tag
,
1349 typechar
, snpa_print (ssnpa
), circuit
->interface
->name
);
1355 /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */
1357 /* 7.3.15.2 a) 6 - maximum area match, can be ommited since we only use 3
1358 * - already checked */
1360 /* 7.3.15.2 a) 7 - Must check that we have an adjacency of the same level */
1361 /* for broadcast circuits, snpa should be compared */
1362 /* FIXME : Do we need to check SNPA? */
1363 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1365 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1368 isis_adj_lookup (chdr
->source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
1372 /* a psnp on a broadcast, how lovely of Juniper :) */
1374 isis_adj_lookup (phdr
->source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
1377 return ISIS_OK
; /* Silently discard */
1381 if (!circuit
->u
.p2p
.neighbor
)
1382 return ISIS_OK
; /* Silently discard */
1385 /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */
1387 /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */
1389 memset (&tlvs
, 0, sizeof (struct tlvs
));
1392 expected
|= TLVFLAG_LSP_ENTRIES
;
1393 expected
|= TLVFLAG_AUTH_INFO
;
1394 retval
= parse_tlvs (circuit
->area
->area_tag
,
1395 STREAM_PNT (circuit
->rcv_stream
),
1396 len
- circuit
->rcv_stream
->getp
,
1397 &expected
, &found
, &tlvs
);
1399 if (retval
> ISIS_WARNING
)
1401 zlog_warn ("something went very wrong processing SNP");
1407 passwd
= &circuit
->area
->area_passwd
;
1409 passwd
= &circuit
->area
->domain_passwd
;
1411 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_RECV
))
1415 if (!(found
& TLVFLAG_AUTH_INFO
) ||
1416 authentication_check (passwd
, &tlvs
.auth_info
))
1418 isis_event_auth_failure (circuit
->area
->area_tag
,
1419 "SNP authentication" " failure",
1420 phdr
? phdr
->source_id
: chdr
->source_id
);
1426 /* debug isis snp-packets */
1427 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
1429 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s",
1430 circuit
->area
->area_tag
,
1432 typechar
, snpa_print (ssnpa
), circuit
->interface
->name
);
1433 if (tlvs
.lsp_entries
)
1435 for (ALL_LIST_ELEMENTS_RO (tlvs
.lsp_entries
, node
, entry
))
1437 zlog_debug ("ISIS-Snp (%s): %cSNP entry %s, seq 0x%08x,"
1438 " cksum 0x%04x, lifetime %us",
1439 circuit
->area
->area_tag
,
1441 rawlspid_print (entry
->lsp_id
),
1442 ntohl (entry
->seq_num
),
1443 ntohs (entry
->checksum
), ntohs (entry
->rem_lifetime
));
1448 /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */
1449 if (tlvs
.lsp_entries
)
1451 for (ALL_LIST_ELEMENTS_RO (tlvs
.lsp_entries
, node
, entry
))
1453 lsp
= lsp_search (entry
->lsp_id
, circuit
->area
->lspdb
[level
- 1]);
1454 own_lsp
= !memcmp (entry
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1457 /* 7.3.15.2 b) 1) is this LSP newer */
1458 cmp
= lsp_compare (circuit
->area
->area_tag
, lsp
, entry
->seq_num
,
1459 entry
->checksum
, entry
->rem_lifetime
);
1460 /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */
1461 if (cmp
== LSP_EQUAL
)
1463 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1464 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1465 /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
1467 else if (cmp
== LSP_OLDER
)
1469 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1470 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1474 /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM
1478 lsp_inc_seqnum (lsp
, ntohl (entry
->seq_num
));
1479 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1483 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1484 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1485 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1491 /* 7.3.15.2 b) 5) if it was not found, and all of those are not 0,
1492 * insert it and set SSN on it */
1493 if (entry
->rem_lifetime
&& entry
->checksum
&& entry
->seq_num
&&
1494 memcmp (entry
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
1496 lsp
= lsp_new (entry
->lsp_id
, ntohs (entry
->rem_lifetime
),
1497 0, 0, entry
->checksum
, level
);
1498 lsp_insert (lsp
, circuit
->area
->lspdb
[level
- 1]);
1499 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1505 /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported */
1506 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1509 * Build a list from our own LSP db bounded with start_ and stop_lsp_id
1511 lsp_list
= list_new ();
1512 lsp_build_list_nonzero_ht (chdr
->start_lsp_id
, chdr
->stop_lsp_id
,
1513 lsp_list
, circuit
->area
->lspdb
[level
- 1]);
1515 /* Fixme: Find a better solution */
1516 if (tlvs
.lsp_entries
)
1518 for (ALL_LIST_ELEMENTS (tlvs
.lsp_entries
, node
, nnode
, entry
))
1520 for (ALL_LIST_ELEMENTS (lsp_list
, node2
, nnode2
, lsp
))
1522 if (lsp_id_cmp (lsp
->lsp_header
->lsp_id
, entry
->lsp_id
) == 0)
1524 list_delete_node (lsp_list
, node2
);
1530 /* on remaining LSPs we set SRM (neighbor knew not of) */
1531 for (ALL_LIST_ELEMENTS_RO (lsp_list
, node
, lsp
))
1533 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1536 list_free (lsp_list
);
1544 process_csnp (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
1546 /* Sanity check - FIXME: move to correct place */
1547 if ((stream_get_endp (circuit
->rcv_stream
) -
1548 stream_get_getp (circuit
->rcv_stream
)) < ISIS_CSNP_HDRLEN
)
1550 zlog_warn ("Packet too short ( < %d)", ISIS_CSNP_HDRLEN
);
1551 return ISIS_WARNING
;
1554 return process_snp (ISIS_SNP_CSNP_FLAG
, level
, circuit
, ssnpa
);
1558 process_psnp (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
1560 if ((stream_get_endp (circuit
->rcv_stream
) -
1561 stream_get_getp (circuit
->rcv_stream
)) < ISIS_PSNP_HDRLEN
)
1563 zlog_warn ("Packet too short");
1564 return ISIS_WARNING
;
1567 return process_snp (ISIS_SNP_PSNP_FLAG
, level
, circuit
, ssnpa
);
1573 * Section 8.2.2 - Receiving ISH PDUs by an intermediate system
1574 * FIXME: sample packet dump, need to figure 0x81 - looks like NLPid
1575 * 0x82 0x15 0x01 0x00 0x04 0x01 0x2c 0x59
1576 * 0x38 0x08 0x47 0x00 0x01 0x00 0x02 0x00
1577 * 0x03 0x00 0x81 0x01 0xcc
1580 process_is_hello (struct isis_circuit
*circuit
)
1582 struct isis_adjacency
*adj
;
1583 int retval
= ISIS_OK
;
1587 /* In this point in time we are not yet able to handle is_hellos
1588 * on lan - Sorry juniper...
1590 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1593 neigh_len
= stream_getc (circuit
->rcv_stream
);
1594 sysid
= STREAM_PNT (circuit
->rcv_stream
) + neigh_len
- 1 - ISIS_SYS_ID_LEN
;
1595 adj
= circuit
->u
.p2p
.neighbor
;
1599 adj
= isis_new_adj (sysid
, NULL
, 0, circuit
);
1603 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
1604 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
1605 circuit
->u
.p2p
.neighbor
= adj
;
1608 if ((adj
->adj_state
== ISIS_ADJ_UP
) && memcmp (adj
->sysid
, sysid
,
1611 /* 8.2.2 a) 1) FIXME: adjStateChange(down) event */
1612 /* 8.2.2 a) 2) delete the adj */
1613 XFREE (MTYPE_ISIS_ADJACENCY
, adj
);
1614 /* 8.2.2 a) 3) create a new adj */
1615 adj
= isis_new_adj (sysid
, NULL
, 0, circuit
);
1620 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
1621 /* 8.2.2 a) 3) ii */
1622 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
1623 /* 8.2.2 a) 4) quite meaningless */
1625 /* 8.2.2 b) ignore on condition */
1626 if ((adj
->adj_state
== ISIS_ADJ_INITIALIZING
) &&
1627 (adj
->sys_type
== ISIS_SYSTYPE_IS
))
1633 /* 8.2.2 c) respond with a p2p IIH */
1634 send_hello (circuit
, 1);
1636 /* 8.2.2 d) type is IS */
1637 adj
->sys_type
= ISIS_SYSTYPE_IS
;
1638 /* 8.2.2 e) FIXME: Circuit type of? */
1648 isis_handle_pdu (struct isis_circuit
*circuit
, u_char
* ssnpa
)
1650 struct isis_fixed_hdr
*hdr
;
1651 struct esis_fixed_hdr
*esis_hdr
;
1653 int retval
= ISIS_OK
;
1656 * Let's first read data from stream to the header
1658 hdr
= (struct isis_fixed_hdr
*) STREAM_DATA (circuit
->rcv_stream
);
1660 if ((hdr
->idrp
!= ISO10589_ISIS
) && (hdr
->idrp
!= ISO9542_ESIS
))
1662 zlog_warn ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr
->idrp
);
1666 /* now we need to know if this is an ISO 9542 packet and
1667 * take real good care of it, waaa!
1669 if (hdr
->idrp
== ISO9542_ESIS
)
1671 esis_hdr
= (struct esis_fixed_hdr
*) STREAM_DATA (circuit
->rcv_stream
);
1672 stream_set_getp (circuit
->rcv_stream
, ESIS_FIXED_HDR_LEN
);
1673 /* FIXME: Need to do some acceptence tests */
1674 /* example length... */
1675 switch (esis_hdr
->pdu_type
)
1681 zlog_debug ("AN ISH PDU!!");
1682 retval
= process_is_hello (circuit
);
1691 stream_set_getp (circuit
->rcv_stream
, ISIS_FIXED_HDR_LEN
);
1694 * and then process it
1697 if (hdr
->length
< ISIS_MINIMUM_FIXED_HDR_LEN
)
1699 zlog_err ("Fixed header length = %d", hdr
->length
);
1703 if (hdr
->version1
!= 1)
1705 zlog_warn ("Unsupported ISIS version %u", hdr
->version1
);
1706 return ISIS_WARNING
;
1709 if ((hdr
->id_len
!= 0) && (hdr
->id_len
!= ISIS_SYS_ID_LEN
))
1712 ("IDFieldLengthMismatch: ID Length field in a received PDU %u, "
1713 "while the parameter for this IS is %u", hdr
->id_len
,
1718 if (hdr
->version2
!= 1)
1720 zlog_warn ("Unsupported ISIS version %u", hdr
->version2
);
1721 return ISIS_WARNING
;
1724 if ((hdr
->max_area_addrs
!= 0)
1725 && (hdr
->max_area_addrs
!= isis
->max_area_addrs
))
1727 zlog_err ("maximumAreaAddressesMismatch: maximumAreaAdresses in a "
1728 "received PDU %u while the parameter for this IS is %u",
1729 hdr
->max_area_addrs
, isis
->max_area_addrs
);
1733 switch (hdr
->pdu_type
)
1736 retval
= process_lan_hello (ISIS_LEVEL1
, circuit
, ssnpa
);
1739 retval
= process_lan_hello (ISIS_LEVEL2
, circuit
, ssnpa
);
1742 retval
= process_p2p_hello (circuit
);
1745 retval
= process_lsp (ISIS_LEVEL1
, circuit
, ssnpa
);
1748 retval
= process_lsp (ISIS_LEVEL2
, circuit
, ssnpa
);
1750 case L1_COMPLETE_SEQ_NUM
:
1751 retval
= process_csnp (ISIS_LEVEL1
, circuit
, ssnpa
);
1753 case L2_COMPLETE_SEQ_NUM
:
1754 retval
= process_csnp (ISIS_LEVEL2
, circuit
, ssnpa
);
1756 case L1_PARTIAL_SEQ_NUM
:
1757 retval
= process_psnp (ISIS_LEVEL1
, circuit
, ssnpa
);
1759 case L2_PARTIAL_SEQ_NUM
:
1760 retval
= process_psnp (ISIS_LEVEL2
, circuit
, ssnpa
);
1771 isis_receive (struct thread
*thread
)
1773 struct isis_circuit
*circuit
;
1774 u_char ssnpa
[ETH_ALEN
];
1780 circuit
= THREAD_ARG (thread
);
1783 if (circuit
->rcv_stream
== NULL
)
1784 circuit
->rcv_stream
= stream_new (ISO_MTU (circuit
));
1786 stream_reset (circuit
->rcv_stream
);
1788 retval
= circuit
->rx (circuit
, ssnpa
);
1789 circuit
->t_read
= NULL
;
1791 if (retval
== ISIS_OK
)
1792 retval
= isis_handle_pdu (circuit
, ssnpa
);
1795 * prepare for next packet.
1797 THREAD_READ_ON (master
, circuit
->t_read
, isis_receive
, circuit
,
1805 isis_receive (struct thread
*thread
)
1807 struct isis_circuit
*circuit
;
1808 u_char ssnpa
[ETH_ALEN
];
1814 circuit
= THREAD_ARG (thread
);
1817 circuit
->t_read
= NULL
;
1819 if (circuit
->rcv_stream
== NULL
)
1820 circuit
->rcv_stream
= stream_new (ISO_MTU (circuit
));
1822 stream_reset (circuit
->rcv_stream
);
1824 retval
= circuit
->rx (circuit
, ssnpa
);
1826 if (retval
== ISIS_OK
)
1827 retval
= isis_handle_pdu (circuit
, ssnpa
);
1830 * prepare for next packet.
1832 circuit
->t_read
= thread_add_timer_msec (master
, isis_receive
, circuit
,
1834 (circuit
->area
->circuit_list
) *
1842 /* filling of the fixed isis header */
1844 fill_fixed_hdr (struct isis_fixed_hdr
*hdr
, u_char pdu_type
)
1846 memset (hdr
, 0, sizeof (struct isis_fixed_hdr
));
1848 hdr
->idrp
= ISO10589_ISIS
;
1854 hdr
->length
= ISIS_LANHELLO_HDRLEN
;
1857 hdr
->length
= ISIS_P2PHELLO_HDRLEN
;
1861 hdr
->length
= ISIS_LSP_HDR_LEN
;
1863 case L1_COMPLETE_SEQ_NUM
:
1864 case L2_COMPLETE_SEQ_NUM
:
1865 hdr
->length
= ISIS_CSNP_HDRLEN
;
1867 case L1_PARTIAL_SEQ_NUM
:
1868 case L2_PARTIAL_SEQ_NUM
:
1869 hdr
->length
= ISIS_PSNP_HDRLEN
;
1872 zlog_warn ("fill_fixed_hdr(): unknown pdu type %d", pdu_type
);
1875 hdr
->length
+= ISIS_FIXED_HDR_LEN
;
1876 hdr
->pdu_type
= pdu_type
;
1878 hdr
->id_len
= 0; /* ISIS_SYS_ID_LEN - 0==6 */
1880 hdr
->max_area_addrs
= 0; /* isis->max_area_addrs - 0==3 */
1887 fill_fixed_hdr_andstream (struct isis_fixed_hdr
*hdr
, u_char pdu_type
,
1888 struct stream
*stream
)
1890 fill_fixed_hdr (hdr
, pdu_type
);
1892 stream_putc (stream
, hdr
->idrp
);
1893 stream_putc (stream
, hdr
->length
);
1894 stream_putc (stream
, hdr
->version1
);
1895 stream_putc (stream
, hdr
->id_len
);
1896 stream_putc (stream
, hdr
->pdu_type
);
1897 stream_putc (stream
, hdr
->version2
);
1898 stream_putc (stream
, hdr
->reserved
);
1899 stream_putc (stream
, hdr
->max_area_addrs
);
1905 send_hello (struct isis_circuit
*circuit
, int level
)
1907 struct isis_fixed_hdr fixed_hdr
;
1908 struct isis_lan_hello_hdr hello_hdr
;
1909 struct isis_p2p_hello_hdr p2p_hello_hdr
;
1912 unsigned long len_pointer
, length
;
1915 if (circuit
->interface
->mtu
== 0)
1917 zlog_warn ("circuit has zero MTU");
1918 return ISIS_WARNING
;
1921 if (!circuit
->snd_stream
)
1922 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
1924 stream_reset (circuit
->snd_stream
);
1926 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1928 fill_fixed_hdr_andstream (&fixed_hdr
, L1_LAN_HELLO
,
1929 circuit
->snd_stream
);
1931 fill_fixed_hdr_andstream (&fixed_hdr
, L2_LAN_HELLO
,
1932 circuit
->snd_stream
);
1934 fill_fixed_hdr_andstream (&fixed_hdr
, P2P_HELLO
, circuit
->snd_stream
);
1937 * Fill LAN Level 1 or 2 Hello PDU header
1939 memset (&hello_hdr
, 0, sizeof (struct isis_lan_hello_hdr
));
1940 interval
= circuit
->hello_multiplier
[level
- 1] *
1941 circuit
->hello_interval
[level
- 1];
1942 if (interval
> USHRT_MAX
)
1943 interval
= USHRT_MAX
;
1944 hello_hdr
.circuit_t
= circuit
->circuit_is_type
;
1945 memcpy (hello_hdr
.source_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1946 hello_hdr
.hold_time
= htons ((u_int16_t
) interval
);
1948 hello_hdr
.pdu_len
= 0; /* Update the PDU Length later */
1949 len_pointer
= stream_get_endp (circuit
->snd_stream
) + 3 + ISIS_SYS_ID_LEN
;
1951 /* copy the shared part of the hello to the p2p hello if needed */
1952 if (circuit
->circ_type
== CIRCUIT_T_P2P
)
1954 memcpy (&p2p_hello_hdr
, &hello_hdr
, 5 + ISIS_SYS_ID_LEN
);
1955 p2p_hello_hdr
.local_id
= circuit
->circuit_id
;
1956 /* FIXME: need better understanding */
1957 stream_put (circuit
->snd_stream
, &p2p_hello_hdr
, ISIS_P2PHELLO_HDRLEN
);
1961 hello_hdr
.prio
= circuit
->u
.bc
.priority
[level
- 1];
1962 if (level
== 1 && circuit
->u
.bc
.l1_desig_is
)
1964 memcpy (hello_hdr
.lan_id
, circuit
->u
.bc
.l1_desig_is
,
1965 ISIS_SYS_ID_LEN
+ 1);
1967 else if (level
== 2 && circuit
->u
.bc
.l2_desig_is
)
1969 memcpy (hello_hdr
.lan_id
, circuit
->u
.bc
.l2_desig_is
,
1970 ISIS_SYS_ID_LEN
+ 1);
1972 stream_put (circuit
->snd_stream
, &hello_hdr
, ISIS_LANHELLO_HDRLEN
);
1976 * Then the variable length part
1978 /* add circuit password */
1979 if (circuit
->passwd
.type
)
1980 if (tlv_add_authinfo (circuit
->passwd
.type
, circuit
->passwd
.len
,
1981 circuit
->passwd
.passwd
, circuit
->snd_stream
))
1982 return ISIS_WARNING
;
1983 /* Area Addresses TLV */
1984 assert (circuit
->area
);
1985 if (circuit
->area
->area_addrs
&& circuit
->area
->area_addrs
->count
> 0)
1986 if (tlv_add_area_addrs (circuit
->area
->area_addrs
, circuit
->snd_stream
))
1987 return ISIS_WARNING
;
1989 /* LAN Neighbors TLV */
1990 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1992 if (level
== 1 && circuit
->u
.bc
.lan_neighs
[0]->count
> 0)
1993 if (tlv_add_lan_neighs (circuit
->u
.bc
.lan_neighs
[0],
1994 circuit
->snd_stream
))
1995 return ISIS_WARNING
;
1996 if (level
== 2 && circuit
->u
.bc
.lan_neighs
[1]->count
> 0)
1997 if (tlv_add_lan_neighs (circuit
->u
.bc
.lan_neighs
[1],
1998 circuit
->snd_stream
))
1999 return ISIS_WARNING
;
2002 /* Protocols Supported TLV */
2003 if (circuit
->nlpids
.count
> 0)
2004 if (tlv_add_nlpid (&circuit
->nlpids
, circuit
->snd_stream
))
2005 return ISIS_WARNING
;
2006 /* IP interface Address TLV */
2007 if (circuit
->ip_router
&& circuit
->ip_addrs
&& circuit
->ip_addrs
->count
> 0)
2008 if (tlv_add_ip_addrs (circuit
->ip_addrs
, circuit
->snd_stream
))
2009 return ISIS_WARNING
;
2012 /* IPv6 Interface Address TLV */
2013 if (circuit
->ipv6_router
&& circuit
->ipv6_link
&&
2014 circuit
->ipv6_link
->count
> 0)
2015 if (tlv_add_ipv6_addrs (circuit
->ipv6_link
, circuit
->snd_stream
))
2016 return ISIS_WARNING
;
2017 #endif /* HAVE_IPV6 */
2019 if (circuit
->u
.bc
.pad_hellos
)
2020 if (tlv_add_padding (circuit
->snd_stream
))
2021 return ISIS_WARNING
;
2023 length
= stream_get_endp (circuit
->snd_stream
);
2024 /* Update PDU length */
2025 stream_putw_at (circuit
->snd_stream
, len_pointer
, (u_int16_t
) length
);
2027 retval
= circuit
->tx (circuit
, level
);
2029 zlog_warn ("sending of LAN Level %d Hello failed", level
);
2031 /* DEBUG_ADJ_PACKETS */
2032 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
2034 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
2036 zlog_debug ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %ld",
2037 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
2038 /* FIXME: use %z when we stop supporting old compilers. */
2039 (unsigned long) STREAM_SIZE (circuit
->snd_stream
));
2043 zlog_debug ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld",
2044 circuit
->area
->area_tag
, circuit
->interface
->name
,
2045 /* FIXME: use %z when we stop supporting old compilers. */
2046 (unsigned long) STREAM_SIZE (circuit
->snd_stream
));
2054 send_lan_hello (struct isis_circuit
*circuit
, int level
)
2056 return send_hello (circuit
, level
);
2060 send_lan_l1_hello (struct thread
*thread
)
2062 struct isis_circuit
*circuit
;
2065 circuit
= THREAD_ARG (thread
);
2067 circuit
->u
.bc
.t_send_lan_hello
[0] = NULL
;
2069 if (circuit
->u
.bc
.run_dr_elect
[0])
2070 retval
= isis_dr_elect (circuit
, 1);
2072 retval
= send_lan_hello (circuit
, 1);
2074 /* set next timer thread */
2075 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_send_lan_hello
[0],
2076 send_lan_l1_hello
, circuit
,
2077 isis_jitter (circuit
->hello_interval
[0], IIH_JITTER
));
2083 send_lan_l2_hello (struct thread
*thread
)
2085 struct isis_circuit
*circuit
;
2088 circuit
= THREAD_ARG (thread
);
2090 circuit
->u
.bc
.t_send_lan_hello
[1] = NULL
;
2092 if (circuit
->u
.bc
.run_dr_elect
[1])
2093 retval
= isis_dr_elect (circuit
, 2);
2095 retval
= send_lan_hello (circuit
, 2);
2097 /* set next timer thread */
2098 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_send_lan_hello
[1],
2099 send_lan_l2_hello
, circuit
,
2100 isis_jitter (circuit
->hello_interval
[1], IIH_JITTER
));
2106 send_p2p_hello (struct thread
*thread
)
2108 struct isis_circuit
*circuit
;
2110 circuit
= THREAD_ARG (thread
);
2112 circuit
->u
.p2p
.t_send_p2p_hello
= NULL
;
2114 send_hello (circuit
, 1);
2116 /* set next timer thread */
2117 THREAD_TIMER_ON (master
, circuit
->u
.p2p
.t_send_p2p_hello
, send_p2p_hello
,
2118 circuit
, isis_jitter (circuit
->hello_interval
[1],
2125 build_csnp (int level
, u_char
* start
, u_char
* stop
, struct list
*lsps
,
2126 struct isis_circuit
*circuit
)
2128 struct isis_fixed_hdr fixed_hdr
;
2129 struct isis_passwd
*passwd
;
2130 int retval
= ISIS_OK
;
2135 fill_fixed_hdr_andstream (&fixed_hdr
, L1_COMPLETE_SEQ_NUM
,
2136 circuit
->snd_stream
);
2138 fill_fixed_hdr_andstream (&fixed_hdr
, L2_COMPLETE_SEQ_NUM
,
2139 circuit
->snd_stream
);
2142 * Fill Level 1 or 2 Complete Sequence Numbers header
2145 lenp
= stream_get_endp (circuit
->snd_stream
);
2146 stream_putw (circuit
->snd_stream
, 0); /* PDU length - when we know it */
2147 /* no need to send the source here, it is always us if we csnp */
2148 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2149 /* with zero circuit id - ref 9.10, 9.11 */
2150 stream_putc (circuit
->snd_stream
, 0x00);
2152 stream_put (circuit
->snd_stream
, start
, ISIS_SYS_ID_LEN
+ 2);
2153 stream_put (circuit
->snd_stream
, stop
, ISIS_SYS_ID_LEN
+ 2);
2159 passwd
= &circuit
->area
->area_passwd
;
2161 passwd
= &circuit
->area
->domain_passwd
;
2163 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
))
2165 retval
= tlv_add_authinfo (passwd
->type
, passwd
->len
,
2166 passwd
->passwd
, circuit
->snd_stream
);
2168 if (!retval
&& lsps
)
2170 retval
= tlv_add_lsp_entries (lsps
, circuit
->snd_stream
);
2172 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
2173 assert (length
>= ISIS_CSNP_HDRLEN
);
2174 /* Update PU length */
2175 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2181 * FIXME: support multiple CSNPs
2185 send_csnp (struct isis_circuit
*circuit
, int level
)
2187 int retval
= ISIS_OK
;
2188 u_char start
[ISIS_SYS_ID_LEN
+ 2];
2189 u_char stop
[ISIS_SYS_ID_LEN
+ 2];
2190 struct list
*list
= NULL
;
2191 struct listnode
*node
;
2192 struct isis_lsp
*lsp
;
2194 memset (start
, 0x00, ISIS_SYS_ID_LEN
+ 2);
2195 memset (stop
, 0xff, ISIS_SYS_ID_LEN
+ 2);
2197 if (circuit
->area
->lspdb
[level
- 1] &&
2198 dict_count (circuit
->area
->lspdb
[level
- 1]) > 0)
2201 lsp_build_list (start
, stop
, list
, circuit
->area
->lspdb
[level
- 1]);
2203 if (circuit
->snd_stream
== NULL
)
2204 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
2206 stream_reset (circuit
->snd_stream
);
2208 retval
= build_csnp (level
, start
, stop
, list
, circuit
);
2210 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2212 zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld",
2213 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
2214 /* FIXME: use %z when we stop supporting old compilers. */
2215 (unsigned long) STREAM_SIZE (circuit
->snd_stream
));
2216 for (ALL_LIST_ELEMENTS_RO (list
, node
, lsp
))
2218 zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x,"
2219 " cksum 0x%04x, lifetime %us",
2220 circuit
->area
->area_tag
,
2221 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2222 ntohl (lsp
->lsp_header
->seq_num
),
2223 ntohs (lsp
->lsp_header
->checksum
),
2224 ntohs (lsp
->lsp_header
->rem_lifetime
));
2230 if (retval
== ISIS_OK
)
2231 retval
= circuit
->tx (circuit
, level
);
2237 send_l1_csnp (struct thread
*thread
)
2239 struct isis_circuit
*circuit
;
2240 int retval
= ISIS_OK
;
2242 circuit
= THREAD_ARG (thread
);
2245 circuit
->t_send_csnp
[0] = NULL
;
2247 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
&& circuit
->u
.bc
.is_dr
[0])
2249 send_csnp (circuit
, 1);
2251 /* set next timer thread */
2252 THREAD_TIMER_ON (master
, circuit
->t_send_csnp
[0], send_l1_csnp
, circuit
,
2253 isis_jitter (circuit
->csnp_interval
[0], CSNP_JITTER
));
2259 send_l2_csnp (struct thread
*thread
)
2261 struct isis_circuit
*circuit
;
2262 int retval
= ISIS_OK
;
2264 circuit
= THREAD_ARG (thread
);
2267 circuit
->t_send_csnp
[1] = NULL
;
2269 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
&& circuit
->u
.bc
.is_dr
[1])
2271 send_csnp (circuit
, 2);
2273 /* set next timer thread */
2274 THREAD_TIMER_ON (master
, circuit
->t_send_csnp
[1], send_l2_csnp
, circuit
,
2275 isis_jitter (circuit
->csnp_interval
[1], CSNP_JITTER
));
2281 build_psnp (int level
, struct isis_circuit
*circuit
, struct list
*lsps
)
2283 struct isis_fixed_hdr fixed_hdr
;
2287 struct isis_lsp
*lsp
;
2288 struct isis_passwd
*passwd
;
2289 struct listnode
*node
;
2292 fill_fixed_hdr_andstream (&fixed_hdr
, L1_PARTIAL_SEQ_NUM
,
2293 circuit
->snd_stream
);
2295 fill_fixed_hdr_andstream (&fixed_hdr
, L2_PARTIAL_SEQ_NUM
,
2296 circuit
->snd_stream
);
2299 * Fill Level 1 or 2 Partial Sequence Numbers header
2301 lenp
= stream_get_endp (circuit
->snd_stream
);
2302 stream_putw (circuit
->snd_stream
, 0); /* PDU length - when we know it */
2303 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2304 stream_putc (circuit
->snd_stream
, circuit
->idx
);
2311 passwd
= &circuit
->area
->area_passwd
;
2313 passwd
= &circuit
->area
->domain_passwd
;
2315 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
))
2317 retval
= tlv_add_authinfo (passwd
->type
, passwd
->len
,
2318 passwd
->passwd
, circuit
->snd_stream
);
2320 if (!retval
&& lsps
)
2322 retval
= tlv_add_lsp_entries (lsps
, circuit
->snd_stream
);
2325 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2327 for (ALL_LIST_ELEMENTS_RO (lsps
, node
, lsp
))
2329 zlog_debug ("ISIS-Snp (%s): PSNP entry %s, seq 0x%08x,"
2330 " cksum 0x%04x, lifetime %us",
2331 circuit
->area
->area_tag
,
2332 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2333 ntohl (lsp
->lsp_header
->seq_num
),
2334 ntohs (lsp
->lsp_header
->checksum
),
2335 ntohs (lsp
->lsp_header
->rem_lifetime
));
2339 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
2340 assert (length
>= ISIS_PSNP_HDRLEN
);
2341 /* Update PDU length */
2342 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2348 * 7.3.15.4 action on expiration of partial SNP interval
2352 send_psnp (int level
, struct isis_circuit
*circuit
)
2354 int retval
= ISIS_OK
;
2355 struct isis_lsp
*lsp
;
2356 struct list
*list
= NULL
;
2357 struct listnode
*node
;
2359 if ((circuit
->circ_type
== CIRCUIT_T_BROADCAST
&&
2360 !circuit
->u
.bc
.is_dr
[level
- 1]) ||
2361 circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
2364 if (circuit
->area
->lspdb
[level
- 1] &&
2365 dict_count (circuit
->area
->lspdb
[level
- 1]) > 0)
2368 lsp_build_list_ssn (circuit
, list
, circuit
->area
->lspdb
[level
- 1]);
2370 if (listcount (list
) > 0)
2372 if (circuit
->snd_stream
== NULL
)
2373 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
2375 stream_reset (circuit
->snd_stream
);
2378 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2379 zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld",
2380 circuit
->area
->area_tag
, level
,
2381 circuit
->interface
->name
,
2382 /* FIXME: use %z when we stop supporting old
2384 (unsigned long) STREAM_SIZE (circuit
->snd_stream
));
2386 retval
= build_psnp (level
, circuit
, list
);
2387 if (retval
== ISIS_OK
)
2388 retval
= circuit
->tx (circuit
, level
);
2390 if (retval
== ISIS_OK
)
2393 * sending succeeded, we can clear SSN flags of this circuit
2394 * for the LSPs in list
2396 for (ALL_LIST_ELEMENTS_RO (list
, node
, lsp
))
2397 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
2408 send_l1_psnp (struct thread
*thread
)
2411 struct isis_circuit
*circuit
;
2412 int retval
= ISIS_OK
;
2414 circuit
= THREAD_ARG (thread
);
2417 circuit
->t_send_psnp
[0] = NULL
;
2419 send_psnp (1, circuit
);
2420 /* set next timer thread */
2421 THREAD_TIMER_ON (master
, circuit
->t_send_psnp
[0], send_l1_psnp
, circuit
,
2422 isis_jitter (circuit
->psnp_interval
[0], PSNP_JITTER
));
2428 * 7.3.15.4 action on expiration of partial SNP interval
2432 send_l2_psnp (struct thread
*thread
)
2434 struct isis_circuit
*circuit
;
2435 int retval
= ISIS_OK
;
2437 circuit
= THREAD_ARG (thread
);
2440 circuit
->t_send_psnp
[1] = NULL
;
2442 send_psnp (2, circuit
);
2444 /* set next timer thread */
2445 THREAD_TIMER_ON (master
, circuit
->t_send_psnp
[1], send_l2_psnp
, circuit
,
2446 isis_jitter (circuit
->psnp_interval
[1], PSNP_JITTER
));
2452 * ISO 10589 - 7.3.14.3
2455 send_lsp (struct thread
*thread
)
2457 struct isis_circuit
*circuit
;
2458 struct isis_lsp
*lsp
;
2459 struct listnode
*node
;
2462 circuit
= THREAD_ARG (thread
);
2465 if (circuit
->state
== C_STATE_UP
)
2467 lsp
= listgetdata ((node
= listhead (circuit
->lsp_queue
)));
2470 * Do not send if levels do not match
2472 if (!(lsp
->level
& circuit
->circuit_is_type
))
2476 * Do not send if we do not have adjacencies in state up on the circuit
2478 if (circuit
->upadjcount
[lsp
->level
- 1] == 0)
2480 /* only send if it needs sending */
2481 if ((time (NULL
) - lsp
->last_sent
) >=
2482 circuit
->area
->lsp_gen_interval
[lsp
->level
- 1])
2485 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
2488 ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
2489 " lifetime %us on %s", circuit
->area
->area_tag
, lsp
->level
,
2490 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2491 ntohl (lsp
->lsp_header
->seq_num
),
2492 ntohs (lsp
->lsp_header
->checksum
),
2493 ntohs (lsp
->lsp_header
->rem_lifetime
),
2494 circuit
->interface
->name
);
2496 /* copy our lsp to the send buffer */
2497 stream_copy (circuit
->snd_stream
, lsp
->pdu
);
2499 retval
= circuit
->tx (circuit
, lsp
->level
);
2502 * If the sending succeeded, we can del the lsp from circuits
2505 if (retval
== ISIS_OK
)
2507 list_delete_node (circuit
->lsp_queue
, node
);
2510 * On broadcast circuits also the SRMflag can be cleared
2512 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
2513 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
2515 if (flags_any_set (lsp
->SRMflags
) == 0)
2518 * need to remember when we were last sent
2520 lsp
->last_sent
= time (NULL
);
2525 zlog_debug ("sending of level %d link state failed", lsp
->level
);
2530 /* my belief is that if it wasn't his time, the lsp can be removed
2534 list_delete_node (circuit
->lsp_queue
, node
);
2538 * If there are still LSPs send next one after lsp-interval (33 msecs)
2540 if (listcount (circuit
->lsp_queue
) > 0)
2541 thread_add_timer (master
, send_lsp
, circuit
, 1);
2549 ack_lsp (struct isis_link_state_hdr
*hdr
, struct isis_circuit
*circuit
,
2555 struct isis_fixed_hdr fixed_hdr
;
2557 if (!circuit
->snd_stream
)
2558 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
2560 stream_reset (circuit
->snd_stream
);
2562 // fill_llc_hdr (stream);
2564 fill_fixed_hdr_andstream (&fixed_hdr
, L1_PARTIAL_SEQ_NUM
,
2565 circuit
->snd_stream
);
2567 fill_fixed_hdr_andstream (&fixed_hdr
, L2_PARTIAL_SEQ_NUM
,
2568 circuit
->snd_stream
);
2571 lenp
= stream_get_endp (circuit
->snd_stream
);
2572 stream_putw (circuit
->snd_stream
, 0); /* PDU length */
2573 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2574 stream_putc (circuit
->snd_stream
, circuit
->idx
);
2575 stream_putc (circuit
->snd_stream
, 9); /* code */
2576 stream_putc (circuit
->snd_stream
, 16); /* len */
2578 stream_putw (circuit
->snd_stream
, ntohs (hdr
->rem_lifetime
));
2579 stream_put (circuit
->snd_stream
, hdr
->lsp_id
, ISIS_SYS_ID_LEN
+ 2);
2580 stream_putl (circuit
->snd_stream
, ntohl (hdr
->seq_num
));
2581 stream_putw (circuit
->snd_stream
, ntohs (hdr
->checksum
));
2583 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
2584 /* Update PDU length */
2585 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2587 retval
= circuit
->tx (circuit
, level
);