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
,
500 "LSP Entry: %s, seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
501 ", lifetime %" PRIu16
"s\n",
502 isis_format_id(e
->id
, 8), e
->seqno
, e
->checksum
,
506 static void free_item_lsp_entry(struct isis_item
*i
)
508 XFREE(MTYPE_ISIS_TLV
, i
);
511 static int pack_item_lsp_entry(struct isis_item
*i
, struct stream
*s
)
513 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
515 if (STREAM_WRITEABLE(s
) < 16)
518 stream_putw(s
, e
->rem_lifetime
);
519 stream_put(s
, e
->id
, 8);
520 stream_putl(s
, e
->seqno
);
521 stream_putw(s
, e
->checksum
);
526 static int unpack_item_lsp_entry(uint16_t mtid
, uint8_t len
, struct stream
*s
,
527 struct sbuf
*log
, void *dest
, int indent
)
529 struct isis_tlvs
*tlvs
= dest
;
531 sbuf_push(log
, indent
, "Unpack LSP entry...\n");
535 "Not enough data left. (Expected 16 bytes of LSP info, got %" PRIu8
,
540 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
541 rv
->rem_lifetime
= stream_getw(s
);
542 stream_get(rv
->id
, s
, 8);
543 rv
->seqno
= stream_getl(s
);
544 rv
->checksum
= stream_getw(s
);
546 format_item_lsp_entry(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
547 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)rv
);
551 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
553 static struct isis_item
*copy_item_extended_reach(struct isis_item
*i
)
555 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
556 struct isis_extended_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
558 memcpy(rv
->id
, r
->id
, 7);
559 rv
->metric
= r
->metric
;
561 if (r
->subtlvs
&& r
->subtlv_len
) {
562 rv
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, r
->subtlv_len
);
563 memcpy(rv
->subtlvs
, r
->subtlvs
, r
->subtlv_len
);
564 rv
->subtlv_len
= r
->subtlv_len
;
567 return (struct isis_item
*)rv
;
570 static void format_item_extended_reach(uint16_t mtid
, struct isis_item
*i
,
571 struct sbuf
*buf
, int indent
)
573 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
575 sbuf_push(buf
, indent
, "%s Reachability: %s (Metric: %u)",
576 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
577 isis_format_id(r
->id
, 7), r
->metric
);
578 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
579 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
580 sbuf_push(buf
, 0, "\n");
582 if (r
->subtlv_len
&& r
->subtlvs
)
583 mpls_te_print_detail(buf
, indent
+ 2, r
->subtlvs
,
587 static void free_item_extended_reach(struct isis_item
*i
)
589 struct isis_extended_reach
*item
= (struct isis_extended_reach
*)i
;
590 XFREE(MTYPE_ISIS_TLV
, item
->subtlvs
);
591 XFREE(MTYPE_ISIS_TLV
, item
);
594 static int pack_item_extended_reach(struct isis_item
*i
, struct stream
*s
)
596 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
598 if (STREAM_WRITEABLE(s
) < 11 + (unsigned)r
->subtlv_len
)
600 stream_put(s
, r
->id
, sizeof(r
->id
));
601 stream_put3(s
, r
->metric
);
602 stream_putc(s
, r
->subtlv_len
);
603 stream_put(s
, r
->subtlvs
, r
->subtlv_len
);
607 static int unpack_item_extended_reach(uint16_t mtid
, uint8_t len
,
608 struct stream
*s
, struct sbuf
*log
,
609 void *dest
, int indent
)
611 struct isis_tlvs
*tlvs
= dest
;
612 struct isis_extended_reach
*rv
= NULL
;
614 struct isis_item_list
*items
;
616 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
617 items
= &tlvs
->extended_reach
;
619 items
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
622 sbuf_push(log
, indent
, "Unpacking %s reachability...\n",
623 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
626 sbuf_push(log
, indent
,
627 "Not enough data left. (expected 11 or more bytes, got %"
633 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
634 stream_get(rv
->id
, s
, 7);
635 rv
->metric
= stream_get3(s
);
636 subtlv_len
= stream_getc(s
);
638 format_item_extended_reach(mtid
, (struct isis_item
*)rv
, log
,
641 if ((size_t)len
< ((size_t)11) + subtlv_len
) {
642 sbuf_push(log
, indent
,
643 "Not enough data left for subtlv size %" PRIu8
644 ", there are only %" PRIu8
" bytes left.\n",
645 subtlv_len
, len
- 11);
649 sbuf_push(log
, indent
, "Storing %" PRIu8
" bytes of subtlvs\n",
653 size_t subtlv_start
= stream_get_getp(s
);
655 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_NE_REACH
, subtlv_len
, s
,
656 log
, NULL
, indent
+ 4)) {
660 stream_set_getp(s
, subtlv_start
);
662 rv
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, subtlv_len
);
663 stream_get(rv
->subtlvs
, s
, subtlv_len
);
664 rv
->subtlv_len
= subtlv_len
;
667 append_item(items
, (struct isis_item
*)rv
);
671 free_item_extended_reach((struct isis_item
*)rv
);
676 /* Functions related to TLV 128 (Old-Style) IP Reach */
677 static struct isis_item
*copy_item_oldstyle_ip_reach(struct isis_item
*i
)
679 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
680 struct isis_oldstyle_ip_reach
*rv
=
681 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
683 rv
->metric
= r
->metric
;
684 rv
->prefix
= r
->prefix
;
685 return (struct isis_item
*)rv
;
688 static void format_item_oldstyle_ip_reach(uint16_t mtid
, struct isis_item
*i
,
689 struct sbuf
*buf
, int indent
)
691 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
692 char prefixbuf
[PREFIX2STR_BUFFER
];
694 sbuf_push(buf
, indent
, "IP Reachability: %s (Metric: %" PRIu8
")\n",
695 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
699 static void free_item_oldstyle_ip_reach(struct isis_item
*i
)
701 XFREE(MTYPE_ISIS_TLV
, i
);
704 static int pack_item_oldstyle_ip_reach(struct isis_item
*i
, struct stream
*s
)
706 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
708 if (STREAM_WRITEABLE(s
) < 12)
711 stream_putc(s
, r
->metric
);
712 stream_putc(s
, 0x80); /* delay metric - unsupported */
713 stream_putc(s
, 0x80); /* expense metric - unsupported */
714 stream_putc(s
, 0x80); /* error metric - unsupported */
715 stream_put(s
, &r
->prefix
.prefix
, 4);
718 masklen2ip(r
->prefix
.prefixlen
, &mask
);
719 stream_put(s
, &mask
, sizeof(mask
));
724 static int unpack_item_oldstyle_ip_reach(uint16_t mtid
, uint8_t len
,
725 struct stream
*s
, struct sbuf
*log
,
726 void *dest
, int indent
)
728 sbuf_push(log
, indent
, "Unpack oldstyle ip reach...\n");
732 "Not enough data left.(Expected 12 bytes of reach information, got %" PRIu8
738 struct isis_oldstyle_ip_reach
*rv
=
739 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
740 rv
->metric
= stream_getc(s
);
741 if ((rv
->metric
& 0x7f) != rv
->metric
) {
742 sbuf_push(log
, indent
, "Metric has unplausible format\n");
745 stream_forward_getp(s
, 3); /* Skip other metrics */
746 rv
->prefix
.family
= AF_INET
;
747 stream_get(&rv
->prefix
.prefix
, s
, 4);
750 stream_get(&mask
, s
, 4);
751 rv
->prefix
.prefixlen
= ip_masklen(mask
);
753 format_item_oldstyle_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
755 append_item(dest
, (struct isis_item
*)rv
);
760 /* Functions related to TLV 129 protocols supported */
762 static void copy_tlv_protocols_supported(struct isis_protocols_supported
*src
,
763 struct isis_protocols_supported
*dest
)
765 if (!src
->protocols
|| !src
->count
)
767 dest
->count
= src
->count
;
768 dest
->protocols
= XCALLOC(MTYPE_ISIS_TLV
, src
->count
);
769 memcpy(dest
->protocols
, src
->protocols
, src
->count
);
772 static void format_tlv_protocols_supported(struct isis_protocols_supported
*p
,
773 struct sbuf
*buf
, int indent
)
775 if (!p
|| !p
->count
|| !p
->protocols
)
778 sbuf_push(buf
, indent
, "Protocols Supported: ");
779 for (uint8_t i
= 0; i
< p
->count
; i
++) {
780 sbuf_push(buf
, 0, "%s%s", nlpid2str(p
->protocols
[i
]),
781 (i
+ 1 < p
->count
) ? ", " : "");
783 sbuf_push(buf
, 0, "\n");
786 static void free_tlv_protocols_supported(struct isis_protocols_supported
*p
)
788 XFREE(MTYPE_ISIS_TLV
, p
->protocols
);
791 static int pack_tlv_protocols_supported(struct isis_protocols_supported
*p
,
794 if (!p
|| !p
->count
|| !p
->protocols
)
797 if (STREAM_WRITEABLE(s
) < (unsigned)(p
->count
+ 2))
800 stream_putc(s
, ISIS_TLV_PROTOCOLS_SUPPORTED
);
801 stream_putc(s
, p
->count
);
802 stream_put(s
, p
->protocols
, p
->count
);
806 static int unpack_tlv_protocols_supported(enum isis_tlv_context context
,
807 uint8_t tlv_type
, uint8_t tlv_len
,
808 struct stream
*s
, struct sbuf
*log
,
809 void *dest
, int indent
)
811 struct isis_tlvs
*tlvs
= dest
;
813 sbuf_push(log
, indent
, "Unpacking Protocols Supported TLV...\n");
815 sbuf_push(log
, indent
, "WARNING: No protocols included\n");
818 if (tlvs
->protocols_supported
.protocols
) {
821 "WARNING: protocols supported TLV present multiple times.\n");
822 stream_forward_getp(s
, tlv_len
);
826 tlvs
->protocols_supported
.count
= tlv_len
;
827 tlvs
->protocols_supported
.protocols
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
);
828 stream_get(tlvs
->protocols_supported
.protocols
, s
, tlv_len
);
830 format_tlv_protocols_supported(&tlvs
->protocols_supported
, log
,
835 /* Functions related to TLV 132 IPv4 Interface addresses */
836 static struct isis_item
*copy_item_ipv4_address(struct isis_item
*i
)
838 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
839 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
842 return (struct isis_item
*)rv
;
845 static void format_item_ipv4_address(uint16_t mtid
, struct isis_item
*i
,
846 struct sbuf
*buf
, int indent
)
848 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
849 char addrbuf
[INET_ADDRSTRLEN
];
851 inet_ntop(AF_INET
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
852 sbuf_push(buf
, indent
, "IPv4 Interface Address: %s\n", addrbuf
);
855 static void free_item_ipv4_address(struct isis_item
*i
)
857 XFREE(MTYPE_ISIS_TLV
, i
);
860 static int pack_item_ipv4_address(struct isis_item
*i
, struct stream
*s
)
862 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
864 if (STREAM_WRITEABLE(s
) < 4)
867 stream_put(s
, &a
->addr
, 4);
872 static int unpack_item_ipv4_address(uint16_t mtid
, uint8_t len
,
873 struct stream
*s
, struct sbuf
*log
,
874 void *dest
, int indent
)
876 struct isis_tlvs
*tlvs
= dest
;
878 sbuf_push(log
, indent
, "Unpack IPv4 Interface address...\n");
882 "Not enough data left.(Expected 4 bytes of IPv4 address, got %" PRIu8
888 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
889 stream_get(&rv
->addr
, s
, 4);
891 format_item_ipv4_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
892 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)rv
);
897 /* Functions related to TLV 232 IPv6 Interface addresses */
898 static struct isis_item
*copy_item_ipv6_address(struct isis_item
*i
)
900 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
901 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
904 return (struct isis_item
*)rv
;
907 static void format_item_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
908 struct sbuf
*buf
, int indent
)
910 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
911 char addrbuf
[INET6_ADDRSTRLEN
];
913 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
914 sbuf_push(buf
, indent
, "IPv6 Interface Address: %s\n", addrbuf
);
917 static void free_item_ipv6_address(struct isis_item
*i
)
919 XFREE(MTYPE_ISIS_TLV
, i
);
922 static int pack_item_ipv6_address(struct isis_item
*i
, struct stream
*s
)
924 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
926 if (STREAM_WRITEABLE(s
) < 16)
929 stream_put(s
, &a
->addr
, 16);
934 static int unpack_item_ipv6_address(uint16_t mtid
, uint8_t len
,
935 struct stream
*s
, struct sbuf
*log
,
936 void *dest
, int indent
)
938 struct isis_tlvs
*tlvs
= dest
;
940 sbuf_push(log
, indent
, "Unpack IPv6 Interface address...\n");
944 "Not enough data left.(Expected 16 bytes of IPv6 address, got %" PRIu8
950 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
951 stream_get(&rv
->addr
, s
, 16);
953 format_item_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
954 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)rv
);
959 /* Functions related to TLV 229 MT Router information */
960 static struct isis_item
*copy_item_mt_router_info(struct isis_item
*i
)
962 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
963 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
965 rv
->overload
= info
->overload
;
966 rv
->attached
= info
->attached
;
967 rv
->mtid
= info
->mtid
;
968 return (struct isis_item
*)rv
;
971 static void format_item_mt_router_info(uint16_t mtid
, struct isis_item
*i
,
972 struct sbuf
*buf
, int indent
)
974 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
976 sbuf_push(buf
, indent
, "MT Router Info: %s%s%s\n",
977 isis_mtid2str(info
->mtid
),
978 info
->overload
? " Overload" : "",
979 info
->attached
? " Attached" : "");
982 static void free_item_mt_router_info(struct isis_item
*i
)
984 XFREE(MTYPE_ISIS_TLV
, i
);
987 static int pack_item_mt_router_info(struct isis_item
*i
, struct stream
*s
)
989 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
991 if (STREAM_WRITEABLE(s
) < 2)
994 uint16_t entry
= info
->mtid
;
997 entry
|= ISIS_MT_OL_MASK
;
999 entry
|= ISIS_MT_AT_MASK
;
1001 stream_putw(s
, entry
);
1006 static int unpack_item_mt_router_info(uint16_t mtid
, uint8_t len
,
1007 struct stream
*s
, struct sbuf
*log
,
1008 void *dest
, int indent
)
1010 struct isis_tlvs
*tlvs
= dest
;
1012 sbuf_push(log
, indent
, "Unpack MT Router info...\n");
1016 "Not enough data left.(Expected 2 bytes of MT info, got %" PRIu8
1022 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1024 uint16_t entry
= stream_getw(s
);
1025 rv
->overload
= entry
& ISIS_MT_OL_MASK
;
1026 rv
->attached
= entry
& ISIS_MT_AT_MASK
;
1027 rv
->mtid
= entry
& ISIS_MT_MASK
;
1029 format_item_mt_router_info(mtid
, (struct isis_item
*)rv
, log
,
1031 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)rv
);
1035 /* Functions related to TLV 134 TE Router ID */
1037 static struct in_addr
*copy_tlv_te_router_id(const struct in_addr
*id
)
1042 struct in_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1043 memcpy(rv
, id
, sizeof(*rv
));
1047 static void format_tlv_te_router_id(const struct in_addr
*id
, struct sbuf
*buf
,
1053 char addrbuf
[INET_ADDRSTRLEN
];
1054 inet_ntop(AF_INET
, id
, addrbuf
, sizeof(addrbuf
));
1055 sbuf_push(buf
, indent
, "TE Router ID: %s\n", addrbuf
);
1058 static void free_tlv_te_router_id(struct in_addr
*id
)
1060 XFREE(MTYPE_ISIS_TLV
, id
);
1063 static int pack_tlv_te_router_id(const struct in_addr
*id
, struct stream
*s
)
1068 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
1071 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID
);
1073 stream_put(s
, id
, 4);
1077 static int unpack_tlv_te_router_id(enum isis_tlv_context context
,
1078 uint8_t tlv_type
, uint8_t tlv_len
,
1079 struct stream
*s
, struct sbuf
*log
,
1080 void *dest
, int indent
)
1082 struct isis_tlvs
*tlvs
= dest
;
1084 sbuf_push(log
, indent
, "Unpacking TE Router ID TLV...\n");
1086 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
1090 if (tlvs
->te_router_id
) {
1091 sbuf_push(log
, indent
,
1092 "WARNING: TE Router ID present multiple times.\n");
1093 stream_forward_getp(s
, tlv_len
);
1097 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, 4);
1098 stream_get(tlvs
->te_router_id
, s
, 4);
1099 format_tlv_te_router_id(tlvs
->te_router_id
, log
, indent
+ 2);
1104 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
1106 static struct isis_item
*copy_item_extended_ip_reach(struct isis_item
*i
)
1108 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1109 struct isis_extended_ip_reach
*rv
=
1110 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1112 rv
->metric
= r
->metric
;
1114 rv
->prefix
= r
->prefix
;
1116 return (struct isis_item
*)rv
;
1119 static void format_item_extended_ip_reach(uint16_t mtid
, struct isis_item
*i
,
1120 struct sbuf
*buf
, int indent
)
1122 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1123 char prefixbuf
[PREFIX2STR_BUFFER
];
1125 sbuf_push(buf
, indent
, "%s IP Reachability: %s (Metric: %u)%s",
1126 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
1127 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)), r
->metric
,
1128 r
->down
? " Down" : "");
1129 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1130 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1131 sbuf_push(buf
, 0, "\n");
1134 static void free_item_extended_ip_reach(struct isis_item
*i
)
1136 struct isis_extended_ip_reach
*item
=
1137 (struct isis_extended_ip_reach
*)i
;
1138 XFREE(MTYPE_ISIS_TLV
, item
);
1141 static int pack_item_extended_ip_reach(struct isis_item
*i
, struct stream
*s
)
1143 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1146 if (STREAM_WRITEABLE(s
) < 5)
1148 stream_putl(s
, r
->metric
);
1150 control
= r
->down
? ISIS_EXTENDED_IP_REACH_DOWN
: 0;
1151 control
|= r
->prefix
.prefixlen
;
1152 stream_putc(s
, control
);
1154 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
))
1156 stream_put(s
, &r
->prefix
.prefix
.s_addr
, PSIZE(r
->prefix
.prefixlen
));
1160 static int unpack_item_extended_ip_reach(uint16_t mtid
, uint8_t len
,
1161 struct stream
*s
, struct sbuf
*log
,
1162 void *dest
, int indent
)
1164 struct isis_tlvs
*tlvs
= dest
;
1165 struct isis_extended_ip_reach
*rv
= NULL
;
1167 uint8_t control
, subtlv_len
;
1168 struct isis_item_list
*items
;
1170 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1171 items
= &tlvs
->extended_ip_reach
;
1173 items
= isis_get_mt_items(&tlvs
->mt_ip_reach
, mtid
);
1176 sbuf_push(log
, indent
, "Unpacking %s IPv4 reachability...\n",
1177 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
1180 if (len
< consume
) {
1181 sbuf_push(log
, indent
,
1182 "Not enough data left. (expected 5 or more bytes, got %" PRIu8
")\n",
1187 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1189 rv
->metric
= stream_getl(s
);
1190 control
= stream_getc(s
);
1191 rv
->down
= (control
& ISIS_EXTENDED_IP_REACH_DOWN
);
1192 rv
->prefix
.family
= AF_INET
;
1193 rv
->prefix
.prefixlen
= control
& 0x3f;
1194 if (rv
->prefix
.prefixlen
> 32) {
1195 sbuf_push(log
, indent
, "Prefixlen %u is inplausible for IPv4\n",
1196 rv
->prefix
.prefixlen
);
1200 consume
+= PSIZE(rv
->prefix
.prefixlen
);
1201 if (len
< consume
) {
1202 sbuf_push(log
, indent
,
1203 "Expected %u bytes of prefix, but only %u bytes available.\n",
1204 PSIZE(rv
->prefix
.prefixlen
), len
- 5);
1207 stream_get(&rv
->prefix
.prefix
.s_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
1208 in_addr_t orig_prefix
= rv
->prefix
.prefix
.s_addr
;
1209 apply_mask_ipv4(&rv
->prefix
);
1210 if (orig_prefix
!= rv
->prefix
.prefix
.s_addr
)
1211 sbuf_push(log
, indent
+ 2,
1212 "WARNING: Prefix had hostbits set.\n");
1213 format_item_extended_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
1216 if (control
& ISIS_EXTENDED_IP_REACH_SUBTLV
) {
1218 if (len
< consume
) {
1219 sbuf_push(log
, indent
,
1220 "Expected 1 byte of subtlv len, but no more data present.\n");
1223 subtlv_len
= stream_getc(s
);
1226 sbuf_push(log
, indent
+ 2,
1227 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
1229 consume
+= subtlv_len
;
1230 if (len
< consume
) {
1231 sbuf_push(log
, indent
,
1233 " bytes of subtlvs, but only %u bytes available.\n",
1235 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
1238 sbuf_push(log
, indent
, "Skipping %" PRIu8
" bytes of subvls",
1240 stream_forward_getp(s
, subtlv_len
);
1243 append_item(items
, (struct isis_item
*)rv
);
1247 free_item_extended_ip_reach((struct isis_item
*)rv
);
1251 /* Functions related to TLV 137 Dynamic Hostname */
1253 static char *copy_tlv_dynamic_hostname(const char *hostname
)
1258 return XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
1261 static void format_tlv_dynamic_hostname(const char *hostname
, struct sbuf
*buf
,
1267 sbuf_push(buf
, indent
, "Hostname: %s\n", hostname
);
1270 static void free_tlv_dynamic_hostname(char *hostname
)
1272 XFREE(MTYPE_ISIS_TLV
, hostname
);
1275 static int pack_tlv_dynamic_hostname(const char *hostname
, struct stream
*s
)
1280 uint8_t name_len
= strlen(hostname
);
1282 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + name_len
))
1285 stream_putc(s
, ISIS_TLV_DYNAMIC_HOSTNAME
);
1286 stream_putc(s
, name_len
);
1287 stream_put(s
, hostname
, name_len
);
1291 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context
,
1292 uint8_t tlv_type
, uint8_t tlv_len
,
1293 struct stream
*s
, struct sbuf
*log
,
1294 void *dest
, int indent
)
1296 struct isis_tlvs
*tlvs
= dest
;
1298 sbuf_push(log
, indent
, "Unpacking Dynamic Hostname TLV...\n");
1300 sbuf_push(log
, indent
, "WARNING: No hostname included\n");
1304 if (tlvs
->hostname
) {
1305 sbuf_push(log
, indent
,
1306 "WARNING: Hostname present multiple times.\n");
1307 stream_forward_getp(s
, tlv_len
);
1311 tlvs
->hostname
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
+ 1);
1312 stream_get(tlvs
->hostname
, s
, tlv_len
);
1313 tlvs
->hostname
[tlv_len
] = '\0';
1316 for (uint8_t i
= 0; i
< tlv_len
; i
++) {
1317 if ((unsigned char)tlvs
->hostname
[i
] > 127
1318 || !isprint((int)tlvs
->hostname
[i
])) {
1320 tlvs
->hostname
[i
] = '?';
1326 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
1332 /* Functions related to TLV 240 P2P Three-Way Adjacency */
1334 const char *isis_threeway_state_name(enum isis_threeway_state state
)
1337 case ISIS_THREEWAY_DOWN
:
1339 case ISIS_THREEWAY_INITIALIZING
:
1340 return "Initializing";
1341 case ISIS_THREEWAY_UP
:
1348 static struct isis_threeway_adj
*copy_tlv_threeway_adj(
1349 const struct isis_threeway_adj
*threeway_adj
)
1354 struct isis_threeway_adj
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1355 memcpy(rv
, threeway_adj
, sizeof(*rv
));
1360 static void format_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
1361 struct sbuf
*buf
, int indent
)
1366 sbuf_push(buf
, indent
, "P2P Three-Way Adjacency:\n");
1367 sbuf_push(buf
, indent
, " State: %s (%d)\n",
1368 isis_threeway_state_name(threeway_adj
->state
),
1369 threeway_adj
->state
);
1370 sbuf_push(buf
, indent
, " Extended Local Circuit ID: %" PRIu32
"\n",
1371 threeway_adj
->local_circuit_id
);
1372 if (!threeway_adj
->neighbor_set
)
1375 sbuf_push(buf
, indent
, " Neighbor System ID: %s\n",
1376 isis_format_id(threeway_adj
->neighbor_id
, 6));
1377 sbuf_push(buf
, indent
, " Neighbor Extended Circuit ID: %" PRIu32
"\n",
1378 threeway_adj
->neighbor_circuit_id
);
1381 static void free_tlv_threeway_adj(struct isis_threeway_adj
*threeway_adj
)
1383 XFREE(MTYPE_ISIS_TLV
, threeway_adj
);
1386 static int pack_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
1392 uint8_t tlv_len
= (threeway_adj
->neighbor_set
) ? 15 : 5;
1394 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
1397 stream_putc(s
, ISIS_TLV_THREE_WAY_ADJ
);
1398 stream_putc(s
, tlv_len
);
1399 stream_putc(s
, threeway_adj
->state
);
1400 stream_putl(s
, threeway_adj
->local_circuit_id
);
1402 if (threeway_adj
->neighbor_set
) {
1403 stream_put(s
, threeway_adj
->neighbor_id
, 6);
1404 stream_putl(s
, threeway_adj
->neighbor_circuit_id
);
1410 static int unpack_tlv_threeway_adj(enum isis_tlv_context context
,
1411 uint8_t tlv_type
, uint8_t tlv_len
,
1412 struct stream
*s
, struct sbuf
*log
,
1413 void *dest
, int indent
)
1415 struct isis_tlvs
*tlvs
= dest
;
1417 sbuf_push(log
, indent
, "Unpacking P2P Three-Way Adjacency TLV...\n");
1418 if (tlv_len
!= 5 && tlv_len
!= 15) {
1419 sbuf_push(log
, indent
, "WARNING: Unexepected TLV size\n");
1420 stream_forward_getp(s
, tlv_len
);
1424 if (tlvs
->threeway_adj
) {
1425 sbuf_push(log
, indent
,
1426 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
1427 stream_forward_getp(s
, tlv_len
);
1431 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
1433 tlvs
->threeway_adj
->state
= stream_getc(s
);
1434 tlvs
->threeway_adj
->local_circuit_id
= stream_getl(s
);
1436 if (tlv_len
== 15) {
1437 tlvs
->threeway_adj
->neighbor_set
= true;
1438 stream_get(tlvs
->threeway_adj
->neighbor_id
, s
, 6);
1439 tlvs
->threeway_adj
->neighbor_circuit_id
= stream_getl(s
);
1445 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
1447 static struct isis_item
*copy_item_ipv6_reach(struct isis_item
*i
)
1449 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1450 struct isis_ipv6_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1451 rv
->metric
= r
->metric
;
1453 rv
->external
= r
->external
;
1454 rv
->prefix
= r
->prefix
;
1455 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
1457 return (struct isis_item
*)rv
;
1460 static void format_item_ipv6_reach(uint16_t mtid
, struct isis_item
*i
,
1461 struct sbuf
*buf
, int indent
)
1463 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1464 char prefixbuf
[PREFIX2STR_BUFFER
];
1466 sbuf_push(buf
, indent
, "%sIPv6 Reachability: %s (Metric: %u)%s%s",
1467 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "MT ",
1468 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
1470 r
->down
? " Down" : "",
1471 r
->external
? " External" : "");
1472 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1473 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1474 sbuf_push(buf
, 0, "\n");
1477 sbuf_push(buf
, indent
, " Subtlvs:\n");
1478 format_subtlvs(r
->subtlvs
, buf
, indent
+ 4);
1482 static void free_item_ipv6_reach(struct isis_item
*i
)
1484 struct isis_ipv6_reach
*item
= (struct isis_ipv6_reach
*)i
;
1486 isis_free_subtlvs(item
->subtlvs
);
1487 XFREE(MTYPE_ISIS_TLV
, item
);
1490 static int pack_item_ipv6_reach(struct isis_item
*i
, struct stream
*s
)
1492 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1495 if (STREAM_WRITEABLE(s
) < 6)
1497 stream_putl(s
, r
->metric
);
1499 control
= r
->down
? ISIS_IPV6_REACH_DOWN
: 0;
1500 control
|= r
->external
? ISIS_IPV6_REACH_EXTERNAL
: 0;
1501 control
|= r
->subtlvs
? ISIS_IPV6_REACH_SUBTLV
: 0;
1503 stream_putc(s
, control
);
1504 stream_putc(s
, r
->prefix
.prefixlen
);
1506 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
))
1508 stream_put(s
, &r
->prefix
.prefix
.s6_addr
, PSIZE(r
->prefix
.prefixlen
));
1511 return pack_subtlvs(r
->subtlvs
, s
);
1516 static int unpack_item_ipv6_reach(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1517 struct sbuf
*log
, void *dest
, int indent
)
1519 struct isis_tlvs
*tlvs
= dest
;
1520 struct isis_ipv6_reach
*rv
= NULL
;
1522 uint8_t control
, subtlv_len
;
1523 struct isis_item_list
*items
;
1525 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1526 items
= &tlvs
->ipv6_reach
;
1528 items
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
1531 sbuf_push(log
, indent
, "Unpacking %sIPv6 reachability...\n",
1532 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "mt ");
1534 if (len
< consume
) {
1535 sbuf_push(log
, indent
,
1536 "Not enough data left. (expected 6 or more bytes, got %"
1542 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1544 rv
->metric
= stream_getl(s
);
1545 control
= stream_getc(s
);
1546 rv
->down
= (control
& ISIS_IPV6_REACH_DOWN
);
1547 rv
->external
= (control
& ISIS_IPV6_REACH_EXTERNAL
);
1549 rv
->prefix
.family
= AF_INET6
;
1550 rv
->prefix
.prefixlen
= stream_getc(s
);
1551 if (rv
->prefix
.prefixlen
> 128) {
1552 sbuf_push(log
, indent
, "Prefixlen %u is inplausible for IPv6\n",
1553 rv
->prefix
.prefixlen
);
1557 consume
+= PSIZE(rv
->prefix
.prefixlen
);
1558 if (len
< consume
) {
1559 sbuf_push(log
, indent
,
1560 "Expected %u bytes of prefix, but only %u bytes available.\n",
1561 PSIZE(rv
->prefix
.prefixlen
), len
- 6);
1564 stream_get(&rv
->prefix
.prefix
.s6_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
1565 struct in6_addr orig_prefix
= rv
->prefix
.prefix
;
1566 apply_mask_ipv6(&rv
->prefix
);
1567 if (memcmp(&orig_prefix
, &rv
->prefix
.prefix
, sizeof(orig_prefix
)))
1568 sbuf_push(log
, indent
+ 2,
1569 "WARNING: Prefix had hostbits set.\n");
1570 format_item_ipv6_reach(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1572 if (control
& ISIS_IPV6_REACH_SUBTLV
) {
1574 if (len
< consume
) {
1575 sbuf_push(log
, indent
,
1576 "Expected 1 byte of subtlv len, but no more data persent.\n");
1579 subtlv_len
= stream_getc(s
);
1582 sbuf_push(log
, indent
+ 2,
1583 " WARNING: subtlv bit set, but there are no subtlvs.\n");
1585 consume
+= subtlv_len
;
1586 if (len
< consume
) {
1587 sbuf_push(log
, indent
,
1589 " bytes of subtlvs, but only %u bytes available.\n",
1591 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
1595 rv
->subtlvs
= isis_alloc_subtlvs();
1596 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
, subtlv_len
, s
,
1597 log
, rv
->subtlvs
, indent
+ 4)) {
1602 append_item(items
, (struct isis_item
*)rv
);
1606 free_item_ipv6_reach((struct isis_item
*)rv
);
1610 /* Functions related to TLV 10 Authentication */
1611 static struct isis_item
*copy_item_auth(struct isis_item
*i
)
1613 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1614 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1616 rv
->type
= auth
->type
;
1617 rv
->length
= auth
->length
;
1618 memcpy(rv
->value
, auth
->value
, sizeof(rv
->value
));
1619 return (struct isis_item
*)rv
;
1622 static void format_item_auth(uint16_t mtid
, struct isis_item
*i
,
1623 struct sbuf
*buf
, int indent
)
1625 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1628 sbuf_push(buf
, indent
, "Authentication:\n");
1629 switch (auth
->type
) {
1630 case ISIS_PASSWD_TYPE_CLEARTXT
:
1631 zlog_sanitize(obuf
, sizeof(obuf
), auth
->value
, auth
->length
);
1632 sbuf_push(buf
, indent
, " Password: %s\n", obuf
);
1634 case ISIS_PASSWD_TYPE_HMAC_MD5
:
1635 for (unsigned int i
= 0; i
< 16; i
++) {
1636 snprintf(obuf
+ 2 * i
, sizeof(obuf
) - 2 * i
,
1637 "%02" PRIx8
, auth
->value
[i
]);
1639 sbuf_push(buf
, indent
, " HMAC-MD5: %s\n", obuf
);
1642 sbuf_push(buf
, indent
, " Unknown (%" PRIu8
")\n", auth
->type
);
1647 static void free_item_auth(struct isis_item
*i
)
1649 XFREE(MTYPE_ISIS_TLV
, i
);
1652 static int pack_item_auth(struct isis_item
*i
, struct stream
*s
)
1654 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1656 if (STREAM_WRITEABLE(s
) < 1)
1658 stream_putc(s
, auth
->type
);
1660 switch (auth
->type
) {
1661 case ISIS_PASSWD_TYPE_CLEARTXT
:
1662 if (STREAM_WRITEABLE(s
) < auth
->length
)
1664 stream_put(s
, auth
->passwd
, auth
->length
);
1666 case ISIS_PASSWD_TYPE_HMAC_MD5
:
1667 if (STREAM_WRITEABLE(s
) < 16)
1669 auth
->offset
= stream_get_endp(s
);
1670 stream_put(s
, NULL
, 16);
1679 static int unpack_item_auth(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1680 struct sbuf
*log
, void *dest
, int indent
)
1682 struct isis_tlvs
*tlvs
= dest
;
1684 sbuf_push(log
, indent
, "Unpack Auth TLV...\n");
1688 "Not enough data left.(Expected 1 bytes of auth type, got %" PRIu8
1694 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1696 rv
->type
= stream_getc(s
);
1697 rv
->length
= len
- 1;
1699 if (rv
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
&& rv
->length
!= 16) {
1702 "Unexpected auth length for HMAC-MD5 (expected 16, got %" PRIu8
1705 XFREE(MTYPE_ISIS_TLV
, rv
);
1709 rv
->offset
= stream_get_getp(s
);
1710 stream_get(rv
->value
, s
, rv
->length
);
1711 format_item_auth(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1712 append_item(&tlvs
->isis_auth
, (struct isis_item
*)rv
);
1716 /* Functions relating to item TLVs */
1718 static void init_item_list(struct isis_item_list
*items
)
1721 items
->tail
= &items
->head
;
1725 static struct isis_item
*copy_item(enum isis_tlv_context context
,
1726 enum isis_tlv_type type
,
1727 struct isis_item
*item
)
1729 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
1731 if (ops
&& ops
->copy_item
)
1732 return ops
->copy_item(item
);
1734 assert(!"Unknown item tlv type!");
1738 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1739 struct isis_item_list
*src
, struct isis_item_list
*dest
)
1741 struct isis_item
*item
;
1743 init_item_list(dest
);
1745 for (item
= src
->head
; item
; item
= item
->next
) {
1746 append_item(dest
, copy_item(context
, type
, item
));
1750 static void format_item(uint16_t mtid
, enum isis_tlv_context context
,
1751 enum isis_tlv_type type
, struct isis_item
*i
,
1752 struct sbuf
*buf
, int indent
)
1754 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
1756 if (ops
&& ops
->format_item
) {
1757 ops
->format_item(mtid
, i
, buf
, indent
);
1761 assert(!"Unknown item tlv type!");
1764 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
1765 enum isis_tlv_type type
, struct isis_item_list
*items
,
1766 struct sbuf
*buf
, int indent
)
1768 struct isis_item
*i
;
1770 for (i
= items
->head
; i
; i
= i
->next
)
1771 format_item(mtid
, context
, type
, i
, buf
, indent
);
1773 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1775 static void free_item(enum isis_tlv_context tlv_context
,
1776 enum isis_tlv_type tlv_type
, struct isis_item
*item
)
1778 const struct tlv_ops
*ops
= tlv_table
[tlv_context
][tlv_type
];
1780 if (ops
&& ops
->free_item
) {
1781 ops
->free_item(item
);
1785 assert(!"Unknown item tlv type!");
1788 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
1789 struct isis_item_list
*items
)
1791 struct isis_item
*item
, *next_item
;
1793 for (item
= items
->head
; item
; item
= next_item
) {
1794 next_item
= item
->next
;
1795 free_item(context
, type
, item
);
1799 static int pack_item(enum isis_tlv_context context
, enum isis_tlv_type type
,
1800 struct isis_item
*i
, struct stream
*s
,
1801 struct isis_tlvs
**fragment_tlvs
,
1802 struct pack_order_entry
*pe
, uint16_t mtid
)
1804 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
1806 if (ops
&& ops
->pack_item
) {
1807 return ops
->pack_item(i
, s
);
1810 assert(!"Unknown item tlv type!");
1814 static void add_item_to_fragment(struct isis_item
*i
, struct pack_order_entry
*pe
,
1815 struct isis_tlvs
*fragment_tlvs
, uint16_t mtid
)
1817 struct isis_item_list
*l
;
1819 if (pe
->how_to_pack
== ISIS_ITEMS
) {
1820 l
= (struct isis_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
1822 struct isis_mt_item_list
*m
;
1823 m
= (struct isis_mt_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
1824 l
= isis_get_mt_items(m
, mtid
);
1827 append_item(l
, copy_item(pe
->context
, pe
->type
, i
));
1830 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
1831 enum isis_tlv_type type
, struct isis_item_list
*items
,
1832 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
1833 struct pack_order_entry
*pe
,
1834 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
1835 struct list
*new_fragment_arg
)
1837 size_t len_pos
, last_len
, len
;
1838 struct isis_item
*item
= NULL
;
1845 if (STREAM_WRITEABLE(s
) < 2)
1848 stream_putc(s
, type
);
1849 len_pos
= stream_get_endp(s
);
1850 stream_putc(s
, 0); /* Put 0 as length for now */
1852 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(type
)
1853 && mtid
!= ISIS_MT_IPV4_UNICAST
) {
1854 if (STREAM_WRITEABLE(s
) < 2)
1856 stream_putw(s
, mtid
);
1859 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_OLDSTYLE_REACH
) {
1860 if (STREAM_WRITEABLE(s
) < 1)
1862 stream_putc(s
, 0); /* Virtual flag is set to 0 */
1866 for (item
= item
? item
: items
->head
; item
; item
= item
->next
) {
1867 rv
= pack_item(context
, type
, item
, s
, fragment_tlvs
, pe
, mtid
);
1871 len
= stream_get_endp(s
) - len_pos
- 1;
1873 /* Multiple auths don't go into one TLV, so always break */
1874 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_AUTH
) {
1880 if (!last_len
) /* strange, not a single item fit */
1882 /* drop last tlv, otherwise, its too long */
1883 stream_set_endp(s
, len_pos
+ 1 + last_len
);
1889 add_item_to_fragment(item
, pe
, *fragment_tlvs
, mtid
);
1894 stream_putc_at(s
, len_pos
, len
);
1903 *fragment_tlvs
= new_fragment(new_fragment_arg
);
1906 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1908 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
)
1911 dest
->tail
= &(*dest
->tail
)->next
;
1915 static struct isis_item
*last_item(struct isis_item_list
*list
)
1917 return container_of(list
->tail
, struct isis_item
, next
);
1920 static int unpack_item(uint16_t mtid
, enum isis_tlv_context context
,
1921 uint8_t tlv_type
, uint8_t len
, struct stream
*s
,
1922 struct sbuf
*log
, void *dest
, int indent
)
1924 const struct tlv_ops
*ops
= tlv_table
[context
][tlv_type
];
1926 if (ops
&& ops
->unpack_item
)
1927 return ops
->unpack_item(mtid
, len
, s
, log
, dest
, indent
);
1929 assert(!"Unknown item tlv type!");
1930 sbuf_push(log
, indent
, "Unknown item tlv type!\n");
1934 static int unpack_tlv_with_items(enum isis_tlv_context context
,
1935 uint8_t tlv_type
, uint8_t tlv_len
,
1936 struct stream
*s
, struct sbuf
*log
, void *dest
,
1944 tlv_start
= stream_get_getp(s
);
1947 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(tlv_type
)) {
1949 sbuf_push(log
, indent
,
1950 "TLV is too short to contain MTID\n");
1953 mtid
= stream_getw(s
) & ISIS_MT_MASK
;
1955 sbuf_push(log
, indent
, "Unpacking as MT %s item TLV...\n",
1956 isis_mtid2str(mtid
));
1958 sbuf_push(log
, indent
, "Unpacking as item TLV...\n");
1959 mtid
= ISIS_MT_IPV4_UNICAST
;
1962 if (context
== ISIS_CONTEXT_LSP
1963 && tlv_type
== ISIS_TLV_OLDSTYLE_REACH
) {
1964 if (tlv_len
- tlv_pos
< 1) {
1965 sbuf_push(log
, indent
,
1966 "TLV is too short for old style reach\n");
1969 stream_forward_getp(s
, 1);
1973 if (context
== ISIS_CONTEXT_LSP
1974 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH
) {
1975 struct isis_tlvs
*tlvs
= dest
;
1976 dest
= &tlvs
->oldstyle_ip_reach
;
1977 } else if (context
== ISIS_CONTEXT_LSP
1978 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH_EXT
) {
1979 struct isis_tlvs
*tlvs
= dest
;
1980 dest
= &tlvs
->oldstyle_ip_reach_ext
;
1983 if (context
== ISIS_CONTEXT_LSP
1984 && tlv_type
== ISIS_TLV_MT_ROUTER_INFO
) {
1985 struct isis_tlvs
*tlvs
= dest
;
1986 tlvs
->mt_router_info_empty
= (tlv_pos
>= (size_t)tlv_len
);
1989 while (tlv_pos
< (size_t)tlv_len
) {
1990 rv
= unpack_item(mtid
, context
, tlv_type
, tlv_len
- tlv_pos
, s
,
1991 log
, dest
, indent
+ 2);
1995 tlv_pos
= stream_get_getp(s
) - tlv_start
;
2001 /* Functions to manipulate mt_item_lists */
2003 static int isis_mt_item_list_cmp(const struct isis_item_list
*a
,
2004 const struct isis_item_list
*b
)
2006 if (a
->mtid
< b
->mtid
)
2008 if (a
->mtid
> b
->mtid
)
2013 RB_PROTOTYPE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
2014 RB_GENERATE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
2016 struct isis_item_list
*isis_get_mt_items(struct isis_mt_item_list
*m
,
2019 struct isis_item_list
*rv
;
2021 rv
= isis_lookup_mt_items(m
, mtid
);
2023 rv
= XCALLOC(MTYPE_ISIS_MT_ITEM_LIST
, sizeof(*rv
));
2026 RB_INSERT(isis_mt_item_list
, m
, rv
);
2032 struct isis_item_list
*isis_lookup_mt_items(struct isis_mt_item_list
*m
,
2035 struct isis_item_list key
= {.mtid
= mtid
};
2037 return RB_FIND(isis_mt_item_list
, m
, &key
);
2040 static void free_mt_items(enum isis_tlv_context context
,
2041 enum isis_tlv_type type
, struct isis_mt_item_list
*m
)
2043 struct isis_item_list
*n
, *nnext
;
2045 RB_FOREACH_SAFE (n
, isis_mt_item_list
, m
, nnext
) {
2046 free_items(context
, type
, n
);
2047 RB_REMOVE(isis_mt_item_list
, m
, n
);
2048 XFREE(MTYPE_ISIS_MT_ITEM_LIST
, n
);
2052 static void format_mt_items(enum isis_tlv_context context
,
2053 enum isis_tlv_type type
,
2054 struct isis_mt_item_list
*m
, struct sbuf
*buf
,
2057 struct isis_item_list
*n
;
2059 RB_FOREACH (n
, isis_mt_item_list
, m
) {
2060 format_items_(n
->mtid
, context
, type
, n
, buf
, indent
);
2064 static int pack_mt_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
2065 struct isis_mt_item_list
*m
, struct stream
*s
,
2066 struct isis_tlvs
**fragment_tlvs
,
2067 struct pack_order_entry
*pe
,
2068 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2069 struct list
*new_fragment_arg
)
2071 struct isis_item_list
*n
;
2073 RB_FOREACH (n
, isis_mt_item_list
, m
) {
2076 rv
= pack_items_(n
->mtid
, context
, type
, n
, s
, fragment_tlvs
,
2077 pe
, new_fragment
, new_fragment_arg
);
2085 static void copy_mt_items(enum isis_tlv_context context
,
2086 enum isis_tlv_type type
,
2087 struct isis_mt_item_list
*src
,
2088 struct isis_mt_item_list
*dest
)
2090 struct isis_item_list
*n
;
2092 RB_INIT(isis_mt_item_list
, dest
);
2094 RB_FOREACH (n
, isis_mt_item_list
, src
) {
2095 copy_items(context
, type
, n
, isis_get_mt_items(dest
, n
->mtid
));
2099 /* Functions related to tlvs in general */
2101 struct isis_tlvs
*isis_alloc_tlvs(void)
2103 struct isis_tlvs
*result
;
2105 result
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*result
));
2107 init_item_list(&result
->isis_auth
);
2108 init_item_list(&result
->area_addresses
);
2109 init_item_list(&result
->mt_router_info
);
2110 init_item_list(&result
->oldstyle_reach
);
2111 init_item_list(&result
->lan_neighbor
);
2112 init_item_list(&result
->lsp_entries
);
2113 init_item_list(&result
->extended_reach
);
2114 RB_INIT(isis_mt_item_list
, &result
->mt_reach
);
2115 init_item_list(&result
->oldstyle_ip_reach
);
2116 init_item_list(&result
->oldstyle_ip_reach_ext
);
2117 init_item_list(&result
->ipv4_address
);
2118 init_item_list(&result
->ipv6_address
);
2119 init_item_list(&result
->extended_ip_reach
);
2120 RB_INIT(isis_mt_item_list
, &result
->mt_ip_reach
);
2121 init_item_list(&result
->ipv6_reach
);
2122 RB_INIT(isis_mt_item_list
, &result
->mt_ipv6_reach
);
2127 struct isis_tlvs
*isis_copy_tlvs(struct isis_tlvs
*tlvs
)
2129 struct isis_tlvs
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2131 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
,
2134 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2135 &tlvs
->area_addresses
, &rv
->area_addresses
);
2137 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2138 &tlvs
->mt_router_info
, &rv
->mt_router_info
);
2140 rv
->mt_router_info_empty
= tlvs
->mt_router_info_empty
;
2142 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2143 &tlvs
->oldstyle_reach
, &rv
->oldstyle_reach
);
2145 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2146 &tlvs
->lan_neighbor
, &rv
->lan_neighbor
);
2148 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
2151 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2152 &tlvs
->extended_reach
, &rv
->extended_reach
);
2154 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
2157 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2158 &tlvs
->oldstyle_ip_reach
, &rv
->oldstyle_ip_reach
);
2160 copy_tlv_protocols_supported(&tlvs
->protocols_supported
,
2161 &rv
->protocols_supported
);
2163 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2164 &tlvs
->oldstyle_ip_reach_ext
, &rv
->oldstyle_ip_reach_ext
);
2166 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
, &tlvs
->ipv4_address
,
2169 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
, &tlvs
->ipv6_address
,
2172 rv
->te_router_id
= copy_tlv_te_router_id(tlvs
->te_router_id
);
2174 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2175 &tlvs
->extended_ip_reach
, &rv
->extended_ip_reach
);
2177 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2178 &tlvs
->mt_ip_reach
, &rv
->mt_ip_reach
);
2180 rv
->hostname
= copy_tlv_dynamic_hostname(tlvs
->hostname
);
2182 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
2185 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2186 &tlvs
->mt_ipv6_reach
, &rv
->mt_ipv6_reach
);
2188 rv
->threeway_adj
= copy_tlv_threeway_adj(tlvs
->threeway_adj
);
2193 static void format_tlvs(struct isis_tlvs
*tlvs
, struct sbuf
*buf
, int indent
)
2195 format_tlv_protocols_supported(&tlvs
->protocols_supported
, buf
, indent
);
2197 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
, buf
,
2200 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2201 &tlvs
->area_addresses
, buf
, indent
);
2203 if (tlvs
->mt_router_info_empty
) {
2204 sbuf_push(buf
, indent
, "MT Router Info: None\n");
2206 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2207 &tlvs
->mt_router_info
, buf
, indent
);
2210 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2211 &tlvs
->oldstyle_reach
, buf
, indent
);
2213 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2214 &tlvs
->lan_neighbor
, buf
, indent
);
2216 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
2219 format_tlv_dynamic_hostname(tlvs
->hostname
, buf
, indent
);
2220 format_tlv_te_router_id(tlvs
->te_router_id
, buf
, indent
);
2222 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2223 &tlvs
->extended_reach
, buf
, indent
);
2225 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
2228 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2229 &tlvs
->oldstyle_ip_reach
, buf
, indent
);
2231 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2232 &tlvs
->oldstyle_ip_reach_ext
, buf
, indent
);
2234 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
2235 &tlvs
->ipv4_address
, buf
, indent
);
2237 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
2238 &tlvs
->ipv6_address
, buf
, indent
);
2240 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2241 &tlvs
->extended_ip_reach
, buf
, indent
);
2243 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2244 &tlvs
->mt_ip_reach
, buf
, indent
);
2246 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
2249 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2250 &tlvs
->mt_ipv6_reach
, buf
, indent
);
2252 format_tlv_threeway_adj(tlvs
->threeway_adj
, buf
, indent
);
2255 const char *isis_format_tlvs(struct isis_tlvs
*tlvs
)
2257 static struct sbuf buf
;
2259 if (!sbuf_buf(&buf
))
2260 sbuf_init(&buf
, NULL
, 0);
2263 format_tlvs(tlvs
, &buf
, 0);
2264 return sbuf_buf(&buf
);
2267 void isis_free_tlvs(struct isis_tlvs
*tlvs
)
2272 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
2273 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2274 &tlvs
->area_addresses
);
2275 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2276 &tlvs
->mt_router_info
);
2277 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2278 &tlvs
->oldstyle_reach
);
2279 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2280 &tlvs
->lan_neighbor
);
2281 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
);
2282 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2283 &tlvs
->extended_reach
);
2284 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
);
2285 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2286 &tlvs
->oldstyle_ip_reach
);
2287 free_tlv_protocols_supported(&tlvs
->protocols_supported
);
2288 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2289 &tlvs
->oldstyle_ip_reach_ext
);
2290 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
2291 &tlvs
->ipv4_address
);
2292 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
2293 &tlvs
->ipv6_address
);
2294 free_tlv_te_router_id(tlvs
->te_router_id
);
2295 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2296 &tlvs
->extended_ip_reach
);
2297 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2298 &tlvs
->mt_ip_reach
);
2299 free_tlv_dynamic_hostname(tlvs
->hostname
);
2300 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
);
2301 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2302 &tlvs
->mt_ipv6_reach
);
2303 free_tlv_threeway_adj(tlvs
->threeway_adj
);
2305 XFREE(MTYPE_ISIS_TLV
, tlvs
);
2308 static void add_padding(struct stream
*s
)
2310 while (STREAM_WRITEABLE(s
)) {
2311 if (STREAM_WRITEABLE(s
) == 1)
2313 uint32_t padding_len
= STREAM_WRITEABLE(s
) - 2;
2315 if (padding_len
> 255) {
2316 if (padding_len
== 256)
2322 stream_putc(s
, ISIS_TLV_PADDING
);
2323 stream_putc(s
, padding_len
);
2324 stream_put(s
, NULL
, padding_len
);
2328 #define LSP_REM_LIFETIME_OFF 10
2329 #define LSP_CHECKSUM_OFF 24
2330 static void safe_auth_md5(struct stream
*s
, uint16_t *checksum
,
2331 uint16_t *rem_lifetime
)
2333 memcpy(rem_lifetime
, STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
,
2334 sizeof(*rem_lifetime
));
2335 memset(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, 0, sizeof(*rem_lifetime
));
2336 memcpy(checksum
, STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, sizeof(*checksum
));
2337 memset(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, 0, sizeof(*checksum
));
2340 static void restore_auth_md5(struct stream
*s
, uint16_t checksum
,
2341 uint16_t rem_lifetime
)
2343 memcpy(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, &rem_lifetime
,
2344 sizeof(rem_lifetime
));
2345 memcpy(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, &checksum
, sizeof(checksum
));
2348 static void update_auth_hmac_md5(struct isis_auth
*auth
, struct stream
*s
,
2352 uint16_t checksum
, rem_lifetime
;
2355 safe_auth_md5(s
, &checksum
, &rem_lifetime
);
2357 memset(STREAM_DATA(s
) + auth
->offset
, 0, 16);
2358 hmac_md5(STREAM_DATA(s
), stream_get_endp(s
), auth
->passwd
,
2359 auth
->plength
, digest
);
2360 memcpy(auth
->value
, digest
, 16);
2361 memcpy(STREAM_DATA(s
) + auth
->offset
, digest
, 16);
2364 restore_auth_md5(s
, checksum
, rem_lifetime
);
2367 static void update_auth(struct isis_tlvs
*tlvs
, struct stream
*s
, bool is_lsp
)
2369 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
2371 for (struct isis_auth
*auth
= auth_head
; auth
; auth
= auth
->next
) {
2372 if (auth
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
2373 update_auth_hmac_md5(auth
, s
, is_lsp
);
2377 static int handle_pack_entry(struct pack_order_entry
*pe
,
2378 struct isis_tlvs
*tlvs
, struct stream
*stream
,
2379 struct isis_tlvs
**fragment_tlvs
,
2380 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2381 struct list
*new_fragment_arg
)
2385 if (pe
->how_to_pack
== ISIS_ITEMS
) {
2386 struct isis_item_list
*l
;
2387 l
= (struct isis_item_list
*)(((char *)tlvs
)
2388 + pe
->what_to_pack
);
2389 rv
= pack_items(pe
->context
, pe
->type
, l
, stream
, fragment_tlvs
,
2390 pe
, new_fragment
, new_fragment_arg
);
2392 struct isis_mt_item_list
*l
;
2393 l
= (struct isis_mt_item_list
*)(((char *)tlvs
)
2394 + pe
->what_to_pack
);
2395 rv
= pack_mt_items(pe
->context
, pe
->type
, l
, stream
,
2396 fragment_tlvs
, pe
, new_fragment
,
2403 static int pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
2404 struct isis_tlvs
*fragment_tlvs
,
2405 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2406 struct list
*new_fragment_arg
)
2410 /* When fragmenting, don't add auth as it's already accounted for in the
2411 * size we are given. */
2412 if (!fragment_tlvs
) {
2413 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
,
2414 &tlvs
->isis_auth
, stream
, NULL
, NULL
, NULL
,
2420 rv
= pack_tlv_protocols_supported(&tlvs
->protocols_supported
, stream
);
2423 if (fragment_tlvs
) {
2424 copy_tlv_protocols_supported(
2425 &tlvs
->protocols_supported
,
2426 &fragment_tlvs
->protocols_supported
);
2429 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2430 &tlvs
->area_addresses
, stream
, NULL
, NULL
, NULL
, NULL
);
2433 if (fragment_tlvs
) {
2434 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2435 &tlvs
->area_addresses
,
2436 &fragment_tlvs
->area_addresses
);
2440 if (tlvs
->mt_router_info_empty
) {
2441 if (STREAM_WRITEABLE(stream
) < 2)
2443 stream_putc(stream
, ISIS_TLV_MT_ROUTER_INFO
);
2444 stream_putc(stream
, 0);
2446 fragment_tlvs
->mt_router_info_empty
= true;
2448 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2449 &tlvs
->mt_router_info
, stream
, NULL
, NULL
, NULL
,
2453 if (fragment_tlvs
) {
2454 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2455 &tlvs
->mt_router_info
,
2456 &fragment_tlvs
->mt_router_info
);
2460 rv
= pack_tlv_dynamic_hostname(tlvs
->hostname
, stream
);
2464 fragment_tlvs
->hostname
=
2465 copy_tlv_dynamic_hostname(tlvs
->hostname
);
2467 rv
= pack_tlv_te_router_id(tlvs
->te_router_id
, stream
);
2470 if (fragment_tlvs
) {
2471 fragment_tlvs
->te_router_id
=
2472 copy_tlv_te_router_id(tlvs
->te_router_id
);
2475 rv
= pack_tlv_threeway_adj(tlvs
->threeway_adj
, stream
);
2478 if (fragment_tlvs
) {
2479 fragment_tlvs
->threeway_adj
=
2480 copy_tlv_threeway_adj(tlvs
->threeway_adj
);
2483 for (size_t pack_idx
= 0; pack_idx
< array_size(pack_order
);
2485 rv
= handle_pack_entry(&pack_order
[pack_idx
], tlvs
, stream
,
2486 fragment_tlvs
? &fragment_tlvs
: NULL
,
2487 new_fragment
, new_fragment_arg
);
2496 int isis_pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
2497 size_t len_pointer
, bool pad
, bool is_lsp
)
2501 rv
= pack_tlvs(tlvs
, stream
, NULL
, NULL
, NULL
);
2506 add_padding(stream
);
2508 if (len_pointer
!= (size_t)-1) {
2509 stream_putw_at(stream
, len_pointer
, stream_get_endp(stream
));
2512 update_auth(tlvs
, stream
, is_lsp
);
2517 static struct isis_tlvs
*new_fragment(struct list
*l
)
2519 struct isis_tlvs
*rv
= isis_alloc_tlvs();
2521 listnode_add(l
, rv
);
2525 struct list
*isis_fragment_tlvs(struct isis_tlvs
*tlvs
, size_t size
)
2527 struct stream
*dummy_stream
= stream_new(size
);
2528 struct list
*rv
= list_new();
2529 struct isis_tlvs
*fragment_tlvs
= new_fragment(rv
);
2531 if (pack_tlvs(tlvs
, dummy_stream
, fragment_tlvs
, new_fragment
, rv
)) {
2532 struct listnode
*node
;
2533 for (ALL_LIST_ELEMENTS_RO(rv
, node
, fragment_tlvs
))
2534 isis_free_tlvs(fragment_tlvs
);
2535 list_delete_and_null(&rv
);
2538 stream_free(dummy_stream
);
2542 static int unpack_tlv_unknown(enum isis_tlv_context context
, uint8_t tlv_type
,
2543 uint8_t tlv_len
, struct stream
*s
,
2544 struct sbuf
*log
, int indent
)
2546 stream_forward_getp(s
, tlv_len
);
2547 sbuf_push(log
, indent
,
2548 "Skipping unknown TLV %" PRIu8
" (%" PRIu8
" bytes)\n",
2553 static int unpack_tlv(enum isis_tlv_context context
, size_t avail_len
,
2554 struct stream
*stream
, struct sbuf
*log
, void *dest
,
2557 uint8_t tlv_type
, tlv_len
;
2558 const struct tlv_ops
*ops
;
2560 sbuf_push(log
, indent
, "Unpacking TLV...\n");
2562 if (avail_len
< 2) {
2565 "Available data %zu too short to contain a TLV header.\n",
2570 tlv_type
= stream_getc(stream
);
2571 tlv_len
= stream_getc(stream
);
2573 sbuf_push(log
, indent
+ 2,
2574 "Found TLV of type %" PRIu8
" and len %" PRIu8
".\n",
2577 if (avail_len
< ((size_t)tlv_len
) + 2) {
2578 sbuf_push(log
, indent
+ 2,
2579 "Available data %zu too short for claimed TLV len %" PRIu8
".\n",
2580 avail_len
- 2, tlv_len
);
2584 ops
= tlv_table
[context
][tlv_type
];
2585 if (ops
&& ops
->unpack
) {
2586 return ops
->unpack(context
, tlv_type
, tlv_len
, stream
, log
,
2590 return unpack_tlv_unknown(context
, tlv_type
, tlv_len
, stream
, log
,
2594 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
2595 struct stream
*stream
, struct sbuf
*log
, void *dest
,
2599 size_t tlv_start
, tlv_pos
;
2601 tlv_start
= stream_get_getp(stream
);
2604 sbuf_push(log
, indent
, "Unpacking %zu bytes of %s...\n", avail_len
,
2605 (context
== ISIS_CONTEXT_LSP
) ? "TLVs" : "sub-TLVs");
2607 while (tlv_pos
< avail_len
) {
2608 rv
= unpack_tlv(context
, avail_len
- tlv_pos
, stream
, log
, dest
,
2613 tlv_pos
= stream_get_getp(stream
) - tlv_start
;
2619 int isis_unpack_tlvs(size_t avail_len
, struct stream
*stream
,
2620 struct isis_tlvs
**dest
, const char **log
)
2622 static struct sbuf logbuf
;
2625 struct isis_tlvs
*result
;
2627 if (!sbuf_buf(&logbuf
))
2628 sbuf_init(&logbuf
, NULL
, 0);
2630 sbuf_reset(&logbuf
);
2631 if (avail_len
> STREAM_READABLE(stream
)) {
2632 sbuf_push(&logbuf
, indent
,
2633 "Stream doesn't contain sufficient data. "
2634 "Claimed %zu, available %zu\n",
2635 avail_len
, STREAM_READABLE(stream
));
2639 result
= isis_alloc_tlvs();
2640 rv
= unpack_tlvs(ISIS_CONTEXT_LSP
, avail_len
, stream
, &logbuf
, result
,
2643 *log
= sbuf_buf(&logbuf
);
2649 #define TLV_OPS(_name_, _desc_) \
2650 static const struct tlv_ops tlv_##_name_##_ops = { \
2651 .name = _desc_, .unpack = unpack_tlv_##_name_, \
2654 #define ITEM_TLV_OPS(_name_, _desc_) \
2655 static const struct tlv_ops tlv_##_name_##_ops = { \
2657 .unpack = unpack_tlv_with_items, \
2659 .pack_item = pack_item_##_name_, \
2660 .free_item = free_item_##_name_, \
2661 .unpack_item = unpack_item_##_name_, \
2662 .format_item = format_item_##_name_, \
2663 .copy_item = copy_item_##_name_}
2665 #define SUBTLV_OPS(_name_, _desc_) \
2666 static const struct tlv_ops subtlv_##_name_##_ops = { \
2667 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
2670 ITEM_TLV_OPS(area_address
, "TLV 1 Area Addresses");
2671 ITEM_TLV_OPS(oldstyle_reach
, "TLV 2 IS Reachability");
2672 ITEM_TLV_OPS(lan_neighbor
, "TLV 6 LAN Neighbors");
2673 ITEM_TLV_OPS(lsp_entry
, "TLV 9 LSP Entries");
2674 ITEM_TLV_OPS(auth
, "TLV 10 IS-IS Auth");
2675 ITEM_TLV_OPS(extended_reach
, "TLV 22 Extended Reachability");
2676 ITEM_TLV_OPS(oldstyle_ip_reach
, "TLV 128/130 IP Reachability");
2677 TLV_OPS(protocols_supported
, "TLV 129 Protocols Supported");
2678 ITEM_TLV_OPS(ipv4_address
, "TLV 132 IPv4 Interface Address");
2679 TLV_OPS(te_router_id
, "TLV 134 TE Router ID");
2680 ITEM_TLV_OPS(extended_ip_reach
, "TLV 135 Extended IP Reachability");
2681 TLV_OPS(dynamic_hostname
, "TLV 137 Dynamic Hostname");
2682 ITEM_TLV_OPS(mt_router_info
, "TLV 229 MT Router Information");
2683 TLV_OPS(threeway_adj
, "TLV 240 P2P Three-Way Adjacency");
2684 ITEM_TLV_OPS(ipv6_address
, "TLV 232 IPv6 Interface Address");
2685 ITEM_TLV_OPS(ipv6_reach
, "TLV 236 IPv6 Reachability");
2687 SUBTLV_OPS(ipv6_source_prefix
, "Sub-TLV 22 IPv6 Source Prefix");
2689 static const struct tlv_ops
*tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
] = {
2690 [ISIS_CONTEXT_LSP
] = {
2691 [ISIS_TLV_AREA_ADDRESSES
] = &tlv_area_address_ops
,
2692 [ISIS_TLV_OLDSTYLE_REACH
] = &tlv_oldstyle_reach_ops
,
2693 [ISIS_TLV_LAN_NEIGHBORS
] = &tlv_lan_neighbor_ops
,
2694 [ISIS_TLV_LSP_ENTRY
] = &tlv_lsp_entry_ops
,
2695 [ISIS_TLV_AUTH
] = &tlv_auth_ops
,
2696 [ISIS_TLV_EXTENDED_REACH
] = &tlv_extended_reach_ops
,
2697 [ISIS_TLV_MT_REACH
] = &tlv_extended_reach_ops
,
2698 [ISIS_TLV_OLDSTYLE_IP_REACH
] = &tlv_oldstyle_ip_reach_ops
,
2699 [ISIS_TLV_PROTOCOLS_SUPPORTED
] = &tlv_protocols_supported_ops
,
2700 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT
] = &tlv_oldstyle_ip_reach_ops
,
2701 [ISIS_TLV_IPV4_ADDRESS
] = &tlv_ipv4_address_ops
,
2702 [ISIS_TLV_TE_ROUTER_ID
] = &tlv_te_router_id_ops
,
2703 [ISIS_TLV_EXTENDED_IP_REACH
] = &tlv_extended_ip_reach_ops
,
2704 [ISIS_TLV_MT_IP_REACH
] = &tlv_extended_ip_reach_ops
,
2705 [ISIS_TLV_DYNAMIC_HOSTNAME
] = &tlv_dynamic_hostname_ops
,
2706 [ISIS_TLV_MT_ROUTER_INFO
] = &tlv_mt_router_info_ops
,
2707 [ISIS_TLV_THREE_WAY_ADJ
] = &tlv_threeway_adj_ops
,
2708 [ISIS_TLV_IPV6_ADDRESS
] = &tlv_ipv6_address_ops
,
2709 [ISIS_TLV_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
2710 [ISIS_TLV_MT_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
2712 [ISIS_CONTEXT_SUBTLV_NE_REACH
] = {},
2713 [ISIS_CONTEXT_SUBTLV_IP_REACH
] = {},
2714 [ISIS_CONTEXT_SUBTLV_IPV6_REACH
] = {
2715 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX
] = &subtlv_ipv6_source_prefix_ops
,
2719 /* Accessor functions */
2721 void isis_tlvs_add_auth(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
)
2723 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
2724 init_item_list(&tlvs
->isis_auth
);
2726 if (passwd
->type
== ISIS_PASSWD_TYPE_UNUSED
)
2729 struct isis_auth
*auth
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*auth
));
2731 auth
->type
= passwd
->type
;
2733 auth
->plength
= passwd
->len
;
2734 memcpy(auth
->passwd
, passwd
->passwd
,
2735 MIN(sizeof(auth
->passwd
), sizeof(passwd
->passwd
)));
2737 if (auth
->type
== ISIS_PASSWD_TYPE_CLEARTXT
) {
2738 auth
->length
= passwd
->len
;
2739 memcpy(auth
->value
, passwd
->passwd
,
2740 MIN(sizeof(auth
->value
), sizeof(passwd
->passwd
)));
2743 append_item(&tlvs
->isis_auth
, (struct isis_item
*)auth
);
2746 void isis_tlvs_add_area_addresses(struct isis_tlvs
*tlvs
,
2747 struct list
*addresses
)
2749 struct listnode
*node
;
2750 struct area_addr
*area_addr
;
2752 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, area_addr
)) {
2753 struct isis_area_address
*a
=
2754 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
2756 a
->len
= area_addr
->addr_len
;
2757 memcpy(a
->addr
, area_addr
->area_addr
, 20);
2758 append_item(&tlvs
->area_addresses
, (struct isis_item
*)a
);
2762 void isis_tlvs_add_lan_neighbors(struct isis_tlvs
*tlvs
, struct list
*neighbors
)
2764 struct listnode
*node
;
2767 for (ALL_LIST_ELEMENTS_RO(neighbors
, node
, snpa
)) {
2768 struct isis_lan_neighbor
*n
=
2769 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*n
));
2771 memcpy(n
->mac
, snpa
, 6);
2772 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)n
);
2776 void isis_tlvs_set_protocols_supported(struct isis_tlvs
*tlvs
,
2777 struct nlpids
*nlpids
)
2779 tlvs
->protocols_supported
.count
= nlpids
->count
;
2780 if (tlvs
->protocols_supported
.protocols
)
2781 XFREE(MTYPE_ISIS_TLV
, tlvs
->protocols_supported
.protocols
);
2782 if (nlpids
->count
) {
2783 tlvs
->protocols_supported
.protocols
=
2784 XCALLOC(MTYPE_ISIS_TLV
, nlpids
->count
);
2785 memcpy(tlvs
->protocols_supported
.protocols
, nlpids
->nlpids
,
2788 tlvs
->protocols_supported
.protocols
= NULL
;
2792 void isis_tlvs_add_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
,
2793 bool overload
, bool attached
)
2795 struct isis_mt_router_info
*i
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*i
));
2797 i
->overload
= overload
;
2798 i
->attached
= attached
;
2800 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)i
);
2803 void isis_tlvs_add_ipv4_address(struct isis_tlvs
*tlvs
, struct in_addr
*addr
)
2805 struct isis_ipv4_address
*a
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
2807 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)a
);
2811 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs
*tlvs
,
2812 struct list
*addresses
)
2814 struct listnode
*node
;
2815 struct prefix_ipv4
*ip_addr
;
2816 unsigned int addr_count
= 0;
2818 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
2819 isis_tlvs_add_ipv4_address(tlvs
, &ip_addr
->prefix
);
2821 if (addr_count
>= 63)
2826 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs
*tlvs
,
2827 struct list
*addresses
)
2829 struct listnode
*node
;
2830 struct prefix_ipv6
*ip_addr
;
2832 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
2833 struct isis_ipv6_address
*a
=
2834 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
2836 a
->addr
= ip_addr
->prefix
;
2837 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)a
);
2841 typedef bool (*auth_validator_func
)(struct isis_passwd
*passwd
,
2842 struct stream
*stream
,
2843 struct isis_auth
*auth
, bool is_lsp
);
2845 static bool auth_validator_cleartxt(struct isis_passwd
*passwd
,
2846 struct stream
*stream
,
2847 struct isis_auth
*auth
, bool is_lsp
)
2849 return (auth
->length
== passwd
->len
2850 && !memcmp(auth
->value
, passwd
->passwd
, passwd
->len
));
2853 static bool auth_validator_hmac_md5(struct isis_passwd
*passwd
,
2854 struct stream
*stream
,
2855 struct isis_auth
*auth
, bool is_lsp
)
2859 uint16_t rem_lifetime
;
2862 safe_auth_md5(stream
, &checksum
, &rem_lifetime
);
2864 memset(STREAM_DATA(stream
) + auth
->offset
, 0, 16);
2865 hmac_md5(STREAM_DATA(stream
), stream_get_endp(stream
), passwd
->passwd
,
2866 passwd
->len
, digest
);
2867 memcpy(STREAM_DATA(stream
) + auth
->offset
, auth
->value
, 16);
2869 bool rv
= !memcmp(digest
, auth
->value
, 16);
2872 restore_auth_md5(stream
, checksum
, rem_lifetime
);
2877 static const auth_validator_func auth_validators
[] = {
2878 [ISIS_PASSWD_TYPE_CLEARTXT
] = auth_validator_cleartxt
,
2879 [ISIS_PASSWD_TYPE_HMAC_MD5
] = auth_validator_hmac_md5
,
2882 bool isis_tlvs_auth_is_valid(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
,
2883 struct stream
*stream
, bool is_lsp
)
2885 /* If no auth is set, always pass authentication */
2889 /* If we don't known how to validate the auth, return invalid */
2890 if (passwd
->type
>= array_size(auth_validators
)
2891 || !auth_validators
[passwd
->type
])
2894 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
2895 struct isis_auth
*auth
;
2896 for (auth
= auth_head
; auth
; auth
= auth
->next
) {
2897 if (auth
->type
== passwd
->type
)
2901 /* If matching auth TLV could not be found, return invalid */
2905 /* Perform validation and return result */
2906 return auth_validators
[passwd
->type
](passwd
, stream
, auth
, is_lsp
);
2909 bool isis_tlvs_area_addresses_match(struct isis_tlvs
*tlvs
,
2910 struct list
*addresses
)
2912 struct isis_area_address
*addr_head
;
2914 addr_head
= (struct isis_area_address
*)tlvs
->area_addresses
.head
;
2915 for (struct isis_area_address
*addr
= addr_head
; addr
;
2916 addr
= addr
->next
) {
2917 struct listnode
*node
;
2918 struct area_addr
*a
;
2920 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, a
)) {
2921 if (a
->addr_len
== addr
->len
2922 && !memcmp(a
->area_addr
, addr
->addr
, addr
->len
))
2930 static void tlvs_area_addresses_to_adj(struct isis_tlvs
*tlvs
,
2931 struct isis_adjacency
*adj
,
2934 if (adj
->area_address_count
!= tlvs
->area_addresses
.count
) {
2936 adj
->area_address_count
= tlvs
->area_addresses
.count
;
2937 adj
->area_addresses
= XREALLOC(
2938 MTYPE_ISIS_ADJACENCY_INFO
, adj
->area_addresses
,
2939 adj
->area_address_count
* sizeof(*adj
->area_addresses
));
2942 struct isis_area_address
*addr
= NULL
;
2943 for (unsigned int i
= 0; i
< tlvs
->area_addresses
.count
; i
++) {
2945 addr
= (struct isis_area_address
*)
2946 tlvs
->area_addresses
.head
;
2950 if (adj
->area_addresses
[i
].addr_len
== addr
->len
2951 && !memcmp(adj
->area_addresses
[i
].area_addr
, addr
->addr
,
2957 adj
->area_addresses
[i
].addr_len
= addr
->len
;
2958 memcpy(adj
->area_addresses
[i
].area_addr
, addr
->addr
, addr
->len
);
2962 static void tlvs_protocols_supported_to_adj(struct isis_tlvs
*tlvs
,
2963 struct isis_adjacency
*adj
,
2966 bool ipv4_supported
= false, ipv6_supported
= false;
2968 for (uint8_t i
= 0; i
< tlvs
->protocols_supported
.count
; i
++) {
2969 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IP
)
2970 ipv4_supported
= true;
2971 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IPV6
)
2972 ipv6_supported
= true;
2975 struct nlpids reduced
= {};
2977 if (ipv4_supported
&& ipv6_supported
) {
2979 reduced
.nlpids
[0] = NLPID_IP
;
2980 reduced
.nlpids
[1] = NLPID_IPV6
;
2981 } else if (ipv4_supported
) {
2983 reduced
.nlpids
[0] = NLPID_IP
;
2984 } else if (ipv6_supported
) {
2986 reduced
.nlpids
[1] = NLPID_IPV6
;
2991 if (adj
->nlpids
.count
== reduced
.count
2992 && !memcmp(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
))
2996 adj
->nlpids
.count
= reduced
.count
;
2997 memcpy(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
);
3000 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs
*tlvs
,
3001 struct isis_adjacency
*adj
,
3004 if (adj
->ipv4_address_count
!= tlvs
->ipv4_address
.count
) {
3006 adj
->ipv4_address_count
= tlvs
->ipv4_address
.count
;
3007 adj
->ipv4_addresses
= XREALLOC(
3008 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv4_addresses
,
3009 adj
->ipv4_address_count
* sizeof(*adj
->ipv4_addresses
));
3012 struct isis_ipv4_address
*addr
= NULL
;
3013 for (unsigned int i
= 0; i
< tlvs
->ipv4_address
.count
; i
++) {
3015 addr
= (struct isis_ipv4_address
*)
3016 tlvs
->ipv4_address
.head
;
3020 if (!memcmp(&adj
->ipv4_addresses
[i
], &addr
->addr
,
3021 sizeof(addr
->addr
)))
3025 adj
->ipv4_addresses
[i
] = addr
->addr
;
3029 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
3030 struct isis_adjacency
*adj
,
3033 if (adj
->ipv6_address_count
!= tlvs
->ipv6_address
.count
) {
3035 adj
->ipv6_address_count
= tlvs
->ipv6_address
.count
;
3036 adj
->ipv6_addresses
= XREALLOC(
3037 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv6_addresses
,
3038 adj
->ipv6_address_count
* sizeof(*adj
->ipv6_addresses
));
3041 struct isis_ipv6_address
*addr
= NULL
;
3042 for (unsigned int i
= 0; i
< tlvs
->ipv6_address
.count
; i
++) {
3044 addr
= (struct isis_ipv6_address
*)
3045 tlvs
->ipv6_address
.head
;
3049 if (!memcmp(&adj
->ipv6_addresses
[i
], &addr
->addr
,
3050 sizeof(addr
->addr
)))
3054 adj
->ipv6_addresses
[i
] = addr
->addr
;
3058 void isis_tlvs_to_adj(struct isis_tlvs
*tlvs
, struct isis_adjacency
*adj
,
3063 tlvs_area_addresses_to_adj(tlvs
, adj
, changed
);
3064 tlvs_protocols_supported_to_adj(tlvs
, adj
, changed
);
3065 tlvs_ipv4_addresses_to_adj(tlvs
, adj
, changed
);
3066 tlvs_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
3069 bool isis_tlvs_own_snpa_found(struct isis_tlvs
*tlvs
, uint8_t *snpa
)
3071 struct isis_lan_neighbor
*ne_head
;
3073 ne_head
= (struct isis_lan_neighbor
*)tlvs
->lan_neighbor
.head
;
3074 for (struct isis_lan_neighbor
*ne
= ne_head
; ne
; ne
= ne
->next
) {
3075 if (!memcmp(ne
->mac
, snpa
, ETH_ALEN
))
3082 void isis_tlvs_add_lsp_entry(struct isis_tlvs
*tlvs
, struct isis_lsp
*lsp
)
3084 struct isis_lsp_entry
*entry
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*entry
));
3086 entry
->rem_lifetime
= lsp
->hdr
.rem_lifetime
;
3087 memcpy(entry
->id
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 2);
3088 entry
->checksum
= lsp
->hdr
.checksum
;
3089 entry
->seqno
= lsp
->hdr
.seqno
;
3092 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)entry
);
3095 void isis_tlvs_add_csnp_entries(struct isis_tlvs
*tlvs
, uint8_t *start_id
,
3096 uint8_t *stop_id
, uint16_t num_lsps
,
3097 dict_t
*lspdb
, struct isis_lsp
**last_lsp
)
3099 dnode_t
*first
= dict_lower_bound(lspdb
, start_id
);
3103 dnode_t
*last
= dict_upper_bound(lspdb
, stop_id
);
3104 dnode_t
*curr
= first
;
3106 isis_tlvs_add_lsp_entry(tlvs
, first
->dict_data
);
3107 *last_lsp
= first
->dict_data
;
3110 curr
= dict_next(lspdb
, curr
);
3112 isis_tlvs_add_lsp_entry(tlvs
, curr
->dict_data
);
3113 *last_lsp
= curr
->dict_data
;
3115 if (curr
== last
|| tlvs
->lsp_entries
.count
== num_lsps
)
3120 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs
*tlvs
,
3121 const char *hostname
)
3123 XFREE(MTYPE_ISIS_TLV
, tlvs
->hostname
);
3125 tlvs
->hostname
= XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
3128 void isis_tlvs_set_te_router_id(struct isis_tlvs
*tlvs
,
3129 const struct in_addr
*id
)
3131 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id
);
3134 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
3135 memcpy(tlvs
->te_router_id
, id
, sizeof(*id
));
3138 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs
*tlvs
,
3139 struct prefix_ipv4
*dest
, uint8_t metric
)
3141 struct isis_oldstyle_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3144 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3145 apply_mask_ipv4(&r
->prefix
);
3146 append_item(&tlvs
->oldstyle_ip_reach
, (struct isis_item
*)r
);
3149 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs
*tlvs
,
3150 struct prefix_ipv4
*dest
, uint32_t metric
)
3152 struct isis_extended_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3155 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3156 apply_mask_ipv4(&r
->prefix
);
3157 append_item(&tlvs
->extended_ip_reach
, (struct isis_item
*)r
);
3160 void isis_tlvs_add_ipv6_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3161 struct prefix_ipv6
*dest
, uint32_t metric
)
3163 struct isis_ipv6_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3166 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3167 apply_mask_ipv6(&r
->prefix
);
3169 struct isis_item_list
*l
;
3170 l
= (mtid
== ISIS_MT_IPV4_UNICAST
)
3172 : isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
3173 append_item(l
, (struct isis_item
*)r
);
3176 void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3177 struct prefix_ipv6
*dest
,
3178 struct prefix_ipv6
*src
,
3181 isis_tlvs_add_ipv6_reach(tlvs
, mtid
, dest
, metric
);
3182 struct isis_item_list
*l
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
,
3185 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)last_item(l
);
3186 r
->subtlvs
= isis_alloc_subtlvs();
3187 r
->subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*src
));
3188 memcpy(r
->subtlvs
->source_prefix
, src
, sizeof(*src
));
3191 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs
*tlvs
, uint8_t *id
,
3194 struct isis_oldstyle_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3197 memcpy(r
->id
, id
, sizeof(r
->id
));
3198 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)r
);
3201 void isis_tlvs_add_extended_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3202 uint8_t *id
, uint32_t metric
,
3203 uint8_t *subtlvs
, uint8_t subtlv_len
)
3205 struct isis_extended_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3207 memcpy(r
->id
, id
, sizeof(r
->id
));
3209 if (subtlvs
&& subtlv_len
) {
3210 r
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, subtlv_len
);
3211 memcpy(r
->subtlvs
, subtlvs
, subtlv_len
);
3212 r
->subtlv_len
= subtlv_len
;
3215 struct isis_item_list
*l
;
3216 if (mtid
== ISIS_MT_IPV4_UNICAST
)
3217 l
= &tlvs
->extended_reach
;
3219 l
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
3220 append_item(l
, (struct isis_item
*)r
);
3223 void isis_tlvs_add_threeway_adj(struct isis_tlvs
*tlvs
,
3224 enum isis_threeway_state state
,
3225 uint32_t local_circuit_id
,
3226 const uint8_t *neighbor_id
,
3227 uint32_t neighbor_circuit_id
)
3229 assert(!tlvs
->threeway_adj
);
3231 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
3232 tlvs
->threeway_adj
->state
= state
;
3233 tlvs
->threeway_adj
->local_circuit_id
= local_circuit_id
;
3236 tlvs
->threeway_adj
->neighbor_set
= true;
3237 memcpy(tlvs
->threeway_adj
->neighbor_id
, neighbor_id
, 6);
3238 tlvs
->threeway_adj
->neighbor_circuit_id
= neighbor_circuit_id
;
3242 struct isis_mt_router_info
*
3243 isis_tlvs_lookup_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
)
3245 if (tlvs
->mt_router_info_empty
)
3248 struct isis_mt_router_info
*rv
;
3249 for (rv
= (struct isis_mt_router_info
*)tlvs
->mt_router_info
.head
; rv
;
3251 if (rv
->mtid
== mtid
)