2 * IS-IS Rout(e)ing protocol - isis_pdu.c
5 * Copyright (C) 2001,2002 Sampo Saaristo
6 * Tampere University of Technology
7 * Institute of Communications Engineering
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public Licenseas published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
14 * This program is distributed in the hope that it will be useful,but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
38 #include "isisd/dict.h"
39 #include "isisd/include-netbsd/iso.h"
40 #include "isisd/isis_constants.h"
41 #include "isisd/isis_common.h"
42 #include "isisd/isis_adjacency.h"
43 #include "isisd/isis_circuit.h"
44 #include "isisd/isis_network.h"
45 #include "isisd/isis_misc.h"
46 #include "isisd/isis_dr.h"
47 #include "isisd/isis_flags.h"
48 #include "isisd/isis_tlv.h"
49 #include "isisd/isisd.h"
50 #include "isisd/isis_dynhn.h"
51 #include "isisd/isis_lsp.h"
52 #include "isisd/isis_pdu.h"
53 #include "isisd/iso_checksum.h"
54 #include "isisd/isis_csm.h"
55 #include "isisd/isis_events.h"
57 extern struct thread_master
*master
;
58 extern struct isis
*isis
;
60 #define ISIS_MINIMUM_FIXED_HDR_LEN 15
61 #define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */
67 /* Utility mask array. */
68 static const u_char maskbit
[] = {
69 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
77 * Compares two sets of area addresses
80 area_match (struct list
*left
, struct list
*right
)
82 struct area_addr
*addr1
, *addr2
;
83 struct listnode
*node1
, *node2
;
85 for (ALL_LIST_ELEMENTS_RO (left
, node1
, addr1
))
87 for (ALL_LIST_ELEMENTS_RO (right
, node2
, addr2
))
89 if (addr1
->addr_len
== addr2
->addr_len
&&
90 !memcmp (addr1
->area_addr
, addr2
->area_addr
, (int) addr1
->addr_len
))
95 return 0; /* mismatch */
99 * Check if ip2 is in the ip1's network (function like Prefix.h:prefix_match() )
100 * param ip1 the IS interface ip address structure
101 * param ip2 the IIH's ip address
102 * return 0 the IIH's IP is not in the IS's subnetwork
103 * 1 the IIH's IP is in the IS's subnetwork
106 ip_same_subnet (struct prefix_ipv4
*ip1
, struct in_addr
*ip2
)
108 u_char
*addr1
, *addr2
;
109 int shift
, offset
, offsetloop
;
112 addr1
= (u_char
*) & ip1
->prefix
.s_addr
;
113 addr2
= (u_char
*) & ip2
->s_addr
;
114 len
= ip1
->prefixlen
;
117 offsetloop
= offset
= len
/ PNBBY
;
120 if (addr1
[offsetloop
] != addr2
[offsetloop
])
124 if (maskbit
[shift
] & (addr1
[offset
] ^ addr2
[offset
]))
127 return 1; /* match */
131 * Compares two set of ip addresses
132 * param left the local interface's ip addresses
133 * param right the iih interface's ip address
138 ip_match (struct list
*left
, struct list
*right
)
140 struct prefix_ipv4
*ip1
;
142 struct listnode
*node1
, *node2
;
144 if ((left
== NULL
) || (right
== NULL
))
147 for (ALL_LIST_ELEMENTS_RO (left
, node1
, ip1
))
149 for (ALL_LIST_ELEMENTS_RO (right
, node2
, ip2
))
151 if (ip_same_subnet (ip1
, ip2
))
153 return 1; /* match */
162 * Checks whether we should accept a PDU of given level
165 accept_level (int level
, int circuit_t
)
167 int retval
= ((circuit_t
& level
) == level
); /* simple approach */
174 * Verify authentication information
175 * Support cleartext and HMAC MD5 authentication
178 authentication_check (struct isis_passwd
*remote
, struct isis_passwd
*local
, struct isis_circuit
* c
)
180 unsigned char digest
[ISIS_AUTH_MD5_SIZE
];
184 switch (c
->passwd
.type
)
186 case ISIS_PASSWD_TYPE_HMAC_MD5
:
187 /* HMAC MD5 (RFC 3567) */
188 /* MD5 computation according to RFC 2104 */
189 hmac_md5(c
->rcv_stream
->data
, stream_get_endp(c
->rcv_stream
), (unsigned char *) &(local
->passwd
), c
->passwd
.len
, (unsigned char *) &digest
);
190 return memcmp (digest
, remote
->passwd
, ISIS_AUTH_MD5_SIZE
);
192 case ISIS_PASSWD_TYPE_CLEARTXT
:
193 /* Cleartext (ISO 10589) */
194 if (local
->len
!= remote
->len
)
195 return 1; /* Auth fail () - passwd len mismatch */
196 return memcmp (local
->passwd
, remote
->passwd
, local
->len
);
199 zlog_warn ("Unsupported authentication type");
203 return 0; /* Authentication pass when no authentication is configured */
207 * Processing helper functions
210 tlvs_to_adj_nlpids (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
213 struct nlpids
*tlv_nlpids
;
218 tlv_nlpids
= tlvs
->nlpids
;
220 adj
->nlpids
.count
= tlv_nlpids
->count
;
222 for (i
= 0; i
< tlv_nlpids
->count
; i
++)
224 adj
->nlpids
.nlpids
[i
] = tlv_nlpids
->nlpids
[i
];
230 del_ip_addr (void *val
)
232 XFREE (MTYPE_ISIS_TMP
, val
);
236 tlvs_to_adj_ipv4_addrs (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
238 struct listnode
*node
;
239 struct in_addr
*ipv4_addr
, *malloced
;
243 adj
->ipv4_addrs
->del
= del_ip_addr
;
244 list_delete (adj
->ipv4_addrs
);
246 adj
->ipv4_addrs
= list_new ();
247 if (tlvs
->ipv4_addrs
)
249 for (ALL_LIST_ELEMENTS_RO (tlvs
->ipv4_addrs
, node
, ipv4_addr
))
251 malloced
= XMALLOC (MTYPE_ISIS_TMP
, sizeof (struct in_addr
));
252 memcpy (malloced
, ipv4_addr
, sizeof (struct in_addr
));
253 listnode_add (adj
->ipv4_addrs
, malloced
);
260 tlvs_to_adj_ipv6_addrs (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
262 struct listnode
*node
;
263 struct in6_addr
*ipv6_addr
, *malloced
;
267 adj
->ipv6_addrs
->del
= del_ip_addr
;
268 list_delete (adj
->ipv6_addrs
);
270 adj
->ipv6_addrs
= list_new ();
271 if (tlvs
->ipv6_addrs
)
273 for (ALL_LIST_ELEMENTS_RO (tlvs
->ipv6_addrs
, node
, ipv6_addr
))
275 malloced
= XMALLOC (MTYPE_ISIS_TMP
, sizeof (struct in6_addr
));
276 memcpy (malloced
, ipv6_addr
, sizeof (struct in6_addr
));
277 listnode_add (adj
->ipv6_addrs
, malloced
);
282 #endif /* HAVE_IPV6 */
291 * Section 8.2.5 - Receiving point-to-point IIH PDUs
295 process_p2p_hello (struct isis_circuit
*circuit
)
297 int retval
= ISIS_OK
;
298 struct isis_p2p_hello_hdr
*hdr
;
299 struct isis_adjacency
*adj
;
300 u_int32_t expected
= 0, found
;
303 if ((stream_get_endp (circuit
->rcv_stream
) -
304 stream_get_getp (circuit
->rcv_stream
)) < ISIS_P2PHELLO_HDRLEN
)
306 zlog_warn ("Packet too short");
310 /* 8.2.5.1 PDU acceptance tests */
312 /* 8.2.5.1 a) external domain untrue */
313 /* FIXME: not useful at all? */
315 /* 8.2.5.1 b) ID Length mismatch */
316 /* checked at the handle_pdu */
318 /* 8.2.5.2 IIH PDU Processing */
320 /* 8.2.5.2 a) 1) Maximum Area Addresses */
321 /* Already checked, and can also be ommited */
326 hdr
= (struct isis_p2p_hello_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
327 circuit
->rcv_stream
->getp
+= ISIS_P2PHELLO_HDRLEN
;
329 /* hdr.circuit_t = stream_getc (stream);
330 stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN);
331 hdr.hold_time = stream_getw (stream);
332 hdr.pdu_len = stream_getw (stream);
333 hdr.local_id = stream_getc (stream); */
336 * My interpertation of the ISO, if no adj exists we will create one for
340 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
342 zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
343 " cir id %02d, length %d",
344 circuit
->area
->area_tag
, circuit
->interface
->name
,
345 circuit_t2string (circuit
->circuit_is_type
),
346 circuit
->circuit_id
, ntohs (hdr
->pdu_len
));
349 adj
= circuit
->u
.p2p
.neighbor
;
352 adj
= isis_new_adj (hdr
->source_id
, NULL
, 0, circuit
);
355 circuit
->u
.p2p
.neighbor
= adj
;
356 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
357 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
360 /* 8.2.6 Monitoring point-to-point adjacencies */
361 adj
->hold_time
= ntohs (hdr
->hold_time
);
362 adj
->last_upd
= time (NULL
);
365 * Lets get the TLVS now
367 expected
|= TLVFLAG_AREA_ADDRS
;
368 expected
|= TLVFLAG_AUTH_INFO
;
369 expected
|= TLVFLAG_NLPID
;
370 expected
|= TLVFLAG_IPV4_ADDR
;
371 expected
|= TLVFLAG_IPV6_ADDR
;
373 retval
= parse_tlvs (circuit
->area
->area_tag
,
374 STREAM_PNT (circuit
->rcv_stream
),
375 ntohs (hdr
->pdu_len
) - ISIS_P2PHELLO_HDRLEN
376 - ISIS_FIXED_HDR_LEN
, &expected
, &found
, &tlvs
);
378 if (retval
> ISIS_WARNING
)
384 /* 8.2.5.1 c) Authentication */
385 if (circuit
->passwd
.type
)
387 if (!(found
& TLVFLAG_AUTH_INFO
) ||
388 authentication_check (&tlvs
.auth_info
, &circuit
->passwd
, circuit
))
390 isis_event_auth_failure (circuit
->area
->area_tag
,
391 "P2P hello authentication failure",
397 /* we do this now because the adj may not survive till the end... */
399 /* we need to copy addresses to the adj */
400 tlvs_to_adj_ipv4_addrs (&tlvs
, adj
);
403 tlvs_to_adj_ipv6_addrs (&tlvs
, adj
);
404 #endif /* HAVE_IPV6 */
406 /* lets take care of the expiry */
407 THREAD_TIMER_OFF (adj
->t_expire
);
408 THREAD_TIMER_ON (master
, adj
->t_expire
, isis_adj_expire
, adj
,
409 (long) adj
->hold_time
);
411 /* 8.2.5.2 a) a match was detected */
412 if (area_match (circuit
->area
->area_addrs
, tlvs
.area_addrs
))
414 /* 8.2.5.2 a) 2) If the system is L1 - table 5 */
415 if (circuit
->area
->is_type
== IS_LEVEL_1
)
417 switch (hdr
->circuit_t
)
420 case IS_LEVEL_1_AND_2
:
421 if (adj
->adj_state
!= ISIS_ADJ_UP
)
423 /* (4) adj state up */
424 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
425 /* (5) adj usage level 1 */
426 adj
->adj_usage
= ISIS_ADJ_LEVEL1
;
428 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
434 if (adj
->adj_state
!= ISIS_ADJ_UP
)
436 /* (7) reject - wrong system type event */
437 zlog_warn ("wrongSystemType");
438 return ISIS_WARNING
; /* Reject */
440 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
442 /* (6) down - wrong system */
443 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
449 /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */
450 if (circuit
->area
->is_type
== IS_LEVEL_1_AND_2
)
452 switch (hdr
->circuit_t
)
455 if (adj
->adj_state
!= ISIS_ADJ_UP
)
457 /* (6) adj state up */
458 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
459 /* (7) adj usage level 1 */
460 adj
->adj_usage
= ISIS_ADJ_LEVEL1
;
462 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
466 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
467 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
469 /* (8) down - wrong system */
470 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
474 if (adj
->adj_state
!= ISIS_ADJ_UP
)
476 /* (6) adj state up */
477 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
478 /* (9) adj usage level 2 */
479 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
481 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1
) ||
482 (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
))
484 /* (8) down - wrong system */
485 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
487 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
492 case IS_LEVEL_1_AND_2
:
493 if (adj
->adj_state
!= ISIS_ADJ_UP
)
495 /* (6) adj state up */
496 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
497 /* (10) adj usage level 1 */
498 adj
->adj_usage
= ISIS_ADJ_LEVEL1AND2
;
500 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1
) ||
501 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
503 /* (8) down - wrong system */
504 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
506 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
514 /* 8.2.5.2 a) 4) If the system is L2 - table 7 */
515 if (circuit
->area
->is_type
== IS_LEVEL_2
)
517 switch (hdr
->circuit_t
)
520 if (adj
->adj_state
!= ISIS_ADJ_UP
)
522 /* (5) reject - wrong system type event */
523 zlog_warn ("wrongSystemType");
524 return ISIS_WARNING
; /* Reject */
526 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
527 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
529 /* (6) down - wrong system */
530 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
533 case IS_LEVEL_1_AND_2
:
535 if (adj
->adj_state
!= ISIS_ADJ_UP
)
537 /* (7) adj state up */
538 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
539 /* (8) adj usage level 2 */
540 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
542 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
544 /* (6) down - wrong system */
545 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
547 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
555 /* 8.2.5.2 b) if no match was detected */
558 if (circuit
->area
->is_type
== IS_LEVEL_1
)
560 /* 8.2.5.2 b) 1) is_type L1 and adj is not up */
561 if (adj
->adj_state
!= ISIS_ADJ_UP
)
563 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch");
564 /* 8.2.5.2 b) 2)is_type L1 and adj is up */
568 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
569 "Down - Area Mismatch");
572 /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */
575 switch (hdr
->circuit_t
)
578 if (adj
->adj_state
!= ISIS_ADJ_UP
)
580 /* (6) reject - Area Mismatch event */
581 zlog_warn ("AreaMismatch");
582 return ISIS_WARNING
; /* Reject */
584 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
586 /* (7) down - area mismatch */
587 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch");
590 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
591 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
593 /* (7) down - wrong system */
594 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
597 case IS_LEVEL_1_AND_2
:
599 if (adj
->adj_state
!= ISIS_ADJ_UP
)
601 /* (8) adj state up */
602 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
603 /* (9) adj usage level 2 */
604 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
606 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
608 /* (7) down - wrong system */
609 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
611 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
613 if (hdr
->circuit_t
== IS_LEVEL_2
)
615 /* (7) down - wrong system */
616 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
621 /* (7) down - area mismatch */
622 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
626 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
634 /* 8.2.5.2 c) if the action was up - comparing circuit IDs */
635 /* FIXME - Missing parts */
637 /* some of my own understanding of the ISO, why the heck does
638 * it not say what should I change the system_type to...
640 switch (adj
->adj_usage
)
642 case ISIS_ADJ_LEVEL1
:
643 adj
->sys_type
= ISIS_SYSTYPE_L1_IS
;
645 case ISIS_ADJ_LEVEL2
:
646 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
648 case ISIS_ADJ_LEVEL1AND2
:
649 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
652 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
656 adj
->circuit_t
= hdr
->circuit_t
;
657 adj
->level
= hdr
->circuit_t
;
665 * Process IS-IS LAN Level 1/2 Hello PDU
668 process_lan_hello (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
670 int retval
= ISIS_OK
;
671 struct isis_lan_hello_hdr hdr
;
672 struct isis_adjacency
*adj
;
673 u_int32_t expected
= 0, found
;
676 struct listnode
*node
;
678 if ((stream_get_endp (circuit
->rcv_stream
) -
679 stream_get_getp (circuit
->rcv_stream
)) < ISIS_LANHELLO_HDRLEN
)
681 zlog_warn ("Packet too short");
685 if (circuit
->ext_domain
)
687 zlog_debug ("level %d LAN Hello received over circuit with "
688 "externalDomain = true", level
);
692 if (!accept_level (level
, circuit
->circuit_is_type
))
694 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
696 zlog_debug ("ISIS-Adj (%s): Interface level mismatch, %s",
697 circuit
->area
->area_tag
, circuit
->interface
->name
);
703 /* Cisco's debug message compatability */
704 if (!accept_level (level
, circuit
->area
->is_type
))
706 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
708 zlog_debug ("ISIS-Adj (%s): is type mismatch",
709 circuit
->area
->area_tag
);
717 hdr
.circuit_t
= stream_getc (circuit
->rcv_stream
);
718 stream_get (hdr
.source_id
, circuit
->rcv_stream
, ISIS_SYS_ID_LEN
);
719 hdr
.hold_time
= stream_getw (circuit
->rcv_stream
);
720 hdr
.pdu_len
= stream_getw (circuit
->rcv_stream
);
721 hdr
.prio
= stream_getc (circuit
->rcv_stream
);
722 stream_get (hdr
.lan_id
, circuit
->rcv_stream
, ISIS_SYS_ID_LEN
+ 1);
724 if (hdr
.circuit_t
!= IS_LEVEL_1
&& hdr
.circuit_t
!= IS_LEVEL_2
&&
725 hdr
.circuit_t
!= IS_LEVEL_1_AND_2
)
727 zlog_warn ("Level %d LAN Hello with Circuit Type %d", level
,
734 expected
|= TLVFLAG_AUTH_INFO
;
735 expected
|= TLVFLAG_AREA_ADDRS
;
736 expected
|= TLVFLAG_LAN_NEIGHS
;
737 expected
|= TLVFLAG_NLPID
;
738 expected
|= TLVFLAG_IPV4_ADDR
;
739 expected
|= TLVFLAG_IPV6_ADDR
;
741 retval
= parse_tlvs (circuit
->area
->area_tag
,
742 STREAM_PNT (circuit
->rcv_stream
),
743 hdr
.pdu_len
- ISIS_LANHELLO_HDRLEN
-
744 ISIS_FIXED_HDR_LEN
, &expected
, &found
, &tlvs
);
746 if (retval
> ISIS_WARNING
)
748 zlog_warn ("parse_tlvs() failed");
752 if (!(found
& TLVFLAG_AREA_ADDRS
))
754 zlog_warn ("No Area addresses TLV in Level %d LAN IS to IS hello",
756 retval
= ISIS_WARNING
;
760 /* Verify authentication, either cleartext of HMAC MD5 */
761 if (circuit
->passwd
.type
)
763 if (!(found
& TLVFLAG_AUTH_INFO
) ||
764 authentication_check (&tlvs
.auth_info
, &circuit
->passwd
, circuit
))
766 isis_event_auth_failure (circuit
->area
->area_tag
,
767 "LAN hello authentication failure",
769 retval
= ISIS_WARNING
;
775 * Accept the level 1 adjacency only if a match between local and
776 * remote area addresses is found
778 if (level
== 1 && !area_match (circuit
->area
->area_addrs
, tlvs
.area_addrs
))
780 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
782 zlog_debug ("ISIS-Adj (%s): Area mismatch, level %d IIH on %s",
783 circuit
->area
->area_tag
, level
,
784 circuit
->interface
->name
);
791 * it's own IIH PDU - discard silently
793 if (!memcmp (circuit
->u
.bc
.snpa
, ssnpa
, ETH_ALEN
))
795 zlog_debug ("ISIS-Adj (%s): it's own IIH PDU - discarded",
796 circuit
->area
->area_tag
);
803 * check if it's own interface ip match iih ip addrs
805 if (!(found
& TLVFLAG_IPV4_ADDR
)
806 || !ip_match (circuit
->ip_addrs
, tlvs
.ipv4_addrs
))
809 ("ISIS-Adj: No usable IP interface addresses in LAN IIH from %s\n",
810 circuit
->interface
->name
);
811 retval
= ISIS_WARNING
;
815 adj
= isis_adj_lookup (hdr
.source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
821 adj
= isis_new_adj (hdr
.source_id
, ssnpa
, level
, circuit
);
829 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
833 adj
->sys_type
= ISIS_SYSTYPE_L1_IS
;
837 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
839 list_delete_all_node (circuit
->u
.bc
.lan_neighs
[level
- 1]);
840 isis_adj_build_neigh_list (circuit
->u
.bc
.adjdb
[level
- 1],
841 circuit
->u
.bc
.lan_neighs
[level
- 1]);
844 if(adj
->dis_record
[level
-1].dis
==ISIS_IS_DIS
)
848 if (memcmp (circuit
->u
.bc
.l1_desig_is
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1))
850 thread_add_event (master
, isis_event_dis_status_change
, circuit
, 0);
851 memcpy (&circuit
->u
.bc
.l1_desig_is
, hdr
.lan_id
,
852 ISIS_SYS_ID_LEN
+ 1);
856 if (memcmp (circuit
->u
.bc
.l2_desig_is
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1))
858 thread_add_event (master
, isis_event_dis_status_change
, circuit
, 0);
859 memcpy (&circuit
->u
.bc
.l2_desig_is
, hdr
.lan_id
,
860 ISIS_SYS_ID_LEN
+ 1);
865 adj
->hold_time
= hdr
.hold_time
;
866 adj
->last_upd
= time (NULL
);
867 adj
->prio
[level
- 1] = hdr
.prio
;
869 memcpy (adj
->lanid
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1);
871 /* which protocol are spoken ??? */
872 if (found
& TLVFLAG_NLPID
)
873 tlvs_to_adj_nlpids (&tlvs
, adj
);
875 /* we need to copy addresses to the adj */
876 if (found
& TLVFLAG_IPV4_ADDR
)
877 tlvs_to_adj_ipv4_addrs (&tlvs
, adj
);
880 if (found
& TLVFLAG_IPV6_ADDR
)
881 tlvs_to_adj_ipv6_addrs (&tlvs
, adj
);
882 #endif /* HAVE_IPV6 */
884 adj
->circuit_t
= hdr
.circuit_t
;
886 /* lets take care of the expiry */
887 THREAD_TIMER_OFF (adj
->t_expire
);
888 THREAD_TIMER_ON (master
, adj
->t_expire
, isis_adj_expire
, adj
,
889 (long) adj
->hold_time
);
892 * If the snpa for this circuit is found from LAN Neighbours TLV
893 * we have two-way communication -> adjacency can be put to state "up"
896 if (found
& TLVFLAG_LAN_NEIGHS
)
898 if (adj
->adj_state
!= ISIS_ADJ_UP
)
900 for (ALL_LIST_ELEMENTS_RO (tlvs
.lan_neighs
, node
, snpa
))
901 if (!memcmp (snpa
, circuit
->u
.bc
.snpa
, ETH_ALEN
))
903 isis_adj_state_change (adj
, ISIS_ADJ_UP
,
904 "own SNPA found in LAN Neighbours TLV");
910 /* DEBUG_ADJ_PACKETS */
911 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
913 /* FIXME: is this place right? fix missing info */
914 zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "
915 "cirID %u, length %ld",
916 circuit
->area
->area_tag
,
917 level
, snpa_print (ssnpa
), circuit
->interface
->name
,
918 circuit_t2string (circuit
->circuit_is_type
),
920 /* FIXME: use %z when we stop supporting old compilers. */
921 (unsigned long) stream_get_endp (circuit
->rcv_stream
));
930 * Process Level 1/2 Link State
932 * Section 7.3.15.1 - Action on receipt of a link state PDU
935 process_lsp (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
937 struct isis_link_state_hdr
*hdr
;
938 struct isis_adjacency
*adj
= NULL
;
939 struct isis_lsp
*lsp
, *lsp0
= NULL
;
940 int retval
= ISIS_OK
, comp
= 0;
941 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
942 struct isis_passwd
*passwd
;
944 /* Sanity check - FIXME: move to correct place */
945 if ((stream_get_endp (circuit
->rcv_stream
) -
946 stream_get_getp (circuit
->rcv_stream
)) < ISIS_LSP_HDR_LEN
)
948 zlog_warn ("Packet too short");
952 /* Reference the header */
953 hdr
= (struct isis_link_state_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
955 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
957 zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "
958 "lifetime %us, len %lu, on %s",
959 circuit
->area
->area_tag
,
961 rawlspid_print (hdr
->lsp_id
),
962 ntohl (hdr
->seq_num
),
963 ntohs (hdr
->checksum
),
964 ntohs (hdr
->rem_lifetime
),
965 /* FIXME: use %z when we stop supporting old compilers. */
966 (unsigned long) stream_get_endp (circuit
->rcv_stream
),
967 circuit
->interface
->name
);
970 assert (ntohs (hdr
->pdu_len
) > ISIS_LSP_HDR_LEN
);
972 /* Checksum sanity check - FIXME: move to correct place */
973 /* 12 = sysid+pdu+remtime */
974 if (iso_csum_verify (STREAM_PNT (circuit
->rcv_stream
) + 4,
975 ntohs (hdr
->pdu_len
) - 12, &hdr
->checksum
))
977 zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
978 circuit
->area
->area_tag
,
979 rawlspid_print (hdr
->lsp_id
), ntohs (hdr
->checksum
));
984 /* 7.3.15.1 a) 1 - external domain circuit will discard lsps */
985 if (circuit
->ext_domain
)
988 ("ISIS-Upd (%s): LSP %s received at level %d over circuit with "
989 "externalDomain = true", circuit
->area
->area_tag
,
990 rawlspid_print (hdr
->lsp_id
), level
);
995 /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
996 if (!accept_level (level
, circuit
->circuit_is_type
))
998 zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of"
1000 circuit
->area
->area_tag
,
1001 rawlspid_print (hdr
->lsp_id
),
1002 level
, circuit_t2string (circuit
->circuit_is_type
));
1004 return ISIS_WARNING
;
1007 /* 7.3.15.1 a) 4 - need to make sure IDLength matches */
1009 /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */
1011 /* 7.3.15.1 a) 7 - password check */
1012 (level
== ISIS_LEVEL1
) ? (passwd
= &circuit
->area
->area_passwd
) :
1013 (passwd
= &circuit
->area
->domain_passwd
);
1016 if (isis_lsp_authinfo_check (circuit
->rcv_stream
, circuit
->area
,
1017 ntohs (hdr
->pdu_len
), passwd
))
1019 isis_event_auth_failure (circuit
->area
->area_tag
,
1020 "LSP authentication failure", hdr
->lsp_id
);
1021 return ISIS_WARNING
;
1024 /* Find the LSP in our database and compare it to this Link State header */
1025 lsp
= lsp_search (hdr
->lsp_id
, circuit
->area
->lspdb
[level
- 1]);
1027 comp
= lsp_compare (circuit
->area
->area_tag
, lsp
, hdr
->seq_num
,
1028 hdr
->checksum
, hdr
->rem_lifetime
);
1029 if (lsp
&& (lsp
->own_lsp
1030 #ifdef TOPOLOGY_GENERATE
1031 || lsp
->from_topology
1032 #endif /* TOPOLOGY_GENERATE */
1036 /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level */
1037 /* for broadcast circuits, snpa should be compared */
1038 /* FIXME : Point To Point */
1040 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1042 adj
= isis_adj_lookup_snpa (ssnpa
, circuit
->u
.bc
.adjdb
[level
- 1]);
1045 zlog_debug ("(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, "
1046 "lifetime %us on %s",
1047 circuit
->area
->area_tag
,
1048 rawlspid_print (hdr
->lsp_id
),
1049 ntohl (hdr
->seq_num
),
1050 ntohs (hdr
->checksum
),
1051 ntohs (hdr
->rem_lifetime
), circuit
->interface
->name
);
1052 return ISIS_WARNING
; /* Silently discard */
1056 /* for non broadcast, we just need to find same level adj */
1059 /* If no adj, or no sharing of level */
1060 if (!circuit
->u
.p2p
.neighbor
)
1062 return ISIS_OK
; /* Silently discard */
1066 if (((level
== 1) &&
1067 (circuit
->u
.p2p
.neighbor
->adj_usage
== ISIS_ADJ_LEVEL2
)) ||
1069 (circuit
->u
.p2p
.neighbor
->adj_usage
== ISIS_ADJ_LEVEL1
)))
1070 return ISIS_WARNING
; /* Silently discard */
1074 /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */
1076 /* 7.3.15.1 a) 8 - Passwords for level 2 - not implemented */
1078 /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented FIXME: do it */
1080 /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */
1081 if (hdr
->rem_lifetime
== 0)
1085 /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't save */
1086 /* only needed on explicit update, eg - p2p */
1087 if (circuit
->circ_type
== CIRCUIT_T_P2P
)
1088 ack_lsp (hdr
, circuit
, level
);
1089 return retval
; /* FIXME: do we need a purge? */
1093 if (memcmp (hdr
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
1095 /* LSP by some other system -> do 7.3.16.4 b) */
1096 /* 7.3.16.4 b) 1) */
1097 if (comp
== LSP_NEWER
)
1099 lsp_update (lsp
, hdr
, circuit
->rcv_stream
, circuit
->area
,
1102 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1104 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1106 ISIS_FLAGS_CLEAR_ALL (lsp
->SSNflags
); /* FIXME: OTHER than c */
1108 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1109 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1111 } /* 7.3.16.4 b) 2) */
1112 else if (comp
== LSP_EQUAL
)
1115 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1117 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1118 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1119 } /* 7.3.16.4 b) 3) */
1122 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1123 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1128 /* our own LSP -> 7.3.16.4 c) */
1129 if (LSP_PSEUDO_ID (lsp
->lsp_header
->lsp_id
) !=
1131 || (LSP_PSEUDO_ID (lsp
->lsp_header
->lsp_id
) ==
1133 && circuit
->u
.bc
.is_dr
[level
- 1] == 1))
1135 lsp
->lsp_header
->seq_num
= htonl (ntohl (hdr
->seq_num
) + 1);
1136 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1137 zlog_debug ("LSP LEN: %d",
1138 ntohs (lsp
->lsp_header
->pdu_len
));
1139 fletcher_checksum (STREAM_DATA (lsp
->pdu
) + 12,
1140 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
1141 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1142 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1143 zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new "
1144 "seq 0x%08x", circuit
->area
->area_tag
,
1145 rawlspid_print (hdr
->lsp_id
),
1146 ntohl (lsp
->lsp_header
->seq_num
));
1147 lsp
->lsp_header
->rem_lifetime
=
1149 (circuit
->area
->max_lsp_lifetime
[level
- 1],
1154 /* Got purge for own pseudo-lsp, and we are not DR */
1155 lsp_purge_dr (lsp
->lsp_header
->lsp_id
, circuit
, level
);
1161 /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a
1163 if (memcmp (hdr
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
) == 0)
1167 /* 7.3.16.4: initiate a purge */
1168 lsp_purge_non_exist (hdr
, circuit
->area
);
1171 /* 7.3.15.1 d) - If this is our own lsp and we have it */
1173 /* In 7.3.16.1, If an Intermediate system R somewhere in the domain
1174 * has information that the current sequence number for source S is
1175 * "greater" than that held by S, ... */
1177 else if (ntohl (hdr
->seq_num
) > ntohl (lsp
->lsp_header
->seq_num
))
1180 lsp
->lsp_header
->seq_num
= htonl (ntohl (hdr
->seq_num
) + 1);
1182 fletcher_checksum (STREAM_DATA (lsp
->pdu
) + 12,
1183 ntohs (lsp
->lsp_header
->pdu_len
) - 12, 12);
1185 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1186 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1187 zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq "
1188 "0x%08x", circuit
->area
->area_tag
,
1189 rawlspid_print (hdr
->lsp_id
),
1190 ntohl (lsp
->lsp_header
->seq_num
));
1191 lsp
->lsp_header
->rem_lifetime
=
1193 (circuit
->area
->max_lsp_lifetime
[level
- 1],
1199 /* 7.3.15.1 e) - This lsp originated on another system */
1201 /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */
1202 if ((!lsp
|| comp
== LSP_NEWER
))
1204 int regenerate
= (lsp
== NULL
);
1208 #ifdef EXTREME_DEBUG
1209 zlog_debug ("level %d number is - %ld", level
,
1210 circuit
->area
->lspdb
[level
- 1]->dict_nodecount
);
1211 #endif /* EXTREME DEBUG */
1212 lsp_search_and_destroy (hdr
->lsp_id
,
1213 circuit
->area
->lspdb
[level
- 1]);
1214 /* exists, so we overwrite */
1215 #ifdef EXTREME_DEBUG
1216 zlog_debug ("level %d number is - %ld", level
,
1217 circuit
->area
->lspdb
[level
- 1]->dict_nodecount
);
1218 #endif /* EXTREME DEBUG */
1221 * If this lsp is a frag, need to see if we have zero lsp present
1223 if (LSP_FRAGMENT (hdr
->lsp_id
) != 0)
1225 memcpy (lspid
, hdr
->lsp_id
, ISIS_SYS_ID_LEN
+ 1);
1226 LSP_FRAGMENT (lspid
) = 0;
1227 lsp0
= lsp_search (lspid
, circuit
->area
->lspdb
[level
- 1]);
1230 zlog_debug ("Got lsp frag, while zero lsp not database");
1235 lsp_new_from_stream_ptr (circuit
->rcv_stream
,
1236 ntohs (hdr
->pdu_len
), lsp0
,
1239 lsp_insert (lsp
, circuit
->area
->lspdb
[level
- 1]);
1241 ISIS_FLAGS_SET_ALL (lsp
->SRMflags
);
1243 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1246 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1247 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1249 if (regenerate
&& circuit
->u
.bc
.is_dr
[level
- 1]) {
1250 lsp_l1_pseudo_generate (circuit
);
1253 /* 7.3.15.1 e) 2) LSP equal to the one in db */
1254 else if (comp
== LSP_EQUAL
)
1256 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1257 lsp_update (lsp
, hdr
, circuit
->rcv_stream
, circuit
->area
, level
);
1258 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1260 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1263 /* 7.3.15.1 e) 3) LSP older than the one in db */
1266 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1267 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1275 * Process Sequence Numbers
1277 * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU
1281 process_snp (int snp_type
, int level
, struct isis_circuit
*circuit
,
1284 int retval
= ISIS_OK
;
1286 char typechar
= ' ';
1288 struct isis_adjacency
*adj
;
1289 struct isis_complete_seqnum_hdr
*chdr
= NULL
;
1290 struct isis_partial_seqnum_hdr
*phdr
= NULL
;
1291 uint32_t found
= 0, expected
= 0;
1292 struct isis_lsp
*lsp
;
1293 struct lsp_entry
*entry
;
1294 struct listnode
*node
, *nnode
;
1295 struct listnode
*node2
, *nnode2
;
1297 struct list
*lsp_list
= NULL
;
1298 struct isis_passwd
*passwd
;
1300 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1302 /* getting the header info */
1305 (struct isis_complete_seqnum_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
1306 circuit
->rcv_stream
->getp
+= ISIS_CSNP_HDRLEN
;
1307 len
= ntohs (chdr
->pdu_len
);
1308 if (len
< ISIS_CSNP_HDRLEN
)
1310 zlog_warn ("Received a CSNP with bogus length!");
1318 (struct isis_partial_seqnum_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
1319 circuit
->rcv_stream
->getp
+= ISIS_PSNP_HDRLEN
;
1320 len
= ntohs (phdr
->pdu_len
);
1321 if (len
< ISIS_PSNP_HDRLEN
)
1323 zlog_warn ("Received a CSNP with bogus length!");
1328 /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */
1329 if (circuit
->ext_domain
)
1332 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1333 "skipping: circuit externalDomain = true",
1334 circuit
->area
->area_tag
,
1335 level
, typechar
, circuit
->interface
->name
);
1340 /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
1341 if (!accept_level (level
, circuit
->circuit_is_type
))
1344 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1345 "skipping: circuit type %s does not match level %d",
1346 circuit
->area
->area_tag
,
1349 circuit
->interface
->name
,
1350 circuit_t2string (circuit
->circuit_is_type
), level
);
1355 /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */
1356 if ((snp_type
== ISIS_SNP_PSNP_FLAG
) &&
1357 (circuit
->circ_type
== CIRCUIT_T_BROADCAST
))
1359 if (!circuit
->u
.bc
.is_dr
[level
- 1])
1362 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
1363 "skipping: we are not the DIS",
1364 circuit
->area
->area_tag
,
1366 typechar
, snpa_print (ssnpa
), circuit
->interface
->name
);
1372 /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */
1374 /* 7.3.15.2 a) 6 - maximum area match, can be ommited since we only use 3
1375 * - already checked */
1377 /* 7.3.15.2 a) 7 - Must check that we have an adjacency of the same level */
1378 /* for broadcast circuits, snpa should be compared */
1379 /* FIXME : Do we need to check SNPA? */
1380 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1382 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1385 isis_adj_lookup (chdr
->source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
1389 /* a psnp on a broadcast, how lovely of Juniper :) */
1391 isis_adj_lookup (phdr
->source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
1394 return ISIS_OK
; /* Silently discard */
1398 if (!circuit
->u
.p2p
.neighbor
)
1399 return ISIS_OK
; /* Silently discard */
1402 /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */
1404 /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */
1406 memset (&tlvs
, 0, sizeof (struct tlvs
));
1409 expected
|= TLVFLAG_LSP_ENTRIES
;
1410 expected
|= TLVFLAG_AUTH_INFO
;
1411 retval
= parse_tlvs (circuit
->area
->area_tag
,
1412 STREAM_PNT (circuit
->rcv_stream
),
1413 len
- circuit
->rcv_stream
->getp
,
1414 &expected
, &found
, &tlvs
);
1416 if (retval
> ISIS_WARNING
)
1418 zlog_warn ("something went very wrong processing SNP");
1424 passwd
= &circuit
->area
->area_passwd
;
1426 passwd
= &circuit
->area
->domain_passwd
;
1428 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_RECV
))
1432 if (!(found
& TLVFLAG_AUTH_INFO
) ||
1433 authentication_check (&tlvs
.auth_info
, passwd
, circuit
))
1435 isis_event_auth_failure (circuit
->area
->area_tag
,
1436 "SNP authentication" " failure",
1437 phdr
? phdr
->source_id
: chdr
->source_id
);
1443 /* debug isis snp-packets */
1444 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
1446 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s",
1447 circuit
->area
->area_tag
,
1449 typechar
, snpa_print (ssnpa
), circuit
->interface
->name
);
1450 if (tlvs
.lsp_entries
)
1452 for (ALL_LIST_ELEMENTS_RO (tlvs
.lsp_entries
, node
, entry
))
1454 zlog_debug ("ISIS-Snp (%s): %cSNP entry %s, seq 0x%08x,"
1455 " cksum 0x%04x, lifetime %us",
1456 circuit
->area
->area_tag
,
1458 rawlspid_print (entry
->lsp_id
),
1459 ntohl (entry
->seq_num
),
1460 ntohs (entry
->checksum
), ntohs (entry
->rem_lifetime
));
1465 /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */
1466 if (tlvs
.lsp_entries
)
1468 for (ALL_LIST_ELEMENTS_RO (tlvs
.lsp_entries
, node
, entry
))
1470 lsp
= lsp_search (entry
->lsp_id
, circuit
->area
->lspdb
[level
- 1]);
1471 own_lsp
= !memcmp (entry
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1474 /* 7.3.15.2 b) 1) is this LSP newer */
1475 cmp
= lsp_compare (circuit
->area
->area_tag
, lsp
, entry
->seq_num
,
1476 entry
->checksum
, entry
->rem_lifetime
);
1477 /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */
1478 if (cmp
== LSP_EQUAL
)
1480 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1481 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1482 /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
1484 else if (cmp
== LSP_OLDER
)
1486 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1487 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1491 /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM
1495 lsp_inc_seqnum (lsp
, ntohl (entry
->seq_num
));
1496 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1500 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1501 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1502 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1508 /* 7.3.15.2 b) 5) if it was not found, and all of those are not 0,
1509 * insert it and set SSN on it */
1510 if (entry
->rem_lifetime
&& entry
->checksum
&& entry
->seq_num
&&
1511 memcmp (entry
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
1513 lsp
= lsp_new (entry
->lsp_id
, ntohs (entry
->rem_lifetime
),
1514 0, 0, entry
->checksum
, level
);
1515 lsp_insert (lsp
, circuit
->area
->lspdb
[level
- 1]);
1516 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1522 /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported */
1523 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1526 * Build a list from our own LSP db bounded with start_ and stop_lsp_id
1528 lsp_list
= list_new ();
1529 lsp_build_list_nonzero_ht (chdr
->start_lsp_id
, chdr
->stop_lsp_id
,
1530 lsp_list
, circuit
->area
->lspdb
[level
- 1]);
1532 /* Fixme: Find a better solution */
1533 if (tlvs
.lsp_entries
)
1535 for (ALL_LIST_ELEMENTS (tlvs
.lsp_entries
, node
, nnode
, entry
))
1537 for (ALL_LIST_ELEMENTS (lsp_list
, node2
, nnode2
, lsp
))
1539 if (lsp_id_cmp (lsp
->lsp_header
->lsp_id
, entry
->lsp_id
) == 0)
1541 list_delete_node (lsp_list
, node2
);
1547 /* on remaining LSPs we set SRM (neighbor knew not of) */
1548 for (ALL_LIST_ELEMENTS_RO (lsp_list
, node
, lsp
))
1550 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1553 list_free (lsp_list
);
1561 process_csnp (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
1563 /* Sanity check - FIXME: move to correct place */
1564 if ((stream_get_endp (circuit
->rcv_stream
) -
1565 stream_get_getp (circuit
->rcv_stream
)) < ISIS_CSNP_HDRLEN
)
1567 zlog_warn ("Packet too short ( < %d)", ISIS_CSNP_HDRLEN
);
1568 return ISIS_WARNING
;
1571 return process_snp (ISIS_SNP_CSNP_FLAG
, level
, circuit
, ssnpa
);
1575 process_psnp (int level
, struct isis_circuit
*circuit
, u_char
* ssnpa
)
1577 if ((stream_get_endp (circuit
->rcv_stream
) -
1578 stream_get_getp (circuit
->rcv_stream
)) < ISIS_PSNP_HDRLEN
)
1580 zlog_warn ("Packet too short");
1581 return ISIS_WARNING
;
1584 return process_snp (ISIS_SNP_PSNP_FLAG
, level
, circuit
, ssnpa
);
1590 * Section 8.2.2 - Receiving ISH PDUs by an intermediate system
1591 * FIXME: sample packet dump, need to figure 0x81 - looks like NLPid
1592 * 0x82 0x15 0x01 0x00 0x04 0x01 0x2c 0x59
1593 * 0x38 0x08 0x47 0x00 0x01 0x00 0x02 0x00
1594 * 0x03 0x00 0x81 0x01 0xcc
1597 process_is_hello (struct isis_circuit
*circuit
)
1599 struct isis_adjacency
*adj
;
1600 int retval
= ISIS_OK
;
1604 /* In this point in time we are not yet able to handle is_hellos
1605 * on lan - Sorry juniper...
1607 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1610 neigh_len
= stream_getc (circuit
->rcv_stream
);
1611 sysid
= STREAM_PNT (circuit
->rcv_stream
) + neigh_len
- 1 - ISIS_SYS_ID_LEN
;
1612 adj
= circuit
->u
.p2p
.neighbor
;
1616 adj
= isis_new_adj (sysid
, NULL
, 0, circuit
);
1620 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
1621 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
1622 circuit
->u
.p2p
.neighbor
= adj
;
1625 if ((adj
->adj_state
== ISIS_ADJ_UP
) && memcmp (adj
->sysid
, sysid
,
1628 /* 8.2.2 a) 1) FIXME: adjStateChange(down) event */
1629 /* 8.2.2 a) 2) delete the adj */
1630 XFREE (MTYPE_ISIS_ADJACENCY
, adj
);
1631 /* 8.2.2 a) 3) create a new adj */
1632 adj
= isis_new_adj (sysid
, NULL
, 0, circuit
);
1637 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
1638 /* 8.2.2 a) 3) ii */
1639 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
1640 /* 8.2.2 a) 4) quite meaningless */
1642 /* 8.2.2 b) ignore on condition */
1643 if ((adj
->adj_state
== ISIS_ADJ_INITIALIZING
) &&
1644 (adj
->sys_type
== ISIS_SYSTYPE_IS
))
1650 /* 8.2.2 c) respond with a p2p IIH */
1651 send_hello (circuit
, 1);
1653 /* 8.2.2 d) type is IS */
1654 adj
->sys_type
= ISIS_SYSTYPE_IS
;
1655 /* 8.2.2 e) FIXME: Circuit type of? */
1665 isis_handle_pdu (struct isis_circuit
*circuit
, u_char
* ssnpa
)
1667 struct isis_fixed_hdr
*hdr
;
1668 struct esis_fixed_hdr
*esis_hdr
;
1670 int retval
= ISIS_OK
;
1673 * Let's first read data from stream to the header
1675 hdr
= (struct isis_fixed_hdr
*) STREAM_DATA (circuit
->rcv_stream
);
1677 if ((hdr
->idrp
!= ISO10589_ISIS
) && (hdr
->idrp
!= ISO9542_ESIS
))
1679 zlog_warn ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr
->idrp
);
1683 /* now we need to know if this is an ISO 9542 packet and
1684 * take real good care of it, waaa!
1686 if (hdr
->idrp
== ISO9542_ESIS
)
1688 esis_hdr
= (struct esis_fixed_hdr
*) STREAM_DATA (circuit
->rcv_stream
);
1689 stream_set_getp (circuit
->rcv_stream
, ESIS_FIXED_HDR_LEN
);
1690 /* FIXME: Need to do some acceptence tests */
1691 /* example length... */
1692 switch (esis_hdr
->pdu_type
)
1698 zlog_debug ("AN ISH PDU!!");
1699 retval
= process_is_hello (circuit
);
1708 stream_set_getp (circuit
->rcv_stream
, ISIS_FIXED_HDR_LEN
);
1711 * and then process it
1714 if (hdr
->length
< ISIS_MINIMUM_FIXED_HDR_LEN
)
1716 zlog_err ("Fixed header length = %d", hdr
->length
);
1720 if (hdr
->version1
!= 1)
1722 zlog_warn ("Unsupported ISIS version %u", hdr
->version1
);
1723 return ISIS_WARNING
;
1726 if ((hdr
->id_len
!= 0) && (hdr
->id_len
!= ISIS_SYS_ID_LEN
))
1729 ("IDFieldLengthMismatch: ID Length field in a received PDU %u, "
1730 "while the parameter for this IS is %u", hdr
->id_len
,
1735 if (hdr
->version2
!= 1)
1737 zlog_warn ("Unsupported ISIS version %u", hdr
->version2
);
1738 return ISIS_WARNING
;
1741 if ((hdr
->max_area_addrs
!= 0)
1742 && (hdr
->max_area_addrs
!= isis
->max_area_addrs
))
1744 zlog_err ("maximumAreaAddressesMismatch: maximumAreaAdresses in a "
1745 "received PDU %u while the parameter for this IS is %u",
1746 hdr
->max_area_addrs
, isis
->max_area_addrs
);
1750 switch (hdr
->pdu_type
)
1753 retval
= process_lan_hello (ISIS_LEVEL1
, circuit
, ssnpa
);
1756 retval
= process_lan_hello (ISIS_LEVEL2
, circuit
, ssnpa
);
1759 retval
= process_p2p_hello (circuit
);
1762 retval
= process_lsp (ISIS_LEVEL1
, circuit
, ssnpa
);
1765 retval
= process_lsp (ISIS_LEVEL2
, circuit
, ssnpa
);
1767 case L1_COMPLETE_SEQ_NUM
:
1768 retval
= process_csnp (ISIS_LEVEL1
, circuit
, ssnpa
);
1770 case L2_COMPLETE_SEQ_NUM
:
1771 retval
= process_csnp (ISIS_LEVEL2
, circuit
, ssnpa
);
1773 case L1_PARTIAL_SEQ_NUM
:
1774 retval
= process_psnp (ISIS_LEVEL1
, circuit
, ssnpa
);
1776 case L2_PARTIAL_SEQ_NUM
:
1777 retval
= process_psnp (ISIS_LEVEL2
, circuit
, ssnpa
);
1788 isis_receive (struct thread
*thread
)
1790 struct isis_circuit
*circuit
;
1791 u_char ssnpa
[ETH_ALEN
];
1797 circuit
= THREAD_ARG (thread
);
1803 if (circuit
->rcv_stream
== NULL
)
1804 circuit
->rcv_stream
= stream_new (ISO_MTU (circuit
));
1806 stream_reset (circuit
->rcv_stream
);
1808 retval
= circuit
->rx (circuit
, ssnpa
);
1809 circuit
->t_read
= NULL
;
1811 if (retval
== ISIS_OK
)
1812 retval
= isis_handle_pdu (circuit
, ssnpa
);
1815 * prepare for next packet.
1817 THREAD_READ_ON (master
, circuit
->t_read
, isis_receive
, circuit
,
1825 isis_receive (struct thread
*thread
)
1827 struct isis_circuit
*circuit
;
1828 u_char ssnpa
[ETH_ALEN
];
1834 circuit
= THREAD_ARG (thread
);
1837 circuit
->t_read
= NULL
;
1839 if (circuit
->rcv_stream
== NULL
)
1840 circuit
->rcv_stream
= stream_new (ISO_MTU (circuit
));
1842 stream_reset (circuit
->rcv_stream
);
1844 retval
= circuit
->rx (circuit
, ssnpa
);
1846 if (retval
== ISIS_OK
)
1847 retval
= isis_handle_pdu (circuit
, ssnpa
);
1850 * prepare for next packet.
1852 circuit
->t_read
= thread_add_timer_msec (master
, isis_receive
, circuit
,
1854 (circuit
->area
->circuit_list
) *
1862 /* filling of the fixed isis header */
1864 fill_fixed_hdr (struct isis_fixed_hdr
*hdr
, u_char pdu_type
)
1866 memset (hdr
, 0, sizeof (struct isis_fixed_hdr
));
1868 hdr
->idrp
= ISO10589_ISIS
;
1874 hdr
->length
= ISIS_LANHELLO_HDRLEN
;
1877 hdr
->length
= ISIS_P2PHELLO_HDRLEN
;
1881 hdr
->length
= ISIS_LSP_HDR_LEN
;
1883 case L1_COMPLETE_SEQ_NUM
:
1884 case L2_COMPLETE_SEQ_NUM
:
1885 hdr
->length
= ISIS_CSNP_HDRLEN
;
1887 case L1_PARTIAL_SEQ_NUM
:
1888 case L2_PARTIAL_SEQ_NUM
:
1889 hdr
->length
= ISIS_PSNP_HDRLEN
;
1892 zlog_warn ("fill_fixed_hdr(): unknown pdu type %d", pdu_type
);
1895 hdr
->length
+= ISIS_FIXED_HDR_LEN
;
1896 hdr
->pdu_type
= pdu_type
;
1898 hdr
->id_len
= 0; /* ISIS_SYS_ID_LEN - 0==6 */
1900 hdr
->max_area_addrs
= 0; /* isis->max_area_addrs - 0==3 */
1907 fill_fixed_hdr_andstream (struct isis_fixed_hdr
*hdr
, u_char pdu_type
,
1908 struct stream
*stream
)
1910 fill_fixed_hdr (hdr
, pdu_type
);
1912 stream_putc (stream
, hdr
->idrp
);
1913 stream_putc (stream
, hdr
->length
);
1914 stream_putc (stream
, hdr
->version1
);
1915 stream_putc (stream
, hdr
->id_len
);
1916 stream_putc (stream
, hdr
->pdu_type
);
1917 stream_putc (stream
, hdr
->version2
);
1918 stream_putc (stream
, hdr
->reserved
);
1919 stream_putc (stream
, hdr
->max_area_addrs
);
1925 send_hello (struct isis_circuit
*circuit
, int level
)
1927 struct isis_fixed_hdr fixed_hdr
;
1928 struct isis_lan_hello_hdr hello_hdr
;
1929 struct isis_p2p_hello_hdr p2p_hello_hdr
;
1930 char hmac_md5_hash
[ISIS_AUTH_MD5_SIZE
];
1933 unsigned long len_pointer
, length
, auth_tlv
;
1936 if (circuit
->state
!= C_STATE_UP
|| circuit
->interface
== NULL
)
1937 return ISIS_WARNING
;
1939 if (circuit
->interface
->mtu
== 0)
1941 zlog_warn ("circuit has zero MTU");
1942 return ISIS_WARNING
;
1945 if (!circuit
->snd_stream
)
1946 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
1948 stream_reset (circuit
->snd_stream
);
1950 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1952 fill_fixed_hdr_andstream (&fixed_hdr
, L1_LAN_HELLO
,
1953 circuit
->snd_stream
);
1955 fill_fixed_hdr_andstream (&fixed_hdr
, L2_LAN_HELLO
,
1956 circuit
->snd_stream
);
1958 fill_fixed_hdr_andstream (&fixed_hdr
, P2P_HELLO
, circuit
->snd_stream
);
1961 * Fill LAN Level 1 or 2 Hello PDU header
1963 memset (&hello_hdr
, 0, sizeof (struct isis_lan_hello_hdr
));
1964 interval
= circuit
->hello_multiplier
[level
- 1] *
1965 circuit
->hello_interval
[level
- 1];
1966 /* If we are the DIS then hello interval is divided by three, as is the hold-timer */
1967 if (circuit
->u
.bc
.is_dr
[level
- 1])
1968 interval
=interval
/3;
1969 if (interval
> USHRT_MAX
)
1970 interval
= USHRT_MAX
;
1971 hello_hdr
.circuit_t
= circuit
->circuit_is_type
;
1972 memcpy (hello_hdr
.source_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1973 hello_hdr
.hold_time
= htons ((u_int16_t
) interval
);
1975 hello_hdr
.pdu_len
= 0; /* Update the PDU Length later */
1976 len_pointer
= stream_get_endp (circuit
->snd_stream
) + 3 + ISIS_SYS_ID_LEN
;
1978 /* copy the shared part of the hello to the p2p hello if needed */
1979 if (circuit
->circ_type
== CIRCUIT_T_P2P
)
1981 memcpy (&p2p_hello_hdr
, &hello_hdr
, 5 + ISIS_SYS_ID_LEN
);
1982 p2p_hello_hdr
.local_id
= circuit
->circuit_id
;
1983 /* FIXME: need better understanding */
1984 stream_put (circuit
->snd_stream
, &p2p_hello_hdr
, ISIS_P2PHELLO_HDRLEN
);
1988 hello_hdr
.prio
= circuit
->u
.bc
.priority
[level
- 1];
1989 if (level
== 1 && circuit
->u
.bc
.l1_desig_is
)
1991 memcpy (hello_hdr
.lan_id
, circuit
->u
.bc
.l1_desig_is
,
1992 ISIS_SYS_ID_LEN
+ 1);
1994 else if (level
== 2 && circuit
->u
.bc
.l2_desig_is
)
1996 memcpy (hello_hdr
.lan_id
, circuit
->u
.bc
.l2_desig_is
,
1997 ISIS_SYS_ID_LEN
+ 1);
1999 stream_put (circuit
->snd_stream
, &hello_hdr
, ISIS_LANHELLO_HDRLEN
);
2003 * Then the variable length part
2006 /* add circuit password */
2008 if (circuit
->passwd
.type
== ISIS_PASSWD_TYPE_CLEARTXT
)
2009 if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT
, circuit
->passwd
.len
,
2010 circuit
->passwd
.passwd
, circuit
->snd_stream
))
2011 return ISIS_WARNING
;
2014 if (circuit
->passwd
.type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
2016 /* Remember where TLV is written so we can later overwrite the MD5 hash */
2017 auth_tlv
= stream_get_endp (circuit
->snd_stream
);
2018 memset(&hmac_md5_hash
, 0, ISIS_AUTH_MD5_SIZE
);
2019 if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5
, ISIS_AUTH_MD5_SIZE
,
2020 hmac_md5_hash
, circuit
->snd_stream
))
2021 return ISIS_WARNING
;
2024 /* Protocols Supported TLV */
2025 if (circuit
->nlpids
.count
> 0)
2026 if (tlv_add_nlpid (&circuit
->nlpids
, circuit
->snd_stream
))
2027 return ISIS_WARNING
;
2029 /* Area Addresses TLV */
2030 assert (circuit
->area
);
2031 if (circuit
->area
->area_addrs
&& circuit
->area
->area_addrs
->count
> 0)
2032 if (tlv_add_area_addrs (circuit
->area
->area_addrs
, circuit
->snd_stream
))
2033 return ISIS_WARNING
;
2035 /* IP interface Address TLV */
2036 if (circuit
->ip_router
&& circuit
->ip_addrs
&& circuit
->ip_addrs
->count
> 0)
2037 if (tlv_add_ip_addrs (circuit
->ip_addrs
, circuit
->snd_stream
))
2038 return ISIS_WARNING
;
2041 /* IPv6 Interface Address TLV */
2042 if (circuit
->ipv6_router
&& circuit
->ipv6_link
&&
2043 circuit
->ipv6_link
->count
> 0)
2044 if (tlv_add_ipv6_addrs (circuit
->ipv6_link
, circuit
->snd_stream
))
2045 return ISIS_WARNING
;
2046 #endif /* HAVE_IPV6 */
2048 /* Restart signaling, vendor C sends it too */
2049 retval
= add_tlv (211, 3, 0, circuit
->snd_stream
);
2051 /* LAN Neighbors TLV */
2052 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
2054 if (level
== 1 && circuit
->u
.bc
.lan_neighs
[0]->count
> 0)
2055 if (tlv_add_lan_neighs (circuit
->u
.bc
.lan_neighs
[0],
2056 circuit
->snd_stream
))
2057 return ISIS_WARNING
;
2058 if (level
== 2 && circuit
->u
.bc
.lan_neighs
[1]->count
> 0)
2059 if (tlv_add_lan_neighs (circuit
->u
.bc
.lan_neighs
[1],
2060 circuit
->snd_stream
))
2061 return ISIS_WARNING
;
2064 if (circuit
->u
.bc
.pad_hellos
)
2065 if (tlv_add_padding (circuit
->snd_stream
))
2066 return ISIS_WARNING
;
2068 length
= stream_get_endp (circuit
->snd_stream
);
2069 /* Update PDU length */
2070 stream_putw_at (circuit
->snd_stream
, len_pointer
, (u_int16_t
) length
);
2072 /* For HMAC MD5 we need to compute the md5 hash and store it */
2073 if (circuit
->passwd
.type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
2075 hmac_md5(circuit
->snd_stream
->data
, stream_get_endp(circuit
->snd_stream
), (unsigned char *) &circuit
->passwd
.passwd
, circuit
->passwd
.len
, (unsigned char *) &hmac_md5_hash
);
2076 /* Copy the hash into the stream */
2077 memcpy(circuit
->snd_stream
->data
+auth_tlv
+3,hmac_md5_hash
,ISIS_AUTH_MD5_SIZE
);
2080 retval
= circuit
->tx (circuit
, level
);
2082 zlog_warn ("sending of LAN Level %d Hello failed", level
);
2084 /* DEBUG_ADJ_PACKETS */
2085 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
2087 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
2089 zlog_debug ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %ld",
2090 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
2091 /* FIXME: use %z when we stop supporting old compilers. */
2092 (unsigned long) STREAM_SIZE (circuit
->snd_stream
));
2096 zlog_debug ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld",
2097 circuit
->area
->area_tag
, circuit
->interface
->name
,
2098 /* FIXME: use %z when we stop supporting old compilers. */
2099 (unsigned long) STREAM_SIZE (circuit
->snd_stream
));
2107 send_lan_hello (struct isis_circuit
*circuit
, int level
)
2109 return send_hello (circuit
, level
);
2113 send_lan_l1_hello (struct thread
*thread
)
2115 struct isis_circuit
*circuit
;
2117 unsigned long next_hello
;
2119 circuit
= THREAD_ARG (thread
);
2122 if (!circuit
->area
) {
2126 /* Pseudonode sends hellos three times more than the other nodes */
2127 if (circuit
->u
.bc
.is_dr
[0])
2128 next_hello
=circuit
->hello_interval
[0]/3+1;
2130 next_hello
=circuit
->hello_interval
[0];
2132 circuit
->u
.bc
.t_send_lan_hello
[0] = NULL
;
2134 if (circuit
->u
.bc
.run_dr_elect
[0])
2135 retval
= isis_dr_elect (circuit
, 1);
2137 retval
= send_lan_hello (circuit
, 1);
2139 /* set next timer thread */
2140 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_send_lan_hello
[0],
2141 send_lan_l1_hello
, circuit
,
2142 isis_jitter (next_hello
, IIH_JITTER
));
2148 send_lan_l2_hello (struct thread
*thread
)
2150 struct isis_circuit
*circuit
;
2152 unsigned long next_hello
;
2154 circuit
= THREAD_ARG (thread
);
2157 if (!circuit
->area
) {
2161 /* Pseudonode sends hellos three times more than the other nodes */
2162 if (circuit
->u
.bc
.is_dr
[1])
2163 next_hello
=circuit
->hello_interval
[1]/3+1;
2165 next_hello
=circuit
->hello_interval
[1];
2167 circuit
->u
.bc
.t_send_lan_hello
[1] = NULL
;
2169 if (circuit
->u
.bc
.run_dr_elect
[1])
2170 retval
= isis_dr_elect (circuit
, 2);
2172 retval
= send_lan_hello (circuit
, 2);
2174 /* set next timer thread */
2175 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_send_lan_hello
[1],
2176 send_lan_l2_hello
, circuit
,
2177 isis_jitter (next_hello
, IIH_JITTER
));
2183 send_p2p_hello (struct thread
*thread
)
2185 struct isis_circuit
*circuit
;
2187 circuit
= THREAD_ARG (thread
);
2189 circuit
->u
.p2p
.t_send_p2p_hello
= NULL
;
2191 send_hello (circuit
, 1);
2193 /* set next timer thread */
2194 THREAD_TIMER_ON (master
, circuit
->u
.p2p
.t_send_p2p_hello
, send_p2p_hello
,
2195 circuit
, isis_jitter (circuit
->hello_interval
[1],
2202 build_csnp (int level
, u_char
* start
, u_char
* stop
, struct list
*lsps
,
2203 struct isis_circuit
*circuit
)
2205 struct isis_fixed_hdr fixed_hdr
;
2206 struct isis_passwd
*passwd
;
2207 int retval
= ISIS_OK
;
2212 fill_fixed_hdr_andstream (&fixed_hdr
, L1_COMPLETE_SEQ_NUM
,
2213 circuit
->snd_stream
);
2215 fill_fixed_hdr_andstream (&fixed_hdr
, L2_COMPLETE_SEQ_NUM
,
2216 circuit
->snd_stream
);
2219 * Fill Level 1 or 2 Complete Sequence Numbers header
2222 lenp
= stream_get_endp (circuit
->snd_stream
);
2223 stream_putw (circuit
->snd_stream
, 0); /* PDU length - when we know it */
2224 /* no need to send the source here, it is always us if we csnp */
2225 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2226 /* with zero circuit id - ref 9.10, 9.11 */
2227 stream_putc (circuit
->snd_stream
, 0x00);
2229 stream_put (circuit
->snd_stream
, start
, ISIS_SYS_ID_LEN
+ 2);
2230 stream_put (circuit
->snd_stream
, stop
, ISIS_SYS_ID_LEN
+ 2);
2236 passwd
= &circuit
->area
->area_passwd
;
2238 passwd
= &circuit
->area
->domain_passwd
;
2240 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
))
2242 retval
= tlv_add_authinfo (passwd
->type
, passwd
->len
,
2243 passwd
->passwd
, circuit
->snd_stream
);
2245 if (!retval
&& lsps
)
2247 retval
= tlv_add_lsp_entries (lsps
, circuit
->snd_stream
);
2249 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
2250 assert (length
>= ISIS_CSNP_HDRLEN
);
2251 /* Update PU length */
2252 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2258 * FIXME: support multiple CSNPs
2262 send_csnp (struct isis_circuit
*circuit
, int level
)
2264 int retval
= ISIS_OK
;
2265 u_char start
[ISIS_SYS_ID_LEN
+ 2];
2266 u_char stop
[ISIS_SYS_ID_LEN
+ 2];
2267 struct list
*list
= NULL
;
2268 struct listnode
*node
;
2269 struct isis_lsp
*lsp
;
2271 if (circuit
->state
!= C_STATE_UP
|| circuit
->interface
== NULL
)
2272 return ISIS_WARNING
;
2274 memset (start
, 0x00, ISIS_SYS_ID_LEN
+ 2);
2275 memset (stop
, 0xff, ISIS_SYS_ID_LEN
+ 2);
2277 if (circuit
->area
->lspdb
[level
- 1] &&
2278 dict_count (circuit
->area
->lspdb
[level
- 1]) > 0)
2281 lsp_build_list (start
, stop
, list
, circuit
->area
->lspdb
[level
- 1]);
2283 if (circuit
->snd_stream
== NULL
)
2284 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
2286 stream_reset (circuit
->snd_stream
);
2288 retval
= build_csnp (level
, start
, stop
, list
, circuit
);
2290 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2292 zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld",
2293 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
2294 /* FIXME: use %z when we stop supporting old compilers. */
2295 (unsigned long) STREAM_SIZE (circuit
->snd_stream
));
2296 for (ALL_LIST_ELEMENTS_RO (list
, node
, lsp
))
2298 zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x,"
2299 " cksum 0x%04x, lifetime %us",
2300 circuit
->area
->area_tag
,
2301 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2302 ntohl (lsp
->lsp_header
->seq_num
),
2303 ntohs (lsp
->lsp_header
->checksum
),
2304 ntohs (lsp
->lsp_header
->rem_lifetime
));
2310 if (retval
== ISIS_OK
)
2311 retval
= circuit
->tx (circuit
, level
);
2317 send_l1_csnp (struct thread
*thread
)
2319 struct isis_circuit
*circuit
;
2320 int retval
= ISIS_OK
;
2322 circuit
= THREAD_ARG (thread
);
2325 circuit
->t_send_csnp
[0] = NULL
;
2327 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
&& circuit
->u
.bc
.is_dr
[0])
2328 send_csnp (circuit
, 1);
2329 /* set next timer thread */
2330 THREAD_TIMER_ON (master
, circuit
->t_send_csnp
[0], send_l1_csnp
, circuit
,
2331 isis_jitter (circuit
->csnp_interval
[0], CSNP_JITTER
));
2337 send_l2_csnp (struct thread
*thread
)
2339 struct isis_circuit
*circuit
;
2340 int retval
= ISIS_OK
;
2342 circuit
= THREAD_ARG (thread
);
2345 circuit
->t_send_csnp
[1] = NULL
;
2347 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
&& circuit
->u
.bc
.is_dr
[1])
2348 send_csnp (circuit
, 2);
2349 /* set next timer thread */
2350 THREAD_TIMER_ON (master
, circuit
->t_send_csnp
[1], send_l2_csnp
, circuit
,
2351 isis_jitter (circuit
->csnp_interval
[1], CSNP_JITTER
));
2357 build_psnp (int level
, struct isis_circuit
*circuit
, struct list
*lsps
)
2359 struct isis_fixed_hdr fixed_hdr
;
2363 struct isis_lsp
*lsp
;
2364 struct isis_passwd
*passwd
;
2365 struct listnode
*node
;
2368 fill_fixed_hdr_andstream (&fixed_hdr
, L1_PARTIAL_SEQ_NUM
,
2369 circuit
->snd_stream
);
2371 fill_fixed_hdr_andstream (&fixed_hdr
, L2_PARTIAL_SEQ_NUM
,
2372 circuit
->snd_stream
);
2375 * Fill Level 1 or 2 Partial Sequence Numbers header
2377 lenp
= stream_get_endp (circuit
->snd_stream
);
2378 stream_putw (circuit
->snd_stream
, 0); /* PDU length - when we know it */
2379 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2380 stream_putc (circuit
->snd_stream
, circuit
->idx
);
2387 passwd
= &circuit
->area
->area_passwd
;
2389 passwd
= &circuit
->area
->domain_passwd
;
2391 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
))
2393 retval
= tlv_add_authinfo (passwd
->type
, passwd
->len
,
2394 passwd
->passwd
, circuit
->snd_stream
);
2396 if (!retval
&& lsps
)
2398 retval
= tlv_add_lsp_entries (lsps
, circuit
->snd_stream
);
2401 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2403 for (ALL_LIST_ELEMENTS_RO (lsps
, node
, lsp
))
2405 zlog_debug ("ISIS-Snp (%s): PSNP entry %s, seq 0x%08x,"
2406 " cksum 0x%04x, lifetime %us",
2407 circuit
->area
->area_tag
,
2408 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2409 ntohl (lsp
->lsp_header
->seq_num
),
2410 ntohs (lsp
->lsp_header
->checksum
),
2411 ntohs (lsp
->lsp_header
->rem_lifetime
));
2415 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
2416 assert (length
>= ISIS_PSNP_HDRLEN
);
2417 /* Update PDU length */
2418 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2424 * 7.3.15.4 action on expiration of partial SNP interval
2428 send_psnp (int level
, struct isis_circuit
*circuit
)
2430 int retval
= ISIS_OK
;
2431 struct isis_lsp
*lsp
;
2432 struct list
*list
= NULL
;
2433 struct listnode
*node
;
2435 if (circuit
->state
!= C_STATE_UP
|| circuit
->interface
== NULL
)
2436 return ISIS_WARNING
;
2438 if ((circuit
->circ_type
== CIRCUIT_T_BROADCAST
&&
2439 !circuit
->u
.bc
.is_dr
[level
- 1]) ||
2440 circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
2443 if (circuit
->area
->lspdb
[level
- 1] &&
2444 dict_count (circuit
->area
->lspdb
[level
- 1]) > 0)
2447 lsp_build_list_ssn (circuit
, list
, circuit
->area
->lspdb
[level
- 1]);
2449 if (listcount (list
) > 0)
2451 if (circuit
->snd_stream
== NULL
)
2452 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
2454 stream_reset (circuit
->snd_stream
);
2457 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2458 zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld",
2459 circuit
->area
->area_tag
, level
,
2460 circuit
->interface
->name
,
2461 /* FIXME: use %z when we stop supporting old
2463 (unsigned long) STREAM_SIZE (circuit
->snd_stream
));
2465 retval
= build_psnp (level
, circuit
, list
);
2466 if (retval
== ISIS_OK
)
2467 retval
= circuit
->tx (circuit
, level
);
2469 if (retval
== ISIS_OK
)
2472 * sending succeeded, we can clear SSN flags of this circuit
2473 * for the LSPs in list
2475 for (ALL_LIST_ELEMENTS_RO (list
, node
, lsp
))
2476 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
2487 send_l1_psnp (struct thread
*thread
)
2490 struct isis_circuit
*circuit
;
2491 int retval
= ISIS_OK
;
2493 circuit
= THREAD_ARG (thread
);
2496 circuit
->t_send_psnp
[0] = NULL
;
2498 send_psnp (1, circuit
);
2499 /* set next timer thread */
2500 THREAD_TIMER_ON (master
, circuit
->t_send_psnp
[0], send_l1_psnp
, circuit
,
2501 isis_jitter (circuit
->psnp_interval
[0], PSNP_JITTER
));
2507 * 7.3.15.4 action on expiration of partial SNP interval
2511 send_l2_psnp (struct thread
*thread
)
2513 struct isis_circuit
*circuit
;
2514 int retval
= ISIS_OK
;
2516 circuit
= THREAD_ARG (thread
);
2519 circuit
->t_send_psnp
[1] = NULL
;
2521 send_psnp (2, circuit
);
2523 /* set next timer thread */
2524 THREAD_TIMER_ON (master
, circuit
->t_send_psnp
[1], send_l2_psnp
, circuit
,
2525 isis_jitter (circuit
->psnp_interval
[1], PSNP_JITTER
));
2531 * ISO 10589 - 7.3.14.3
2534 send_lsp (struct thread
*thread
)
2536 struct isis_circuit
*circuit
;
2537 struct isis_lsp
*lsp
;
2538 struct listnode
*node
;
2541 circuit
= THREAD_ARG (thread
);
2544 if (circuit
->state
!= C_STATE_UP
|| circuit
->interface
== NULL
)
2545 return ISIS_WARNING
;
2547 lsp
= listgetdata ((node
= listhead (circuit
->lsp_queue
)));
2550 * Do not send if levels do not match
2552 if (!(lsp
->level
& circuit
->circuit_is_type
))
2556 * Do not send if we do not have adjacencies in state up on the circuit
2558 if (circuit
->upadjcount
[lsp
->level
- 1] == 0)
2560 /* only send if it needs sending */
2561 if ((time (NULL
) - lsp
->last_sent
) >=
2562 circuit
->area
->lsp_gen_interval
[lsp
->level
- 1])
2565 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
2568 ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
2569 " lifetime %us on %s", circuit
->area
->area_tag
, lsp
->level
,
2570 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2571 ntohl (lsp
->lsp_header
->seq_num
),
2572 ntohs (lsp
->lsp_header
->checksum
),
2573 ntohs (lsp
->lsp_header
->rem_lifetime
),
2574 circuit
->interface
->name
);
2576 /* copy our lsp to the send buffer */
2577 stream_copy (circuit
->snd_stream
, lsp
->pdu
);
2579 retval
= circuit
->tx (circuit
, lsp
->level
);
2582 * If the sending succeeded, we can del the lsp from circuits
2585 if (retval
== ISIS_OK
)
2587 list_delete_node (circuit
->lsp_queue
, node
);
2590 * On broadcast circuits also the SRMflag can be cleared
2592 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
2593 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
2595 if (flags_any_set (lsp
->SRMflags
) == 0)
2598 * need to remember when we were last sent
2600 lsp
->last_sent
= time (NULL
);
2605 zlog_debug ("sending of level %d link state failed", lsp
->level
);
2610 /* my belief is that if it wasn't his time, the lsp can be removed
2614 list_delete_node (circuit
->lsp_queue
, node
);
2618 * If there are still LSPs send next one after lsp-interval (33 msecs)
2620 if (listcount (circuit
->lsp_queue
) > 0)
2621 thread_add_timer (master
, send_lsp
, circuit
, 1);
2628 ack_lsp (struct isis_link_state_hdr
*hdr
, struct isis_circuit
*circuit
,
2634 struct isis_fixed_hdr fixed_hdr
;
2636 if (!circuit
->snd_stream
)
2637 circuit
->snd_stream
= stream_new (ISO_MTU (circuit
));
2639 stream_reset (circuit
->snd_stream
);
2641 // fill_llc_hdr (stream);
2643 fill_fixed_hdr_andstream (&fixed_hdr
, L1_PARTIAL_SEQ_NUM
,
2644 circuit
->snd_stream
);
2646 fill_fixed_hdr_andstream (&fixed_hdr
, L2_PARTIAL_SEQ_NUM
,
2647 circuit
->snd_stream
);
2650 lenp
= stream_get_endp (circuit
->snd_stream
);
2651 stream_putw (circuit
->snd_stream
, 0); /* PDU length */
2652 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2653 stream_putc (circuit
->snd_stream
, circuit
->idx
);
2654 stream_putc (circuit
->snd_stream
, 9); /* code */
2655 stream_putc (circuit
->snd_stream
, 16); /* len */
2657 stream_putw (circuit
->snd_stream
, ntohs (hdr
->rem_lifetime
));
2658 stream_put (circuit
->snd_stream
, hdr
->lsp_id
, ISIS_SYS_ID_LEN
+ 2);
2659 stream_putl (circuit
->snd_stream
, ntohl (hdr
->seq_num
));
2660 stream_putw (circuit
->snd_stream
, ntohs (hdr
->checksum
));
2662 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
2663 /* Update PDU length */
2664 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2666 retval
= circuit
->tx (circuit
, level
);