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"
45 #include "isisd/isis_te.h"
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
60 free_tlvs (struct tlvs *tlvs)
63 list_delete (tlvs->area_addrs);
65 list_delete (tlvs->is_neighs);
66 if (tlvs->te_is_neighs)
67 list_delete (tlvs->te_is_neighs);
69 list_delete (tlvs->es_neighs);
70 if (tlvs->lsp_entries)
71 list_delete (tlvs->lsp_entries);
72 if (tlvs->prefix_neighs)
73 list_delete (tlvs->prefix_neighs);
75 list_delete (tlvs->lan_neighs);
77 list_delete (tlvs->ipv4_addrs);
78 if (tlvs->ipv4_int_reachs)
79 list_delete (tlvs->ipv4_int_reachs);
80 if (tlvs->ipv4_ext_reachs)
81 list_delete (tlvs->ipv4_ext_reachs);
82 if (tlvs->te_ipv4_reachs)
83 list_delete (tlvs->te_ipv4_reachs);
86 list_delete (tlvs->ipv6_addrs);
87 if (tlvs->ipv6_reachs)
88 list_delete (tlvs->ipv6_reachs);
89 #endif /* HAVE_IPV6 */
91 memset (tlvs, 0, sizeof (struct tlvs));
97 * Parses the tlvs found in the variant length part of the PDU.
98 * Caller tells with flags in "expected" which TLV's it is interested in.
101 parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
102 u_int32_t * found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset)
105 struct lan_neigh *lan_nei;
106 struct area_addr *area_addr;
107 struct is_neigh *is_nei;
108 struct te_is_neigh *te_is_nei;
109 struct es_neigh *es_nei;
110 struct lsp_entry *lsp_entry;
111 struct in_addr *ipv4_addr;
112 struct ipv4_reachability *ipv4_reach;
113 struct te_ipv4_reachability *te_ipv4_reach;
115 struct in6_addr *ipv6_addr;
116 struct ipv6_reachability *ipv6_reach;
118 #endif /* HAVE_IPV6 */
119 int value_len, retval = ISIS_OK;
120 u_char *start = stream, *pnt = stream, *endpnt;
123 memset (tlvs, 0, sizeof (struct tlvs));
125 while (pnt < stream + size - 2)
131 if (pnt + length > stream + size)
133 zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet "
134 "boundaries", areatag, type, length);
135 retval = ISIS_WARNING;
141 /* +-------+-------+-------+-------+-------+-------+-------+-------+
143 * +-------+-------+-------+-------+-------+-------+-------+-------+
145 * +-------+-------+-------+-------+-------+-------+-------+-------+
148 *found |= TLVFLAG_AREA_ADDRS;
149 #ifdef EXTREME_TLV_DEBUG
150 zlog_debug ("TLV Area Adresses len %d", length);
151 #endif /* EXTREME_TLV_DEBUG */
152 if (*expected & TLVFLAG_AREA_ADDRS)
154 while (length > value_len)
156 area_addr = (struct area_addr *) pnt;
157 value_len += area_addr->addr_len + 1;
158 pnt += area_addr->addr_len + 1;
159 if (!tlvs->area_addrs)
160 tlvs->area_addrs = list_new ();
161 listnode_add (tlvs->area_addrs, area_addr);
171 *found |= TLVFLAG_IS_NEIGHS;
172 #ifdef EXTREME_TLV_DEBUG
173 zlog_debug ("ISIS-TLV (%s): IS Neighbours length %d",
175 #endif /* EXTREME_TLV_DEBUG */
176 if (TLVFLAG_IS_NEIGHS & *expected)
178 /* +-------+-------+-------+-------+-------+-------+-------+-------+
180 * +-------+-------+-------+-------+-------+-------+-------+-------+
184 /* +-------+-------+-------+-------+-------+-------+-------+-------+
185 * | 0 | I/E | Default Metric |
186 * +-------+-------+-------+-------+-------+-------+-------+-------+
187 * | S | I/E | Delay Metric |
188 * +-------+-------+-------+-------+-------+-------+-------+-------+
189 * | S | I/E | Expense Metric |
190 * +-------+-------+-------+-------+-------+-------+-------+-------+
191 * | S | I/E | Error Metric |
192 * +-------+-------+-------+-------+-------+-------+-------+-------+
194 * +---------------------------------------------------------------+
197 while (length > value_len)
199 is_nei = (struct is_neigh *) pnt;
200 value_len += 4 + ISIS_SYS_ID_LEN + 1;
201 pnt += 4 + ISIS_SYS_ID_LEN + 1;
202 if (!tlvs->is_neighs)
203 tlvs->is_neighs = list_new ();
204 listnode_add (tlvs->is_neighs, is_nei);
213 case TE_IS_NEIGHBOURS:
214 /* +-------+-------+-------+-------+-------+-------+-------+-------+
216 * +---------------------------------------------------------------+
218 * +---------------------------------------------------------------+
219 * | SubTLVs Length | 1
220 * +---------------------------------------------------------------+
223 *found |= TLVFLAG_TE_IS_NEIGHS;
224 #ifdef EXTREME_TLV_DEBUG
225 zlog_debug ("ISIS-TLV (%s): Extended IS Neighbours length %d",
227 #endif /* EXTREME_TLV_DEBUG */
228 if (TLVFLAG_TE_IS_NEIGHS & *expected)
230 while (length > value_len)
232 te_is_nei = (struct te_is_neigh *) pnt;
233 value_len += IS_NEIGHBOURS_LEN;
234 pnt += IS_NEIGHBOURS_LEN;
235 /* FIXME - subtlvs are handled here, for now we skip */
236 /* FIXME: All TE SubTLVs are not necessary present in LSP PDU. */
237 /* So, it must be copied in a new te_is_neigh structure */
238 /* rather than just initialize pointer to the original LSP PDU */
239 /* to avoid consider the rest of lspdu as subTLVs or buffer overflow */
240 if (IS_MPLS_TE(isisMplsTE))
242 struct te_is_neigh *new = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct te_is_neigh));
243 memcpy(new->neigh_id, te_is_nei->neigh_id, ISIS_SYS_ID_LEN + 1);
244 memcpy(new->te_metric, te_is_nei->te_metric, 3);
245 new->sub_tlvs_length = te_is_nei->sub_tlvs_length;
246 memcpy(new->sub_tlvs, pnt, te_is_nei->sub_tlvs_length);
249 /* Skip SUB TLVs payload */
250 value_len += te_is_nei->sub_tlvs_length;
251 pnt += te_is_nei->sub_tlvs_length;
253 if (!tlvs->te_is_neighs)
254 tlvs->te_is_neighs = list_new ();
255 listnode_add (tlvs->te_is_neighs, te_is_nei);
265 /* +-------+-------+-------+-------+-------+-------+-------+-------+
266 * | 0 | I/E | Default Metric |
267 * +-------+-------+-------+-------+-------+-------+-------+-------+
268 * | S | I/E | Delay Metric |
269 * +-------+-------+-------+-------+-------+-------+-------+-------+
270 * | S | I/E | Expense Metric |
271 * +-------+-------+-------+-------+-------+-------+-------+-------+
272 * | S | I/E | Error Metric |
273 * +-------+-------+-------+-------+-------+-------+-------+-------+
275 * +---------------------------------------------------------------+
277 * +---------------------------------------------------------------+
280 #ifdef EXTREME_TLV_DEBUG
281 zlog_debug ("ISIS-TLV (%s): ES Neighbours length %d",
283 #endif /* EXTREME_TLV_DEBUG */
284 *found |= TLVFLAG_ES_NEIGHS;
285 if (*expected & TLVFLAG_ES_NEIGHS)
287 es_nei = (struct es_neigh *) pnt;
290 while (length > value_len)
292 /* FIXME FIXME FIXME - add to the list */
293 /* sys_id->id = pnt; */
294 value_len += ISIS_SYS_ID_LEN;
295 pnt += ISIS_SYS_ID_LEN;
296 /* if (!es_nei->neigh_ids) es_nei->neigh_ids = sysid; */
298 if (!tlvs->es_neighs)
299 tlvs->es_neighs = list_new ();
300 listnode_add (tlvs->es_neighs, es_nei);
309 /* +-------+-------+-------+-------+-------+-------+-------+-------+
311 * +-------+-------+-------+-------+-------+-------+-------+-------+
314 *found |= TLVFLAG_LAN_NEIGHS;
315 #ifdef EXTREME_TLV_DEBUG
316 zlog_debug ("ISIS-TLV (%s): LAN Neigbours length %d",
318 #endif /* EXTREME_TLV_DEBUG */
319 if (TLVFLAG_LAN_NEIGHS & *expected)
321 while (length > value_len)
323 lan_nei = (struct lan_neigh *) pnt;
324 if (!tlvs->lan_neighs)
325 tlvs->lan_neighs = list_new ();
326 listnode_add (tlvs->lan_neighs, lan_nei);
327 value_len += ETH_ALEN;
338 #ifdef EXTREME_TLV_DEBUG
339 zlog_debug ("TLV padding %d", length);
340 #endif /* EXTREME_TLV_DEBUG */
345 /* +-------+-------+-------+-------+-------+-------+-------+-------+
346 * | Remaining Lifetime | 2
347 * +-------+-------+-------+-------+-------+-------+-------+-------+
349 * +-------+-------+-------+-------+-------+-------+-------+-------+
350 * | LSP Sequence Number |Â 4
351 * +-------+-------+-------+-------+-------+-------+-------+-------+
353 * +-------+-------+-------+-------+-------+-------+-------+-------+
355 #ifdef EXTREME_TLV_DEBUG
356 zlog_debug ("ISIS-TLV (%s): LSP Entries length %d", areatag, length);
357 #endif /* EXTREME_TLV_DEBUG */
358 *found |= TLVFLAG_LSP_ENTRIES;
359 if (TLVFLAG_LSP_ENTRIES & *expected)
361 while (length > value_len)
363 lsp_entry = (struct lsp_entry *) pnt;
364 value_len += 10 + ISIS_SYS_ID_LEN;
365 pnt += 10 + ISIS_SYS_ID_LEN;
366 if (!tlvs->lsp_entries)
367 tlvs->lsp_entries = list_new ();
368 listnode_add (tlvs->lsp_entries, lsp_entry);
378 /* +-------+-------+-------+-------+-------+-------+-------+-------+
379 * | 16 bit fletcher CHECKSUM |
380 * +-------+-------+-------+-------+-------+-------+-------+-------+
383 *found |= TLVFLAG_CHECKSUM;
384 #ifdef EXTREME_TLV_DEBUG
385 zlog_debug ("ISIS-TLV (%s): Checksum length %d", areatag, length);
386 #endif /* EXTREME_TLV_DEBUG */
387 if (*expected & TLVFLAG_CHECKSUM)
389 tlvs->checksum = (struct checksum *) pnt;
394 case PROTOCOLS_SUPPORTED:
395 /* +-------+-------+-------+-------+-------+-------+-------+-------+
397 * +-------+-------+-------+-------+-------+-------+-------+-------+
400 *found |= TLVFLAG_NLPID;
401 #ifdef EXTREME_TLV_DEBUG
402 zlog_debug ("ISIS-TLV (%s): Protocols Supported length %d",
404 #endif /* EXTREME_TLV_DEBUG */
405 if (*expected & TLVFLAG_NLPID)
407 tlvs->nlpids = (struct nlpids *) (pnt - 1);
413 /* +-------+-------+-------+-------+-------+-------+-------+-------+
414 * + IP version 4 address + 4
415 * +-------+-------+-------+-------+-------+-------+-------+-------+
418 *found |= TLVFLAG_IPV4_ADDR;
419 #ifdef EXTREME_TLV_DEBUG
420 zlog_debug ("ISIS-TLV (%s): IPv4 Address length %d",
422 #endif /* EXTREME_TLV_DEBUG */
423 if (*expected & TLVFLAG_IPV4_ADDR)
425 while (length > value_len)
427 ipv4_addr = (struct in_addr *) pnt;
428 #ifdef EXTREME_TLV_DEBUG
429 zlog_debug ("ISIS-TLV (%s) : IP ADDR %s, pnt %p", areatag,
430 inet_ntoa (*ipv4_addr), pnt);
431 #endif /* EXTREME_TLV_DEBUG */
432 if (!tlvs->ipv4_addrs)
433 tlvs->ipv4_addrs = list_new ();
434 listnode_add (tlvs->ipv4_addrs, ipv4_addr);
446 *found |= TLVFLAG_AUTH_INFO;
447 #ifdef EXTREME_TLV_DEBUG
448 zlog_debug ("ISIS-TLV (%s): IS-IS Authentication Information",
451 if (*expected & TLVFLAG_AUTH_INFO)
453 tlvs->auth_info.type = *pnt;
456 zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) "
457 "incorrect.", areatag, type, length);
461 tlvs->auth_info.len = length;
463 memcpy (tlvs->auth_info.passwd, pnt, length);
464 /* Return the authentication tlv pos for later computation
465 * of MD5 (RFC 5304, 2)
468 *auth_tlv_offset += (pnt - start - 3);
477 case DYNAMIC_HOSTNAME:
478 *found |= TLVFLAG_DYN_HOSTNAME;
479 #ifdef EXTREME_TLV_DEBUG
480 zlog_debug ("ISIS-TLV (%s): Dynamic Hostname length %d",
482 #endif /* EXTREME_TLV_DEBUG */
483 if (*expected & TLVFLAG_DYN_HOSTNAME)
485 /* the length is also included in the pointed struct */
486 tlvs->hostname = (struct hostname *) (pnt - 1);
492 /* +---------------------------------------------------------------+
494 * +---------------------------------------------------------------+
496 *found |= TLVFLAG_TE_ROUTER_ID;
497 #ifdef EXTREME_TLV_DEBUG
498 zlog_debug ("ISIS-TLV (%s): TE Router ID %d", areatag, length);
499 #endif /* EXTREME_TLV_DEBUG */
500 if (*expected & TLVFLAG_TE_ROUTER_ID)
501 tlvs->router_id = (struct te_router_id *) (pnt);
505 case IPV4_INT_REACHABILITY:
506 /* +-------+-------+-------+-------+-------+-------+-------+-------+
507 * | 0 | I/E | Default Metric | 1
508 * +-------+-------+-------+-------+-------+-------+-------+-------+
509 * | S | I/E | Delay Metric | 1
510 * +-------+-------+-------+-------+-------+-------+-------+-------+
511 * | S | I/E | Expense Metric | 1
512 * +-------+-------+-------+-------+-------+-------+-------+-------+
513 * | S | I/E | Error Metric | 1
514 * +-------+-------+-------+-------+-------+-------+-------+-------+
516 * +---------------------------------------------------------------+
518 * +---------------------------------------------------------------+
521 *found |= TLVFLAG_IPV4_INT_REACHABILITY;
522 #ifdef EXTREME_TLV_DEBUG
523 zlog_debug ("ISIS-TLV (%s): IPv4 internal Reachability length %d",
525 #endif /* EXTREME_TLV_DEBUG */
526 if (*expected & TLVFLAG_IPV4_INT_REACHABILITY)
528 while (length > value_len)
530 ipv4_reach = (struct ipv4_reachability *) pnt;
531 if (!tlvs->ipv4_int_reachs)
532 tlvs->ipv4_int_reachs = list_new ();
533 listnode_add (tlvs->ipv4_int_reachs, ipv4_reach);
544 case IPV4_EXT_REACHABILITY:
545 /* +-------+-------+-------+-------+-------+-------+-------+-------+
546 * | 0 | I/E | Default Metric | 1
547 * +-------+-------+-------+-------+-------+-------+-------+-------+
548 * | S | I/E | Delay Metric | 1
549 * +-------+-------+-------+-------+-------+-------+-------+-------+
550 * | S | I/E | Expense Metric | 1
551 * +-------+-------+-------+-------+-------+-------+-------+-------+
552 * | S | I/E | Error Metric | 1
553 * +-------+-------+-------+-------+-------+-------+-------+-------+
555 * +---------------------------------------------------------------+
557 * +---------------------------------------------------------------+
560 *found |= TLVFLAG_IPV4_EXT_REACHABILITY;
561 #ifdef EXTREME_TLV_DEBUG
562 zlog_debug ("ISIS-TLV (%s): IPv4 external Reachability length %d",
564 #endif /* EXTREME_TLV_DEBUG */
565 if (*expected & TLVFLAG_IPV4_EXT_REACHABILITY)
567 while (length > value_len)
569 ipv4_reach = (struct ipv4_reachability *) pnt;
570 if (!tlvs->ipv4_ext_reachs)
571 tlvs->ipv4_ext_reachs = list_new ();
572 listnode_add (tlvs->ipv4_ext_reachs, ipv4_reach);
583 case TE_IPV4_REACHABILITY:
584 /* +-------+-------+-------+-------+-------+-------+-------+-------+
586 * +-------+-------+-------+-------+-------+-------+-------+-------+
587 * | U/D | sTLV? | Prefix Mask Len | 1
588 * +-------+-------+-------+-------+-------+-------+-------+-------+
590 * +---------------------------------------------------------------+
592 * +---------------------------------------------------------------+
595 *found |= TLVFLAG_TE_IPV4_REACHABILITY;
596 #ifdef EXTREME_TLV_DEBUG
597 zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d",
599 #endif /* EXTREME_TLV_DEBUG */
600 endpnt = pnt + length;
601 if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
603 while (length > value_len)
605 te_ipv4_reach = (struct te_ipv4_reachability *) pnt;
606 if ((te_ipv4_reach->control & 0x3F) > IPV4_MAX_BITLEN)
608 zlog_warn ("ISIS-TLV (%s): invalid IPv4 extended reach"
609 "ability prefix length %d", areatag,
610 te_ipv4_reach->control & 0x3F);
611 retval = ISIS_WARNING;
614 if (!tlvs->te_ipv4_reachs)
615 tlvs->te_ipv4_reachs = list_new ();
616 listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach);
617 /* this trickery is permitable since no subtlvs are defined */
618 value_len += 5 + ((te_ipv4_reach->control & 0x3F) ?
619 ((((te_ipv4_reach->control & 0x3F) -
621 pnt += 5 + ((te_ipv4_reach->control & 0x3F) ?
622 ((((te_ipv4_reach->control & 0x3F) - 1) >> 3) + 1) : 0);
631 /* +-------+-------+-------+-------+-------+-------+-------+-------+
632 * + IP version 6 address + 16
633 * +-------+-------+-------+-------+-------+-------+-------+-------+
636 *found |= TLVFLAG_IPV6_ADDR;
637 #ifdef EXTREME_TLV_DEBUG
638 zlog_debug ("ISIS-TLV (%s): IPv6 Address length %d",
640 #endif /* EXTREME_TLV_DEBUG */
641 if (*expected & TLVFLAG_IPV6_ADDR)
643 while (length > value_len)
645 ipv6_addr = (struct in6_addr *) pnt;
646 if (!tlvs->ipv6_addrs)
647 tlvs->ipv6_addrs = list_new ();
648 listnode_add (tlvs->ipv6_addrs, ipv6_addr);
659 case IPV6_REACHABILITY:
660 /* +-------+-------+-------+-------+-------+-------+-------+-------+
661 * | Default Metric | 4
662 * +-------+-------+-------+-------+-------+-------+-------+-------+
663 * | Control Informantion |
664 * +---------------------------------------------------------------+
665 * | IPv6 Prefix Length |--+
666 * +---------------------------------------------------------------+ |
668 * +---------------------------------------------------------------+
670 *found |= TLVFLAG_IPV6_REACHABILITY;
671 endpnt = pnt + length;
673 if (*expected & TLVFLAG_IPV6_REACHABILITY)
675 while (length > value_len)
677 ipv6_reach = (struct ipv6_reachability *) pnt;
678 if (ipv6_reach->prefix_len > IPV6_MAX_BITLEN)
680 zlog_warn ("ISIS-TLV (%s): invalid IPv6 extended reach"
681 "ability prefix length %d", areatag,
682 ipv6_reach->prefix_len);
683 retval = ISIS_WARNING;
687 prefix_octets = ((ipv6_reach->prefix_len + 7) / 8);
688 value_len += prefix_octets + 6;
689 pnt += prefix_octets + 6;
690 /* FIXME: sub-tlvs */
691 if (!tlvs->ipv6_reachs)
692 tlvs->ipv6_reachs = list_new ();
693 listnode_add (tlvs->ipv6_reachs, ipv6_reach);
699 #endif /* HAVE_IPV6 */
702 /* +---------------------------------------------------------------+
703 * | Adjacency state | 1
704 * +---------------------------------------------------------------+
705 * | Extended Local Circuit ID | 4
706 * +---------------------------------------------------------------+
707 * | Neighbor System ID (If known) | 0-8
709 * +---------------------------------------------------------------+
710 * | Neighbor Local Circuit ID (If known) | 4
711 * +---------------------------------------------------------------+
713 *found |= TLVFLAG_3WAY_HELLO;
714 if (*expected & TLVFLAG_3WAY_HELLO)
716 while (length > value_len)
718 /* FIXME: make this work */
719 /* Adjacency State (one octet):
723 Extended Local Circuit ID (four octets)
724 Neighbor System ID if known (zero to eight octets)
725 Neighbor Extended Local Circuit ID (four octets, if Neighbor
726 System ID is present) */
737 case GRACEFUL_RESTART:
738 /* +-------+-------+-------+-------+-------+-------+-------+-------+
739 * | Reserved | SA | RA | RR | 1
740 * +-------+-------+-------+-------+-------+-------+-------+-------+
741 * | Remaining Time | 2
742 * +---------------------------------------------------------------+
743 * | Restarting Neighbor ID (If known) | 0-8
744 * +---------------------------------------------------------------+
746 *found |= TLVFLAG_GRACEFUL_RESTART;
747 if (*expected & TLVFLAG_GRACEFUL_RESTART)
749 /* FIXME: make this work */
755 zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
756 areatag, type, length);
767 add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
769 if ((stream_get_size (stream) - stream_get_endp (stream)) <
770 (((unsigned)len) + 2))
772 zlog_warn ("No room for TLV of type %d "
773 "(total size %d available %d required %d)",
774 tag, (int)stream_get_size (stream),
775 (int)(stream_get_size (stream) - stream_get_endp (stream)),
780 stream_putc (stream, tag); /* TAG */
781 stream_putc (stream, len); /* LENGTH */
782 stream_put (stream, value, (int) len); /* VALUE */
785 zlog_debug ("Added TLV %d len %d", tag, len);
786 #endif /* EXTREME DEBUG */
791 tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
793 struct listnode *node;
794 struct area_addr *area_addr;
799 for (ALL_LIST_ELEMENTS_RO (area_addrs, node, area_addr))
801 if (pos - value + area_addr->addr_len > 255)
803 *pos = area_addr->addr_len;
805 memcpy (pos, area_addr->area_addr, (int) area_addr->addr_len);
806 pos += area_addr->addr_len;
809 return add_tlv (AREA_ADDRESSES, pos - value, value, stream);
812 zlog_warn ("tlv_add_area_addrs(): TLV longer than 255");
817 tlv_add_is_neighs (struct list *is_neighs, struct stream *stream)
819 struct listnode *node;
820 struct is_neigh *is_neigh;
825 *pos = 0; /*is_neigh->virtual; */
828 for (ALL_LIST_ELEMENTS_RO (is_neighs, node, is_neigh))
830 if (pos - value + IS_NEIGHBOURS_LEN > 255)
832 retval = add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
833 if (retval != ISIS_OK)
837 *pos = is_neigh->metrics.metric_default;
839 *pos = is_neigh->metrics.metric_delay;
841 *pos = is_neigh->metrics.metric_expense;
843 *pos = is_neigh->metrics.metric_error;
845 memcpy (pos, is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
846 pos += ISIS_SYS_ID_LEN + 1;
849 return add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
853 tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
855 struct listnode *node;
856 struct te_is_neigh *te_is_neigh;
861 for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh))
863 /* FIXME: Check if Total SubTLVs size doesn't exceed 255 */
864 if (pos - value + IS_NEIGHBOURS_LEN + te_is_neigh->sub_tlvs_length > 255)
866 retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
867 if (retval != ISIS_OK)
872 memcpy (pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
873 pos += ISIS_SYS_ID_LEN + 1;
874 memcpy (pos, te_is_neigh->te_metric, 3);
876 /* Set the total size of Sub TLVs */
877 *pos = te_is_neigh->sub_tlvs_length;
879 /* Copy Sub TLVs if any */
880 if (te_is_neigh->sub_tlvs_length > 0)
882 memcpy (pos, te_is_neigh->sub_tlvs, te_is_neigh->sub_tlvs_length);
883 pos += te_is_neigh->sub_tlvs_length;
887 return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
891 tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream)
893 struct listnode *node;
899 for (ALL_LIST_ELEMENTS_RO (lan_neighs, node, snpa))
901 if (pos - value + ETH_ALEN > 255)
903 retval = add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
904 if (retval != ISIS_OK)
908 memcpy (pos, snpa, ETH_ALEN);
912 return add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
916 tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream)
918 return add_tlv (PROTOCOLS_SUPPORTED, nlpids->count, nlpids->nlpids, stream);
922 tlv_add_authinfo (u_char auth_type, u_char auth_len, u_char *auth_value,
923 struct stream *stream)
928 memcpy (pos, auth_value, auth_len);
930 return add_tlv (AUTH_INFO, auth_len + 1, value, stream);
934 tlv_add_checksum (struct checksum *checksum, struct stream *stream)
938 return add_tlv (CHECKSUM, pos - value, value, stream);
942 tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream)
944 struct listnode *node;
945 struct prefix_ipv4 *ipv4;
949 for (ALL_LIST_ELEMENTS_RO (ip_addrs, node, ipv4))
951 if (pos - value + IPV4_MAX_BYTELEN > 255)
953 /* RFC 1195 s4.2: only one tuple of 63 allowed. */
954 zlog_warn ("tlv_add_ip_addrs(): cutting off at 63 IP addresses");
957 *(u_int32_t *) pos = ipv4->prefix.s_addr;
958 pos += IPV4_MAX_BYTELEN;
961 return add_tlv (IPV4_ADDR, pos - value, value, stream);
964 /* Used to add TLV containing just one IPv4 address - either IPv4 address TLV
965 * (in case of LSP) or TE router ID TLV. */
967 tlv_add_in_addr (struct in_addr *addr, struct stream *stream, u_char tag)
972 memcpy (pos, addr, IPV4_MAX_BYTELEN);
973 pos += IPV4_MAX_BYTELEN;
975 return add_tlv (tag, pos - value, value, stream);
979 tlv_add_dynamic_hostname (struct hostname *hostname, struct stream *stream)
981 return add_tlv (DYNAMIC_HOSTNAME, hostname->namelen, hostname->name,
986 tlv_add_lsp_entries (struct list *lsps, struct stream *stream)
988 struct listnode *node;
989 struct isis_lsp *lsp;
994 for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp))
996 if (pos - value + LSP_ENTRIES_LEN > 255)
998 retval = add_tlv (LSP_ENTRIES, pos - value, value, stream);
999 if (retval != ISIS_OK)
1003 *((u_int16_t *) pos) = lsp->lsp_header->rem_lifetime;
1005 memcpy (pos, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
1006 pos += ISIS_SYS_ID_LEN + 2;
1007 *((u_int32_t *) pos) = lsp->lsp_header->seq_num;
1009 *((u_int16_t *) pos) = lsp->lsp_header->checksum;
1013 return add_tlv (LSP_ENTRIES, pos - value, value, stream);
1017 tlv_add_ipv4_reachs (u_char tag, struct list *ipv4_reachs, struct stream *stream)
1019 struct listnode *node;
1020 struct ipv4_reachability *reach;
1022 u_char *pos = value;
1025 for (ALL_LIST_ELEMENTS_RO (ipv4_reachs, node, reach))
1027 if (pos - value + IPV4_REACH_LEN > 255)
1030 add_tlv (tag, pos - value, value, stream);
1031 if (retval != ISIS_OK)
1035 *pos = reach->metrics.metric_default;
1037 *pos = reach->metrics.metric_delay;
1039 *pos = reach->metrics.metric_expense;
1041 *pos = reach->metrics.metric_error;
1043 *(u_int32_t *) pos = reach->prefix.s_addr;
1044 pos += IPV4_MAX_BYTELEN;
1045 *(u_int32_t *) pos = reach->mask.s_addr;
1046 pos += IPV4_MAX_BYTELEN;
1049 return add_tlv (tag, pos - value, value, stream);
1053 tlv_add_ipv4_int_reachs (struct list *ipv4_reachs, struct stream *stream)
1055 return tlv_add_ipv4_reachs(IPV4_INT_REACHABILITY, ipv4_reachs, stream);
1059 tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream)
1061 return tlv_add_ipv4_reachs(IPV4_EXT_REACHABILITY, ipv4_reachs, stream);
1066 tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream)
1068 struct listnode *node;
1069 struct te_ipv4_reachability *te_reach;
1071 u_char *pos = value;
1075 for (ALL_LIST_ELEMENTS_RO (te_ipv4_reachs, node, te_reach))
1077 prefix_size = ((((te_reach->control & 0x3F) - 1) >> 3) + 1);
1079 if (pos - value + (5 + prefix_size) > 255)
1082 add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
1083 if (retval != ISIS_OK)
1087 *(u_int32_t *) pos = te_reach->te_metric;
1089 *pos = te_reach->control;
1091 memcpy (pos, &te_reach->prefix_start, prefix_size);
1095 return add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
1100 tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream)
1102 struct listnode *node;
1103 struct prefix_ipv6 *ipv6;
1105 u_char *pos = value;
1108 for (ALL_LIST_ELEMENTS_RO (ipv6_addrs, node, ipv6))
1110 if (pos - value + IPV6_MAX_BYTELEN > 255)
1112 retval = add_tlv (IPV6_ADDR, pos - value, value, stream);
1113 if (retval != ISIS_OK)
1117 memcpy (pos, ipv6->prefix.s6_addr, IPV6_MAX_BYTELEN);
1118 pos += IPV6_MAX_BYTELEN;
1121 return add_tlv (IPV6_ADDR, pos - value, value, stream);
1125 tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream)
1127 struct listnode *node;
1128 struct ipv6_reachability *ip6reach;
1130 u_char *pos = value;
1131 int retval, prefix_octets;
1133 for (ALL_LIST_ELEMENTS_RO (ipv6_reachs, node, ip6reach))
1135 if (pos - value + IPV6_MAX_BYTELEN + 6 > 255)
1137 retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
1138 if (retval != ISIS_OK)
1142 *(uint32_t *) pos = ip6reach->metric;
1144 *pos = ip6reach->control_info;
1146 prefix_octets = ((ip6reach->prefix_len + 7) / 8);
1147 *pos = ip6reach->prefix_len;
1149 memcpy (pos, ip6reach->prefix, prefix_octets);
1150 pos += prefix_octets;
1153 return add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
1155 #endif /* HAVE_IPV6 */
1158 tlv_add_padding (struct stream *stream)
1160 int fullpads, i, left;
1163 * How many times can we add full padding ?
1165 fullpads = (stream_get_size (stream) - stream_get_endp (stream)) / 257;
1166 for (i = 0; i < fullpads; i++)
1168 if (!stream_putc (stream, (u_char) PADDING)) /* TAG */
1170 if (!stream_putc (stream, (u_char) 255)) /* LENGHT */
1172 stream_put (stream, NULL, 255); /* zero padding */
1175 left = stream_get_size (stream) - stream_get_endp (stream);
1182 stream_putc (stream, PADDING);
1183 stream_putc (stream, 0);
1187 stream_putc (stream, PADDING);
1188 stream_putc (stream, left - 2);
1189 stream_put (stream, NULL, left-2);
1194 zlog_warn ("tlv_add_padding(): no room for tlv");
1195 return ISIS_WARNING;