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
);
85 list_delete (tlvs
->ipv6_addrs
);
86 if (tlvs
->ipv6_reachs
)
87 list_delete (tlvs
->ipv6_reachs
);
89 memset (tlvs
, 0, sizeof (struct tlvs
));
95 * Parses the tlvs found in the variant length part of the PDU.
96 * Caller tells with flags in "expected" which TLV's it is interested in.
99 parse_tlvs (char *areatag
, u_char
* stream
, int size
, u_int32_t
* expected
,
100 u_int32_t
* found
, struct tlvs
*tlvs
, u_int32_t
*auth_tlv_offset
)
103 struct lan_neigh
*lan_nei
;
104 struct area_addr
*area_addr
;
105 struct is_neigh
*is_nei
;
106 struct te_is_neigh
*te_is_nei
;
107 struct es_neigh
*es_nei
;
108 struct lsp_entry
*lsp_entry
;
109 struct in_addr
*ipv4_addr
;
110 struct ipv4_reachability
*ipv4_reach
;
111 struct te_ipv4_reachability
*te_ipv4_reach
;
112 struct in6_addr
*ipv6_addr
;
113 struct ipv6_reachability
*ipv6_reach
;
115 int value_len
, retval
= ISIS_OK
;
116 u_char
*start
= stream
, *pnt
= stream
, *endpnt
;
119 memset (tlvs
, 0, sizeof (struct tlvs
));
121 while (pnt
< stream
+ size
- 2)
127 if (pnt
+ length
> stream
+ size
)
129 zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet "
130 "boundaries", areatag
, type
, length
);
131 retval
= ISIS_WARNING
;
137 /* +-------+-------+-------+-------+-------+-------+-------+-------+
139 * +-------+-------+-------+-------+-------+-------+-------+-------+
141 * +-------+-------+-------+-------+-------+-------+-------+-------+
144 *found
|= TLVFLAG_AREA_ADDRS
;
145 #ifdef EXTREME_TLV_DEBUG
146 zlog_debug ("TLV Area Adresses len %d", length
);
147 #endif /* EXTREME_TLV_DEBUG */
148 if (*expected
& TLVFLAG_AREA_ADDRS
)
150 while (length
> value_len
)
152 area_addr
= (struct area_addr
*) pnt
;
153 value_len
+= area_addr
->addr_len
+ 1;
154 pnt
+= area_addr
->addr_len
+ 1;
155 if (!tlvs
->area_addrs
)
156 tlvs
->area_addrs
= list_new ();
157 listnode_add (tlvs
->area_addrs
, area_addr
);
167 *found
|= TLVFLAG_IS_NEIGHS
;
168 #ifdef EXTREME_TLV_DEBUG
169 zlog_debug ("ISIS-TLV (%s): IS Neighbours length %d",
171 #endif /* EXTREME_TLV_DEBUG */
172 if (TLVFLAG_IS_NEIGHS
& *expected
)
174 /* +-------+-------+-------+-------+-------+-------+-------+-------+
176 * +-------+-------+-------+-------+-------+-------+-------+-------+
180 /* +-------+-------+-------+-------+-------+-------+-------+-------+
181 * | 0 | I/E | Default Metric |
182 * +-------+-------+-------+-------+-------+-------+-------+-------+
183 * | S | I/E | Delay Metric |
184 * +-------+-------+-------+-------+-------+-------+-------+-------+
185 * | S | I/E | Expense Metric |
186 * +-------+-------+-------+-------+-------+-------+-------+-------+
187 * | S | I/E | Error Metric |
188 * +-------+-------+-------+-------+-------+-------+-------+-------+
190 * +---------------------------------------------------------------+
193 while (length
> value_len
)
195 is_nei
= (struct is_neigh
*) pnt
;
196 value_len
+= 4 + ISIS_SYS_ID_LEN
+ 1;
197 pnt
+= 4 + ISIS_SYS_ID_LEN
+ 1;
198 if (!tlvs
->is_neighs
)
199 tlvs
->is_neighs
= list_new ();
200 listnode_add (tlvs
->is_neighs
, is_nei
);
209 case TE_IS_NEIGHBOURS
:
210 /* +-------+-------+-------+-------+-------+-------+-------+-------+
212 * +---------------------------------------------------------------+
214 * +---------------------------------------------------------------+
215 * | SubTLVs Length | 1
216 * +---------------------------------------------------------------+
219 *found
|= TLVFLAG_TE_IS_NEIGHS
;
220 #ifdef EXTREME_TLV_DEBUG
221 zlog_debug ("ISIS-TLV (%s): Extended IS Neighbours length %d",
223 #endif /* EXTREME_TLV_DEBUG */
224 if (TLVFLAG_TE_IS_NEIGHS
& *expected
)
226 while (length
> value_len
)
228 te_is_nei
= (struct te_is_neigh
*) pnt
;
229 value_len
+= IS_NEIGHBOURS_LEN
;
230 pnt
+= IS_NEIGHBOURS_LEN
;
231 /* FIXME - subtlvs are handled here, for now we skip */
232 /* FIXME: All TE SubTLVs are not necessary present in LSP PDU. */
233 /* So, it must be copied in a new te_is_neigh structure */
234 /* rather than just initialize pointer to the original LSP PDU */
235 /* to avoid consider the rest of lspdu as subTLVs or buffer overflow */
236 if (IS_MPLS_TE(isisMplsTE
))
238 struct te_is_neigh
*new = XCALLOC(MTYPE_ISIS_TLV
, sizeof(struct te_is_neigh
));
239 memcpy(new->neigh_id
, te_is_nei
->neigh_id
, ISIS_SYS_ID_LEN
+ 1);
240 memcpy(new->te_metric
, te_is_nei
->te_metric
, 3);
241 new->sub_tlvs_length
= te_is_nei
->sub_tlvs_length
;
242 memcpy(new->sub_tlvs
, pnt
, te_is_nei
->sub_tlvs_length
);
245 /* Skip SUB TLVs payload */
246 value_len
+= te_is_nei
->sub_tlvs_length
;
247 pnt
+= te_is_nei
->sub_tlvs_length
;
249 if (!tlvs
->te_is_neighs
)
250 tlvs
->te_is_neighs
= list_new ();
251 listnode_add (tlvs
->te_is_neighs
, te_is_nei
);
261 /* +-------+-------+-------+-------+-------+-------+-------+-------+
262 * | 0 | I/E | Default Metric |
263 * +-------+-------+-------+-------+-------+-------+-------+-------+
264 * | S | I/E | Delay Metric |
265 * +-------+-------+-------+-------+-------+-------+-------+-------+
266 * | S | I/E | Expense Metric |
267 * +-------+-------+-------+-------+-------+-------+-------+-------+
268 * | S | I/E | Error Metric |
269 * +-------+-------+-------+-------+-------+-------+-------+-------+
271 * +---------------------------------------------------------------+
273 * +---------------------------------------------------------------+
276 #ifdef EXTREME_TLV_DEBUG
277 zlog_debug ("ISIS-TLV (%s): ES Neighbours length %d",
279 #endif /* EXTREME_TLV_DEBUG */
280 *found
|= TLVFLAG_ES_NEIGHS
;
281 if (*expected
& TLVFLAG_ES_NEIGHS
)
283 es_nei
= (struct es_neigh
*) pnt
;
286 while (length
> value_len
)
288 /* FIXME FIXME FIXME - add to the list */
289 /* sys_id->id = pnt; */
290 value_len
+= ISIS_SYS_ID_LEN
;
291 pnt
+= ISIS_SYS_ID_LEN
;
292 /* if (!es_nei->neigh_ids) es_nei->neigh_ids = sysid; */
294 if (!tlvs
->es_neighs
)
295 tlvs
->es_neighs
= list_new ();
296 listnode_add (tlvs
->es_neighs
, es_nei
);
305 /* +-------+-------+-------+-------+-------+-------+-------+-------+
307 * +-------+-------+-------+-------+-------+-------+-------+-------+
310 *found
|= TLVFLAG_LAN_NEIGHS
;
311 #ifdef EXTREME_TLV_DEBUG
312 zlog_debug ("ISIS-TLV (%s): LAN Neigbours length %d",
314 #endif /* EXTREME_TLV_DEBUG */
315 if (TLVFLAG_LAN_NEIGHS
& *expected
)
317 while (length
> value_len
)
319 lan_nei
= (struct lan_neigh
*) pnt
;
320 if (!tlvs
->lan_neighs
)
321 tlvs
->lan_neighs
= list_new ();
322 listnode_add (tlvs
->lan_neighs
, lan_nei
);
323 value_len
+= ETH_ALEN
;
334 #ifdef EXTREME_TLV_DEBUG
335 zlog_debug ("TLV padding %d", length
);
336 #endif /* EXTREME_TLV_DEBUG */
341 /* +-------+-------+-------+-------+-------+-------+-------+-------+
342 * | Remaining Lifetime | 2
343 * +-------+-------+-------+-------+-------+-------+-------+-------+
345 * +-------+-------+-------+-------+-------+-------+-------+-------+
346 * | LSP Sequence Number |Â 4
347 * +-------+-------+-------+-------+-------+-------+-------+-------+
349 * +-------+-------+-------+-------+-------+-------+-------+-------+
351 #ifdef EXTREME_TLV_DEBUG
352 zlog_debug ("ISIS-TLV (%s): LSP Entries length %d", areatag
, length
);
353 #endif /* EXTREME_TLV_DEBUG */
354 *found
|= TLVFLAG_LSP_ENTRIES
;
355 if (TLVFLAG_LSP_ENTRIES
& *expected
)
357 while (length
> value_len
)
359 lsp_entry
= (struct lsp_entry
*) pnt
;
360 value_len
+= 10 + ISIS_SYS_ID_LEN
;
361 pnt
+= 10 + ISIS_SYS_ID_LEN
;
362 if (!tlvs
->lsp_entries
)
363 tlvs
->lsp_entries
= list_new ();
364 listnode_add (tlvs
->lsp_entries
, lsp_entry
);
374 /* +-------+-------+-------+-------+-------+-------+-------+-------+
375 * | 16 bit fletcher CHECKSUM |
376 * +-------+-------+-------+-------+-------+-------+-------+-------+
379 *found
|= TLVFLAG_CHECKSUM
;
380 #ifdef EXTREME_TLV_DEBUG
381 zlog_debug ("ISIS-TLV (%s): Checksum length %d", areatag
, length
);
382 #endif /* EXTREME_TLV_DEBUG */
383 if (*expected
& TLVFLAG_CHECKSUM
)
385 tlvs
->checksum
= (struct checksum
*) pnt
;
390 case PROTOCOLS_SUPPORTED
:
391 /* +-------+-------+-------+-------+-------+-------+-------+-------+
393 * +-------+-------+-------+-------+-------+-------+-------+-------+
396 *found
|= TLVFLAG_NLPID
;
397 #ifdef EXTREME_TLV_DEBUG
398 zlog_debug ("ISIS-TLV (%s): Protocols Supported length %d",
400 #endif /* EXTREME_TLV_DEBUG */
401 if (*expected
& TLVFLAG_NLPID
)
403 tlvs
->nlpids
= (struct nlpids
*) (pnt
- 1);
409 /* +-------+-------+-------+-------+-------+-------+-------+-------+
410 * + IP version 4 address + 4
411 * +-------+-------+-------+-------+-------+-------+-------+-------+
414 *found
|= TLVFLAG_IPV4_ADDR
;
415 #ifdef EXTREME_TLV_DEBUG
416 zlog_debug ("ISIS-TLV (%s): IPv4 Address length %d",
418 #endif /* EXTREME_TLV_DEBUG */
419 if (*expected
& TLVFLAG_IPV4_ADDR
)
421 while (length
> value_len
)
423 ipv4_addr
= (struct in_addr
*) pnt
;
424 #ifdef EXTREME_TLV_DEBUG
425 zlog_debug ("ISIS-TLV (%s) : IP ADDR %s, pnt %p", areatag
,
426 inet_ntoa (*ipv4_addr
), pnt
);
427 #endif /* EXTREME_TLV_DEBUG */
428 if (!tlvs
->ipv4_addrs
)
429 tlvs
->ipv4_addrs
= list_new ();
430 listnode_add (tlvs
->ipv4_addrs
, ipv4_addr
);
442 *found
|= TLVFLAG_AUTH_INFO
;
443 #ifdef EXTREME_TLV_DEBUG
444 zlog_debug ("ISIS-TLV (%s): IS-IS Authentication Information",
447 if (*expected
& TLVFLAG_AUTH_INFO
)
449 tlvs
->auth_info
.type
= *pnt
;
452 zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) "
453 "incorrect.", areatag
, type
, length
);
457 tlvs
->auth_info
.len
= length
;
459 memcpy (tlvs
->auth_info
.passwd
, pnt
, length
);
460 /* Return the authentication tlv pos for later computation
461 * of MD5 (RFC 5304, 2)
464 *auth_tlv_offset
+= (pnt
- start
- 3);
473 case DYNAMIC_HOSTNAME
:
474 *found
|= TLVFLAG_DYN_HOSTNAME
;
475 #ifdef EXTREME_TLV_DEBUG
476 zlog_debug ("ISIS-TLV (%s): Dynamic Hostname length %d",
478 #endif /* EXTREME_TLV_DEBUG */
479 if (*expected
& TLVFLAG_DYN_HOSTNAME
)
481 /* the length is also included in the pointed struct */
482 tlvs
->hostname
= (struct hostname
*) (pnt
- 1);
488 /* +---------------------------------------------------------------+
490 * +---------------------------------------------------------------+
492 *found
|= TLVFLAG_TE_ROUTER_ID
;
493 #ifdef EXTREME_TLV_DEBUG
494 zlog_debug ("ISIS-TLV (%s): TE Router ID %d", areatag
, length
);
495 #endif /* EXTREME_TLV_DEBUG */
496 if (*expected
& TLVFLAG_TE_ROUTER_ID
)
497 tlvs
->router_id
= (struct te_router_id
*) (pnt
);
501 case IPV4_INT_REACHABILITY
:
502 /* +-------+-------+-------+-------+-------+-------+-------+-------+
503 * | 0 | I/E | Default Metric | 1
504 * +-------+-------+-------+-------+-------+-------+-------+-------+
505 * | S | I/E | Delay Metric | 1
506 * +-------+-------+-------+-------+-------+-------+-------+-------+
507 * | S | I/E | Expense Metric | 1
508 * +-------+-------+-------+-------+-------+-------+-------+-------+
509 * | S | I/E | Error Metric | 1
510 * +-------+-------+-------+-------+-------+-------+-------+-------+
512 * +---------------------------------------------------------------+
514 * +---------------------------------------------------------------+
517 *found
|= TLVFLAG_IPV4_INT_REACHABILITY
;
518 #ifdef EXTREME_TLV_DEBUG
519 zlog_debug ("ISIS-TLV (%s): IPv4 internal Reachability length %d",
521 #endif /* EXTREME_TLV_DEBUG */
522 if (*expected
& TLVFLAG_IPV4_INT_REACHABILITY
)
524 while (length
> value_len
)
526 ipv4_reach
= (struct ipv4_reachability
*) pnt
;
527 if (!tlvs
->ipv4_int_reachs
)
528 tlvs
->ipv4_int_reachs
= list_new ();
529 listnode_add (tlvs
->ipv4_int_reachs
, ipv4_reach
);
540 case IPV4_EXT_REACHABILITY
:
541 /* +-------+-------+-------+-------+-------+-------+-------+-------+
542 * | 0 | I/E | Default Metric | 1
543 * +-------+-------+-------+-------+-------+-------+-------+-------+
544 * | S | I/E | Delay Metric | 1
545 * +-------+-------+-------+-------+-------+-------+-------+-------+
546 * | S | I/E | Expense Metric | 1
547 * +-------+-------+-------+-------+-------+-------+-------+-------+
548 * | S | I/E | Error Metric | 1
549 * +-------+-------+-------+-------+-------+-------+-------+-------+
551 * +---------------------------------------------------------------+
553 * +---------------------------------------------------------------+
556 *found
|= TLVFLAG_IPV4_EXT_REACHABILITY
;
557 #ifdef EXTREME_TLV_DEBUG
558 zlog_debug ("ISIS-TLV (%s): IPv4 external Reachability length %d",
560 #endif /* EXTREME_TLV_DEBUG */
561 if (*expected
& TLVFLAG_IPV4_EXT_REACHABILITY
)
563 while (length
> value_len
)
565 ipv4_reach
= (struct ipv4_reachability
*) pnt
;
566 if (!tlvs
->ipv4_ext_reachs
)
567 tlvs
->ipv4_ext_reachs
= list_new ();
568 listnode_add (tlvs
->ipv4_ext_reachs
, ipv4_reach
);
579 case TE_IPV4_REACHABILITY
:
580 /* +-------+-------+-------+-------+-------+-------+-------+-------+
582 * +-------+-------+-------+-------+-------+-------+-------+-------+
583 * | U/D | sTLV? | Prefix Mask Len | 1
584 * +-------+-------+-------+-------+-------+-------+-------+-------+
586 * +---------------------------------------------------------------+
588 * +---------------------------------------------------------------+
591 *found
|= TLVFLAG_TE_IPV4_REACHABILITY
;
592 #ifdef EXTREME_TLV_DEBUG
593 zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d",
595 #endif /* EXTREME_TLV_DEBUG */
596 endpnt
= pnt
+ length
;
597 if (*expected
& TLVFLAG_TE_IPV4_REACHABILITY
)
599 while (length
> value_len
)
601 te_ipv4_reach
= (struct te_ipv4_reachability
*) pnt
;
602 if ((te_ipv4_reach
->control
& 0x3F) > IPV4_MAX_BITLEN
)
604 zlog_warn ("ISIS-TLV (%s): invalid IPv4 extended reach"
605 "ability prefix length %d", areatag
,
606 te_ipv4_reach
->control
& 0x3F);
607 retval
= ISIS_WARNING
;
610 if (!tlvs
->te_ipv4_reachs
)
611 tlvs
->te_ipv4_reachs
= list_new ();
612 listnode_add (tlvs
->te_ipv4_reachs
, te_ipv4_reach
);
613 /* this trickery is permitable since no subtlvs are defined */
614 value_len
+= 5 + ((te_ipv4_reach
->control
& 0x3F) ?
615 ((((te_ipv4_reach
->control
& 0x3F) -
617 pnt
+= 5 + ((te_ipv4_reach
->control
& 0x3F) ?
618 ((((te_ipv4_reach
->control
& 0x3F) - 1) >> 3) + 1) : 0);
626 /* +-------+-------+-------+-------+-------+-------+-------+-------+
627 * + IP version 6 address + 16
628 * +-------+-------+-------+-------+-------+-------+-------+-------+
631 *found
|= TLVFLAG_IPV6_ADDR
;
632 #ifdef EXTREME_TLV_DEBUG
633 zlog_debug ("ISIS-TLV (%s): IPv6 Address length %d",
635 #endif /* EXTREME_TLV_DEBUG */
636 if (*expected
& TLVFLAG_IPV6_ADDR
)
638 while (length
> value_len
)
640 ipv6_addr
= (struct in6_addr
*) pnt
;
641 if (!tlvs
->ipv6_addrs
)
642 tlvs
->ipv6_addrs
= list_new ();
643 listnode_add (tlvs
->ipv6_addrs
, ipv6_addr
);
654 case IPV6_REACHABILITY
:
655 /* +-------+-------+-------+-------+-------+-------+-------+-------+
656 * | Default Metric | 4
657 * +-------+-------+-------+-------+-------+-------+-------+-------+
658 * | Control Informantion |
659 * +---------------------------------------------------------------+
660 * | IPv6 Prefix Length |--+
661 * +---------------------------------------------------------------+ |
663 * +---------------------------------------------------------------+
665 *found
|= TLVFLAG_IPV6_REACHABILITY
;
666 endpnt
= pnt
+ length
;
668 if (*expected
& TLVFLAG_IPV6_REACHABILITY
)
670 while (length
> value_len
)
672 ipv6_reach
= (struct ipv6_reachability
*) pnt
;
673 if (ipv6_reach
->prefix_len
> IPV6_MAX_BITLEN
)
675 zlog_warn ("ISIS-TLV (%s): invalid IPv6 extended reach"
676 "ability prefix length %d", areatag
,
677 ipv6_reach
->prefix_len
);
678 retval
= ISIS_WARNING
;
682 prefix_octets
= ((ipv6_reach
->prefix_len
+ 7) / 8);
683 value_len
+= prefix_octets
+ 6;
684 pnt
+= prefix_octets
+ 6;
685 /* FIXME: sub-tlvs */
686 if (!tlvs
->ipv6_reachs
)
687 tlvs
->ipv6_reachs
= list_new ();
688 listnode_add (tlvs
->ipv6_reachs
, ipv6_reach
);
696 /* +---------------------------------------------------------------+
697 * | Adjacency state | 1
698 * +---------------------------------------------------------------+
699 * | Extended Local Circuit ID | 4
700 * +---------------------------------------------------------------+
701 * | Neighbor System ID (If known) | 0-8
703 * +---------------------------------------------------------------+
704 * | Neighbor Local Circuit ID (If known) | 4
705 * +---------------------------------------------------------------+
707 *found
|= TLVFLAG_3WAY_HELLO
;
708 if (*expected
& TLVFLAG_3WAY_HELLO
)
710 while (length
> value_len
)
712 /* FIXME: make this work */
713 /* Adjacency State (one octet):
717 Extended Local Circuit ID (four octets)
718 Neighbor System ID if known (zero to eight octets)
719 Neighbor Extended Local Circuit ID (four octets, if Neighbor
720 System ID is present) */
731 case GRACEFUL_RESTART
:
732 /* +-------+-------+-------+-------+-------+-------+-------+-------+
733 * | Reserved | SA | RA | RR | 1
734 * +-------+-------+-------+-------+-------+-------+-------+-------+
735 * | Remaining Time | 2
736 * +---------------------------------------------------------------+
737 * | Restarting Neighbor ID (If known) | 0-8
738 * +---------------------------------------------------------------+
740 *found
|= TLVFLAG_GRACEFUL_RESTART
;
741 if (*expected
& TLVFLAG_GRACEFUL_RESTART
)
743 /* FIXME: make this work */
749 zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
750 areatag
, type
, length
);
761 add_tlv (u_char tag
, u_char len
, u_char
* value
, struct stream
*stream
)
763 if ((stream_get_size (stream
) - stream_get_endp (stream
)) <
764 (((unsigned)len
) + 2))
766 zlog_warn ("No room for TLV of type %d "
767 "(total size %d available %d required %d)",
768 tag
, (int)stream_get_size (stream
),
769 (int)(stream_get_size (stream
) - stream_get_endp (stream
)),
774 stream_putc (stream
, tag
); /* TAG */
775 stream_putc (stream
, len
); /* LENGTH */
776 stream_put (stream
, value
, (int) len
); /* VALUE */
779 zlog_debug ("Added TLV %d len %d", tag
, len
);
780 #endif /* EXTREME DEBUG */
785 tlv_add_area_addrs (struct list
*area_addrs
, struct stream
*stream
)
787 struct listnode
*node
;
788 struct area_addr
*area_addr
;
793 for (ALL_LIST_ELEMENTS_RO (area_addrs
, node
, area_addr
))
795 if (pos
- value
+ area_addr
->addr_len
> 255)
797 *pos
= area_addr
->addr_len
;
799 memcpy (pos
, area_addr
->area_addr
, (int) area_addr
->addr_len
);
800 pos
+= area_addr
->addr_len
;
803 return add_tlv (AREA_ADDRESSES
, pos
- value
, value
, stream
);
806 zlog_warn ("tlv_add_area_addrs(): TLV longer than 255");
811 tlv_add_is_neighs (struct list
*is_neighs
, struct stream
*stream
)
813 struct listnode
*node
;
814 struct is_neigh
*is_neigh
;
819 *pos
= 0; /*is_neigh->virtual; */
822 for (ALL_LIST_ELEMENTS_RO (is_neighs
, node
, is_neigh
))
824 if (pos
- value
+ IS_NEIGHBOURS_LEN
> 255)
826 retval
= add_tlv (IS_NEIGHBOURS
, pos
- value
, value
, stream
);
827 if (retval
!= ISIS_OK
)
831 *pos
= is_neigh
->metrics
.metric_default
;
833 *pos
= is_neigh
->metrics
.metric_delay
;
835 *pos
= is_neigh
->metrics
.metric_expense
;
837 *pos
= is_neigh
->metrics
.metric_error
;
839 memcpy (pos
, is_neigh
->neigh_id
, ISIS_SYS_ID_LEN
+ 1);
840 pos
+= ISIS_SYS_ID_LEN
+ 1;
843 return add_tlv (IS_NEIGHBOURS
, pos
- value
, value
, stream
);
847 tlv_add_te_is_neighs (struct list
*te_is_neighs
, struct stream
*stream
)
849 struct listnode
*node
;
850 struct te_is_neigh
*te_is_neigh
;
855 for (ALL_LIST_ELEMENTS_RO (te_is_neighs
, node
, te_is_neigh
))
857 /* FIXME: Check if Total SubTLVs size doesn't exceed 255 */
858 if (pos
- value
+ IS_NEIGHBOURS_LEN
+ te_is_neigh
->sub_tlvs_length
> 255)
860 retval
= add_tlv (TE_IS_NEIGHBOURS
, pos
- value
, value
, stream
);
861 if (retval
!= ISIS_OK
)
866 memcpy (pos
, te_is_neigh
->neigh_id
, ISIS_SYS_ID_LEN
+ 1);
867 pos
+= ISIS_SYS_ID_LEN
+ 1;
868 memcpy (pos
, te_is_neigh
->te_metric
, 3);
870 /* Set the total size of Sub TLVs */
871 *pos
= te_is_neigh
->sub_tlvs_length
;
873 /* Copy Sub TLVs if any */
874 if (te_is_neigh
->sub_tlvs_length
> 0)
876 memcpy (pos
, te_is_neigh
->sub_tlvs
, te_is_neigh
->sub_tlvs_length
);
877 pos
+= te_is_neigh
->sub_tlvs_length
;
881 return add_tlv (TE_IS_NEIGHBOURS
, pos
- value
, value
, stream
);
885 tlv_add_lan_neighs (struct list
*lan_neighs
, struct stream
*stream
)
887 struct listnode
*node
;
893 for (ALL_LIST_ELEMENTS_RO (lan_neighs
, node
, snpa
))
895 if (pos
- value
+ ETH_ALEN
> 255)
897 retval
= add_tlv (LAN_NEIGHBOURS
, pos
- value
, value
, stream
);
898 if (retval
!= ISIS_OK
)
902 memcpy (pos
, snpa
, ETH_ALEN
);
906 return add_tlv (LAN_NEIGHBOURS
, pos
- value
, value
, stream
);
910 tlv_add_nlpid (struct nlpids
*nlpids
, struct stream
*stream
)
912 return add_tlv (PROTOCOLS_SUPPORTED
, nlpids
->count
, nlpids
->nlpids
, stream
);
916 tlv_add_authinfo (u_char auth_type
, u_char auth_len
, u_char
*auth_value
,
917 struct stream
*stream
)
922 memcpy (pos
, auth_value
, auth_len
);
924 return add_tlv (AUTH_INFO
, auth_len
+ 1, value
, stream
);
928 tlv_add_checksum (struct checksum
*checksum
, struct stream
*stream
)
932 return add_tlv (CHECKSUM
, pos
- value
, value
, stream
);
936 tlv_add_ip_addrs (struct list
*ip_addrs
, struct stream
*stream
)
938 struct listnode
*node
;
939 struct prefix_ipv4
*ipv4
;
943 for (ALL_LIST_ELEMENTS_RO (ip_addrs
, node
, ipv4
))
945 if (pos
- value
+ IPV4_MAX_BYTELEN
> 255)
947 /* RFC 1195 s4.2: only one tuple of 63 allowed. */
948 zlog_warn ("tlv_add_ip_addrs(): cutting off at 63 IP addresses");
951 *(u_int32_t
*) pos
= ipv4
->prefix
.s_addr
;
952 pos
+= IPV4_MAX_BYTELEN
;
955 return add_tlv (IPV4_ADDR
, pos
- value
, value
, stream
);
958 /* Used to add TLV containing just one IPv4 address - either IPv4 address TLV
959 * (in case of LSP) or TE router ID TLV. */
961 tlv_add_in_addr (struct in_addr
*addr
, struct stream
*stream
, u_char tag
)
966 memcpy (pos
, addr
, IPV4_MAX_BYTELEN
);
967 pos
+= IPV4_MAX_BYTELEN
;
969 return add_tlv (tag
, pos
- value
, value
, stream
);
973 tlv_add_dynamic_hostname (struct hostname
*hostname
, struct stream
*stream
)
975 return add_tlv (DYNAMIC_HOSTNAME
, hostname
->namelen
, hostname
->name
,
980 tlv_add_lsp_entries (struct list
*lsps
, struct stream
*stream
)
982 struct listnode
*node
;
983 struct isis_lsp
*lsp
;
988 for (ALL_LIST_ELEMENTS_RO (lsps
, node
, lsp
))
990 if (pos
- value
+ LSP_ENTRIES_LEN
> 255)
992 retval
= add_tlv (LSP_ENTRIES
, pos
- value
, value
, stream
);
993 if (retval
!= ISIS_OK
)
997 *((u_int16_t
*) pos
) = lsp
->lsp_header
->rem_lifetime
;
999 memcpy (pos
, lsp
->lsp_header
->lsp_id
, ISIS_SYS_ID_LEN
+ 2);
1000 pos
+= ISIS_SYS_ID_LEN
+ 2;
1001 *((u_int32_t
*) pos
) = lsp
->lsp_header
->seq_num
;
1003 *((u_int16_t
*) pos
) = lsp
->lsp_header
->checksum
;
1007 return add_tlv (LSP_ENTRIES
, pos
- value
, value
, stream
);
1011 tlv_add_ipv4_reachs (u_char tag
, struct list
*ipv4_reachs
, struct stream
*stream
)
1013 struct listnode
*node
;
1014 struct ipv4_reachability
*reach
;
1016 u_char
*pos
= value
;
1019 for (ALL_LIST_ELEMENTS_RO (ipv4_reachs
, node
, reach
))
1021 if (pos
- value
+ IPV4_REACH_LEN
> 255)
1024 add_tlv (tag
, pos
- value
, value
, stream
);
1025 if (retval
!= ISIS_OK
)
1029 *pos
= reach
->metrics
.metric_default
;
1031 *pos
= reach
->metrics
.metric_delay
;
1033 *pos
= reach
->metrics
.metric_expense
;
1035 *pos
= reach
->metrics
.metric_error
;
1037 *(u_int32_t
*) pos
= reach
->prefix
.s_addr
;
1038 pos
+= IPV4_MAX_BYTELEN
;
1039 *(u_int32_t
*) pos
= reach
->mask
.s_addr
;
1040 pos
+= IPV4_MAX_BYTELEN
;
1043 return add_tlv (tag
, pos
- value
, value
, stream
);
1047 tlv_add_ipv4_int_reachs (struct list
*ipv4_reachs
, struct stream
*stream
)
1049 return tlv_add_ipv4_reachs(IPV4_INT_REACHABILITY
, ipv4_reachs
, stream
);
1053 tlv_add_ipv4_ext_reachs (struct list
*ipv4_reachs
, struct stream
*stream
)
1055 return tlv_add_ipv4_reachs(IPV4_EXT_REACHABILITY
, ipv4_reachs
, stream
);
1060 tlv_add_te_ipv4_reachs (struct list
*te_ipv4_reachs
, struct stream
*stream
)
1062 struct listnode
*node
;
1063 struct te_ipv4_reachability
*te_reach
;
1065 u_char
*pos
= value
;
1069 for (ALL_LIST_ELEMENTS_RO (te_ipv4_reachs
, node
, te_reach
))
1071 prefix_size
= ((((te_reach
->control
& 0x3F) - 1) >> 3) + 1);
1073 if (pos
- value
+ (5 + prefix_size
) > 255)
1076 add_tlv (TE_IPV4_REACHABILITY
, pos
- value
, value
, stream
);
1077 if (retval
!= ISIS_OK
)
1081 *(u_int32_t
*) pos
= te_reach
->te_metric
;
1083 *pos
= te_reach
->control
;
1085 memcpy (pos
, &te_reach
->prefix_start
, prefix_size
);
1089 return add_tlv (TE_IPV4_REACHABILITY
, pos
- value
, value
, stream
);
1093 tlv_add_ipv6_addrs (struct list
*ipv6_addrs
, struct stream
*stream
)
1095 struct listnode
*node
;
1096 struct prefix_ipv6
*ipv6
;
1098 u_char
*pos
= value
;
1101 for (ALL_LIST_ELEMENTS_RO (ipv6_addrs
, node
, ipv6
))
1103 if (pos
- value
+ IPV6_MAX_BYTELEN
> 255)
1105 retval
= add_tlv (IPV6_ADDR
, pos
- value
, value
, stream
);
1106 if (retval
!= ISIS_OK
)
1110 memcpy (pos
, ipv6
->prefix
.s6_addr
, IPV6_MAX_BYTELEN
);
1111 pos
+= IPV6_MAX_BYTELEN
;
1114 return add_tlv (IPV6_ADDR
, pos
- value
, value
, stream
);
1118 tlv_add_ipv6_reachs (struct list
*ipv6_reachs
, struct stream
*stream
)
1120 struct listnode
*node
;
1121 struct ipv6_reachability
*ip6reach
;
1123 u_char
*pos
= value
;
1124 int retval
, prefix_octets
;
1126 for (ALL_LIST_ELEMENTS_RO (ipv6_reachs
, node
, ip6reach
))
1128 if (pos
- value
+ IPV6_MAX_BYTELEN
+ 6 > 255)
1130 retval
= add_tlv (IPV6_REACHABILITY
, pos
- value
, value
, stream
);
1131 if (retval
!= ISIS_OK
)
1135 *(uint32_t *) pos
= ip6reach
->metric
;
1137 *pos
= ip6reach
->control_info
;
1139 prefix_octets
= ((ip6reach
->prefix_len
+ 7) / 8);
1140 *pos
= ip6reach
->prefix_len
;
1142 memcpy (pos
, ip6reach
->prefix
, prefix_octets
);
1143 pos
+= prefix_octets
;
1146 return add_tlv (IPV6_REACHABILITY
, pos
- value
, value
, stream
);
1150 tlv_add_padding (struct stream
*stream
)
1152 int fullpads
, i
, left
;
1155 * How many times can we add full padding ?
1157 fullpads
= (stream_get_size (stream
) - stream_get_endp (stream
)) / 257;
1158 for (i
= 0; i
< fullpads
; i
++)
1160 if (!stream_putc (stream
, (u_char
) PADDING
)) /* TAG */
1162 if (!stream_putc (stream
, (u_char
) 255)) /* LENGHT */
1164 stream_put (stream
, NULL
, 255); /* zero padding */
1167 left
= stream_get_size (stream
) - stream_get_endp (stream
);
1174 stream_putc (stream
, PADDING
);
1175 stream_putc (stream
, 0);
1179 stream_putc (stream
, PADDING
);
1180 stream_putc (stream
, left
- 2);
1181 stream_put (stream
, NULL
, left
-2);
1186 zlog_warn ("tlv_add_padding(): no room for tlv");
1187 return ISIS_WARNING
;