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_flags.h"
43 #include "isisd/isis_adjacency.h"
44 #include "isisd/isis_circuit.h"
45 #include "isisd/isis_network.h"
46 #include "isisd/isis_misc.h"
47 #include "isisd/isis_dr.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"
56 #include "isisd/isis_te.h"
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 const 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 * Verify authentication information
172 * Support cleartext and HMAC MD5 authentication
175 authentication_check (struct isis_passwd
*remote
, struct isis_passwd
*local
,
176 struct stream
*stream
, uint32_t auth_tlv_offset
)
178 unsigned char digest
[ISIS_AUTH_MD5_SIZE
];
180 /* Auth fail () - passwd type mismatch */
181 if (local
->type
!= remote
->type
)
186 /* No authentication required */
187 case ISIS_PASSWD_TYPE_UNUSED
:
190 /* Cleartext (ISO 10589) */
191 case ISIS_PASSWD_TYPE_CLEARTXT
:
192 /* Auth fail () - passwd len mismatch */
193 if (remote
->len
!= local
->len
)
195 return memcmp (local
->passwd
, remote
->passwd
, local
->len
);
197 /* HMAC MD5 (RFC 3567) */
198 case ISIS_PASSWD_TYPE_HMAC_MD5
:
199 /* Auth fail () - passwd len mismatch */
200 if (remote
->len
!= ISIS_AUTH_MD5_SIZE
)
202 /* Set the authentication value to 0 before the check */
203 memset (STREAM_DATA (stream
) + auth_tlv_offset
+ 3, 0,
205 /* Compute the digest */
206 hmac_md5 (STREAM_DATA (stream
), stream_get_endp (stream
),
207 (unsigned char *) &(local
->passwd
), local
->len
,
208 (unsigned char *) &digest
);
209 /* Copy back the authentication value after the check */
210 memcpy (STREAM_DATA (stream
) + auth_tlv_offset
+ 3,
211 remote
->passwd
, ISIS_AUTH_MD5_SIZE
);
212 return memcmp (digest
, remote
->passwd
, ISIS_AUTH_MD5_SIZE
);
215 zlog_err ("Unsupported authentication type");
219 /* Authentication pass when no authentication is configured */
224 lsp_authentication_check (struct stream
*stream
, struct isis_area
*area
,
225 int level
, struct isis_passwd
*passwd
)
227 struct isis_link_state_hdr
*hdr
;
228 uint32_t expected
= 0, found
= 0, auth_tlv_offset
= 0;
229 uint16_t checksum
, rem_lifetime
, pdu_len
;
231 int retval
= ISIS_OK
;
233 hdr
= (struct isis_link_state_hdr
*) (STREAM_PNT (stream
));
234 pdu_len
= ntohs (hdr
->pdu_len
);
235 expected
|= TLVFLAG_AUTH_INFO
;
236 auth_tlv_offset
= stream_get_getp (stream
) + ISIS_LSP_HDR_LEN
;
237 retval
= parse_tlvs (area
->area_tag
, STREAM_PNT (stream
) + ISIS_LSP_HDR_LEN
,
238 pdu_len
- ISIS_FIXED_HDR_LEN
- ISIS_LSP_HDR_LEN
,
239 &expected
, &found
, &tlvs
, &auth_tlv_offset
);
241 if (retval
!= ISIS_OK
)
243 zlog_err ("ISIS-Upd (%s): Parse failed L%d LSP %s, seq 0x%08x, "
244 "cksum 0x%04x, lifetime %us, len %u",
245 area
->area_tag
, level
, rawlspid_print (hdr
->lsp_id
),
246 ntohl (hdr
->seq_num
), ntohs (hdr
->checksum
),
247 ntohs (hdr
->rem_lifetime
), pdu_len
);
248 if ((isis
->debugs
& DEBUG_UPDATE_PACKETS
) &&
249 (isis
->debugs
& DEBUG_PACKET_DUMP
))
250 zlog_dump_data (STREAM_DATA (stream
), stream_get_endp (stream
));
254 if (!(found
& TLVFLAG_AUTH_INFO
))
256 zlog_err ("No authentication tlv in LSP");
260 if (tlvs
.auth_info
.type
!= ISIS_PASSWD_TYPE_CLEARTXT
&&
261 tlvs
.auth_info
.type
!= ISIS_PASSWD_TYPE_HMAC_MD5
)
263 zlog_err ("Unknown authentication type in LSP");
268 * RFC 5304 set checksum and remaining lifetime to zero before
269 * verification and reset to old values after verification.
271 checksum
= hdr
->checksum
;
272 rem_lifetime
= hdr
->rem_lifetime
;
274 hdr
->rem_lifetime
= 0;
275 retval
= authentication_check (&tlvs
.auth_info
, passwd
, stream
,
277 hdr
->checksum
= checksum
;
278 hdr
->rem_lifetime
= rem_lifetime
;
284 * Processing helper functions
289 XFREE (MTYPE_ISIS_TMP
, val
);
293 tlvs_to_adj_area_addrs (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
295 struct listnode
*node
;
296 struct area_addr
*area_addr
, *malloced
;
300 adj
->area_addrs
->del
= del_addr
;
301 list_delete (adj
->area_addrs
);
303 adj
->area_addrs
= list_new ();
304 if (tlvs
->area_addrs
)
306 for (ALL_LIST_ELEMENTS_RO (tlvs
->area_addrs
, node
, area_addr
))
308 malloced
= XMALLOC (MTYPE_ISIS_TMP
, sizeof (struct area_addr
));
309 memcpy (malloced
, area_addr
, sizeof (struct area_addr
));
310 listnode_add (adj
->area_addrs
, malloced
);
316 tlvs_to_adj_nlpids (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
319 struct nlpids
*tlv_nlpids
;
324 tlv_nlpids
= tlvs
->nlpids
;
325 if (tlv_nlpids
->count
> array_size (adj
->nlpids
.nlpids
))
328 adj
->nlpids
.count
= tlv_nlpids
->count
;
330 for (i
= 0; i
< tlv_nlpids
->count
; i
++)
332 adj
->nlpids
.nlpids
[i
] = tlv_nlpids
->nlpids
[i
];
339 tlvs_to_adj_ipv4_addrs (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
341 struct listnode
*node
;
342 struct in_addr
*ipv4_addr
, *malloced
;
346 adj
->ipv4_addrs
->del
= del_addr
;
347 list_delete (adj
->ipv4_addrs
);
349 adj
->ipv4_addrs
= list_new ();
350 if (tlvs
->ipv4_addrs
)
352 for (ALL_LIST_ELEMENTS_RO (tlvs
->ipv4_addrs
, node
, ipv4_addr
))
354 malloced
= XMALLOC (MTYPE_ISIS_TMP
, sizeof (struct in_addr
));
355 memcpy (malloced
, ipv4_addr
, sizeof (struct in_addr
));
356 listnode_add (adj
->ipv4_addrs
, malloced
);
363 tlvs_to_adj_ipv6_addrs (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
365 struct listnode
*node
;
366 struct in6_addr
*ipv6_addr
, *malloced
;
370 adj
->ipv6_addrs
->del
= del_addr
;
371 list_delete (adj
->ipv6_addrs
);
373 adj
->ipv6_addrs
= list_new ();
374 if (tlvs
->ipv6_addrs
)
376 for (ALL_LIST_ELEMENTS_RO (tlvs
->ipv6_addrs
, node
, ipv6_addr
))
378 malloced
= XMALLOC (MTYPE_ISIS_TMP
, sizeof (struct in6_addr
));
379 memcpy (malloced
, ipv6_addr
, sizeof (struct in6_addr
));
380 listnode_add (adj
->ipv6_addrs
, malloced
);
385 #endif /* HAVE_IPV6 */
394 * Section 8.2.5 - Receiving point-to-point IIH PDUs
398 process_p2p_hello (struct isis_circuit
*circuit
)
400 int retval
= ISIS_OK
;
401 struct isis_p2p_hello_hdr
*hdr
;
402 struct isis_adjacency
*adj
;
403 u_int32_t expected
= 0, found
= 0, auth_tlv_offset
= 0;
406 int v4_usable
= 0, v6_usable
= 0;
408 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
410 zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH on %s, cirType %s, cirID %u",
411 circuit
->area
->area_tag
, circuit
->interface
->name
,
412 circuit_t2string (circuit
->is_type
), circuit
->circuit_id
);
413 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
414 zlog_dump_data (STREAM_DATA (circuit
->rcv_stream
),
415 stream_get_endp (circuit
->rcv_stream
));
418 if (circuit
->circ_type
!= CIRCUIT_T_P2P
)
420 zlog_warn ("p2p hello on non p2p circuit");
424 if ((stream_get_endp (circuit
->rcv_stream
) -
425 stream_get_getp (circuit
->rcv_stream
)) < ISIS_P2PHELLO_HDRLEN
)
427 zlog_warn ("Packet too short");
431 /* 8.2.5.1 PDU acceptance tests */
433 /* 8.2.5.1 a) external domain untrue */
434 /* FIXME: not useful at all? */
436 /* 8.2.5.1 b) ID Length mismatch */
437 /* checked at the handle_pdu */
439 /* 8.2.5.2 IIH PDU Processing */
441 /* 8.2.5.2 a) 1) Maximum Area Addresses */
442 /* Already checked, and can also be ommited */
447 hdr
= (struct isis_p2p_hello_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
448 pdu_len
= ntohs (hdr
->pdu_len
);
450 if (pdu_len
< (ISIS_FIXED_HDR_LEN
+ ISIS_P2PHELLO_HDRLEN
) ||
451 pdu_len
> ISO_MTU(circuit
) ||
452 pdu_len
> stream_get_endp (circuit
->rcv_stream
))
454 zlog_warn ("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with "
455 "invalid pdu length %d",
456 circuit
->area
->area_tag
, circuit
->interface
->name
, pdu_len
);
461 * Set the stream endp to PDU length, ignoring additional padding
462 * introduced by transport chips.
464 if (pdu_len
< stream_get_endp (circuit
->rcv_stream
))
465 stream_set_endp (circuit
->rcv_stream
, pdu_len
);
467 stream_forward_getp (circuit
->rcv_stream
, ISIS_P2PHELLO_HDRLEN
);
470 * Lets get the TLVS now
472 expected
|= TLVFLAG_AREA_ADDRS
;
473 expected
|= TLVFLAG_AUTH_INFO
;
474 expected
|= TLVFLAG_NLPID
;
475 expected
|= TLVFLAG_IPV4_ADDR
;
476 expected
|= TLVFLAG_IPV6_ADDR
;
478 auth_tlv_offset
= stream_get_getp (circuit
->rcv_stream
);
479 retval
= parse_tlvs (circuit
->area
->area_tag
,
480 STREAM_PNT (circuit
->rcv_stream
),
481 pdu_len
- ISIS_P2PHELLO_HDRLEN
- ISIS_FIXED_HDR_LEN
,
482 &expected
, &found
, &tlvs
, &auth_tlv_offset
);
484 if (retval
> ISIS_WARNING
)
486 zlog_warn ("parse_tlvs() failed");
491 if (!(found
& TLVFLAG_AREA_ADDRS
))
493 zlog_warn ("No Area addresses TLV in P2P IS to IS hello");
498 if (!(found
& TLVFLAG_NLPID
))
500 zlog_warn ("No supported protocols TLV in P2P IS to IS hello");
505 /* 8.2.5.1 c) Authentication */
506 if (circuit
->passwd
.type
)
508 if (!(found
& TLVFLAG_AUTH_INFO
) ||
509 authentication_check (&tlvs
.auth_info
, &circuit
->passwd
,
510 circuit
->rcv_stream
, auth_tlv_offset
))
512 isis_event_auth_failure (circuit
->area
->area_tag
,
513 "P2P hello authentication failure",
521 * check if it's own interface ip match iih ip addrs
523 if (found
& TLVFLAG_IPV4_ADDR
)
525 if (ip_match (circuit
->ip_addrs
, tlvs
.ipv4_addrs
))
528 zlog_warn ("ISIS-Adj: IPv4 addresses present but no overlap "
529 "in P2P IIH from %s\n", circuit
->interface
->name
);
532 else /* !(found & TLVFLAG_IPV4_ADDR) */
533 zlog_warn ("ISIS-Adj: no IPv4 in P2P IIH from %s "
534 "(this isisd has no IPv6)\n", circuit
->interface
->name
);
537 if (found
& TLVFLAG_IPV6_ADDR
)
539 /* TBA: check that we have a linklocal ourselves? */
540 struct listnode
*node
;
542 for (ALL_LIST_ELEMENTS_RO (tlvs
.ipv6_addrs
, node
, ip
))
543 if (IN6_IS_ADDR_LINKLOCAL (ip
))
550 zlog_warn ("ISIS-Adj: IPv6 addresses present but no link-local "
551 "in P2P IIH from %s\n", circuit
->interface
->name
);
554 if (!(found
& (TLVFLAG_IPV4_ADDR
| TLVFLAG_IPV6_ADDR
)))
555 zlog_warn ("ISIS-Adj: neither IPv4 nor IPv6 addr in P2P IIH from %s\n",
556 circuit
->interface
->name
);
559 if (!v6_usable
&& !v4_usable
)
566 * it's own p2p IIH PDU - discard
568 if (!memcmp (hdr
->source_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
570 zlog_warn ("ISIS-Adj (%s): it's own IIH PDU - discarded",
571 circuit
->area
->area_tag
);
577 * My interpertation of the ISO, if no adj exists we will create one for
580 adj
= circuit
->u
.p2p
.neighbor
;
581 /* If an adjacency exists, check it is with the source of the hello
585 if (memcmp(hdr
->source_id
, adj
->sysid
, ISIS_SYS_ID_LEN
))
587 zlog_debug("hello source and adjacency do not match, set adj down\n");
588 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "adj do not exist");
592 if (!adj
|| adj
->level
!= hdr
->circuit_t
)
596 adj
= isis_new_adj (hdr
->source_id
, NULL
, hdr
->circuit_t
, circuit
);
602 adj
->level
= hdr
->circuit_t
;
604 circuit
->u
.p2p
.neighbor
= adj
;
605 /* Build lsp with the new neighbor entry when a new
606 * adjacency is formed. Set adjacency circuit type to
607 * IIH PDU header circuit type before lsp is regenerated
608 * when an adjacency is up. This will result in the new
609 * adjacency entry getting added to the lsp tlv neighbor list.
611 adj
->circuit_t
= hdr
->circuit_t
;
612 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
613 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
616 /* 8.2.6 Monitoring point-to-point adjacencies */
617 adj
->hold_time
= ntohs (hdr
->hold_time
);
618 adj
->last_upd
= time (NULL
);
620 /* we do this now because the adj may not survive till the end... */
621 tlvs_to_adj_area_addrs (&tlvs
, adj
);
623 /* which protocol are spoken ??? */
624 if (tlvs_to_adj_nlpids (&tlvs
, adj
))
630 /* we need to copy addresses to the adj */
631 if (found
& TLVFLAG_IPV4_ADDR
)
632 tlvs_to_adj_ipv4_addrs (&tlvs
, adj
);
634 /* Update MPLS TE Remote IP address parameter if possible */
635 if (IS_MPLS_TE(isisMplsTE
) && circuit
->mtc
&& IS_CIRCUIT_TE(circuit
->mtc
))
636 if (adj
->ipv4_addrs
!= NULL
&& listcount(adj
->ipv4_addrs
) != 0)
638 struct in_addr
*ip_addr
;
639 ip_addr
= (struct in_addr
*)listgetdata ((struct listnode
*)listhead (adj
->ipv4_addrs
));
640 set_circuitparams_rmt_ipaddr (circuit
->mtc
, *ip_addr
);
644 if (found
& TLVFLAG_IPV6_ADDR
)
645 tlvs_to_adj_ipv6_addrs (&tlvs
, adj
);
646 #endif /* HAVE_IPV6 */
648 /* lets take care of the expiry */
649 THREAD_TIMER_OFF (adj
->t_expire
);
650 THREAD_TIMER_ON (master
, adj
->t_expire
, isis_adj_expire
, adj
,
651 (long) adj
->hold_time
);
653 /* 8.2.5.2 a) a match was detected */
654 if (area_match (circuit
->area
->area_addrs
, tlvs
.area_addrs
))
656 /* 8.2.5.2 a) 2) If the system is L1 - table 5 */
657 if (circuit
->area
->is_type
== IS_LEVEL_1
)
659 switch (hdr
->circuit_t
)
662 case IS_LEVEL_1_AND_2
:
663 if (adj
->adj_state
!= ISIS_ADJ_UP
)
665 /* (4) adj state up */
666 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
667 /* (5) adj usage level 1 */
668 adj
->adj_usage
= ISIS_ADJ_LEVEL1
;
670 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
676 if (adj
->adj_state
!= ISIS_ADJ_UP
)
678 /* (7) reject - wrong system type event */
679 zlog_warn ("wrongSystemType");
681 return ISIS_WARNING
; /* Reject */
683 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
685 /* (6) down - wrong system */
686 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
692 /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */
693 if (circuit
->area
->is_type
== IS_LEVEL_1_AND_2
)
695 switch (hdr
->circuit_t
)
698 if (adj
->adj_state
!= ISIS_ADJ_UP
)
700 /* (6) adj state up */
701 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
702 /* (7) adj usage level 1 */
703 adj
->adj_usage
= ISIS_ADJ_LEVEL1
;
705 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
709 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
710 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
712 /* (8) down - wrong system */
713 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
717 if (adj
->adj_state
!= ISIS_ADJ_UP
)
719 /* (6) adj state up */
720 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
721 /* (9) adj usage level 2 */
722 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
724 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1
) ||
725 (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
))
727 /* (8) down - wrong system */
728 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
730 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
735 case IS_LEVEL_1_AND_2
:
736 if (adj
->adj_state
!= ISIS_ADJ_UP
)
738 /* (6) adj state up */
739 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
740 /* (10) adj usage level 1 */
741 adj
->adj_usage
= ISIS_ADJ_LEVEL1AND2
;
743 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1
) ||
744 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
746 /* (8) down - wrong system */
747 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
749 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
757 /* 8.2.5.2 a) 4) If the system is L2 - table 7 */
758 if (circuit
->area
->is_type
== IS_LEVEL_2
)
760 switch (hdr
->circuit_t
)
763 if (adj
->adj_state
!= ISIS_ADJ_UP
)
765 /* (5) reject - wrong system type event */
766 zlog_warn ("wrongSystemType");
768 return ISIS_WARNING
; /* Reject */
770 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
771 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
773 /* (6) down - wrong system */
774 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
777 case IS_LEVEL_1_AND_2
:
779 if (adj
->adj_state
!= ISIS_ADJ_UP
)
781 /* (7) adj state up */
782 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
783 /* (8) adj usage level 2 */
784 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
786 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
788 /* (6) down - wrong system */
789 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
791 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
799 /* 8.2.5.2 b) if no match was detected */
800 else if (listcount (circuit
->area
->area_addrs
) > 0)
802 if (circuit
->area
->is_type
== IS_LEVEL_1
)
804 /* 8.2.5.2 b) 1) is_type L1 and adj is not up */
805 if (adj
->adj_state
!= ISIS_ADJ_UP
)
807 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch");
808 /* 8.2.5.2 b) 2)is_type L1 and adj is up */
812 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
813 "Down - Area Mismatch");
816 /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */
819 switch (hdr
->circuit_t
)
822 if (adj
->adj_state
!= ISIS_ADJ_UP
)
824 /* (6) reject - Area Mismatch event */
825 zlog_warn ("AreaMismatch");
827 return ISIS_WARNING
; /* Reject */
829 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
831 /* (7) down - area mismatch */
832 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch");
835 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
836 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
838 /* (7) down - wrong system */
839 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
842 case IS_LEVEL_1_AND_2
:
844 if (adj
->adj_state
!= ISIS_ADJ_UP
)
846 /* (8) adj state up */
847 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
848 /* (9) adj usage level 2 */
849 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
851 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
853 /* (7) down - wrong system */
854 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
856 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
858 if (hdr
->circuit_t
== IS_LEVEL_2
)
860 /* (7) down - wrong system */
861 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
866 /* (7) down - area mismatch */
867 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
871 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
881 /* down - area mismatch */
882 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch");
884 /* 8.2.5.2 c) if the action was up - comparing circuit IDs */
885 /* FIXME - Missing parts */
887 /* some of my own understanding of the ISO, why the heck does
888 * it not say what should I change the system_type to...
890 switch (adj
->adj_usage
)
892 case ISIS_ADJ_LEVEL1
:
893 adj
->sys_type
= ISIS_SYSTYPE_L1_IS
;
895 case ISIS_ADJ_LEVEL2
:
896 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
898 case ISIS_ADJ_LEVEL1AND2
:
899 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
902 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
907 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
909 zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
910 " cir id %02d, length %d",
911 circuit
->area
->area_tag
, circuit
->interface
->name
,
912 circuit_t2string (circuit
->is_type
),
913 circuit
->circuit_id
, pdu_len
);
922 * Process IS-IS LAN Level 1/2 Hello PDU
925 process_lan_hello (int level
, struct isis_circuit
*circuit
, const u_char
*ssnpa
)
927 int retval
= ISIS_OK
;
928 struct isis_lan_hello_hdr hdr
;
929 struct isis_adjacency
*adj
;
930 u_int32_t expected
= 0, found
= 0, auth_tlv_offset
= 0;
933 struct listnode
*node
;
934 int v4_usable
= 0, v6_usable
= 0;
936 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
938 zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH on %s, cirType %s, "
940 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
941 circuit_t2string (circuit
->is_type
), circuit
->circuit_id
);
942 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
943 zlog_dump_data (STREAM_DATA (circuit
->rcv_stream
),
944 stream_get_endp (circuit
->rcv_stream
));
947 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
949 zlog_warn ("lan hello on non broadcast circuit");
953 if ((stream_get_endp (circuit
->rcv_stream
) -
954 stream_get_getp (circuit
->rcv_stream
)) < ISIS_LANHELLO_HDRLEN
)
956 zlog_warn ("Packet too short");
960 if (circuit
->ext_domain
)
962 zlog_debug ("level %d LAN Hello received over circuit with "
963 "externalDomain = true", level
);
967 if (!accept_level (level
, circuit
->is_type
))
969 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
971 zlog_debug ("ISIS-Adj (%s): Interface level mismatch, %s",
972 circuit
->area
->area_tag
, circuit
->interface
->name
);
978 /* Cisco's debug message compatability */
979 if (!accept_level (level
, circuit
->area
->is_type
))
981 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
983 zlog_debug ("ISIS-Adj (%s): is type mismatch",
984 circuit
->area
->area_tag
);
992 hdr
.circuit_t
= stream_getc (circuit
->rcv_stream
);
993 stream_get (hdr
.source_id
, circuit
->rcv_stream
, ISIS_SYS_ID_LEN
);
994 hdr
.hold_time
= stream_getw (circuit
->rcv_stream
);
995 hdr
.pdu_len
= stream_getw (circuit
->rcv_stream
);
996 hdr
.prio
= stream_getc (circuit
->rcv_stream
);
997 stream_get (hdr
.lan_id
, circuit
->rcv_stream
, ISIS_SYS_ID_LEN
+ 1);
999 if (hdr
.pdu_len
< (ISIS_FIXED_HDR_LEN
+ ISIS_LANHELLO_HDRLEN
) ||
1000 hdr
.pdu_len
> ISO_MTU(circuit
) ||
1001 hdr
.pdu_len
> stream_get_endp (circuit
->rcv_stream
))
1003 zlog_warn ("ISIS-Adj (%s): Rcvd LAN IIH from (%s) with "
1004 "invalid pdu length %d",
1005 circuit
->area
->area_tag
, circuit
->interface
->name
,
1007 return ISIS_WARNING
;
1011 * Set the stream endp to PDU length, ignoring additional padding
1012 * introduced by transport chips.
1014 if (hdr
.pdu_len
< stream_get_endp (circuit
->rcv_stream
))
1015 stream_set_endp (circuit
->rcv_stream
, hdr
.pdu_len
);
1017 if (hdr
.circuit_t
!= IS_LEVEL_1
&&
1018 hdr
.circuit_t
!= IS_LEVEL_2
&&
1019 hdr
.circuit_t
!= IS_LEVEL_1_AND_2
&&
1020 (level
& hdr
.circuit_t
) == 0)
1022 zlog_err ("Level %d LAN Hello with Circuit Type %d", level
,
1030 expected
|= TLVFLAG_AUTH_INFO
;
1031 expected
|= TLVFLAG_AREA_ADDRS
;
1032 expected
|= TLVFLAG_LAN_NEIGHS
;
1033 expected
|= TLVFLAG_NLPID
;
1034 expected
|= TLVFLAG_IPV4_ADDR
;
1035 expected
|= TLVFLAG_IPV6_ADDR
;
1037 auth_tlv_offset
= stream_get_getp (circuit
->rcv_stream
);
1038 retval
= parse_tlvs (circuit
->area
->area_tag
,
1039 STREAM_PNT (circuit
->rcv_stream
),
1040 hdr
.pdu_len
- ISIS_LANHELLO_HDRLEN
- ISIS_FIXED_HDR_LEN
,
1041 &expected
, &found
, &tlvs
,
1044 if (retval
> ISIS_WARNING
)
1046 zlog_warn ("parse_tlvs() failed");
1050 if (!(found
& TLVFLAG_AREA_ADDRS
))
1052 zlog_warn ("No Area addresses TLV in Level %d LAN IS to IS hello",
1054 retval
= ISIS_WARNING
;
1058 if (!(found
& TLVFLAG_NLPID
))
1060 zlog_warn ("No supported protocols TLV in Level %d LAN IS to IS hello",
1062 retval
= ISIS_WARNING
;
1066 /* Verify authentication, either cleartext of HMAC MD5 */
1067 if (circuit
->passwd
.type
)
1069 if (!(found
& TLVFLAG_AUTH_INFO
) ||
1070 authentication_check (&tlvs
.auth_info
, &circuit
->passwd
,
1071 circuit
->rcv_stream
, auth_tlv_offset
))
1073 isis_event_auth_failure (circuit
->area
->area_tag
,
1074 "LAN hello authentication failure",
1076 retval
= ISIS_WARNING
;
1081 if (!memcmp (hdr
.source_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
1083 zlog_warn ("ISIS-Adj (%s): duplicate system ID on interface %s",
1084 circuit
->area
->area_tag
, circuit
->interface
->name
);
1085 return ISIS_WARNING
;
1089 * Accept the level 1 adjacency only if a match between local and
1090 * remote area addresses is found
1092 if (listcount (circuit
->area
->area_addrs
) == 0 ||
1093 (level
== IS_LEVEL_1
&&
1094 area_match (circuit
->area
->area_addrs
, tlvs
.area_addrs
) == 0))
1096 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
1098 zlog_debug ("ISIS-Adj (%s): Area mismatch, level %d IIH on %s",
1099 circuit
->area
->area_tag
, level
,
1100 circuit
->interface
->name
);
1107 * it's own IIH PDU - discard silently
1109 if (!memcmp (circuit
->u
.bc
.snpa
, ssnpa
, ETH_ALEN
))
1111 zlog_debug ("ISIS-Adj (%s): it's own IIH PDU - discarded",
1112 circuit
->area
->area_tag
);
1119 * check if it's own interface ip match iih ip addrs
1121 if (found
& TLVFLAG_IPV4_ADDR
)
1123 if (ip_match (circuit
->ip_addrs
, tlvs
.ipv4_addrs
))
1126 zlog_warn ("ISIS-Adj: IPv4 addresses present but no overlap "
1127 "in LAN IIH from %s\n", circuit
->interface
->name
);
1130 else /* !(found & TLVFLAG_IPV4_ADDR) */
1131 zlog_warn ("ISIS-Adj: no IPv4 in LAN IIH from %s "
1132 "(this isisd has no IPv6)\n", circuit
->interface
->name
);
1135 if (found
& TLVFLAG_IPV6_ADDR
)
1137 /* TBA: check that we have a linklocal ourselves? */
1138 struct listnode
*node
;
1139 struct in6_addr
*ip
;
1140 for (ALL_LIST_ELEMENTS_RO (tlvs
.ipv6_addrs
, node
, ip
))
1141 if (IN6_IS_ADDR_LINKLOCAL (ip
))
1148 zlog_warn ("ISIS-Adj: IPv6 addresses present but no link-local "
1149 "in LAN IIH from %s\n", circuit
->interface
->name
);
1152 if (!(found
& (TLVFLAG_IPV4_ADDR
| TLVFLAG_IPV6_ADDR
)))
1153 zlog_warn ("ISIS-Adj: neither IPv4 nor IPv6 addr in LAN IIH from %s\n",
1154 circuit
->interface
->name
);
1157 if (!v6_usable
&& !v4_usable
)
1160 return ISIS_WARNING
;
1164 adj
= isis_adj_lookup (hdr
.source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
1165 if ((adj
== NULL
) || (memcmp(adj
->snpa
, ssnpa
, ETH_ALEN
)) ||
1166 (adj
->level
!= level
))
1173 adj
= isis_new_adj (hdr
.source_id
, ssnpa
, level
, circuit
);
1176 retval
= ISIS_ERROR
;
1183 memcpy (adj
->snpa
, ssnpa
, 6);
1185 memset (adj
->snpa
, ' ', 6);
1189 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
1191 if (level
== IS_LEVEL_1
)
1192 adj
->sys_type
= ISIS_SYSTYPE_L1_IS
;
1194 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
1195 list_delete_all_node (circuit
->u
.bc
.lan_neighs
[level
- 1]);
1196 isis_adj_build_neigh_list (circuit
->u
.bc
.adjdb
[level
- 1],
1197 circuit
->u
.bc
.lan_neighs
[level
- 1]);
1200 if(adj
->dis_record
[level
-1].dis
==ISIS_IS_DIS
)
1204 if (memcmp (circuit
->u
.bc
.l1_desig_is
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1))
1206 thread_add_event (master
, isis_event_dis_status_change
, circuit
, 0);
1207 memcpy (&circuit
->u
.bc
.l1_desig_is
, hdr
.lan_id
,
1208 ISIS_SYS_ID_LEN
+ 1);
1212 if (memcmp (circuit
->u
.bc
.l2_desig_is
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1))
1214 thread_add_event (master
, isis_event_dis_status_change
, circuit
, 0);
1215 memcpy (&circuit
->u
.bc
.l2_desig_is
, hdr
.lan_id
,
1216 ISIS_SYS_ID_LEN
+ 1);
1221 adj
->hold_time
= hdr
.hold_time
;
1222 adj
->last_upd
= time (NULL
);
1223 adj
->prio
[level
- 1] = hdr
.prio
;
1225 memcpy (adj
->lanid
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1);
1227 tlvs_to_adj_area_addrs (&tlvs
, adj
);
1229 /* which protocol are spoken ??? */
1230 if (tlvs_to_adj_nlpids (&tlvs
, adj
))
1232 retval
= ISIS_WARNING
;
1236 /* we need to copy addresses to the adj */
1237 if (found
& TLVFLAG_IPV4_ADDR
)
1238 tlvs_to_adj_ipv4_addrs (&tlvs
, adj
);
1241 if (found
& TLVFLAG_IPV6_ADDR
)
1242 tlvs_to_adj_ipv6_addrs (&tlvs
, adj
);
1243 #endif /* HAVE_IPV6 */
1245 adj
->circuit_t
= hdr
.circuit_t
;
1247 /* lets take care of the expiry */
1248 THREAD_TIMER_OFF (adj
->t_expire
);
1249 THREAD_TIMER_ON (master
, adj
->t_expire
, isis_adj_expire
, adj
,
1250 (long) adj
->hold_time
);
1253 * If the snpa for this circuit is found from LAN Neighbours TLV
1254 * we have two-way communication -> adjacency can be put to state "up"
1257 if (found
& TLVFLAG_LAN_NEIGHS
)
1259 if (adj
->adj_state
!= ISIS_ADJ_UP
)
1261 for (ALL_LIST_ELEMENTS_RO (tlvs
.lan_neighs
, node
, snpa
))
1263 if (!memcmp (snpa
, circuit
->u
.bc
.snpa
, ETH_ALEN
))
1265 isis_adj_state_change (adj
, ISIS_ADJ_UP
,
1266 "own SNPA found in LAN Neighbours TLV");
1273 for (ALL_LIST_ELEMENTS_RO (tlvs
.lan_neighs
, node
, snpa
))
1274 if (!memcmp (snpa
, circuit
->u
.bc
.snpa
, ETH_ALEN
))
1280 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
,
1281 "own SNPA not found in LAN Neighbours TLV");
1284 else if (adj
->adj_state
== ISIS_ADJ_UP
)
1286 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
,
1287 "no LAN Neighbours TLV found");
1291 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
1293 zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "
1294 "cirID %u, length %zd",
1295 circuit
->area
->area_tag
,
1296 level
, snpa_print (ssnpa
), circuit
->interface
->name
,
1297 circuit_t2string (circuit
->is_type
),
1298 circuit
->circuit_id
,
1299 stream_get_endp (circuit
->rcv_stream
));
1308 * Process Level 1/2 Link State
1310 * Section 7.3.15.1 - Action on receipt of a link state PDU
1313 process_lsp (int level
, struct isis_circuit
*circuit
, const u_char
*ssnpa
)
1315 struct isis_link_state_hdr
*hdr
;
1316 struct isis_adjacency
*adj
= NULL
;
1317 struct isis_lsp
*lsp
, *lsp0
= NULL
;
1318 int retval
= ISIS_OK
, comp
= 0;
1319 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
1320 struct isis_passwd
*passwd
;
1324 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1326 zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP on %s, cirType %s, cirID %u",
1327 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
1328 circuit_t2string (circuit
->is_type
), circuit
->circuit_id
);
1329 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
1330 zlog_dump_data (STREAM_DATA (circuit
->rcv_stream
),
1331 stream_get_endp (circuit
->rcv_stream
));
1334 if ((stream_get_endp (circuit
->rcv_stream
) -
1335 stream_get_getp (circuit
->rcv_stream
)) < ISIS_LSP_HDR_LEN
)
1337 zlog_warn ("Packet too short");
1338 return ISIS_WARNING
;
1341 /* Reference the header */
1342 hdr
= (struct isis_link_state_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
1343 pdu_len
= ntohs (hdr
->pdu_len
);
1345 /* lsp length check */
1346 if (pdu_len
< (ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
) ||
1347 pdu_len
> ISO_MTU(circuit
) ||
1348 pdu_len
> stream_get_endp (circuit
->rcv_stream
))
1350 zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP length %d",
1351 circuit
->area
->area_tag
,
1352 rawlspid_print (hdr
->lsp_id
), pdu_len
);
1354 return ISIS_WARNING
;
1358 * Set the stream endp to PDU length, ignoring additional padding
1359 * introduced by transport chips.
1361 if (pdu_len
< stream_get_endp (circuit
->rcv_stream
))
1362 stream_set_endp (circuit
->rcv_stream
, pdu_len
);
1364 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1366 zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "
1367 "lifetime %us, len %u, on %s",
1368 circuit
->area
->area_tag
,
1370 rawlspid_print (hdr
->lsp_id
),
1371 ntohl (hdr
->seq_num
),
1372 ntohs (hdr
->checksum
),
1373 ntohs (hdr
->rem_lifetime
),
1375 circuit
->interface
->name
);
1378 /* lsp is_type check */
1379 if ((hdr
->lsp_bits
& IS_LEVEL_1_AND_2
) != IS_LEVEL_1
&&
1380 (hdr
->lsp_bits
& IS_LEVEL_1_AND_2
) != IS_LEVEL_1_AND_2
)
1382 zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP is type %x",
1383 circuit
->area
->area_tag
,
1384 rawlspid_print (hdr
->lsp_id
), hdr
->lsp_bits
);
1385 /* continue as per RFC1122 Be liberal in what you accept, and
1386 * conservative in what you send */
1389 /* Checksum sanity check - FIXME: move to correct place */
1390 /* 12 = sysid+pdu+remtime */
1391 if (iso_csum_verify (STREAM_PNT (circuit
->rcv_stream
) + 4,
1392 pdu_len
- 12, &hdr
->checksum
))
1394 zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
1395 circuit
->area
->area_tag
,
1396 rawlspid_print (hdr
->lsp_id
), ntohs (hdr
->checksum
));
1398 return ISIS_WARNING
;
1401 /* 7.3.15.1 a) 1 - external domain circuit will discard lsps */
1402 if (circuit
->ext_domain
)
1405 ("ISIS-Upd (%s): LSP %s received at level %d over circuit with "
1406 "externalDomain = true", circuit
->area
->area_tag
,
1407 rawlspid_print (hdr
->lsp_id
), level
);
1409 return ISIS_WARNING
;
1412 /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
1413 if (!accept_level (level
, circuit
->is_type
))
1415 zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of"
1417 circuit
->area
->area_tag
,
1418 rawlspid_print (hdr
->lsp_id
),
1419 level
, circuit_t2string (circuit
->is_type
));
1421 return ISIS_WARNING
;
1424 /* 7.3.15.1 a) 4 - need to make sure IDLength matches */
1426 /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */
1428 /* 7.3.15.1 a) 7 - password check */
1429 (level
== IS_LEVEL_1
) ? (passwd
= &circuit
->area
->area_passwd
) :
1430 (passwd
= &circuit
->area
->domain_passwd
);
1433 if (lsp_authentication_check (circuit
->rcv_stream
, circuit
->area
,
1436 isis_event_auth_failure (circuit
->area
->area_tag
,
1437 "LSP authentication failure", hdr
->lsp_id
);
1438 return ISIS_WARNING
;
1441 /* Find the LSP in our database and compare it to this Link State header */
1442 lsp
= lsp_search (hdr
->lsp_id
, circuit
->area
->lspdb
[level
- 1]);
1444 comp
= lsp_compare (circuit
->area
->area_tag
, lsp
, hdr
->seq_num
,
1445 hdr
->checksum
, hdr
->rem_lifetime
);
1446 if (lsp
&& (lsp
->own_lsp
1447 #ifdef TOPOLOGY_GENERATE
1448 || lsp
->from_topology
1449 #endif /* TOPOLOGY_GENERATE */
1453 /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level */
1454 /* for broadcast circuits, snpa should be compared */
1456 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1458 adj
= isis_adj_lookup_snpa (ssnpa
, circuit
->u
.bc
.adjdb
[level
- 1]);
1461 zlog_debug ("(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, "
1462 "lifetime %us on %s",
1463 circuit
->area
->area_tag
,
1464 rawlspid_print (hdr
->lsp_id
),
1465 ntohl (hdr
->seq_num
),
1466 ntohs (hdr
->checksum
),
1467 ntohs (hdr
->rem_lifetime
), circuit
->interface
->name
);
1468 return ISIS_WARNING
; /* Silently discard */
1471 /* for non broadcast, we just need to find same level adj */
1474 /* If no adj, or no sharing of level */
1475 if (!circuit
->u
.p2p
.neighbor
)
1477 return ISIS_OK
; /* Silently discard */
1481 if (((level
== IS_LEVEL_1
) &&
1482 (circuit
->u
.p2p
.neighbor
->adj_usage
== ISIS_ADJ_LEVEL2
)) ||
1483 ((level
== IS_LEVEL_2
) &&
1484 (circuit
->u
.p2p
.neighbor
->adj_usage
== ISIS_ADJ_LEVEL1
)))
1485 return ISIS_WARNING
; /* Silently discard */
1486 adj
= circuit
->u
.p2p
.neighbor
;
1491 /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */
1493 /* 7.3.15.1 a) 8 - Passwords for level 2 - not implemented */
1495 /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented FIXME: do it */
1497 /* 7.3.16.2 - If this is an LSP from another IS with identical seq_num but
1498 * wrong checksum, initiate a purge. */
1500 && (lsp
->lsp_header
->seq_num
== hdr
->seq_num
)
1501 && (lsp
->lsp_header
->checksum
!= hdr
->checksum
))
1503 zlog_warn("ISIS-Upd (%s): LSP %s seq 0x%08x with confused checksum received.",
1504 circuit
->area
->area_tag
, rawlspid_print(hdr
->lsp_id
),
1505 ntohl(hdr
->seq_num
));
1506 hdr
->rem_lifetime
= 0;
1512 /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */
1513 if (hdr
->rem_lifetime
== 0)
1517 /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't save */
1518 /* only needed on explicit update, eg - p2p */
1519 if (circuit
->circ_type
== CIRCUIT_T_P2P
)
1520 ack_lsp (hdr
, circuit
, level
);
1521 return retval
; /* FIXME: do we need a purge? */
1525 if (memcmp (hdr
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
1527 /* LSP by some other system -> do 7.3.16.4 b) */
1528 /* 7.3.16.4 b) 1) */
1529 if (comp
== LSP_NEWER
)
1531 lsp_update (lsp
, circuit
->rcv_stream
, circuit
->area
, level
);
1533 lsp_set_all_srmflags (lsp
);
1535 ISIS_FLAGS_CLEAR_ALL (lsp
->SSNflags
); /* FIXME: OTHER than c */
1537 /* For the case of lsp confusion, flood the purge back to its
1538 * originator so that it can react. Otherwise, don't reflood
1539 * through incoming circuit as usual */
1543 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1545 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1546 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1548 } /* 7.3.16.4 b) 2) */
1549 else if (comp
== LSP_EQUAL
)
1552 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1554 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1555 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1556 } /* 7.3.16.4 b) 3) */
1559 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1560 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1563 else if (lsp
->lsp_header
->rem_lifetime
!= 0)
1565 /* our own LSP -> 7.3.16.4 c) */
1566 if (comp
== LSP_NEWER
)
1568 lsp_inc_seqnum (lsp
, ntohl (hdr
->seq_num
));
1569 lsp_set_all_srmflags (lsp
);
1573 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1574 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1576 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1577 zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new "
1578 "seq 0x%08x", circuit
->area
->area_tag
,
1579 rawlspid_print (hdr
->lsp_id
),
1580 ntohl (lsp
->lsp_header
->seq_num
));
1585 /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a
1587 if (memcmp (hdr
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
) == 0)
1591 /* 7.3.16.4: initiate a purge */
1592 lsp_purge_non_exist(level
, hdr
, circuit
->area
);
1595 /* 7.3.15.1 d) - If this is our own lsp and we have it */
1597 /* In 7.3.16.1, If an Intermediate system R somewhere in the domain
1598 * has information that the current sequence number for source S is
1599 * "greater" than that held by S, ... */
1601 if (ntohl (hdr
->seq_num
) > ntohl (lsp
->lsp_header
->seq_num
))
1604 lsp_inc_seqnum (lsp
, ntohl (hdr
->seq_num
));
1605 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1606 zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq "
1607 "0x%08x", circuit
->area
->area_tag
,
1608 rawlspid_print (hdr
->lsp_id
),
1609 ntohl (lsp
->lsp_header
->seq_num
));
1611 /* If the received LSP is older or equal,
1612 * resend the LSP which will act as ACK */
1613 lsp_set_all_srmflags (lsp
);
1617 /* 7.3.15.1 e) - This lsp originated on another system */
1619 /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */
1620 if ((!lsp
|| comp
== LSP_NEWER
))
1623 * If this lsp is a frag, need to see if we have zero lsp present
1625 if (LSP_FRAGMENT (hdr
->lsp_id
) != 0)
1627 memcpy (lspid
, hdr
->lsp_id
, ISIS_SYS_ID_LEN
+ 1);
1628 LSP_FRAGMENT (lspid
) = 0;
1629 lsp0
= lsp_search (lspid
, circuit
->area
->lspdb
[level
- 1]);
1632 zlog_debug ("Got lsp frag, while zero lsp not in database");
1639 lsp
= lsp_new_from_stream_ptr (circuit
->rcv_stream
,
1641 circuit
->area
, level
);
1642 lsp_insert (lsp
, circuit
->area
->lspdb
[level
- 1]);
1644 else /* exists, so we overwrite */
1646 lsp_update (lsp
, circuit
->rcv_stream
, circuit
->area
, level
);
1649 lsp_set_all_srmflags (lsp
);
1651 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1654 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1655 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1658 /* 7.3.15.1 e) 2) LSP equal to the one in db */
1659 else if (comp
== LSP_EQUAL
)
1661 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1662 lsp_update (lsp
, circuit
->rcv_stream
, circuit
->area
, level
);
1663 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1664 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1666 /* 7.3.15.1 e) 3) LSP older than the one in db */
1669 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1670 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1677 * Process Sequence Numbers
1679 * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU
1683 process_snp (int snp_type
, int level
, struct isis_circuit
*circuit
,
1684 const u_char
*ssnpa
)
1686 int retval
= ISIS_OK
;
1688 char typechar
= ' ';
1690 struct isis_adjacency
*adj
;
1691 struct isis_complete_seqnum_hdr
*chdr
= NULL
;
1692 struct isis_partial_seqnum_hdr
*phdr
= NULL
;
1693 uint32_t found
= 0, expected
= 0, auth_tlv_offset
= 0;
1694 struct isis_lsp
*lsp
;
1695 struct lsp_entry
*entry
;
1696 struct listnode
*node
, *nnode
;
1697 struct listnode
*node2
, *nnode2
;
1699 struct list
*lsp_list
= NULL
;
1700 struct isis_passwd
*passwd
;
1702 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1704 /* getting the header info */
1707 (struct isis_complete_seqnum_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
1708 stream_forward_getp (circuit
->rcv_stream
, ISIS_CSNP_HDRLEN
);
1709 pdu_len
= ntohs (chdr
->pdu_len
);
1710 if (pdu_len
< (ISIS_FIXED_HDR_LEN
+ ISIS_CSNP_HDRLEN
) ||
1711 pdu_len
> ISO_MTU(circuit
) ||
1712 pdu_len
> stream_get_endp (circuit
->rcv_stream
))
1714 zlog_warn ("Received a CSNP with bogus length %d", pdu_len
);
1715 return ISIS_WARNING
;
1722 (struct isis_partial_seqnum_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
1723 stream_forward_getp (circuit
->rcv_stream
, ISIS_PSNP_HDRLEN
);
1724 pdu_len
= ntohs (phdr
->pdu_len
);
1725 if (pdu_len
< (ISIS_FIXED_HDR_LEN
+ ISIS_PSNP_HDRLEN
) ||
1726 pdu_len
> ISO_MTU(circuit
) ||
1727 pdu_len
> stream_get_endp (circuit
->rcv_stream
))
1729 zlog_warn ("Received a PSNP with bogus length %d", pdu_len
);
1730 return ISIS_WARNING
;
1735 * Set the stream endp to PDU length, ignoring additional padding
1736 * introduced by transport chips.
1738 if (pdu_len
< stream_get_endp (circuit
->rcv_stream
))
1739 stream_set_endp (circuit
->rcv_stream
, pdu_len
);
1741 /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */
1742 if (circuit
->ext_domain
)
1745 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1746 "skipping: circuit externalDomain = true",
1747 circuit
->area
->area_tag
,
1748 level
, typechar
, circuit
->interface
->name
);
1753 /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
1754 if (!accept_level (level
, circuit
->is_type
))
1757 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1758 "skipping: circuit type %s does not match level %d",
1759 circuit
->area
->area_tag
,
1762 circuit
->interface
->name
,
1763 circuit_t2string (circuit
->is_type
), level
);
1768 /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */
1769 if ((snp_type
== ISIS_SNP_PSNP_FLAG
) &&
1770 (circuit
->circ_type
== CIRCUIT_T_BROADCAST
) &&
1771 (!circuit
->u
.bc
.is_dr
[level
- 1]))
1773 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
1774 "skipping: we are not the DIS",
1775 circuit
->area
->area_tag
,
1777 typechar
, snpa_print (ssnpa
), circuit
->interface
->name
);
1782 /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */
1784 /* 7.3.15.2 a) 6 - maximum area match, can be ommited since we only use 3
1785 * - already checked */
1787 /* 7.3.15.2 a) 7 - Must check that we have an adjacency of the same level */
1788 /* for broadcast circuits, snpa should be compared */
1789 /* FIXME : Do we need to check SNPA? */
1790 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1792 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1795 isis_adj_lookup (chdr
->source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
1799 /* a psnp on a broadcast, how lovely of Juniper :) */
1801 isis_adj_lookup (phdr
->source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
1804 return ISIS_OK
; /* Silently discard */
1808 if (!circuit
->u
.p2p
.neighbor
)
1810 zlog_warn ("no p2p neighbor on circuit %s", circuit
->interface
->name
);
1811 return ISIS_OK
; /* Silently discard */
1815 /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */
1817 /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */
1819 memset (&tlvs
, 0, sizeof (struct tlvs
));
1822 expected
|= TLVFLAG_LSP_ENTRIES
;
1823 expected
|= TLVFLAG_AUTH_INFO
;
1825 auth_tlv_offset
= stream_get_getp (circuit
->rcv_stream
);
1826 retval
= parse_tlvs (circuit
->area
->area_tag
,
1827 STREAM_PNT (circuit
->rcv_stream
),
1828 pdu_len
- stream_get_getp (circuit
->rcv_stream
),
1829 &expected
, &found
, &tlvs
, &auth_tlv_offset
);
1831 if (retval
> ISIS_WARNING
)
1833 zlog_warn ("something went very wrong processing SNP");
1838 if (level
== IS_LEVEL_1
)
1839 passwd
= &circuit
->area
->area_passwd
;
1841 passwd
= &circuit
->area
->domain_passwd
;
1843 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_RECV
))
1847 if (!(found
& TLVFLAG_AUTH_INFO
) ||
1848 authentication_check (&tlvs
.auth_info
, passwd
,
1849 circuit
->rcv_stream
, auth_tlv_offset
))
1851 isis_event_auth_failure (circuit
->area
->area_tag
,
1852 "SNP authentication" " failure",
1853 phdr
? phdr
->source_id
:
1861 /* debug isis snp-packets */
1862 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
1864 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s",
1865 circuit
->area
->area_tag
,
1867 typechar
, snpa_print (ssnpa
), circuit
->interface
->name
);
1868 if (tlvs
.lsp_entries
)
1870 for (ALL_LIST_ELEMENTS_RO (tlvs
.lsp_entries
, node
, entry
))
1872 zlog_debug ("ISIS-Snp (%s): %cSNP entry %s, seq 0x%08x,"
1873 " cksum 0x%04x, lifetime %us",
1874 circuit
->area
->area_tag
,
1876 rawlspid_print (entry
->lsp_id
),
1877 ntohl (entry
->seq_num
),
1878 ntohs (entry
->checksum
), ntohs (entry
->rem_lifetime
));
1883 /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */
1884 if (tlvs
.lsp_entries
)
1886 for (ALL_LIST_ELEMENTS_RO (tlvs
.lsp_entries
, node
, entry
))
1888 lsp
= lsp_search (entry
->lsp_id
, circuit
->area
->lspdb
[level
- 1]);
1889 own_lsp
= !memcmp (entry
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1892 /* 7.3.15.2 b) 1) is this LSP newer */
1893 cmp
= lsp_compare (circuit
->area
->area_tag
, lsp
, entry
->seq_num
,
1894 entry
->checksum
, entry
->rem_lifetime
);
1895 /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */
1896 if (cmp
== LSP_EQUAL
)
1898 /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */
1899 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1901 /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
1902 else if (cmp
== LSP_OLDER
)
1904 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1905 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1907 /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM on p2p */
1912 lsp_inc_seqnum (lsp
, ntohl (entry
->seq_num
));
1913 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1917 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1918 /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */
1919 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1925 /* 7.3.15.2 b) 5) if it was not found, and all of those are not 0,
1926 * insert it and set SSN on it */
1927 if (entry
->rem_lifetime
&& entry
->checksum
&& entry
->seq_num
&&
1928 memcmp (entry
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
1930 lsp
= lsp_new(circuit
->area
, entry
->lsp_id
,
1931 ntohs(entry
->rem_lifetime
),
1932 0, 0, entry
->checksum
, level
);
1933 lsp_insert (lsp
, circuit
->area
->lspdb
[level
- 1]);
1934 ISIS_FLAGS_CLEAR_ALL (lsp
->SRMflags
);
1935 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1941 /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported */
1942 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1945 * Build a list from our own LSP db bounded with
1946 * start_lsp_id and stop_lsp_id
1948 lsp_list
= list_new ();
1949 lsp_build_list_nonzero_ht (chdr
->start_lsp_id
, chdr
->stop_lsp_id
,
1950 lsp_list
, circuit
->area
->lspdb
[level
- 1]);
1952 /* Fixme: Find a better solution */
1953 if (tlvs
.lsp_entries
)
1955 for (ALL_LIST_ELEMENTS (tlvs
.lsp_entries
, node
, nnode
, entry
))
1957 for (ALL_LIST_ELEMENTS (lsp_list
, node2
, nnode2
, lsp
))
1959 if (lsp_id_cmp (lsp
->lsp_header
->lsp_id
, entry
->lsp_id
) == 0)
1961 list_delete_node (lsp_list
, node2
);
1967 /* on remaining LSPs we set SRM (neighbor knew not of) */
1968 for (ALL_LIST_ELEMENTS_RO (lsp_list
, node
, lsp
))
1969 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1971 list_delete (lsp_list
);
1980 process_csnp (int level
, struct isis_circuit
*circuit
, const u_char
*ssnpa
)
1982 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
1984 zlog_debug ("ISIS-Snp (%s): Rcvd L%d CSNP on %s, cirType %s, cirID %u",
1985 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
1986 circuit_t2string (circuit
->is_type
), circuit
->circuit_id
);
1987 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
1988 zlog_dump_data (STREAM_DATA (circuit
->rcv_stream
),
1989 stream_get_endp (circuit
->rcv_stream
));
1992 /* Sanity check - FIXME: move to correct place */
1993 if ((stream_get_endp (circuit
->rcv_stream
) -
1994 stream_get_getp (circuit
->rcv_stream
)) < ISIS_CSNP_HDRLEN
)
1996 zlog_warn ("Packet too short ( < %d)", ISIS_CSNP_HDRLEN
);
1997 return ISIS_WARNING
;
2000 return process_snp (ISIS_SNP_CSNP_FLAG
, level
, circuit
, ssnpa
);
2004 process_psnp (int level
, struct isis_circuit
*circuit
, const u_char
*ssnpa
)
2006 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2008 zlog_debug ("ISIS-Snp (%s): Rcvd L%d PSNP on %s, cirType %s, cirID %u",
2009 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
2010 circuit_t2string (circuit
->is_type
), circuit
->circuit_id
);
2011 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
2012 zlog_dump_data (STREAM_DATA (circuit
->rcv_stream
),
2013 stream_get_endp (circuit
->rcv_stream
));
2016 if ((stream_get_endp (circuit
->rcv_stream
) -
2017 stream_get_getp (circuit
->rcv_stream
)) < ISIS_PSNP_HDRLEN
)
2019 zlog_warn ("Packet too short ( < %d)", ISIS_PSNP_HDRLEN
);
2020 return ISIS_WARNING
;
2023 return process_snp (ISIS_SNP_PSNP_FLAG
, level
, circuit
, ssnpa
);
2031 isis_handle_pdu (struct isis_circuit
*circuit
, u_char
* ssnpa
)
2033 struct isis_fixed_hdr
*hdr
;
2035 int retval
= ISIS_OK
;
2038 * Let's first read data from stream to the header
2040 hdr
= (struct isis_fixed_hdr
*) STREAM_DATA (circuit
->rcv_stream
);
2042 if ((hdr
->idrp
!= ISO10589_ISIS
) && (hdr
->idrp
!= ISO9542_ESIS
))
2044 zlog_err ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr
->idrp
);
2048 /* now we need to know if this is an ISO 9542 packet and
2049 * take real good care of it, waaa!
2051 if (hdr
->idrp
== ISO9542_ESIS
)
2053 zlog_err ("No support for ES-IS packet IDRP=%02x", hdr
->idrp
);
2056 stream_set_getp (circuit
->rcv_stream
, ISIS_FIXED_HDR_LEN
);
2059 * and then process it
2062 if (hdr
->length
< ISIS_MINIMUM_FIXED_HDR_LEN
)
2064 zlog_err ("Fixed header length = %d", hdr
->length
);
2068 if (hdr
->version1
!= 1)
2070 zlog_warn ("Unsupported ISIS version %u", hdr
->version1
);
2071 return ISIS_WARNING
;
2074 if ((hdr
->id_len
!= 0) && (hdr
->id_len
!= ISIS_SYS_ID_LEN
))
2077 ("IDFieldLengthMismatch: ID Length field in a received PDU %u, "
2078 "while the parameter for this IS is %u", hdr
->id_len
,
2083 if (hdr
->version2
!= 1)
2085 zlog_warn ("Unsupported ISIS version %u", hdr
->version2
);
2086 return ISIS_WARNING
;
2089 if (circuit
->is_passive
)
2091 zlog_warn ("Received ISIS PDU on passive circuit %s",
2092 circuit
->interface
->name
);
2093 return ISIS_WARNING
;
2097 if ((hdr
->max_area_addrs
!= 0)
2098 && (hdr
->max_area_addrs
!= isis
->max_area_addrs
))
2100 zlog_err ("maximumAreaAddressesMismatch: maximumAreaAdresses in a "
2101 "received PDU %u while the parameter for this IS is %u",
2102 hdr
->max_area_addrs
, isis
->max_area_addrs
);
2106 switch (hdr
->pdu_type
)
2109 retval
= process_lan_hello (ISIS_LEVEL1
, circuit
, ssnpa
);
2112 retval
= process_lan_hello (ISIS_LEVEL2
, circuit
, ssnpa
);
2115 retval
= process_p2p_hello (circuit
);
2118 retval
= process_lsp (ISIS_LEVEL1
, circuit
, ssnpa
);
2121 retval
= process_lsp (ISIS_LEVEL2
, circuit
, ssnpa
);
2123 case L1_COMPLETE_SEQ_NUM
:
2124 retval
= process_csnp (ISIS_LEVEL1
, circuit
, ssnpa
);
2126 case L2_COMPLETE_SEQ_NUM
:
2127 retval
= process_csnp (ISIS_LEVEL2
, circuit
, ssnpa
);
2129 case L1_PARTIAL_SEQ_NUM
:
2130 retval
= process_psnp (ISIS_LEVEL1
, circuit
, ssnpa
);
2132 case L2_PARTIAL_SEQ_NUM
:
2133 retval
= process_psnp (ISIS_LEVEL2
, circuit
, ssnpa
);
2144 isis_receive (struct thread
*thread
)
2146 struct isis_circuit
*circuit
;
2147 u_char ssnpa
[ETH_ALEN
];
2153 circuit
= THREAD_ARG (thread
);
2156 isis_circuit_stream(circuit
, &circuit
->rcv_stream
);
2158 retval
= circuit
->rx (circuit
, ssnpa
);
2159 circuit
->t_read
= NULL
;
2161 if (retval
== ISIS_OK
)
2162 retval
= isis_handle_pdu (circuit
, ssnpa
);
2165 * prepare for next packet.
2167 if (!circuit
->is_passive
)
2169 THREAD_READ_ON (master
, circuit
->t_read
, isis_receive
, circuit
,
2178 isis_receive (struct thread
*thread
)
2180 struct isis_circuit
*circuit
;
2181 u_char ssnpa
[ETH_ALEN
];
2187 circuit
= THREAD_ARG (thread
);
2190 circuit
->t_read
= NULL
;
2192 isis_circuit_stream(circuit
, &circuit
->rcv_stream
);
2194 retval
= circuit
->rx (circuit
, ssnpa
);
2196 if (retval
== ISIS_OK
)
2197 retval
= isis_handle_pdu (circuit
, ssnpa
);
2200 * prepare for next packet.
2202 if (!circuit
->is_passive
)
2204 circuit
->t_read
= thread_add_timer_msec (master
, isis_receive
, circuit
,
2206 (circuit
->area
->circuit_list
) *
2215 /* filling of the fixed isis header */
2217 fill_fixed_hdr (struct isis_fixed_hdr
*hdr
, u_char pdu_type
)
2219 memset (hdr
, 0, sizeof (struct isis_fixed_hdr
));
2221 hdr
->idrp
= ISO10589_ISIS
;
2227 hdr
->length
= ISIS_LANHELLO_HDRLEN
;
2230 hdr
->length
= ISIS_P2PHELLO_HDRLEN
;
2234 hdr
->length
= ISIS_LSP_HDR_LEN
;
2236 case L1_COMPLETE_SEQ_NUM
:
2237 case L2_COMPLETE_SEQ_NUM
:
2238 hdr
->length
= ISIS_CSNP_HDRLEN
;
2240 case L1_PARTIAL_SEQ_NUM
:
2241 case L2_PARTIAL_SEQ_NUM
:
2242 hdr
->length
= ISIS_PSNP_HDRLEN
;
2245 zlog_warn ("fill_fixed_hdr(): unknown pdu type %d", pdu_type
);
2248 hdr
->length
+= ISIS_FIXED_HDR_LEN
;
2249 hdr
->pdu_type
= pdu_type
;
2251 hdr
->id_len
= 0; /* ISIS_SYS_ID_LEN - 0==6 */
2253 hdr
->max_area_addrs
= 0; /* isis->max_area_addrs - 0==3 */
2260 fill_fixed_hdr_andstream (struct isis_fixed_hdr
*hdr
, u_char pdu_type
,
2261 struct stream
*stream
)
2263 fill_fixed_hdr (hdr
, pdu_type
);
2265 stream_putc (stream
, hdr
->idrp
);
2266 stream_putc (stream
, hdr
->length
);
2267 stream_putc (stream
, hdr
->version1
);
2268 stream_putc (stream
, hdr
->id_len
);
2269 stream_putc (stream
, hdr
->pdu_type
);
2270 stream_putc (stream
, hdr
->version2
);
2271 stream_putc (stream
, hdr
->reserved
);
2272 stream_putc (stream
, hdr
->max_area_addrs
);
2278 send_hello (struct isis_circuit
*circuit
, int level
)
2280 struct isis_fixed_hdr fixed_hdr
;
2281 struct isis_lan_hello_hdr hello_hdr
;
2282 struct isis_p2p_hello_hdr p2p_hello_hdr
;
2283 unsigned char hmac_md5_hash
[ISIS_AUTH_MD5_SIZE
];
2284 size_t len_pointer
, length
, auth_tlv_offset
= 0;
2288 if (circuit
->is_passive
)
2291 if (circuit
->interface
->mtu
== 0)
2293 zlog_warn ("circuit has zero MTU");
2294 return ISIS_WARNING
;
2297 isis_circuit_stream(circuit
, &circuit
->snd_stream
);
2299 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
2300 if (level
== IS_LEVEL_1
)
2301 fill_fixed_hdr_andstream (&fixed_hdr
, L1_LAN_HELLO
,
2302 circuit
->snd_stream
);
2304 fill_fixed_hdr_andstream (&fixed_hdr
, L2_LAN_HELLO
,
2305 circuit
->snd_stream
);
2307 fill_fixed_hdr_andstream (&fixed_hdr
, P2P_HELLO
, circuit
->snd_stream
);
2310 * Fill LAN Level 1 or 2 Hello PDU header
2312 memset (&hello_hdr
, 0, sizeof (struct isis_lan_hello_hdr
));
2313 interval
= circuit
->hello_multiplier
[level
- 1] *
2314 circuit
->hello_interval
[level
- 1];
2315 if (interval
> USHRT_MAX
)
2316 interval
= USHRT_MAX
;
2317 hello_hdr
.circuit_t
= circuit
->is_type
;
2318 memcpy (hello_hdr
.source_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2319 hello_hdr
.hold_time
= htons ((u_int16_t
) interval
);
2321 hello_hdr
.pdu_len
= 0; /* Update the PDU Length later */
2322 len_pointer
= stream_get_endp (circuit
->snd_stream
) + 3 + ISIS_SYS_ID_LEN
;
2324 /* copy the shared part of the hello to the p2p hello if needed */
2325 if (circuit
->circ_type
== CIRCUIT_T_P2P
)
2327 memcpy (&p2p_hello_hdr
, &hello_hdr
, 5 + ISIS_SYS_ID_LEN
);
2328 p2p_hello_hdr
.local_id
= circuit
->circuit_id
;
2329 /* FIXME: need better understanding */
2330 stream_put (circuit
->snd_stream
, &p2p_hello_hdr
, ISIS_P2PHELLO_HDRLEN
);
2334 hello_hdr
.prio
= circuit
->priority
[level
- 1];
2335 if (level
== IS_LEVEL_1
)
2337 memcpy (hello_hdr
.lan_id
, circuit
->u
.bc
.l1_desig_is
,
2338 ISIS_SYS_ID_LEN
+ 1);
2340 else if (level
== IS_LEVEL_2
)
2342 memcpy (hello_hdr
.lan_id
, circuit
->u
.bc
.l2_desig_is
,
2343 ISIS_SYS_ID_LEN
+ 1);
2345 stream_put (circuit
->snd_stream
, &hello_hdr
, ISIS_LANHELLO_HDRLEN
);
2349 * Then the variable length part.
2352 /* add circuit password */
2353 switch (circuit
->passwd
.type
)
2356 case ISIS_PASSWD_TYPE_CLEARTXT
:
2357 if (tlv_add_authinfo (circuit
->passwd
.type
, circuit
->passwd
.len
,
2358 circuit
->passwd
.passwd
, circuit
->snd_stream
))
2359 return ISIS_WARNING
;
2363 case ISIS_PASSWD_TYPE_HMAC_MD5
:
2364 /* Remember where TLV is written so we can later overwrite the MD5 hash */
2365 auth_tlv_offset
= stream_get_endp (circuit
->snd_stream
);
2366 memset(&hmac_md5_hash
, 0, ISIS_AUTH_MD5_SIZE
);
2367 if (tlv_add_authinfo (circuit
->passwd
.type
, ISIS_AUTH_MD5_SIZE
,
2368 hmac_md5_hash
, circuit
->snd_stream
))
2369 return ISIS_WARNING
;
2376 /* Area Addresses TLV */
2377 if (listcount (circuit
->area
->area_addrs
) == 0)
2378 return ISIS_WARNING
;
2379 if (tlv_add_area_addrs (circuit
->area
->area_addrs
, circuit
->snd_stream
))
2380 return ISIS_WARNING
;
2382 /* LAN Neighbors TLV */
2383 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
2385 if (level
== IS_LEVEL_1
&& circuit
->u
.bc
.lan_neighs
[0] &&
2386 listcount (circuit
->u
.bc
.lan_neighs
[0]) > 0)
2387 if (tlv_add_lan_neighs (circuit
->u
.bc
.lan_neighs
[0],
2388 circuit
->snd_stream
))
2389 return ISIS_WARNING
;
2390 if (level
== IS_LEVEL_2
&& circuit
->u
.bc
.lan_neighs
[1] &&
2391 listcount (circuit
->u
.bc
.lan_neighs
[1]) > 0)
2392 if (tlv_add_lan_neighs (circuit
->u
.bc
.lan_neighs
[1],
2393 circuit
->snd_stream
))
2394 return ISIS_WARNING
;
2397 /* Protocols Supported TLV */
2398 if (circuit
->nlpids
.count
> 0)
2399 if (tlv_add_nlpid (&circuit
->nlpids
, circuit
->snd_stream
))
2400 return ISIS_WARNING
;
2401 /* IP interface Address TLV */
2402 if (circuit
->ip_router
&& circuit
->ip_addrs
&&
2403 listcount (circuit
->ip_addrs
) > 0)
2404 if (tlv_add_ip_addrs (circuit
->ip_addrs
, circuit
->snd_stream
))
2405 return ISIS_WARNING
;
2408 /* IPv6 Interface Address TLV */
2409 if (circuit
->ipv6_router
&& circuit
->ipv6_link
&&
2410 listcount (circuit
->ipv6_link
) > 0)
2411 if (tlv_add_ipv6_addrs (circuit
->ipv6_link
, circuit
->snd_stream
))
2412 return ISIS_WARNING
;
2413 #endif /* HAVE_IPV6 */
2415 if (circuit
->pad_hellos
)
2416 if (tlv_add_padding (circuit
->snd_stream
))
2417 return ISIS_WARNING
;
2419 length
= stream_get_endp (circuit
->snd_stream
);
2420 /* Update PDU length */
2421 stream_putw_at (circuit
->snd_stream
, len_pointer
, (u_int16_t
) length
);
2423 /* For HMAC MD5 we need to compute the md5 hash and store it */
2424 if (circuit
->passwd
.type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
2426 hmac_md5 (STREAM_DATA (circuit
->snd_stream
),
2427 stream_get_endp (circuit
->snd_stream
),
2428 (unsigned char *) &circuit
->passwd
.passwd
, circuit
->passwd
.len
,
2429 (unsigned char *) &hmac_md5_hash
);
2430 /* Copy the hash into the stream */
2431 memcpy (STREAM_DATA (circuit
->snd_stream
) + auth_tlv_offset
+ 3,
2432 hmac_md5_hash
, ISIS_AUTH_MD5_SIZE
);
2435 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
2437 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
2439 zlog_debug ("ISIS-Adj (%s): Sending L%d LAN IIH on %s, length %zd",
2440 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
2445 zlog_debug ("ISIS-Adj (%s): Sending P2P IIH on %s, length %zd",
2446 circuit
->area
->area_tag
, circuit
->interface
->name
,
2449 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
2450 zlog_dump_data (STREAM_DATA (circuit
->snd_stream
),
2451 stream_get_endp (circuit
->snd_stream
));
2454 retval
= circuit
->tx (circuit
, level
);
2455 if (retval
!= ISIS_OK
)
2456 zlog_err ("ISIS-Adj (%s): Send L%d IIH on %s failed",
2457 circuit
->area
->area_tag
, level
, circuit
->interface
->name
);
2463 send_lan_l1_hello (struct thread
*thread
)
2465 struct isis_circuit
*circuit
;
2468 circuit
= THREAD_ARG (thread
);
2470 circuit
->u
.bc
.t_send_lan_hello
[0] = NULL
;
2472 if (!(circuit
->area
->is_type
& IS_LEVEL_1
))
2474 zlog_warn ("ISIS-Hello (%s): Trying to send L1 IIH in L2-only area",
2475 circuit
->area
->area_tag
);
2479 if (circuit
->u
.bc
.run_dr_elect
[0])
2480 retval
= isis_dr_elect (circuit
, 1);
2482 retval
= send_hello (circuit
, 1);
2484 /* set next timer thread */
2485 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_send_lan_hello
[0],
2486 send_lan_l1_hello
, circuit
,
2487 isis_jitter (circuit
->hello_interval
[0], IIH_JITTER
));
2493 send_lan_l2_hello (struct thread
*thread
)
2495 struct isis_circuit
*circuit
;
2498 circuit
= THREAD_ARG (thread
);
2500 circuit
->u
.bc
.t_send_lan_hello
[1] = NULL
;
2502 if (!(circuit
->area
->is_type
& IS_LEVEL_2
))
2504 zlog_warn ("ISIS-Hello (%s): Trying to send L2 IIH in L1 area",
2505 circuit
->area
->area_tag
);
2509 if (circuit
->u
.bc
.run_dr_elect
[1])
2510 retval
= isis_dr_elect (circuit
, 2);
2512 retval
= send_hello (circuit
, 2);
2514 /* set next timer thread */
2515 THREAD_TIMER_ON (master
, circuit
->u
.bc
.t_send_lan_hello
[1],
2516 send_lan_l2_hello
, circuit
,
2517 isis_jitter (circuit
->hello_interval
[1], IIH_JITTER
));
2523 send_p2p_hello (struct thread
*thread
)
2525 struct isis_circuit
*circuit
;
2527 circuit
= THREAD_ARG (thread
);
2529 circuit
->u
.p2p
.t_send_p2p_hello
= NULL
;
2531 send_hello (circuit
, 1);
2533 /* set next timer thread */
2534 THREAD_TIMER_ON (master
, circuit
->u
.p2p
.t_send_p2p_hello
, send_p2p_hello
,
2535 circuit
, isis_jitter (circuit
->hello_interval
[1],
2542 build_csnp (int level
, u_char
* start
, u_char
* stop
, struct list
*lsps
,
2543 struct isis_circuit
*circuit
)
2545 struct isis_fixed_hdr fixed_hdr
;
2546 struct isis_passwd
*passwd
;
2549 unsigned char hmac_md5_hash
[ISIS_AUTH_MD5_SIZE
];
2550 unsigned long auth_tlv_offset
= 0;
2551 int retval
= ISIS_OK
;
2553 isis_circuit_stream(circuit
, &circuit
->snd_stream
);
2555 if (level
== IS_LEVEL_1
)
2556 fill_fixed_hdr_andstream (&fixed_hdr
, L1_COMPLETE_SEQ_NUM
,
2557 circuit
->snd_stream
);
2559 fill_fixed_hdr_andstream (&fixed_hdr
, L2_COMPLETE_SEQ_NUM
,
2560 circuit
->snd_stream
);
2563 * Fill Level 1 or 2 Complete Sequence Numbers header
2566 lenp
= stream_get_endp (circuit
->snd_stream
);
2567 stream_putw (circuit
->snd_stream
, 0); /* PDU length - when we know it */
2568 /* no need to send the source here, it is always us if we csnp */
2569 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2570 /* with zero circuit id - ref 9.10, 9.11 */
2571 stream_putc (circuit
->snd_stream
, 0x00);
2573 stream_put (circuit
->snd_stream
, start
, ISIS_SYS_ID_LEN
+ 2);
2574 stream_put (circuit
->snd_stream
, stop
, ISIS_SYS_ID_LEN
+ 2);
2579 if (level
== IS_LEVEL_1
)
2580 passwd
= &circuit
->area
->area_passwd
;
2582 passwd
= &circuit
->area
->domain_passwd
;
2584 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
))
2586 switch (passwd
->type
)
2589 case ISIS_PASSWD_TYPE_CLEARTXT
:
2590 if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT
, passwd
->len
,
2591 passwd
->passwd
, circuit
->snd_stream
))
2592 return ISIS_WARNING
;
2596 case ISIS_PASSWD_TYPE_HMAC_MD5
:
2597 /* Remember where TLV is written so we can later overwrite the MD5 hash */
2598 auth_tlv_offset
= stream_get_endp (circuit
->snd_stream
);
2599 memset(&hmac_md5_hash
, 0, ISIS_AUTH_MD5_SIZE
);
2600 if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5
, ISIS_AUTH_MD5_SIZE
,
2601 hmac_md5_hash
, circuit
->snd_stream
))
2602 return ISIS_WARNING
;
2610 retval
= tlv_add_lsp_entries (lsps
, circuit
->snd_stream
);
2611 if (retval
!= ISIS_OK
)
2614 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
2615 /* Update PU length */
2616 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2618 /* For HMAC MD5 we need to compute the md5 hash and store it */
2619 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
) &&
2620 passwd
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
2622 hmac_md5 (STREAM_DATA (circuit
->snd_stream
),
2623 stream_get_endp(circuit
->snd_stream
),
2624 (unsigned char *) &passwd
->passwd
, passwd
->len
,
2625 (unsigned char *) &hmac_md5_hash
);
2626 /* Copy the hash into the stream */
2627 memcpy (STREAM_DATA (circuit
->snd_stream
) + auth_tlv_offset
+ 3,
2628 hmac_md5_hash
, ISIS_AUTH_MD5_SIZE
);
2635 * Count the maximum number of lsps that can be accomodated by a given size.
2638 get_max_lsp_count (uint16_t size
)
2642 uint16_t remaining_size
;
2644 /* First count the full size TLVs */
2645 tlv_count
= size
/ MAX_LSP_ENTRIES_TLV_SIZE
;
2646 lsp_count
= tlv_count
* (MAX_LSP_ENTRIES_TLV_SIZE
/ LSP_ENTRIES_LEN
);
2648 /* The last TLV, if any */
2649 remaining_size
= size
% MAX_LSP_ENTRIES_TLV_SIZE
;
2650 if (remaining_size
- 2 >= LSP_ENTRIES_LEN
)
2651 lsp_count
+= (remaining_size
- 2) / LSP_ENTRIES_LEN
;
2657 * Calculate the length of Authentication Info. TLV.
2660 auth_tlv_length (int level
, struct isis_circuit
*circuit
)
2662 struct isis_passwd
*passwd
;
2665 if (level
== IS_LEVEL_1
)
2666 passwd
= &circuit
->area
->area_passwd
;
2668 passwd
= &circuit
->area
->domain_passwd
;
2670 /* Also include the length of TLV header */
2671 length
= AUTH_INFO_HDRLEN
;
2672 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
))
2674 switch (passwd
->type
)
2677 case ISIS_PASSWD_TYPE_CLEARTXT
:
2678 length
+= passwd
->len
;
2682 case ISIS_PASSWD_TYPE_HMAC_MD5
:
2683 length
+= ISIS_AUTH_MD5_SIZE
;
2695 * Calculate the maximum number of lsps that can be accomodated in a CSNP/PSNP.
2698 max_lsps_per_snp (int snp_type
, int level
, struct isis_circuit
*circuit
)
2704 snp_hdr_len
= ISIS_FIXED_HDR_LEN
;
2705 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
2706 snp_hdr_len
+= ISIS_CSNP_HDRLEN
;
2708 snp_hdr_len
+= ISIS_PSNP_HDRLEN
;
2710 auth_tlv_len
= auth_tlv_length (level
, circuit
);
2711 lsp_count
= get_max_lsp_count (
2712 stream_get_size (circuit
->snd_stream
) - snp_hdr_len
- auth_tlv_len
);
2717 * FIXME: support multiple CSNPs
2721 send_csnp (struct isis_circuit
*circuit
, int level
)
2723 u_char start
[ISIS_SYS_ID_LEN
+ 2];
2724 u_char stop
[ISIS_SYS_ID_LEN
+ 2];
2725 struct list
*list
= NULL
;
2726 struct listnode
*node
;
2727 struct isis_lsp
*lsp
;
2728 u_char num_lsps
, loop
= 1;
2729 int i
, retval
= ISIS_OK
;
2731 if (circuit
->area
->lspdb
[level
- 1] == NULL
||
2732 dict_count (circuit
->area
->lspdb
[level
- 1]) == 0)
2735 memset (start
, 0x00, ISIS_SYS_ID_LEN
+ 2);
2736 memset (stop
, 0xff, ISIS_SYS_ID_LEN
+ 2);
2738 num_lsps
= max_lsps_per_snp (ISIS_SNP_CSNP_FLAG
, level
, circuit
);
2743 lsp_build_list (start
, stop
, num_lsps
, list
,
2744 circuit
->area
->lspdb
[level
- 1]);
2746 * Update the stop lsp_id before encoding this CSNP.
2748 if (listcount (list
) < num_lsps
)
2750 memset (stop
, 0xff, ISIS_SYS_ID_LEN
+ 2);
2754 node
= listtail (list
);
2755 lsp
= listgetdata (node
);
2756 memcpy (stop
, lsp
->lsp_header
->lsp_id
, ISIS_SYS_ID_LEN
+ 2);
2759 retval
= build_csnp (level
, start
, stop
, list
, circuit
);
2760 if (retval
!= ISIS_OK
)
2762 zlog_err ("ISIS-Snp (%s): Build L%d CSNP on %s failed",
2763 circuit
->area
->area_tag
, level
, circuit
->interface
->name
);
2768 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2770 zlog_debug ("ISIS-Snp (%s): Sending L%d CSNP on %s, length %zd",
2771 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
2772 stream_get_endp (circuit
->snd_stream
));
2773 for (ALL_LIST_ELEMENTS_RO (list
, node
, lsp
))
2775 zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x,"
2776 " cksum 0x%04x, lifetime %us",
2777 circuit
->area
->area_tag
,
2778 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2779 ntohl (lsp
->lsp_header
->seq_num
),
2780 ntohs (lsp
->lsp_header
->checksum
),
2781 ntohs (lsp
->lsp_header
->rem_lifetime
));
2783 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
2784 zlog_dump_data (STREAM_DATA (circuit
->snd_stream
),
2785 stream_get_endp (circuit
->snd_stream
));
2788 retval
= circuit
->tx (circuit
, level
);
2789 if (retval
!= ISIS_OK
)
2791 zlog_err ("ISIS-Snp (%s): Send L%d CSNP on %s failed",
2792 circuit
->area
->area_tag
, level
,
2793 circuit
->interface
->name
);
2799 * Start lsp_id of the next CSNP should be one plus the
2800 * stop lsp_id in this current CSNP.
2802 memcpy (start
, stop
, ISIS_SYS_ID_LEN
+ 2);
2804 for (i
= ISIS_SYS_ID_LEN
+ 1; i
>= 0; --i
)
2806 if (start
[i
] < (u_char
)0xff)
2813 memset (stop
, 0xff, ISIS_SYS_ID_LEN
+ 2);
2821 send_l1_csnp (struct thread
*thread
)
2823 struct isis_circuit
*circuit
;
2824 int retval
= ISIS_OK
;
2826 circuit
= THREAD_ARG (thread
);
2829 circuit
->t_send_csnp
[0] = NULL
;
2831 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
&& circuit
->u
.bc
.is_dr
[0])
2833 send_csnp (circuit
, 1);
2835 /* set next timer thread */
2836 THREAD_TIMER_ON (master
, circuit
->t_send_csnp
[0], send_l1_csnp
, circuit
,
2837 isis_jitter (circuit
->csnp_interval
[0], CSNP_JITTER
));
2843 send_l2_csnp (struct thread
*thread
)
2845 struct isis_circuit
*circuit
;
2846 int retval
= ISIS_OK
;
2848 circuit
= THREAD_ARG (thread
);
2851 circuit
->t_send_csnp
[1] = NULL
;
2853 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
&& circuit
->u
.bc
.is_dr
[1])
2855 send_csnp (circuit
, 2);
2857 /* set next timer thread */
2858 THREAD_TIMER_ON (master
, circuit
->t_send_csnp
[1], send_l2_csnp
, circuit
,
2859 isis_jitter (circuit
->csnp_interval
[1], CSNP_JITTER
));
2865 build_psnp (int level
, struct isis_circuit
*circuit
, struct list
*lsps
)
2867 struct isis_fixed_hdr fixed_hdr
;
2870 struct isis_lsp
*lsp
;
2871 struct isis_passwd
*passwd
;
2872 struct listnode
*node
;
2873 unsigned char hmac_md5_hash
[ISIS_AUTH_MD5_SIZE
];
2874 unsigned long auth_tlv_offset
= 0;
2875 int retval
= ISIS_OK
;
2877 isis_circuit_stream(circuit
, &circuit
->snd_stream
);
2879 if (level
== IS_LEVEL_1
)
2880 fill_fixed_hdr_andstream (&fixed_hdr
, L1_PARTIAL_SEQ_NUM
,
2881 circuit
->snd_stream
);
2883 fill_fixed_hdr_andstream (&fixed_hdr
, L2_PARTIAL_SEQ_NUM
,
2884 circuit
->snd_stream
);
2887 * Fill Level 1 or 2 Partial Sequence Numbers header
2889 lenp
= stream_get_endp (circuit
->snd_stream
);
2890 stream_putw (circuit
->snd_stream
, 0); /* PDU length - when we know it */
2891 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2892 stream_putc (circuit
->snd_stream
, circuit
->idx
);
2898 if (level
== IS_LEVEL_1
)
2899 passwd
= &circuit
->area
->area_passwd
;
2901 passwd
= &circuit
->area
->domain_passwd
;
2903 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
))
2905 switch (passwd
->type
)
2908 case ISIS_PASSWD_TYPE_CLEARTXT
:
2909 if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT
, passwd
->len
,
2910 passwd
->passwd
, circuit
->snd_stream
))
2911 return ISIS_WARNING
;
2915 case ISIS_PASSWD_TYPE_HMAC_MD5
:
2916 /* Remember where TLV is written so we can later overwrite the MD5 hash */
2917 auth_tlv_offset
= stream_get_endp (circuit
->snd_stream
);
2918 memset(&hmac_md5_hash
, 0, ISIS_AUTH_MD5_SIZE
);
2919 if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5
, ISIS_AUTH_MD5_SIZE
,
2920 hmac_md5_hash
, circuit
->snd_stream
))
2921 return ISIS_WARNING
;
2929 retval
= tlv_add_lsp_entries (lsps
, circuit
->snd_stream
);
2930 if (retval
!= ISIS_OK
)
2933 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2935 for (ALL_LIST_ELEMENTS_RO (lsps
, node
, lsp
))
2937 zlog_debug ("ISIS-Snp (%s): PSNP entry %s, seq 0x%08x,"
2938 " cksum 0x%04x, lifetime %us",
2939 circuit
->area
->area_tag
,
2940 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2941 ntohl (lsp
->lsp_header
->seq_num
),
2942 ntohs (lsp
->lsp_header
->checksum
),
2943 ntohs (lsp
->lsp_header
->rem_lifetime
));
2947 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
2948 /* Update PDU length */
2949 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2951 /* For HMAC MD5 we need to compute the md5 hash and store it */
2952 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
) &&
2953 passwd
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
2955 hmac_md5 (STREAM_DATA (circuit
->snd_stream
),
2956 stream_get_endp(circuit
->snd_stream
),
2957 (unsigned char *) &passwd
->passwd
, passwd
->len
,
2958 (unsigned char *) &hmac_md5_hash
);
2959 /* Copy the hash into the stream */
2960 memcpy (STREAM_DATA (circuit
->snd_stream
) + auth_tlv_offset
+ 3,
2961 hmac_md5_hash
, ISIS_AUTH_MD5_SIZE
);
2968 * 7.3.15.4 action on expiration of partial SNP interval
2972 send_psnp (int level
, struct isis_circuit
*circuit
)
2974 struct isis_lsp
*lsp
;
2975 struct list
*list
= NULL
;
2976 struct listnode
*node
;
2978 int retval
= ISIS_OK
;
2980 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
&&
2981 circuit
->u
.bc
.is_dr
[level
- 1])
2984 if (circuit
->area
->lspdb
[level
- 1] == NULL
||
2985 dict_count (circuit
->area
->lspdb
[level
- 1]) == 0)
2988 if (! circuit
->snd_stream
)
2991 num_lsps
= max_lsps_per_snp (ISIS_SNP_PSNP_FLAG
, level
, circuit
);
2996 lsp_build_list_ssn (circuit
, num_lsps
, list
,
2997 circuit
->area
->lspdb
[level
- 1]);
2999 if (listcount (list
) == 0)
3005 retval
= build_psnp (level
, circuit
, list
);
3006 if (retval
!= ISIS_OK
)
3008 zlog_err ("ISIS-Snp (%s): Build L%d PSNP on %s failed",
3009 circuit
->area
->area_tag
, level
, circuit
->interface
->name
);
3014 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
3016 zlog_debug ("ISIS-Snp (%s): Sending L%d PSNP on %s, length %zd",
3017 circuit
->area
->area_tag
, level
,
3018 circuit
->interface
->name
,
3019 stream_get_endp (circuit
->snd_stream
));
3020 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
3021 zlog_dump_data (STREAM_DATA (circuit
->snd_stream
),
3022 stream_get_endp (circuit
->snd_stream
));
3025 retval
= circuit
->tx (circuit
, level
);
3026 if (retval
!= ISIS_OK
)
3028 zlog_err ("ISIS-Snp (%s): Send L%d PSNP on %s failed",
3029 circuit
->area
->area_tag
, level
,
3030 circuit
->interface
->name
);
3036 * sending succeeded, we can clear SSN flags of this circuit
3037 * for the LSPs in list
3039 for (ALL_LIST_ELEMENTS_RO (list
, node
, lsp
))
3040 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
3048 send_l1_psnp (struct thread
*thread
)
3051 struct isis_circuit
*circuit
;
3052 int retval
= ISIS_OK
;
3054 circuit
= THREAD_ARG (thread
);
3057 circuit
->t_send_psnp
[0] = NULL
;
3059 send_psnp (1, circuit
);
3060 /* set next timer thread */
3061 THREAD_TIMER_ON (master
, circuit
->t_send_psnp
[0], send_l1_psnp
, circuit
,
3062 isis_jitter (circuit
->psnp_interval
[0], PSNP_JITTER
));
3068 * 7.3.15.4 action on expiration of partial SNP interval
3072 send_l2_psnp (struct thread
*thread
)
3074 struct isis_circuit
*circuit
;
3075 int retval
= ISIS_OK
;
3077 circuit
= THREAD_ARG (thread
);
3080 circuit
->t_send_psnp
[1] = NULL
;
3082 send_psnp (2, circuit
);
3084 /* set next timer thread */
3085 THREAD_TIMER_ON (master
, circuit
->t_send_psnp
[1], send_l2_psnp
, circuit
,
3086 isis_jitter (circuit
->psnp_interval
[1], PSNP_JITTER
));
3092 * ISO 10589 - 7.3.14.3
3095 send_lsp (struct thread
*thread
)
3097 struct isis_circuit
*circuit
;
3098 struct isis_lsp
*lsp
;
3099 struct listnode
*node
;
3101 int retval
= ISIS_OK
;
3103 circuit
= THREAD_ARG (thread
);
3106 if (!circuit
->lsp_queue
)
3109 node
= listhead (circuit
->lsp_queue
);
3112 * Handle case where there are no LSPs on the queue. This can
3113 * happen, for instance, if an adjacency goes down before this
3114 * thread gets a chance to run.
3120 * Delete LSP from lsp_queue. If it's still in queue, it is assumed
3121 * as 'transmit pending', but send_lsp may never be called again.
3122 * Retry will happen because SRM flag will not be cleared.
3124 lsp
= listgetdata(node
);
3125 list_delete_node (circuit
->lsp_queue
, node
);
3127 /* Set the last-cleared time if the queue is empty. */
3128 /* TODO: Is is possible that new lsps keep being added to the queue
3129 * that the queue is never empty? */
3130 if (list_isempty (circuit
->lsp_queue
))
3131 circuit
->lsp_queue_last_cleared
= time (NULL
);
3133 if (circuit
->state
!= C_STATE_UP
|| circuit
->is_passive
== 1)
3137 * Do not send if levels do not match
3139 if (!(lsp
->level
& circuit
->is_type
))
3143 * Do not send if we do not have adjacencies in state up on the circuit
3145 if (circuit
->upadjcount
[lsp
->level
- 1] == 0)
3148 /* stream_copy will assert and stop program execution if LSP is larger than
3149 * the circuit's MTU. So handle and log this case here. */
3150 if (stream_get_endp(lsp
->pdu
) > stream_get_size(circuit
->snd_stream
))
3152 zlog_err("ISIS-Upd (%s): Can't send L%d LSP %s, seq 0x%08x,"
3153 " cksum 0x%04x, lifetime %us on %s. LSP Size is %zu"
3154 " while interface stream size is %zu.",
3155 circuit
->area
->area_tag
, lsp
->level
,
3156 rawlspid_print(lsp
->lsp_header
->lsp_id
),
3157 ntohl(lsp
->lsp_header
->seq_num
),
3158 ntohs(lsp
->lsp_header
->checksum
),
3159 ntohs(lsp
->lsp_header
->rem_lifetime
),
3160 circuit
->interface
->name
,
3161 stream_get_endp(lsp
->pdu
),
3162 stream_get_size(circuit
->snd_stream
));
3163 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
3164 zlog_dump_data(STREAM_DATA(lsp
->pdu
), stream_get_endp(lsp
->pdu
));
3165 retval
= ISIS_ERROR
;
3169 /* copy our lsp to the send buffer */
3170 stream_copy (circuit
->snd_stream
, lsp
->pdu
);
3172 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
3175 ("ISIS-Upd (%s): Sending L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
3176 " lifetime %us on %s", circuit
->area
->area_tag
, lsp
->level
,
3177 rawlspid_print (lsp
->lsp_header
->lsp_id
),
3178 ntohl (lsp
->lsp_header
->seq_num
),
3179 ntohs (lsp
->lsp_header
->checksum
),
3180 ntohs (lsp
->lsp_header
->rem_lifetime
),
3181 circuit
->interface
->name
);
3182 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
3183 zlog_dump_data (STREAM_DATA (circuit
->snd_stream
),
3184 stream_get_endp (circuit
->snd_stream
));
3188 retval
= circuit
->tx (circuit
, lsp
->level
);
3189 if (retval
!= ISIS_OK
)
3191 zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed %s",
3192 circuit
->area
->area_tag
, lsp
->level
,
3193 circuit
->interface
->name
,
3194 (retval
== ISIS_WARNING
) ? "temporarily" : "permanently");
3199 || (retval
== ISIS_OK
&& circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
3200 || (retval
!= ISIS_OK
&& retval
!= ISIS_WARNING
))
3202 /* SRM flag will trigger retransmission. We will not retransmit if we
3203 * encountered a fatal error.
3204 * On success, they should only be cleared if it's a broadcast circuit.
3205 * On a P2P circuit, we will wait for the ack from the neighbor to clear
3208 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
3215 ack_lsp (struct isis_link_state_hdr
*hdr
, struct isis_circuit
*circuit
,
3221 struct isis_fixed_hdr fixed_hdr
;
3223 isis_circuit_stream(circuit
, &circuit
->snd_stream
);
3225 // fill_llc_hdr (stream);
3226 if (level
== IS_LEVEL_1
)
3227 fill_fixed_hdr_andstream (&fixed_hdr
, L1_PARTIAL_SEQ_NUM
,
3228 circuit
->snd_stream
);
3230 fill_fixed_hdr_andstream (&fixed_hdr
, L2_PARTIAL_SEQ_NUM
,
3231 circuit
->snd_stream
);
3234 lenp
= stream_get_endp (circuit
->snd_stream
);
3235 stream_putw (circuit
->snd_stream
, 0); /* PDU length */
3236 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
3237 stream_putc (circuit
->snd_stream
, circuit
->idx
);
3238 stream_putc (circuit
->snd_stream
, 9); /* code */
3239 stream_putc (circuit
->snd_stream
, 16); /* len */
3241 stream_putw (circuit
->snd_stream
, ntohs (hdr
->rem_lifetime
));
3242 stream_put (circuit
->snd_stream
, hdr
->lsp_id
, ISIS_SYS_ID_LEN
+ 2);
3243 stream_putl (circuit
->snd_stream
, ntohl (hdr
->seq_num
));
3244 stream_putw (circuit
->snd_stream
, ntohs (hdr
->checksum
));
3246 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
3247 /* Update PDU length */
3248 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
3250 retval
= circuit
->tx (circuit
, level
);
3251 if (retval
!= ISIS_OK
)
3252 zlog_err ("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed",
3253 circuit
->area
->area_tag
, level
,
3254 circuit
->interface
->name
);