2 * IS-IS Rout(e)ing protocol - isis_tlv.c
3 * IS-IS TLV related routines
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; see the file COPYING; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 #include "isisd/dict.h"
35 #include "isisd/isis_constants.h"
36 #include "isisd/isis_common.h"
37 #include "isisd/isis_flags.h"
38 #include "isisd/isis_circuit.h"
39 #include "isisd/isis_tlv.h"
40 #include "isisd/isisd.h"
41 #include "isisd/isis_dynhn.h"
42 #include "isisd/isis_misc.h"
43 #include "isisd/isis_pdu.h"
44 #include "isisd/isis_lsp.h"
45 #include "isisd/isis_te.h"
46 #include "isisd/isis_mt.h"
48 void free_tlv(void *val
)
50 XFREE(MTYPE_ISIS_TLV
, val
);
56 * Called after parsing of a PDU. There shouldn't be any tlv's left, so this
57 * is only a caution to avoid memory leaks
59 void free_tlvs(struct tlvs
*tlvs
)
62 list_delete(tlvs
->area_addrs
);
63 if (tlvs
->mt_router_info
)
64 list_delete(tlvs
->mt_router_info
);
66 list_delete(tlvs
->is_neighs
);
67 if (tlvs
->te_is_neighs
)
68 list_delete(tlvs
->te_is_neighs
);
69 if (tlvs
->mt_is_neighs
)
70 list_delete(tlvs
->mt_is_neighs
);
72 list_delete(tlvs
->es_neighs
);
73 if (tlvs
->lsp_entries
)
74 list_delete(tlvs
->lsp_entries
);
75 if (tlvs
->prefix_neighs
)
76 list_delete(tlvs
->prefix_neighs
);
78 list_delete(tlvs
->lan_neighs
);
80 list_delete(tlvs
->ipv4_addrs
);
81 if (tlvs
->ipv4_int_reachs
)
82 list_delete(tlvs
->ipv4_int_reachs
);
83 if (tlvs
->ipv4_ext_reachs
)
84 list_delete(tlvs
->ipv4_ext_reachs
);
85 if (tlvs
->te_ipv4_reachs
)
86 list_delete(tlvs
->te_ipv4_reachs
);
87 if (tlvs
->mt_ipv4_reachs
)
88 list_delete(tlvs
->mt_ipv4_reachs
);
90 list_delete(tlvs
->ipv6_addrs
);
91 if (tlvs
->ipv6_reachs
)
92 list_delete(tlvs
->ipv6_reachs
);
93 if (tlvs
->mt_ipv6_reachs
)
94 list_delete(tlvs
->mt_ipv6_reachs
);
96 memset(tlvs
, 0, sizeof(struct tlvs
));
101 static int parse_mtid(uint16_t *mtid
, bool read_mtid
, unsigned int *length
,
105 *mtid
= ISIS_MT_IPV4_UNICAST
;
111 if (*length
< sizeof(mtid_buf
)) {
112 zlog_warn("ISIS-TLV: mt tlv too short to contain MT id");
116 memcpy(&mtid_buf
, *pnt
, sizeof(mtid_buf
));
117 *pnt
+= sizeof(mtid_buf
);
118 *length
-= sizeof(mtid_buf
);
120 *mtid
= ntohs(mtid_buf
) & ISIS_MT_MASK
;
124 static int parse_mt_is_neighs(struct tlvs
*tlvs
, bool read_mtid
,
125 unsigned int length
, u_char
*pnt
)
127 struct list
*neigh_list
;
131 rv
= parse_mtid(&mtid
, read_mtid
, &length
, &pnt
);
135 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
136 if (!tlvs
->te_is_neighs
) {
137 tlvs
->te_is_neighs
= list_new();
138 tlvs
->te_is_neighs
->del
= free_tlv
;
140 neigh_list
= tlvs
->te_is_neighs
;
142 struct tlv_mt_neighbors
*neighbors
;
144 neighbors
= tlvs_get_mt_neighbors(tlvs
, mtid
);
145 neighbors
->list
->del
= free_tlv
;
146 neigh_list
= neighbors
->list
;
149 while (length
>= IS_NEIGHBOURS_LEN
) {
150 struct te_is_neigh
*neigh
=
151 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*neigh
));
153 memcpy(neigh
, pnt
, IS_NEIGHBOURS_LEN
);
154 pnt
+= IS_NEIGHBOURS_LEN
;
155 length
-= IS_NEIGHBOURS_LEN
;
157 if (neigh
->sub_tlvs_length
> length
) {
159 "ISIS-TLV: neighbor subtlv length exceeds TLV size");
160 XFREE(MTYPE_ISIS_TLV
, neigh
);
164 memcpy(neigh
->sub_tlvs
, pnt
, neigh
->sub_tlvs_length
);
165 pnt
+= neigh
->sub_tlvs_length
;
166 length
-= neigh
->sub_tlvs_length
;
168 listnode_add(neigh_list
, neigh
);
172 zlog_warn("ISIS-TLV: TE/MT neighor TLV has trailing data");
179 static int parse_mt_ipv4_reachs(struct tlvs
*tlvs
, bool read_mtid
,
180 unsigned int length
, u_char
*pnt
)
182 struct list
*reach_list
;
186 rv
= parse_mtid(&mtid
, read_mtid
, &length
, &pnt
);
190 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
191 if (!tlvs
->te_ipv4_reachs
) {
192 tlvs
->te_ipv4_reachs
= list_new();
193 tlvs
->te_ipv4_reachs
->del
= free_tlv
;
195 reach_list
= tlvs
->te_ipv4_reachs
;
197 struct tlv_mt_ipv4_reachs
*reachs
;
199 reachs
= tlvs_get_mt_ipv4_reachs(tlvs
, mtid
);
200 reachs
->list
->del
= free_tlv
;
201 reach_list
= reachs
->list
;
204 while (length
>= 5) /* Metric + Control */
206 struct te_ipv4_reachability
*reach
=
207 XCALLOC(MTYPE_ISIS_TLV
, TE_IPV4_REACH_LEN
);
209 memcpy(reach
, pnt
, 5); /* Metric + Control */
213 unsigned char prefixlen
= reach
->control
& 0x3F;
215 if (prefixlen
> IPV4_MAX_BITLEN
) {
217 "ISIS-TLV: invalid IPv4 extended reachability prefix length %d",
219 XFREE(MTYPE_ISIS_TLV
, reach
);
223 if (length
< (unsigned int)PSIZE(prefixlen
)) {
225 "ISIS-TLV: invalid IPv4 extended reachability prefix too long for tlv");
226 XFREE(MTYPE_ISIS_TLV
, reach
);
230 memcpy(&reach
->prefix_start
, pnt
, PSIZE(prefixlen
));
231 pnt
+= PSIZE(prefixlen
);
232 length
-= PSIZE(prefixlen
);
234 if (reach
->control
& TE_IPV4_HAS_SUBTLV
) {
237 "ISIS-TLV: invalid IPv4 extended reachability SubTLV missing");
238 XFREE(MTYPE_ISIS_TLV
, reach
);
242 u_char subtlv_len
= *pnt
;
246 if (length
< subtlv_len
) {
248 "ISIS-TLV: invalid IPv4 extended reachability SubTLVs have oversize");
249 XFREE(MTYPE_ISIS_TLV
, reach
);
253 /* Skip Sub-TLVs for now */
255 length
-= subtlv_len
;
257 listnode_add(reach_list
, reach
);
262 "ISIS-TLV: TE/MT ipv4 reachability TLV has trailing data");
269 static int parse_mt_ipv6_reachs(struct tlvs
*tlvs
, bool read_mtid
,
270 unsigned int length
, u_char
*pnt
)
272 struct list
*reach_list
;
276 rv
= parse_mtid(&mtid
, read_mtid
, &length
, &pnt
);
280 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
281 if (!tlvs
->ipv6_reachs
) {
282 tlvs
->ipv6_reachs
= list_new();
283 tlvs
->ipv6_reachs
->del
= free_tlv
;
285 reach_list
= tlvs
->ipv6_reachs
;
287 struct tlv_mt_ipv6_reachs
*reachs
;
289 reachs
= tlvs_get_mt_ipv6_reachs(tlvs
, mtid
);
290 reachs
->list
->del
= free_tlv
;
291 reach_list
= reachs
->list
;
294 while (length
>= 6) /* Metric + Control + Prefixlen */
296 struct ipv6_reachability
*reach
=
297 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*reach
));
299 memcpy(reach
, pnt
, 6); /* Metric + Control + Prefixlen */
303 if (reach
->prefix_len
> IPV6_MAX_BITLEN
) {
305 "ISIS-TLV: invalid IPv6 reachability prefix length %d",
307 XFREE(MTYPE_ISIS_TLV
, reach
);
311 if (length
< (unsigned int)PSIZE(reach
->prefix_len
)) {
313 "ISIS-TLV: invalid IPv6 reachability prefix too long for tlv");
314 XFREE(MTYPE_ISIS_TLV
, reach
);
318 memcpy(&reach
->prefix
, pnt
, PSIZE(reach
->prefix_len
));
319 pnt
+= PSIZE(reach
->prefix_len
);
320 length
-= PSIZE(reach
->prefix_len
);
322 if (reach
->control_info
& CTRL_INFO_SUBTLVS
) {
325 "ISIS-TLV: invalid IPv6 reachability SubTLV missing");
326 XFREE(MTYPE_ISIS_TLV
, reach
);
330 u_char subtlv_len
= *pnt
;
334 if (length
< subtlv_len
) {
336 "ISIS-TLV: invalid IPv6 reachability SubTLVs have oversize");
337 XFREE(MTYPE_ISIS_TLV
, reach
);
341 /* Skip Sub-TLVs for now */
343 length
-= subtlv_len
;
345 listnode_add(reach_list
, reach
);
350 "ISIS-TLV: (MT) IPv6 reachability TLV has trailing data");
358 * Parses the tlvs found in the variant length part of the PDU.
359 * Caller tells with flags in "expected" which TLV's it is interested in.
361 int parse_tlvs(char *areatag
, u_char
*stream
, int size
, u_int32_t
*expected
,
362 u_int32_t
*found
, struct tlvs
*tlvs
, u_int32_t
*auth_tlv_offset
)
365 struct lan_neigh
*lan_nei
;
366 struct area_addr
*area_addr
;
367 struct is_neigh
*is_nei
;
368 struct es_neigh
*es_nei
;
369 struct lsp_entry
*lsp_entry
;
370 struct in_addr
*ipv4_addr
;
371 struct ipv4_reachability
*ipv4_reach
;
372 struct in6_addr
*ipv6_addr
;
373 int value_len
, retval
= ISIS_OK
;
374 u_char
*start
= stream
, *pnt
= stream
;
377 memset(tlvs
, 0, sizeof(struct tlvs
));
379 while (pnt
< stream
+ size
- 2) {
384 if (pnt
+ length
> stream
+ size
) {
386 "ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet "
388 areatag
, type
, length
);
389 retval
= ISIS_WARNING
;
394 /* +-------+-------+-------+-------+-------+-------+-------+-------+
396 * +-------+-------+-------+-------+-------+-------+-------+-------+
398 * +-------+-------+-------+-------+-------+-------+-------+-------+
401 *found
|= TLVFLAG_AREA_ADDRS
;
402 #ifdef EXTREME_TLV_DEBUG
403 zlog_debug("TLV Area Adresses len %d", length
);
404 #endif /* EXTREME_TLV_DEBUG */
405 if (*expected
& TLVFLAG_AREA_ADDRS
) {
406 while (length
> value_len
) {
407 area_addr
= (struct area_addr
*)pnt
;
408 value_len
+= area_addr
->addr_len
+ 1;
409 pnt
+= area_addr
->addr_len
+ 1;
410 if (!tlvs
->area_addrs
)
411 tlvs
->area_addrs
= list_new();
412 listnode_add(tlvs
->area_addrs
,
421 *found
|= TLVFLAG_IS_NEIGHS
;
422 #ifdef EXTREME_TLV_DEBUG
423 zlog_debug("ISIS-TLV (%s): IS Neighbours length %d",
425 #endif /* EXTREME_TLV_DEBUG */
426 if (TLVFLAG_IS_NEIGHS
& *expected
) {
427 /* +-------+-------+-------+-------+-------+-------+-------+-------+
429 * +-------+-------+-------+-------+-------+-------+-------+-------+
433 /* +-------+-------+-------+-------+-------+-------+-------+-------+
434 * | 0 | I/E | Default
436 * +-------+-------+-------+-------+-------+-------+-------+-------+
437 * | S | I/E | Delay Metric
439 * +-------+-------+-------+-------+-------+-------+-------+-------+
440 * | S | I/E | Expense
442 * +-------+-------+-------+-------+-------+-------+-------+-------+
443 * | S | I/E | Error Metric
445 * +-------+-------+-------+-------+-------+-------+-------+-------+
447 * +---------------------------------------------------------------+
450 while (length
> value_len
) {
451 is_nei
= (struct is_neigh
*)pnt
;
452 value_len
+= 4 + ISIS_SYS_ID_LEN
+ 1;
453 pnt
+= 4 + ISIS_SYS_ID_LEN
+ 1;
454 if (!tlvs
->is_neighs
)
455 tlvs
->is_neighs
= list_new();
456 listnode_add(tlvs
->is_neighs
, is_nei
);
463 case TE_IS_NEIGHBOURS
:
464 *found
|= TLVFLAG_TE_IS_NEIGHS
;
465 #ifdef EXTREME_TLV_DEBUG
467 "ISIS-TLV (%s): Extended IS Neighbours length %d",
469 #endif /* EXTREME_TLV_DEBUG */
470 if (TLVFLAG_TE_IS_NEIGHS
& *expected
)
471 retval
= parse_mt_is_neighs(tlvs
, false, length
,
476 case MT_IS_NEIGHBOURS
:
477 *found
|= TLVFLAG_TE_IS_NEIGHS
;
478 #ifdef EXTREME_TLV_DEBUG
479 zlog_debug("ISIS-TLV (%s): MT IS Neighbours length %d",
482 if (TLVFLAG_TE_IS_NEIGHS
& *expected
)
483 retval
= parse_mt_is_neighs(tlvs
, true, length
,
489 /* +-------+-------+-------+-------+-------+-------+-------+-------+
490 * | 0 | I/E | Default Metric |
491 * +-------+-------+-------+-------+-------+-------+-------+-------+
492 * | S | I/E | Delay Metric |
493 * +-------+-------+-------+-------+-------+-------+-------+-------+
494 * | S | I/E | Expense Metric |
495 * +-------+-------+-------+-------+-------+-------+-------+-------+
496 * | S | I/E | Error Metric |
497 * +-------+-------+-------+-------+-------+-------+-------+-------+
499 * +---------------------------------------------------------------+
501 * +---------------------------------------------------------------+
504 #ifdef EXTREME_TLV_DEBUG
505 zlog_debug("ISIS-TLV (%s): ES Neighbours length %d",
507 #endif /* EXTREME_TLV_DEBUG */
508 *found
|= TLVFLAG_ES_NEIGHS
;
509 if (*expected
& TLVFLAG_ES_NEIGHS
) {
510 es_nei
= (struct es_neigh
*)pnt
;
513 while (length
> value_len
) {
514 /* FIXME FIXME FIXME - add to the list
516 /* sys_id->id = pnt; */
517 value_len
+= ISIS_SYS_ID_LEN
;
518 pnt
+= ISIS_SYS_ID_LEN
;
519 /* if (!es_nei->neigh_ids)
520 * es_nei->neigh_ids = sysid; */
522 if (!tlvs
->es_neighs
)
523 tlvs
->es_neighs
= list_new();
524 listnode_add(tlvs
->es_neighs
, es_nei
);
531 /* +-------+-------+-------+-------+-------+-------+-------+-------+
533 * +-------+-------+-------+-------+-------+-------+-------+-------+
536 *found
|= TLVFLAG_LAN_NEIGHS
;
537 #ifdef EXTREME_TLV_DEBUG
538 zlog_debug("ISIS-TLV (%s): LAN Neigbours length %d",
540 #endif /* EXTREME_TLV_DEBUG */
541 if (TLVFLAG_LAN_NEIGHS
& *expected
) {
542 while (length
> value_len
) {
543 lan_nei
= (struct lan_neigh
*)pnt
;
544 if (!tlvs
->lan_neighs
)
545 tlvs
->lan_neighs
= list_new();
546 listnode_add(tlvs
->lan_neighs
, lan_nei
);
547 value_len
+= ETH_ALEN
;
556 #ifdef EXTREME_TLV_DEBUG
557 zlog_debug("TLV padding %d", length
);
558 #endif /* EXTREME_TLV_DEBUG */
563 /* +-------+-------+-------+-------+-------+-------+-------+-------+
564 * | Remaining Lifetime | 2
565 * +-------+-------+-------+-------+-------+-------+-------+-------+
567 * +-------+-------+-------+-------+-------+-------+-------+-------+
568 * | LSP Sequence Number |Â 4
569 * +-------+-------+-------+-------+-------+-------+-------+-------+
571 * +-------+-------+-------+-------+-------+-------+-------+-------+
573 #ifdef EXTREME_TLV_DEBUG
574 zlog_debug("ISIS-TLV (%s): LSP Entries length %d",
576 #endif /* EXTREME_TLV_DEBUG */
577 *found
|= TLVFLAG_LSP_ENTRIES
;
578 if (TLVFLAG_LSP_ENTRIES
& *expected
) {
579 while (length
> value_len
) {
580 lsp_entry
= (struct lsp_entry
*)pnt
;
581 value_len
+= 10 + ISIS_SYS_ID_LEN
;
582 pnt
+= 10 + ISIS_SYS_ID_LEN
;
583 if (!tlvs
->lsp_entries
)
584 tlvs
->lsp_entries
= list_new();
585 listnode_add(tlvs
->lsp_entries
,
594 /* +-------+-------+-------+-------+-------+-------+-------+-------+
595 * | 16 bit fletcher CHECKSUM |
596 * +-------+-------+-------+-------+-------+-------+-------+-------+
599 *found
|= TLVFLAG_CHECKSUM
;
600 #ifdef EXTREME_TLV_DEBUG
601 zlog_debug("ISIS-TLV (%s): Checksum length %d", areatag
,
603 #endif /* EXTREME_TLV_DEBUG */
604 if (*expected
& TLVFLAG_CHECKSUM
) {
605 tlvs
->checksum
= (struct checksum
*)pnt
;
610 case PROTOCOLS_SUPPORTED
:
611 /* +-------+-------+-------+-------+-------+-------+-------+-------+
613 * +-------+-------+-------+-------+-------+-------+-------+-------+
616 *found
|= TLVFLAG_NLPID
;
617 #ifdef EXTREME_TLV_DEBUG
619 "ISIS-TLV (%s): Protocols Supported length %d",
621 #endif /* EXTREME_TLV_DEBUG */
622 if (*expected
& TLVFLAG_NLPID
) {
623 tlvs
->nlpids
= (struct nlpids
*)(pnt
- 1);
629 /* +-------+-------+-------+-------+-------+-------+-------+-------+
630 * + IP version 4 address + 4
631 * +-------+-------+-------+-------+-------+-------+-------+-------+
634 *found
|= TLVFLAG_IPV4_ADDR
;
635 #ifdef EXTREME_TLV_DEBUG
636 zlog_debug("ISIS-TLV (%s): IPv4 Address length %d",
638 #endif /* EXTREME_TLV_DEBUG */
639 if (*expected
& TLVFLAG_IPV4_ADDR
) {
640 while (length
> value_len
) {
641 ipv4_addr
= (struct in_addr
*)pnt
;
642 #ifdef EXTREME_TLV_DEBUG
644 "ISIS-TLV (%s) : IP ADDR %s, pnt %p",
645 areatag
, inet_ntoa(*ipv4_addr
),
647 #endif /* EXTREME_TLV_DEBUG */
648 if (!tlvs
->ipv4_addrs
)
649 tlvs
->ipv4_addrs
= list_new();
650 listnode_add(tlvs
->ipv4_addrs
,
661 *found
|= TLVFLAG_AUTH_INFO
;
662 #ifdef EXTREME_TLV_DEBUG
664 "ISIS-TLV (%s): IS-IS Authentication Information",
667 if (*expected
& TLVFLAG_AUTH_INFO
) {
668 tlvs
->auth_info
.type
= *pnt
;
671 "ISIS-TLV (%s): TLV (type %d, length %d) "
673 areatag
, type
, length
);
677 tlvs
->auth_info
.len
= length
;
679 memcpy(tlvs
->auth_info
.passwd
, pnt
, length
);
680 /* Return the authentication tlv pos for later
682 * of MD5 (RFC 5304, 2)
685 *auth_tlv_offset
+= (pnt
- start
- 3);
692 case DYNAMIC_HOSTNAME
:
693 *found
|= TLVFLAG_DYN_HOSTNAME
;
694 #ifdef EXTREME_TLV_DEBUG
695 zlog_debug("ISIS-TLV (%s): Dynamic Hostname length %d",
697 #endif /* EXTREME_TLV_DEBUG */
698 if (*expected
& TLVFLAG_DYN_HOSTNAME
) {
699 /* the length is also included in the pointed
701 tlvs
->hostname
= (struct hostname
*)(pnt
- 1);
707 /* +---------------------------------------------------------------+
709 * +---------------------------------------------------------------+
711 *found
|= TLVFLAG_TE_ROUTER_ID
;
712 #ifdef EXTREME_TLV_DEBUG
713 zlog_debug("ISIS-TLV (%s): TE Router ID %d", areatag
,
715 #endif /* EXTREME_TLV_DEBUG */
716 if (*expected
& TLVFLAG_TE_ROUTER_ID
)
717 tlvs
->router_id
= (struct te_router_id
*)(pnt
);
721 case IPV4_INT_REACHABILITY
:
722 /* +-------+-------+-------+-------+-------+-------+-------+-------+
723 * | 0 | I/E | Default Metric | 1
724 * +-------+-------+-------+-------+-------+-------+-------+-------+
725 * | S | I/E | Delay Metric | 1
726 * +-------+-------+-------+-------+-------+-------+-------+-------+
727 * | S | I/E | Expense Metric | 1
728 * +-------+-------+-------+-------+-------+-------+-------+-------+
729 * | S | I/E | Error Metric | 1
730 * +-------+-------+-------+-------+-------+-------+-------+-------+
732 * +---------------------------------------------------------------+
734 * +---------------------------------------------------------------+
737 *found
|= TLVFLAG_IPV4_INT_REACHABILITY
;
738 #ifdef EXTREME_TLV_DEBUG
740 "ISIS-TLV (%s): IPv4 internal Reachability length %d",
742 #endif /* EXTREME_TLV_DEBUG */
743 if (*expected
& TLVFLAG_IPV4_INT_REACHABILITY
) {
744 while (length
> value_len
) {
746 (struct ipv4_reachability
*)pnt
;
747 if (!tlvs
->ipv4_int_reachs
)
748 tlvs
->ipv4_int_reachs
=
750 listnode_add(tlvs
->ipv4_int_reachs
,
760 case IPV4_EXT_REACHABILITY
:
761 /* +-------+-------+-------+-------+-------+-------+-------+-------+
762 * | 0 | I/E | Default Metric | 1
763 * +-------+-------+-------+-------+-------+-------+-------+-------+
764 * | S | I/E | Delay Metric | 1
765 * +-------+-------+-------+-------+-------+-------+-------+-------+
766 * | S | I/E | Expense Metric | 1
767 * +-------+-------+-------+-------+-------+-------+-------+-------+
768 * | S | I/E | Error Metric | 1
769 * +-------+-------+-------+-------+-------+-------+-------+-------+
771 * +---------------------------------------------------------------+
773 * +---------------------------------------------------------------+
776 *found
|= TLVFLAG_IPV4_EXT_REACHABILITY
;
777 #ifdef EXTREME_TLV_DEBUG
779 "ISIS-TLV (%s): IPv4 external Reachability length %d",
781 #endif /* EXTREME_TLV_DEBUG */
782 if (*expected
& TLVFLAG_IPV4_EXT_REACHABILITY
) {
783 while (length
> value_len
) {
785 (struct ipv4_reachability
*)pnt
;
786 if (!tlvs
->ipv4_ext_reachs
)
787 tlvs
->ipv4_ext_reachs
=
789 listnode_add(tlvs
->ipv4_ext_reachs
,
799 case TE_IPV4_REACHABILITY
:
800 *found
|= TLVFLAG_TE_IPV4_REACHABILITY
;
801 #ifdef EXTREME_TLV_DEBUG
803 "ISIS-TLV (%s): IPv4 extended Reachability length %d",
805 #endif /* EXTREME_TLV_DEBUG */
806 if (*expected
& TLVFLAG_TE_IPV4_REACHABILITY
)
807 retval
= parse_mt_ipv4_reachs(tlvs
, false,
811 case MT_IPV4_REACHABILITY
:
812 *found
|= TLVFLAG_TE_IPV4_REACHABILITY
;
813 #ifdef EXTREME_TLV_DEBUG
815 "ISIS-TLV (%s): IPv4 MT Reachability length %d",
817 #endif /* EXTREME_TLV_DEBUG */
818 if (*expected
& TLVFLAG_TE_IPV4_REACHABILITY
)
819 retval
= parse_mt_ipv4_reachs(tlvs
, true,
824 /* +-------+-------+-------+-------+-------+-------+-------+-------+
825 * + IP version 6 address + 16
826 * +-------+-------+-------+-------+-------+-------+-------+-------+
829 *found
|= TLVFLAG_IPV6_ADDR
;
830 #ifdef EXTREME_TLV_DEBUG
831 zlog_debug("ISIS-TLV (%s): IPv6 Address length %d",
833 #endif /* EXTREME_TLV_DEBUG */
834 if (*expected
& TLVFLAG_IPV6_ADDR
) {
835 while (length
> value_len
) {
836 ipv6_addr
= (struct in6_addr
*)pnt
;
837 if (!tlvs
->ipv6_addrs
)
838 tlvs
->ipv6_addrs
= list_new();
839 listnode_add(tlvs
->ipv6_addrs
,
849 case IPV6_REACHABILITY
:
850 *found
|= TLVFLAG_IPV6_REACHABILITY
;
851 #ifdef EXTREME_TLV_DEBUG
852 zlog_debug("ISIS-TLV (%s): IPv6 Reachability length %d",
854 #endif /* EXTREME_TLV_DEBUG */
855 if (*expected
& TLVFLAG_IPV6_REACHABILITY
)
856 retval
= parse_mt_ipv6_reachs(tlvs
, false,
860 case MT_IPV6_REACHABILITY
:
861 *found
|= TLVFLAG_IPV6_REACHABILITY
;
862 #ifdef EXTREME_TLV_DEBUG
863 zlog_debug("ISIS-TLV (%s): IPv6 Reachability length %d",
865 #endif /* EXTREME_TLV_DEBUG */
866 if (*expected
& TLVFLAG_IPV6_REACHABILITY
)
867 retval
= parse_mt_ipv6_reachs(tlvs
, true,
872 /* +---------------------------------------------------------------+
873 * | Adjacency state | 1
874 * +---------------------------------------------------------------+
875 * | Extended Local Circuit ID | 4
876 * +---------------------------------------------------------------+
877 * | Neighbor System ID (If known)
880 * +---------------------------------------------------------------+
881 * | Neighbor Local Circuit ID (If
883 * +---------------------------------------------------------------+
885 *found
|= TLVFLAG_3WAY_HELLO
;
886 if (*expected
& TLVFLAG_3WAY_HELLO
) {
887 while (length
> value_len
) {
888 /* FIXME: make this work */
889 /* Adjacency State (one
894 Extended Local Circuit ID
896 Neighbor System ID if known
897 (zero to eight octets)
898 Neighbor Extended Local
899 Circuit ID (four octets, if Neighbor
900 System ID is present) */
909 case GRACEFUL_RESTART
:
910 /* +-------+-------+-------+-------+-------+-------+-------+-------+
911 * | Reserved | SA | RA
913 * +-------+-------+-------+-------+-------+-------+-------+-------+
914 * | Remaining Time | 2
915 * +---------------------------------------------------------------+
916 * | Restarting Neighbor ID (If known)
918 * +---------------------------------------------------------------+
920 *found
|= TLVFLAG_GRACEFUL_RESTART
;
921 if (*expected
& TLVFLAG_GRACEFUL_RESTART
) {
922 /* FIXME: make this work */
927 case MT_ROUTER_INFORMATION
:
928 *found
|= TLVFLAG_MT_ROUTER_INFORMATION
;
929 if (*expected
& TLVFLAG_MT_ROUTER_INFORMATION
) {
930 if (!tlvs
->mt_router_info
) {
931 tlvs
->mt_router_info
= list_new();
932 tlvs
->mt_router_info
->del
= free_tlv
;
934 while (length
> value_len
) {
936 struct mt_router_info
*info
;
938 if (value_len
+ sizeof(mt_info
)
941 "ISIS-TLV (%s): TLV 229 is truncated.",
943 pnt
+= length
- value_len
;
947 memcpy(&mt_info
, pnt
, sizeof(mt_info
));
948 pnt
+= sizeof(mt_info
);
949 value_len
+= sizeof(mt_info
);
951 mt_info
= ntohs(mt_info
);
952 info
= XCALLOC(MTYPE_ISIS_TLV
,
954 info
->mtid
= mt_info
& ISIS_MT_MASK
;
956 mt_info
& ISIS_MT_OL_MASK
;
957 listnode_add(tlvs
->mt_router_info
,
966 "ISIS-TLV (%s): unsupported TLV type %d, length %d",
967 areatag
, type
, length
);
972 /* Abort Parsing if error occured */
973 if (retval
!= ISIS_OK
)
980 int add_tlv(u_char tag
, u_char len
, u_char
*value
, struct stream
*stream
)
982 if ((stream_get_size(stream
) - stream_get_endp(stream
))
983 < (((unsigned)len
) + 2)) {
985 "No room for TLV of type %d "
986 "(total size %d available %d required %d)",
987 tag
, (int)stream_get_size(stream
),
988 (int)(stream_get_size(stream
)
989 - stream_get_endp(stream
)),
994 stream_putc(stream
, tag
); /* TAG */
995 stream_putc(stream
, len
); /* LENGTH */
996 stream_put(stream
, value
, (int)len
); /* VALUE */
999 zlog_debug("Added TLV %d len %d", tag
, len
);
1000 #endif /* EXTREME DEBUG */
1004 int tlv_add_mt_router_info(struct list
*mt_router_info
, struct stream
*stream
)
1006 struct listnode
*node
;
1007 struct mt_router_info
*info
;
1009 uint16_t value
[127];
1010 uint16_t *pos
= value
;
1012 for (ALL_LIST_ELEMENTS_RO(mt_router_info
, node
, info
)) {
1015 mt_info
= info
->mtid
;
1017 mt_info
|= ISIS_MT_OL_MASK
;
1019 *pos
= htons(mt_info
);
1023 return add_tlv(MT_ROUTER_INFORMATION
, (pos
- value
) * sizeof(*pos
),
1024 (u_char
*)value
, stream
);
1027 int tlv_add_area_addrs(struct list
*area_addrs
, struct stream
*stream
)
1029 struct listnode
*node
;
1030 struct area_addr
*area_addr
;
1033 u_char
*pos
= value
;
1035 for (ALL_LIST_ELEMENTS_RO(area_addrs
, node
, area_addr
)) {
1036 if (pos
- value
+ area_addr
->addr_len
> 255)
1038 *pos
= area_addr
->addr_len
;
1040 memcpy(pos
, area_addr
->area_addr
, (int)area_addr
->addr_len
);
1041 pos
+= area_addr
->addr_len
;
1044 return add_tlv(AREA_ADDRESSES
, pos
- value
, value
, stream
);
1047 zlog_warn("tlv_add_area_addrs(): TLV longer than 255");
1048 return ISIS_WARNING
;
1051 int tlv_add_is_neighs(struct list
*is_neighs
, struct stream
*stream
)
1053 struct listnode
*node
;
1054 struct is_neigh
*is_neigh
;
1056 u_char
*pos
= value
;
1059 *pos
= 0; /*is_neigh->virtual; */
1062 for (ALL_LIST_ELEMENTS_RO(is_neighs
, node
, is_neigh
)) {
1063 if (pos
- value
+ IS_NEIGHBOURS_LEN
> 255) {
1064 retval
= add_tlv(IS_NEIGHBOURS
, pos
- value
, value
,
1066 if (retval
!= ISIS_OK
)
1070 *pos
= is_neigh
->metrics
.metric_default
;
1072 *pos
= is_neigh
->metrics
.metric_delay
;
1074 *pos
= is_neigh
->metrics
.metric_expense
;
1076 *pos
= is_neigh
->metrics
.metric_error
;
1078 memcpy(pos
, is_neigh
->neigh_id
, ISIS_SYS_ID_LEN
+ 1);
1079 pos
+= ISIS_SYS_ID_LEN
+ 1;
1082 return add_tlv(IS_NEIGHBOURS
, pos
- value
, value
, stream
);
1085 static size_t max_tlv_size(struct stream
*stream
)
1087 size_t avail
= stream_get_size(stream
) - stream_get_endp(stream
);
1098 unsigned int tlv_add_te_is_neighs(struct list
*te_is_neighs
,
1099 struct stream
*stream
, void *arg
)
1101 struct listnode
*node
;
1102 struct te_is_neigh
*te_is_neigh
;
1104 u_char
*pos
= value
;
1105 uint16_t mtid
= arg
? *(uint16_t *)arg
: ISIS_MT_IPV4_UNICAST
;
1106 unsigned int consumed
= 0;
1107 size_t max_size
= max_tlv_size(stream
);
1109 if (mtid
!= ISIS_MT_IPV4_UNICAST
) {
1110 uint16_t mtid_conversion
= ntohs(mtid
);
1111 memcpy(pos
, &mtid_conversion
, sizeof(mtid_conversion
));
1112 pos
+= sizeof(mtid_conversion
);
1115 for (ALL_LIST_ELEMENTS_RO(te_is_neighs
, node
, te_is_neigh
)) {
1116 /* FIXME: Check if Total SubTLVs size doesn't exceed 255 */
1117 if ((size_t)(pos
- value
) + IS_NEIGHBOURS_LEN
1118 + te_is_neigh
->sub_tlvs_length
1122 memcpy(pos
, te_is_neigh
->neigh_id
, ISIS_SYS_ID_LEN
+ 1);
1123 pos
+= ISIS_SYS_ID_LEN
+ 1;
1124 memcpy(pos
, te_is_neigh
->te_metric
, 3);
1126 /* Set the total size of Sub TLVs */
1127 *pos
= te_is_neigh
->sub_tlvs_length
;
1129 /* Copy Sub TLVs if any */
1130 if (te_is_neigh
->sub_tlvs_length
> 0) {
1131 memcpy(pos
, te_is_neigh
->sub_tlvs
,
1132 te_is_neigh
->sub_tlvs_length
);
1133 pos
+= te_is_neigh
->sub_tlvs_length
;
1139 int rv
= add_tlv((mtid
!= ISIS_MT_IPV4_UNICAST
)
1142 pos
- value
, value
, stream
);
1143 assert(rv
== ISIS_OK
);
1148 int tlv_add_lan_neighs(struct list
*lan_neighs
, struct stream
*stream
)
1150 struct listnode
*node
;
1153 u_char
*pos
= value
;
1156 for (ALL_LIST_ELEMENTS_RO(lan_neighs
, node
, snpa
)) {
1157 if (pos
- value
+ ETH_ALEN
> 255) {
1158 retval
= add_tlv(LAN_NEIGHBOURS
, pos
- value
, value
,
1160 if (retval
!= ISIS_OK
)
1164 memcpy(pos
, snpa
, ETH_ALEN
);
1168 return add_tlv(LAN_NEIGHBOURS
, pos
- value
, value
, stream
);
1171 int tlv_add_nlpid(struct nlpids
*nlpids
, struct stream
*stream
)
1173 return add_tlv(PROTOCOLS_SUPPORTED
, nlpids
->count
, nlpids
->nlpids
,
1177 int tlv_add_authinfo(u_char auth_type
, u_char auth_len
, u_char
*auth_value
,
1178 struct stream
*stream
)
1181 u_char
*pos
= value
;
1183 memcpy(pos
, auth_value
, auth_len
);
1185 return add_tlv(AUTH_INFO
, auth_len
+ 1, value
, stream
);
1188 int tlv_add_checksum(struct checksum
*checksum
, struct stream
*stream
)
1191 u_char
*pos
= value
;
1192 return add_tlv(CHECKSUM
, pos
- value
, value
, stream
);
1195 int tlv_add_ip_addrs(struct list
*ip_addrs
, struct stream
*stream
)
1197 struct listnode
*node
;
1198 struct prefix_ipv4
*ipv4
;
1200 u_char
*pos
= value
;
1202 for (ALL_LIST_ELEMENTS_RO(ip_addrs
, node
, ipv4
)) {
1203 if (pos
- value
+ IPV4_MAX_BYTELEN
> 255) {
1204 /* RFC 1195 s4.2: only one tuple of 63 allowed. */
1206 "tlv_add_ip_addrs(): cutting off at 63 IP addresses");
1209 *(u_int32_t
*)pos
= ipv4
->prefix
.s_addr
;
1210 pos
+= IPV4_MAX_BYTELEN
;
1213 return add_tlv(IPV4_ADDR
, pos
- value
, value
, stream
);
1216 /* Used to add TLV containing just one IPv4 address - either IPv4 address TLV
1217 * (in case of LSP) or TE router ID TLV. */
1218 int tlv_add_in_addr(struct in_addr
*addr
, struct stream
*stream
, u_char tag
)
1221 u_char
*pos
= value
;
1223 memcpy(pos
, addr
, IPV4_MAX_BYTELEN
);
1224 pos
+= IPV4_MAX_BYTELEN
;
1226 return add_tlv(tag
, pos
- value
, value
, stream
);
1229 int tlv_add_dynamic_hostname(struct hostname
*hostname
, struct stream
*stream
)
1231 return add_tlv(DYNAMIC_HOSTNAME
, hostname
->namelen
, hostname
->name
,
1235 int tlv_add_lsp_entries(struct list
*lsps
, struct stream
*stream
)
1237 struct listnode
*node
;
1238 struct isis_lsp
*lsp
;
1240 u_char
*pos
= value
;
1243 for (ALL_LIST_ELEMENTS_RO(lsps
, node
, lsp
)) {
1244 if (pos
- value
+ LSP_ENTRIES_LEN
> 255) {
1245 retval
= add_tlv(LSP_ENTRIES
, pos
- value
, value
,
1247 if (retval
!= ISIS_OK
)
1251 *((u_int16_t
*)pos
) = lsp
->lsp_header
->rem_lifetime
;
1253 memcpy(pos
, lsp
->lsp_header
->lsp_id
, ISIS_SYS_ID_LEN
+ 2);
1254 pos
+= ISIS_SYS_ID_LEN
+ 2;
1255 *((u_int32_t
*)pos
) = lsp
->lsp_header
->seq_num
;
1257 *((u_int16_t
*)pos
) = lsp
->lsp_header
->checksum
;
1261 return add_tlv(LSP_ENTRIES
, pos
- value
, value
, stream
);
1264 static int tlv_add_ipv4_reachs(u_char tag
, struct list
*ipv4_reachs
,
1265 struct stream
*stream
)
1267 struct listnode
*node
;
1268 struct ipv4_reachability
*reach
;
1270 u_char
*pos
= value
;
1273 for (ALL_LIST_ELEMENTS_RO(ipv4_reachs
, node
, reach
)) {
1274 if (pos
- value
+ IPV4_REACH_LEN
> 255) {
1275 retval
= add_tlv(tag
, pos
- value
, value
, stream
);
1276 if (retval
!= ISIS_OK
)
1280 *pos
= reach
->metrics
.metric_default
;
1282 *pos
= reach
->metrics
.metric_delay
;
1284 *pos
= reach
->metrics
.metric_expense
;
1286 *pos
= reach
->metrics
.metric_error
;
1288 *(u_int32_t
*)pos
= reach
->prefix
.s_addr
;
1289 pos
+= IPV4_MAX_BYTELEN
;
1290 *(u_int32_t
*)pos
= reach
->mask
.s_addr
;
1291 pos
+= IPV4_MAX_BYTELEN
;
1294 return add_tlv(tag
, pos
- value
, value
, stream
);
1297 int tlv_add_ipv4_int_reachs(struct list
*ipv4_reachs
, struct stream
*stream
)
1299 return tlv_add_ipv4_reachs(IPV4_INT_REACHABILITY
, ipv4_reachs
, stream
);
1302 int tlv_add_ipv4_ext_reachs(struct list
*ipv4_reachs
, struct stream
*stream
)
1304 return tlv_add_ipv4_reachs(IPV4_EXT_REACHABILITY
, ipv4_reachs
, stream
);
1308 unsigned int tlv_add_te_ipv4_reachs(struct list
*te_ipv4_reachs
,
1309 struct stream
*stream
, void *arg
)
1311 struct listnode
*node
;
1312 struct te_ipv4_reachability
*te_reach
;
1314 u_char
*pos
= value
;
1315 uint16_t mtid
= arg
? *(uint16_t *)arg
: ISIS_MT_IPV4_UNICAST
;
1316 unsigned int consumed
= 0;
1317 size_t max_size
= max_tlv_size(stream
);
1319 if (mtid
!= ISIS_MT_IPV4_UNICAST
) {
1320 uint16_t mtid_conversion
= ntohs(mtid
);
1321 memcpy(pos
, &mtid_conversion
, sizeof(mtid_conversion
));
1322 pos
+= sizeof(mtid_conversion
);
1325 for (ALL_LIST_ELEMENTS_RO(te_ipv4_reachs
, node
, te_reach
)) {
1326 unsigned char prefixlen
= te_reach
->control
& 0x3F;
1328 if ((size_t)(pos
- value
) + 5 + PSIZE(prefixlen
) > max_size
)
1331 *(u_int32_t
*)pos
= te_reach
->te_metric
;
1333 *pos
= te_reach
->control
;
1335 memcpy(pos
, &te_reach
->prefix_start
, PSIZE(prefixlen
));
1336 pos
+= PSIZE(prefixlen
);
1341 int rv
= add_tlv((mtid
!= ISIS_MT_IPV4_UNICAST
)
1342 ? MT_IPV4_REACHABILITY
1343 : TE_IPV4_REACHABILITY
,
1344 pos
- value
, value
, stream
);
1345 assert(rv
== ISIS_OK
);
1351 int tlv_add_ipv6_addrs(struct list
*ipv6_addrs
, struct stream
*stream
)
1353 struct listnode
*node
;
1354 struct prefix_ipv6
*ipv6
;
1356 u_char
*pos
= value
;
1359 for (ALL_LIST_ELEMENTS_RO(ipv6_addrs
, node
, ipv6
)) {
1360 if (pos
- value
+ IPV6_MAX_BYTELEN
> 255) {
1361 retval
= add_tlv(IPV6_ADDR
, pos
- value
, value
, stream
);
1362 if (retval
!= ISIS_OK
)
1366 memcpy(pos
, ipv6
->prefix
.s6_addr
, IPV6_MAX_BYTELEN
);
1367 pos
+= IPV6_MAX_BYTELEN
;
1370 return add_tlv(IPV6_ADDR
, pos
- value
, value
, stream
);
1373 unsigned int tlv_add_ipv6_reachs(struct list
*ipv6_reachs
,
1374 struct stream
*stream
, void *arg
)
1376 struct listnode
*node
;
1377 struct ipv6_reachability
*ip6reach
;
1379 u_char
*pos
= value
;
1380 uint16_t mtid
= arg
? *(uint16_t *)arg
: ISIS_MT_IPV4_UNICAST
;
1381 unsigned int consumed
= 0;
1382 size_t max_size
= max_tlv_size(stream
);
1384 if (mtid
!= ISIS_MT_IPV4_UNICAST
) {
1385 uint16_t mtid_conversion
= ntohs(mtid
);
1386 memcpy(pos
, &mtid_conversion
, sizeof(mtid_conversion
));
1387 pos
+= sizeof(mtid_conversion
);
1390 for (ALL_LIST_ELEMENTS_RO(ipv6_reachs
, node
, ip6reach
)) {
1391 if ((size_t)(pos
- value
) + 6 + PSIZE(ip6reach
->prefix_len
)
1395 *(uint32_t *)pos
= ip6reach
->metric
;
1397 *pos
= ip6reach
->control_info
;
1399 *pos
= ip6reach
->prefix_len
;
1401 memcpy(pos
, ip6reach
->prefix
, PSIZE(ip6reach
->prefix_len
));
1402 pos
+= PSIZE(ip6reach
->prefix_len
);
1407 int rv
= add_tlv((mtid
!= ISIS_MT_IPV4_UNICAST
)
1408 ? MT_IPV6_REACHABILITY
1409 : IPV6_REACHABILITY
,
1410 pos
- value
, value
, stream
);
1411 assert(rv
== ISIS_OK
);
1417 int tlv_add_padding(struct stream
*stream
)
1419 int fullpads
, i
, left
;
1422 * How many times can we add full padding ?
1424 fullpads
= (stream_get_size(stream
) - stream_get_endp(stream
)) / 257;
1425 for (i
= 0; i
< fullpads
; i
++) {
1426 if (!stream_putc(stream
, (u_char
)PADDING
)) /* TAG */
1428 if (!stream_putc(stream
, (u_char
)255)) /* LENGHT */
1430 stream_put(stream
, NULL
, 255); /* zero padding */
1433 left
= stream_get_size(stream
) - stream_get_endp(stream
);
1439 stream_putc(stream
, PADDING
);
1440 stream_putc(stream
, 0);
1444 stream_putc(stream
, PADDING
);
1445 stream_putc(stream
, left
- 2);
1446 stream_put(stream
, NULL
, left
- 2);
1451 zlog_warn("tlv_add_padding(): no room for tlv");
1452 return ISIS_WARNING
;