2 * IS-IS TLV Serializer/Deserializer
4 * Copyright (C) 2015,2017 Christian Franke
6 * This file is part of FRR.
8 * FRR is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
13 * FRR is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with FRR; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
30 #include "isisd/isisd.h"
31 #include "isisd/isis_memory.h"
32 #include "isisd/isis_tlvs.h"
33 #include "isisd/isis_common.h"
34 #include "isisd/isis_mt.h"
35 #include "isisd/isis_misc.h"
36 #include "isisd/isis_adjacency.h"
37 #include "isisd/isis_circuit.h"
38 #include "isisd/isis_pdu.h"
39 #include "isisd/isis_lsp.h"
40 #include "isisd/isis_te.h"
42 DEFINE_MTYPE_STATIC(ISISD
, ISIS_TLV
, "ISIS TLVs")
43 DEFINE_MTYPE_STATIC(ISISD
, ISIS_SUBTLV
, "ISIS Sub-TLVs")
44 DEFINE_MTYPE_STATIC(ISISD
, ISIS_MT_ITEM_LIST
, "ISIS MT Item Lists")
46 typedef int (*unpack_tlv_func
)(enum isis_tlv_context context
, uint8_t tlv_type
,
47 uint8_t tlv_len
, struct stream
*s
,
48 struct sbuf
*log
, void *dest
, int indent
);
49 typedef int (*pack_item_func
)(struct isis_item
*item
, struct stream
*s
);
50 typedef void (*free_item_func
)(struct isis_item
*i
);
51 typedef int (*unpack_item_func
)(uint16_t mtid
, uint8_t len
, struct stream
*s
,
52 struct sbuf
*log
, void *dest
, int indent
);
53 typedef void (*format_item_func
)(uint16_t mtid
, struct isis_item
*i
,
54 struct sbuf
*buf
, int indent
);
55 typedef struct isis_item
*(*copy_item_func
)(struct isis_item
*i
);
59 unpack_tlv_func unpack
;
61 pack_item_func pack_item
;
62 free_item_func free_item
;
63 unpack_item_func unpack_item
;
64 format_item_func format_item
;
65 copy_item_func copy_item
;
73 struct pack_order_entry
{
74 enum isis_tlv_context context
;
75 enum isis_tlv_type type
;
76 enum how_to_pack how_to_pack
;
79 #define PACK_ENTRY(t, h, w) \
81 .context = ISIS_CONTEXT_LSP, .type = ISIS_TLV_##t, \
83 .what_to_pack = offsetof(struct isis_tlvs, w), \
86 static struct pack_order_entry pack_order
[] = {
87 PACK_ENTRY(OLDSTYLE_REACH
, ISIS_ITEMS
, oldstyle_reach
),
88 PACK_ENTRY(LAN_NEIGHBORS
, ISIS_ITEMS
, lan_neighbor
),
89 PACK_ENTRY(LSP_ENTRY
, ISIS_ITEMS
, lsp_entries
),
90 PACK_ENTRY(EXTENDED_REACH
, ISIS_ITEMS
, extended_reach
),
91 PACK_ENTRY(MT_REACH
, ISIS_MT_ITEMS
, mt_reach
),
92 PACK_ENTRY(OLDSTYLE_IP_REACH
, ISIS_ITEMS
, oldstyle_ip_reach
),
93 PACK_ENTRY(OLDSTYLE_IP_REACH_EXT
, ISIS_ITEMS
, oldstyle_ip_reach_ext
),
94 PACK_ENTRY(IPV4_ADDRESS
, ISIS_ITEMS
, ipv4_address
),
95 PACK_ENTRY(IPV6_ADDRESS
, ISIS_ITEMS
, ipv6_address
),
96 PACK_ENTRY(EXTENDED_IP_REACH
, ISIS_ITEMS
, extended_ip_reach
),
97 PACK_ENTRY(MT_IP_REACH
, ISIS_MT_ITEMS
, mt_ip_reach
),
98 PACK_ENTRY(IPV6_REACH
, ISIS_ITEMS
, ipv6_reach
),
99 PACK_ENTRY(MT_IPV6_REACH
, ISIS_MT_ITEMS
, mt_ipv6_reach
)};
101 /* This is a forward definition. The table is actually initialized
102 * in at the bottom. */
103 static const struct tlv_ops
*tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
];
105 /* End of _ops forward definition. */
108 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
);
110 /* Functions for Sub-TVL ??? IPv6 Source Prefix */
112 static struct prefix_ipv6
*copy_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
)
117 struct prefix_ipv6
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
118 rv
->family
= p
->family
;
119 rv
->prefixlen
= p
->prefixlen
;
120 memcpy(&rv
->prefix
, &p
->prefix
, sizeof(rv
->prefix
));
124 static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
125 struct sbuf
*buf
, int indent
)
130 char prefixbuf
[PREFIX2STR_BUFFER
];
131 sbuf_push(buf
, indent
, "IPv6 Source Prefix: %s\n",
132 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
)));
135 static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
141 if (STREAM_WRITEABLE(s
) < 3 + (unsigned)PSIZE(p
->prefixlen
))
144 stream_putc(s
, ISIS_SUBTLV_IPV6_SOURCE_PREFIX
);
145 stream_putc(s
, 1 + PSIZE(p
->prefixlen
));
146 stream_putc(s
, p
->prefixlen
);
147 stream_put(s
, &p
->prefix
, PSIZE(p
->prefixlen
));
151 static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context
,
152 uint8_t tlv_type
, uint8_t tlv_len
,
153 struct stream
*s
, struct sbuf
*log
,
154 void *dest
, int indent
)
156 struct isis_subtlvs
*subtlvs
= dest
;
157 struct prefix_ipv6 p
= {
161 sbuf_push(log
, indent
, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
166 "Not enough data left. (expected 1 or more bytes, got %" PRIu8
172 p
.prefixlen
= stream_getc(s
);
173 if (p
.prefixlen
> 128) {
174 sbuf_push(log
, indent
, "Prefixlen %u is inplausible for IPv6\n",
179 if (tlv_len
!= 1 + PSIZE(p
.prefixlen
)) {
182 "TLV size differs from expected size for the prefixlen. "
183 "(expected %u but got %" PRIu8
")\n",
184 1 + PSIZE(p
.prefixlen
), tlv_len
);
188 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
190 if (subtlvs
->source_prefix
) {
193 "WARNING: source prefix Sub-TLV present multiple times.\n");
194 /* Ignore all but first occurrence of the source prefix Sub-TLV
199 subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(p
));
200 memcpy(subtlvs
->source_prefix
, &p
, sizeof(p
));
204 /* Functions related to subtlvs */
206 static struct isis_subtlvs
*isis_alloc_subtlvs(void)
208 struct isis_subtlvs
*result
;
210 result
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*result
));
215 static struct isis_subtlvs
*copy_subtlvs(struct isis_subtlvs
*subtlvs
)
220 struct isis_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
223 copy_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
);
227 static void format_subtlvs(struct isis_subtlvs
*subtlvs
, struct sbuf
*buf
,
230 format_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, buf
, indent
);
233 static void isis_free_subtlvs(struct isis_subtlvs
*subtlvs
)
238 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
->source_prefix
);
240 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
);
243 static int pack_subtlvs(struct isis_subtlvs
*subtlvs
, struct stream
*s
)
246 size_t subtlv_len_pos
= stream_get_endp(s
);
248 if (STREAM_WRITEABLE(s
) < 1)
251 stream_putc(s
, 0); /* Put 0 as subtlvs length, filled in later */
253 rv
= pack_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, s
);
257 size_t subtlv_len
= stream_get_endp(s
) - subtlv_len_pos
- 1;
258 if (subtlv_len
> 255)
261 stream_putc_at(s
, subtlv_len_pos
, subtlv_len
);
265 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
266 struct stream
*stream
, struct sbuf
*log
, void *dest
,
269 /* Functions related to TLVs 1 Area Addresses */
271 static struct isis_item
*copy_item_area_address(struct isis_item
*i
)
273 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
274 struct isis_area_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
277 memcpy(rv
->addr
, addr
->addr
, addr
->len
);
278 return (struct isis_item
*)rv
;
281 static void format_item_area_address(uint16_t mtid
, struct isis_item
*i
,
282 struct sbuf
*buf
, int indent
)
284 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
286 sbuf_push(buf
, indent
, "Area Address: %s\n",
287 isonet_print(addr
->addr
, addr
->len
));
290 static void free_item_area_address(struct isis_item
*i
)
292 XFREE(MTYPE_ISIS_TLV
, i
);
295 static int pack_item_area_address(struct isis_item
*i
, struct stream
*s
)
297 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
299 if (STREAM_WRITEABLE(s
) < (unsigned)1 + addr
->len
)
301 stream_putc(s
, addr
->len
);
302 stream_put(s
, addr
->addr
, addr
->len
);
306 static int unpack_item_area_address(uint16_t mtid
, uint8_t len
,
307 struct stream
*s
, struct sbuf
*log
,
308 void *dest
, int indent
)
310 struct isis_tlvs
*tlvs
= dest
;
311 struct isis_area_address
*rv
= NULL
;
313 sbuf_push(log
, indent
, "Unpack area address...\n");
317 "Not enough data left. (Expected 1 byte of address length, got %" PRIu8
323 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
324 rv
->len
= stream_getc(s
);
326 if (len
< 1 + rv
->len
) {
327 sbuf_push(log
, indent
, "Not enough data left. (Expected %" PRIu8
328 " bytes of address, got %" PRIu8
")\n",
333 if (rv
->len
< 1 || rv
->len
> 20) {
334 sbuf_push(log
, indent
,
335 "Implausible area address length %" PRIu8
"\n",
340 stream_get(rv
->addr
, s
, rv
->len
);
342 format_item_area_address(ISIS_MT_IPV4_UNICAST
, (struct isis_item
*)rv
,
344 append_item(&tlvs
->area_addresses
, (struct isis_item
*)rv
);
347 XFREE(MTYPE_ISIS_TLV
, rv
);
351 /* Functions related to TLV 2 (Old-Style) IS Reach */
352 static struct isis_item
*copy_item_oldstyle_reach(struct isis_item
*i
)
354 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
355 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
357 memcpy(rv
->id
, r
->id
, 7);
358 rv
->metric
= r
->metric
;
359 return (struct isis_item
*)rv
;
362 static void format_item_oldstyle_reach(uint16_t mtid
, struct isis_item
*i
,
363 struct sbuf
*buf
, int indent
)
365 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
367 sbuf_push(buf
, indent
, "IS Reachability: %s (Metric: %" PRIu8
")\n",
368 isis_format_id(r
->id
, 7), r
->metric
);
371 static void free_item_oldstyle_reach(struct isis_item
*i
)
373 XFREE(MTYPE_ISIS_TLV
, i
);
376 static int pack_item_oldstyle_reach(struct isis_item
*i
, struct stream
*s
)
378 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
380 if (STREAM_WRITEABLE(s
) < 11)
383 stream_putc(s
, r
->metric
);
384 stream_putc(s
, 0x80); /* delay metric - unsupported */
385 stream_putc(s
, 0x80); /* expense metric - unsupported */
386 stream_putc(s
, 0x80); /* error metric - unsupported */
387 stream_put(s
, r
->id
, 7);
392 static int unpack_item_oldstyle_reach(uint16_t mtid
, uint8_t len
,
393 struct stream
*s
, struct sbuf
*log
,
394 void *dest
, int indent
)
396 struct isis_tlvs
*tlvs
= dest
;
398 sbuf_push(log
, indent
, "Unpack oldstyle reach...\n");
402 "Not enough data left.(Expected 11 bytes of reach information, got %" PRIu8
408 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
409 rv
->metric
= stream_getc(s
);
410 if ((rv
->metric
& 0x3f) != rv
->metric
) {
411 sbuf_push(log
, indent
, "Metric has unplausible format\n");
414 stream_forward_getp(s
, 3); /* Skip other metrics */
415 stream_get(rv
->id
, s
, 7);
417 format_item_oldstyle_reach(mtid
, (struct isis_item
*)rv
, log
,
419 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)rv
);
423 /* Functions related to TLV 6 LAN Neighbors */
424 static struct isis_item
*copy_item_lan_neighbor(struct isis_item
*i
)
426 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
427 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
429 memcpy(rv
->mac
, n
->mac
, 6);
430 return (struct isis_item
*)rv
;
433 static void format_item_lan_neighbor(uint16_t mtid
, struct isis_item
*i
,
434 struct sbuf
*buf
, int indent
)
436 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
438 sbuf_push(buf
, indent
, "LAN Neighbor: %s\n", isis_format_id(n
->mac
, 6));
441 static void free_item_lan_neighbor(struct isis_item
*i
)
443 XFREE(MTYPE_ISIS_TLV
, i
);
446 static int pack_item_lan_neighbor(struct isis_item
*i
, struct stream
*s
)
448 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
450 if (STREAM_WRITEABLE(s
) < 6)
453 stream_put(s
, n
->mac
, 6);
458 static int unpack_item_lan_neighbor(uint16_t mtid
, uint8_t len
,
459 struct stream
*s
, struct sbuf
*log
,
460 void *dest
, int indent
)
462 struct isis_tlvs
*tlvs
= dest
;
464 sbuf_push(log
, indent
, "Unpack LAN neighbor...\n");
468 "Not enough data left.(Expected 6 bytes of mac, got %" PRIu8
474 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
475 stream_get(rv
->mac
, s
, 6);
477 format_item_lan_neighbor(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
478 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)rv
);
482 /* Functions related to TLV 9 LSP Entry */
483 static struct isis_item
*copy_item_lsp_entry(struct isis_item
*i
)
485 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
486 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
488 rv
->rem_lifetime
= e
->rem_lifetime
;
489 memcpy(rv
->id
, e
->id
, sizeof(rv
->id
));
490 rv
->seqno
= e
->seqno
;
491 rv
->checksum
= e
->checksum
;
493 return (struct isis_item
*)rv
;
496 static void format_item_lsp_entry(uint16_t mtid
, struct isis_item
*i
,
497 struct sbuf
*buf
, int indent
)
499 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
501 sbuf_push(buf
, indent
,
502 "LSP Entry: %s, seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
503 ", lifetime %" PRIu16
"s\n",
504 isis_format_id(e
->id
, 8), e
->seqno
, e
->checksum
,
508 static void free_item_lsp_entry(struct isis_item
*i
)
510 XFREE(MTYPE_ISIS_TLV
, i
);
513 static int pack_item_lsp_entry(struct isis_item
*i
, struct stream
*s
)
515 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
517 if (STREAM_WRITEABLE(s
) < 16)
520 stream_putw(s
, e
->rem_lifetime
);
521 stream_put(s
, e
->id
, 8);
522 stream_putl(s
, e
->seqno
);
523 stream_putw(s
, e
->checksum
);
528 static int unpack_item_lsp_entry(uint16_t mtid
, uint8_t len
, struct stream
*s
,
529 struct sbuf
*log
, void *dest
, int indent
)
531 struct isis_tlvs
*tlvs
= dest
;
533 sbuf_push(log
, indent
, "Unpack LSP entry...\n");
537 "Not enough data left. (Expected 16 bytes of LSP info, got %" PRIu8
,
542 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
543 rv
->rem_lifetime
= stream_getw(s
);
544 stream_get(rv
->id
, s
, 8);
545 rv
->seqno
= stream_getl(s
);
546 rv
->checksum
= stream_getw(s
);
548 format_item_lsp_entry(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
549 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)rv
);
553 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
555 static struct isis_item
*copy_item_extended_reach(struct isis_item
*i
)
557 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
558 struct isis_extended_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
560 memcpy(rv
->id
, r
->id
, 7);
561 rv
->metric
= r
->metric
;
563 if (r
->subtlvs
&& r
->subtlv_len
) {
564 rv
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, r
->subtlv_len
);
565 memcpy(rv
->subtlvs
, r
->subtlvs
, r
->subtlv_len
);
566 rv
->subtlv_len
= r
->subtlv_len
;
569 return (struct isis_item
*)rv
;
572 static void format_item_extended_reach(uint16_t mtid
, struct isis_item
*i
,
573 struct sbuf
*buf
, int indent
)
575 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
577 sbuf_push(buf
, indent
, "%s Reachability: %s (Metric: %u)",
578 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
579 isis_format_id(r
->id
, 7), r
->metric
);
580 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
581 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
582 sbuf_push(buf
, 0, "\n");
584 if (r
->subtlv_len
&& r
->subtlvs
)
585 mpls_te_print_detail(buf
, indent
+ 2, r
->subtlvs
,
589 static void free_item_extended_reach(struct isis_item
*i
)
591 struct isis_extended_reach
*item
= (struct isis_extended_reach
*)i
;
592 XFREE(MTYPE_ISIS_TLV
, item
->subtlvs
);
593 XFREE(MTYPE_ISIS_TLV
, item
);
596 static int pack_item_extended_reach(struct isis_item
*i
, struct stream
*s
)
598 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
600 if (STREAM_WRITEABLE(s
) < 11 + (unsigned)r
->subtlv_len
)
602 stream_put(s
, r
->id
, sizeof(r
->id
));
603 stream_put3(s
, r
->metric
);
604 stream_putc(s
, r
->subtlv_len
);
605 stream_put(s
, r
->subtlvs
, r
->subtlv_len
);
609 static int unpack_item_extended_reach(uint16_t mtid
, uint8_t len
,
610 struct stream
*s
, struct sbuf
*log
,
611 void *dest
, int indent
)
613 struct isis_tlvs
*tlvs
= dest
;
614 struct isis_extended_reach
*rv
= NULL
;
616 struct isis_item_list
*items
;
618 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
619 items
= &tlvs
->extended_reach
;
621 items
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
624 sbuf_push(log
, indent
, "Unpacking %s reachability...\n",
625 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
630 "Not enough data left. (expected 11 or more bytes, got %" PRIu8
636 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
637 stream_get(rv
->id
, s
, 7);
638 rv
->metric
= stream_get3(s
);
639 subtlv_len
= stream_getc(s
);
641 format_item_extended_reach(mtid
, (struct isis_item
*)rv
, log
,
644 if ((size_t)len
< ((size_t)11) + subtlv_len
) {
645 sbuf_push(log
, indent
,
646 "Not enough data left for subtlv size %" PRIu8
647 ", there are only %" PRIu8
" bytes left.\n",
648 subtlv_len
, len
- 11);
652 sbuf_push(log
, indent
, "Storing %" PRIu8
" bytes of subtlvs\n",
656 size_t subtlv_start
= stream_get_getp(s
);
658 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_NE_REACH
, subtlv_len
, s
,
659 log
, NULL
, indent
+ 4)) {
663 stream_set_getp(s
, subtlv_start
);
665 rv
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, subtlv_len
);
666 stream_get(rv
->subtlvs
, s
, subtlv_len
);
667 rv
->subtlv_len
= subtlv_len
;
670 append_item(items
, (struct isis_item
*)rv
);
674 free_item_extended_reach((struct isis_item
*)rv
);
679 /* Functions related to TLV 128 (Old-Style) IP Reach */
680 static struct isis_item
*copy_item_oldstyle_ip_reach(struct isis_item
*i
)
682 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
683 struct isis_oldstyle_ip_reach
*rv
=
684 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
686 rv
->metric
= r
->metric
;
687 rv
->prefix
= r
->prefix
;
688 return (struct isis_item
*)rv
;
691 static void format_item_oldstyle_ip_reach(uint16_t mtid
, struct isis_item
*i
,
692 struct sbuf
*buf
, int indent
)
694 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
695 char prefixbuf
[PREFIX2STR_BUFFER
];
697 sbuf_push(buf
, indent
, "IP Reachability: %s (Metric: %" PRIu8
")\n",
698 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
702 static void free_item_oldstyle_ip_reach(struct isis_item
*i
)
704 XFREE(MTYPE_ISIS_TLV
, i
);
707 static int pack_item_oldstyle_ip_reach(struct isis_item
*i
, struct stream
*s
)
709 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
711 if (STREAM_WRITEABLE(s
) < 12)
714 stream_putc(s
, r
->metric
);
715 stream_putc(s
, 0x80); /* delay metric - unsupported */
716 stream_putc(s
, 0x80); /* expense metric - unsupported */
717 stream_putc(s
, 0x80); /* error metric - unsupported */
718 stream_put(s
, &r
->prefix
.prefix
, 4);
721 masklen2ip(r
->prefix
.prefixlen
, &mask
);
722 stream_put(s
, &mask
, sizeof(mask
));
727 static int unpack_item_oldstyle_ip_reach(uint16_t mtid
, uint8_t len
,
728 struct stream
*s
, struct sbuf
*log
,
729 void *dest
, int indent
)
731 sbuf_push(log
, indent
, "Unpack oldstyle ip reach...\n");
735 "Not enough data left.(Expected 12 bytes of reach information, got %" PRIu8
741 struct isis_oldstyle_ip_reach
*rv
=
742 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
743 rv
->metric
= stream_getc(s
);
744 if ((rv
->metric
& 0x7f) != rv
->metric
) {
745 sbuf_push(log
, indent
, "Metric has unplausible format\n");
748 stream_forward_getp(s
, 3); /* Skip other metrics */
749 rv
->prefix
.family
= AF_INET
;
750 stream_get(&rv
->prefix
.prefix
, s
, 4);
753 stream_get(&mask
, s
, 4);
754 rv
->prefix
.prefixlen
= ip_masklen(mask
);
756 format_item_oldstyle_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
758 append_item(dest
, (struct isis_item
*)rv
);
763 /* Functions related to TLV 129 protocols supported */
765 static void copy_tlv_protocols_supported(struct isis_protocols_supported
*src
,
766 struct isis_protocols_supported
*dest
)
768 if (!src
->protocols
|| !src
->count
)
770 dest
->count
= src
->count
;
771 dest
->protocols
= XCALLOC(MTYPE_ISIS_TLV
, src
->count
);
772 memcpy(dest
->protocols
, src
->protocols
, src
->count
);
775 static void format_tlv_protocols_supported(struct isis_protocols_supported
*p
,
776 struct sbuf
*buf
, int indent
)
778 if (!p
|| !p
->count
|| !p
->protocols
)
781 sbuf_push(buf
, indent
, "Protocols Supported: ");
782 for (uint8_t i
= 0; i
< p
->count
; i
++) {
783 sbuf_push(buf
, 0, "%s%s", nlpid2str(p
->protocols
[i
]),
784 (i
+ 1 < p
->count
) ? ", " : "");
786 sbuf_push(buf
, 0, "\n");
789 static void free_tlv_protocols_supported(struct isis_protocols_supported
*p
)
791 XFREE(MTYPE_ISIS_TLV
, p
->protocols
);
794 static int pack_tlv_protocols_supported(struct isis_protocols_supported
*p
,
797 if (!p
|| !p
->count
|| !p
->protocols
)
800 if (STREAM_WRITEABLE(s
) < (unsigned)(p
->count
+ 2))
803 stream_putc(s
, ISIS_TLV_PROTOCOLS_SUPPORTED
);
804 stream_putc(s
, p
->count
);
805 stream_put(s
, p
->protocols
, p
->count
);
809 static int unpack_tlv_protocols_supported(enum isis_tlv_context context
,
810 uint8_t tlv_type
, uint8_t tlv_len
,
811 struct stream
*s
, struct sbuf
*log
,
812 void *dest
, int indent
)
814 struct isis_tlvs
*tlvs
= dest
;
816 sbuf_push(log
, indent
, "Unpacking Protocols Supported TLV...\n");
818 sbuf_push(log
, indent
, "WARNING: No protocols included\n");
821 if (tlvs
->protocols_supported
.protocols
) {
824 "WARNING: protocols supported TLV present multiple times.\n");
825 stream_forward_getp(s
, tlv_len
);
829 tlvs
->protocols_supported
.count
= tlv_len
;
830 tlvs
->protocols_supported
.protocols
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
);
831 stream_get(tlvs
->protocols_supported
.protocols
, s
, tlv_len
);
833 format_tlv_protocols_supported(&tlvs
->protocols_supported
, log
,
838 /* Functions related to TLV 132 IPv4 Interface addresses */
839 static struct isis_item
*copy_item_ipv4_address(struct isis_item
*i
)
841 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
842 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
845 return (struct isis_item
*)rv
;
848 static void format_item_ipv4_address(uint16_t mtid
, struct isis_item
*i
,
849 struct sbuf
*buf
, int indent
)
851 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
852 char addrbuf
[INET_ADDRSTRLEN
];
854 inet_ntop(AF_INET
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
855 sbuf_push(buf
, indent
, "IPv4 Interface Address: %s\n", addrbuf
);
858 static void free_item_ipv4_address(struct isis_item
*i
)
860 XFREE(MTYPE_ISIS_TLV
, i
);
863 static int pack_item_ipv4_address(struct isis_item
*i
, struct stream
*s
)
865 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
867 if (STREAM_WRITEABLE(s
) < 4)
870 stream_put(s
, &a
->addr
, 4);
875 static int unpack_item_ipv4_address(uint16_t mtid
, uint8_t len
,
876 struct stream
*s
, struct sbuf
*log
,
877 void *dest
, int indent
)
879 struct isis_tlvs
*tlvs
= dest
;
881 sbuf_push(log
, indent
, "Unpack IPv4 Interface address...\n");
885 "Not enough data left.(Expected 4 bytes of IPv4 address, got %" PRIu8
891 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
892 stream_get(&rv
->addr
, s
, 4);
894 format_item_ipv4_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
895 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)rv
);
900 /* Functions related to TLV 232 IPv6 Interface addresses */
901 static struct isis_item
*copy_item_ipv6_address(struct isis_item
*i
)
903 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
904 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
907 return (struct isis_item
*)rv
;
910 static void format_item_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
911 struct sbuf
*buf
, int indent
)
913 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
914 char addrbuf
[INET6_ADDRSTRLEN
];
916 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
917 sbuf_push(buf
, indent
, "IPv6 Interface Address: %s\n", addrbuf
);
920 static void free_item_ipv6_address(struct isis_item
*i
)
922 XFREE(MTYPE_ISIS_TLV
, i
);
925 static int pack_item_ipv6_address(struct isis_item
*i
, struct stream
*s
)
927 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
929 if (STREAM_WRITEABLE(s
) < 16)
932 stream_put(s
, &a
->addr
, 16);
937 static int unpack_item_ipv6_address(uint16_t mtid
, uint8_t len
,
938 struct stream
*s
, struct sbuf
*log
,
939 void *dest
, int indent
)
941 struct isis_tlvs
*tlvs
= dest
;
943 sbuf_push(log
, indent
, "Unpack IPv6 Interface address...\n");
947 "Not enough data left.(Expected 16 bytes of IPv6 address, got %" PRIu8
953 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
954 stream_get(&rv
->addr
, s
, 16);
956 format_item_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
957 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)rv
);
962 /* Functions related to TLV 229 MT Router information */
963 static struct isis_item
*copy_item_mt_router_info(struct isis_item
*i
)
965 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
966 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
968 rv
->overload
= info
->overload
;
969 rv
->attached
= info
->attached
;
970 rv
->mtid
= info
->mtid
;
971 return (struct isis_item
*)rv
;
974 static void format_item_mt_router_info(uint16_t mtid
, struct isis_item
*i
,
975 struct sbuf
*buf
, int indent
)
977 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
979 sbuf_push(buf
, indent
, "MT Router Info: %s%s%s\n",
980 isis_mtid2str(info
->mtid
), info
->overload
? " Overload" : "",
981 info
->attached
? " Attached" : "");
984 static void free_item_mt_router_info(struct isis_item
*i
)
986 XFREE(MTYPE_ISIS_TLV
, i
);
989 static int pack_item_mt_router_info(struct isis_item
*i
, struct stream
*s
)
991 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
993 if (STREAM_WRITEABLE(s
) < 2)
996 uint16_t entry
= info
->mtid
;
999 entry
|= ISIS_MT_OL_MASK
;
1001 entry
|= ISIS_MT_AT_MASK
;
1003 stream_putw(s
, entry
);
1008 static int unpack_item_mt_router_info(uint16_t mtid
, uint8_t len
,
1009 struct stream
*s
, struct sbuf
*log
,
1010 void *dest
, int indent
)
1012 struct isis_tlvs
*tlvs
= dest
;
1014 sbuf_push(log
, indent
, "Unpack MT Router info...\n");
1018 "Not enough data left.(Expected 2 bytes of MT info, got %" PRIu8
1024 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1026 uint16_t entry
= stream_getw(s
);
1027 rv
->overload
= entry
& ISIS_MT_OL_MASK
;
1028 rv
->attached
= entry
& ISIS_MT_AT_MASK
;
1029 rv
->mtid
= entry
& ISIS_MT_MASK
;
1031 format_item_mt_router_info(mtid
, (struct isis_item
*)rv
, log
,
1033 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)rv
);
1037 /* Functions related to TLV 134 TE Router ID */
1039 static struct in_addr
*copy_tlv_te_router_id(const struct in_addr
*id
)
1044 struct in_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1045 memcpy(rv
, id
, sizeof(*rv
));
1049 static void format_tlv_te_router_id(const struct in_addr
*id
, struct sbuf
*buf
,
1055 char addrbuf
[INET_ADDRSTRLEN
];
1056 inet_ntop(AF_INET
, id
, addrbuf
, sizeof(addrbuf
));
1057 sbuf_push(buf
, indent
, "TE Router ID: %s\n", addrbuf
);
1060 static void free_tlv_te_router_id(struct in_addr
*id
)
1062 XFREE(MTYPE_ISIS_TLV
, id
);
1065 static int pack_tlv_te_router_id(const struct in_addr
*id
, struct stream
*s
)
1070 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
1073 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID
);
1075 stream_put(s
, id
, 4);
1079 static int unpack_tlv_te_router_id(enum isis_tlv_context context
,
1080 uint8_t tlv_type
, uint8_t tlv_len
,
1081 struct stream
*s
, struct sbuf
*log
,
1082 void *dest
, int indent
)
1084 struct isis_tlvs
*tlvs
= dest
;
1086 sbuf_push(log
, indent
, "Unpacking TE Router ID TLV...\n");
1088 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
1092 if (tlvs
->te_router_id
) {
1093 sbuf_push(log
, indent
,
1094 "WARNING: TE Router ID present multiple times.\n");
1095 stream_forward_getp(s
, tlv_len
);
1099 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, 4);
1100 stream_get(tlvs
->te_router_id
, s
, 4);
1101 format_tlv_te_router_id(tlvs
->te_router_id
, log
, indent
+ 2);
1106 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
1108 static struct isis_item
*copy_item_extended_ip_reach(struct isis_item
*i
)
1110 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1111 struct isis_extended_ip_reach
*rv
=
1112 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1114 rv
->metric
= r
->metric
;
1116 rv
->prefix
= r
->prefix
;
1118 return (struct isis_item
*)rv
;
1121 static void format_item_extended_ip_reach(uint16_t mtid
, struct isis_item
*i
,
1122 struct sbuf
*buf
, int indent
)
1124 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1125 char prefixbuf
[PREFIX2STR_BUFFER
];
1127 sbuf_push(buf
, indent
, "%s IP Reachability: %s (Metric: %u)%s",
1128 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
1129 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
1130 r
->metric
, r
->down
? " Down" : "");
1131 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1132 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1133 sbuf_push(buf
, 0, "\n");
1136 static void free_item_extended_ip_reach(struct isis_item
*i
)
1138 struct isis_extended_ip_reach
*item
=
1139 (struct isis_extended_ip_reach
*)i
;
1140 XFREE(MTYPE_ISIS_TLV
, item
);
1143 static int pack_item_extended_ip_reach(struct isis_item
*i
, struct stream
*s
)
1145 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1148 if (STREAM_WRITEABLE(s
) < 5)
1150 stream_putl(s
, r
->metric
);
1152 control
= r
->down
? ISIS_EXTENDED_IP_REACH_DOWN
: 0;
1153 control
|= r
->prefix
.prefixlen
;
1154 stream_putc(s
, control
);
1156 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
))
1158 stream_put(s
, &r
->prefix
.prefix
.s_addr
, PSIZE(r
->prefix
.prefixlen
));
1162 static int unpack_item_extended_ip_reach(uint16_t mtid
, uint8_t len
,
1163 struct stream
*s
, struct sbuf
*log
,
1164 void *dest
, int indent
)
1166 struct isis_tlvs
*tlvs
= dest
;
1167 struct isis_extended_ip_reach
*rv
= NULL
;
1169 uint8_t control
, subtlv_len
;
1170 struct isis_item_list
*items
;
1172 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1173 items
= &tlvs
->extended_ip_reach
;
1175 items
= isis_get_mt_items(&tlvs
->mt_ip_reach
, mtid
);
1178 sbuf_push(log
, indent
, "Unpacking %s IPv4 reachability...\n",
1179 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
1182 if (len
< consume
) {
1185 "Not enough data left. (expected 5 or more bytes, got %" PRIu8
1191 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1193 rv
->metric
= stream_getl(s
);
1194 control
= stream_getc(s
);
1195 rv
->down
= (control
& ISIS_EXTENDED_IP_REACH_DOWN
);
1196 rv
->prefix
.family
= AF_INET
;
1197 rv
->prefix
.prefixlen
= control
& 0x3f;
1198 if (rv
->prefix
.prefixlen
> 32) {
1199 sbuf_push(log
, indent
, "Prefixlen %u is inplausible for IPv4\n",
1200 rv
->prefix
.prefixlen
);
1204 consume
+= PSIZE(rv
->prefix
.prefixlen
);
1205 if (len
< consume
) {
1208 "Expected %u bytes of prefix, but only %u bytes available.\n",
1209 PSIZE(rv
->prefix
.prefixlen
), len
- 5);
1212 stream_get(&rv
->prefix
.prefix
.s_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
1213 in_addr_t orig_prefix
= rv
->prefix
.prefix
.s_addr
;
1214 apply_mask_ipv4(&rv
->prefix
);
1215 if (orig_prefix
!= rv
->prefix
.prefix
.s_addr
)
1216 sbuf_push(log
, indent
+ 2,
1217 "WARNING: Prefix had hostbits set.\n");
1218 format_item_extended_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
1221 if (control
& ISIS_EXTENDED_IP_REACH_SUBTLV
) {
1223 if (len
< consume
) {
1226 "Expected 1 byte of subtlv len, but no more data present.\n");
1229 subtlv_len
= stream_getc(s
);
1234 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
1236 consume
+= subtlv_len
;
1237 if (len
< consume
) {
1241 " bytes of subtlvs, but only %u bytes available.\n",
1243 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
1246 sbuf_push(log
, indent
, "Skipping %" PRIu8
" bytes of subvls",
1248 stream_forward_getp(s
, subtlv_len
);
1251 append_item(items
, (struct isis_item
*)rv
);
1255 free_item_extended_ip_reach((struct isis_item
*)rv
);
1259 /* Functions related to TLV 137 Dynamic Hostname */
1261 static char *copy_tlv_dynamic_hostname(const char *hostname
)
1266 return XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
1269 static void format_tlv_dynamic_hostname(const char *hostname
, struct sbuf
*buf
,
1275 sbuf_push(buf
, indent
, "Hostname: %s\n", hostname
);
1278 static void free_tlv_dynamic_hostname(char *hostname
)
1280 XFREE(MTYPE_ISIS_TLV
, hostname
);
1283 static int pack_tlv_dynamic_hostname(const char *hostname
, struct stream
*s
)
1288 uint8_t name_len
= strlen(hostname
);
1290 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + name_len
))
1293 stream_putc(s
, ISIS_TLV_DYNAMIC_HOSTNAME
);
1294 stream_putc(s
, name_len
);
1295 stream_put(s
, hostname
, name_len
);
1299 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context
,
1300 uint8_t tlv_type
, uint8_t tlv_len
,
1301 struct stream
*s
, struct sbuf
*log
,
1302 void *dest
, int indent
)
1304 struct isis_tlvs
*tlvs
= dest
;
1306 sbuf_push(log
, indent
, "Unpacking Dynamic Hostname TLV...\n");
1308 sbuf_push(log
, indent
, "WARNING: No hostname included\n");
1312 if (tlvs
->hostname
) {
1313 sbuf_push(log
, indent
,
1314 "WARNING: Hostname present multiple times.\n");
1315 stream_forward_getp(s
, tlv_len
);
1319 tlvs
->hostname
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
+ 1);
1320 stream_get(tlvs
->hostname
, s
, tlv_len
);
1321 tlvs
->hostname
[tlv_len
] = '\0';
1324 for (uint8_t i
= 0; i
< tlv_len
; i
++) {
1325 if ((unsigned char)tlvs
->hostname
[i
] > 127
1326 || !isprint((int)tlvs
->hostname
[i
])) {
1328 tlvs
->hostname
[i
] = '?';
1334 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
1340 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
1342 static struct isis_item
*copy_item_ipv6_reach(struct isis_item
*i
)
1344 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1345 struct isis_ipv6_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1346 rv
->metric
= r
->metric
;
1348 rv
->external
= r
->external
;
1349 rv
->prefix
= r
->prefix
;
1350 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
1352 return (struct isis_item
*)rv
;
1355 static void format_item_ipv6_reach(uint16_t mtid
, struct isis_item
*i
,
1356 struct sbuf
*buf
, int indent
)
1358 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1359 char prefixbuf
[PREFIX2STR_BUFFER
];
1361 sbuf_push(buf
, indent
, "%sIPv6 Reachability: %s (Metric: %u)%s%s",
1362 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "MT ",
1363 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
1364 r
->metric
, r
->down
? " Down" : "",
1365 r
->external
? " External" : "");
1366 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1367 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1368 sbuf_push(buf
, 0, "\n");
1371 sbuf_push(buf
, indent
, " Subtlvs:\n");
1372 format_subtlvs(r
->subtlvs
, buf
, indent
+ 4);
1376 static void free_item_ipv6_reach(struct isis_item
*i
)
1378 struct isis_ipv6_reach
*item
= (struct isis_ipv6_reach
*)i
;
1380 isis_free_subtlvs(item
->subtlvs
);
1381 XFREE(MTYPE_ISIS_TLV
, item
);
1384 static int pack_item_ipv6_reach(struct isis_item
*i
, struct stream
*s
)
1386 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1389 if (STREAM_WRITEABLE(s
) < 6)
1391 stream_putl(s
, r
->metric
);
1393 control
= r
->down
? ISIS_IPV6_REACH_DOWN
: 0;
1394 control
|= r
->external
? ISIS_IPV6_REACH_EXTERNAL
: 0;
1395 control
|= r
->subtlvs
? ISIS_IPV6_REACH_SUBTLV
: 0;
1397 stream_putc(s
, control
);
1398 stream_putc(s
, r
->prefix
.prefixlen
);
1400 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
))
1402 stream_put(s
, &r
->prefix
.prefix
.s6_addr
, PSIZE(r
->prefix
.prefixlen
));
1405 return pack_subtlvs(r
->subtlvs
, s
);
1410 static int unpack_item_ipv6_reach(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1411 struct sbuf
*log
, void *dest
, int indent
)
1413 struct isis_tlvs
*tlvs
= dest
;
1414 struct isis_ipv6_reach
*rv
= NULL
;
1416 uint8_t control
, subtlv_len
;
1417 struct isis_item_list
*items
;
1419 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1420 items
= &tlvs
->ipv6_reach
;
1422 items
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
1425 sbuf_push(log
, indent
, "Unpacking %sIPv6 reachability...\n",
1426 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "mt ");
1428 if (len
< consume
) {
1431 "Not enough data left. (expected 6 or more bytes, got %" PRIu8
1437 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1439 rv
->metric
= stream_getl(s
);
1440 control
= stream_getc(s
);
1441 rv
->down
= (control
& ISIS_IPV6_REACH_DOWN
);
1442 rv
->external
= (control
& ISIS_IPV6_REACH_EXTERNAL
);
1444 rv
->prefix
.family
= AF_INET6
;
1445 rv
->prefix
.prefixlen
= stream_getc(s
);
1446 if (rv
->prefix
.prefixlen
> 128) {
1447 sbuf_push(log
, indent
, "Prefixlen %u is inplausible for IPv6\n",
1448 rv
->prefix
.prefixlen
);
1452 consume
+= PSIZE(rv
->prefix
.prefixlen
);
1453 if (len
< consume
) {
1456 "Expected %u bytes of prefix, but only %u bytes available.\n",
1457 PSIZE(rv
->prefix
.prefixlen
), len
- 6);
1460 stream_get(&rv
->prefix
.prefix
.s6_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
1461 struct in6_addr orig_prefix
= rv
->prefix
.prefix
;
1462 apply_mask_ipv6(&rv
->prefix
);
1463 if (memcmp(&orig_prefix
, &rv
->prefix
.prefix
, sizeof(orig_prefix
)))
1464 sbuf_push(log
, indent
+ 2,
1465 "WARNING: Prefix had hostbits set.\n");
1466 format_item_ipv6_reach(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1468 if (control
& ISIS_IPV6_REACH_SUBTLV
) {
1470 if (len
< consume
) {
1473 "Expected 1 byte of subtlv len, but no more data persent.\n");
1476 subtlv_len
= stream_getc(s
);
1481 " WARNING: subtlv bit set, but there are no subtlvs.\n");
1483 consume
+= subtlv_len
;
1484 if (len
< consume
) {
1488 " bytes of subtlvs, but only %u bytes available.\n",
1490 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
1494 rv
->subtlvs
= isis_alloc_subtlvs();
1495 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
, subtlv_len
, s
,
1496 log
, rv
->subtlvs
, indent
+ 4)) {
1501 append_item(items
, (struct isis_item
*)rv
);
1505 free_item_ipv6_reach((struct isis_item
*)rv
);
1509 /* Functions related to TLV 10 Authentication */
1510 static struct isis_item
*copy_item_auth(struct isis_item
*i
)
1512 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1513 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1515 rv
->type
= auth
->type
;
1516 rv
->length
= auth
->length
;
1517 memcpy(rv
->value
, auth
->value
, sizeof(rv
->value
));
1518 return (struct isis_item
*)rv
;
1521 static void format_item_auth(uint16_t mtid
, struct isis_item
*i
,
1522 struct sbuf
*buf
, int indent
)
1524 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1527 sbuf_push(buf
, indent
, "Authentication:\n");
1528 switch (auth
->type
) {
1529 case ISIS_PASSWD_TYPE_CLEARTXT
:
1530 zlog_sanitize(obuf
, sizeof(obuf
), auth
->value
, auth
->length
);
1531 sbuf_push(buf
, indent
, " Password: %s\n", obuf
);
1533 case ISIS_PASSWD_TYPE_HMAC_MD5
:
1534 for (unsigned int i
= 0; i
< 16; i
++) {
1535 snprintf(obuf
+ 2 * i
, sizeof(obuf
) - 2 * i
,
1536 "%02" PRIx8
, auth
->value
[i
]);
1538 sbuf_push(buf
, indent
, " HMAC-MD5: %s\n", obuf
);
1541 sbuf_push(buf
, indent
, " Unknown (%" PRIu8
")\n", auth
->type
);
1546 static void free_item_auth(struct isis_item
*i
)
1548 XFREE(MTYPE_ISIS_TLV
, i
);
1551 static int pack_item_auth(struct isis_item
*i
, struct stream
*s
)
1553 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1555 if (STREAM_WRITEABLE(s
) < 1)
1557 stream_putc(s
, auth
->type
);
1559 switch (auth
->type
) {
1560 case ISIS_PASSWD_TYPE_CLEARTXT
:
1561 if (STREAM_WRITEABLE(s
) < auth
->length
)
1563 stream_put(s
, auth
->passwd
, auth
->length
);
1565 case ISIS_PASSWD_TYPE_HMAC_MD5
:
1566 if (STREAM_WRITEABLE(s
) < 16)
1568 auth
->offset
= stream_get_endp(s
);
1569 stream_put(s
, NULL
, 16);
1578 static int unpack_item_auth(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1579 struct sbuf
*log
, void *dest
, int indent
)
1581 struct isis_tlvs
*tlvs
= dest
;
1583 sbuf_push(log
, indent
, "Unpack Auth TLV...\n");
1587 "Not enough data left.(Expected 1 bytes of auth type, got %" PRIu8
1593 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1595 rv
->type
= stream_getc(s
);
1596 rv
->length
= len
- 1;
1598 if (rv
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
&& rv
->length
!= 16) {
1601 "Unexpected auth length for HMAC-MD5 (expected 16, got %" PRIu8
1604 XFREE(MTYPE_ISIS_TLV
, rv
);
1608 rv
->offset
= stream_get_getp(s
);
1609 stream_get(rv
->value
, s
, rv
->length
);
1610 format_item_auth(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1611 append_item(&tlvs
->isis_auth
, (struct isis_item
*)rv
);
1615 /* Functions relating to item TLVs */
1617 static void init_item_list(struct isis_item_list
*items
)
1620 items
->tail
= &items
->head
;
1624 static struct isis_item
*copy_item(enum isis_tlv_context context
,
1625 enum isis_tlv_type type
,
1626 struct isis_item
*item
)
1628 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
1630 if (ops
&& ops
->copy_item
)
1631 return ops
->copy_item(item
);
1633 assert(!"Unknown item tlv type!");
1637 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1638 struct isis_item_list
*src
, struct isis_item_list
*dest
)
1640 struct isis_item
*item
;
1642 init_item_list(dest
);
1644 for (item
= src
->head
; item
; item
= item
->next
) {
1645 append_item(dest
, copy_item(context
, type
, item
));
1649 static void format_item(uint16_t mtid
, enum isis_tlv_context context
,
1650 enum isis_tlv_type type
, struct isis_item
*i
,
1651 struct sbuf
*buf
, int indent
)
1653 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
1655 if (ops
&& ops
->format_item
) {
1656 ops
->format_item(mtid
, i
, buf
, indent
);
1660 assert(!"Unknown item tlv type!");
1663 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
1664 enum isis_tlv_type type
, struct isis_item_list
*items
,
1665 struct sbuf
*buf
, int indent
)
1667 struct isis_item
*i
;
1669 for (i
= items
->head
; i
; i
= i
->next
)
1670 format_item(mtid
, context
, type
, i
, buf
, indent
);
1672 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1674 static void free_item(enum isis_tlv_context tlv_context
,
1675 enum isis_tlv_type tlv_type
, struct isis_item
*item
)
1677 const struct tlv_ops
*ops
= tlv_table
[tlv_context
][tlv_type
];
1679 if (ops
&& ops
->free_item
) {
1680 ops
->free_item(item
);
1684 assert(!"Unknown item tlv type!");
1687 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1688 struct isis_item_list
*items
)
1690 struct isis_item
*item
, *next_item
;
1692 for (item
= items
->head
; item
; item
= next_item
) {
1693 next_item
= item
->next
;
1694 free_item(context
, type
, item
);
1698 static int pack_item(enum isis_tlv_context context
, enum isis_tlv_type type
,
1699 struct isis_item
*i
, struct stream
*s
,
1700 struct isis_tlvs
**fragment_tlvs
,
1701 struct pack_order_entry
*pe
, uint16_t mtid
)
1703 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
1705 if (ops
&& ops
->pack_item
) {
1706 return ops
->pack_item(i
, s
);
1709 assert(!"Unknown item tlv type!");
1713 static void add_item_to_fragment(struct isis_item
*i
,
1714 struct pack_order_entry
*pe
,
1715 struct isis_tlvs
*fragment_tlvs
, uint16_t mtid
)
1717 struct isis_item_list
*l
;
1719 if (pe
->how_to_pack
== ISIS_ITEMS
) {
1720 l
= (struct isis_item_list
*)(((char *)fragment_tlvs
)
1721 + pe
->what_to_pack
);
1723 struct isis_mt_item_list
*m
;
1724 m
= (struct isis_mt_item_list
*)(((char *)fragment_tlvs
)
1725 + pe
->what_to_pack
);
1726 l
= isis_get_mt_items(m
, mtid
);
1729 append_item(l
, copy_item(pe
->context
, pe
->type
, i
));
1732 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
1733 enum isis_tlv_type type
, struct isis_item_list
*items
,
1734 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
1735 struct pack_order_entry
*pe
,
1736 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
1737 struct list
*new_fragment_arg
)
1739 size_t len_pos
, last_len
, len
;
1740 struct isis_item
*item
= NULL
;
1747 if (STREAM_WRITEABLE(s
) < 2)
1750 stream_putc(s
, type
);
1751 len_pos
= stream_get_endp(s
);
1752 stream_putc(s
, 0); /* Put 0 as length for now */
1754 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(type
)
1755 && mtid
!= ISIS_MT_IPV4_UNICAST
) {
1756 if (STREAM_WRITEABLE(s
) < 2)
1758 stream_putw(s
, mtid
);
1761 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_OLDSTYLE_REACH
) {
1762 if (STREAM_WRITEABLE(s
) < 1)
1764 stream_putc(s
, 0); /* Virtual flag is set to 0 */
1768 for (item
= item
? item
: items
->head
; item
; item
= item
->next
) {
1769 rv
= pack_item(context
, type
, item
, s
, fragment_tlvs
, pe
, mtid
);
1773 len
= stream_get_endp(s
) - len_pos
- 1;
1775 /* Multiple auths don't go into one TLV, so always break */
1776 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_AUTH
) {
1782 if (!last_len
) /* strange, not a single item fit */
1784 /* drop last tlv, otherwise, its too long */
1785 stream_set_endp(s
, len_pos
+ 1 + last_len
);
1791 add_item_to_fragment(item
, pe
, *fragment_tlvs
, mtid
);
1796 stream_putc_at(s
, len_pos
, len
);
1805 *fragment_tlvs
= new_fragment(new_fragment_arg
);
1808 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1810 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
)
1813 dest
->tail
= &(*dest
->tail
)->next
;
1817 static int unpack_item(uint16_t mtid
, enum isis_tlv_context context
,
1818 uint8_t tlv_type
, uint8_t len
, struct stream
*s
,
1819 struct sbuf
*log
, void *dest
, int indent
)
1821 const struct tlv_ops
*ops
= tlv_table
[context
][tlv_type
];
1823 if (ops
&& ops
->unpack_item
)
1824 return ops
->unpack_item(mtid
, len
, s
, log
, dest
, indent
);
1826 assert(!"Unknown item tlv type!");
1827 sbuf_push(log
, indent
, "Unknown item tlv type!\n");
1831 static int unpack_tlv_with_items(enum isis_tlv_context context
,
1832 uint8_t tlv_type
, uint8_t tlv_len
,
1833 struct stream
*s
, struct sbuf
*log
, void *dest
,
1841 tlv_start
= stream_get_getp(s
);
1844 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(tlv_type
)) {
1846 sbuf_push(log
, indent
,
1847 "TLV is too short to contain MTID\n");
1850 mtid
= stream_getw(s
) & ISIS_MT_MASK
;
1852 sbuf_push(log
, indent
, "Unpacking as MT %s item TLV...\n",
1853 isis_mtid2str(mtid
));
1855 sbuf_push(log
, indent
, "Unpacking as item TLV...\n");
1856 mtid
= ISIS_MT_IPV4_UNICAST
;
1859 if (context
== ISIS_CONTEXT_LSP
1860 && tlv_type
== ISIS_TLV_OLDSTYLE_REACH
) {
1861 if (tlv_len
- tlv_pos
< 1) {
1862 sbuf_push(log
, indent
,
1863 "TLV is too short for old style reach\n");
1866 stream_forward_getp(s
, 1);
1870 if (context
== ISIS_CONTEXT_LSP
1871 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH
) {
1872 struct isis_tlvs
*tlvs
= dest
;
1873 dest
= &tlvs
->oldstyle_ip_reach
;
1874 } else if (context
== ISIS_CONTEXT_LSP
1875 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH_EXT
) {
1876 struct isis_tlvs
*tlvs
= dest
;
1877 dest
= &tlvs
->oldstyle_ip_reach_ext
;
1880 if (context
== ISIS_CONTEXT_LSP
1881 && tlv_type
== ISIS_TLV_MT_ROUTER_INFO
) {
1882 struct isis_tlvs
*tlvs
= dest
;
1883 tlvs
->mt_router_info_empty
= (tlv_pos
>= (size_t)tlv_len
);
1886 while (tlv_pos
< (size_t)tlv_len
) {
1887 rv
= unpack_item(mtid
, context
, tlv_type
, tlv_len
- tlv_pos
, s
,
1888 log
, dest
, indent
+ 2);
1892 tlv_pos
= stream_get_getp(s
) - tlv_start
;
1898 /* Functions to manipulate mt_item_lists */
1900 static int isis_mt_item_list_cmp(const struct isis_item_list
*a
,
1901 const struct isis_item_list
*b
)
1903 if (a
->mtid
< b
->mtid
)
1905 if (a
->mtid
> b
->mtid
)
1910 RB_PROTOTYPE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
1911 RB_GENERATE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
1913 struct isis_item_list
*isis_get_mt_items(struct isis_mt_item_list
*m
,
1916 struct isis_item_list
*rv
;
1918 rv
= isis_lookup_mt_items(m
, mtid
);
1920 rv
= XCALLOC(MTYPE_ISIS_MT_ITEM_LIST
, sizeof(*rv
));
1923 RB_INSERT(isis_mt_item_list
, m
, rv
);
1929 struct isis_item_list
*isis_lookup_mt_items(struct isis_mt_item_list
*m
,
1932 struct isis_item_list key
= {.mtid
= mtid
};
1934 return RB_FIND(isis_mt_item_list
, m
, &key
);
1937 static void free_mt_items(enum isis_tlv_context context
,
1938 enum isis_tlv_type type
, struct isis_mt_item_list
*m
)
1940 struct isis_item_list
*n
, *nnext
;
1942 RB_FOREACH_SAFE (n
, isis_mt_item_list
, m
, nnext
) {
1943 free_items(context
, type
, n
);
1944 RB_REMOVE(isis_mt_item_list
, m
, n
);
1945 XFREE(MTYPE_ISIS_MT_ITEM_LIST
, n
);
1949 static void format_mt_items(enum isis_tlv_context context
,
1950 enum isis_tlv_type type
,
1951 struct isis_mt_item_list
*m
, struct sbuf
*buf
,
1954 struct isis_item_list
*n
;
1956 RB_FOREACH (n
, isis_mt_item_list
, m
) {
1957 format_items_(n
->mtid
, context
, type
, n
, buf
, indent
);
1961 static int pack_mt_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1962 struct isis_mt_item_list
*m
, struct stream
*s
,
1963 struct isis_tlvs
**fragment_tlvs
,
1964 struct pack_order_entry
*pe
,
1965 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
1966 struct list
*new_fragment_arg
)
1968 struct isis_item_list
*n
;
1970 RB_FOREACH (n
, isis_mt_item_list
, m
) {
1973 rv
= pack_items_(n
->mtid
, context
, type
, n
, s
, fragment_tlvs
,
1974 pe
, new_fragment
, new_fragment_arg
);
1982 static void copy_mt_items(enum isis_tlv_context context
,
1983 enum isis_tlv_type type
,
1984 struct isis_mt_item_list
*src
,
1985 struct isis_mt_item_list
*dest
)
1987 struct isis_item_list
*n
;
1989 RB_INIT(isis_mt_item_list
, dest
);
1991 RB_FOREACH (n
, isis_mt_item_list
, src
) {
1992 copy_items(context
, type
, n
, isis_get_mt_items(dest
, n
->mtid
));
1996 /* Functions related to tlvs in general */
1998 struct isis_tlvs
*isis_alloc_tlvs(void)
2000 struct isis_tlvs
*result
;
2002 result
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*result
));
2004 init_item_list(&result
->isis_auth
);
2005 init_item_list(&result
->area_addresses
);
2006 init_item_list(&result
->mt_router_info
);
2007 init_item_list(&result
->oldstyle_reach
);
2008 init_item_list(&result
->lan_neighbor
);
2009 init_item_list(&result
->lsp_entries
);
2010 init_item_list(&result
->extended_reach
);
2011 RB_INIT(isis_mt_item_list
, &result
->mt_reach
);
2012 init_item_list(&result
->oldstyle_ip_reach
);
2013 init_item_list(&result
->oldstyle_ip_reach_ext
);
2014 init_item_list(&result
->ipv4_address
);
2015 init_item_list(&result
->ipv6_address
);
2016 init_item_list(&result
->extended_ip_reach
);
2017 RB_INIT(isis_mt_item_list
, &result
->mt_ip_reach
);
2018 init_item_list(&result
->ipv6_reach
);
2019 RB_INIT(isis_mt_item_list
, &result
->mt_ipv6_reach
);
2024 struct isis_tlvs
*isis_copy_tlvs(struct isis_tlvs
*tlvs
)
2026 struct isis_tlvs
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2028 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
,
2031 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2032 &tlvs
->area_addresses
, &rv
->area_addresses
);
2034 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2035 &tlvs
->mt_router_info
, &rv
->mt_router_info
);
2037 tlvs
->mt_router_info_empty
= rv
->mt_router_info_empty
;
2039 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2040 &tlvs
->oldstyle_reach
, &rv
->oldstyle_reach
);
2042 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2043 &tlvs
->lan_neighbor
, &rv
->lan_neighbor
);
2045 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
2048 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2049 &tlvs
->extended_reach
, &rv
->extended_reach
);
2051 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
2054 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2055 &tlvs
->oldstyle_ip_reach
, &rv
->oldstyle_ip_reach
);
2057 copy_tlv_protocols_supported(&tlvs
->protocols_supported
,
2058 &rv
->protocols_supported
);
2060 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2061 &tlvs
->oldstyle_ip_reach_ext
, &rv
->oldstyle_ip_reach_ext
);
2063 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
, &tlvs
->ipv4_address
,
2066 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
, &tlvs
->ipv6_address
,
2069 rv
->te_router_id
= copy_tlv_te_router_id(tlvs
->te_router_id
);
2071 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2072 &tlvs
->extended_ip_reach
, &rv
->extended_ip_reach
);
2074 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2075 &tlvs
->mt_ip_reach
, &rv
->mt_ip_reach
);
2077 rv
->hostname
= copy_tlv_dynamic_hostname(tlvs
->hostname
);
2079 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
2082 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2083 &tlvs
->mt_ipv6_reach
, &rv
->mt_ipv6_reach
);
2088 static void format_tlvs(struct isis_tlvs
*tlvs
, struct sbuf
*buf
, int indent
)
2090 format_tlv_protocols_supported(&tlvs
->protocols_supported
, buf
, indent
);
2092 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
, buf
,
2095 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2096 &tlvs
->area_addresses
, buf
, indent
);
2098 if (tlvs
->mt_router_info_empty
) {
2099 sbuf_push(buf
, indent
, "MT Router Info: None\n");
2101 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2102 &tlvs
->mt_router_info
, buf
, indent
);
2105 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2106 &tlvs
->oldstyle_reach
, buf
, indent
);
2108 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2109 &tlvs
->lan_neighbor
, buf
, indent
);
2111 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
2114 format_tlv_dynamic_hostname(tlvs
->hostname
, buf
, indent
);
2115 format_tlv_te_router_id(tlvs
->te_router_id
, buf
, indent
);
2117 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2118 &tlvs
->extended_reach
, buf
, indent
);
2120 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
2123 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2124 &tlvs
->oldstyle_ip_reach
, buf
, indent
);
2126 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2127 &tlvs
->oldstyle_ip_reach_ext
, buf
, indent
);
2129 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
2130 &tlvs
->ipv4_address
, buf
, indent
);
2132 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
2133 &tlvs
->ipv6_address
, buf
, indent
);
2135 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2136 &tlvs
->extended_ip_reach
, buf
, indent
);
2138 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2139 &tlvs
->mt_ip_reach
, buf
, indent
);
2141 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
2144 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2145 &tlvs
->mt_ipv6_reach
, buf
, indent
);
2148 const char *isis_format_tlvs(struct isis_tlvs
*tlvs
)
2150 static struct sbuf buf
;
2152 if (!sbuf_buf(&buf
))
2153 sbuf_init(&buf
, NULL
, 0);
2156 format_tlvs(tlvs
, &buf
, 0);
2157 return sbuf_buf(&buf
);
2160 void isis_free_tlvs(struct isis_tlvs
*tlvs
)
2165 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
2166 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2167 &tlvs
->area_addresses
);
2168 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2169 &tlvs
->mt_router_info
);
2170 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2171 &tlvs
->oldstyle_reach
);
2172 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2173 &tlvs
->lan_neighbor
);
2174 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
);
2175 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2176 &tlvs
->extended_reach
);
2177 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
);
2178 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2179 &tlvs
->oldstyle_ip_reach
);
2180 free_tlv_protocols_supported(&tlvs
->protocols_supported
);
2181 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2182 &tlvs
->oldstyle_ip_reach_ext
);
2183 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
2184 &tlvs
->ipv4_address
);
2185 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
2186 &tlvs
->ipv6_address
);
2187 free_tlv_te_router_id(tlvs
->te_router_id
);
2188 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2189 &tlvs
->extended_ip_reach
);
2190 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2191 &tlvs
->mt_ip_reach
);
2192 free_tlv_dynamic_hostname(tlvs
->hostname
);
2193 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
);
2194 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2195 &tlvs
->mt_ipv6_reach
);
2197 XFREE(MTYPE_ISIS_TLV
, tlvs
);
2200 static void add_padding(struct stream
*s
)
2202 while (STREAM_WRITEABLE(s
)) {
2203 if (STREAM_WRITEABLE(s
) == 1)
2205 uint32_t padding_len
= STREAM_WRITEABLE(s
) - 2;
2207 if (padding_len
> 255) {
2208 if (padding_len
== 256)
2214 stream_putc(s
, ISIS_TLV_PADDING
);
2215 stream_putc(s
, padding_len
);
2216 stream_put(s
, NULL
, padding_len
);
2220 #define LSP_REM_LIFETIME_OFF 10
2221 #define LSP_CHECKSUM_OFF 24
2222 static void safe_auth_md5(struct stream
*s
, uint16_t *checksum
,
2223 uint16_t *rem_lifetime
)
2225 memcpy(rem_lifetime
, STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
,
2226 sizeof(*rem_lifetime
));
2227 memset(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, 0, sizeof(*rem_lifetime
));
2228 memcpy(checksum
, STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, sizeof(*checksum
));
2229 memset(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, 0, sizeof(*checksum
));
2232 static void restore_auth_md5(struct stream
*s
, uint16_t checksum
,
2233 uint16_t rem_lifetime
)
2235 memcpy(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, &rem_lifetime
,
2236 sizeof(rem_lifetime
));
2237 memcpy(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, &checksum
, sizeof(checksum
));
2240 static void update_auth_hmac_md5(struct isis_auth
*auth
, struct stream
*s
,
2244 uint16_t checksum
, rem_lifetime
;
2247 safe_auth_md5(s
, &checksum
, &rem_lifetime
);
2249 memset(STREAM_DATA(s
) + auth
->offset
, 0, 16);
2250 hmac_md5(STREAM_DATA(s
), stream_get_endp(s
), auth
->passwd
,
2251 auth
->plength
, digest
);
2252 memcpy(auth
->value
, digest
, 16);
2253 memcpy(STREAM_DATA(s
) + auth
->offset
, digest
, 16);
2256 restore_auth_md5(s
, checksum
, rem_lifetime
);
2259 static void update_auth(struct isis_tlvs
*tlvs
, struct stream
*s
, bool is_lsp
)
2261 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
2263 for (struct isis_auth
*auth
= auth_head
; auth
; auth
= auth
->next
) {
2264 if (auth
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
2265 update_auth_hmac_md5(auth
, s
, is_lsp
);
2269 static int handle_pack_entry(struct pack_order_entry
*pe
,
2270 struct isis_tlvs
*tlvs
, struct stream
*stream
,
2271 struct isis_tlvs
**fragment_tlvs
,
2272 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2273 struct list
*new_fragment_arg
)
2277 if (pe
->how_to_pack
== ISIS_ITEMS
) {
2278 struct isis_item_list
*l
;
2279 l
= (struct isis_item_list
*)(((char *)tlvs
)
2280 + pe
->what_to_pack
);
2281 rv
= pack_items(pe
->context
, pe
->type
, l
, stream
, fragment_tlvs
,
2282 pe
, new_fragment
, new_fragment_arg
);
2284 struct isis_mt_item_list
*l
;
2285 l
= (struct isis_mt_item_list
*)(((char *)tlvs
)
2286 + pe
->what_to_pack
);
2287 rv
= pack_mt_items(pe
->context
, pe
->type
, l
, stream
,
2288 fragment_tlvs
, pe
, new_fragment
,
2295 static int pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
2296 struct isis_tlvs
*fragment_tlvs
,
2297 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2298 struct list
*new_fragment_arg
)
2302 /* When fragmenting, don't add auth as it's already accounted for in the
2303 * size we are given. */
2304 if (!fragment_tlvs
) {
2305 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
,
2306 &tlvs
->isis_auth
, stream
, NULL
, NULL
, NULL
,
2312 rv
= pack_tlv_protocols_supported(&tlvs
->protocols_supported
, stream
);
2315 if (fragment_tlvs
) {
2316 copy_tlv_protocols_supported(
2317 &tlvs
->protocols_supported
,
2318 &fragment_tlvs
->protocols_supported
);
2321 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2322 &tlvs
->area_addresses
, stream
, NULL
, NULL
, NULL
, NULL
);
2325 if (fragment_tlvs
) {
2326 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2327 &tlvs
->area_addresses
,
2328 &fragment_tlvs
->area_addresses
);
2332 if (tlvs
->mt_router_info_empty
) {
2333 if (STREAM_WRITEABLE(stream
) < 2)
2335 stream_putc(stream
, ISIS_TLV_MT_ROUTER_INFO
);
2336 stream_putc(stream
, 0);
2338 fragment_tlvs
->mt_router_info_empty
= true;
2340 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2341 &tlvs
->mt_router_info
, stream
, NULL
, NULL
, NULL
,
2345 if (fragment_tlvs
) {
2346 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2347 &tlvs
->mt_router_info
,
2348 &fragment_tlvs
->mt_router_info
);
2352 rv
= pack_tlv_dynamic_hostname(tlvs
->hostname
, stream
);
2356 fragment_tlvs
->hostname
=
2357 copy_tlv_dynamic_hostname(tlvs
->hostname
);
2359 rv
= pack_tlv_te_router_id(tlvs
->te_router_id
, stream
);
2362 if (fragment_tlvs
) {
2363 fragment_tlvs
->te_router_id
=
2364 copy_tlv_te_router_id(tlvs
->te_router_id
);
2367 for (size_t pack_idx
= 0; pack_idx
< array_size(pack_order
);
2369 rv
= handle_pack_entry(&pack_order
[pack_idx
], tlvs
, stream
,
2370 fragment_tlvs
? &fragment_tlvs
: NULL
,
2371 new_fragment
, new_fragment_arg
);
2380 int isis_pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
2381 size_t len_pointer
, bool pad
, bool is_lsp
)
2385 rv
= pack_tlvs(tlvs
, stream
, NULL
, NULL
, NULL
);
2390 add_padding(stream
);
2392 if (len_pointer
!= (size_t)-1) {
2393 stream_putw_at(stream
, len_pointer
, stream_get_endp(stream
));
2396 update_auth(tlvs
, stream
, is_lsp
);
2401 static struct isis_tlvs
*new_fragment(struct list
*l
)
2403 struct isis_tlvs
*rv
= isis_alloc_tlvs();
2405 listnode_add(l
, rv
);
2409 struct list
*isis_fragment_tlvs(struct isis_tlvs
*tlvs
, size_t size
)
2411 struct stream
*dummy_stream
= stream_new(size
);
2412 struct list
*rv
= list_new();
2413 struct isis_tlvs
*fragment_tlvs
= new_fragment(rv
);
2415 if (pack_tlvs(tlvs
, dummy_stream
, fragment_tlvs
, new_fragment
, rv
)) {
2416 struct listnode
*node
;
2417 for (ALL_LIST_ELEMENTS_RO(rv
, node
, fragment_tlvs
))
2418 isis_free_tlvs(fragment_tlvs
);
2419 list_delete_and_null(&rv
);
2422 stream_free(dummy_stream
);
2426 static int unpack_tlv_unknown(enum isis_tlv_context context
, uint8_t tlv_type
,
2427 uint8_t tlv_len
, struct stream
*s
,
2428 struct sbuf
*log
, int indent
)
2430 stream_forward_getp(s
, tlv_len
);
2431 sbuf_push(log
, indent
,
2432 "Skipping unknown TLV %" PRIu8
" (%" PRIu8
" bytes)\n",
2437 static int unpack_tlv(enum isis_tlv_context context
, size_t avail_len
,
2438 struct stream
*stream
, struct sbuf
*log
, void *dest
,
2441 uint8_t tlv_type
, tlv_len
;
2442 const struct tlv_ops
*ops
;
2444 sbuf_push(log
, indent
, "Unpacking TLV...\n");
2446 if (avail_len
< 2) {
2449 "Available data %zu too short to contain a TLV header.\n",
2454 tlv_type
= stream_getc(stream
);
2455 tlv_len
= stream_getc(stream
);
2457 sbuf_push(log
, indent
+ 2,
2458 "Found TLV of type %" PRIu8
" and len %" PRIu8
".\n",
2461 if (avail_len
< ((size_t)tlv_len
) + 2) {
2464 "Available data %zu too short for claimed TLV len %" PRIu8
2466 avail_len
- 2, tlv_len
);
2470 ops
= tlv_table
[context
][tlv_type
];
2471 if (ops
&& ops
->unpack
) {
2472 return ops
->unpack(context
, tlv_type
, tlv_len
, stream
, log
,
2476 return unpack_tlv_unknown(context
, tlv_type
, tlv_len
, stream
, log
,
2480 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
2481 struct stream
*stream
, struct sbuf
*log
, void *dest
,
2485 size_t tlv_start
, tlv_pos
;
2487 tlv_start
= stream_get_getp(stream
);
2490 sbuf_push(log
, indent
, "Unpacking %zu bytes of %s...\n", avail_len
,
2491 (context
== ISIS_CONTEXT_LSP
) ? "TLVs" : "sub-TLVs");
2493 while (tlv_pos
< avail_len
) {
2494 rv
= unpack_tlv(context
, avail_len
- tlv_pos
, stream
, log
, dest
,
2499 tlv_pos
= stream_get_getp(stream
) - tlv_start
;
2505 int isis_unpack_tlvs(size_t avail_len
, struct stream
*stream
,
2506 struct isis_tlvs
**dest
, const char **log
)
2508 static struct sbuf logbuf
;
2511 struct isis_tlvs
*result
;
2513 if (!sbuf_buf(&logbuf
))
2514 sbuf_init(&logbuf
, NULL
, 0);
2516 sbuf_reset(&logbuf
);
2517 if (avail_len
> STREAM_READABLE(stream
)) {
2518 sbuf_push(&logbuf
, indent
,
2519 "Stream doesn't contain sufficient data. "
2520 "Claimed %zu, available %zu\n",
2521 avail_len
, STREAM_READABLE(stream
));
2525 result
= isis_alloc_tlvs();
2526 rv
= unpack_tlvs(ISIS_CONTEXT_LSP
, avail_len
, stream
, &logbuf
, result
,
2529 *log
= sbuf_buf(&logbuf
);
2535 #define TLV_OPS(_name_, _desc_) \
2536 static const struct tlv_ops tlv_##_name_##_ops = { \
2537 .name = _desc_, .unpack = unpack_tlv_##_name_, \
2540 #define ITEM_TLV_OPS(_name_, _desc_) \
2541 static const struct tlv_ops tlv_##_name_##_ops = { \
2543 .unpack = unpack_tlv_with_items, \
2545 .pack_item = pack_item_##_name_, \
2546 .free_item = free_item_##_name_, \
2547 .unpack_item = unpack_item_##_name_, \
2548 .format_item = format_item_##_name_, \
2549 .copy_item = copy_item_##_name_}
2551 #define SUBTLV_OPS(_name_, _desc_) \
2552 static const struct tlv_ops subtlv_##_name_##_ops = { \
2553 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
2556 ITEM_TLV_OPS(area_address
, "TLV 1 Area Addresses");
2557 ITEM_TLV_OPS(oldstyle_reach
, "TLV 2 IS Reachability");
2558 ITEM_TLV_OPS(lan_neighbor
, "TLV 6 LAN Neighbors");
2559 ITEM_TLV_OPS(lsp_entry
, "TLV 9 LSP Entries");
2560 ITEM_TLV_OPS(auth
, "TLV 10 IS-IS Auth");
2561 ITEM_TLV_OPS(extended_reach
, "TLV 22 Extended Reachability");
2562 ITEM_TLV_OPS(oldstyle_ip_reach
, "TLV 128/130 IP Reachability");
2563 TLV_OPS(protocols_supported
, "TLV 129 Protocols Supported");
2564 ITEM_TLV_OPS(ipv4_address
, "TLV 132 IPv4 Interface Address");
2565 TLV_OPS(te_router_id
, "TLV 134 TE Router ID");
2566 ITEM_TLV_OPS(extended_ip_reach
, "TLV 135 Extended IP Reachability");
2567 TLV_OPS(dynamic_hostname
, "TLV 137 Dynamic Hostname");
2568 ITEM_TLV_OPS(mt_router_info
, "TLV 229 MT Router Information");
2569 ITEM_TLV_OPS(ipv6_address
, "TLV 232 IPv6 Interface Address");
2570 ITEM_TLV_OPS(ipv6_reach
, "TLV 236 IPv6 Reachability");
2572 SUBTLV_OPS(ipv6_source_prefix
, "Sub-TLV 22 IPv6 Source Prefix");
2574 static const struct tlv_ops
*tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
] =
2575 {[ISIS_CONTEXT_LSP
] =
2577 [ISIS_TLV_AREA_ADDRESSES
] =
2578 &tlv_area_address_ops
,
2579 [ISIS_TLV_OLDSTYLE_REACH
] =
2580 &tlv_oldstyle_reach_ops
,
2581 [ISIS_TLV_LAN_NEIGHBORS
] =
2582 &tlv_lan_neighbor_ops
,
2583 [ISIS_TLV_LSP_ENTRY
] = &tlv_lsp_entry_ops
,
2584 [ISIS_TLV_AUTH
] = &tlv_auth_ops
,
2585 [ISIS_TLV_EXTENDED_REACH
] =
2586 &tlv_extended_reach_ops
,
2587 [ISIS_TLV_MT_REACH
] = &tlv_extended_reach_ops
,
2588 [ISIS_TLV_OLDSTYLE_IP_REACH
] =
2589 &tlv_oldstyle_ip_reach_ops
,
2590 [ISIS_TLV_PROTOCOLS_SUPPORTED
] =
2591 &tlv_protocols_supported_ops
,
2592 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT
] =
2593 &tlv_oldstyle_ip_reach_ops
,
2594 [ISIS_TLV_IPV4_ADDRESS
] =
2595 &tlv_ipv4_address_ops
,
2596 [ISIS_TLV_TE_ROUTER_ID
] =
2597 &tlv_te_router_id_ops
,
2598 [ISIS_TLV_EXTENDED_IP_REACH
] =
2599 &tlv_extended_ip_reach_ops
,
2600 [ISIS_TLV_MT_IP_REACH
] =
2601 &tlv_extended_ip_reach_ops
,
2602 [ISIS_TLV_DYNAMIC_HOSTNAME
] =
2603 &tlv_dynamic_hostname_ops
,
2604 [ISIS_TLV_MT_ROUTER_INFO
] =
2605 &tlv_mt_router_info_ops
,
2606 [ISIS_TLV_IPV6_ADDRESS
] =
2607 &tlv_ipv6_address_ops
,
2608 [ISIS_TLV_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
2609 [ISIS_TLV_MT_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
2611 [ISIS_CONTEXT_SUBTLV_NE_REACH
] = {},
2612 [ISIS_CONTEXT_SUBTLV_IP_REACH
] = {},
2613 [ISIS_CONTEXT_SUBTLV_IPV6_REACH
] = {
2614 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX
] =
2615 &subtlv_ipv6_source_prefix_ops
,
2618 /* Accessor functions */
2620 void isis_tlvs_add_auth(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
)
2622 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
2623 init_item_list(&tlvs
->isis_auth
);
2625 if (passwd
->type
== ISIS_PASSWD_TYPE_UNUSED
)
2628 struct isis_auth
*auth
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*auth
));
2630 auth
->type
= passwd
->type
;
2632 auth
->plength
= passwd
->len
;
2633 memcpy(auth
->passwd
, passwd
->passwd
,
2634 MIN(sizeof(auth
->passwd
), sizeof(passwd
->passwd
)));
2636 if (auth
->type
== ISIS_PASSWD_TYPE_CLEARTXT
) {
2637 auth
->length
= passwd
->len
;
2638 memcpy(auth
->value
, passwd
->passwd
,
2639 MIN(sizeof(auth
->value
), sizeof(passwd
->passwd
)));
2642 append_item(&tlvs
->isis_auth
, (struct isis_item
*)auth
);
2645 void isis_tlvs_add_area_addresses(struct isis_tlvs
*tlvs
,
2646 struct list
*addresses
)
2648 struct listnode
*node
;
2649 struct area_addr
*area_addr
;
2651 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, area_addr
)) {
2652 struct isis_area_address
*a
=
2653 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
2655 a
->len
= area_addr
->addr_len
;
2656 memcpy(a
->addr
, area_addr
->area_addr
, 20);
2657 append_item(&tlvs
->area_addresses
, (struct isis_item
*)a
);
2661 void isis_tlvs_add_lan_neighbors(struct isis_tlvs
*tlvs
, struct list
*neighbors
)
2663 struct listnode
*node
;
2666 for (ALL_LIST_ELEMENTS_RO(neighbors
, node
, snpa
)) {
2667 struct isis_lan_neighbor
*n
=
2668 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*n
));
2670 memcpy(n
->mac
, snpa
, 6);
2671 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)n
);
2675 void isis_tlvs_set_protocols_supported(struct isis_tlvs
*tlvs
,
2676 struct nlpids
*nlpids
)
2678 tlvs
->protocols_supported
.count
= nlpids
->count
;
2679 if (tlvs
->protocols_supported
.protocols
)
2680 XFREE(MTYPE_ISIS_TLV
, tlvs
->protocols_supported
.protocols
);
2681 if (nlpids
->count
) {
2682 tlvs
->protocols_supported
.protocols
=
2683 XCALLOC(MTYPE_ISIS_TLV
, nlpids
->count
);
2684 memcpy(tlvs
->protocols_supported
.protocols
, nlpids
->nlpids
,
2687 tlvs
->protocols_supported
.protocols
= NULL
;
2691 void isis_tlvs_add_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
,
2692 bool overload
, bool attached
)
2694 struct isis_mt_router_info
*i
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*i
));
2696 i
->overload
= overload
;
2697 i
->attached
= attached
;
2699 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)i
);
2702 void isis_tlvs_add_ipv4_address(struct isis_tlvs
*tlvs
, struct in_addr
*addr
)
2704 struct isis_ipv4_address
*a
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
2706 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)a
);
2710 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs
*tlvs
,
2711 struct list
*addresses
)
2713 struct listnode
*node
;
2714 struct prefix_ipv4
*ip_addr
;
2715 unsigned int addr_count
= 0;
2717 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
2718 isis_tlvs_add_ipv4_address(tlvs
, &ip_addr
->prefix
);
2720 if (addr_count
>= 63)
2725 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs
*tlvs
,
2726 struct list
*addresses
)
2728 struct listnode
*node
;
2729 struct prefix_ipv6
*ip_addr
;
2731 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
2732 struct isis_ipv6_address
*a
=
2733 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
2735 a
->addr
= ip_addr
->prefix
;
2736 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)a
);
2740 typedef bool (*auth_validator_func
)(struct isis_passwd
*passwd
,
2741 struct stream
*stream
,
2742 struct isis_auth
*auth
, bool is_lsp
);
2744 static bool auth_validator_cleartxt(struct isis_passwd
*passwd
,
2745 struct stream
*stream
,
2746 struct isis_auth
*auth
, bool is_lsp
)
2748 return (auth
->length
== passwd
->len
2749 && !memcmp(auth
->value
, passwd
->passwd
, passwd
->len
));
2752 static bool auth_validator_hmac_md5(struct isis_passwd
*passwd
,
2753 struct stream
*stream
,
2754 struct isis_auth
*auth
, bool is_lsp
)
2758 uint16_t rem_lifetime
;
2761 safe_auth_md5(stream
, &checksum
, &rem_lifetime
);
2763 memset(STREAM_DATA(stream
) + auth
->offset
, 0, 16);
2764 hmac_md5(STREAM_DATA(stream
), stream_get_endp(stream
), passwd
->passwd
,
2765 passwd
->len
, digest
);
2766 memcpy(STREAM_DATA(stream
) + auth
->offset
, auth
->value
, 16);
2768 bool rv
= !memcmp(digest
, auth
->value
, 16);
2771 restore_auth_md5(stream
, checksum
, rem_lifetime
);
2776 static const auth_validator_func auth_validators
[] = {
2777 [ISIS_PASSWD_TYPE_CLEARTXT
] = auth_validator_cleartxt
,
2778 [ISIS_PASSWD_TYPE_HMAC_MD5
] = auth_validator_hmac_md5
,
2781 bool isis_tlvs_auth_is_valid(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
,
2782 struct stream
*stream
, bool is_lsp
)
2784 /* If no auth is set, always pass authentication */
2788 /* If we don't known how to validate the auth, return invalid */
2789 if (passwd
->type
>= array_size(auth_validators
)
2790 || !auth_validators
[passwd
->type
])
2793 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
2794 struct isis_auth
*auth
;
2795 for (auth
= auth_head
; auth
; auth
= auth
->next
) {
2796 if (auth
->type
== passwd
->type
)
2800 /* If matching auth TLV could not be found, return invalid */
2804 /* Perform validation and return result */
2805 return auth_validators
[passwd
->type
](passwd
, stream
, auth
, is_lsp
);
2808 bool isis_tlvs_area_addresses_match(struct isis_tlvs
*tlvs
,
2809 struct list
*addresses
)
2811 struct isis_area_address
*addr_head
;
2813 addr_head
= (struct isis_area_address
*)tlvs
->area_addresses
.head
;
2814 for (struct isis_area_address
*addr
= addr_head
; addr
;
2815 addr
= addr
->next
) {
2816 struct listnode
*node
;
2817 struct area_addr
*a
;
2819 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, a
)) {
2820 if (a
->addr_len
== addr
->len
2821 && !memcmp(a
->area_addr
, addr
->addr
, addr
->len
))
2829 static void tlvs_area_addresses_to_adj(struct isis_tlvs
*tlvs
,
2830 struct isis_adjacency
*adj
,
2833 if (adj
->area_address_count
!= tlvs
->area_addresses
.count
) {
2835 adj
->area_address_count
= tlvs
->area_addresses
.count
;
2836 adj
->area_addresses
= XREALLOC(
2837 MTYPE_ISIS_ADJACENCY_INFO
, adj
->area_addresses
,
2838 adj
->area_address_count
* sizeof(*adj
->area_addresses
));
2841 struct isis_area_address
*addr
= NULL
;
2842 for (unsigned int i
= 0; i
< tlvs
->area_addresses
.count
; i
++) {
2844 addr
= (struct isis_area_address
*)
2845 tlvs
->area_addresses
.head
;
2849 if (adj
->area_addresses
[i
].addr_len
== addr
->len
2850 && !memcmp(adj
->area_addresses
[i
].area_addr
, addr
->addr
,
2856 adj
->area_addresses
[i
].addr_len
= addr
->len
;
2857 memcpy(adj
->area_addresses
[i
].area_addr
, addr
->addr
, addr
->len
);
2861 static void tlvs_protocols_supported_to_adj(struct isis_tlvs
*tlvs
,
2862 struct isis_adjacency
*adj
,
2865 bool ipv4_supported
= false, ipv6_supported
= false;
2867 for (uint8_t i
= 0; i
< tlvs
->protocols_supported
.count
; i
++) {
2868 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IP
)
2869 ipv4_supported
= true;
2870 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IPV6
)
2871 ipv6_supported
= true;
2874 struct nlpids reduced
= {};
2876 if (ipv4_supported
&& ipv6_supported
) {
2878 reduced
.nlpids
[0] = NLPID_IP
;
2879 reduced
.nlpids
[1] = NLPID_IPV6
;
2880 } else if (ipv4_supported
) {
2882 reduced
.nlpids
[0] = NLPID_IP
;
2883 } else if (ipv6_supported
) {
2885 reduced
.nlpids
[1] = NLPID_IPV6
;
2890 if (adj
->nlpids
.count
== reduced
.count
2891 && !memcmp(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
))
2895 adj
->nlpids
.count
= reduced
.count
;
2896 memcpy(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
);
2899 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs
*tlvs
,
2900 struct isis_adjacency
*adj
,
2903 if (adj
->ipv4_address_count
!= tlvs
->ipv4_address
.count
) {
2905 adj
->ipv4_address_count
= tlvs
->ipv4_address
.count
;
2906 adj
->ipv4_addresses
= XREALLOC(
2907 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv4_addresses
,
2908 adj
->ipv4_address_count
* sizeof(*adj
->ipv4_addresses
));
2911 struct isis_ipv4_address
*addr
= NULL
;
2912 for (unsigned int i
= 0; i
< tlvs
->ipv4_address
.count
; i
++) {
2914 addr
= (struct isis_ipv4_address
*)
2915 tlvs
->ipv4_address
.head
;
2919 if (!memcmp(&adj
->ipv4_addresses
[i
], &addr
->addr
,
2920 sizeof(addr
->addr
)))
2924 adj
->ipv4_addresses
[i
] = addr
->addr
;
2928 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
2929 struct isis_adjacency
*adj
,
2932 if (adj
->ipv6_address_count
!= tlvs
->ipv6_address
.count
) {
2934 adj
->ipv6_address_count
= tlvs
->ipv6_address
.count
;
2935 adj
->ipv6_addresses
= XREALLOC(
2936 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv6_addresses
,
2937 adj
->ipv6_address_count
* sizeof(*adj
->ipv6_addresses
));
2940 struct isis_ipv6_address
*addr
= NULL
;
2941 for (unsigned int i
= 0; i
< tlvs
->ipv6_address
.count
; i
++) {
2943 addr
= (struct isis_ipv6_address
*)
2944 tlvs
->ipv6_address
.head
;
2948 if (!memcmp(&adj
->ipv6_addresses
[i
], &addr
->addr
,
2949 sizeof(addr
->addr
)))
2953 adj
->ipv6_addresses
[i
] = addr
->addr
;
2957 void isis_tlvs_to_adj(struct isis_tlvs
*tlvs
, struct isis_adjacency
*adj
,
2962 tlvs_area_addresses_to_adj(tlvs
, adj
, changed
);
2963 tlvs_protocols_supported_to_adj(tlvs
, adj
, changed
);
2964 tlvs_ipv4_addresses_to_adj(tlvs
, adj
, changed
);
2965 tlvs_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
2968 bool isis_tlvs_own_snpa_found(struct isis_tlvs
*tlvs
, uint8_t *snpa
)
2970 struct isis_lan_neighbor
*ne_head
;
2972 ne_head
= (struct isis_lan_neighbor
*)tlvs
->lan_neighbor
.head
;
2973 for (struct isis_lan_neighbor
*ne
= ne_head
; ne
; ne
= ne
->next
) {
2974 if (!memcmp(ne
->mac
, snpa
, ETH_ALEN
))
2981 void isis_tlvs_add_lsp_entry(struct isis_tlvs
*tlvs
, struct isis_lsp
*lsp
)
2983 struct isis_lsp_entry
*entry
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*entry
));
2985 entry
->rem_lifetime
= lsp
->hdr
.rem_lifetime
;
2986 memcpy(entry
->id
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 2);
2987 entry
->checksum
= lsp
->hdr
.checksum
;
2988 entry
->seqno
= lsp
->hdr
.seqno
;
2991 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)entry
);
2994 void isis_tlvs_add_csnp_entries(struct isis_tlvs
*tlvs
, uint8_t *start_id
,
2995 uint8_t *stop_id
, uint16_t num_lsps
,
2996 dict_t
*lspdb
, struct isis_lsp
**last_lsp
)
2998 dnode_t
*first
= dict_lower_bound(lspdb
, start_id
);
3002 dnode_t
*last
= dict_upper_bound(lspdb
, stop_id
);
3003 dnode_t
*curr
= first
;
3005 isis_tlvs_add_lsp_entry(tlvs
, first
->dict_data
);
3006 *last_lsp
= first
->dict_data
;
3009 curr
= dict_next(lspdb
, curr
);
3011 isis_tlvs_add_lsp_entry(tlvs
, curr
->dict_data
);
3012 *last_lsp
= curr
->dict_data
;
3014 if (curr
== last
|| tlvs
->lsp_entries
.count
== num_lsps
)
3019 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs
*tlvs
,
3020 const char *hostname
)
3022 XFREE(MTYPE_ISIS_TLV
, tlvs
->hostname
);
3024 tlvs
->hostname
= XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
3027 void isis_tlvs_set_te_router_id(struct isis_tlvs
*tlvs
,
3028 const struct in_addr
*id
)
3030 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id
);
3033 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
3034 memcpy(tlvs
->te_router_id
, id
, sizeof(*id
));
3037 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs
*tlvs
,
3038 struct prefix_ipv4
*dest
, uint8_t metric
)
3040 struct isis_oldstyle_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3043 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3044 apply_mask_ipv4(&r
->prefix
);
3045 append_item(&tlvs
->oldstyle_ip_reach
, (struct isis_item
*)r
);
3048 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs
*tlvs
,
3049 struct prefix_ipv4
*dest
, uint32_t metric
)
3051 struct isis_extended_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3054 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3055 apply_mask_ipv4(&r
->prefix
);
3056 append_item(&tlvs
->extended_ip_reach
, (struct isis_item
*)r
);
3059 void isis_tlvs_add_ipv6_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3060 struct prefix_ipv6
*dest
, uint32_t metric
)
3062 struct isis_ipv6_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3065 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3066 apply_mask_ipv6(&r
->prefix
);
3068 struct isis_item_list
*l
;
3069 l
= (mtid
== ISIS_MT_IPV4_UNICAST
)
3071 : isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
3072 append_item(l
, (struct isis_item
*)r
);
3075 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs
*tlvs
, uint8_t *id
,
3078 struct isis_oldstyle_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3081 memcpy(r
->id
, id
, sizeof(r
->id
));
3082 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)r
);
3085 void isis_tlvs_add_extended_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3086 uint8_t *id
, uint32_t metric
,
3087 uint8_t *subtlvs
, uint8_t subtlv_len
)
3089 struct isis_extended_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3091 memcpy(r
->id
, id
, sizeof(r
->id
));
3093 if (subtlvs
&& subtlv_len
) {
3094 r
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, subtlv_len
);
3095 memcpy(r
->subtlvs
, subtlvs
, subtlv_len
);
3096 r
->subtlv_len
= subtlv_len
;
3099 struct isis_item_list
*l
;
3100 if (mtid
== ISIS_MT_IPV4_UNICAST
)
3101 l
= &tlvs
->extended_reach
;
3103 l
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
3104 append_item(l
, (struct isis_item
*)r
);
3107 struct isis_mt_router_info
*
3108 isis_tlvs_lookup_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
)
3110 if (tlvs
->mt_router_info_empty
)
3113 struct isis_mt_router_info
*rv
;
3114 for (rv
= (struct isis_mt_router_info
*)tlvs
->mt_router_info
.head
; rv
;
3116 if (rv
->mtid
== mtid
)