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");
164 sbuf_push(log
, indent
,
165 "Not enough data left. (expected 1 or more bytes, got %" PRIu8
")\n",
170 p
.prefixlen
= stream_getc(s
);
171 if (p
.prefixlen
> 128) {
172 sbuf_push(log
, indent
, "Prefixlen %u is inplausible for IPv6\n",
177 if (tlv_len
!= 1 + PSIZE(p
.prefixlen
)) {
180 "TLV size differs from expected size for the prefixlen. "
181 "(expected %u but got %" PRIu8
")\n",
182 1 + PSIZE(p
.prefixlen
), tlv_len
);
186 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
188 if (subtlvs
->source_prefix
) {
191 "WARNING: source prefix Sub-TLV present multiple times.\n");
192 /* Ignore all but first occurrence of the source prefix Sub-TLV
197 subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(p
));
198 memcpy(subtlvs
->source_prefix
, &p
, sizeof(p
));
202 /* Functions related to subtlvs */
204 static struct isis_subtlvs
*isis_alloc_subtlvs(void)
206 struct isis_subtlvs
*result
;
208 result
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*result
));
213 static struct isis_subtlvs
*copy_subtlvs(struct isis_subtlvs
*subtlvs
)
218 struct isis_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
221 copy_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
);
225 static void format_subtlvs(struct isis_subtlvs
*subtlvs
, struct sbuf
*buf
,
228 format_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, buf
, indent
);
231 static void isis_free_subtlvs(struct isis_subtlvs
*subtlvs
)
236 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
->source_prefix
);
238 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
);
241 static int pack_subtlvs(struct isis_subtlvs
*subtlvs
, struct stream
*s
)
244 size_t subtlv_len_pos
= stream_get_endp(s
);
246 if (STREAM_WRITEABLE(s
) < 1)
249 stream_putc(s
, 0); /* Put 0 as subtlvs length, filled in later */
251 rv
= pack_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, s
);
255 size_t subtlv_len
= stream_get_endp(s
) - subtlv_len_pos
- 1;
256 if (subtlv_len
> 255)
259 stream_putc_at(s
, subtlv_len_pos
, subtlv_len
);
263 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
264 struct stream
*stream
, struct sbuf
*log
, void *dest
,
267 /* Functions related to TLVs 1 Area Addresses */
269 static struct isis_item
*copy_item_area_address(struct isis_item
*i
)
271 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
272 struct isis_area_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
275 memcpy(rv
->addr
, addr
->addr
, addr
->len
);
276 return (struct isis_item
*)rv
;
279 static void format_item_area_address(uint16_t mtid
, struct isis_item
*i
,
280 struct sbuf
*buf
, int indent
)
282 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
284 sbuf_push(buf
, indent
, "Area Address: %s\n",
285 isonet_print(addr
->addr
, addr
->len
));
288 static void free_item_area_address(struct isis_item
*i
)
290 XFREE(MTYPE_ISIS_TLV
, i
);
293 static int pack_item_area_address(struct isis_item
*i
, struct stream
*s
)
295 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
297 if (STREAM_WRITEABLE(s
) < (unsigned)1 + addr
->len
)
299 stream_putc(s
, addr
->len
);
300 stream_put(s
, addr
->addr
, addr
->len
);
304 static int unpack_item_area_address(uint16_t mtid
, uint8_t len
,
305 struct stream
*s
, struct sbuf
*log
,
306 void *dest
, int indent
)
308 struct isis_tlvs
*tlvs
= dest
;
309 struct isis_area_address
*rv
= NULL
;
311 sbuf_push(log
, indent
, "Unpack area address...\n");
315 "Not enough data left. (Expected 1 byte of address length, got %" PRIu8
321 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
322 rv
->len
= stream_getc(s
);
324 if (len
< 1 + rv
->len
) {
325 sbuf_push(log
, indent
, "Not enough data left. (Expected %" PRIu8
326 " bytes of address, got %" PRIu8
")\n",
331 if (rv
->len
< 1 || rv
->len
> 20) {
332 sbuf_push(log
, indent
,
333 "Implausible area address length %" PRIu8
"\n",
338 stream_get(rv
->addr
, s
, rv
->len
);
340 format_item_area_address(ISIS_MT_IPV4_UNICAST
, (struct isis_item
*)rv
,
342 append_item(&tlvs
->area_addresses
, (struct isis_item
*)rv
);
345 XFREE(MTYPE_ISIS_TLV
, rv
);
349 /* Functions related to TLV 2 (Old-Style) IS Reach */
350 static struct isis_item
*copy_item_oldstyle_reach(struct isis_item
*i
)
352 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
353 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
355 memcpy(rv
->id
, r
->id
, 7);
356 rv
->metric
= r
->metric
;
357 return (struct isis_item
*)rv
;
360 static void format_item_oldstyle_reach(uint16_t mtid
, struct isis_item
*i
,
361 struct sbuf
*buf
, int indent
)
363 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
365 sbuf_push(buf
, indent
, "IS Reachability: %s (Metric: %" PRIu8
")\n",
366 isis_format_id(r
->id
, 7), r
->metric
);
369 static void free_item_oldstyle_reach(struct isis_item
*i
)
371 XFREE(MTYPE_ISIS_TLV
, i
);
374 static int pack_item_oldstyle_reach(struct isis_item
*i
, struct stream
*s
)
376 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
378 if (STREAM_WRITEABLE(s
) < 11)
381 stream_putc(s
, r
->metric
);
382 stream_putc(s
, 0x80); /* delay metric - unsupported */
383 stream_putc(s
, 0x80); /* expense metric - unsupported */
384 stream_putc(s
, 0x80); /* error metric - unsupported */
385 stream_put(s
, r
->id
, 7);
390 static int unpack_item_oldstyle_reach(uint16_t mtid
, uint8_t len
,
391 struct stream
*s
, struct sbuf
*log
,
392 void *dest
, int indent
)
394 struct isis_tlvs
*tlvs
= dest
;
396 sbuf_push(log
, indent
, "Unpack oldstyle reach...\n");
400 "Not enough data left.(Expected 11 bytes of reach information, got %" PRIu8
406 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
407 rv
->metric
= stream_getc(s
);
408 if ((rv
->metric
& 0x3f) != rv
->metric
) {
409 sbuf_push(log
, indent
, "Metric has unplausible format\n");
412 stream_forward_getp(s
, 3); /* Skip other metrics */
413 stream_get(rv
->id
, s
, 7);
415 format_item_oldstyle_reach(mtid
, (struct isis_item
*)rv
, log
,
417 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)rv
);
421 /* Functions related to TLV 6 LAN Neighbors */
422 static struct isis_item
*copy_item_lan_neighbor(struct isis_item
*i
)
424 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
425 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
427 memcpy(rv
->mac
, n
->mac
, 6);
428 return (struct isis_item
*)rv
;
431 static void format_item_lan_neighbor(uint16_t mtid
, struct isis_item
*i
,
432 struct sbuf
*buf
, int indent
)
434 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
436 sbuf_push(buf
, indent
, "LAN Neighbor: %s\n", isis_format_id(n
->mac
, 6));
439 static void free_item_lan_neighbor(struct isis_item
*i
)
441 XFREE(MTYPE_ISIS_TLV
, i
);
444 static int pack_item_lan_neighbor(struct isis_item
*i
, struct stream
*s
)
446 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
448 if (STREAM_WRITEABLE(s
) < 6)
451 stream_put(s
, n
->mac
, 6);
456 static int unpack_item_lan_neighbor(uint16_t mtid
, uint8_t len
,
457 struct stream
*s
, struct sbuf
*log
,
458 void *dest
, int indent
)
460 struct isis_tlvs
*tlvs
= dest
;
462 sbuf_push(log
, indent
, "Unpack LAN neighbor...\n");
466 "Not enough data left.(Expected 6 bytes of mac, got %" PRIu8
472 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
473 stream_get(rv
->mac
, s
, 6);
475 format_item_lan_neighbor(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
476 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)rv
);
480 /* Functions related to TLV 9 LSP Entry */
481 static struct isis_item
*copy_item_lsp_entry(struct isis_item
*i
)
483 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
484 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
486 rv
->rem_lifetime
= e
->rem_lifetime
;
487 memcpy(rv
->id
, e
->id
, sizeof(rv
->id
));
488 rv
->seqno
= e
->seqno
;
489 rv
->checksum
= e
->checksum
;
491 return (struct isis_item
*)rv
;
494 static void format_item_lsp_entry(uint16_t mtid
, struct isis_item
*i
,
495 struct sbuf
*buf
, int indent
)
497 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
499 sbuf_push(buf
, indent
, "LSP Entry: %s, seq 0x%08" PRIx32
500 ", cksum 0x%04" PRIx16
", lifetime %" PRIu16
"s\n",
501 isis_format_id(e
->id
, 8), e
->seqno
, e
->checksum
,
505 static void free_item_lsp_entry(struct isis_item
*i
)
507 XFREE(MTYPE_ISIS_TLV
, i
);
510 static int pack_item_lsp_entry(struct isis_item
*i
, struct stream
*s
)
512 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
514 if (STREAM_WRITEABLE(s
) < 16)
517 stream_putw(s
, e
->rem_lifetime
);
518 stream_put(s
, e
->id
, 8);
519 stream_putl(s
, e
->seqno
);
520 stream_putw(s
, e
->checksum
);
525 static int unpack_item_lsp_entry(uint16_t mtid
, uint8_t len
, struct stream
*s
,
526 struct sbuf
*log
, void *dest
, int indent
)
528 struct isis_tlvs
*tlvs
= dest
;
530 sbuf_push(log
, indent
, "Unpack LSP entry...\n");
534 "Not enough data left. (Expected 16 bytes of LSP info, got %" PRIu8
,
539 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
540 rv
->rem_lifetime
= stream_getw(s
);
541 stream_get(rv
->id
, s
, 8);
542 rv
->seqno
= stream_getl(s
);
543 rv
->checksum
= stream_getw(s
);
545 format_item_lsp_entry(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
546 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)rv
);
550 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
552 static struct isis_item
*copy_item_extended_reach(struct isis_item
*i
)
554 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
555 struct isis_extended_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
557 memcpy(rv
->id
, r
->id
, 7);
558 rv
->metric
= r
->metric
;
560 if (r
->subtlvs
&& r
->subtlv_len
) {
561 rv
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, r
->subtlv_len
);
562 memcpy(rv
->subtlvs
, r
->subtlvs
, r
->subtlv_len
);
563 rv
->subtlv_len
= r
->subtlv_len
;
566 return (struct isis_item
*)rv
;
569 static void format_item_extended_reach(uint16_t mtid
, struct isis_item
*i
,
570 struct sbuf
*buf
, int indent
)
572 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
574 sbuf_push(buf
, indent
, "%s Reachability: %s (Metric: %u)",
575 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
576 isis_format_id(r
->id
, 7), r
->metric
);
577 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
578 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
579 sbuf_push(buf
, 0, "\n");
581 if (r
->subtlv_len
&& r
->subtlvs
)
582 mpls_te_print_detail(buf
, indent
+ 2, r
->subtlvs
, r
->subtlv_len
);
585 static void free_item_extended_reach(struct isis_item
*i
)
587 struct isis_extended_reach
*item
= (struct isis_extended_reach
*)i
;
588 XFREE(MTYPE_ISIS_TLV
, item
->subtlvs
);
589 XFREE(MTYPE_ISIS_TLV
, item
);
592 static int pack_item_extended_reach(struct isis_item
*i
, struct stream
*s
)
594 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
596 if (STREAM_WRITEABLE(s
) < 11 + (unsigned)r
->subtlv_len
)
598 stream_put(s
, r
->id
, sizeof(r
->id
));
599 stream_put3(s
, r
->metric
);
600 stream_putc(s
, r
->subtlv_len
);
601 stream_put(s
, r
->subtlvs
, r
->subtlv_len
);
605 static int unpack_item_extended_reach(uint16_t mtid
, uint8_t len
,
606 struct stream
*s
, struct sbuf
*log
,
607 void *dest
, int indent
)
609 struct isis_tlvs
*tlvs
= dest
;
610 struct isis_extended_reach
*rv
= NULL
;
612 struct isis_item_list
*items
;
614 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
615 items
= &tlvs
->extended_reach
;
617 items
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
620 sbuf_push(log
, indent
, "Unpacking %s reachability...\n",
621 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
624 sbuf_push(log
, indent
,
625 "Not enough data left. (expected 11 or more bytes, got %"
631 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
632 stream_get(rv
->id
, s
, 7);
633 rv
->metric
= stream_get3(s
);
634 subtlv_len
= stream_getc(s
);
636 format_item_extended_reach(mtid
, (struct isis_item
*)rv
, log
,
639 if ((size_t)len
< ((size_t)11) + subtlv_len
) {
640 sbuf_push(log
, indent
,
641 "Not enough data left for subtlv size %" PRIu8
642 ", there are only %" PRIu8
" bytes left.\n",
643 subtlv_len
, len
- 11);
647 sbuf_push(log
, indent
, "Storing %" PRIu8
" bytes of subtlvs\n",
651 size_t subtlv_start
= stream_get_getp(s
);
653 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_NE_REACH
, subtlv_len
, s
,
654 log
, NULL
, indent
+ 4)) {
658 stream_set_getp(s
, subtlv_start
);
660 rv
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, subtlv_len
);
661 stream_get(rv
->subtlvs
, s
, subtlv_len
);
662 rv
->subtlv_len
= subtlv_len
;
665 append_item(items
, (struct isis_item
*)rv
);
669 free_item_extended_reach((struct isis_item
*)rv
);
674 /* Functions related to TLV 128 (Old-Style) IP Reach */
675 static struct isis_item
*copy_item_oldstyle_ip_reach(struct isis_item
*i
)
677 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
678 struct isis_oldstyle_ip_reach
*rv
=
679 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
681 rv
->metric
= r
->metric
;
682 rv
->prefix
= r
->prefix
;
683 return (struct isis_item
*)rv
;
686 static void format_item_oldstyle_ip_reach(uint16_t mtid
, struct isis_item
*i
,
687 struct sbuf
*buf
, int indent
)
689 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
690 char prefixbuf
[PREFIX2STR_BUFFER
];
692 sbuf_push(buf
, indent
, "IP Reachability: %s (Metric: %" PRIu8
")\n",
693 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)), r
->metric
);
696 static void free_item_oldstyle_ip_reach(struct isis_item
*i
)
698 XFREE(MTYPE_ISIS_TLV
, i
);
701 static int pack_item_oldstyle_ip_reach(struct isis_item
*i
, struct stream
*s
)
703 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
705 if (STREAM_WRITEABLE(s
) < 12)
708 stream_putc(s
, r
->metric
);
709 stream_putc(s
, 0x80); /* delay metric - unsupported */
710 stream_putc(s
, 0x80); /* expense metric - unsupported */
711 stream_putc(s
, 0x80); /* error metric - unsupported */
712 stream_put(s
, &r
->prefix
.prefix
, 4);
715 masklen2ip(r
->prefix
.prefixlen
, &mask
);
716 stream_put(s
, &mask
, sizeof(mask
));
721 static int unpack_item_oldstyle_ip_reach(uint16_t mtid
, uint8_t len
,
722 struct stream
*s
, struct sbuf
*log
,
723 void *dest
, int indent
)
725 sbuf_push(log
, indent
, "Unpack oldstyle ip reach...\n");
729 "Not enough data left.(Expected 12 bytes of reach information, got %" PRIu8
735 struct isis_oldstyle_ip_reach
*rv
=
736 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
737 rv
->metric
= stream_getc(s
);
738 if ((rv
->metric
& 0x7f) != rv
->metric
) {
739 sbuf_push(log
, indent
, "Metric has unplausible format\n");
742 stream_forward_getp(s
, 3); /* Skip other metrics */
743 rv
->prefix
.family
= AF_INET
;
744 stream_get(&rv
->prefix
.prefix
, s
, 4);
747 stream_get(&mask
, s
, 4);
748 rv
->prefix
.prefixlen
= ip_masklen(mask
);
750 format_item_oldstyle_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
752 append_item(dest
, (struct isis_item
*)rv
);
757 /* Functions related to TLV 129 protocols supported */
759 static void copy_tlv_protocols_supported(struct isis_protocols_supported
*src
,
760 struct isis_protocols_supported
*dest
)
762 if (!src
->protocols
|| !src
->count
)
764 dest
->count
= src
->count
;
765 dest
->protocols
= XCALLOC(MTYPE_ISIS_TLV
, src
->count
);
766 memcpy(dest
->protocols
, src
->protocols
, src
->count
);
769 static void format_tlv_protocols_supported(struct isis_protocols_supported
*p
,
770 struct sbuf
*buf
, int indent
)
772 if (!p
|| !p
->count
|| !p
->protocols
)
775 sbuf_push(buf
, indent
, "Protocols Supported: ");
776 for (uint8_t i
= 0; i
< p
->count
; i
++) {
777 sbuf_push(buf
, 0, "%s%s", nlpid2str(p
->protocols
[i
]),
778 (i
+ 1 < p
->count
) ? ", " : "");
780 sbuf_push(buf
, 0, "\n");
783 static void free_tlv_protocols_supported(struct isis_protocols_supported
*p
)
785 XFREE(MTYPE_ISIS_TLV
, p
->protocols
);
788 static int pack_tlv_protocols_supported(struct isis_protocols_supported
*p
,
791 if (!p
|| !p
->count
|| !p
->protocols
)
794 if (STREAM_WRITEABLE(s
) < (unsigned)(p
->count
+ 2))
797 stream_putc(s
, ISIS_TLV_PROTOCOLS_SUPPORTED
);
798 stream_putc(s
, p
->count
);
799 stream_put(s
, p
->protocols
, p
->count
);
803 static int unpack_tlv_protocols_supported(enum isis_tlv_context context
,
804 uint8_t tlv_type
, uint8_t tlv_len
,
805 struct stream
*s
, struct sbuf
*log
,
806 void *dest
, int indent
)
808 struct isis_tlvs
*tlvs
= dest
;
810 sbuf_push(log
, indent
, "Unpacking Protocols Supported TLV...\n");
812 sbuf_push(log
, indent
, "WARNING: No protocols included\n");
815 if (tlvs
->protocols_supported
.protocols
) {
818 "WARNING: protocols supported TLV present multiple times.\n");
819 stream_forward_getp(s
, tlv_len
);
823 tlvs
->protocols_supported
.count
= tlv_len
;
824 tlvs
->protocols_supported
.protocols
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
);
825 stream_get(tlvs
->protocols_supported
.protocols
, s
, tlv_len
);
827 format_tlv_protocols_supported(&tlvs
->protocols_supported
, log
,
832 /* Functions related to TLV 132 IPv4 Interface addresses */
833 static struct isis_item
*copy_item_ipv4_address(struct isis_item
*i
)
835 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
836 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
839 return (struct isis_item
*)rv
;
842 static void format_item_ipv4_address(uint16_t mtid
, struct isis_item
*i
,
843 struct sbuf
*buf
, int indent
)
845 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
846 char addrbuf
[INET_ADDRSTRLEN
];
848 inet_ntop(AF_INET
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
849 sbuf_push(buf
, indent
, "IPv4 Interface Address: %s\n", addrbuf
);
852 static void free_item_ipv4_address(struct isis_item
*i
)
854 XFREE(MTYPE_ISIS_TLV
, i
);
857 static int pack_item_ipv4_address(struct isis_item
*i
, struct stream
*s
)
859 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
861 if (STREAM_WRITEABLE(s
) < 4)
864 stream_put(s
, &a
->addr
, 4);
869 static int unpack_item_ipv4_address(uint16_t mtid
, uint8_t len
,
870 struct stream
*s
, struct sbuf
*log
,
871 void *dest
, int indent
)
873 struct isis_tlvs
*tlvs
= dest
;
875 sbuf_push(log
, indent
, "Unpack IPv4 Interface address...\n");
879 "Not enough data left.(Expected 4 bytes of IPv4 address, got %" PRIu8
885 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
886 stream_get(&rv
->addr
, s
, 4);
888 format_item_ipv4_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
889 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)rv
);
894 /* Functions related to TLV 232 IPv6 Interface addresses */
895 static struct isis_item
*copy_item_ipv6_address(struct isis_item
*i
)
897 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
898 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
901 return (struct isis_item
*)rv
;
904 static void format_item_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
905 struct sbuf
*buf
, int indent
)
907 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
908 char addrbuf
[INET6_ADDRSTRLEN
];
910 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
911 sbuf_push(buf
, indent
, "IPv6 Interface Address: %s\n", addrbuf
);
914 static void free_item_ipv6_address(struct isis_item
*i
)
916 XFREE(MTYPE_ISIS_TLV
, i
);
919 static int pack_item_ipv6_address(struct isis_item
*i
, struct stream
*s
)
921 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
923 if (STREAM_WRITEABLE(s
) < 16)
926 stream_put(s
, &a
->addr
, 16);
931 static int unpack_item_ipv6_address(uint16_t mtid
, uint8_t len
,
932 struct stream
*s
, struct sbuf
*log
,
933 void *dest
, int indent
)
935 struct isis_tlvs
*tlvs
= dest
;
937 sbuf_push(log
, indent
, "Unpack IPv6 Interface address...\n");
941 "Not enough data left.(Expected 16 bytes of IPv6 address, got %" PRIu8
947 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
948 stream_get(&rv
->addr
, s
, 16);
950 format_item_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
951 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)rv
);
956 /* Functions related to TLV 229 MT Router information */
957 static struct isis_item
*copy_item_mt_router_info(struct isis_item
*i
)
959 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
960 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
962 rv
->overload
= info
->overload
;
963 rv
->attached
= info
->attached
;
964 rv
->mtid
= info
->mtid
;
965 return (struct isis_item
*)rv
;
968 static void format_item_mt_router_info(uint16_t mtid
, struct isis_item
*i
,
969 struct sbuf
*buf
, int indent
)
971 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
973 sbuf_push(buf
, indent
, "MT Router Info: %s%s%s\n",
974 isis_mtid2str(info
->mtid
),
975 info
->overload
? " Overload" : "",
976 info
->attached
? " Attached" : "");
979 static void free_item_mt_router_info(struct isis_item
*i
)
981 XFREE(MTYPE_ISIS_TLV
, i
);
984 static int pack_item_mt_router_info(struct isis_item
*i
, struct stream
*s
)
986 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
988 if (STREAM_WRITEABLE(s
) < 2)
991 uint16_t entry
= info
->mtid
;
994 entry
|= ISIS_MT_OL_MASK
;
996 entry
|= ISIS_MT_AT_MASK
;
998 stream_putw(s
, entry
);
1003 static int unpack_item_mt_router_info(uint16_t mtid
, uint8_t len
,
1004 struct stream
*s
, struct sbuf
*log
,
1005 void *dest
, int indent
)
1007 struct isis_tlvs
*tlvs
= dest
;
1009 sbuf_push(log
, indent
, "Unpack MT Router info...\n");
1013 "Not enough data left.(Expected 2 bytes of MT info, got %" PRIu8
1019 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1021 uint16_t entry
= stream_getw(s
);
1022 rv
->overload
= entry
& ISIS_MT_OL_MASK
;
1023 rv
->attached
= entry
& ISIS_MT_AT_MASK
;
1024 rv
->mtid
= entry
& ISIS_MT_MASK
;
1026 format_item_mt_router_info(mtid
, (struct isis_item
*)rv
, log
,
1028 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)rv
);
1032 /* Functions related to TLV 134 TE Router ID */
1034 static struct in_addr
*copy_tlv_te_router_id(const struct in_addr
*id
)
1039 struct in_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1040 memcpy(rv
, id
, sizeof(*rv
));
1044 static void format_tlv_te_router_id(const struct in_addr
*id
, struct sbuf
*buf
,
1050 char addrbuf
[INET_ADDRSTRLEN
];
1051 inet_ntop(AF_INET
, id
, addrbuf
, sizeof(addrbuf
));
1052 sbuf_push(buf
, indent
, "TE Router ID: %s\n", addrbuf
);
1055 static void free_tlv_te_router_id(struct in_addr
*id
)
1057 XFREE(MTYPE_ISIS_TLV
, id
);
1060 static int pack_tlv_te_router_id(const struct in_addr
*id
, struct stream
*s
)
1065 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
1068 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID
);
1070 stream_put(s
, id
, 4);
1074 static int unpack_tlv_te_router_id(enum isis_tlv_context context
,
1075 uint8_t tlv_type
, uint8_t tlv_len
,
1076 struct stream
*s
, struct sbuf
*log
,
1077 void *dest
, int indent
)
1079 struct isis_tlvs
*tlvs
= dest
;
1081 sbuf_push(log
, indent
, "Unpacking TE Router ID TLV...\n");
1083 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
1087 if (tlvs
->te_router_id
) {
1088 sbuf_push(log
, indent
,
1089 "WARNING: TE Router ID present multiple times.\n");
1090 stream_forward_getp(s
, tlv_len
);
1094 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, 4);
1095 stream_get(tlvs
->te_router_id
, s
, 4);
1096 format_tlv_te_router_id(tlvs
->te_router_id
, log
, indent
+ 2);
1101 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
1103 static struct isis_item
*copy_item_extended_ip_reach(struct isis_item
*i
)
1105 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1106 struct isis_extended_ip_reach
*rv
=
1107 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1109 rv
->metric
= r
->metric
;
1111 rv
->prefix
= r
->prefix
;
1113 return (struct isis_item
*)rv
;
1116 static void format_item_extended_ip_reach(uint16_t mtid
, struct isis_item
*i
,
1117 struct sbuf
*buf
, int indent
)
1119 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1120 char prefixbuf
[PREFIX2STR_BUFFER
];
1122 sbuf_push(buf
, indent
, "%s IP Reachability: %s (Metric: %u)%s",
1123 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
1124 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)), r
->metric
,
1125 r
->down
? " Down" : "");
1126 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1127 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1128 sbuf_push(buf
, 0, "\n");
1131 static void free_item_extended_ip_reach(struct isis_item
*i
)
1133 struct isis_extended_ip_reach
*item
=
1134 (struct isis_extended_ip_reach
*)i
;
1135 XFREE(MTYPE_ISIS_TLV
, item
);
1138 static int pack_item_extended_ip_reach(struct isis_item
*i
, struct stream
*s
)
1140 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1143 if (STREAM_WRITEABLE(s
) < 5)
1145 stream_putl(s
, r
->metric
);
1147 control
= r
->down
? ISIS_EXTENDED_IP_REACH_DOWN
: 0;
1148 control
|= r
->prefix
.prefixlen
;
1149 stream_putc(s
, control
);
1151 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
))
1153 stream_put(s
, &r
->prefix
.prefix
.s_addr
, PSIZE(r
->prefix
.prefixlen
));
1157 static int unpack_item_extended_ip_reach(uint16_t mtid
, uint8_t len
,
1158 struct stream
*s
, struct sbuf
*log
,
1159 void *dest
, int indent
)
1161 struct isis_tlvs
*tlvs
= dest
;
1162 struct isis_extended_ip_reach
*rv
= NULL
;
1164 uint8_t control
, subtlv_len
;
1165 struct isis_item_list
*items
;
1167 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1168 items
= &tlvs
->extended_ip_reach
;
1170 items
= isis_get_mt_items(&tlvs
->mt_ip_reach
, mtid
);
1173 sbuf_push(log
, indent
, "Unpacking %s IPv4 reachability...\n",
1174 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
1177 if (len
< consume
) {
1178 sbuf_push(log
, indent
,
1179 "Not enough data left. (expected 5 or more bytes, got %" PRIu8
")\n",
1184 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1186 rv
->metric
= stream_getl(s
);
1187 control
= stream_getc(s
);
1188 rv
->down
= (control
& ISIS_EXTENDED_IP_REACH_DOWN
);
1189 rv
->prefix
.family
= AF_INET
;
1190 rv
->prefix
.prefixlen
= control
& 0x3f;
1191 if (rv
->prefix
.prefixlen
> 32) {
1192 sbuf_push(log
, indent
, "Prefixlen %u is inplausible for IPv4\n",
1193 rv
->prefix
.prefixlen
);
1197 consume
+= PSIZE(rv
->prefix
.prefixlen
);
1198 if (len
< consume
) {
1199 sbuf_push(log
, indent
,
1200 "Expected %u bytes of prefix, but only %u bytes available.\n",
1201 PSIZE(rv
->prefix
.prefixlen
), len
- 5);
1204 stream_get(&rv
->prefix
.prefix
.s_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
1205 in_addr_t orig_prefix
= rv
->prefix
.prefix
.s_addr
;
1206 apply_mask_ipv4(&rv
->prefix
);
1207 if (orig_prefix
!= rv
->prefix
.prefix
.s_addr
)
1208 sbuf_push(log
, indent
+ 2,
1209 "WARNING: Prefix had hostbits set.\n");
1210 format_item_extended_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
1213 if (control
& ISIS_EXTENDED_IP_REACH_SUBTLV
) {
1215 if (len
< consume
) {
1216 sbuf_push(log
, indent
,
1217 "Expected 1 byte of subtlv len, but no more data present.\n");
1220 subtlv_len
= stream_getc(s
);
1223 sbuf_push(log
, indent
+ 2,
1224 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
1226 consume
+= subtlv_len
;
1227 if (len
< consume
) {
1228 sbuf_push(log
, indent
,
1230 " bytes of subtlvs, but only %u bytes available.\n",
1232 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
1235 sbuf_push(log
, indent
, "Skipping %" PRIu8
" bytes of subvls",
1237 stream_forward_getp(s
, subtlv_len
);
1240 append_item(items
, (struct isis_item
*)rv
);
1244 free_item_extended_ip_reach((struct isis_item
*)rv
);
1248 /* Functions related to TLV 137 Dynamic Hostname */
1250 static char *copy_tlv_dynamic_hostname(const char *hostname
)
1255 return XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
1258 static void format_tlv_dynamic_hostname(const char *hostname
, struct sbuf
*buf
,
1264 sbuf_push(buf
, indent
, "Hostname: %s\n", hostname
);
1267 static void free_tlv_dynamic_hostname(char *hostname
)
1269 XFREE(MTYPE_ISIS_TLV
, hostname
);
1272 static int pack_tlv_dynamic_hostname(const char *hostname
, struct stream
*s
)
1277 uint8_t name_len
= strlen(hostname
);
1279 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + name_len
))
1282 stream_putc(s
, ISIS_TLV_DYNAMIC_HOSTNAME
);
1283 stream_putc(s
, name_len
);
1284 stream_put(s
, hostname
, name_len
);
1288 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context
,
1289 uint8_t tlv_type
, uint8_t tlv_len
,
1290 struct stream
*s
, struct sbuf
*log
,
1291 void *dest
, int indent
)
1293 struct isis_tlvs
*tlvs
= dest
;
1295 sbuf_push(log
, indent
, "Unpacking Dynamic Hostname TLV...\n");
1297 sbuf_push(log
, indent
, "WARNING: No hostname included\n");
1301 if (tlvs
->hostname
) {
1302 sbuf_push(log
, indent
,
1303 "WARNING: Hostname present multiple times.\n");
1304 stream_forward_getp(s
, tlv_len
);
1308 tlvs
->hostname
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
+ 1);
1309 stream_get(tlvs
->hostname
, s
, tlv_len
);
1310 tlvs
->hostname
[tlv_len
] = '\0';
1313 for (uint8_t i
= 0; i
< tlv_len
; i
++) {
1314 if ((unsigned char)tlvs
->hostname
[i
] > 127
1315 || !isprint(tlvs
->hostname
[i
])) {
1317 tlvs
->hostname
[i
] = '?';
1323 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
1329 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
1331 static struct isis_item
*copy_item_ipv6_reach(struct isis_item
*i
)
1333 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1334 struct isis_ipv6_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1335 rv
->metric
= r
->metric
;
1337 rv
->external
= r
->external
;
1338 rv
->prefix
= r
->prefix
;
1339 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
1341 return (struct isis_item
*)rv
;
1344 static void format_item_ipv6_reach(uint16_t mtid
, struct isis_item
*i
,
1345 struct sbuf
*buf
, int indent
)
1347 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1348 char prefixbuf
[PREFIX2STR_BUFFER
];
1350 sbuf_push(buf
, indent
, "%sIPv6 Reachability: %s (Metric: %u)%s%s",
1351 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "MT ",
1352 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
1354 r
->down
? " Down" : "",
1355 r
->external
? " External" : "");
1356 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1357 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1358 sbuf_push(buf
, 0, "\n");
1361 sbuf_push(buf
, indent
, " Subtlvs:\n");
1362 format_subtlvs(r
->subtlvs
, buf
, indent
+ 4);
1366 static void free_item_ipv6_reach(struct isis_item
*i
)
1368 struct isis_ipv6_reach
*item
= (struct isis_ipv6_reach
*)i
;
1370 isis_free_subtlvs(item
->subtlvs
);
1371 XFREE(MTYPE_ISIS_TLV
, item
);
1374 static int pack_item_ipv6_reach(struct isis_item
*i
, struct stream
*s
)
1376 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1379 if (STREAM_WRITEABLE(s
) < 6)
1381 stream_putl(s
, r
->metric
);
1383 control
= r
->down
? ISIS_IPV6_REACH_DOWN
: 0;
1384 control
|= r
->external
? ISIS_IPV6_REACH_EXTERNAL
: 0;
1385 control
|= r
->subtlvs
? ISIS_IPV6_REACH_SUBTLV
: 0;
1387 stream_putc(s
, control
);
1388 stream_putc(s
, r
->prefix
.prefixlen
);
1390 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
))
1392 stream_put(s
, &r
->prefix
.prefix
.s6_addr
, PSIZE(r
->prefix
.prefixlen
));
1395 return pack_subtlvs(r
->subtlvs
, s
);
1400 static int unpack_item_ipv6_reach(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1401 struct sbuf
*log
, void *dest
, int indent
)
1403 struct isis_tlvs
*tlvs
= dest
;
1404 struct isis_ipv6_reach
*rv
= NULL
;
1406 uint8_t control
, subtlv_len
;
1407 struct isis_item_list
*items
;
1409 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1410 items
= &tlvs
->ipv6_reach
;
1412 items
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
1415 sbuf_push(log
, indent
, "Unpacking %sIPv6 reachability...\n",
1416 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "mt ");
1418 if (len
< consume
) {
1419 sbuf_push(log
, indent
,
1420 "Not enough data left. (expected 6 or more bytes, got %"
1426 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1428 rv
->metric
= stream_getl(s
);
1429 control
= stream_getc(s
);
1430 rv
->down
= (control
& ISIS_IPV6_REACH_DOWN
);
1431 rv
->external
= (control
& ISIS_IPV6_REACH_EXTERNAL
);
1433 rv
->prefix
.family
= AF_INET6
;
1434 rv
->prefix
.prefixlen
= stream_getc(s
);
1435 if (rv
->prefix
.prefixlen
> 128) {
1436 sbuf_push(log
, indent
, "Prefixlen %u is inplausible for IPv6\n",
1437 rv
->prefix
.prefixlen
);
1441 consume
+= PSIZE(rv
->prefix
.prefixlen
);
1442 if (len
< consume
) {
1443 sbuf_push(log
, indent
,
1444 "Expected %u bytes of prefix, but only %u bytes available.\n",
1445 PSIZE(rv
->prefix
.prefixlen
), len
- 6);
1448 stream_get(&rv
->prefix
.prefix
.s6_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
1449 struct in6_addr orig_prefix
= rv
->prefix
.prefix
;
1450 apply_mask_ipv6(&rv
->prefix
);
1451 if (memcmp(&orig_prefix
, &rv
->prefix
.prefix
, sizeof(orig_prefix
)))
1452 sbuf_push(log
, indent
+ 2,
1453 "WARNING: Prefix had hostbits set.\n");
1454 format_item_ipv6_reach(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1456 if (control
& ISIS_IPV6_REACH_SUBTLV
) {
1458 if (len
< consume
) {
1459 sbuf_push(log
, indent
,
1460 "Expected 1 byte of subtlv len, but no more data persent.\n");
1463 subtlv_len
= stream_getc(s
);
1466 sbuf_push(log
, indent
+ 2,
1467 " WARNING: subtlv bit set, but there are no subtlvs.\n");
1469 consume
+= subtlv_len
;
1470 if (len
< consume
) {
1471 sbuf_push(log
, indent
,
1473 " bytes of subtlvs, but only %u bytes available.\n",
1475 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
1479 rv
->subtlvs
= isis_alloc_subtlvs();
1480 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
, subtlv_len
, s
,
1481 log
, rv
->subtlvs
, indent
+ 4)) {
1486 append_item(items
, (struct isis_item
*)rv
);
1490 free_item_ipv6_reach((struct isis_item
*)rv
);
1494 /* Functions related to TLV 10 Authentication */
1495 static struct isis_item
*copy_item_auth(struct isis_item
*i
)
1497 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1498 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1500 rv
->type
= auth
->type
;
1501 rv
->length
= auth
->length
;
1502 memcpy(rv
->value
, auth
->value
, sizeof(rv
->value
));
1503 return (struct isis_item
*)rv
;
1506 static void format_item_auth(uint16_t mtid
, struct isis_item
*i
,
1507 struct sbuf
*buf
, int indent
)
1509 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1512 sbuf_push(buf
, indent
, "Authentication:\n");
1513 switch (auth
->type
) {
1514 case ISIS_PASSWD_TYPE_CLEARTXT
:
1515 zlog_sanitize(obuf
, sizeof(obuf
), auth
->value
, auth
->length
);
1516 sbuf_push(buf
, indent
, " Password: %s\n", obuf
);
1518 case ISIS_PASSWD_TYPE_HMAC_MD5
:
1519 for (unsigned int i
= 0; i
< 16; i
++) {
1520 snprintf(obuf
+ 2 * i
, sizeof(obuf
) - 2 * i
,
1521 "%02" PRIx8
, auth
->value
[i
]);
1523 sbuf_push(buf
, indent
, " HMAC-MD5: %s\n", obuf
);
1526 sbuf_push(buf
, indent
, " Unknown (%" PRIu8
")\n", auth
->type
);
1531 static void free_item_auth(struct isis_item
*i
)
1533 XFREE(MTYPE_ISIS_TLV
, i
);
1536 static int pack_item_auth(struct isis_item
*i
, struct stream
*s
)
1538 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1540 if (STREAM_WRITEABLE(s
) < 1)
1542 stream_putc(s
, auth
->type
);
1544 switch (auth
->type
) {
1545 case ISIS_PASSWD_TYPE_CLEARTXT
:
1546 if (STREAM_WRITEABLE(s
) < auth
->length
)
1548 stream_put(s
, auth
->passwd
, auth
->length
);
1550 case ISIS_PASSWD_TYPE_HMAC_MD5
:
1551 if (STREAM_WRITEABLE(s
) < 16)
1553 auth
->offset
= stream_get_endp(s
);
1554 stream_put(s
, NULL
, 16);
1563 static int unpack_item_auth(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1564 struct sbuf
*log
, void *dest
, int indent
)
1566 struct isis_tlvs
*tlvs
= dest
;
1568 sbuf_push(log
, indent
, "Unpack Auth TLV...\n");
1572 "Not enough data left.(Expected 1 bytes of auth type, got %" PRIu8
1578 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1580 rv
->type
= stream_getc(s
);
1581 rv
->length
= len
- 1;
1583 if (rv
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
&& rv
->length
!= 16) {
1586 "Unexpected auth length for HMAC-MD5 (expected 16, got %" PRIu8
1589 XFREE(MTYPE_ISIS_TLV
, rv
);
1593 rv
->offset
= stream_get_getp(s
);
1594 stream_get(rv
->value
, s
, rv
->length
);
1595 format_item_auth(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1596 append_item(&tlvs
->isis_auth
, (struct isis_item
*)rv
);
1600 /* Functions relating to item TLVs */
1602 static void init_item_list(struct isis_item_list
*items
)
1605 items
->tail
= &items
->head
;
1609 static struct isis_item
*copy_item(enum isis_tlv_context context
,
1610 enum isis_tlv_type type
,
1611 struct isis_item
*item
)
1613 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
1615 if (ops
&& ops
->copy_item
)
1616 return ops
->copy_item(item
);
1618 assert(!"Unknown item tlv type!");
1622 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1623 struct isis_item_list
*src
, struct isis_item_list
*dest
)
1625 struct isis_item
*item
;
1627 init_item_list(dest
);
1629 for (item
= src
->head
; item
; item
= item
->next
) {
1630 append_item(dest
, copy_item(context
, type
, item
));
1634 static void format_item(uint16_t mtid
, enum isis_tlv_context context
,
1635 enum isis_tlv_type type
, struct isis_item
*i
,
1636 struct sbuf
*buf
, int indent
)
1638 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
1640 if (ops
&& ops
->format_item
) {
1641 ops
->format_item(mtid
, i
, buf
, indent
);
1645 assert(!"Unknown item tlv type!");
1648 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
1649 enum isis_tlv_type type
, struct isis_item_list
*items
,
1650 struct sbuf
*buf
, int indent
)
1652 struct isis_item
*i
;
1654 for (i
= items
->head
; i
; i
= i
->next
)
1655 format_item(mtid
, context
, type
, i
, buf
, indent
);
1657 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1659 static void free_item(enum isis_tlv_context tlv_context
,
1660 enum isis_tlv_type tlv_type
, struct isis_item
*item
)
1662 const struct tlv_ops
*ops
= tlv_table
[tlv_context
][tlv_type
];
1664 if (ops
&& ops
->free_item
) {
1665 ops
->free_item(item
);
1669 assert(!"Unknown item tlv type!");
1672 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1673 struct isis_item_list
*items
)
1675 struct isis_item
*item
, *next_item
;
1677 for (item
= items
->head
; item
; item
= next_item
) {
1678 next_item
= item
->next
;
1679 free_item(context
, type
, item
);
1683 static int pack_item(enum isis_tlv_context context
, enum isis_tlv_type type
,
1684 struct isis_item
*i
, struct stream
*s
,
1685 struct isis_tlvs
**fragment_tlvs
,
1686 struct pack_order_entry
*pe
, uint16_t mtid
)
1688 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
1690 if (ops
&& ops
->pack_item
) {
1691 return ops
->pack_item(i
, s
);
1694 assert(!"Unknown item tlv type!");
1698 static void add_item_to_fragment(struct isis_item
*i
, struct pack_order_entry
*pe
,
1699 struct isis_tlvs
*fragment_tlvs
, uint16_t mtid
)
1701 struct isis_item_list
*l
;
1703 if (pe
->how_to_pack
== ISIS_ITEMS
) {
1704 l
= (struct isis_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
1706 struct isis_mt_item_list
*m
;
1707 m
= (struct isis_mt_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
1708 l
= isis_get_mt_items(m
, mtid
);
1711 append_item(l
, copy_item(pe
->context
, pe
->type
, i
));
1714 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
1715 enum isis_tlv_type type
, struct isis_item_list
*items
,
1716 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
1717 struct pack_order_entry
*pe
,
1718 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
1719 struct list
*new_fragment_arg
)
1721 size_t len_pos
, last_len
, len
;
1722 struct isis_item
*item
= NULL
;
1729 if (STREAM_WRITEABLE(s
) < 2)
1732 stream_putc(s
, type
);
1733 len_pos
= stream_get_endp(s
);
1734 stream_putc(s
, 0); /* Put 0 as length for now */
1736 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(type
)
1737 && mtid
!= ISIS_MT_IPV4_UNICAST
) {
1738 if (STREAM_WRITEABLE(s
) < 2)
1740 stream_putw(s
, mtid
);
1743 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_OLDSTYLE_REACH
) {
1744 if (STREAM_WRITEABLE(s
) < 1)
1746 stream_putc(s
, 0); /* Virtual flag is set to 0 */
1750 for (item
= item
? item
: items
->head
; item
; item
= item
->next
) {
1751 rv
= pack_item(context
, type
, item
, s
, fragment_tlvs
, pe
, mtid
);
1755 len
= stream_get_endp(s
) - len_pos
- 1;
1757 /* Multiple auths don't go into one TLV, so always break */
1758 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_AUTH
) {
1764 if (!last_len
) /* strange, not a single item fit */
1766 /* drop last tlv, otherwise, its too long */
1767 stream_set_endp(s
, len_pos
+ 1 + last_len
);
1773 add_item_to_fragment(item
, pe
, *fragment_tlvs
, mtid
);
1778 stream_putc_at(s
, len_pos
, len
);
1787 *fragment_tlvs
= new_fragment(new_fragment_arg
);
1790 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1792 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
)
1795 dest
->tail
= &(*dest
->tail
)->next
;
1799 static int unpack_item(uint16_t mtid
, enum isis_tlv_context context
,
1800 uint8_t tlv_type
, uint8_t len
, struct stream
*s
,
1801 struct sbuf
*log
, void *dest
, int indent
)
1803 const struct tlv_ops
*ops
= tlv_table
[context
][tlv_type
];
1805 if (ops
&& ops
->unpack_item
)
1806 return ops
->unpack_item(mtid
, len
, s
, log
, dest
, indent
);
1808 assert(!"Unknown item tlv type!");
1809 sbuf_push(log
, indent
, "Unknown item tlv type!\n");
1813 static int unpack_tlv_with_items(enum isis_tlv_context context
,
1814 uint8_t tlv_type
, uint8_t tlv_len
,
1815 struct stream
*s
, struct sbuf
*log
, void *dest
,
1823 tlv_start
= stream_get_getp(s
);
1826 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(tlv_type
)) {
1828 sbuf_push(log
, indent
,
1829 "TLV is too short to contain MTID\n");
1832 mtid
= stream_getw(s
) & ISIS_MT_MASK
;
1834 sbuf_push(log
, indent
, "Unpacking as MT %s item TLV...\n",
1835 isis_mtid2str(mtid
));
1837 sbuf_push(log
, indent
, "Unpacking as item TLV...\n");
1838 mtid
= ISIS_MT_IPV4_UNICAST
;
1841 if (context
== ISIS_CONTEXT_LSP
1842 && tlv_type
== ISIS_TLV_OLDSTYLE_REACH
) {
1843 if (tlv_len
- tlv_pos
< 1) {
1844 sbuf_push(log
, indent
,
1845 "TLV is too short for old style reach\n");
1848 stream_forward_getp(s
, 1);
1852 if (context
== ISIS_CONTEXT_LSP
1853 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH
) {
1854 struct isis_tlvs
*tlvs
= dest
;
1855 dest
= &tlvs
->oldstyle_ip_reach
;
1856 } else if (context
== ISIS_CONTEXT_LSP
1857 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH_EXT
) {
1858 struct isis_tlvs
*tlvs
= dest
;
1859 dest
= &tlvs
->oldstyle_ip_reach_ext
;
1862 if (context
== ISIS_CONTEXT_LSP
1863 && tlv_type
== ISIS_TLV_MT_ROUTER_INFO
) {
1864 struct isis_tlvs
*tlvs
= dest
;
1865 tlvs
->mt_router_info_empty
= (tlv_pos
>= (size_t)tlv_len
);
1868 while (tlv_pos
< (size_t)tlv_len
) {
1869 rv
= unpack_item(mtid
, context
, tlv_type
, tlv_len
- tlv_pos
, s
,
1870 log
, dest
, indent
+ 2);
1874 tlv_pos
= stream_get_getp(s
) - tlv_start
;
1880 /* Functions to manipulate mt_item_lists */
1882 static int isis_mt_item_list_cmp(const struct isis_item_list
*a
,
1883 const struct isis_item_list
*b
)
1885 if (a
->mtid
< b
->mtid
)
1887 if (a
->mtid
> b
->mtid
)
1892 RB_PROTOTYPE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
1893 RB_GENERATE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
1895 struct isis_item_list
*isis_get_mt_items(struct isis_mt_item_list
*m
,
1898 struct isis_item_list
*rv
;
1900 rv
= isis_lookup_mt_items(m
, mtid
);
1902 rv
= XCALLOC(MTYPE_ISIS_MT_ITEM_LIST
, sizeof(*rv
));
1905 RB_INSERT(isis_mt_item_list
, m
, rv
);
1911 struct isis_item_list
*isis_lookup_mt_items(struct isis_mt_item_list
*m
,
1914 struct isis_item_list key
= {.mtid
= mtid
};
1916 return RB_FIND(isis_mt_item_list
, m
, &key
);
1919 static void free_mt_items(enum isis_tlv_context context
,
1920 enum isis_tlv_type type
, struct isis_mt_item_list
*m
)
1922 struct isis_item_list
*n
, *nnext
;
1924 RB_FOREACH_SAFE (n
, isis_mt_item_list
, m
, nnext
) {
1925 free_items(context
, type
, n
);
1926 RB_REMOVE(isis_mt_item_list
, m
, n
);
1927 XFREE(MTYPE_ISIS_MT_ITEM_LIST
, n
);
1931 static void format_mt_items(enum isis_tlv_context context
,
1932 enum isis_tlv_type type
,
1933 struct isis_mt_item_list
*m
, struct sbuf
*buf
,
1936 struct isis_item_list
*n
;
1938 RB_FOREACH (n
, isis_mt_item_list
, m
) {
1939 format_items_(n
->mtid
, context
, type
, n
, buf
, indent
);
1943 static int pack_mt_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1944 struct isis_mt_item_list
*m
, struct stream
*s
,
1945 struct isis_tlvs
**fragment_tlvs
,
1946 struct pack_order_entry
*pe
,
1947 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
1948 struct list
*new_fragment_arg
)
1950 struct isis_item_list
*n
;
1952 RB_FOREACH (n
, isis_mt_item_list
, m
) {
1955 rv
= pack_items_(n
->mtid
, context
, type
, n
, s
, fragment_tlvs
,
1956 pe
, new_fragment
, new_fragment_arg
);
1964 static void copy_mt_items(enum isis_tlv_context context
,
1965 enum isis_tlv_type type
,
1966 struct isis_mt_item_list
*src
,
1967 struct isis_mt_item_list
*dest
)
1969 struct isis_item_list
*n
;
1971 RB_INIT(isis_mt_item_list
, dest
);
1973 RB_FOREACH (n
, isis_mt_item_list
, src
) {
1974 copy_items(context
, type
, n
, isis_get_mt_items(dest
, n
->mtid
));
1978 /* Functions related to tlvs in general */
1980 struct isis_tlvs
*isis_alloc_tlvs(void)
1982 struct isis_tlvs
*result
;
1984 result
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*result
));
1986 init_item_list(&result
->isis_auth
);
1987 init_item_list(&result
->area_addresses
);
1988 init_item_list(&result
->mt_router_info
);
1989 init_item_list(&result
->oldstyle_reach
);
1990 init_item_list(&result
->lan_neighbor
);
1991 init_item_list(&result
->lsp_entries
);
1992 init_item_list(&result
->extended_reach
);
1993 RB_INIT(isis_mt_item_list
, &result
->mt_reach
);
1994 init_item_list(&result
->oldstyle_ip_reach
);
1995 init_item_list(&result
->oldstyle_ip_reach_ext
);
1996 init_item_list(&result
->ipv4_address
);
1997 init_item_list(&result
->ipv6_address
);
1998 init_item_list(&result
->extended_ip_reach
);
1999 RB_INIT(isis_mt_item_list
, &result
->mt_ip_reach
);
2000 init_item_list(&result
->ipv6_reach
);
2001 RB_INIT(isis_mt_item_list
, &result
->mt_ipv6_reach
);
2006 struct isis_tlvs
*isis_copy_tlvs(struct isis_tlvs
*tlvs
)
2008 struct isis_tlvs
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2010 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
,
2013 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2014 &tlvs
->area_addresses
, &rv
->area_addresses
);
2016 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2017 &tlvs
->mt_router_info
, &rv
->mt_router_info
);
2019 tlvs
->mt_router_info_empty
= rv
->mt_router_info_empty
;
2021 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2022 &tlvs
->oldstyle_reach
, &rv
->oldstyle_reach
);
2024 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2025 &tlvs
->lan_neighbor
, &rv
->lan_neighbor
);
2027 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
2030 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2031 &tlvs
->extended_reach
, &rv
->extended_reach
);
2033 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
2036 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2037 &tlvs
->oldstyle_ip_reach
, &rv
->oldstyle_ip_reach
);
2039 copy_tlv_protocols_supported(&tlvs
->protocols_supported
,
2040 &rv
->protocols_supported
);
2042 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2043 &tlvs
->oldstyle_ip_reach_ext
, &rv
->oldstyle_ip_reach_ext
);
2045 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
, &tlvs
->ipv4_address
,
2048 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
, &tlvs
->ipv6_address
,
2051 rv
->te_router_id
= copy_tlv_te_router_id(tlvs
->te_router_id
);
2053 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2054 &tlvs
->extended_ip_reach
, &rv
->extended_ip_reach
);
2056 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2057 &tlvs
->mt_ip_reach
, &rv
->mt_ip_reach
);
2059 rv
->hostname
= copy_tlv_dynamic_hostname(tlvs
->hostname
);
2061 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
2064 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2065 &tlvs
->mt_ipv6_reach
, &rv
->mt_ipv6_reach
);
2070 static void format_tlvs(struct isis_tlvs
*tlvs
, struct sbuf
*buf
, int indent
)
2072 format_tlv_protocols_supported(&tlvs
->protocols_supported
, buf
, indent
);
2074 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
, buf
,
2077 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2078 &tlvs
->area_addresses
, buf
, indent
);
2080 if (tlvs
->mt_router_info_empty
) {
2081 sbuf_push(buf
, indent
, "MT Router Info: None\n");
2083 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2084 &tlvs
->mt_router_info
, buf
, indent
);
2087 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2088 &tlvs
->oldstyle_reach
, buf
, indent
);
2090 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2091 &tlvs
->lan_neighbor
, buf
, indent
);
2093 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
2096 format_tlv_dynamic_hostname(tlvs
->hostname
, buf
, indent
);
2097 format_tlv_te_router_id(tlvs
->te_router_id
, buf
, indent
);
2099 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2100 &tlvs
->extended_reach
, buf
, indent
);
2102 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
2105 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2106 &tlvs
->oldstyle_ip_reach
, buf
, indent
);
2108 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2109 &tlvs
->oldstyle_ip_reach_ext
, buf
, indent
);
2111 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
2112 &tlvs
->ipv4_address
, buf
, indent
);
2114 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
2115 &tlvs
->ipv6_address
, buf
, indent
);
2117 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2118 &tlvs
->extended_ip_reach
, buf
, indent
);
2120 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2121 &tlvs
->mt_ip_reach
, buf
, indent
);
2123 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
2126 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2127 &tlvs
->mt_ipv6_reach
, buf
, indent
);
2130 const char *isis_format_tlvs(struct isis_tlvs
*tlvs
)
2132 static struct sbuf buf
;
2134 if (!sbuf_buf(&buf
))
2135 sbuf_init(&buf
, NULL
, 0);
2138 format_tlvs(tlvs
, &buf
, 0);
2139 return sbuf_buf(&buf
);
2142 void isis_free_tlvs(struct isis_tlvs
*tlvs
)
2147 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
2148 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2149 &tlvs
->area_addresses
);
2150 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2151 &tlvs
->mt_router_info
);
2152 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2153 &tlvs
->oldstyle_reach
);
2154 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2155 &tlvs
->lan_neighbor
);
2156 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
);
2157 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2158 &tlvs
->extended_reach
);
2159 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
);
2160 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2161 &tlvs
->oldstyle_ip_reach
);
2162 free_tlv_protocols_supported(&tlvs
->protocols_supported
);
2163 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2164 &tlvs
->oldstyle_ip_reach_ext
);
2165 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
2166 &tlvs
->ipv4_address
);
2167 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
2168 &tlvs
->ipv6_address
);
2169 free_tlv_te_router_id(tlvs
->te_router_id
);
2170 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2171 &tlvs
->extended_ip_reach
);
2172 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2173 &tlvs
->mt_ip_reach
);
2174 free_tlv_dynamic_hostname(tlvs
->hostname
);
2175 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
);
2176 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2177 &tlvs
->mt_ipv6_reach
);
2179 XFREE(MTYPE_ISIS_TLV
, tlvs
);
2182 static void add_padding(struct stream
*s
)
2184 while (STREAM_WRITEABLE(s
)) {
2185 if (STREAM_WRITEABLE(s
) == 1)
2187 uint32_t padding_len
= STREAM_WRITEABLE(s
) - 2;
2189 if (padding_len
> 255) {
2190 if (padding_len
== 256)
2196 stream_putc(s
, ISIS_TLV_PADDING
);
2197 stream_putc(s
, padding_len
);
2198 stream_put(s
, NULL
, padding_len
);
2202 #define LSP_REM_LIFETIME_OFF 10
2203 #define LSP_CHECKSUM_OFF 24
2204 static void safe_auth_md5(struct stream
*s
, uint16_t *checksum
,
2205 uint16_t *rem_lifetime
)
2207 memcpy(rem_lifetime
, STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
,
2208 sizeof(*rem_lifetime
));
2209 memset(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, 0, sizeof(*rem_lifetime
));
2210 memcpy(checksum
, STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, sizeof(*checksum
));
2211 memset(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, 0, sizeof(*checksum
));
2214 static void restore_auth_md5(struct stream
*s
, uint16_t checksum
,
2215 uint16_t rem_lifetime
)
2217 memcpy(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, &rem_lifetime
,
2218 sizeof(rem_lifetime
));
2219 memcpy(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, &checksum
, sizeof(checksum
));
2222 static void update_auth_hmac_md5(struct isis_auth
*auth
, struct stream
*s
,
2226 uint16_t checksum
, rem_lifetime
;
2229 safe_auth_md5(s
, &checksum
, &rem_lifetime
);
2231 memset(STREAM_DATA(s
) + auth
->offset
, 0, 16);
2232 hmac_md5(STREAM_DATA(s
), stream_get_endp(s
), auth
->passwd
,
2233 auth
->plength
, digest
);
2234 memcpy(auth
->value
, digest
, 16);
2235 memcpy(STREAM_DATA(s
) + auth
->offset
, digest
, 16);
2238 restore_auth_md5(s
, checksum
, rem_lifetime
);
2241 static void update_auth(struct isis_tlvs
*tlvs
, struct stream
*s
, bool is_lsp
)
2243 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
2245 for (struct isis_auth
*auth
= auth_head
; auth
; auth
= auth
->next
) {
2246 if (auth
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
2247 update_auth_hmac_md5(auth
, s
, is_lsp
);
2251 static int handle_pack_entry(struct pack_order_entry
*pe
,
2252 struct isis_tlvs
*tlvs
, struct stream
*stream
,
2253 struct isis_tlvs
**fragment_tlvs
,
2254 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2255 struct list
*new_fragment_arg
)
2259 if (pe
->how_to_pack
== ISIS_ITEMS
) {
2260 struct isis_item_list
*l
;
2261 l
= (struct isis_item_list
*)(((char *)tlvs
)
2262 + pe
->what_to_pack
);
2263 rv
= pack_items(pe
->context
, pe
->type
, l
, stream
, fragment_tlvs
,
2264 pe
, new_fragment
, new_fragment_arg
);
2266 struct isis_mt_item_list
*l
;
2267 l
= (struct isis_mt_item_list
*)(((char *)tlvs
)
2268 + pe
->what_to_pack
);
2269 rv
= pack_mt_items(pe
->context
, pe
->type
, l
, stream
,
2270 fragment_tlvs
, pe
, new_fragment
,
2277 static int pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
2278 struct isis_tlvs
*fragment_tlvs
,
2279 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2280 struct list
*new_fragment_arg
)
2284 /* When fragmenting, don't add auth as it's already accounted for in the
2285 * size we are given. */
2286 if (!fragment_tlvs
) {
2287 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
,
2288 stream
, NULL
, NULL
, NULL
, NULL
);
2293 rv
= pack_tlv_protocols_supported(&tlvs
->protocols_supported
, stream
);
2296 if (fragment_tlvs
) {
2297 copy_tlv_protocols_supported(
2298 &tlvs
->protocols_supported
,
2299 &fragment_tlvs
->protocols_supported
);
2302 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2303 &tlvs
->area_addresses
, stream
, NULL
, NULL
, NULL
, NULL
);
2306 if (fragment_tlvs
) {
2307 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2308 &tlvs
->area_addresses
,
2309 &fragment_tlvs
->area_addresses
);
2313 if (tlvs
->mt_router_info_empty
) {
2314 if (STREAM_WRITEABLE(stream
) < 2)
2316 stream_putc(stream
, ISIS_TLV_MT_ROUTER_INFO
);
2317 stream_putc(stream
, 0);
2319 fragment_tlvs
->mt_router_info_empty
= true;
2321 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2322 &tlvs
->mt_router_info
, stream
, NULL
, NULL
, NULL
,
2326 if (fragment_tlvs
) {
2327 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2328 &tlvs
->mt_router_info
,
2329 &fragment_tlvs
->mt_router_info
);
2333 rv
= pack_tlv_dynamic_hostname(tlvs
->hostname
, stream
);
2337 fragment_tlvs
->hostname
=
2338 copy_tlv_dynamic_hostname(tlvs
->hostname
);
2340 rv
= pack_tlv_te_router_id(tlvs
->te_router_id
, stream
);
2343 if (fragment_tlvs
) {
2344 fragment_tlvs
->te_router_id
=
2345 copy_tlv_te_router_id(tlvs
->te_router_id
);
2348 for (size_t pack_idx
= 0; pack_idx
< array_size(pack_order
);
2350 rv
= handle_pack_entry(&pack_order
[pack_idx
], tlvs
, stream
,
2351 fragment_tlvs
? &fragment_tlvs
: NULL
,
2352 new_fragment
, new_fragment_arg
);
2361 int isis_pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
2362 size_t len_pointer
, bool pad
, bool is_lsp
)
2366 rv
= pack_tlvs(tlvs
, stream
, NULL
, NULL
, NULL
);
2371 add_padding(stream
);
2373 if (len_pointer
!= (size_t)-1) {
2374 stream_putw_at(stream
, len_pointer
, stream_get_endp(stream
));
2377 update_auth(tlvs
, stream
, is_lsp
);
2382 static struct isis_tlvs
*new_fragment(struct list
*l
)
2384 struct isis_tlvs
*rv
= isis_alloc_tlvs();
2386 listnode_add(l
, rv
);
2390 struct list
*isis_fragment_tlvs(struct isis_tlvs
*tlvs
, size_t size
)
2392 struct stream
*dummy_stream
= stream_new(size
);
2393 struct list
*rv
= list_new();
2394 struct isis_tlvs
*fragment_tlvs
= new_fragment(rv
);
2396 if (pack_tlvs(tlvs
, dummy_stream
, fragment_tlvs
, new_fragment
, rv
)) {
2397 struct listnode
*node
;
2398 for (ALL_LIST_ELEMENTS_RO(rv
, node
, fragment_tlvs
))
2399 isis_free_tlvs(fragment_tlvs
);
2404 stream_free(dummy_stream
);
2408 static int unpack_tlv_unknown(enum isis_tlv_context context
, uint8_t tlv_type
,
2409 uint8_t tlv_len
, struct stream
*s
,
2410 struct sbuf
*log
, int indent
)
2412 stream_forward_getp(s
, tlv_len
);
2413 sbuf_push(log
, indent
,
2414 "Skipping unknown TLV %" PRIu8
" (%" PRIu8
" bytes)\n",
2419 static int unpack_tlv(enum isis_tlv_context context
, size_t avail_len
,
2420 struct stream
*stream
, struct sbuf
*log
, void *dest
,
2423 uint8_t tlv_type
, tlv_len
;
2424 const struct tlv_ops
*ops
;
2426 sbuf_push(log
, indent
, "Unpacking TLV...\n");
2428 if (avail_len
< 2) {
2431 "Available data %zu too short to contain a TLV header.\n",
2436 tlv_type
= stream_getc(stream
);
2437 tlv_len
= stream_getc(stream
);
2439 sbuf_push(log
, indent
+ 2,
2440 "Found TLV of type %" PRIu8
" and len %" PRIu8
".\n",
2443 if (avail_len
< ((size_t)tlv_len
) + 2) {
2444 sbuf_push(log
, indent
+ 2,
2445 "Available data %zu too short for claimed TLV len %" PRIu8
".\n",
2446 avail_len
- 2, tlv_len
);
2450 ops
= tlv_table
[context
][tlv_type
];
2451 if (ops
&& ops
->unpack
) {
2452 return ops
->unpack(context
, tlv_type
, tlv_len
, stream
, log
,
2456 return unpack_tlv_unknown(context
, tlv_type
, tlv_len
, stream
, log
,
2460 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
2461 struct stream
*stream
, struct sbuf
*log
, void *dest
,
2465 size_t tlv_start
, tlv_pos
;
2467 tlv_start
= stream_get_getp(stream
);
2470 sbuf_push(log
, indent
, "Unpacking %zu bytes of %s...\n", avail_len
,
2471 (context
== ISIS_CONTEXT_LSP
) ? "TLVs" : "sub-TLVs");
2473 while (tlv_pos
< avail_len
) {
2474 rv
= unpack_tlv(context
, avail_len
- tlv_pos
, stream
, log
, dest
,
2479 tlv_pos
= stream_get_getp(stream
) - tlv_start
;
2485 int isis_unpack_tlvs(size_t avail_len
, struct stream
*stream
,
2486 struct isis_tlvs
**dest
, const char **log
)
2488 static struct sbuf logbuf
;
2491 struct isis_tlvs
*result
;
2493 if (!sbuf_buf(&logbuf
))
2494 sbuf_init(&logbuf
, NULL
, 0);
2496 sbuf_reset(&logbuf
);
2497 if (avail_len
> STREAM_READABLE(stream
)) {
2498 sbuf_push(&logbuf
, indent
,
2499 "Stream doesn't contain sufficient data. "
2500 "Claimed %zu, available %zu\n",
2501 avail_len
, STREAM_READABLE(stream
));
2505 result
= isis_alloc_tlvs();
2506 rv
= unpack_tlvs(ISIS_CONTEXT_LSP
, avail_len
, stream
, &logbuf
, result
,
2509 *log
= sbuf_buf(&logbuf
);
2515 #define TLV_OPS(_name_, _desc_) \
2516 static const struct tlv_ops tlv_##_name_##_ops = { \
2517 .name = _desc_, .unpack = unpack_tlv_##_name_, \
2520 #define ITEM_TLV_OPS(_name_, _desc_) \
2521 static const struct tlv_ops tlv_##_name_##_ops = { \
2523 .unpack = unpack_tlv_with_items, \
2525 .pack_item = pack_item_##_name_, \
2526 .free_item = free_item_##_name_, \
2527 .unpack_item = unpack_item_##_name_, \
2528 .format_item = format_item_##_name_, \
2529 .copy_item = copy_item_##_name_}
2531 #define SUBTLV_OPS(_name_, _desc_) \
2532 static const struct tlv_ops subtlv_##_name_##_ops = { \
2533 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
2536 ITEM_TLV_OPS(area_address
, "TLV 1 Area Addresses");
2537 ITEM_TLV_OPS(oldstyle_reach
, "TLV 2 IS Reachability");
2538 ITEM_TLV_OPS(lan_neighbor
, "TLV 6 LAN Neighbors");
2539 ITEM_TLV_OPS(lsp_entry
, "TLV 9 LSP Entries");
2540 ITEM_TLV_OPS(auth
, "TLV 10 IS-IS Auth");
2541 ITEM_TLV_OPS(extended_reach
, "TLV 22 Extended Reachability");
2542 ITEM_TLV_OPS(oldstyle_ip_reach
, "TLV 128/130 IP Reachability");
2543 TLV_OPS(protocols_supported
, "TLV 129 Protocols Supported");
2544 ITEM_TLV_OPS(ipv4_address
, "TLV 132 IPv4 Interface Address");
2545 TLV_OPS(te_router_id
, "TLV 134 TE Router ID");
2546 ITEM_TLV_OPS(extended_ip_reach
, "TLV 135 Extended IP Reachability");
2547 TLV_OPS(dynamic_hostname
, "TLV 137 Dynamic Hostname");
2548 ITEM_TLV_OPS(mt_router_info
, "TLV 229 MT Router Information");
2549 ITEM_TLV_OPS(ipv6_address
, "TLV 232 IPv6 Interface Address");
2550 ITEM_TLV_OPS(ipv6_reach
, "TLV 236 IPv6 Reachability");
2552 SUBTLV_OPS(ipv6_source_prefix
, "Sub-TLV 22 IPv6 Source Prefix");
2554 static const struct tlv_ops
*tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
] = {
2555 [ISIS_CONTEXT_LSP
] = {
2556 [ISIS_TLV_AREA_ADDRESSES
] = &tlv_area_address_ops
,
2557 [ISIS_TLV_OLDSTYLE_REACH
] = &tlv_oldstyle_reach_ops
,
2558 [ISIS_TLV_LAN_NEIGHBORS
] = &tlv_lan_neighbor_ops
,
2559 [ISIS_TLV_LSP_ENTRY
] = &tlv_lsp_entry_ops
,
2560 [ISIS_TLV_AUTH
] = &tlv_auth_ops
,
2561 [ISIS_TLV_EXTENDED_REACH
] = &tlv_extended_reach_ops
,
2562 [ISIS_TLV_MT_REACH
] = &tlv_extended_reach_ops
,
2563 [ISIS_TLV_OLDSTYLE_IP_REACH
] = &tlv_oldstyle_ip_reach_ops
,
2564 [ISIS_TLV_PROTOCOLS_SUPPORTED
] = &tlv_protocols_supported_ops
,
2565 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT
] = &tlv_oldstyle_ip_reach_ops
,
2566 [ISIS_TLV_IPV4_ADDRESS
] = &tlv_ipv4_address_ops
,
2567 [ISIS_TLV_TE_ROUTER_ID
] = &tlv_te_router_id_ops
,
2568 [ISIS_TLV_EXTENDED_IP_REACH
] = &tlv_extended_ip_reach_ops
,
2569 [ISIS_TLV_MT_IP_REACH
] = &tlv_extended_ip_reach_ops
,
2570 [ISIS_TLV_DYNAMIC_HOSTNAME
] = &tlv_dynamic_hostname_ops
,
2571 [ISIS_TLV_MT_ROUTER_INFO
] = &tlv_mt_router_info_ops
,
2572 [ISIS_TLV_IPV6_ADDRESS
] = &tlv_ipv6_address_ops
,
2573 [ISIS_TLV_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
2574 [ISIS_TLV_MT_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
2576 [ISIS_CONTEXT_SUBTLV_NE_REACH
] = {},
2577 [ISIS_CONTEXT_SUBTLV_IP_REACH
] = {},
2578 [ISIS_CONTEXT_SUBTLV_IPV6_REACH
] = {
2579 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX
] = &subtlv_ipv6_source_prefix_ops
,
2583 /* Accessor functions */
2585 void isis_tlvs_add_auth(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
)
2587 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
2588 init_item_list(&tlvs
->isis_auth
);
2590 if (passwd
->type
== ISIS_PASSWD_TYPE_UNUSED
)
2593 struct isis_auth
*auth
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*auth
));
2595 auth
->type
= passwd
->type
;
2597 auth
->plength
= passwd
->len
;
2598 memcpy(auth
->passwd
, passwd
->passwd
,
2599 MIN(sizeof(auth
->passwd
), sizeof(passwd
->passwd
)));
2601 if (auth
->type
== ISIS_PASSWD_TYPE_CLEARTXT
) {
2602 auth
->length
= passwd
->len
;
2603 memcpy(auth
->value
, passwd
->passwd
,
2604 MIN(sizeof(auth
->value
), sizeof(passwd
->passwd
)));
2607 append_item(&tlvs
->isis_auth
, (struct isis_item
*)auth
);
2610 void isis_tlvs_add_area_addresses(struct isis_tlvs
*tlvs
,
2611 struct list
*addresses
)
2613 struct listnode
*node
;
2614 struct area_addr
*area_addr
;
2616 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, area_addr
)) {
2617 struct isis_area_address
*a
=
2618 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
2620 a
->len
= area_addr
->addr_len
;
2621 memcpy(a
->addr
, area_addr
->area_addr
, 20);
2622 append_item(&tlvs
->area_addresses
, (struct isis_item
*)a
);
2626 void isis_tlvs_add_lan_neighbors(struct isis_tlvs
*tlvs
, struct list
*neighbors
)
2628 struct listnode
*node
;
2631 for (ALL_LIST_ELEMENTS_RO(neighbors
, node
, snpa
)) {
2632 struct isis_lan_neighbor
*n
=
2633 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*n
));
2635 memcpy(n
->mac
, snpa
, 6);
2636 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)n
);
2640 void isis_tlvs_set_protocols_supported(struct isis_tlvs
*tlvs
,
2641 struct nlpids
*nlpids
)
2643 tlvs
->protocols_supported
.count
= nlpids
->count
;
2644 if (tlvs
->protocols_supported
.protocols
)
2645 XFREE(MTYPE_ISIS_TLV
, tlvs
->protocols_supported
.protocols
);
2646 if (nlpids
->count
) {
2647 tlvs
->protocols_supported
.protocols
=
2648 XCALLOC(MTYPE_ISIS_TLV
, nlpids
->count
);
2649 memcpy(tlvs
->protocols_supported
.protocols
, nlpids
->nlpids
,
2652 tlvs
->protocols_supported
.protocols
= NULL
;
2656 void isis_tlvs_add_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
,
2657 bool overload
, bool attached
)
2659 struct isis_mt_router_info
*i
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*i
));
2661 i
->overload
= overload
;
2662 i
->attached
= attached
;
2664 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)i
);
2667 void isis_tlvs_add_ipv4_address(struct isis_tlvs
*tlvs
, struct in_addr
*addr
)
2669 struct isis_ipv4_address
*a
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
2671 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)a
);
2675 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs
*tlvs
,
2676 struct list
*addresses
)
2678 struct listnode
*node
;
2679 struct prefix_ipv4
*ip_addr
;
2680 unsigned int addr_count
= 0;
2682 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
2683 isis_tlvs_add_ipv4_address(tlvs
, &ip_addr
->prefix
);
2685 if (addr_count
>= 63)
2690 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs
*tlvs
,
2691 struct list
*addresses
)
2693 struct listnode
*node
;
2694 struct prefix_ipv6
*ip_addr
;
2696 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
2697 struct isis_ipv6_address
*a
=
2698 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
2700 a
->addr
= ip_addr
->prefix
;
2701 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)a
);
2705 typedef bool (*auth_validator_func
)(struct isis_passwd
*passwd
,
2706 struct stream
*stream
,
2707 struct isis_auth
*auth
, bool is_lsp
);
2709 static bool auth_validator_cleartxt(struct isis_passwd
*passwd
,
2710 struct stream
*stream
,
2711 struct isis_auth
*auth
, bool is_lsp
)
2713 return (auth
->length
== passwd
->len
2714 && !memcmp(auth
->value
, passwd
->passwd
, passwd
->len
));
2717 static bool auth_validator_hmac_md5(struct isis_passwd
*passwd
,
2718 struct stream
*stream
,
2719 struct isis_auth
*auth
, bool is_lsp
)
2723 uint16_t rem_lifetime
;
2726 safe_auth_md5(stream
, &checksum
, &rem_lifetime
);
2728 memset(STREAM_DATA(stream
) + auth
->offset
, 0, 16);
2729 hmac_md5(STREAM_DATA(stream
), stream_get_endp(stream
), passwd
->passwd
,
2730 passwd
->len
, digest
);
2731 memcpy(STREAM_DATA(stream
) + auth
->offset
, auth
->value
, 16);
2733 bool rv
= !memcmp(digest
, auth
->value
, 16);
2736 restore_auth_md5(stream
, checksum
, rem_lifetime
);
2741 static const auth_validator_func auth_validators
[] = {
2742 [ISIS_PASSWD_TYPE_CLEARTXT
] = auth_validator_cleartxt
,
2743 [ISIS_PASSWD_TYPE_HMAC_MD5
] = auth_validator_hmac_md5
,
2746 bool isis_tlvs_auth_is_valid(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
,
2747 struct stream
*stream
, bool is_lsp
)
2749 /* If no auth is set, always pass authentication */
2753 /* If we don't known how to validate the auth, return invalid */
2754 if (passwd
->type
>= array_size(auth_validators
)
2755 || !auth_validators
[passwd
->type
])
2758 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
2759 struct isis_auth
*auth
;
2760 for (auth
= auth_head
; auth
; auth
= auth
->next
) {
2761 if (auth
->type
== passwd
->type
)
2765 /* If matching auth TLV could not be found, return invalid */
2769 /* Perform validation and return result */
2770 return auth_validators
[passwd
->type
](passwd
, stream
, auth
, is_lsp
);
2773 bool isis_tlvs_area_addresses_match(struct isis_tlvs
*tlvs
,
2774 struct list
*addresses
)
2776 struct isis_area_address
*addr_head
;
2778 addr_head
= (struct isis_area_address
*)tlvs
->area_addresses
.head
;
2779 for (struct isis_area_address
*addr
= addr_head
; addr
;
2780 addr
= addr
->next
) {
2781 struct listnode
*node
;
2782 struct area_addr
*a
;
2784 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, a
)) {
2785 if (a
->addr_len
== addr
->len
2786 && !memcmp(a
->area_addr
, addr
->addr
, addr
->len
))
2794 static void tlvs_area_addresses_to_adj(struct isis_tlvs
*tlvs
,
2795 struct isis_adjacency
*adj
,
2798 if (adj
->area_address_count
!= tlvs
->area_addresses
.count
) {
2800 adj
->area_address_count
= tlvs
->area_addresses
.count
;
2801 adj
->area_addresses
= XREALLOC(
2802 MTYPE_ISIS_ADJACENCY_INFO
, adj
->area_addresses
,
2803 adj
->area_address_count
* sizeof(*adj
->area_addresses
));
2806 struct isis_area_address
*addr
= NULL
;
2807 for (unsigned int i
= 0; i
< tlvs
->area_addresses
.count
; i
++) {
2809 addr
= (struct isis_area_address
*)
2810 tlvs
->area_addresses
.head
;
2814 if (adj
->area_addresses
[i
].addr_len
== addr
->len
2815 && !memcmp(adj
->area_addresses
[i
].area_addr
, addr
->addr
,
2821 adj
->area_addresses
[i
].addr_len
= addr
->len
;
2822 memcpy(adj
->area_addresses
[i
].area_addr
, addr
->addr
, addr
->len
);
2826 static void tlvs_protocols_supported_to_adj(struct isis_tlvs
*tlvs
,
2827 struct isis_adjacency
*adj
,
2830 bool ipv4_supported
= false, ipv6_supported
= false;
2832 for (uint8_t i
= 0; i
< tlvs
->protocols_supported
.count
; i
++) {
2833 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IP
)
2834 ipv4_supported
= true;
2835 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IPV6
)
2836 ipv6_supported
= true;
2839 struct nlpids reduced
= {};
2841 if (ipv4_supported
&& ipv6_supported
) {
2843 reduced
.nlpids
[0] = NLPID_IP
;
2844 reduced
.nlpids
[1] = NLPID_IPV6
;
2845 } else if (ipv4_supported
) {
2847 reduced
.nlpids
[0] = NLPID_IP
;
2848 } else if (ipv6_supported
) {
2850 reduced
.nlpids
[1] = NLPID_IPV6
;
2855 if (adj
->nlpids
.count
== reduced
.count
2856 && !memcmp(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
))
2860 adj
->nlpids
.count
= reduced
.count
;
2861 memcpy(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
);
2864 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs
*tlvs
,
2865 struct isis_adjacency
*adj
,
2868 if (adj
->ipv4_address_count
!= tlvs
->ipv4_address
.count
) {
2870 adj
->ipv4_address_count
= tlvs
->ipv4_address
.count
;
2871 adj
->ipv4_addresses
= XREALLOC(
2872 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv4_addresses
,
2873 adj
->ipv4_address_count
* sizeof(*adj
->ipv4_addresses
));
2876 struct isis_ipv4_address
*addr
= NULL
;
2877 for (unsigned int i
= 0; i
< tlvs
->ipv4_address
.count
; i
++) {
2879 addr
= (struct isis_ipv4_address
*)
2880 tlvs
->ipv4_address
.head
;
2884 if (!memcmp(&adj
->ipv4_addresses
[i
], &addr
->addr
,
2885 sizeof(addr
->addr
)))
2889 adj
->ipv4_addresses
[i
] = addr
->addr
;
2893 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
2894 struct isis_adjacency
*adj
,
2897 if (adj
->ipv6_address_count
!= tlvs
->ipv6_address
.count
) {
2899 adj
->ipv6_address_count
= tlvs
->ipv6_address
.count
;
2900 adj
->ipv6_addresses
= XREALLOC(
2901 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv6_addresses
,
2902 adj
->ipv6_address_count
* sizeof(*adj
->ipv6_addresses
));
2905 struct isis_ipv6_address
*addr
= NULL
;
2906 for (unsigned int i
= 0; i
< tlvs
->ipv6_address
.count
; i
++) {
2908 addr
= (struct isis_ipv6_address
*)
2909 tlvs
->ipv6_address
.head
;
2913 if (!memcmp(&adj
->ipv6_addresses
[i
], &addr
->addr
,
2914 sizeof(addr
->addr
)))
2918 adj
->ipv6_addresses
[i
] = addr
->addr
;
2922 void isis_tlvs_to_adj(struct isis_tlvs
*tlvs
, struct isis_adjacency
*adj
,
2927 tlvs_area_addresses_to_adj(tlvs
, adj
, changed
);
2928 tlvs_protocols_supported_to_adj(tlvs
, adj
, changed
);
2929 tlvs_ipv4_addresses_to_adj(tlvs
, adj
, changed
);
2930 tlvs_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
2933 bool isis_tlvs_own_snpa_found(struct isis_tlvs
*tlvs
, uint8_t *snpa
)
2935 struct isis_lan_neighbor
*ne_head
;
2937 ne_head
= (struct isis_lan_neighbor
*)tlvs
->lan_neighbor
.head
;
2938 for (struct isis_lan_neighbor
*ne
= ne_head
; ne
; ne
= ne
->next
) {
2939 if (!memcmp(ne
->mac
, snpa
, ETH_ALEN
))
2946 void isis_tlvs_add_lsp_entry(struct isis_tlvs
*tlvs
, struct isis_lsp
*lsp
)
2948 struct isis_lsp_entry
*entry
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*entry
));
2950 entry
->rem_lifetime
= lsp
->hdr
.rem_lifetime
;
2951 memcpy(entry
->id
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 2);
2952 entry
->checksum
= lsp
->hdr
.checksum
;
2953 entry
->seqno
= lsp
->hdr
.seqno
;
2956 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)entry
);
2959 void isis_tlvs_add_csnp_entries(struct isis_tlvs
*tlvs
, uint8_t *start_id
,
2960 uint8_t *stop_id
, uint16_t num_lsps
,
2961 dict_t
*lspdb
, struct isis_lsp
**last_lsp
)
2963 dnode_t
*first
= dict_lower_bound(lspdb
, start_id
);
2967 dnode_t
*last
= dict_upper_bound(lspdb
, stop_id
);
2968 dnode_t
*curr
= first
;
2970 isis_tlvs_add_lsp_entry(tlvs
, first
->dict_data
);
2971 *last_lsp
= first
->dict_data
;
2974 curr
= dict_next(lspdb
, curr
);
2976 isis_tlvs_add_lsp_entry(tlvs
, curr
->dict_data
);
2977 *last_lsp
= curr
->dict_data
;
2979 if (curr
== last
|| tlvs
->lsp_entries
.count
== num_lsps
)
2984 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs
*tlvs
,
2985 const char *hostname
)
2987 XFREE(MTYPE_ISIS_TLV
, tlvs
->hostname
);
2989 tlvs
->hostname
= XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
2992 void isis_tlvs_set_te_router_id(struct isis_tlvs
*tlvs
,
2993 const struct in_addr
*id
)
2995 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id
);
2998 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
2999 memcpy(tlvs
->te_router_id
, id
, sizeof(*id
));
3002 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs
*tlvs
,
3003 struct prefix_ipv4
*dest
, uint8_t metric
)
3005 struct isis_oldstyle_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3008 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3009 apply_mask_ipv4(&r
->prefix
);
3010 append_item(&tlvs
->oldstyle_ip_reach
, (struct isis_item
*)r
);
3013 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs
*tlvs
,
3014 struct prefix_ipv4
*dest
, uint32_t metric
)
3016 struct isis_extended_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3019 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3020 apply_mask_ipv4(&r
->prefix
);
3021 append_item(&tlvs
->extended_ip_reach
, (struct isis_item
*)r
);
3024 void isis_tlvs_add_ipv6_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3025 struct prefix_ipv6
*dest
, uint32_t metric
)
3027 struct isis_ipv6_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3030 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3031 apply_mask_ipv6(&r
->prefix
);
3033 struct isis_item_list
*l
;
3034 l
= (mtid
== ISIS_MT_IPV4_UNICAST
)
3036 : isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
3037 append_item(l
, (struct isis_item
*)r
);
3040 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs
*tlvs
, uint8_t *id
,
3043 struct isis_oldstyle_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3046 memcpy(r
->id
, id
, sizeof(r
->id
));
3047 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)r
);
3050 void isis_tlvs_add_extended_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3051 uint8_t *id
, uint32_t metric
,
3052 uint8_t *subtlvs
, uint8_t subtlv_len
)
3054 struct isis_extended_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3056 memcpy(r
->id
, id
, sizeof(r
->id
));
3058 if (subtlvs
&& subtlv_len
) {
3059 r
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, subtlv_len
);
3060 memcpy(r
->subtlvs
, subtlvs
, subtlv_len
);
3061 r
->subtlv_len
= subtlv_len
;
3064 struct isis_item_list
*l
;
3065 if (mtid
== ISIS_MT_IPV4_UNICAST
)
3066 l
= &tlvs
->extended_reach
;
3068 l
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
3069 append_item(l
, (struct isis_item
*)r
);
3072 struct isis_mt_router_info
*
3073 isis_tlvs_lookup_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
)
3075 if (tlvs
->mt_router_info_empty
)
3078 struct isis_mt_router_info
*rv
;
3079 for (rv
= (struct isis_mt_router_info
*)tlvs
->mt_router_info
.head
; rv
;
3081 if (rv
->mtid
== mtid
)