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/isis_constants.h"
40 #include "isisd/isis_common.h"
41 #include "isisd/isis_flags.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_tlv.h"
48 #include "isisd/isisd.h"
49 #include "isisd/isis_dynhn.h"
50 #include "isisd/isis_lsp.h"
51 #include "isisd/isis_pdu.h"
52 #include "isisd/iso_checksum.h"
53 #include "isisd/isis_csm.h"
54 #include "isisd/isis_events.h"
55 #include "isisd/isis_te.h"
56 #include "isisd/isis_mt.h"
58 #define ISIS_MINIMUM_FIXED_HDR_LEN 15
59 #define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */
70 * Compares two sets of area addresses
73 area_match (struct list
*left
, struct list
*right
)
75 struct area_addr
*addr1
, *addr2
;
76 struct listnode
*node1
, *node2
;
78 for (ALL_LIST_ELEMENTS_RO (left
, node1
, addr1
))
80 for (ALL_LIST_ELEMENTS_RO (right
, node2
, addr2
))
82 if (addr1
->addr_len
== addr2
->addr_len
&&
83 !memcmp (addr1
->area_addr
, addr2
->area_addr
, (int) addr1
->addr_len
))
88 return 0; /* mismatch */
92 * Checks whether we should accept a PDU of given level
95 accept_level (int level
, int circuit_t
)
97 int retval
= ((circuit_t
& level
) == level
); /* simple approach */
103 * Verify authentication information
104 * Support cleartext and HMAC MD5 authentication
107 authentication_check (struct isis_passwd
*remote
, struct isis_passwd
*local
,
108 struct stream
*stream
, uint32_t auth_tlv_offset
)
110 unsigned char digest
[ISIS_AUTH_MD5_SIZE
];
112 /* Auth fail () - passwd type mismatch */
113 if (local
->type
!= remote
->type
)
118 /* No authentication required */
119 case ISIS_PASSWD_TYPE_UNUSED
:
122 /* Cleartext (ISO 10589) */
123 case ISIS_PASSWD_TYPE_CLEARTXT
:
124 /* Auth fail () - passwd len mismatch */
125 if (remote
->len
!= local
->len
)
127 return memcmp (local
->passwd
, remote
->passwd
, local
->len
);
129 /* HMAC MD5 (RFC 3567) */
130 case ISIS_PASSWD_TYPE_HMAC_MD5
:
131 /* Auth fail () - passwd len mismatch */
132 if (remote
->len
!= ISIS_AUTH_MD5_SIZE
)
134 /* Set the authentication value to 0 before the check */
135 memset (STREAM_DATA (stream
) + auth_tlv_offset
+ 3, 0,
137 /* Compute the digest */
138 hmac_md5 (STREAM_DATA (stream
), stream_get_endp (stream
),
139 (unsigned char *) &(local
->passwd
), local
->len
,
140 (unsigned char *) &digest
);
141 /* Copy back the authentication value after the check */
142 memcpy (STREAM_DATA (stream
) + auth_tlv_offset
+ 3,
143 remote
->passwd
, ISIS_AUTH_MD5_SIZE
);
144 return memcmp (digest
, remote
->passwd
, ISIS_AUTH_MD5_SIZE
);
147 zlog_err ("Unsupported authentication type");
151 /* Authentication pass when no authentication is configured */
156 lsp_authentication_check (struct stream
*stream
, struct isis_area
*area
,
157 int level
, struct isis_passwd
*passwd
)
159 struct isis_link_state_hdr
*hdr
;
160 uint32_t expected
= 0, found
= 0, auth_tlv_offset
= 0;
161 uint16_t checksum
, rem_lifetime
, pdu_len
;
163 int retval
= ISIS_OK
;
165 hdr
= (struct isis_link_state_hdr
*) (STREAM_PNT (stream
));
166 pdu_len
= ntohs (hdr
->pdu_len
);
167 expected
|= TLVFLAG_AUTH_INFO
;
168 auth_tlv_offset
= stream_get_getp (stream
) + ISIS_LSP_HDR_LEN
;
169 retval
= parse_tlvs (area
->area_tag
, STREAM_PNT (stream
) + ISIS_LSP_HDR_LEN
,
170 pdu_len
- ISIS_FIXED_HDR_LEN
- ISIS_LSP_HDR_LEN
,
171 &expected
, &found
, &tlvs
, &auth_tlv_offset
);
173 if (retval
!= ISIS_OK
)
175 zlog_err ("ISIS-Upd (%s): Parse failed L%d LSP %s, seq 0x%08x, "
176 "cksum 0x%04x, lifetime %us, len %u",
177 area
->area_tag
, level
, rawlspid_print (hdr
->lsp_id
),
178 ntohl (hdr
->seq_num
), ntohs (hdr
->checksum
),
179 ntohs (hdr
->rem_lifetime
), pdu_len
);
180 if ((isis
->debugs
& DEBUG_UPDATE_PACKETS
) &&
181 (isis
->debugs
& DEBUG_PACKET_DUMP
))
182 zlog_dump_data (STREAM_DATA (stream
), stream_get_endp (stream
));
186 if (!(found
& TLVFLAG_AUTH_INFO
))
188 zlog_err ("No authentication tlv in LSP");
192 if (tlvs
.auth_info
.type
!= ISIS_PASSWD_TYPE_CLEARTXT
&&
193 tlvs
.auth_info
.type
!= ISIS_PASSWD_TYPE_HMAC_MD5
)
195 zlog_err ("Unknown authentication type in LSP");
200 * RFC 5304 set checksum and remaining lifetime to zero before
201 * verification and reset to old values after verification.
203 checksum
= hdr
->checksum
;
204 rem_lifetime
= hdr
->rem_lifetime
;
206 hdr
->rem_lifetime
= 0;
207 retval
= authentication_check (&tlvs
.auth_info
, passwd
, stream
,
209 hdr
->checksum
= checksum
;
210 hdr
->rem_lifetime
= rem_lifetime
;
216 * Processing helper functions
221 XFREE (MTYPE_ISIS_TMP
, val
);
225 tlvs_to_adj_area_addrs (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
227 struct listnode
*node
;
228 struct area_addr
*area_addr
, *malloced
;
232 adj
->area_addrs
->del
= del_addr
;
233 list_delete (adj
->area_addrs
);
235 adj
->area_addrs
= list_new ();
236 if (tlvs
->area_addrs
)
238 for (ALL_LIST_ELEMENTS_RO (tlvs
->area_addrs
, node
, area_addr
))
240 malloced
= XMALLOC (MTYPE_ISIS_TMP
, sizeof (struct area_addr
));
241 memcpy (malloced
, area_addr
, sizeof (struct area_addr
));
242 listnode_add (adj
->area_addrs
, malloced
);
248 tlvs_to_adj_nlpids (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
251 struct nlpids
*tlv_nlpids
;
256 tlv_nlpids
= tlvs
->nlpids
;
257 if (tlv_nlpids
->count
> array_size (adj
->nlpids
.nlpids
))
260 adj
->nlpids
.count
= tlv_nlpids
->count
;
262 for (i
= 0; i
< tlv_nlpids
->count
; i
++)
264 adj
->nlpids
.nlpids
[i
] = tlv_nlpids
->nlpids
[i
];
271 tlvs_to_adj_ipv4_addrs (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
273 struct listnode
*node
;
274 struct in_addr
*ipv4_addr
, *malloced
;
278 adj
->ipv4_addrs
->del
= del_addr
;
279 list_delete (adj
->ipv4_addrs
);
281 adj
->ipv4_addrs
= list_new ();
282 if (tlvs
->ipv4_addrs
)
284 for (ALL_LIST_ELEMENTS_RO (tlvs
->ipv4_addrs
, node
, ipv4_addr
))
286 malloced
= XMALLOC (MTYPE_ISIS_TMP
, sizeof (struct in_addr
));
287 memcpy (malloced
, ipv4_addr
, sizeof (struct in_addr
));
288 listnode_add (adj
->ipv4_addrs
, malloced
);
294 tlvs_to_adj_ipv6_addrs (struct tlvs
*tlvs
, struct isis_adjacency
*adj
)
296 struct listnode
*node
;
297 struct in6_addr
*ipv6_addr
, *malloced
;
301 adj
->ipv6_addrs
->del
= del_addr
;
302 list_delete (adj
->ipv6_addrs
);
304 adj
->ipv6_addrs
= list_new ();
305 if (tlvs
->ipv6_addrs
)
307 for (ALL_LIST_ELEMENTS_RO (tlvs
->ipv6_addrs
, node
, ipv6_addr
))
309 malloced
= XMALLOC (MTYPE_ISIS_TMP
, sizeof (struct in6_addr
));
310 memcpy (malloced
, ipv6_addr
, sizeof (struct in6_addr
));
311 listnode_add (adj
->ipv6_addrs
, malloced
);
324 * Section 8.2.5 - Receiving point-to-point IIH PDUs
328 process_p2p_hello (struct isis_circuit
*circuit
)
330 int retval
= ISIS_OK
;
331 struct isis_p2p_hello_hdr
*hdr
;
332 struct isis_adjacency
*adj
;
333 u_int32_t expected
= 0, found
= 0, auth_tlv_offset
= 0;
336 int v4_usable
= 0, v6_usable
= 0;
338 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
340 zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH on %s, cirType %s, cirID %u",
341 circuit
->area
->area_tag
, circuit
->interface
->name
,
342 circuit_t2string (circuit
->is_type
), circuit
->circuit_id
);
343 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
344 zlog_dump_data (STREAM_DATA (circuit
->rcv_stream
),
345 stream_get_endp (circuit
->rcv_stream
));
348 if (circuit
->circ_type
!= CIRCUIT_T_P2P
)
350 zlog_warn ("p2p hello on non p2p circuit");
354 if ((stream_get_endp (circuit
->rcv_stream
) -
355 stream_get_getp (circuit
->rcv_stream
)) < ISIS_P2PHELLO_HDRLEN
)
357 zlog_warn ("Packet too short");
361 /* 8.2.5.1 PDU acceptance tests */
363 /* 8.2.5.1 a) external domain untrue */
364 /* FIXME: not useful at all? */
366 /* 8.2.5.1 b) ID Length mismatch */
367 /* checked at the handle_pdu */
369 /* 8.2.5.2 IIH PDU Processing */
371 /* 8.2.5.2 a) 1) Maximum Area Addresses */
372 /* Already checked, and can also be ommited */
377 hdr
= (struct isis_p2p_hello_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
378 pdu_len
= ntohs (hdr
->pdu_len
);
380 if (pdu_len
< (ISIS_FIXED_HDR_LEN
+ ISIS_P2PHELLO_HDRLEN
) ||
381 pdu_len
> ISO_MTU(circuit
) ||
382 pdu_len
> stream_get_endp (circuit
->rcv_stream
))
384 zlog_warn ("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with "
385 "invalid pdu length %d",
386 circuit
->area
->area_tag
, circuit
->interface
->name
, pdu_len
);
391 * Set the stream endp to PDU length, ignoring additional padding
392 * introduced by transport chips.
394 if (pdu_len
< stream_get_endp (circuit
->rcv_stream
))
395 stream_set_endp (circuit
->rcv_stream
, pdu_len
);
397 stream_forward_getp (circuit
->rcv_stream
, ISIS_P2PHELLO_HDRLEN
);
400 * Lets get the TLVS now
402 expected
|= TLVFLAG_AREA_ADDRS
;
403 expected
|= TLVFLAG_AUTH_INFO
;
404 expected
|= TLVFLAG_NLPID
;
405 expected
|= TLVFLAG_IPV4_ADDR
;
406 expected
|= TLVFLAG_IPV6_ADDR
;
407 expected
|= TLVFLAG_MT_ROUTER_INFORMATION
;
409 auth_tlv_offset
= stream_get_getp (circuit
->rcv_stream
);
410 retval
= parse_tlvs (circuit
->area
->area_tag
,
411 STREAM_PNT (circuit
->rcv_stream
),
412 pdu_len
- ISIS_P2PHELLO_HDRLEN
- ISIS_FIXED_HDR_LEN
,
413 &expected
, &found
, &tlvs
, &auth_tlv_offset
);
415 if (retval
> ISIS_WARNING
)
417 zlog_warn ("parse_tlvs() failed");
422 if (!(found
& TLVFLAG_AREA_ADDRS
))
424 zlog_warn ("No Area addresses TLV in P2P IS to IS hello");
429 if (!(found
& TLVFLAG_NLPID
))
431 zlog_warn ("No supported protocols TLV in P2P IS to IS hello");
436 /* 8.2.5.1 c) Authentication */
437 if (circuit
->passwd
.type
)
439 if (!(found
& TLVFLAG_AUTH_INFO
) ||
440 authentication_check (&tlvs
.auth_info
, &circuit
->passwd
,
441 circuit
->rcv_stream
, auth_tlv_offset
))
443 isis_event_auth_failure (circuit
->area
->area_tag
,
444 "P2P hello authentication failure",
452 * check if both ends have an IPv4 address
454 if (circuit
->ip_addrs
&& listcount(circuit
->ip_addrs
)
455 && tlvs
.ipv4_addrs
&& listcount(tlvs
.ipv4_addrs
))
460 if (found
& TLVFLAG_IPV6_ADDR
)
462 /* TBA: check that we have a linklocal ourselves? */
463 struct listnode
*node
;
465 for (ALL_LIST_ELEMENTS_RO (tlvs
.ipv6_addrs
, node
, ip
))
466 if (IN6_IS_ADDR_LINKLOCAL (ip
))
473 zlog_warn ("ISIS-Adj: IPv6 addresses present but no link-local "
474 "in P2P IIH from %s\n", circuit
->interface
->name
);
477 if (!(found
& (TLVFLAG_IPV4_ADDR
| TLVFLAG_IPV6_ADDR
)))
478 zlog_warn ("ISIS-Adj: neither IPv4 nor IPv6 addr in P2P IIH from %s\n",
479 circuit
->interface
->name
);
481 if (!v6_usable
&& !v4_usable
)
488 * it's own p2p IIH PDU - discard
490 if (!memcmp (hdr
->source_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
492 zlog_warn ("ISIS-Adj (%s): it's own IIH PDU - discarded",
493 circuit
->area
->area_tag
);
499 * My interpertation of the ISO, if no adj exists we will create one for
502 adj
= circuit
->u
.p2p
.neighbor
;
503 /* If an adjacency exists, check it is with the source of the hello
507 if (memcmp(hdr
->source_id
, adj
->sysid
, ISIS_SYS_ID_LEN
))
509 zlog_debug("hello source and adjacency do not match, set adj down\n");
510 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "adj do not exist");
514 if (!adj
|| adj
->level
!= hdr
->circuit_t
)
518 adj
= isis_new_adj (hdr
->source_id
, NULL
, hdr
->circuit_t
, circuit
);
524 adj
->level
= hdr
->circuit_t
;
526 circuit
->u
.p2p
.neighbor
= adj
;
527 /* Build lsp with the new neighbor entry when a new
528 * adjacency is formed. Set adjacency circuit type to
529 * IIH PDU header circuit type before lsp is regenerated
530 * when an adjacency is up. This will result in the new
531 * adjacency entry getting added to the lsp tlv neighbor list.
533 adj
->circuit_t
= hdr
->circuit_t
;
534 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
535 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
538 /* 8.2.6 Monitoring point-to-point adjacencies */
539 adj
->hold_time
= ntohs (hdr
->hold_time
);
540 adj
->last_upd
= time (NULL
);
542 /* we do this now because the adj may not survive till the end... */
543 tlvs_to_adj_area_addrs (&tlvs
, adj
);
545 /* which protocol are spoken ??? */
546 if (tlvs_to_adj_nlpids (&tlvs
, adj
))
552 /* we need to copy addresses to the adj */
553 if (found
& TLVFLAG_IPV4_ADDR
)
554 tlvs_to_adj_ipv4_addrs (&tlvs
, adj
);
556 /* Update MPLS TE Remote IP address parameter if possible */
557 if (IS_MPLS_TE(isisMplsTE
) && circuit
->mtc
&& IS_CIRCUIT_TE(circuit
->mtc
))
558 if (adj
->ipv4_addrs
!= NULL
&& listcount(adj
->ipv4_addrs
) != 0)
560 struct in_addr
*ip_addr
;
561 ip_addr
= (struct in_addr
*)listgetdata ((struct listnode
*)listhead (adj
->ipv4_addrs
));
562 set_circuitparams_rmt_ipaddr (circuit
->mtc
, *ip_addr
);
565 if (found
& TLVFLAG_IPV6_ADDR
)
566 tlvs_to_adj_ipv6_addrs (&tlvs
, adj
);
568 bool mt_set_changed
= tlvs_to_adj_mt_set(&tlvs
, v4_usable
, v6_usable
, adj
);
570 /* lets take care of the expiry */
571 THREAD_TIMER_OFF (adj
->t_expire
);
572 thread_add_timer(master
, isis_adj_expire
, adj
, (long)adj
->hold_time
,
575 /* 8.2.5.2 a) a match was detected */
576 if (area_match (circuit
->area
->area_addrs
, tlvs
.area_addrs
))
578 /* 8.2.5.2 a) 2) If the system is L1 - table 5 */
579 if (circuit
->area
->is_type
== IS_LEVEL_1
)
581 switch (hdr
->circuit_t
)
584 case IS_LEVEL_1_AND_2
:
585 if (adj
->adj_state
!= ISIS_ADJ_UP
)
587 /* (4) adj state up */
588 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
589 /* (5) adj usage level 1 */
590 adj
->adj_usage
= ISIS_ADJ_LEVEL1
;
592 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
598 if (adj
->adj_state
!= ISIS_ADJ_UP
)
600 /* (7) reject - wrong system type event */
601 zlog_warn ("wrongSystemType");
603 return ISIS_WARNING
; /* Reject */
605 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
607 /* (6) down - wrong system */
608 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
614 /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */
615 if (circuit
->area
->is_type
== IS_LEVEL_1_AND_2
)
617 switch (hdr
->circuit_t
)
620 if (adj
->adj_state
!= ISIS_ADJ_UP
)
622 /* (6) adj state up */
623 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
624 /* (7) adj usage level 1 */
625 adj
->adj_usage
= ISIS_ADJ_LEVEL1
;
627 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
631 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
632 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
634 /* (8) down - wrong system */
635 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
639 if (adj
->adj_state
!= ISIS_ADJ_UP
)
641 /* (6) adj state up */
642 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
643 /* (9) adj usage level 2 */
644 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
646 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1
) ||
647 (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
))
649 /* (8) down - wrong system */
650 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
652 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
657 case IS_LEVEL_1_AND_2
:
658 if (adj
->adj_state
!= ISIS_ADJ_UP
)
660 /* (6) adj state up */
661 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
662 /* (10) adj usage level 1 */
663 adj
->adj_usage
= ISIS_ADJ_LEVEL1AND2
;
665 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1
) ||
666 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
668 /* (8) down - wrong system */
669 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
671 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
679 /* 8.2.5.2 a) 4) If the system is L2 - table 7 */
680 if (circuit
->area
->is_type
== IS_LEVEL_2
)
682 switch (hdr
->circuit_t
)
685 if (adj
->adj_state
!= ISIS_ADJ_UP
)
687 /* (5) reject - wrong system type event */
688 zlog_warn ("wrongSystemType");
690 return ISIS_WARNING
; /* Reject */
692 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
693 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
695 /* (6) down - wrong system */
696 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
699 case IS_LEVEL_1_AND_2
:
701 if (adj
->adj_state
!= ISIS_ADJ_UP
)
703 /* (7) adj state up */
704 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
705 /* (8) adj usage level 2 */
706 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
708 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
710 /* (6) down - wrong system */
711 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
713 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
721 /* 8.2.5.2 b) if no match was detected */
722 else if (listcount (circuit
->area
->area_addrs
) > 0)
724 if (circuit
->area
->is_type
== IS_LEVEL_1
)
726 /* 8.2.5.2 b) 1) is_type L1 and adj is not up */
727 if (adj
->adj_state
!= ISIS_ADJ_UP
)
729 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch");
730 /* 8.2.5.2 b) 2)is_type L1 and adj is up */
734 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
735 "Down - Area Mismatch");
738 /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */
741 switch (hdr
->circuit_t
)
744 if (adj
->adj_state
!= ISIS_ADJ_UP
)
746 /* (6) reject - Area Mismatch event */
747 zlog_warn ("AreaMismatch");
749 return ISIS_WARNING
; /* Reject */
751 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
753 /* (7) down - area mismatch */
754 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch");
757 else if ((adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
) ||
758 (adj
->adj_usage
== ISIS_ADJ_LEVEL2
))
760 /* (7) down - wrong system */
761 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
764 case IS_LEVEL_1_AND_2
:
766 if (adj
->adj_state
!= ISIS_ADJ_UP
)
768 /* (8) adj state up */
769 isis_adj_state_change (adj
, ISIS_ADJ_UP
, NULL
);
770 /* (9) adj usage level 2 */
771 adj
->adj_usage
= ISIS_ADJ_LEVEL2
;
773 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1
)
775 /* (7) down - wrong system */
776 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Wrong System");
778 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL1AND2
)
780 if (hdr
->circuit_t
== IS_LEVEL_2
)
782 /* (7) down - wrong system */
783 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
788 /* (7) down - area mismatch */
789 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
,
793 else if (adj
->adj_usage
== ISIS_ADJ_LEVEL2
)
803 /* down - area mismatch */
804 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "Area Mismatch");
807 if (adj
->adj_state
== ISIS_ADJ_UP
&& mt_set_changed
)
809 lsp_regenerate_schedule(adj
->circuit
->area
,
810 isis_adj_usage2levels(adj
->adj_usage
), 0);
813 /* 8.2.5.2 c) if the action was up - comparing circuit IDs */
814 /* FIXME - Missing parts */
816 /* some of my own understanding of the ISO, why the heck does
817 * it not say what should I change the system_type to...
819 switch (adj
->adj_usage
)
821 case ISIS_ADJ_LEVEL1
:
822 adj
->sys_type
= ISIS_SYSTYPE_L1_IS
;
824 case ISIS_ADJ_LEVEL2
:
825 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
827 case ISIS_ADJ_LEVEL1AND2
:
828 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
831 adj
->sys_type
= ISIS_SYSTYPE_UNKNOWN
;
836 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
838 zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
839 " cir id %02d, length %d",
840 circuit
->area
->area_tag
, circuit
->interface
->name
,
841 circuit_t2string (circuit
->is_type
),
842 circuit
->circuit_id
, pdu_len
);
851 * Process IS-IS LAN Level 1/2 Hello PDU
854 process_lan_hello (int level
, struct isis_circuit
*circuit
, const u_char
*ssnpa
)
856 int retval
= ISIS_OK
;
857 struct isis_lan_hello_hdr hdr
;
858 struct isis_adjacency
*adj
;
859 u_int32_t expected
= 0, found
= 0, auth_tlv_offset
= 0;
862 struct listnode
*node
;
863 int v4_usable
= 0, v6_usable
= 0;
865 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
867 zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH on %s, cirType %s, "
869 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
870 circuit_t2string (circuit
->is_type
), circuit
->circuit_id
);
871 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
872 zlog_dump_data (STREAM_DATA (circuit
->rcv_stream
),
873 stream_get_endp (circuit
->rcv_stream
));
876 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
878 zlog_warn ("lan hello on non broadcast circuit");
882 if ((stream_get_endp (circuit
->rcv_stream
) -
883 stream_get_getp (circuit
->rcv_stream
)) < ISIS_LANHELLO_HDRLEN
)
885 zlog_warn ("Packet too short");
889 if (circuit
->ext_domain
)
891 zlog_debug ("level %d LAN Hello received over circuit with "
892 "externalDomain = true", level
);
896 if (!accept_level (level
, circuit
->is_type
))
898 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
900 zlog_debug ("ISIS-Adj (%s): Interface level mismatch, %s",
901 circuit
->area
->area_tag
, circuit
->interface
->name
);
907 /* Cisco's debug message compatability */
908 if (!accept_level (level
, circuit
->area
->is_type
))
910 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
912 zlog_debug ("ISIS-Adj (%s): is type mismatch",
913 circuit
->area
->area_tag
);
921 hdr
.circuit_t
= stream_getc (circuit
->rcv_stream
);
922 stream_get (hdr
.source_id
, circuit
->rcv_stream
, ISIS_SYS_ID_LEN
);
923 hdr
.hold_time
= stream_getw (circuit
->rcv_stream
);
924 hdr
.pdu_len
= stream_getw (circuit
->rcv_stream
);
925 hdr
.prio
= stream_getc (circuit
->rcv_stream
);
926 stream_get (hdr
.lan_id
, circuit
->rcv_stream
, ISIS_SYS_ID_LEN
+ 1);
928 if (hdr
.pdu_len
< (ISIS_FIXED_HDR_LEN
+ ISIS_LANHELLO_HDRLEN
) ||
929 hdr
.pdu_len
> ISO_MTU(circuit
) ||
930 hdr
.pdu_len
> stream_get_endp (circuit
->rcv_stream
))
932 zlog_warn ("ISIS-Adj (%s): Rcvd LAN IIH from (%s) with "
933 "invalid pdu length %d",
934 circuit
->area
->area_tag
, circuit
->interface
->name
,
940 * Set the stream endp to PDU length, ignoring additional padding
941 * introduced by transport chips.
943 if (hdr
.pdu_len
< stream_get_endp (circuit
->rcv_stream
))
944 stream_set_endp (circuit
->rcv_stream
, hdr
.pdu_len
);
946 if (hdr
.circuit_t
!= IS_LEVEL_1
&&
947 hdr
.circuit_t
!= IS_LEVEL_2
&&
948 hdr
.circuit_t
!= IS_LEVEL_1_AND_2
&&
949 (level
& hdr
.circuit_t
) == 0)
951 zlog_err ("Level %d LAN Hello with Circuit Type %d", level
,
959 expected
|= TLVFLAG_AUTH_INFO
;
960 expected
|= TLVFLAG_AREA_ADDRS
;
961 expected
|= TLVFLAG_LAN_NEIGHS
;
962 expected
|= TLVFLAG_NLPID
;
963 expected
|= TLVFLAG_IPV4_ADDR
;
964 expected
|= TLVFLAG_IPV6_ADDR
;
965 expected
|= TLVFLAG_MT_ROUTER_INFORMATION
;
967 auth_tlv_offset
= stream_get_getp (circuit
->rcv_stream
);
968 retval
= parse_tlvs (circuit
->area
->area_tag
,
969 STREAM_PNT (circuit
->rcv_stream
),
970 hdr
.pdu_len
- ISIS_LANHELLO_HDRLEN
- ISIS_FIXED_HDR_LEN
,
971 &expected
, &found
, &tlvs
,
974 if (retval
> ISIS_WARNING
)
976 zlog_warn ("parse_tlvs() failed");
980 if (!(found
& TLVFLAG_AREA_ADDRS
))
982 zlog_warn ("No Area addresses TLV in Level %d LAN IS to IS hello",
984 retval
= ISIS_WARNING
;
988 if (!(found
& TLVFLAG_NLPID
))
990 zlog_warn ("No supported protocols TLV in Level %d LAN IS to IS hello",
992 retval
= ISIS_WARNING
;
996 /* Verify authentication, either cleartext of HMAC MD5 */
997 if (circuit
->passwd
.type
)
999 if (!(found
& TLVFLAG_AUTH_INFO
) ||
1000 authentication_check (&tlvs
.auth_info
, &circuit
->passwd
,
1001 circuit
->rcv_stream
, auth_tlv_offset
))
1003 isis_event_auth_failure (circuit
->area
->area_tag
,
1004 "LAN hello authentication failure",
1006 retval
= ISIS_WARNING
;
1011 if (!memcmp (hdr
.source_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
1013 zlog_warn ("ISIS-Adj (%s): duplicate system ID on interface %s",
1014 circuit
->area
->area_tag
, circuit
->interface
->name
);
1015 return ISIS_WARNING
;
1019 * Accept the level 1 adjacency only if a match between local and
1020 * remote area addresses is found
1022 if (listcount (circuit
->area
->area_addrs
) == 0 ||
1023 (level
== IS_LEVEL_1
&&
1024 area_match (circuit
->area
->area_addrs
, tlvs
.area_addrs
) == 0))
1026 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
1028 zlog_debug ("ISIS-Adj (%s): Area mismatch, level %d IIH on %s",
1029 circuit
->area
->area_tag
, level
,
1030 circuit
->interface
->name
);
1037 * it's own IIH PDU - discard silently
1039 if (!memcmp (circuit
->u
.bc
.snpa
, ssnpa
, ETH_ALEN
))
1041 zlog_debug ("ISIS-Adj (%s): it's own IIH PDU - discarded",
1042 circuit
->area
->area_tag
);
1049 * check if both ends have an IPv4 address
1051 if (circuit
->ip_addrs
&& listcount(circuit
->ip_addrs
)
1052 && tlvs
.ipv4_addrs
&& listcount(tlvs
.ipv4_addrs
))
1057 if (found
& TLVFLAG_IPV6_ADDR
)
1059 /* TBA: check that we have a linklocal ourselves? */
1060 struct listnode
*node
;
1061 struct in6_addr
*ip
;
1062 for (ALL_LIST_ELEMENTS_RO (tlvs
.ipv6_addrs
, node
, ip
))
1063 if (IN6_IS_ADDR_LINKLOCAL (ip
))
1070 zlog_warn ("ISIS-Adj: IPv6 addresses present but no link-local "
1071 "in LAN IIH from %s\n", circuit
->interface
->name
);
1074 if (!(found
& (TLVFLAG_IPV4_ADDR
| TLVFLAG_IPV6_ADDR
)))
1075 zlog_warn ("ISIS-Adj: neither IPv4 nor IPv6 addr in LAN IIH from %s\n",
1076 circuit
->interface
->name
);
1078 if (!v6_usable
&& !v4_usable
)
1081 return ISIS_WARNING
;
1085 adj
= isis_adj_lookup (hdr
.source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
1086 if ((adj
== NULL
) || (memcmp(adj
->snpa
, ssnpa
, ETH_ALEN
)) ||
1087 (adj
->level
!= level
))
1094 adj
= isis_new_adj (hdr
.source_id
, ssnpa
, level
, circuit
);
1097 retval
= ISIS_ERROR
;
1104 memcpy (adj
->snpa
, ssnpa
, 6);
1106 memset (adj
->snpa
, ' ', 6);
1110 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
, NULL
);
1112 if (level
== IS_LEVEL_1
)
1113 adj
->sys_type
= ISIS_SYSTYPE_L1_IS
;
1115 adj
->sys_type
= ISIS_SYSTYPE_L2_IS
;
1116 list_delete_all_node (circuit
->u
.bc
.lan_neighs
[level
- 1]);
1117 isis_adj_build_neigh_list (circuit
->u
.bc
.adjdb
[level
- 1],
1118 circuit
->u
.bc
.lan_neighs
[level
- 1]);
1121 if(adj
->dis_record
[level
-1].dis
==ISIS_IS_DIS
)
1125 if (memcmp (circuit
->u
.bc
.l1_desig_is
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1))
1127 thread_add_event(master
, isis_event_dis_status_change
, circuit
, 0,
1129 memcpy (&circuit
->u
.bc
.l1_desig_is
, hdr
.lan_id
,
1130 ISIS_SYS_ID_LEN
+ 1);
1134 if (memcmp (circuit
->u
.bc
.l2_desig_is
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1))
1136 thread_add_event(master
, isis_event_dis_status_change
, circuit
, 0,
1138 memcpy (&circuit
->u
.bc
.l2_desig_is
, hdr
.lan_id
,
1139 ISIS_SYS_ID_LEN
+ 1);
1144 adj
->hold_time
= hdr
.hold_time
;
1145 adj
->last_upd
= time (NULL
);
1146 adj
->prio
[level
- 1] = hdr
.prio
;
1148 memcpy (adj
->lanid
, hdr
.lan_id
, ISIS_SYS_ID_LEN
+ 1);
1150 tlvs_to_adj_area_addrs (&tlvs
, adj
);
1152 /* which protocol are spoken ??? */
1153 if (tlvs_to_adj_nlpids (&tlvs
, adj
))
1155 retval
= ISIS_WARNING
;
1159 /* we need to copy addresses to the adj */
1160 if (found
& TLVFLAG_IPV4_ADDR
)
1161 tlvs_to_adj_ipv4_addrs (&tlvs
, adj
);
1163 if (found
& TLVFLAG_IPV6_ADDR
)
1164 tlvs_to_adj_ipv6_addrs (&tlvs
, adj
);
1166 adj
->circuit_t
= hdr
.circuit_t
;
1168 bool mt_set_changed
= tlvs_to_adj_mt_set(&tlvs
, v4_usable
, v6_usable
, adj
);
1170 /* lets take care of the expiry */
1171 THREAD_TIMER_OFF (adj
->t_expire
);
1172 thread_add_timer(master
, isis_adj_expire
, adj
, (long)adj
->hold_time
,
1176 * If the snpa for this circuit is found from LAN Neighbours TLV
1177 * we have two-way communication -> adjacency can be put to state "up"
1180 if (found
& TLVFLAG_LAN_NEIGHS
)
1182 if (adj
->adj_state
!= ISIS_ADJ_UP
)
1184 for (ALL_LIST_ELEMENTS_RO (tlvs
.lan_neighs
, node
, snpa
))
1186 if (!memcmp (snpa
, circuit
->u
.bc
.snpa
, ETH_ALEN
))
1188 isis_adj_state_change (adj
, ISIS_ADJ_UP
,
1189 "own SNPA found in LAN Neighbours TLV");
1196 for (ALL_LIST_ELEMENTS_RO (tlvs
.lan_neighs
, node
, snpa
))
1197 if (!memcmp (snpa
, circuit
->u
.bc
.snpa
, ETH_ALEN
))
1203 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
,
1204 "own SNPA not found in LAN Neighbours TLV");
1207 else if (adj
->adj_state
== ISIS_ADJ_UP
)
1209 isis_adj_state_change (adj
, ISIS_ADJ_INITIALIZING
,
1210 "no LAN Neighbours TLV found");
1213 if (adj
->adj_state
== ISIS_ADJ_UP
&& mt_set_changed
)
1214 lsp_regenerate_schedule(adj
->circuit
->area
, level
, 0);
1217 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
1219 zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "
1220 "cirID %u, length %zd",
1221 circuit
->area
->area_tag
,
1222 level
, snpa_print (ssnpa
), circuit
->interface
->name
,
1223 circuit_t2string (circuit
->is_type
),
1224 circuit
->circuit_id
,
1225 stream_get_endp (circuit
->rcv_stream
));
1234 * Process Level 1/2 Link State
1236 * Section 7.3.15.1 - Action on receipt of a link state PDU
1239 process_lsp (int level
, struct isis_circuit
*circuit
, const u_char
*ssnpa
)
1241 struct isis_link_state_hdr
*hdr
;
1242 struct isis_adjacency
*adj
= NULL
;
1243 struct isis_lsp
*lsp
, *lsp0
= NULL
;
1244 int retval
= ISIS_OK
, comp
= 0;
1245 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
1246 struct isis_passwd
*passwd
;
1250 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1252 zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP on %s, cirType %s, cirID %u",
1253 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
1254 circuit_t2string (circuit
->is_type
), circuit
->circuit_id
);
1255 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
1256 zlog_dump_data (STREAM_DATA (circuit
->rcv_stream
),
1257 stream_get_endp (circuit
->rcv_stream
));
1260 if ((stream_get_endp (circuit
->rcv_stream
) -
1261 stream_get_getp (circuit
->rcv_stream
)) < ISIS_LSP_HDR_LEN
)
1263 zlog_warn ("Packet too short");
1264 return ISIS_WARNING
;
1267 /* Reference the header */
1268 hdr
= (struct isis_link_state_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
1269 pdu_len
= ntohs (hdr
->pdu_len
);
1271 /* lsp length check */
1272 if (pdu_len
< (ISIS_FIXED_HDR_LEN
+ ISIS_LSP_HDR_LEN
) ||
1273 pdu_len
> ISO_MTU(circuit
) ||
1274 pdu_len
> stream_get_endp (circuit
->rcv_stream
))
1276 zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP length %d",
1277 circuit
->area
->area_tag
,
1278 rawlspid_print (hdr
->lsp_id
), pdu_len
);
1280 return ISIS_WARNING
;
1284 * Set the stream endp to PDU length, ignoring additional padding
1285 * introduced by transport chips.
1287 if (pdu_len
< stream_get_endp (circuit
->rcv_stream
))
1288 stream_set_endp (circuit
->rcv_stream
, pdu_len
);
1290 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1292 zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "
1293 "lifetime %us, len %u, on %s",
1294 circuit
->area
->area_tag
,
1296 rawlspid_print (hdr
->lsp_id
),
1297 ntohl (hdr
->seq_num
),
1298 ntohs (hdr
->checksum
),
1299 ntohs (hdr
->rem_lifetime
),
1301 circuit
->interface
->name
);
1304 /* lsp is_type check */
1305 if ((hdr
->lsp_bits
& IS_LEVEL_1_AND_2
) != IS_LEVEL_1
&&
1306 (hdr
->lsp_bits
& IS_LEVEL_1_AND_2
) != IS_LEVEL_1_AND_2
)
1308 zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP is type %x",
1309 circuit
->area
->area_tag
,
1310 rawlspid_print (hdr
->lsp_id
), hdr
->lsp_bits
);
1311 /* continue as per RFC1122 Be liberal in what you accept, and
1312 * conservative in what you send */
1315 /* Checksum sanity check - FIXME: move to correct place */
1316 /* 12 = sysid+pdu+remtime */
1317 if (iso_csum_verify (STREAM_PNT (circuit
->rcv_stream
) + 4,
1318 pdu_len
- 12, &hdr
->checksum
))
1320 zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
1321 circuit
->area
->area_tag
,
1322 rawlspid_print (hdr
->lsp_id
), ntohs (hdr
->checksum
));
1324 return ISIS_WARNING
;
1327 /* 7.3.15.1 a) 1 - external domain circuit will discard lsps */
1328 if (circuit
->ext_domain
)
1331 ("ISIS-Upd (%s): LSP %s received at level %d over circuit with "
1332 "externalDomain = true", circuit
->area
->area_tag
,
1333 rawlspid_print (hdr
->lsp_id
), level
);
1335 return ISIS_WARNING
;
1338 /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
1339 if (!accept_level (level
, circuit
->is_type
))
1341 zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of"
1343 circuit
->area
->area_tag
,
1344 rawlspid_print (hdr
->lsp_id
),
1345 level
, circuit_t2string (circuit
->is_type
));
1347 return ISIS_WARNING
;
1350 /* 7.3.15.1 a) 4 - need to make sure IDLength matches */
1352 /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */
1354 /* 7.3.15.1 a) 7 - password check */
1355 (level
== IS_LEVEL_1
) ? (passwd
= &circuit
->area
->area_passwd
) :
1356 (passwd
= &circuit
->area
->domain_passwd
);
1359 if (lsp_authentication_check (circuit
->rcv_stream
, circuit
->area
,
1362 isis_event_auth_failure (circuit
->area
->area_tag
,
1363 "LSP authentication failure", hdr
->lsp_id
);
1364 return ISIS_WARNING
;
1367 /* Find the LSP in our database and compare it to this Link State header */
1368 lsp
= lsp_search (hdr
->lsp_id
, circuit
->area
->lspdb
[level
- 1]);
1370 comp
= lsp_compare (circuit
->area
->area_tag
, lsp
, hdr
->seq_num
,
1371 hdr
->checksum
, hdr
->rem_lifetime
);
1372 if (lsp
&& (lsp
->own_lsp
))
1375 /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level */
1376 /* for broadcast circuits, snpa should be compared */
1378 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1380 adj
= isis_adj_lookup_snpa (ssnpa
, circuit
->u
.bc
.adjdb
[level
- 1]);
1383 zlog_debug ("(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, "
1384 "lifetime %us on %s",
1385 circuit
->area
->area_tag
,
1386 rawlspid_print (hdr
->lsp_id
),
1387 ntohl (hdr
->seq_num
),
1388 ntohs (hdr
->checksum
),
1389 ntohs (hdr
->rem_lifetime
), circuit
->interface
->name
);
1390 return ISIS_WARNING
; /* Silently discard */
1393 /* for non broadcast, we just need to find same level adj */
1396 /* If no adj, or no sharing of level */
1397 if (!circuit
->u
.p2p
.neighbor
)
1399 return ISIS_OK
; /* Silently discard */
1403 if (((level
== IS_LEVEL_1
) &&
1404 (circuit
->u
.p2p
.neighbor
->adj_usage
== ISIS_ADJ_LEVEL2
)) ||
1405 ((level
== IS_LEVEL_2
) &&
1406 (circuit
->u
.p2p
.neighbor
->adj_usage
== ISIS_ADJ_LEVEL1
)))
1407 return ISIS_WARNING
; /* Silently discard */
1408 adj
= circuit
->u
.p2p
.neighbor
;
1413 /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */
1415 /* 7.3.15.1 a) 8 - Passwords for level 2 - not implemented */
1417 /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented FIXME: do it */
1419 /* 7.3.16.2 - If this is an LSP from another IS with identical seq_num but
1420 * wrong checksum, initiate a purge. */
1422 && (lsp
->lsp_header
->seq_num
== hdr
->seq_num
)
1423 && (lsp
->lsp_header
->checksum
!= hdr
->checksum
))
1425 zlog_warn("ISIS-Upd (%s): LSP %s seq 0x%08x with confused checksum received.",
1426 circuit
->area
->area_tag
, rawlspid_print(hdr
->lsp_id
),
1427 ntohl(hdr
->seq_num
));
1428 hdr
->rem_lifetime
= 0;
1434 /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */
1435 if (hdr
->rem_lifetime
== 0)
1439 /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't save */
1440 /* only needed on explicit update, eg - p2p */
1441 if (circuit
->circ_type
== CIRCUIT_T_P2P
)
1442 ack_lsp (hdr
, circuit
, level
);
1443 return retval
; /* FIXME: do we need a purge? */
1447 if (memcmp (hdr
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
1449 /* LSP by some other system -> do 7.3.16.4 b) */
1450 /* 7.3.16.4 b) 1) */
1451 if (comp
== LSP_NEWER
)
1453 lsp_update (lsp
, circuit
->rcv_stream
, circuit
->area
, level
);
1455 lsp_set_all_srmflags (lsp
);
1457 ISIS_FLAGS_CLEAR_ALL (lsp
->SSNflags
); /* FIXME: OTHER than c */
1459 /* For the case of lsp confusion, flood the purge back to its
1460 * originator so that it can react. Otherwise, don't reflood
1461 * through incoming circuit as usual */
1465 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1467 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1468 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1470 } /* 7.3.16.4 b) 2) */
1471 else if (comp
== LSP_EQUAL
)
1474 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1476 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1477 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1478 } /* 7.3.16.4 b) 3) */
1481 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1482 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1485 else if (lsp
->lsp_header
->rem_lifetime
!= 0)
1487 /* our own LSP -> 7.3.16.4 c) */
1488 if (comp
== LSP_NEWER
)
1490 lsp_inc_seqnum (lsp
, ntohl (hdr
->seq_num
));
1491 lsp_set_all_srmflags (lsp
);
1495 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1496 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1498 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1499 zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new "
1500 "seq 0x%08x", circuit
->area
->area_tag
,
1501 rawlspid_print (hdr
->lsp_id
),
1502 ntohl (lsp
->lsp_header
->seq_num
));
1507 /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a
1509 if (memcmp (hdr
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
) == 0)
1513 /* 7.3.16.4: initiate a purge */
1514 lsp_purge_non_exist(level
, hdr
, circuit
->area
);
1517 /* 7.3.15.1 d) - If this is our own lsp and we have it */
1519 /* In 7.3.16.1, If an Intermediate system R somewhere in the domain
1520 * has information that the current sequence number for source S is
1521 * "greater" than that held by S, ... */
1523 if (ntohl (hdr
->seq_num
) > ntohl (lsp
->lsp_header
->seq_num
))
1526 lsp_inc_seqnum (lsp
, ntohl (hdr
->seq_num
));
1527 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
1528 zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq "
1529 "0x%08x", circuit
->area
->area_tag
,
1530 rawlspid_print (hdr
->lsp_id
),
1531 ntohl (lsp
->lsp_header
->seq_num
));
1533 /* If the received LSP is older or equal,
1534 * resend the LSP which will act as ACK */
1535 lsp_set_all_srmflags (lsp
);
1539 /* 7.3.15.1 e) - This lsp originated on another system */
1541 /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */
1542 if ((!lsp
|| comp
== LSP_NEWER
))
1545 * If this lsp is a frag, need to see if we have zero lsp present
1547 if (LSP_FRAGMENT (hdr
->lsp_id
) != 0)
1549 memcpy (lspid
, hdr
->lsp_id
, ISIS_SYS_ID_LEN
+ 1);
1550 LSP_FRAGMENT (lspid
) = 0;
1551 lsp0
= lsp_search (lspid
, circuit
->area
->lspdb
[level
- 1]);
1554 zlog_debug ("Got lsp frag, while zero lsp not in database");
1561 lsp
= lsp_new_from_stream_ptr (circuit
->rcv_stream
,
1563 circuit
->area
, level
);
1564 lsp_insert (lsp
, circuit
->area
->lspdb
[level
- 1]);
1566 else /* exists, so we overwrite */
1568 lsp_update (lsp
, circuit
->rcv_stream
, circuit
->area
, level
);
1571 lsp_set_all_srmflags (lsp
);
1573 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1576 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1577 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1580 /* 7.3.15.1 e) 2) LSP equal to the one in db */
1581 else if (comp
== LSP_EQUAL
)
1583 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1584 lsp_update (lsp
, circuit
->rcv_stream
, circuit
->area
, level
);
1585 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
1586 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1588 /* 7.3.15.1 e) 3) LSP older than the one in db */
1591 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1592 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1599 * Process Sequence Numbers
1601 * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU
1605 process_snp (int snp_type
, int level
, struct isis_circuit
*circuit
,
1606 const u_char
*ssnpa
)
1608 int retval
= ISIS_OK
;
1610 char typechar
= ' ';
1612 struct isis_adjacency
*adj
;
1613 struct isis_complete_seqnum_hdr
*chdr
= NULL
;
1614 struct isis_partial_seqnum_hdr
*phdr
= NULL
;
1615 uint32_t found
= 0, expected
= 0, auth_tlv_offset
= 0;
1616 struct isis_lsp
*lsp
;
1617 struct lsp_entry
*entry
;
1618 struct listnode
*node
, *nnode
;
1619 struct listnode
*node2
, *nnode2
;
1621 struct list
*lsp_list
= NULL
;
1622 struct isis_passwd
*passwd
;
1624 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1626 /* getting the header info */
1629 (struct isis_complete_seqnum_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
1630 stream_forward_getp (circuit
->rcv_stream
, ISIS_CSNP_HDRLEN
);
1631 pdu_len
= ntohs (chdr
->pdu_len
);
1632 if (pdu_len
< (ISIS_FIXED_HDR_LEN
+ ISIS_CSNP_HDRLEN
) ||
1633 pdu_len
> ISO_MTU(circuit
) ||
1634 pdu_len
> stream_get_endp (circuit
->rcv_stream
))
1636 zlog_warn ("Received a CSNP with bogus length %d", pdu_len
);
1637 return ISIS_WARNING
;
1644 (struct isis_partial_seqnum_hdr
*) STREAM_PNT (circuit
->rcv_stream
);
1645 stream_forward_getp (circuit
->rcv_stream
, ISIS_PSNP_HDRLEN
);
1646 pdu_len
= ntohs (phdr
->pdu_len
);
1647 if (pdu_len
< (ISIS_FIXED_HDR_LEN
+ ISIS_PSNP_HDRLEN
) ||
1648 pdu_len
> ISO_MTU(circuit
) ||
1649 pdu_len
> stream_get_endp (circuit
->rcv_stream
))
1651 zlog_warn ("Received a PSNP with bogus length %d", pdu_len
);
1652 return ISIS_WARNING
;
1657 * Set the stream endp to PDU length, ignoring additional padding
1658 * introduced by transport chips.
1660 if (pdu_len
< stream_get_endp (circuit
->rcv_stream
))
1661 stream_set_endp (circuit
->rcv_stream
, pdu_len
);
1663 /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */
1664 if (circuit
->ext_domain
)
1667 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1668 "skipping: circuit externalDomain = true",
1669 circuit
->area
->area_tag
,
1670 level
, typechar
, circuit
->interface
->name
);
1675 /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
1676 if (!accept_level (level
, circuit
->is_type
))
1679 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
1680 "skipping: circuit type %s does not match level %d",
1681 circuit
->area
->area_tag
,
1684 circuit
->interface
->name
,
1685 circuit_t2string (circuit
->is_type
), level
);
1690 /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */
1691 if ((snp_type
== ISIS_SNP_PSNP_FLAG
) &&
1692 (circuit
->circ_type
== CIRCUIT_T_BROADCAST
) &&
1693 (!circuit
->u
.bc
.is_dr
[level
- 1]))
1695 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
1696 "skipping: we are not the DIS",
1697 circuit
->area
->area_tag
,
1699 typechar
, snpa_print (ssnpa
), circuit
->interface
->name
);
1704 /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */
1706 /* 7.3.15.2 a) 6 - maximum area match, can be ommited since we only use 3
1707 * - already checked */
1709 /* 7.3.15.2 a) 7 - Must check that we have an adjacency of the same level */
1710 /* for broadcast circuits, snpa should be compared */
1711 /* FIXME : Do we need to check SNPA? */
1712 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1714 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1717 isis_adj_lookup (chdr
->source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
1721 /* a psnp on a broadcast, how lovely of Juniper :) */
1723 isis_adj_lookup (phdr
->source_id
, circuit
->u
.bc
.adjdb
[level
- 1]);
1726 return ISIS_OK
; /* Silently discard */
1730 if (!circuit
->u
.p2p
.neighbor
)
1732 zlog_warn ("no p2p neighbor on circuit %s", circuit
->interface
->name
);
1733 return ISIS_OK
; /* Silently discard */
1737 /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */
1739 /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */
1741 memset (&tlvs
, 0, sizeof (struct tlvs
));
1744 expected
|= TLVFLAG_LSP_ENTRIES
;
1745 expected
|= TLVFLAG_AUTH_INFO
;
1747 auth_tlv_offset
= stream_get_getp (circuit
->rcv_stream
);
1748 retval
= parse_tlvs (circuit
->area
->area_tag
,
1749 STREAM_PNT (circuit
->rcv_stream
),
1750 pdu_len
- stream_get_getp (circuit
->rcv_stream
),
1751 &expected
, &found
, &tlvs
, &auth_tlv_offset
);
1753 if (retval
> ISIS_WARNING
)
1755 zlog_warn ("something went very wrong processing SNP");
1760 if (level
== IS_LEVEL_1
)
1761 passwd
= &circuit
->area
->area_passwd
;
1763 passwd
= &circuit
->area
->domain_passwd
;
1765 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_RECV
))
1769 if (!(found
& TLVFLAG_AUTH_INFO
) ||
1770 authentication_check (&tlvs
.auth_info
, passwd
,
1771 circuit
->rcv_stream
, auth_tlv_offset
))
1773 isis_event_auth_failure (circuit
->area
->area_tag
,
1774 "SNP authentication" " failure",
1775 phdr
? phdr
->source_id
:
1783 /* debug isis snp-packets */
1784 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
1786 zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s",
1787 circuit
->area
->area_tag
,
1789 typechar
, snpa_print (ssnpa
), circuit
->interface
->name
);
1790 if (tlvs
.lsp_entries
)
1792 for (ALL_LIST_ELEMENTS_RO (tlvs
.lsp_entries
, node
, entry
))
1794 zlog_debug ("ISIS-Snp (%s): %cSNP entry %s, seq 0x%08x,"
1795 " cksum 0x%04x, lifetime %us",
1796 circuit
->area
->area_tag
,
1798 rawlspid_print (entry
->lsp_id
),
1799 ntohl (entry
->seq_num
),
1800 ntohs (entry
->checksum
), ntohs (entry
->rem_lifetime
));
1805 /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */
1806 if (tlvs
.lsp_entries
)
1808 for (ALL_LIST_ELEMENTS_RO (tlvs
.lsp_entries
, node
, entry
))
1810 lsp
= lsp_search (entry
->lsp_id
, circuit
->area
->lspdb
[level
- 1]);
1811 own_lsp
= !memcmp (entry
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1814 /* 7.3.15.2 b) 1) is this LSP newer */
1815 cmp
= lsp_compare (circuit
->area
->area_tag
, lsp
, entry
->seq_num
,
1816 entry
->checksum
, entry
->rem_lifetime
);
1817 /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */
1818 if (cmp
== LSP_EQUAL
)
1820 /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */
1821 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1823 /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
1824 else if (cmp
== LSP_OLDER
)
1826 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
1827 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1829 /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM on p2p */
1834 lsp_inc_seqnum (lsp
, ntohl (entry
->seq_num
));
1835 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1839 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1840 /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */
1841 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
1847 /* 7.3.15.2 b) 5) if it was not found, and all of those are not 0,
1848 * insert it and set SSN on it */
1849 if (entry
->rem_lifetime
&& entry
->checksum
&& entry
->seq_num
&&
1850 memcmp (entry
->lsp_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
1852 lsp
= lsp_new(circuit
->area
, entry
->lsp_id
,
1853 ntohs(entry
->rem_lifetime
),
1854 0, 0, entry
->checksum
, level
);
1855 lsp_insert (lsp
, circuit
->area
->lspdb
[level
- 1]);
1856 ISIS_FLAGS_CLEAR_ALL (lsp
->SRMflags
);
1857 ISIS_SET_FLAG (lsp
->SSNflags
, circuit
);
1863 /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported */
1864 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
1867 * Build a list from our own LSP db bounded with
1868 * start_lsp_id and stop_lsp_id
1870 lsp_list
= list_new ();
1871 lsp_build_list_nonzero_ht (chdr
->start_lsp_id
, chdr
->stop_lsp_id
,
1872 lsp_list
, circuit
->area
->lspdb
[level
- 1]);
1874 /* Fixme: Find a better solution */
1875 if (tlvs
.lsp_entries
)
1877 for (ALL_LIST_ELEMENTS (tlvs
.lsp_entries
, node
, nnode
, entry
))
1879 for (ALL_LIST_ELEMENTS (lsp_list
, node2
, nnode2
, lsp
))
1881 if (lsp_id_cmp (lsp
->lsp_header
->lsp_id
, entry
->lsp_id
) == 0)
1883 list_delete_node (lsp_list
, node2
);
1889 /* on remaining LSPs we set SRM (neighbor knew not of) */
1890 for (ALL_LIST_ELEMENTS_RO (lsp_list
, node
, lsp
))
1891 ISIS_SET_FLAG (lsp
->SRMflags
, circuit
);
1893 list_delete (lsp_list
);
1902 process_csnp (int level
, struct isis_circuit
*circuit
, const u_char
*ssnpa
)
1904 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
1906 zlog_debug ("ISIS-Snp (%s): Rcvd L%d CSNP on %s, cirType %s, cirID %u",
1907 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
1908 circuit_t2string (circuit
->is_type
), circuit
->circuit_id
);
1909 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
1910 zlog_dump_data (STREAM_DATA (circuit
->rcv_stream
),
1911 stream_get_endp (circuit
->rcv_stream
));
1914 /* Sanity check - FIXME: move to correct place */
1915 if ((stream_get_endp (circuit
->rcv_stream
) -
1916 stream_get_getp (circuit
->rcv_stream
)) < ISIS_CSNP_HDRLEN
)
1918 zlog_warn ("Packet too short ( < %d)", ISIS_CSNP_HDRLEN
);
1919 return ISIS_WARNING
;
1922 return process_snp (ISIS_SNP_CSNP_FLAG
, level
, circuit
, ssnpa
);
1926 process_psnp (int level
, struct isis_circuit
*circuit
, const u_char
*ssnpa
)
1928 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
1930 zlog_debug ("ISIS-Snp (%s): Rcvd L%d PSNP on %s, cirType %s, cirID %u",
1931 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
1932 circuit_t2string (circuit
->is_type
), circuit
->circuit_id
);
1933 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
1934 zlog_dump_data (STREAM_DATA (circuit
->rcv_stream
),
1935 stream_get_endp (circuit
->rcv_stream
));
1938 if ((stream_get_endp (circuit
->rcv_stream
) -
1939 stream_get_getp (circuit
->rcv_stream
)) < ISIS_PSNP_HDRLEN
)
1941 zlog_warn ("Packet too short ( < %d)", ISIS_PSNP_HDRLEN
);
1942 return ISIS_WARNING
;
1945 return process_snp (ISIS_SNP_PSNP_FLAG
, level
, circuit
, ssnpa
);
1953 isis_handle_pdu (struct isis_circuit
*circuit
, u_char
* ssnpa
)
1955 struct isis_fixed_hdr
*hdr
;
1957 int retval
= ISIS_OK
;
1960 * Let's first read data from stream to the header
1962 hdr
= (struct isis_fixed_hdr
*) STREAM_DATA (circuit
->rcv_stream
);
1964 if ((hdr
->idrp
!= ISO10589_ISIS
) && (hdr
->idrp
!= ISO9542_ESIS
))
1966 zlog_err ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr
->idrp
);
1970 /* now we need to know if this is an ISO 9542 packet and
1971 * take real good care of it, waaa!
1973 if (hdr
->idrp
== ISO9542_ESIS
)
1975 zlog_err ("No support for ES-IS packet IDRP=%02x", hdr
->idrp
);
1978 stream_set_getp (circuit
->rcv_stream
, ISIS_FIXED_HDR_LEN
);
1981 * and then process it
1984 if (hdr
->length
< ISIS_MINIMUM_FIXED_HDR_LEN
)
1986 zlog_err ("Fixed header length = %d", hdr
->length
);
1990 if (hdr
->version1
!= 1)
1992 zlog_warn ("Unsupported ISIS version %u", hdr
->version1
);
1993 return ISIS_WARNING
;
1996 if ((hdr
->id_len
!= 0) && (hdr
->id_len
!= ISIS_SYS_ID_LEN
))
1999 ("IDFieldLengthMismatch: ID Length field in a received PDU %u, "
2000 "while the parameter for this IS is %u", hdr
->id_len
,
2005 if (hdr
->version2
!= 1)
2007 zlog_warn ("Unsupported ISIS version %u", hdr
->version2
);
2008 return ISIS_WARNING
;
2011 if (circuit
->is_passive
)
2013 zlog_warn ("Received ISIS PDU on passive circuit %s",
2014 circuit
->interface
->name
);
2015 return ISIS_WARNING
;
2019 if ((hdr
->max_area_addrs
!= 0)
2020 && (hdr
->max_area_addrs
!= isis
->max_area_addrs
))
2022 zlog_err ("maximumAreaAddressesMismatch: maximumAreaAdresses in a "
2023 "received PDU %u while the parameter for this IS is %u",
2024 hdr
->max_area_addrs
, isis
->max_area_addrs
);
2028 switch (hdr
->pdu_type
)
2031 retval
= process_lan_hello (ISIS_LEVEL1
, circuit
, ssnpa
);
2034 retval
= process_lan_hello (ISIS_LEVEL2
, circuit
, ssnpa
);
2037 retval
= process_p2p_hello (circuit
);
2040 retval
= process_lsp (ISIS_LEVEL1
, circuit
, ssnpa
);
2043 retval
= process_lsp (ISIS_LEVEL2
, circuit
, ssnpa
);
2045 case L1_COMPLETE_SEQ_NUM
:
2046 retval
= process_csnp (ISIS_LEVEL1
, circuit
, ssnpa
);
2048 case L2_COMPLETE_SEQ_NUM
:
2049 retval
= process_csnp (ISIS_LEVEL2
, circuit
, ssnpa
);
2051 case L1_PARTIAL_SEQ_NUM
:
2052 retval
= process_psnp (ISIS_LEVEL1
, circuit
, ssnpa
);
2054 case L2_PARTIAL_SEQ_NUM
:
2055 retval
= process_psnp (ISIS_LEVEL2
, circuit
, ssnpa
);
2065 isis_receive (struct thread
*thread
)
2067 struct isis_circuit
*circuit
;
2068 u_char ssnpa
[ETH_ALEN
];
2074 circuit
= THREAD_ARG (thread
);
2077 circuit
->t_read
= NULL
;
2079 isis_circuit_stream(circuit
, &circuit
->rcv_stream
);
2081 retval
= circuit
->rx (circuit
, ssnpa
);
2083 if (retval
== ISIS_OK
)
2084 retval
= isis_handle_pdu (circuit
, ssnpa
);
2087 * prepare for next packet.
2089 if (!circuit
->is_passive
)
2090 isis_circuit_prepare (circuit
);
2095 /* filling of the fixed isis header */
2097 fill_fixed_hdr (struct isis_fixed_hdr
*hdr
, u_char pdu_type
)
2099 memset (hdr
, 0, sizeof (struct isis_fixed_hdr
));
2101 hdr
->idrp
= ISO10589_ISIS
;
2107 hdr
->length
= ISIS_LANHELLO_HDRLEN
;
2110 hdr
->length
= ISIS_P2PHELLO_HDRLEN
;
2114 hdr
->length
= ISIS_LSP_HDR_LEN
;
2116 case L1_COMPLETE_SEQ_NUM
:
2117 case L2_COMPLETE_SEQ_NUM
:
2118 hdr
->length
= ISIS_CSNP_HDRLEN
;
2120 case L1_PARTIAL_SEQ_NUM
:
2121 case L2_PARTIAL_SEQ_NUM
:
2122 hdr
->length
= ISIS_PSNP_HDRLEN
;
2125 zlog_warn ("fill_fixed_hdr(): unknown pdu type %d", pdu_type
);
2128 hdr
->length
+= ISIS_FIXED_HDR_LEN
;
2129 hdr
->pdu_type
= pdu_type
;
2131 hdr
->id_len
= 0; /* ISIS_SYS_ID_LEN - 0==6 */
2133 hdr
->max_area_addrs
= 0; /* isis->max_area_addrs - 0==3 */
2140 fill_fixed_hdr_andstream (struct isis_fixed_hdr
*hdr
, u_char pdu_type
,
2141 struct stream
*stream
)
2143 fill_fixed_hdr (hdr
, pdu_type
);
2145 stream_putc (stream
, hdr
->idrp
);
2146 stream_putc (stream
, hdr
->length
);
2147 stream_putc (stream
, hdr
->version1
);
2148 stream_putc (stream
, hdr
->id_len
);
2149 stream_putc (stream
, hdr
->pdu_type
);
2150 stream_putc (stream
, hdr
->version2
);
2151 stream_putc (stream
, hdr
->reserved
);
2152 stream_putc (stream
, hdr
->max_area_addrs
);
2158 send_hello (struct isis_circuit
*circuit
, int level
)
2160 struct isis_fixed_hdr fixed_hdr
;
2161 struct isis_lan_hello_hdr hello_hdr
;
2162 struct isis_p2p_hello_hdr p2p_hello_hdr
;
2163 unsigned char hmac_md5_hash
[ISIS_AUTH_MD5_SIZE
];
2164 size_t len_pointer
, length
, auth_tlv_offset
= 0;
2168 if (circuit
->is_passive
)
2171 if (circuit
->interface
->mtu
== 0)
2173 zlog_warn ("circuit has zero MTU");
2174 return ISIS_WARNING
;
2177 isis_circuit_stream(circuit
, &circuit
->snd_stream
);
2179 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
2180 if (level
== IS_LEVEL_1
)
2181 fill_fixed_hdr_andstream (&fixed_hdr
, L1_LAN_HELLO
,
2182 circuit
->snd_stream
);
2184 fill_fixed_hdr_andstream (&fixed_hdr
, L2_LAN_HELLO
,
2185 circuit
->snd_stream
);
2187 fill_fixed_hdr_andstream (&fixed_hdr
, P2P_HELLO
, circuit
->snd_stream
);
2190 * Fill LAN Level 1 or 2 Hello PDU header
2192 memset (&hello_hdr
, 0, sizeof (struct isis_lan_hello_hdr
));
2193 interval
= circuit
->hello_multiplier
[level
- 1] *
2194 circuit
->hello_interval
[level
- 1];
2195 if (interval
> USHRT_MAX
)
2196 interval
= USHRT_MAX
;
2197 hello_hdr
.circuit_t
= circuit
->is_type
;
2198 memcpy (hello_hdr
.source_id
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2199 hello_hdr
.hold_time
= htons ((u_int16_t
) interval
);
2201 hello_hdr
.pdu_len
= 0; /* Update the PDU Length later */
2202 len_pointer
= stream_get_endp (circuit
->snd_stream
) + 3 + ISIS_SYS_ID_LEN
;
2204 /* copy the shared part of the hello to the p2p hello if needed */
2205 if (circuit
->circ_type
== CIRCUIT_T_P2P
)
2207 memcpy (&p2p_hello_hdr
, &hello_hdr
, 5 + ISIS_SYS_ID_LEN
);
2208 p2p_hello_hdr
.local_id
= circuit
->circuit_id
;
2209 /* FIXME: need better understanding */
2210 stream_put (circuit
->snd_stream
, &p2p_hello_hdr
, ISIS_P2PHELLO_HDRLEN
);
2214 hello_hdr
.prio
= circuit
->priority
[level
- 1];
2215 if (level
== IS_LEVEL_1
)
2217 memcpy (hello_hdr
.lan_id
, circuit
->u
.bc
.l1_desig_is
,
2218 ISIS_SYS_ID_LEN
+ 1);
2220 else if (level
== IS_LEVEL_2
)
2222 memcpy (hello_hdr
.lan_id
, circuit
->u
.bc
.l2_desig_is
,
2223 ISIS_SYS_ID_LEN
+ 1);
2225 stream_put (circuit
->snd_stream
, &hello_hdr
, ISIS_LANHELLO_HDRLEN
);
2229 * Then the variable length part.
2232 /* add circuit password */
2233 switch (circuit
->passwd
.type
)
2236 case ISIS_PASSWD_TYPE_CLEARTXT
:
2237 if (tlv_add_authinfo (circuit
->passwd
.type
, circuit
->passwd
.len
,
2238 circuit
->passwd
.passwd
, circuit
->snd_stream
))
2239 return ISIS_WARNING
;
2243 case ISIS_PASSWD_TYPE_HMAC_MD5
:
2244 /* Remember where TLV is written so we can later overwrite the MD5 hash */
2245 auth_tlv_offset
= stream_get_endp (circuit
->snd_stream
);
2246 memset(&hmac_md5_hash
, 0, ISIS_AUTH_MD5_SIZE
);
2247 if (tlv_add_authinfo (circuit
->passwd
.type
, ISIS_AUTH_MD5_SIZE
,
2248 hmac_md5_hash
, circuit
->snd_stream
))
2249 return ISIS_WARNING
;
2256 /* Area Addresses TLV */
2257 if (listcount (circuit
->area
->area_addrs
) == 0)
2258 return ISIS_WARNING
;
2259 if (tlv_add_area_addrs (circuit
->area
->area_addrs
, circuit
->snd_stream
))
2260 return ISIS_WARNING
;
2262 /* LAN Neighbors TLV */
2263 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
2265 if (level
== IS_LEVEL_1
&& circuit
->u
.bc
.lan_neighs
[0] &&
2266 listcount (circuit
->u
.bc
.lan_neighs
[0]) > 0)
2267 if (tlv_add_lan_neighs (circuit
->u
.bc
.lan_neighs
[0],
2268 circuit
->snd_stream
))
2269 return ISIS_WARNING
;
2270 if (level
== IS_LEVEL_2
&& circuit
->u
.bc
.lan_neighs
[1] &&
2271 listcount (circuit
->u
.bc
.lan_neighs
[1]) > 0)
2272 if (tlv_add_lan_neighs (circuit
->u
.bc
.lan_neighs
[1],
2273 circuit
->snd_stream
))
2274 return ISIS_WARNING
;
2277 /* Protocols Supported TLV */
2278 if (circuit
->nlpids
.count
> 0)
2279 if (tlv_add_nlpid (&circuit
->nlpids
, circuit
->snd_stream
))
2280 return ISIS_WARNING
;
2281 /* IP interface Address TLV */
2282 if (circuit
->ip_router
&& circuit
->ip_addrs
&&
2283 listcount (circuit
->ip_addrs
) > 0)
2284 if (tlv_add_ip_addrs (circuit
->ip_addrs
, circuit
->snd_stream
))
2285 return ISIS_WARNING
;
2290 * TLV gets included if no topology is enabled on the interface,
2291 * if one topology other than #0 is enabled, or if multiple topologies
2294 struct isis_circuit_mt_setting
**mt_settings
;
2295 unsigned int mt_count
;
2297 mt_settings
= circuit_mt_settings(circuit
, &mt_count
);
2298 if ((mt_count
== 0 && area_is_mt(circuit
->area
))
2299 || (mt_count
== 1 && mt_settings
[0]->mtid
!= ISIS_MT_IPV4_UNICAST
)
2302 struct list
*mt_info
= list_new();
2303 mt_info
->del
= free_tlv
;
2305 for (unsigned int i
= 0; i
< mt_count
; i
++)
2307 struct mt_router_info
*info
;
2309 info
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*info
));
2310 info
->mtid
= mt_settings
[i
]->mtid
;
2311 /* overload info is not valid in IIH, so it's not included here */
2312 listnode_add(mt_info
, info
);
2314 tlv_add_mt_router_info (mt_info
, circuit
->snd_stream
);
2318 /* IPv6 Interface Address TLV */
2319 if (circuit
->ipv6_router
&& circuit
->ipv6_link
&&
2320 listcount (circuit
->ipv6_link
) > 0)
2321 if (tlv_add_ipv6_addrs (circuit
->ipv6_link
, circuit
->snd_stream
))
2322 return ISIS_WARNING
;
2324 if (circuit
->pad_hellos
)
2325 if (tlv_add_padding (circuit
->snd_stream
))
2326 return ISIS_WARNING
;
2328 length
= stream_get_endp (circuit
->snd_stream
);
2329 /* Update PDU length */
2330 stream_putw_at (circuit
->snd_stream
, len_pointer
, (u_int16_t
) length
);
2332 /* For HMAC MD5 we need to compute the md5 hash and store it */
2333 if (circuit
->passwd
.type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
2335 hmac_md5 (STREAM_DATA (circuit
->snd_stream
),
2336 stream_get_endp (circuit
->snd_stream
),
2337 (unsigned char *) &circuit
->passwd
.passwd
, circuit
->passwd
.len
,
2338 (unsigned char *) &hmac_md5_hash
);
2339 /* Copy the hash into the stream */
2340 memcpy (STREAM_DATA (circuit
->snd_stream
) + auth_tlv_offset
+ 3,
2341 hmac_md5_hash
, ISIS_AUTH_MD5_SIZE
);
2344 if (isis
->debugs
& DEBUG_ADJ_PACKETS
)
2346 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
2348 zlog_debug ("ISIS-Adj (%s): Sending L%d LAN IIH on %s, length %zd",
2349 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
2354 zlog_debug ("ISIS-Adj (%s): Sending P2P IIH on %s, length %zd",
2355 circuit
->area
->area_tag
, circuit
->interface
->name
,
2358 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
2359 zlog_dump_data (STREAM_DATA (circuit
->snd_stream
),
2360 stream_get_endp (circuit
->snd_stream
));
2363 retval
= circuit
->tx (circuit
, level
);
2364 if (retval
!= ISIS_OK
)
2365 zlog_err ("ISIS-Adj (%s): Send L%d IIH on %s failed",
2366 circuit
->area
->area_tag
, level
, circuit
->interface
->name
);
2372 send_lan_l1_hello (struct thread
*thread
)
2374 struct isis_circuit
*circuit
;
2377 circuit
= THREAD_ARG (thread
);
2379 circuit
->u
.bc
.t_send_lan_hello
[0] = NULL
;
2381 if (!(circuit
->area
->is_type
& IS_LEVEL_1
))
2383 zlog_warn ("ISIS-Hello (%s): Trying to send L1 IIH in L2-only area",
2384 circuit
->area
->area_tag
);
2388 if (circuit
->u
.bc
.run_dr_elect
[0])
2389 isis_dr_elect (circuit
, 1);
2391 retval
= send_hello (circuit
, 1);
2393 /* set next timer thread */
2394 thread_add_timer(master
, send_lan_l1_hello
, circuit
,
2395 isis_jitter(circuit
->hello_interval
[0], IIH_JITTER
),
2396 &circuit
->u
.bc
.t_send_lan_hello
[0]);
2402 send_lan_l2_hello (struct thread
*thread
)
2404 struct isis_circuit
*circuit
;
2407 circuit
= THREAD_ARG (thread
);
2409 circuit
->u
.bc
.t_send_lan_hello
[1] = NULL
;
2411 if (!(circuit
->area
->is_type
& IS_LEVEL_2
))
2413 zlog_warn ("ISIS-Hello (%s): Trying to send L2 IIH in L1 area",
2414 circuit
->area
->area_tag
);
2418 if (circuit
->u
.bc
.run_dr_elect
[1])
2419 isis_dr_elect (circuit
, 2);
2421 retval
= send_hello (circuit
, 2);
2423 /* set next timer thread */
2424 thread_add_timer(master
, send_lan_l2_hello
, circuit
,
2425 isis_jitter(circuit
->hello_interval
[1], IIH_JITTER
),
2426 &circuit
->u
.bc
.t_send_lan_hello
[1]);
2432 send_p2p_hello (struct thread
*thread
)
2434 struct isis_circuit
*circuit
;
2436 circuit
= THREAD_ARG (thread
);
2438 circuit
->u
.p2p
.t_send_p2p_hello
= NULL
;
2440 send_hello (circuit
, 1);
2442 /* set next timer thread */
2443 thread_add_timer(master
, send_p2p_hello
, circuit
,
2444 isis_jitter(circuit
->hello_interval
[1], IIH_JITTER
),
2445 &circuit
->u
.p2p
.t_send_p2p_hello
);
2451 build_csnp (int level
, u_char
* start
, u_char
* stop
, struct list
*lsps
,
2452 struct isis_circuit
*circuit
)
2454 struct isis_fixed_hdr fixed_hdr
;
2455 struct isis_passwd
*passwd
;
2458 unsigned char hmac_md5_hash
[ISIS_AUTH_MD5_SIZE
];
2459 unsigned long auth_tlv_offset
= 0;
2460 int retval
= ISIS_OK
;
2462 isis_circuit_stream(circuit
, &circuit
->snd_stream
);
2464 if (level
== IS_LEVEL_1
)
2465 fill_fixed_hdr_andstream (&fixed_hdr
, L1_COMPLETE_SEQ_NUM
,
2466 circuit
->snd_stream
);
2468 fill_fixed_hdr_andstream (&fixed_hdr
, L2_COMPLETE_SEQ_NUM
,
2469 circuit
->snd_stream
);
2472 * Fill Level 1 or 2 Complete Sequence Numbers header
2475 lenp
= stream_get_endp (circuit
->snd_stream
);
2476 stream_putw (circuit
->snd_stream
, 0); /* PDU length - when we know it */
2477 /* no need to send the source here, it is always us if we csnp */
2478 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2479 /* with zero circuit id - ref 9.10, 9.11 */
2480 stream_putc (circuit
->snd_stream
, 0x00);
2482 stream_put (circuit
->snd_stream
, start
, ISIS_SYS_ID_LEN
+ 2);
2483 stream_put (circuit
->snd_stream
, stop
, ISIS_SYS_ID_LEN
+ 2);
2488 if (level
== IS_LEVEL_1
)
2489 passwd
= &circuit
->area
->area_passwd
;
2491 passwd
= &circuit
->area
->domain_passwd
;
2493 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
))
2495 switch (passwd
->type
)
2498 case ISIS_PASSWD_TYPE_CLEARTXT
:
2499 if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT
, passwd
->len
,
2500 passwd
->passwd
, circuit
->snd_stream
))
2501 return ISIS_WARNING
;
2505 case ISIS_PASSWD_TYPE_HMAC_MD5
:
2506 /* Remember where TLV is written so we can later overwrite the MD5 hash */
2507 auth_tlv_offset
= stream_get_endp (circuit
->snd_stream
);
2508 memset(&hmac_md5_hash
, 0, ISIS_AUTH_MD5_SIZE
);
2509 if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5
, ISIS_AUTH_MD5_SIZE
,
2510 hmac_md5_hash
, circuit
->snd_stream
))
2511 return ISIS_WARNING
;
2519 retval
= tlv_add_lsp_entries (lsps
, circuit
->snd_stream
);
2520 if (retval
!= ISIS_OK
)
2523 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
2524 /* Update PU length */
2525 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2527 /* For HMAC MD5 we need to compute the md5 hash and store it */
2528 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
) &&
2529 passwd
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
2531 hmac_md5 (STREAM_DATA (circuit
->snd_stream
),
2532 stream_get_endp(circuit
->snd_stream
),
2533 (unsigned char *) &passwd
->passwd
, passwd
->len
,
2534 (unsigned char *) &hmac_md5_hash
);
2535 /* Copy the hash into the stream */
2536 memcpy (STREAM_DATA (circuit
->snd_stream
) + auth_tlv_offset
+ 3,
2537 hmac_md5_hash
, ISIS_AUTH_MD5_SIZE
);
2544 * Count the maximum number of lsps that can be accomodated by a given size.
2547 get_max_lsp_count (uint16_t size
)
2551 uint16_t remaining_size
;
2553 /* First count the full size TLVs */
2554 tlv_count
= size
/ MAX_LSP_ENTRIES_TLV_SIZE
;
2555 lsp_count
= tlv_count
* (MAX_LSP_ENTRIES_TLV_SIZE
/ LSP_ENTRIES_LEN
);
2557 /* The last TLV, if any */
2558 remaining_size
= size
% MAX_LSP_ENTRIES_TLV_SIZE
;
2559 if (remaining_size
- 2 >= LSP_ENTRIES_LEN
)
2560 lsp_count
+= (remaining_size
- 2) / LSP_ENTRIES_LEN
;
2566 * Calculate the length of Authentication Info. TLV.
2569 auth_tlv_length (int level
, struct isis_circuit
*circuit
)
2571 struct isis_passwd
*passwd
;
2574 if (level
== IS_LEVEL_1
)
2575 passwd
= &circuit
->area
->area_passwd
;
2577 passwd
= &circuit
->area
->domain_passwd
;
2579 /* Also include the length of TLV header */
2580 length
= AUTH_INFO_HDRLEN
;
2581 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
))
2583 switch (passwd
->type
)
2586 case ISIS_PASSWD_TYPE_CLEARTXT
:
2587 length
+= passwd
->len
;
2591 case ISIS_PASSWD_TYPE_HMAC_MD5
:
2592 length
+= ISIS_AUTH_MD5_SIZE
;
2604 * Calculate the maximum number of lsps that can be accomodated in a CSNP/PSNP.
2607 max_lsps_per_snp (int snp_type
, int level
, struct isis_circuit
*circuit
)
2613 snp_hdr_len
= ISIS_FIXED_HDR_LEN
;
2614 if (snp_type
== ISIS_SNP_CSNP_FLAG
)
2615 snp_hdr_len
+= ISIS_CSNP_HDRLEN
;
2617 snp_hdr_len
+= ISIS_PSNP_HDRLEN
;
2619 auth_tlv_len
= auth_tlv_length (level
, circuit
);
2620 lsp_count
= get_max_lsp_count (
2621 stream_get_size (circuit
->snd_stream
) - snp_hdr_len
- auth_tlv_len
);
2626 * FIXME: support multiple CSNPs
2630 send_csnp (struct isis_circuit
*circuit
, int level
)
2632 u_char start
[ISIS_SYS_ID_LEN
+ 2];
2633 u_char stop
[ISIS_SYS_ID_LEN
+ 2];
2634 struct list
*list
= NULL
;
2635 struct listnode
*node
;
2636 struct isis_lsp
*lsp
;
2637 u_char num_lsps
, loop
= 1;
2638 int i
, retval
= ISIS_OK
;
2640 if (circuit
->area
->lspdb
[level
- 1] == NULL
||
2641 dict_count (circuit
->area
->lspdb
[level
- 1]) == 0)
2644 memset (start
, 0x00, ISIS_SYS_ID_LEN
+ 2);
2645 memset (stop
, 0xff, ISIS_SYS_ID_LEN
+ 2);
2647 num_lsps
= max_lsps_per_snp (ISIS_SNP_CSNP_FLAG
, level
, circuit
);
2652 lsp_build_list (start
, stop
, num_lsps
, list
,
2653 circuit
->area
->lspdb
[level
- 1]);
2655 * Update the stop lsp_id before encoding this CSNP.
2657 if (listcount (list
) < num_lsps
)
2659 memset (stop
, 0xff, ISIS_SYS_ID_LEN
+ 2);
2663 node
= listtail (list
);
2664 lsp
= listgetdata (node
);
2665 memcpy (stop
, lsp
->lsp_header
->lsp_id
, ISIS_SYS_ID_LEN
+ 2);
2668 retval
= build_csnp (level
, start
, stop
, list
, circuit
);
2669 if (retval
!= ISIS_OK
)
2671 zlog_err ("ISIS-Snp (%s): Build L%d CSNP on %s failed",
2672 circuit
->area
->area_tag
, level
, circuit
->interface
->name
);
2677 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2679 zlog_debug ("ISIS-Snp (%s): Sending L%d CSNP on %s, length %zd",
2680 circuit
->area
->area_tag
, level
, circuit
->interface
->name
,
2681 stream_get_endp (circuit
->snd_stream
));
2682 for (ALL_LIST_ELEMENTS_RO (list
, node
, lsp
))
2684 zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x,"
2685 " cksum 0x%04x, lifetime %us",
2686 circuit
->area
->area_tag
,
2687 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2688 ntohl (lsp
->lsp_header
->seq_num
),
2689 ntohs (lsp
->lsp_header
->checksum
),
2690 ntohs (lsp
->lsp_header
->rem_lifetime
));
2692 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
2693 zlog_dump_data (STREAM_DATA (circuit
->snd_stream
),
2694 stream_get_endp (circuit
->snd_stream
));
2697 retval
= circuit
->tx (circuit
, level
);
2698 if (retval
!= ISIS_OK
)
2700 zlog_err ("ISIS-Snp (%s): Send L%d CSNP on %s failed",
2701 circuit
->area
->area_tag
, level
,
2702 circuit
->interface
->name
);
2708 * Start lsp_id of the next CSNP should be one plus the
2709 * stop lsp_id in this current CSNP.
2711 memcpy (start
, stop
, ISIS_SYS_ID_LEN
+ 2);
2713 for (i
= ISIS_SYS_ID_LEN
+ 1; i
>= 0; --i
)
2715 if (start
[i
] < (u_char
)0xff)
2722 memset (stop
, 0xff, ISIS_SYS_ID_LEN
+ 2);
2730 send_l1_csnp (struct thread
*thread
)
2732 struct isis_circuit
*circuit
;
2733 int retval
= ISIS_OK
;
2735 circuit
= THREAD_ARG (thread
);
2738 circuit
->t_send_csnp
[0] = NULL
;
2740 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
&& circuit
->u
.bc
.is_dr
[0])
2742 send_csnp (circuit
, 1);
2744 /* set next timer thread */
2745 thread_add_timer(master
, send_l1_csnp
, circuit
,
2746 isis_jitter(circuit
->csnp_interval
[0], CSNP_JITTER
),
2747 &circuit
->t_send_csnp
[0]);
2753 send_l2_csnp (struct thread
*thread
)
2755 struct isis_circuit
*circuit
;
2756 int retval
= ISIS_OK
;
2758 circuit
= THREAD_ARG (thread
);
2761 circuit
->t_send_csnp
[1] = NULL
;
2763 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
&& circuit
->u
.bc
.is_dr
[1])
2765 send_csnp (circuit
, 2);
2767 /* set next timer thread */
2768 thread_add_timer(master
, send_l2_csnp
, circuit
,
2769 isis_jitter(circuit
->csnp_interval
[1], CSNP_JITTER
),
2770 &circuit
->t_send_csnp
[1]);
2776 build_psnp (int level
, struct isis_circuit
*circuit
, struct list
*lsps
)
2778 struct isis_fixed_hdr fixed_hdr
;
2781 struct isis_lsp
*lsp
;
2782 struct isis_passwd
*passwd
;
2783 struct listnode
*node
;
2784 unsigned char hmac_md5_hash
[ISIS_AUTH_MD5_SIZE
];
2785 unsigned long auth_tlv_offset
= 0;
2786 int retval
= ISIS_OK
;
2788 isis_circuit_stream(circuit
, &circuit
->snd_stream
);
2790 if (level
== IS_LEVEL_1
)
2791 fill_fixed_hdr_andstream (&fixed_hdr
, L1_PARTIAL_SEQ_NUM
,
2792 circuit
->snd_stream
);
2794 fill_fixed_hdr_andstream (&fixed_hdr
, L2_PARTIAL_SEQ_NUM
,
2795 circuit
->snd_stream
);
2798 * Fill Level 1 or 2 Partial Sequence Numbers header
2800 lenp
= stream_get_endp (circuit
->snd_stream
);
2801 stream_putw (circuit
->snd_stream
, 0); /* PDU length - when we know it */
2802 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
2803 stream_putc (circuit
->snd_stream
, circuit
->idx
);
2809 if (level
== IS_LEVEL_1
)
2810 passwd
= &circuit
->area
->area_passwd
;
2812 passwd
= &circuit
->area
->domain_passwd
;
2814 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
))
2816 switch (passwd
->type
)
2819 case ISIS_PASSWD_TYPE_CLEARTXT
:
2820 if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT
, passwd
->len
,
2821 passwd
->passwd
, circuit
->snd_stream
))
2822 return ISIS_WARNING
;
2826 case ISIS_PASSWD_TYPE_HMAC_MD5
:
2827 /* Remember where TLV is written so we can later overwrite the MD5 hash */
2828 auth_tlv_offset
= stream_get_endp (circuit
->snd_stream
);
2829 memset(&hmac_md5_hash
, 0, ISIS_AUTH_MD5_SIZE
);
2830 if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5
, ISIS_AUTH_MD5_SIZE
,
2831 hmac_md5_hash
, circuit
->snd_stream
))
2832 return ISIS_WARNING
;
2840 retval
= tlv_add_lsp_entries (lsps
, circuit
->snd_stream
);
2841 if (retval
!= ISIS_OK
)
2844 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2846 for (ALL_LIST_ELEMENTS_RO (lsps
, node
, lsp
))
2848 zlog_debug ("ISIS-Snp (%s): PSNP entry %s, seq 0x%08x,"
2849 " cksum 0x%04x, lifetime %us",
2850 circuit
->area
->area_tag
,
2851 rawlspid_print (lsp
->lsp_header
->lsp_id
),
2852 ntohl (lsp
->lsp_header
->seq_num
),
2853 ntohs (lsp
->lsp_header
->checksum
),
2854 ntohs (lsp
->lsp_header
->rem_lifetime
));
2858 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
2859 /* Update PDU length */
2860 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
2862 /* For HMAC MD5 we need to compute the md5 hash and store it */
2863 if (CHECK_FLAG(passwd
->snp_auth
, SNP_AUTH_SEND
) &&
2864 passwd
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
2866 hmac_md5 (STREAM_DATA (circuit
->snd_stream
),
2867 stream_get_endp(circuit
->snd_stream
),
2868 (unsigned char *) &passwd
->passwd
, passwd
->len
,
2869 (unsigned char *) &hmac_md5_hash
);
2870 /* Copy the hash into the stream */
2871 memcpy (STREAM_DATA (circuit
->snd_stream
) + auth_tlv_offset
+ 3,
2872 hmac_md5_hash
, ISIS_AUTH_MD5_SIZE
);
2879 * 7.3.15.4 action on expiration of partial SNP interval
2883 send_psnp (int level
, struct isis_circuit
*circuit
)
2885 struct isis_lsp
*lsp
;
2886 struct list
*list
= NULL
;
2887 struct listnode
*node
;
2889 int retval
= ISIS_OK
;
2891 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
&&
2892 circuit
->u
.bc
.is_dr
[level
- 1])
2895 if (circuit
->area
->lspdb
[level
- 1] == NULL
||
2896 dict_count (circuit
->area
->lspdb
[level
- 1]) == 0)
2899 if (! circuit
->snd_stream
)
2902 num_lsps
= max_lsps_per_snp (ISIS_SNP_PSNP_FLAG
, level
, circuit
);
2907 lsp_build_list_ssn (circuit
, num_lsps
, list
,
2908 circuit
->area
->lspdb
[level
- 1]);
2910 if (listcount (list
) == 0)
2916 retval
= build_psnp (level
, circuit
, list
);
2917 if (retval
!= ISIS_OK
)
2919 zlog_err ("ISIS-Snp (%s): Build L%d PSNP on %s failed",
2920 circuit
->area
->area_tag
, level
, circuit
->interface
->name
);
2925 if (isis
->debugs
& DEBUG_SNP_PACKETS
)
2927 zlog_debug ("ISIS-Snp (%s): Sending L%d PSNP on %s, length %zd",
2928 circuit
->area
->area_tag
, level
,
2929 circuit
->interface
->name
,
2930 stream_get_endp (circuit
->snd_stream
));
2931 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
2932 zlog_dump_data (STREAM_DATA (circuit
->snd_stream
),
2933 stream_get_endp (circuit
->snd_stream
));
2936 retval
= circuit
->tx (circuit
, level
);
2937 if (retval
!= ISIS_OK
)
2939 zlog_err ("ISIS-Snp (%s): Send L%d PSNP on %s failed",
2940 circuit
->area
->area_tag
, level
,
2941 circuit
->interface
->name
);
2947 * sending succeeded, we can clear SSN flags of this circuit
2948 * for the LSPs in list
2950 for (ALL_LIST_ELEMENTS_RO (list
, node
, lsp
))
2951 ISIS_CLEAR_FLAG (lsp
->SSNflags
, circuit
);
2959 send_l1_psnp (struct thread
*thread
)
2962 struct isis_circuit
*circuit
;
2963 int retval
= ISIS_OK
;
2965 circuit
= THREAD_ARG (thread
);
2968 circuit
->t_send_psnp
[0] = NULL
;
2970 send_psnp (1, circuit
);
2971 /* set next timer thread */
2972 thread_add_timer(master
, send_l1_psnp
, circuit
,
2973 isis_jitter(circuit
->psnp_interval
[0], PSNP_JITTER
),
2974 &circuit
->t_send_psnp
[0]);
2980 * 7.3.15.4 action on expiration of partial SNP interval
2984 send_l2_psnp (struct thread
*thread
)
2986 struct isis_circuit
*circuit
;
2987 int retval
= ISIS_OK
;
2989 circuit
= THREAD_ARG (thread
);
2992 circuit
->t_send_psnp
[1] = NULL
;
2994 send_psnp (2, circuit
);
2996 /* set next timer thread */
2997 thread_add_timer(master
, send_l2_psnp
, circuit
,
2998 isis_jitter(circuit
->psnp_interval
[1], PSNP_JITTER
),
2999 &circuit
->t_send_psnp
[1]);
3005 * ISO 10589 - 7.3.14.3
3008 send_lsp (struct thread
*thread
)
3010 struct isis_circuit
*circuit
;
3011 struct isis_lsp
*lsp
;
3012 struct listnode
*node
;
3014 int retval
= ISIS_OK
;
3016 circuit
= THREAD_ARG (thread
);
3019 if (!circuit
->lsp_queue
)
3022 node
= listhead (circuit
->lsp_queue
);
3025 * Handle case where there are no LSPs on the queue. This can
3026 * happen, for instance, if an adjacency goes down before this
3027 * thread gets a chance to run.
3033 * Delete LSP from lsp_queue. If it's still in queue, it is assumed
3034 * as 'transmit pending', but send_lsp may never be called again.
3035 * Retry will happen because SRM flag will not be cleared.
3037 lsp
= listgetdata(node
);
3038 list_delete_node (circuit
->lsp_queue
, node
);
3040 /* Set the last-cleared time if the queue is empty. */
3041 /* TODO: Is is possible that new lsps keep being added to the queue
3042 * that the queue is never empty? */
3043 if (list_isempty (circuit
->lsp_queue
))
3044 circuit
->lsp_queue_last_cleared
= time (NULL
);
3046 if (circuit
->state
!= C_STATE_UP
|| circuit
->is_passive
== 1)
3050 * Do not send if levels do not match
3052 if (!(lsp
->level
& circuit
->is_type
))
3056 * Do not send if we do not have adjacencies in state up on the circuit
3058 if (circuit
->upadjcount
[lsp
->level
- 1] == 0)
3061 /* stream_copy will assert and stop program execution if LSP is larger than
3062 * the circuit's MTU. So handle and log this case here. */
3063 if (stream_get_endp(lsp
->pdu
) > stream_get_size(circuit
->snd_stream
))
3065 zlog_err("ISIS-Upd (%s): Can't send L%d LSP %s, seq 0x%08x,"
3066 " cksum 0x%04x, lifetime %us on %s. LSP Size is %zu"
3067 " while interface stream size is %zu.",
3068 circuit
->area
->area_tag
, lsp
->level
,
3069 rawlspid_print(lsp
->lsp_header
->lsp_id
),
3070 ntohl(lsp
->lsp_header
->seq_num
),
3071 ntohs(lsp
->lsp_header
->checksum
),
3072 ntohs(lsp
->lsp_header
->rem_lifetime
),
3073 circuit
->interface
->name
,
3074 stream_get_endp(lsp
->pdu
),
3075 stream_get_size(circuit
->snd_stream
));
3076 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
3077 zlog_dump_data(STREAM_DATA(lsp
->pdu
), stream_get_endp(lsp
->pdu
));
3078 retval
= ISIS_ERROR
;
3082 /* copy our lsp to the send buffer */
3083 stream_copy (circuit
->snd_stream
, lsp
->pdu
);
3085 if (isis
->debugs
& DEBUG_UPDATE_PACKETS
)
3088 ("ISIS-Upd (%s): Sending L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
3089 " lifetime %us on %s", circuit
->area
->area_tag
, lsp
->level
,
3090 rawlspid_print (lsp
->lsp_header
->lsp_id
),
3091 ntohl (lsp
->lsp_header
->seq_num
),
3092 ntohs (lsp
->lsp_header
->checksum
),
3093 ntohs (lsp
->lsp_header
->rem_lifetime
),
3094 circuit
->interface
->name
);
3095 if (isis
->debugs
& DEBUG_PACKET_DUMP
)
3096 zlog_dump_data (STREAM_DATA (circuit
->snd_stream
),
3097 stream_get_endp (circuit
->snd_stream
));
3101 retval
= circuit
->tx (circuit
, lsp
->level
);
3102 if (retval
!= ISIS_OK
)
3104 zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed %s",
3105 circuit
->area
->area_tag
, lsp
->level
,
3106 circuit
->interface
->name
,
3107 (retval
== ISIS_WARNING
) ? "temporarily" : "permanently");
3112 || (retval
== ISIS_OK
&& circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
3113 || (retval
!= ISIS_OK
&& retval
!= ISIS_WARNING
))
3115 /* SRM flag will trigger retransmission. We will not retransmit if we
3116 * encountered a fatal error.
3117 * On success, they should only be cleared if it's a broadcast circuit.
3118 * On a P2P circuit, we will wait for the ack from the neighbor to clear
3121 ISIS_CLEAR_FLAG (lsp
->SRMflags
, circuit
);
3128 ack_lsp (struct isis_link_state_hdr
*hdr
, struct isis_circuit
*circuit
,
3134 struct isis_fixed_hdr fixed_hdr
;
3136 isis_circuit_stream(circuit
, &circuit
->snd_stream
);
3138 // fill_llc_hdr (stream);
3139 if (level
== IS_LEVEL_1
)
3140 fill_fixed_hdr_andstream (&fixed_hdr
, L1_PARTIAL_SEQ_NUM
,
3141 circuit
->snd_stream
);
3143 fill_fixed_hdr_andstream (&fixed_hdr
, L2_PARTIAL_SEQ_NUM
,
3144 circuit
->snd_stream
);
3147 lenp
= stream_get_endp (circuit
->snd_stream
);
3148 stream_putw (circuit
->snd_stream
, 0); /* PDU length */
3149 stream_put (circuit
->snd_stream
, isis
->sysid
, ISIS_SYS_ID_LEN
);
3150 stream_putc (circuit
->snd_stream
, circuit
->idx
);
3151 stream_putc (circuit
->snd_stream
, 9); /* code */
3152 stream_putc (circuit
->snd_stream
, 16); /* len */
3154 stream_putw (circuit
->snd_stream
, ntohs (hdr
->rem_lifetime
));
3155 stream_put (circuit
->snd_stream
, hdr
->lsp_id
, ISIS_SYS_ID_LEN
+ 2);
3156 stream_putl (circuit
->snd_stream
, ntohl (hdr
->seq_num
));
3157 stream_putw (circuit
->snd_stream
, ntohs (hdr
->checksum
));
3159 length
= (u_int16_t
) stream_get_endp (circuit
->snd_stream
);
3160 /* Update PDU length */
3161 stream_putw_at (circuit
->snd_stream
, lenp
, length
);
3163 retval
= circuit
->tx (circuit
, level
);
3164 if (retval
!= ISIS_OK
)
3165 zlog_err ("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed",
3166 circuit
->area
->area_tag
, level
,
3167 circuit
->interface
->name
);