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; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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"
49 XFREE (MTYPE_ISIS_TLV
, val
);
55 * Called after parsing of a PDU. There shouldn't be any tlv's left, so this
56 * is only a caution to avoid memory leaks
59 free_tlvs (struct tlvs
*tlvs
)
62 list_delete (tlvs
->area_addrs
);
64 list_delete (tlvs
->is_neighs
);
65 if (tlvs
->te_is_neighs
)
66 list_delete (tlvs
->te_is_neighs
);
68 list_delete (tlvs
->es_neighs
);
69 if (tlvs
->lsp_entries
)
70 list_delete (tlvs
->lsp_entries
);
71 if (tlvs
->prefix_neighs
)
72 list_delete (tlvs
->prefix_neighs
);
74 list_delete (tlvs
->lan_neighs
);
76 list_delete (tlvs
->ipv4_addrs
);
77 if (tlvs
->ipv4_int_reachs
)
78 list_delete (tlvs
->ipv4_int_reachs
);
79 if (tlvs
->ipv4_ext_reachs
)
80 list_delete (tlvs
->ipv4_ext_reachs
);
81 if (tlvs
->te_ipv4_reachs
)
82 list_delete (tlvs
->te_ipv4_reachs
);
85 list_delete (tlvs
->ipv6_addrs
);
86 if (tlvs
->ipv6_reachs
)
87 list_delete (tlvs
->ipv6_reachs
);
88 #endif /* HAVE_IPV6 */
90 memset (tlvs
, 0, sizeof (struct tlvs
));
96 * Parses the tlvs found in the variant length part of the PDU.
97 * Caller tells with flags in "expected" which TLV's it is interested in.
100 parse_tlvs (char *areatag
, u_char
* stream
, int size
, u_int32_t
* expected
,
101 u_int32_t
* found
, struct tlvs
*tlvs
, u_int32_t
*auth_tlv_offset
)
104 struct lan_neigh
*lan_nei
;
105 struct area_addr
*area_addr
;
106 struct is_neigh
*is_nei
;
107 struct te_is_neigh
*te_is_nei
;
108 struct es_neigh
*es_nei
;
109 struct lsp_entry
*lsp_entry
;
110 struct in_addr
*ipv4_addr
;
111 struct ipv4_reachability
*ipv4_reach
;
112 struct te_ipv4_reachability
*te_ipv4_reach
;
114 struct in6_addr
*ipv6_addr
;
115 struct ipv6_reachability
*ipv6_reach
;
117 #endif /* HAVE_IPV6 */
118 int value_len
, retval
= ISIS_OK
;
119 u_char
*start
= stream
, *pnt
= stream
, *endpnt
;
122 memset (tlvs
, 0, sizeof (struct tlvs
));
124 while (pnt
< stream
+ size
- 2)
130 if (pnt
+ length
> stream
+ size
)
132 zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet "
133 "boundaries", areatag
, type
, length
);
134 retval
= ISIS_WARNING
;
140 /* +-------+-------+-------+-------+-------+-------+-------+-------+
142 * +-------+-------+-------+-------+-------+-------+-------+-------+
144 * +-------+-------+-------+-------+-------+-------+-------+-------+
147 *found
|= TLVFLAG_AREA_ADDRS
;
148 #ifdef EXTREME_TLV_DEBUG
149 zlog_debug ("TLV Area Adresses len %d", length
);
150 #endif /* EXTREME_TLV_DEBUG */
151 if (*expected
& TLVFLAG_AREA_ADDRS
)
153 while (length
> value_len
)
155 area_addr
= (struct area_addr
*) pnt
;
156 value_len
+= area_addr
->addr_len
+ 1;
157 pnt
+= area_addr
->addr_len
+ 1;
158 if (!tlvs
->area_addrs
)
159 tlvs
->area_addrs
= list_new ();
160 listnode_add (tlvs
->area_addrs
, area_addr
);
170 *found
|= TLVFLAG_IS_NEIGHS
;
171 #ifdef EXTREME_TLV_DEBUG
172 zlog_debug ("ISIS-TLV (%s): IS Neighbours length %d",
174 #endif /* EXTREME_TLV_DEBUG */
175 if (TLVFLAG_IS_NEIGHS
& *expected
)
177 /* +-------+-------+-------+-------+-------+-------+-------+-------+
179 * +-------+-------+-------+-------+-------+-------+-------+-------+
183 /* +-------+-------+-------+-------+-------+-------+-------+-------+
184 * | 0 | I/E | Default Metric |
185 * +-------+-------+-------+-------+-------+-------+-------+-------+
186 * | S | I/E | Delay Metric |
187 * +-------+-------+-------+-------+-------+-------+-------+-------+
188 * | S | I/E | Expense Metric |
189 * +-------+-------+-------+-------+-------+-------+-------+-------+
190 * | S | I/E | Error Metric |
191 * +-------+-------+-------+-------+-------+-------+-------+-------+
193 * +---------------------------------------------------------------+
196 while (length
> value_len
)
198 is_nei
= (struct is_neigh
*) pnt
;
199 value_len
+= 4 + ISIS_SYS_ID_LEN
+ 1;
200 pnt
+= 4 + ISIS_SYS_ID_LEN
+ 1;
201 if (!tlvs
->is_neighs
)
202 tlvs
->is_neighs
= list_new ();
203 listnode_add (tlvs
->is_neighs
, is_nei
);
212 case TE_IS_NEIGHBOURS
:
213 /* +-------+-------+-------+-------+-------+-------+-------+-------+
215 * +---------------------------------------------------------------+
217 * +---------------------------------------------------------------+
218 * | SubTLVs Length | 1
219 * +---------------------------------------------------------------+
222 *found
|= TLVFLAG_TE_IS_NEIGHS
;
223 #ifdef EXTREME_TLV_DEBUG
224 zlog_debug ("ISIS-TLV (%s): Extended IS Neighbours length %d",
226 #endif /* EXTREME_TLV_DEBUG */
227 if (TLVFLAG_TE_IS_NEIGHS
& *expected
)
229 while (length
> value_len
)
231 te_is_nei
= (struct te_is_neigh
*) pnt
;
234 /* FIXME - subtlvs are handled here, for now we skip */
235 value_len
+= te_is_nei
->sub_tlvs_length
;
236 pnt
+= te_is_nei
->sub_tlvs_length
;
238 if (!tlvs
->te_is_neighs
)
239 tlvs
->te_is_neighs
= list_new ();
240 listnode_add (tlvs
->te_is_neighs
, te_is_nei
);
250 /* +-------+-------+-------+-------+-------+-------+-------+-------+
251 * | 0 | I/E | Default Metric |
252 * +-------+-------+-------+-------+-------+-------+-------+-------+
253 * | S | I/E | Delay Metric |
254 * +-------+-------+-------+-------+-------+-------+-------+-------+
255 * | S | I/E | Expense Metric |
256 * +-------+-------+-------+-------+-------+-------+-------+-------+
257 * | S | I/E | Error Metric |
258 * +-------+-------+-------+-------+-------+-------+-------+-------+
260 * +---------------------------------------------------------------+
262 * +---------------------------------------------------------------+
265 #ifdef EXTREME_TLV_DEBUG
266 zlog_debug ("ISIS-TLV (%s): ES Neighbours length %d",
268 #endif /* EXTREME_TLV_DEBUG */
269 *found
|= TLVFLAG_ES_NEIGHS
;
270 if (*expected
& TLVFLAG_ES_NEIGHS
)
272 es_nei
= (struct es_neigh
*) pnt
;
275 while (length
> value_len
)
277 /* FIXME FIXME FIXME - add to the list */
278 /* sys_id->id = pnt; */
279 value_len
+= ISIS_SYS_ID_LEN
;
280 pnt
+= ISIS_SYS_ID_LEN
;
281 /* if (!es_nei->neigh_ids) es_nei->neigh_ids = sysid; */
283 if (!tlvs
->es_neighs
)
284 tlvs
->es_neighs
= list_new ();
285 listnode_add (tlvs
->es_neighs
, es_nei
);
294 /* +-------+-------+-------+-------+-------+-------+-------+-------+
296 * +-------+-------+-------+-------+-------+-------+-------+-------+
299 *found
|= TLVFLAG_LAN_NEIGHS
;
300 #ifdef EXTREME_TLV_DEBUG
301 zlog_debug ("ISIS-TLV (%s): LAN Neigbours length %d",
303 #endif /* EXTREME_TLV_DEBUG */
304 if (TLVFLAG_LAN_NEIGHS
& *expected
)
306 while (length
> value_len
)
308 lan_nei
= (struct lan_neigh
*) pnt
;
309 if (!tlvs
->lan_neighs
)
310 tlvs
->lan_neighs
= list_new ();
311 listnode_add (tlvs
->lan_neighs
, lan_nei
);
312 value_len
+= ETH_ALEN
;
323 #ifdef EXTREME_TLV_DEBUG
324 zlog_debug ("TLV padding %d", length
);
325 #endif /* EXTREME_TLV_DEBUG */
330 /* +-------+-------+-------+-------+-------+-------+-------+-------+
331 * | Remaining Lifetime | 2
332 * +-------+-------+-------+-------+-------+-------+-------+-------+
334 * +-------+-------+-------+-------+-------+-------+-------+-------+
335 * | LSP Sequence Number |Â 4
336 * +-------+-------+-------+-------+-------+-------+-------+-------+
338 * +-------+-------+-------+-------+-------+-------+-------+-------+
340 #ifdef EXTREME_TLV_DEBUG
341 zlog_debug ("ISIS-TLV (%s): LSP Entries length %d", areatag
, length
);
342 #endif /* EXTREME_TLV_DEBUG */
343 *found
|= TLVFLAG_LSP_ENTRIES
;
344 if (TLVFLAG_LSP_ENTRIES
& *expected
)
346 while (length
> value_len
)
348 lsp_entry
= (struct lsp_entry
*) pnt
;
349 value_len
+= 10 + ISIS_SYS_ID_LEN
;
350 pnt
+= 10 + ISIS_SYS_ID_LEN
;
351 if (!tlvs
->lsp_entries
)
352 tlvs
->lsp_entries
= list_new ();
353 listnode_add (tlvs
->lsp_entries
, lsp_entry
);
363 /* +-------+-------+-------+-------+-------+-------+-------+-------+
364 * | 16 bit fletcher CHECKSUM |
365 * +-------+-------+-------+-------+-------+-------+-------+-------+
368 *found
|= TLVFLAG_CHECKSUM
;
369 #ifdef EXTREME_TLV_DEBUG
370 zlog_debug ("ISIS-TLV (%s): Checksum length %d", areatag
, length
);
371 #endif /* EXTREME_TLV_DEBUG */
372 if (*expected
& TLVFLAG_CHECKSUM
)
374 tlvs
->checksum
= (struct checksum
*) pnt
;
379 case PROTOCOLS_SUPPORTED
:
380 /* +-------+-------+-------+-------+-------+-------+-------+-------+
382 * +-------+-------+-------+-------+-------+-------+-------+-------+
385 *found
|= TLVFLAG_NLPID
;
386 #ifdef EXTREME_TLV_DEBUG
387 zlog_debug ("ISIS-TLV (%s): Protocols Supported length %d",
389 #endif /* EXTREME_TLV_DEBUG */
390 if (*expected
& TLVFLAG_NLPID
)
392 tlvs
->nlpids
= (struct nlpids
*) (pnt
- 1);
398 /* +-------+-------+-------+-------+-------+-------+-------+-------+
399 * + IP version 4 address + 4
400 * +-------+-------+-------+-------+-------+-------+-------+-------+
403 *found
|= TLVFLAG_IPV4_ADDR
;
404 #ifdef EXTREME_TLV_DEBUG
405 zlog_debug ("ISIS-TLV (%s): IPv4 Address length %d",
407 #endif /* EXTREME_TLV_DEBUG */
408 if (*expected
& TLVFLAG_IPV4_ADDR
)
410 while (length
> value_len
)
412 ipv4_addr
= (struct in_addr
*) pnt
;
413 #ifdef EXTREME_TLV_DEBUG
414 zlog_debug ("ISIS-TLV (%s) : IP ADDR %s, pnt %p", areatag
,
415 inet_ntoa (*ipv4_addr
), pnt
);
416 #endif /* EXTREME_TLV_DEBUG */
417 if (!tlvs
->ipv4_addrs
)
418 tlvs
->ipv4_addrs
= list_new ();
419 listnode_add (tlvs
->ipv4_addrs
, ipv4_addr
);
431 *found
|= TLVFLAG_AUTH_INFO
;
432 #ifdef EXTREME_TLV_DEBUG
433 zlog_debug ("ISIS-TLV (%s): IS-IS Authentication Information",
436 if (*expected
& TLVFLAG_AUTH_INFO
)
438 tlvs
->auth_info
.type
= *pnt
;
441 zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) "
442 "incorrect.", areatag
, type
, length
);
446 tlvs
->auth_info
.len
= length
;
448 memcpy (tlvs
->auth_info
.passwd
, pnt
, length
);
449 /* Return the authentication tlv pos for later computation
450 * of MD5 (RFC 5304, 2)
453 *auth_tlv_offset
+= (pnt
- start
- 3);
462 case DYNAMIC_HOSTNAME
:
463 *found
|= TLVFLAG_DYN_HOSTNAME
;
464 #ifdef EXTREME_TLV_DEBUG
465 zlog_debug ("ISIS-TLV (%s): Dynamic Hostname length %d",
467 #endif /* EXTREME_TLV_DEBUG */
468 if (*expected
& TLVFLAG_DYN_HOSTNAME
)
470 /* the length is also included in the pointed struct */
471 tlvs
->hostname
= (struct hostname
*) (pnt
- 1);
477 /* +---------------------------------------------------------------+
479 * +---------------------------------------------------------------+
481 *found
|= TLVFLAG_TE_ROUTER_ID
;
482 #ifdef EXTREME_TLV_DEBUG
483 zlog_debug ("ISIS-TLV (%s): TE Router ID %d", areatag
, length
);
484 #endif /* EXTREME_TLV_DEBUG */
485 if (*expected
& TLVFLAG_TE_ROUTER_ID
)
486 tlvs
->router_id
= (struct te_router_id
*) (pnt
);
490 case IPV4_INT_REACHABILITY
:
491 /* +-------+-------+-------+-------+-------+-------+-------+-------+
492 * | 0 | I/E | Default Metric | 1
493 * +-------+-------+-------+-------+-------+-------+-------+-------+
494 * | S | I/E | Delay Metric | 1
495 * +-------+-------+-------+-------+-------+-------+-------+-------+
496 * | S | I/E | Expense Metric | 1
497 * +-------+-------+-------+-------+-------+-------+-------+-------+
498 * | S | I/E | Error Metric | 1
499 * +-------+-------+-------+-------+-------+-------+-------+-------+
501 * +---------------------------------------------------------------+
503 * +---------------------------------------------------------------+
506 *found
|= TLVFLAG_IPV4_INT_REACHABILITY
;
507 #ifdef EXTREME_TLV_DEBUG
508 zlog_debug ("ISIS-TLV (%s): IPv4 internal Reachability length %d",
510 #endif /* EXTREME_TLV_DEBUG */
511 if (*expected
& TLVFLAG_IPV4_INT_REACHABILITY
)
513 while (length
> value_len
)
515 ipv4_reach
= (struct ipv4_reachability
*) pnt
;
516 if (!tlvs
->ipv4_int_reachs
)
517 tlvs
->ipv4_int_reachs
= list_new ();
518 listnode_add (tlvs
->ipv4_int_reachs
, ipv4_reach
);
529 case IPV4_EXT_REACHABILITY
:
530 /* +-------+-------+-------+-------+-------+-------+-------+-------+
531 * | 0 | I/E | Default Metric | 1
532 * +-------+-------+-------+-------+-------+-------+-------+-------+
533 * | S | I/E | Delay Metric | 1
534 * +-------+-------+-------+-------+-------+-------+-------+-------+
535 * | S | I/E | Expense Metric | 1
536 * +-------+-------+-------+-------+-------+-------+-------+-------+
537 * | S | I/E | Error Metric | 1
538 * +-------+-------+-------+-------+-------+-------+-------+-------+
540 * +---------------------------------------------------------------+
542 * +---------------------------------------------------------------+
545 *found
|= TLVFLAG_IPV4_EXT_REACHABILITY
;
546 #ifdef EXTREME_TLV_DEBUG
547 zlog_debug ("ISIS-TLV (%s): IPv4 external Reachability length %d",
549 #endif /* EXTREME_TLV_DEBUG */
550 if (*expected
& TLVFLAG_IPV4_EXT_REACHABILITY
)
552 while (length
> value_len
)
554 ipv4_reach
= (struct ipv4_reachability
*) pnt
;
555 if (!tlvs
->ipv4_ext_reachs
)
556 tlvs
->ipv4_ext_reachs
= list_new ();
557 listnode_add (tlvs
->ipv4_ext_reachs
, ipv4_reach
);
568 case TE_IPV4_REACHABILITY
:
569 /* +-------+-------+-------+-------+-------+-------+-------+-------+
571 * +-------+-------+-------+-------+-------+-------+-------+-------+
572 * | U/D | sTLV? | Prefix Mask Len | 1
573 * +-------+-------+-------+-------+-------+-------+-------+-------+
575 * +---------------------------------------------------------------+
577 * +---------------------------------------------------------------+
580 *found
|= TLVFLAG_TE_IPV4_REACHABILITY
;
581 #ifdef EXTREME_TLV_DEBUG
582 zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d",
584 #endif /* EXTREME_TLV_DEBUG */
585 endpnt
= pnt
+ length
;
586 if (*expected
& TLVFLAG_TE_IPV4_REACHABILITY
)
588 while (length
> value_len
)
590 te_ipv4_reach
= (struct te_ipv4_reachability
*) pnt
;
591 if ((te_ipv4_reach
->control
& 0x3F) > IPV4_MAX_BITLEN
)
593 zlog_warn ("ISIS-TLV (%s): invalid IPv4 extended reach"
594 "ability prefix length %d", areatag
,
595 te_ipv4_reach
->control
& 0x3F);
596 retval
= ISIS_WARNING
;
599 if (!tlvs
->te_ipv4_reachs
)
600 tlvs
->te_ipv4_reachs
= list_new ();
601 listnode_add (tlvs
->te_ipv4_reachs
, te_ipv4_reach
);
602 /* this trickery is permitable since no subtlvs are defined */
603 value_len
+= 5 + ((te_ipv4_reach
->control
& 0x3F) ?
604 ((((te_ipv4_reach
->control
& 0x3F) -
606 pnt
+= 5 + ((te_ipv4_reach
->control
& 0x3F) ?
607 ((((te_ipv4_reach
->control
& 0x3F) - 1) >> 3) + 1) : 0);
616 /* +-------+-------+-------+-------+-------+-------+-------+-------+
617 * + IP version 6 address + 16
618 * +-------+-------+-------+-------+-------+-------+-------+-------+
621 *found
|= TLVFLAG_IPV6_ADDR
;
622 #ifdef EXTREME_TLV_DEBUG
623 zlog_debug ("ISIS-TLV (%s): IPv6 Address length %d",
625 #endif /* EXTREME_TLV_DEBUG */
626 if (*expected
& TLVFLAG_IPV6_ADDR
)
628 while (length
> value_len
)
630 ipv6_addr
= (struct in6_addr
*) pnt
;
631 if (!tlvs
->ipv6_addrs
)
632 tlvs
->ipv6_addrs
= list_new ();
633 listnode_add (tlvs
->ipv6_addrs
, ipv6_addr
);
644 case IPV6_REACHABILITY
:
645 /* +-------+-------+-------+-------+-------+-------+-------+-------+
646 * | Default Metric | 4
647 * +-------+-------+-------+-------+-------+-------+-------+-------+
648 * | Control Informantion |
649 * +---------------------------------------------------------------+
650 * | IPv6 Prefix Length |--+
651 * +---------------------------------------------------------------+ |
653 * +---------------------------------------------------------------+
655 *found
|= TLVFLAG_IPV6_REACHABILITY
;
656 endpnt
= pnt
+ length
;
658 if (*expected
& TLVFLAG_IPV6_REACHABILITY
)
660 while (length
> value_len
)
662 ipv6_reach
= (struct ipv6_reachability
*) pnt
;
663 if (ipv6_reach
->prefix_len
> IPV6_MAX_BITLEN
)
665 zlog_warn ("ISIS-TLV (%s): invalid IPv6 extended reach"
666 "ability prefix length %d", areatag
,
667 ipv6_reach
->prefix_len
);
668 retval
= ISIS_WARNING
;
672 prefix_octets
= ((ipv6_reach
->prefix_len
+ 7) / 8);
673 value_len
+= prefix_octets
+ 6;
674 pnt
+= prefix_octets
+ 6;
675 /* FIXME: sub-tlvs */
676 if (!tlvs
->ipv6_reachs
)
677 tlvs
->ipv6_reachs
= list_new ();
678 listnode_add (tlvs
->ipv6_reachs
, ipv6_reach
);
684 #endif /* HAVE_IPV6 */
687 /* +---------------------------------------------------------------+
688 * | Adjacency state | 1
689 * +---------------------------------------------------------------+
690 * | Extended Local Circuit ID | 4
691 * +---------------------------------------------------------------+
692 * | Neighbor System ID (If known) | 0-8
694 * +---------------------------------------------------------------+
695 * | Neighbor Local Circuit ID (If known) | 4
696 * +---------------------------------------------------------------+
698 *found
|= TLVFLAG_3WAY_HELLO
;
699 if (*expected
& TLVFLAG_3WAY_HELLO
)
701 while (length
> value_len
)
703 /* FIXME: make this work */
704 /* Adjacency State (one octet):
708 Extended Local Circuit ID (four octets)
709 Neighbor System ID if known (zero to eight octets)
710 Neighbor Extended Local Circuit ID (four octets, if Neighbor
711 System ID is present) */
722 case GRACEFUL_RESTART
:
723 /* +-------+-------+-------+-------+-------+-------+-------+-------+
724 * | Reserved | SA | RA | RR | 1
725 * +-------+-------+-------+-------+-------+-------+-------+-------+
726 * | Remaining Time | 2
727 * +---------------------------------------------------------------+
728 * | Restarting Neighbor ID (If known) | 0-8
729 * +---------------------------------------------------------------+
731 *found
|= TLVFLAG_GRACEFUL_RESTART
;
732 if (*expected
& TLVFLAG_GRACEFUL_RESTART
)
734 /* FIXME: make this work */
740 zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
741 areatag
, type
, length
);
752 add_tlv (u_char tag
, u_char len
, u_char
* value
, struct stream
*stream
)
754 if ((stream_get_size (stream
) - stream_get_endp (stream
)) <
755 (((unsigned)len
) + 2))
757 zlog_warn ("No room for TLV of type %d "
758 "(total size %d available %d required %d)",
759 tag
, (int)stream_get_size (stream
),
760 (int)(stream_get_size (stream
) - stream_get_endp (stream
)),
765 stream_putc (stream
, tag
); /* TAG */
766 stream_putc (stream
, len
); /* LENGTH */
767 stream_put (stream
, value
, (int) len
); /* VALUE */
770 zlog_debug ("Added TLV %d len %d", tag
, len
);
771 #endif /* EXTREME DEBUG */
776 tlv_add_area_addrs (struct list
*area_addrs
, struct stream
*stream
)
778 struct listnode
*node
;
779 struct area_addr
*area_addr
;
784 for (ALL_LIST_ELEMENTS_RO (area_addrs
, node
, area_addr
))
786 if (pos
- value
+ area_addr
->addr_len
> 255)
788 *pos
= area_addr
->addr_len
;
790 memcpy (pos
, area_addr
->area_addr
, (int) area_addr
->addr_len
);
791 pos
+= area_addr
->addr_len
;
794 return add_tlv (AREA_ADDRESSES
, pos
- value
, value
, stream
);
797 zlog_warn ("tlv_add_area_addrs(): TLV longer than 255");
802 tlv_add_is_neighs (struct list
*is_neighs
, struct stream
*stream
)
804 struct listnode
*node
;
805 struct is_neigh
*is_neigh
;
810 *pos
= 0; /*is_neigh->virtual; */
813 for (ALL_LIST_ELEMENTS_RO (is_neighs
, node
, is_neigh
))
815 if (pos
- value
+ IS_NEIGHBOURS_LEN
> 255)
817 retval
= add_tlv (IS_NEIGHBOURS
, pos
- value
, value
, stream
);
818 if (retval
!= ISIS_OK
)
822 *pos
= is_neigh
->metrics
.metric_default
;
824 *pos
= is_neigh
->metrics
.metric_delay
;
826 *pos
= is_neigh
->metrics
.metric_expense
;
828 *pos
= is_neigh
->metrics
.metric_error
;
830 memcpy (pos
, is_neigh
->neigh_id
, ISIS_SYS_ID_LEN
+ 1);
831 pos
+= ISIS_SYS_ID_LEN
+ 1;
834 return add_tlv (IS_NEIGHBOURS
, pos
- value
, value
, stream
);
838 tlv_add_te_is_neighs (struct list
*te_is_neighs
, struct stream
*stream
)
840 struct listnode
*node
;
841 struct te_is_neigh
*te_is_neigh
;
846 for (ALL_LIST_ELEMENTS_RO (te_is_neighs
, node
, te_is_neigh
))
848 /* FIXME: This will be wrong if we are going to add TE sub TLVs. */
849 if (pos
- value
+ IS_NEIGHBOURS_LEN
> 255)
851 retval
= add_tlv (TE_IS_NEIGHBOURS
, pos
- value
, value
, stream
);
852 if (retval
!= ISIS_OK
)
857 memcpy (pos
, te_is_neigh
->neigh_id
, ISIS_SYS_ID_LEN
+ 1);
858 pos
+= ISIS_SYS_ID_LEN
+ 1;
859 memcpy (pos
, te_is_neigh
->te_metric
, 3);
861 /* Sub TLVs length. */
866 return add_tlv (TE_IS_NEIGHBOURS
, pos
- value
, value
, stream
);
870 tlv_add_lan_neighs (struct list
*lan_neighs
, struct stream
*stream
)
872 struct listnode
*node
;
878 for (ALL_LIST_ELEMENTS_RO (lan_neighs
, node
, snpa
))
880 if (pos
- value
+ ETH_ALEN
> 255)
882 retval
= add_tlv (LAN_NEIGHBOURS
, pos
- value
, value
, stream
);
883 if (retval
!= ISIS_OK
)
887 memcpy (pos
, snpa
, ETH_ALEN
);
891 return add_tlv (LAN_NEIGHBOURS
, pos
- value
, value
, stream
);
895 tlv_add_nlpid (struct nlpids
*nlpids
, struct stream
*stream
)
897 return add_tlv (PROTOCOLS_SUPPORTED
, nlpids
->count
, nlpids
->nlpids
, stream
);
901 tlv_add_authinfo (u_char auth_type
, u_char auth_len
, u_char
*auth_value
,
902 struct stream
*stream
)
907 memcpy (pos
, auth_value
, auth_len
);
909 return add_tlv (AUTH_INFO
, auth_len
+ 1, value
, stream
);
913 tlv_add_checksum (struct checksum
*checksum
, struct stream
*stream
)
917 return add_tlv (CHECKSUM
, pos
- value
, value
, stream
);
921 tlv_add_ip_addrs (struct list
*ip_addrs
, struct stream
*stream
)
923 struct listnode
*node
;
924 struct prefix_ipv4
*ipv4
;
928 for (ALL_LIST_ELEMENTS_RO (ip_addrs
, node
, ipv4
))
930 if (pos
- value
+ IPV4_MAX_BYTELEN
> 255)
932 /* RFC 1195 s4.2: only one tuple of 63 allowed. */
933 zlog_warn ("tlv_add_ip_addrs(): cutting off at 63 IP addresses");
936 *(u_int32_t
*) pos
= ipv4
->prefix
.s_addr
;
937 pos
+= IPV4_MAX_BYTELEN
;
940 return add_tlv (IPV4_ADDR
, pos
- value
, value
, stream
);
943 /* Used to add TLV containing just one IPv4 address - either IPv4 address TLV
944 * (in case of LSP) or TE router ID TLV. */
946 tlv_add_in_addr (struct in_addr
*addr
, struct stream
*stream
, u_char tag
)
951 memcpy (pos
, addr
, IPV4_MAX_BYTELEN
);
952 pos
+= IPV4_MAX_BYTELEN
;
954 return add_tlv (tag
, pos
- value
, value
, stream
);
958 tlv_add_dynamic_hostname (struct hostname
*hostname
, struct stream
*stream
)
960 return add_tlv (DYNAMIC_HOSTNAME
, hostname
->namelen
, hostname
->name
,
965 tlv_add_lsp_entries (struct list
*lsps
, struct stream
*stream
)
967 struct listnode
*node
;
968 struct isis_lsp
*lsp
;
973 for (ALL_LIST_ELEMENTS_RO (lsps
, node
, lsp
))
975 if (pos
- value
+ LSP_ENTRIES_LEN
> 255)
977 retval
= add_tlv (LSP_ENTRIES
, pos
- value
, value
, stream
);
978 if (retval
!= ISIS_OK
)
982 *((u_int16_t
*) pos
) = lsp
->lsp_header
->rem_lifetime
;
984 memcpy (pos
, lsp
->lsp_header
->lsp_id
, ISIS_SYS_ID_LEN
+ 2);
985 pos
+= ISIS_SYS_ID_LEN
+ 2;
986 *((u_int32_t
*) pos
) = lsp
->lsp_header
->seq_num
;
988 *((u_int16_t
*) pos
) = lsp
->lsp_header
->checksum
;
992 return add_tlv (LSP_ENTRIES
, pos
- value
, value
, stream
);
996 tlv_add_ipv4_reachs (u_char tag
, struct list
*ipv4_reachs
, struct stream
*stream
)
998 struct listnode
*node
;
999 struct ipv4_reachability
*reach
;
1001 u_char
*pos
= value
;
1004 for (ALL_LIST_ELEMENTS_RO (ipv4_reachs
, node
, reach
))
1006 if (pos
- value
+ IPV4_REACH_LEN
> 255)
1009 add_tlv (tag
, pos
- value
, value
, stream
);
1010 if (retval
!= ISIS_OK
)
1014 *pos
= reach
->metrics
.metric_default
;
1016 *pos
= reach
->metrics
.metric_delay
;
1018 *pos
= reach
->metrics
.metric_expense
;
1020 *pos
= reach
->metrics
.metric_error
;
1022 *(u_int32_t
*) pos
= reach
->prefix
.s_addr
;
1023 pos
+= IPV4_MAX_BYTELEN
;
1024 *(u_int32_t
*) pos
= reach
->mask
.s_addr
;
1025 pos
+= IPV4_MAX_BYTELEN
;
1028 return add_tlv (tag
, pos
- value
, value
, stream
);
1032 tlv_add_ipv4_int_reachs (struct list
*ipv4_reachs
, struct stream
*stream
)
1034 return tlv_add_ipv4_reachs(IPV4_INT_REACHABILITY
, ipv4_reachs
, stream
);
1038 tlv_add_ipv4_ext_reachs (struct list
*ipv4_reachs
, struct stream
*stream
)
1040 return tlv_add_ipv4_reachs(IPV4_EXT_REACHABILITY
, ipv4_reachs
, stream
);
1045 tlv_add_te_ipv4_reachs (struct list
*te_ipv4_reachs
, struct stream
*stream
)
1047 struct listnode
*node
;
1048 struct te_ipv4_reachability
*te_reach
;
1050 u_char
*pos
= value
;
1054 for (ALL_LIST_ELEMENTS_RO (te_ipv4_reachs
, node
, te_reach
))
1056 prefix_size
= ((((te_reach
->control
& 0x3F) - 1) >> 3) + 1);
1058 if (pos
- value
+ (5 + prefix_size
) > 255)
1061 add_tlv (TE_IPV4_REACHABILITY
, pos
- value
, value
, stream
);
1062 if (retval
!= ISIS_OK
)
1066 *(u_int32_t
*) pos
= te_reach
->te_metric
;
1068 *pos
= te_reach
->control
;
1070 memcpy (pos
, &te_reach
->prefix_start
, prefix_size
);
1074 return add_tlv (TE_IPV4_REACHABILITY
, pos
- value
, value
, stream
);
1079 tlv_add_ipv6_addrs (struct list
*ipv6_addrs
, struct stream
*stream
)
1081 struct listnode
*node
;
1082 struct prefix_ipv6
*ipv6
;
1084 u_char
*pos
= value
;
1087 for (ALL_LIST_ELEMENTS_RO (ipv6_addrs
, node
, ipv6
))
1089 if (pos
- value
+ IPV6_MAX_BYTELEN
> 255)
1091 retval
= add_tlv (IPV6_ADDR
, pos
- value
, value
, stream
);
1092 if (retval
!= ISIS_OK
)
1096 memcpy (pos
, ipv6
->prefix
.s6_addr
, IPV6_MAX_BYTELEN
);
1097 pos
+= IPV6_MAX_BYTELEN
;
1100 return add_tlv (IPV6_ADDR
, pos
- value
, value
, stream
);
1104 tlv_add_ipv6_reachs (struct list
*ipv6_reachs
, struct stream
*stream
)
1106 struct listnode
*node
;
1107 struct ipv6_reachability
*ip6reach
;
1109 u_char
*pos
= value
;
1110 int retval
, prefix_octets
;
1112 for (ALL_LIST_ELEMENTS_RO (ipv6_reachs
, node
, ip6reach
))
1114 if (pos
- value
+ IPV6_MAX_BYTELEN
+ 6 > 255)
1116 retval
= add_tlv (IPV6_REACHABILITY
, pos
- value
, value
, stream
);
1117 if (retval
!= ISIS_OK
)
1121 *(uint32_t *) pos
= ip6reach
->metric
;
1123 *pos
= ip6reach
->control_info
;
1125 prefix_octets
= ((ip6reach
->prefix_len
+ 7) / 8);
1126 *pos
= ip6reach
->prefix_len
;
1128 memcpy (pos
, ip6reach
->prefix
, prefix_octets
);
1129 pos
+= prefix_octets
;
1132 return add_tlv (IPV6_REACHABILITY
, pos
- value
, value
, stream
);
1134 #endif /* HAVE_IPV6 */
1137 tlv_add_padding (struct stream
*stream
)
1139 int fullpads
, i
, left
;
1142 * How many times can we add full padding ?
1144 fullpads
= (stream_get_size (stream
) - stream_get_endp (stream
)) / 257;
1145 for (i
= 0; i
< fullpads
; i
++)
1147 if (!stream_putc (stream
, (u_char
) PADDING
)) /* TAG */
1149 if (!stream_putc (stream
, (u_char
) 255)) /* LENGHT */
1151 stream_put (stream
, NULL
, 255); /* zero padding */
1154 left
= stream_get_size (stream
) - stream_get_endp (stream
);
1161 stream_putc (stream
, PADDING
);
1162 stream_putc (stream
, 0);
1166 stream_putc (stream
, PADDING
);
1167 stream_putc (stream
, left
- 2);
1168 stream_put (stream
, NULL
, left
-2);
1173 zlog_warn ("tlv_add_padding(): no room for tlv");
1174 return ISIS_WARNING
;