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-TLV 3 SR Prefix-SID */
112 static struct isis_item
*copy_item_prefix_sid(struct isis_item
*i
)
114 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
115 struct isis_prefix_sid
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
117 rv
->flags
= sid
->flags
;
118 rv
->algorithm
= sid
->algorithm
;
119 rv
->value
= sid
->value
;
120 return (struct isis_item
*)rv
;
123 static void format_item_prefix_sid(uint16_t mtid
, struct isis_item
*i
,
124 struct sbuf
*buf
, int indent
)
126 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
128 sbuf_push(buf
, indent
, "SR Prefix-SID:\n");
129 sbuf_push(buf
, indent
, " Flags:%s%s%s%s%s%s\n",
130 sid
->flags
& ISIS_PREFIX_SID_READVERTISED
? " READVERTISED" : "",
131 sid
->flags
& ISIS_PREFIX_SID_NODE
? " NODE" : "",
132 sid
->flags
& ISIS_PREFIX_SID_NO_PHP
? " NO_PHP" : "",
133 sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
? " EXPLICIT-NULL" : "",
134 sid
->flags
& ISIS_PREFIX_SID_VALUE
? " VALUE" : "",
135 sid
->flags
& ISIS_PREFIX_SID_LOCAL
? " LOCAL" : "");
136 sbuf_push(buf
, indent
, " Algorithm: %" PRIu8
"\n", sid
->algorithm
);
137 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
138 sbuf_push(buf
, indent
, "Label: %" PRIu32
"\n", sid
->value
);
140 sbuf_push(buf
, indent
, "Index: %" PRIu32
"\n", sid
->value
);
144 static void free_item_prefix_sid(struct isis_item
*i
)
146 XFREE(MTYPE_ISIS_SUBTLV
, i
);
149 static int pack_item_prefix_sid(struct isis_item
*i
, struct stream
*s
)
151 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
153 uint8_t size
= (sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? 5 : 6;
155 if (STREAM_WRITEABLE(s
) < size
)
158 stream_putc(s
, sid
->flags
);
159 stream_putc(s
, sid
->algorithm
);
161 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
162 stream_put3(s
, sid
->value
);
164 stream_putl(s
, sid
->value
);
170 static int unpack_item_prefix_sid(uint16_t mtid
, uint8_t len
, struct stream
*s
,
171 struct sbuf
*log
, void *dest
, int indent
)
173 struct isis_subtlvs
*subtlvs
= dest
;
174 struct isis_prefix_sid sid
= {
177 sbuf_push(log
, indent
, "Unpacking SR Prefix-SID...\n");
180 sbuf_push(log
, indent
,
181 "Not enough data left. (expected 5 or more bytes, got %" PRIu8
")\n",
186 sid
.flags
= stream_getc(s
);
187 if ((sid
.flags
& ISIS_PREFIX_SID_VALUE
)
188 != (sid
.flags
& ISIS_PREFIX_SID_LOCAL
)) {
189 sbuf_push(log
, indent
, "Flags inplausible: Local Flag needs to match Value Flag\n");
193 sid
.algorithm
= stream_getc(s
);
195 uint8_t expected_size
= (sid
.flags
& ISIS_PREFIX_SID_VALUE
) ? 5 : 6;
196 if (len
!= expected_size
) {
197 sbuf_push(log
, indent
,
198 "TLV size differs from expected size. "
199 "(expected %u but got %" PRIu8
")\n",
204 if (sid
.flags
& ISIS_PREFIX_SID_VALUE
) {
205 sid
.value
= stream_get3(s
);
207 sid
.value
= stream_getl(s
);
210 format_item_prefix_sid(mtid
, (struct isis_item
*)&sid
, log
, indent
+ 2);
211 append_item(&subtlvs
->prefix_sids
, copy_item_prefix_sid((struct isis_item
*)&sid
));
215 /* Functions for Sub-TVL ??? IPv6 Source Prefix */
217 static struct prefix_ipv6
*copy_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
)
222 struct prefix_ipv6
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
223 rv
->family
= p
->family
;
224 rv
->prefixlen
= p
->prefixlen
;
225 memcpy(&rv
->prefix
, &p
->prefix
, sizeof(rv
->prefix
));
229 static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
230 struct sbuf
*buf
, int indent
)
235 char prefixbuf
[PREFIX2STR_BUFFER
];
236 sbuf_push(buf
, indent
, "IPv6 Source Prefix: %s\n",
237 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
)));
240 static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
246 if (STREAM_WRITEABLE(s
) < 3 + (unsigned)PSIZE(p
->prefixlen
))
249 stream_putc(s
, ISIS_SUBTLV_IPV6_SOURCE_PREFIX
);
250 stream_putc(s
, 1 + PSIZE(p
->prefixlen
));
251 stream_putc(s
, p
->prefixlen
);
252 stream_put(s
, &p
->prefix
, PSIZE(p
->prefixlen
));
256 static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context
,
257 uint8_t tlv_type
, uint8_t tlv_len
,
258 struct stream
*s
, struct sbuf
*log
,
259 void *dest
, int indent
)
261 struct isis_subtlvs
*subtlvs
= dest
;
262 struct prefix_ipv6 p
= {
266 sbuf_push(log
, indent
, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
269 sbuf_push(log
, indent
,
270 "Not enough data left. (expected 1 or more bytes, got %" PRIu8
")\n",
275 p
.prefixlen
= stream_getc(s
);
276 if (p
.prefixlen
> 128) {
277 sbuf_push(log
, indent
, "Prefixlen %u is inplausible for IPv6\n",
282 if (tlv_len
!= 1 + PSIZE(p
.prefixlen
)) {
285 "TLV size differs from expected size for the prefixlen. "
286 "(expected %u but got %" PRIu8
")\n",
287 1 + PSIZE(p
.prefixlen
), tlv_len
);
291 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
293 if (subtlvs
->source_prefix
) {
296 "WARNING: source prefix Sub-TLV present multiple times.\n");
297 /* Ignore all but first occurrence of the source prefix Sub-TLV
302 subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(p
));
303 memcpy(subtlvs
->source_prefix
, &p
, sizeof(p
));
306 static void init_item_list(struct isis_item_list
*items
);
307 static struct isis_item
*copy_item(enum isis_tlv_context context
,
308 enum isis_tlv_type type
,
309 struct isis_item
*item
);
310 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
311 struct isis_item_list
*src
, struct isis_item_list
*dest
);
312 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
313 enum isis_tlv_type type
, struct isis_item_list
*items
,
314 struct sbuf
*buf
, int indent
);
315 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
316 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
317 struct isis_item_list
*items
);
318 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
319 enum isis_tlv_type type
, struct isis_item_list
*items
,
320 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
321 struct pack_order_entry
*pe
,
322 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
323 struct list
*new_fragment_arg
);
324 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
326 /* Functions related to subtlvs */
328 static struct isis_subtlvs
*isis_alloc_subtlvs(enum isis_tlv_context context
)
330 struct isis_subtlvs
*result
;
332 result
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*result
));
333 result
->context
= context
;
335 init_item_list(&result
->prefix_sids
);
340 static struct isis_subtlvs
*copy_subtlvs(struct isis_subtlvs
*subtlvs
)
345 struct isis_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
347 rv
->context
= subtlvs
->context
;
349 copy_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
350 &subtlvs
->prefix_sids
, &rv
->prefix_sids
);
353 copy_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
);
357 static void format_subtlvs(struct isis_subtlvs
*subtlvs
, struct sbuf
*buf
,
360 format_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
361 &subtlvs
->prefix_sids
, buf
, indent
);
363 format_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, buf
, indent
);
366 static void isis_free_subtlvs(struct isis_subtlvs
*subtlvs
)
371 free_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
372 &subtlvs
->prefix_sids
);
374 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
->source_prefix
);
376 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
);
379 static int pack_subtlvs(struct isis_subtlvs
*subtlvs
, struct stream
*s
)
382 size_t subtlv_len_pos
= stream_get_endp(s
);
384 if (STREAM_WRITEABLE(s
) < 1)
387 stream_putc(s
, 0); /* Put 0 as subtlvs length, filled in later */
389 rv
= pack_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
390 &subtlvs
->prefix_sids
, s
, NULL
, NULL
, NULL
, NULL
);
394 rv
= pack_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, s
);
398 size_t subtlv_len
= stream_get_endp(s
) - subtlv_len_pos
- 1;
399 if (subtlv_len
> 255)
402 stream_putc_at(s
, subtlv_len_pos
, subtlv_len
);
406 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
407 struct stream
*stream
, struct sbuf
*log
, void *dest
,
408 int indent
, bool *unpacked_known_tlvs
);
410 /* Functions related to TLVs 1 Area Addresses */
412 static struct isis_item
*copy_item_area_address(struct isis_item
*i
)
414 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
415 struct isis_area_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
418 memcpy(rv
->addr
, addr
->addr
, addr
->len
);
419 return (struct isis_item
*)rv
;
422 static void format_item_area_address(uint16_t mtid
, struct isis_item
*i
,
423 struct sbuf
*buf
, int indent
)
425 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
427 sbuf_push(buf
, indent
, "Area Address: %s\n",
428 isonet_print(addr
->addr
, addr
->len
));
431 static void free_item_area_address(struct isis_item
*i
)
433 XFREE(MTYPE_ISIS_TLV
, i
);
436 static int pack_item_area_address(struct isis_item
*i
, struct stream
*s
)
438 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
440 if (STREAM_WRITEABLE(s
) < (unsigned)1 + addr
->len
)
442 stream_putc(s
, addr
->len
);
443 stream_put(s
, addr
->addr
, addr
->len
);
447 static int unpack_item_area_address(uint16_t mtid
, uint8_t len
,
448 struct stream
*s
, struct sbuf
*log
,
449 void *dest
, int indent
)
451 struct isis_tlvs
*tlvs
= dest
;
452 struct isis_area_address
*rv
= NULL
;
454 sbuf_push(log
, indent
, "Unpack area address...\n");
458 "Not enough data left. (Expected 1 byte of address length, got %" PRIu8
464 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
465 rv
->len
= stream_getc(s
);
467 if (len
< 1 + rv
->len
) {
468 sbuf_push(log
, indent
, "Not enough data left. (Expected %" PRIu8
469 " bytes of address, got %" PRIu8
")\n",
474 if (rv
->len
< 1 || rv
->len
> 20) {
475 sbuf_push(log
, indent
,
476 "Implausible area address length %" PRIu8
"\n",
481 stream_get(rv
->addr
, s
, rv
->len
);
483 format_item_area_address(ISIS_MT_IPV4_UNICAST
, (struct isis_item
*)rv
,
485 append_item(&tlvs
->area_addresses
, (struct isis_item
*)rv
);
488 XFREE(MTYPE_ISIS_TLV
, rv
);
492 /* Functions related to TLV 2 (Old-Style) IS Reach */
493 static struct isis_item
*copy_item_oldstyle_reach(struct isis_item
*i
)
495 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
496 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
498 memcpy(rv
->id
, r
->id
, 7);
499 rv
->metric
= r
->metric
;
500 return (struct isis_item
*)rv
;
503 static void format_item_oldstyle_reach(uint16_t mtid
, struct isis_item
*i
,
504 struct sbuf
*buf
, int indent
)
506 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
508 sbuf_push(buf
, indent
, "IS Reachability: %s (Metric: %" PRIu8
")\n",
509 isis_format_id(r
->id
, 7), r
->metric
);
512 static void free_item_oldstyle_reach(struct isis_item
*i
)
514 XFREE(MTYPE_ISIS_TLV
, i
);
517 static int pack_item_oldstyle_reach(struct isis_item
*i
, struct stream
*s
)
519 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
521 if (STREAM_WRITEABLE(s
) < 11)
524 stream_putc(s
, r
->metric
);
525 stream_putc(s
, 0x80); /* delay metric - unsupported */
526 stream_putc(s
, 0x80); /* expense metric - unsupported */
527 stream_putc(s
, 0x80); /* error metric - unsupported */
528 stream_put(s
, r
->id
, 7);
533 static int unpack_item_oldstyle_reach(uint16_t mtid
, uint8_t len
,
534 struct stream
*s
, struct sbuf
*log
,
535 void *dest
, int indent
)
537 struct isis_tlvs
*tlvs
= dest
;
539 sbuf_push(log
, indent
, "Unpack oldstyle reach...\n");
543 "Not enough data left.(Expected 11 bytes of reach information, got %" PRIu8
549 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
550 rv
->metric
= stream_getc(s
);
551 if ((rv
->metric
& 0x3f) != rv
->metric
) {
552 sbuf_push(log
, indent
, "Metric has unplausible format\n");
555 stream_forward_getp(s
, 3); /* Skip other metrics */
556 stream_get(rv
->id
, s
, 7);
558 format_item_oldstyle_reach(mtid
, (struct isis_item
*)rv
, log
,
560 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)rv
);
564 /* Functions related to TLV 6 LAN Neighbors */
565 static struct isis_item
*copy_item_lan_neighbor(struct isis_item
*i
)
567 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
568 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
570 memcpy(rv
->mac
, n
->mac
, 6);
571 return (struct isis_item
*)rv
;
574 static void format_item_lan_neighbor(uint16_t mtid
, struct isis_item
*i
,
575 struct sbuf
*buf
, int indent
)
577 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
579 sbuf_push(buf
, indent
, "LAN Neighbor: %s\n", isis_format_id(n
->mac
, 6));
582 static void free_item_lan_neighbor(struct isis_item
*i
)
584 XFREE(MTYPE_ISIS_TLV
, i
);
587 static int pack_item_lan_neighbor(struct isis_item
*i
, struct stream
*s
)
589 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
591 if (STREAM_WRITEABLE(s
) < 6)
594 stream_put(s
, n
->mac
, 6);
599 static int unpack_item_lan_neighbor(uint16_t mtid
, uint8_t len
,
600 struct stream
*s
, struct sbuf
*log
,
601 void *dest
, int indent
)
603 struct isis_tlvs
*tlvs
= dest
;
605 sbuf_push(log
, indent
, "Unpack LAN neighbor...\n");
609 "Not enough data left.(Expected 6 bytes of mac, got %" PRIu8
615 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
616 stream_get(rv
->mac
, s
, 6);
618 format_item_lan_neighbor(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
619 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)rv
);
623 /* Functions related to TLV 9 LSP Entry */
624 static struct isis_item
*copy_item_lsp_entry(struct isis_item
*i
)
626 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
627 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
629 rv
->rem_lifetime
= e
->rem_lifetime
;
630 memcpy(rv
->id
, e
->id
, sizeof(rv
->id
));
631 rv
->seqno
= e
->seqno
;
632 rv
->checksum
= e
->checksum
;
634 return (struct isis_item
*)rv
;
637 static void format_item_lsp_entry(uint16_t mtid
, struct isis_item
*i
,
638 struct sbuf
*buf
, int indent
)
640 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
642 sbuf_push(buf
, indent
,
643 "LSP Entry: %s, seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
644 ", lifetime %" PRIu16
"s\n",
645 isis_format_id(e
->id
, 8), e
->seqno
, e
->checksum
,
649 static void free_item_lsp_entry(struct isis_item
*i
)
651 XFREE(MTYPE_ISIS_TLV
, i
);
654 static int pack_item_lsp_entry(struct isis_item
*i
, struct stream
*s
)
656 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
658 if (STREAM_WRITEABLE(s
) < 16)
661 stream_putw(s
, e
->rem_lifetime
);
662 stream_put(s
, e
->id
, 8);
663 stream_putl(s
, e
->seqno
);
664 stream_putw(s
, e
->checksum
);
669 static int unpack_item_lsp_entry(uint16_t mtid
, uint8_t len
, struct stream
*s
,
670 struct sbuf
*log
, void *dest
, int indent
)
672 struct isis_tlvs
*tlvs
= dest
;
674 sbuf_push(log
, indent
, "Unpack LSP entry...\n");
678 "Not enough data left. (Expected 16 bytes of LSP info, got %" PRIu8
,
683 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
684 rv
->rem_lifetime
= stream_getw(s
);
685 stream_get(rv
->id
, s
, 8);
686 rv
->seqno
= stream_getl(s
);
687 rv
->checksum
= stream_getw(s
);
689 format_item_lsp_entry(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
690 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)rv
);
694 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
696 static struct isis_item
*copy_item_extended_reach(struct isis_item
*i
)
698 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
699 struct isis_extended_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
701 memcpy(rv
->id
, r
->id
, 7);
702 rv
->metric
= r
->metric
;
704 if (r
->subtlvs
&& r
->subtlv_len
) {
705 rv
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, r
->subtlv_len
);
706 memcpy(rv
->subtlvs
, r
->subtlvs
, r
->subtlv_len
);
707 rv
->subtlv_len
= r
->subtlv_len
;
710 return (struct isis_item
*)rv
;
713 static void format_item_extended_reach(uint16_t mtid
, struct isis_item
*i
,
714 struct sbuf
*buf
, int indent
)
716 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
718 sbuf_push(buf
, indent
, "%s Reachability: %s (Metric: %u)",
719 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
720 isis_format_id(r
->id
, 7), r
->metric
);
721 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
722 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
723 sbuf_push(buf
, 0, "\n");
725 if (r
->subtlv_len
&& r
->subtlvs
)
726 mpls_te_print_detail(buf
, indent
+ 2, r
->subtlvs
,
730 static void free_item_extended_reach(struct isis_item
*i
)
732 struct isis_extended_reach
*item
= (struct isis_extended_reach
*)i
;
733 XFREE(MTYPE_ISIS_TLV
, item
->subtlvs
);
734 XFREE(MTYPE_ISIS_TLV
, item
);
737 static int pack_item_extended_reach(struct isis_item
*i
, struct stream
*s
)
739 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
741 if (STREAM_WRITEABLE(s
) < 11 + (unsigned)r
->subtlv_len
)
743 stream_put(s
, r
->id
, sizeof(r
->id
));
744 stream_put3(s
, r
->metric
);
745 stream_putc(s
, r
->subtlv_len
);
746 stream_put(s
, r
->subtlvs
, r
->subtlv_len
);
750 static int unpack_item_extended_reach(uint16_t mtid
, uint8_t len
,
751 struct stream
*s
, struct sbuf
*log
,
752 void *dest
, int indent
)
754 struct isis_tlvs
*tlvs
= dest
;
755 struct isis_extended_reach
*rv
= NULL
;
757 struct isis_item_list
*items
;
759 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
760 items
= &tlvs
->extended_reach
;
762 items
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
765 sbuf_push(log
, indent
, "Unpacking %s reachability...\n",
766 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
769 sbuf_push(log
, indent
,
770 "Not enough data left. (expected 11 or more bytes, got %"
776 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
777 stream_get(rv
->id
, s
, 7);
778 rv
->metric
= stream_get3(s
);
779 subtlv_len
= stream_getc(s
);
781 format_item_extended_reach(mtid
, (struct isis_item
*)rv
, log
,
784 if ((size_t)len
< ((size_t)11) + subtlv_len
) {
785 sbuf_push(log
, indent
,
786 "Not enough data left for subtlv size %" PRIu8
787 ", there are only %" PRIu8
" bytes left.\n",
788 subtlv_len
, len
- 11);
792 sbuf_push(log
, indent
, "Storing %" PRIu8
" bytes of subtlvs\n",
796 size_t subtlv_start
= stream_get_getp(s
);
798 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_NE_REACH
, subtlv_len
, s
,
799 log
, NULL
, indent
+ 4, NULL
)) {
803 stream_set_getp(s
, subtlv_start
);
805 rv
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, subtlv_len
);
806 stream_get(rv
->subtlvs
, s
, subtlv_len
);
807 rv
->subtlv_len
= subtlv_len
;
810 append_item(items
, (struct isis_item
*)rv
);
814 free_item_extended_reach((struct isis_item
*)rv
);
819 /* Functions related to TLV 128 (Old-Style) IP Reach */
820 static struct isis_item
*copy_item_oldstyle_ip_reach(struct isis_item
*i
)
822 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
823 struct isis_oldstyle_ip_reach
*rv
=
824 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
826 rv
->metric
= r
->metric
;
827 rv
->prefix
= r
->prefix
;
828 return (struct isis_item
*)rv
;
831 static void format_item_oldstyle_ip_reach(uint16_t mtid
, struct isis_item
*i
,
832 struct sbuf
*buf
, int indent
)
834 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
835 char prefixbuf
[PREFIX2STR_BUFFER
];
837 sbuf_push(buf
, indent
, "IP Reachability: %s (Metric: %" PRIu8
")\n",
838 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
842 static void free_item_oldstyle_ip_reach(struct isis_item
*i
)
844 XFREE(MTYPE_ISIS_TLV
, i
);
847 static int pack_item_oldstyle_ip_reach(struct isis_item
*i
, struct stream
*s
)
849 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
851 if (STREAM_WRITEABLE(s
) < 12)
854 stream_putc(s
, r
->metric
);
855 stream_putc(s
, 0x80); /* delay metric - unsupported */
856 stream_putc(s
, 0x80); /* expense metric - unsupported */
857 stream_putc(s
, 0x80); /* error metric - unsupported */
858 stream_put(s
, &r
->prefix
.prefix
, 4);
861 masklen2ip(r
->prefix
.prefixlen
, &mask
);
862 stream_put(s
, &mask
, sizeof(mask
));
867 static int unpack_item_oldstyle_ip_reach(uint16_t mtid
, uint8_t len
,
868 struct stream
*s
, struct sbuf
*log
,
869 void *dest
, int indent
)
871 sbuf_push(log
, indent
, "Unpack oldstyle ip reach...\n");
875 "Not enough data left.(Expected 12 bytes of reach information, got %" PRIu8
881 struct isis_oldstyle_ip_reach
*rv
=
882 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
883 rv
->metric
= stream_getc(s
);
884 if ((rv
->metric
& 0x7f) != rv
->metric
) {
885 sbuf_push(log
, indent
, "Metric has unplausible format\n");
888 stream_forward_getp(s
, 3); /* Skip other metrics */
889 rv
->prefix
.family
= AF_INET
;
890 stream_get(&rv
->prefix
.prefix
, s
, 4);
893 stream_get(&mask
, s
, 4);
894 rv
->prefix
.prefixlen
= ip_masklen(mask
);
896 format_item_oldstyle_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
898 append_item(dest
, (struct isis_item
*)rv
);
903 /* Functions related to TLV 129 protocols supported */
905 static void copy_tlv_protocols_supported(struct isis_protocols_supported
*src
,
906 struct isis_protocols_supported
*dest
)
908 if (!src
->protocols
|| !src
->count
)
910 dest
->count
= src
->count
;
911 dest
->protocols
= XCALLOC(MTYPE_ISIS_TLV
, src
->count
);
912 memcpy(dest
->protocols
, src
->protocols
, src
->count
);
915 static void format_tlv_protocols_supported(struct isis_protocols_supported
*p
,
916 struct sbuf
*buf
, int indent
)
918 if (!p
|| !p
->count
|| !p
->protocols
)
921 sbuf_push(buf
, indent
, "Protocols Supported: ");
922 for (uint8_t i
= 0; i
< p
->count
; i
++) {
923 sbuf_push(buf
, 0, "%s%s", nlpid2str(p
->protocols
[i
]),
924 (i
+ 1 < p
->count
) ? ", " : "");
926 sbuf_push(buf
, 0, "\n");
929 static void free_tlv_protocols_supported(struct isis_protocols_supported
*p
)
931 XFREE(MTYPE_ISIS_TLV
, p
->protocols
);
934 static int pack_tlv_protocols_supported(struct isis_protocols_supported
*p
,
937 if (!p
|| !p
->count
|| !p
->protocols
)
940 if (STREAM_WRITEABLE(s
) < (unsigned)(p
->count
+ 2))
943 stream_putc(s
, ISIS_TLV_PROTOCOLS_SUPPORTED
);
944 stream_putc(s
, p
->count
);
945 stream_put(s
, p
->protocols
, p
->count
);
949 static int unpack_tlv_protocols_supported(enum isis_tlv_context context
,
950 uint8_t tlv_type
, uint8_t tlv_len
,
951 struct stream
*s
, struct sbuf
*log
,
952 void *dest
, int indent
)
954 struct isis_tlvs
*tlvs
= dest
;
956 sbuf_push(log
, indent
, "Unpacking Protocols Supported TLV...\n");
958 sbuf_push(log
, indent
, "WARNING: No protocols included\n");
961 if (tlvs
->protocols_supported
.protocols
) {
964 "WARNING: protocols supported TLV present multiple times.\n");
965 stream_forward_getp(s
, tlv_len
);
969 tlvs
->protocols_supported
.count
= tlv_len
;
970 tlvs
->protocols_supported
.protocols
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
);
971 stream_get(tlvs
->protocols_supported
.protocols
, s
, tlv_len
);
973 format_tlv_protocols_supported(&tlvs
->protocols_supported
, log
,
978 /* Functions related to TLV 132 IPv4 Interface addresses */
979 static struct isis_item
*copy_item_ipv4_address(struct isis_item
*i
)
981 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
982 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
985 return (struct isis_item
*)rv
;
988 static void format_item_ipv4_address(uint16_t mtid
, struct isis_item
*i
,
989 struct sbuf
*buf
, int indent
)
991 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
992 char addrbuf
[INET_ADDRSTRLEN
];
994 inet_ntop(AF_INET
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
995 sbuf_push(buf
, indent
, "IPv4 Interface Address: %s\n", addrbuf
);
998 static void free_item_ipv4_address(struct isis_item
*i
)
1000 XFREE(MTYPE_ISIS_TLV
, i
);
1003 static int pack_item_ipv4_address(struct isis_item
*i
, struct stream
*s
)
1005 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
1007 if (STREAM_WRITEABLE(s
) < 4)
1010 stream_put(s
, &a
->addr
, 4);
1015 static int unpack_item_ipv4_address(uint16_t mtid
, uint8_t len
,
1016 struct stream
*s
, struct sbuf
*log
,
1017 void *dest
, int indent
)
1019 struct isis_tlvs
*tlvs
= dest
;
1021 sbuf_push(log
, indent
, "Unpack IPv4 Interface address...\n");
1025 "Not enough data left.(Expected 4 bytes of IPv4 address, got %" PRIu8
1031 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1032 stream_get(&rv
->addr
, s
, 4);
1034 format_item_ipv4_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1035 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)rv
);
1040 /* Functions related to TLV 232 IPv6 Interface addresses */
1041 static struct isis_item
*copy_item_ipv6_address(struct isis_item
*i
)
1043 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1044 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1047 return (struct isis_item
*)rv
;
1050 static void format_item_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
1051 struct sbuf
*buf
, int indent
)
1053 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1054 char addrbuf
[INET6_ADDRSTRLEN
];
1056 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
1057 sbuf_push(buf
, indent
, "IPv6 Interface Address: %s\n", addrbuf
);
1060 static void free_item_ipv6_address(struct isis_item
*i
)
1062 XFREE(MTYPE_ISIS_TLV
, i
);
1065 static int pack_item_ipv6_address(struct isis_item
*i
, struct stream
*s
)
1067 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1069 if (STREAM_WRITEABLE(s
) < 16)
1072 stream_put(s
, &a
->addr
, 16);
1077 static int unpack_item_ipv6_address(uint16_t mtid
, uint8_t len
,
1078 struct stream
*s
, struct sbuf
*log
,
1079 void *dest
, int indent
)
1081 struct isis_tlvs
*tlvs
= dest
;
1083 sbuf_push(log
, indent
, "Unpack IPv6 Interface address...\n");
1087 "Not enough data left.(Expected 16 bytes of IPv6 address, got %" PRIu8
1093 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1094 stream_get(&rv
->addr
, s
, 16);
1096 format_item_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1097 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)rv
);
1102 /* Functions related to TLV 229 MT Router information */
1103 static struct isis_item
*copy_item_mt_router_info(struct isis_item
*i
)
1105 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1106 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1108 rv
->overload
= info
->overload
;
1109 rv
->attached
= info
->attached
;
1110 rv
->mtid
= info
->mtid
;
1111 return (struct isis_item
*)rv
;
1114 static void format_item_mt_router_info(uint16_t mtid
, struct isis_item
*i
,
1115 struct sbuf
*buf
, int indent
)
1117 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1119 sbuf_push(buf
, indent
, "MT Router Info: %s%s%s\n",
1120 isis_mtid2str(info
->mtid
),
1121 info
->overload
? " Overload" : "",
1122 info
->attached
? " Attached" : "");
1125 static void free_item_mt_router_info(struct isis_item
*i
)
1127 XFREE(MTYPE_ISIS_TLV
, i
);
1130 static int pack_item_mt_router_info(struct isis_item
*i
, struct stream
*s
)
1132 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1134 if (STREAM_WRITEABLE(s
) < 2)
1137 uint16_t entry
= info
->mtid
;
1140 entry
|= ISIS_MT_OL_MASK
;
1142 entry
|= ISIS_MT_AT_MASK
;
1144 stream_putw(s
, entry
);
1149 static int unpack_item_mt_router_info(uint16_t mtid
, uint8_t len
,
1150 struct stream
*s
, struct sbuf
*log
,
1151 void *dest
, int indent
)
1153 struct isis_tlvs
*tlvs
= dest
;
1155 sbuf_push(log
, indent
, "Unpack MT Router info...\n");
1159 "Not enough data left.(Expected 2 bytes of MT info, got %" PRIu8
1165 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1167 uint16_t entry
= stream_getw(s
);
1168 rv
->overload
= entry
& ISIS_MT_OL_MASK
;
1169 rv
->attached
= entry
& ISIS_MT_AT_MASK
;
1170 rv
->mtid
= entry
& ISIS_MT_MASK
;
1172 format_item_mt_router_info(mtid
, (struct isis_item
*)rv
, log
,
1174 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)rv
);
1178 /* Functions related to TLV 134 TE Router ID */
1180 static struct in_addr
*copy_tlv_te_router_id(const struct in_addr
*id
)
1185 struct in_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1186 memcpy(rv
, id
, sizeof(*rv
));
1190 static void format_tlv_te_router_id(const struct in_addr
*id
, struct sbuf
*buf
,
1196 char addrbuf
[INET_ADDRSTRLEN
];
1197 inet_ntop(AF_INET
, id
, addrbuf
, sizeof(addrbuf
));
1198 sbuf_push(buf
, indent
, "TE Router ID: %s\n", addrbuf
);
1201 static void free_tlv_te_router_id(struct in_addr
*id
)
1203 XFREE(MTYPE_ISIS_TLV
, id
);
1206 static int pack_tlv_te_router_id(const struct in_addr
*id
, struct stream
*s
)
1211 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
1214 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID
);
1216 stream_put(s
, id
, 4);
1220 static int unpack_tlv_te_router_id(enum isis_tlv_context context
,
1221 uint8_t tlv_type
, uint8_t tlv_len
,
1222 struct stream
*s
, struct sbuf
*log
,
1223 void *dest
, int indent
)
1225 struct isis_tlvs
*tlvs
= dest
;
1227 sbuf_push(log
, indent
, "Unpacking TE Router ID TLV...\n");
1229 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
1233 if (tlvs
->te_router_id
) {
1234 sbuf_push(log
, indent
,
1235 "WARNING: TE Router ID present multiple times.\n");
1236 stream_forward_getp(s
, tlv_len
);
1240 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, 4);
1241 stream_get(tlvs
->te_router_id
, s
, 4);
1242 format_tlv_te_router_id(tlvs
->te_router_id
, log
, indent
+ 2);
1247 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
1249 static struct isis_item
*copy_item_extended_ip_reach(struct isis_item
*i
)
1251 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1252 struct isis_extended_ip_reach
*rv
=
1253 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1255 rv
->metric
= r
->metric
;
1257 rv
->prefix
= r
->prefix
;
1259 return (struct isis_item
*)rv
;
1262 static void format_item_extended_ip_reach(uint16_t mtid
, struct isis_item
*i
,
1263 struct sbuf
*buf
, int indent
)
1265 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1266 char prefixbuf
[PREFIX2STR_BUFFER
];
1268 sbuf_push(buf
, indent
, "%s IP Reachability: %s (Metric: %u)%s",
1269 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
1270 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)), r
->metric
,
1271 r
->down
? " Down" : "");
1272 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1273 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1274 sbuf_push(buf
, 0, "\n");
1277 sbuf_push(buf
, indent
, " Subtlvs:\n");
1278 format_subtlvs(r
->subtlvs
, buf
, indent
+ 4);
1282 static void free_item_extended_ip_reach(struct isis_item
*i
)
1284 struct isis_extended_ip_reach
*item
=
1285 (struct isis_extended_ip_reach
*)i
;
1286 isis_free_subtlvs(item
->subtlvs
);
1287 XFREE(MTYPE_ISIS_TLV
, item
);
1290 static int pack_item_extended_ip_reach(struct isis_item
*i
, struct stream
*s
)
1292 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1295 if (STREAM_WRITEABLE(s
) < 5)
1297 stream_putl(s
, r
->metric
);
1299 control
= r
->down
? ISIS_EXTENDED_IP_REACH_DOWN
: 0;
1300 control
|= r
->prefix
.prefixlen
;
1301 control
|= r
->subtlvs
? ISIS_EXTENDED_IP_REACH_SUBTLV
: 0;
1303 stream_putc(s
, control
);
1305 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
))
1307 stream_put(s
, &r
->prefix
.prefix
.s_addr
, PSIZE(r
->prefix
.prefixlen
));
1310 return pack_subtlvs(r
->subtlvs
, s
);
1314 static int unpack_item_extended_ip_reach(uint16_t mtid
, uint8_t len
,
1315 struct stream
*s
, struct sbuf
*log
,
1316 void *dest
, int indent
)
1318 struct isis_tlvs
*tlvs
= dest
;
1319 struct isis_extended_ip_reach
*rv
= NULL
;
1321 uint8_t control
, subtlv_len
;
1322 struct isis_item_list
*items
;
1324 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1325 items
= &tlvs
->extended_ip_reach
;
1327 items
= isis_get_mt_items(&tlvs
->mt_ip_reach
, mtid
);
1330 sbuf_push(log
, indent
, "Unpacking %s IPv4 reachability...\n",
1331 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
1334 if (len
< consume
) {
1335 sbuf_push(log
, indent
,
1336 "Not enough data left. (expected 5 or more bytes, got %" PRIu8
")\n",
1341 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1343 rv
->metric
= stream_getl(s
);
1344 control
= stream_getc(s
);
1345 rv
->down
= (control
& ISIS_EXTENDED_IP_REACH_DOWN
);
1346 rv
->prefix
.family
= AF_INET
;
1347 rv
->prefix
.prefixlen
= control
& 0x3f;
1348 if (rv
->prefix
.prefixlen
> 32) {
1349 sbuf_push(log
, indent
, "Prefixlen %u is inplausible for IPv4\n",
1350 rv
->prefix
.prefixlen
);
1354 consume
+= PSIZE(rv
->prefix
.prefixlen
);
1355 if (len
< consume
) {
1356 sbuf_push(log
, indent
,
1357 "Expected %u bytes of prefix, but only %u bytes available.\n",
1358 PSIZE(rv
->prefix
.prefixlen
), len
- 5);
1361 stream_get(&rv
->prefix
.prefix
.s_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
1362 in_addr_t orig_prefix
= rv
->prefix
.prefix
.s_addr
;
1363 apply_mask_ipv4(&rv
->prefix
);
1364 if (orig_prefix
!= rv
->prefix
.prefix
.s_addr
)
1365 sbuf_push(log
, indent
+ 2,
1366 "WARNING: Prefix had hostbits set.\n");
1367 format_item_extended_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
1370 if (control
& ISIS_EXTENDED_IP_REACH_SUBTLV
) {
1372 if (len
< consume
) {
1373 sbuf_push(log
, indent
,
1374 "Expected 1 byte of subtlv len, but no more data present.\n");
1377 subtlv_len
= stream_getc(s
);
1380 sbuf_push(log
, indent
+ 2,
1381 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
1383 consume
+= subtlv_len
;
1384 if (len
< consume
) {
1385 sbuf_push(log
, indent
,
1387 " bytes of subtlvs, but only %u bytes available.\n",
1389 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
1393 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
1394 bool unpacked_known_tlvs
= false;
1396 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
, subtlv_len
, s
,
1397 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
1400 if (!unpacked_known_tlvs
) {
1401 isis_free_subtlvs(rv
->subtlvs
);
1406 append_item(items
, (struct isis_item
*)rv
);
1410 free_item_extended_ip_reach((struct isis_item
*)rv
);
1414 /* Functions related to TLV 137 Dynamic Hostname */
1416 static char *copy_tlv_dynamic_hostname(const char *hostname
)
1421 return XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
1424 static void format_tlv_dynamic_hostname(const char *hostname
, struct sbuf
*buf
,
1430 sbuf_push(buf
, indent
, "Hostname: %s\n", hostname
);
1433 static void free_tlv_dynamic_hostname(char *hostname
)
1435 XFREE(MTYPE_ISIS_TLV
, hostname
);
1438 static int pack_tlv_dynamic_hostname(const char *hostname
, struct stream
*s
)
1443 uint8_t name_len
= strlen(hostname
);
1445 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + name_len
))
1448 stream_putc(s
, ISIS_TLV_DYNAMIC_HOSTNAME
);
1449 stream_putc(s
, name_len
);
1450 stream_put(s
, hostname
, name_len
);
1454 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context
,
1455 uint8_t tlv_type
, uint8_t tlv_len
,
1456 struct stream
*s
, struct sbuf
*log
,
1457 void *dest
, int indent
)
1459 struct isis_tlvs
*tlvs
= dest
;
1461 sbuf_push(log
, indent
, "Unpacking Dynamic Hostname TLV...\n");
1463 sbuf_push(log
, indent
, "WARNING: No hostname included\n");
1467 if (tlvs
->hostname
) {
1468 sbuf_push(log
, indent
,
1469 "WARNING: Hostname present multiple times.\n");
1470 stream_forward_getp(s
, tlv_len
);
1474 tlvs
->hostname
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
+ 1);
1475 stream_get(tlvs
->hostname
, s
, tlv_len
);
1476 tlvs
->hostname
[tlv_len
] = '\0';
1479 for (uint8_t i
= 0; i
< tlv_len
; i
++) {
1480 if ((unsigned char)tlvs
->hostname
[i
] > 127
1481 || !isprint((int)tlvs
->hostname
[i
])) {
1483 tlvs
->hostname
[i
] = '?';
1489 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
1495 /* Functions related to TLV 150 Spine-Leaf-Extension */
1497 static struct isis_spine_leaf
*copy_tlv_spine_leaf(
1498 const struct isis_spine_leaf
*spine_leaf
)
1503 struct isis_spine_leaf
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1504 memcpy(rv
, spine_leaf
, sizeof(*rv
));
1509 static void format_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
1510 struct sbuf
*buf
, int indent
)
1515 sbuf_push(buf
, indent
, "Spine-Leaf-Extension:\n");
1516 if (spine_leaf
->has_tier
) {
1517 if (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
) {
1518 sbuf_push(buf
, indent
, " Tier: undefined\n");
1520 sbuf_push(buf
, indent
, " Tier: %" PRIu8
"\n",
1525 sbuf_push(buf
, indent
, " Flags:%s%s%s\n",
1526 spine_leaf
->is_leaf
? " LEAF" : "",
1527 spine_leaf
->is_spine
? " SPINE" : "",
1528 spine_leaf
->is_backup
? " BACKUP" : "");
1532 static void free_tlv_spine_leaf(struct isis_spine_leaf
*spine_leaf
)
1534 XFREE(MTYPE_ISIS_TLV
, spine_leaf
);
1537 #define ISIS_SPINE_LEAF_FLAG_TIER 0x08
1538 #define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
1539 #define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
1540 #define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
1542 static int pack_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
1548 uint8_t tlv_len
= 2;
1550 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
1553 stream_putc(s
, ISIS_TLV_SPINE_LEAF_EXT
);
1554 stream_putc(s
, tlv_len
);
1556 uint16_t spine_leaf_flags
= 0;
1558 if (spine_leaf
->has_tier
) {
1559 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_TIER
;
1560 spine_leaf_flags
|= spine_leaf
->tier
<< 12;
1563 if (spine_leaf
->is_leaf
)
1564 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_LEAF
;
1566 if (spine_leaf
->is_spine
)
1567 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_SPINE
;
1569 if (spine_leaf
->is_backup
)
1570 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_BACKUP
;
1572 stream_putw(s
, spine_leaf_flags
);
1577 static int unpack_tlv_spine_leaf(enum isis_tlv_context context
,
1578 uint8_t tlv_type
, uint8_t tlv_len
,
1579 struct stream
*s
, struct sbuf
*log
,
1580 void *dest
, int indent
)
1582 struct isis_tlvs
*tlvs
= dest
;
1584 sbuf_push(log
, indent
, "Unpacking Spine Leaf Extension TLV...\n");
1586 sbuf_push(log
, indent
, "WARNING: Unexepected TLV size\n");
1587 stream_forward_getp(s
, tlv_len
);
1591 if (tlvs
->spine_leaf
) {
1592 sbuf_push(log
, indent
,
1593 "WARNING: Spine Leaf Extension TLV present multiple times.\n");
1594 stream_forward_getp(s
, tlv_len
);
1598 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
1600 uint16_t spine_leaf_flags
= stream_getw(s
);
1602 if (spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_TIER
) {
1603 tlvs
->spine_leaf
->has_tier
= true;
1604 tlvs
->spine_leaf
->tier
= spine_leaf_flags
>> 12;
1607 tlvs
->spine_leaf
->is_leaf
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_LEAF
;
1608 tlvs
->spine_leaf
->is_spine
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_SPINE
;
1609 tlvs
->spine_leaf
->is_backup
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_BACKUP
;
1611 stream_forward_getp(s
, tlv_len
- 2);
1615 /* Functions related to TLV 240 P2P Three-Way Adjacency */
1617 const char *isis_threeway_state_name(enum isis_threeway_state state
)
1620 case ISIS_THREEWAY_DOWN
:
1622 case ISIS_THREEWAY_INITIALIZING
:
1623 return "Initializing";
1624 case ISIS_THREEWAY_UP
:
1631 static struct isis_threeway_adj
*copy_tlv_threeway_adj(
1632 const struct isis_threeway_adj
*threeway_adj
)
1637 struct isis_threeway_adj
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1638 memcpy(rv
, threeway_adj
, sizeof(*rv
));
1643 static void format_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
1644 struct sbuf
*buf
, int indent
)
1649 sbuf_push(buf
, indent
, "P2P Three-Way Adjacency:\n");
1650 sbuf_push(buf
, indent
, " State: %s (%d)\n",
1651 isis_threeway_state_name(threeway_adj
->state
),
1652 threeway_adj
->state
);
1653 sbuf_push(buf
, indent
, " Extended Local Circuit ID: %" PRIu32
"\n",
1654 threeway_adj
->local_circuit_id
);
1655 if (!threeway_adj
->neighbor_set
)
1658 sbuf_push(buf
, indent
, " Neighbor System ID: %s\n",
1659 isis_format_id(threeway_adj
->neighbor_id
, 6));
1660 sbuf_push(buf
, indent
, " Neighbor Extended Circuit ID: %" PRIu32
"\n",
1661 threeway_adj
->neighbor_circuit_id
);
1664 static void free_tlv_threeway_adj(struct isis_threeway_adj
*threeway_adj
)
1666 XFREE(MTYPE_ISIS_TLV
, threeway_adj
);
1669 static int pack_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
1675 uint8_t tlv_len
= (threeway_adj
->neighbor_set
) ? 15 : 5;
1677 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
1680 stream_putc(s
, ISIS_TLV_THREE_WAY_ADJ
);
1681 stream_putc(s
, tlv_len
);
1682 stream_putc(s
, threeway_adj
->state
);
1683 stream_putl(s
, threeway_adj
->local_circuit_id
);
1685 if (threeway_adj
->neighbor_set
) {
1686 stream_put(s
, threeway_adj
->neighbor_id
, 6);
1687 stream_putl(s
, threeway_adj
->neighbor_circuit_id
);
1693 static int unpack_tlv_threeway_adj(enum isis_tlv_context context
,
1694 uint8_t tlv_type
, uint8_t tlv_len
,
1695 struct stream
*s
, struct sbuf
*log
,
1696 void *dest
, int indent
)
1698 struct isis_tlvs
*tlvs
= dest
;
1700 sbuf_push(log
, indent
, "Unpacking P2P Three-Way Adjacency TLV...\n");
1701 if (tlv_len
!= 5 && tlv_len
!= 15) {
1702 sbuf_push(log
, indent
, "WARNING: Unexepected TLV size\n");
1703 stream_forward_getp(s
, tlv_len
);
1707 if (tlvs
->threeway_adj
) {
1708 sbuf_push(log
, indent
,
1709 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
1710 stream_forward_getp(s
, tlv_len
);
1714 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
1716 tlvs
->threeway_adj
->state
= stream_getc(s
);
1717 tlvs
->threeway_adj
->local_circuit_id
= stream_getl(s
);
1719 if (tlv_len
== 15) {
1720 tlvs
->threeway_adj
->neighbor_set
= true;
1721 stream_get(tlvs
->threeway_adj
->neighbor_id
, s
, 6);
1722 tlvs
->threeway_adj
->neighbor_circuit_id
= stream_getl(s
);
1728 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
1730 static struct isis_item
*copy_item_ipv6_reach(struct isis_item
*i
)
1732 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1733 struct isis_ipv6_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1734 rv
->metric
= r
->metric
;
1736 rv
->external
= r
->external
;
1737 rv
->prefix
= r
->prefix
;
1738 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
1740 return (struct isis_item
*)rv
;
1743 static void format_item_ipv6_reach(uint16_t mtid
, struct isis_item
*i
,
1744 struct sbuf
*buf
, int indent
)
1746 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1747 char prefixbuf
[PREFIX2STR_BUFFER
];
1749 sbuf_push(buf
, indent
, "%sIPv6 Reachability: %s (Metric: %u)%s%s",
1750 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "MT ",
1751 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
1753 r
->down
? " Down" : "",
1754 r
->external
? " External" : "");
1755 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1756 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1757 sbuf_push(buf
, 0, "\n");
1760 sbuf_push(buf
, indent
, " Subtlvs:\n");
1761 format_subtlvs(r
->subtlvs
, buf
, indent
+ 4);
1765 static void free_item_ipv6_reach(struct isis_item
*i
)
1767 struct isis_ipv6_reach
*item
= (struct isis_ipv6_reach
*)i
;
1769 isis_free_subtlvs(item
->subtlvs
);
1770 XFREE(MTYPE_ISIS_TLV
, item
);
1773 static int pack_item_ipv6_reach(struct isis_item
*i
, struct stream
*s
)
1775 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1778 if (STREAM_WRITEABLE(s
) < 6)
1780 stream_putl(s
, r
->metric
);
1782 control
= r
->down
? ISIS_IPV6_REACH_DOWN
: 0;
1783 control
|= r
->external
? ISIS_IPV6_REACH_EXTERNAL
: 0;
1784 control
|= r
->subtlvs
? ISIS_IPV6_REACH_SUBTLV
: 0;
1786 stream_putc(s
, control
);
1787 stream_putc(s
, r
->prefix
.prefixlen
);
1789 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
))
1791 stream_put(s
, &r
->prefix
.prefix
.s6_addr
, PSIZE(r
->prefix
.prefixlen
));
1794 return pack_subtlvs(r
->subtlvs
, s
);
1799 static int unpack_item_ipv6_reach(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1800 struct sbuf
*log
, void *dest
, int indent
)
1802 struct isis_tlvs
*tlvs
= dest
;
1803 struct isis_ipv6_reach
*rv
= NULL
;
1805 uint8_t control
, subtlv_len
;
1806 struct isis_item_list
*items
;
1808 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1809 items
= &tlvs
->ipv6_reach
;
1811 items
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
1814 sbuf_push(log
, indent
, "Unpacking %sIPv6 reachability...\n",
1815 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "mt ");
1817 if (len
< consume
) {
1818 sbuf_push(log
, indent
,
1819 "Not enough data left. (expected 6 or more bytes, got %"
1825 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1827 rv
->metric
= stream_getl(s
);
1828 control
= stream_getc(s
);
1829 rv
->down
= (control
& ISIS_IPV6_REACH_DOWN
);
1830 rv
->external
= (control
& ISIS_IPV6_REACH_EXTERNAL
);
1832 rv
->prefix
.family
= AF_INET6
;
1833 rv
->prefix
.prefixlen
= stream_getc(s
);
1834 if (rv
->prefix
.prefixlen
> 128) {
1835 sbuf_push(log
, indent
, "Prefixlen %u is inplausible for IPv6\n",
1836 rv
->prefix
.prefixlen
);
1840 consume
+= PSIZE(rv
->prefix
.prefixlen
);
1841 if (len
< consume
) {
1842 sbuf_push(log
, indent
,
1843 "Expected %u bytes of prefix, but only %u bytes available.\n",
1844 PSIZE(rv
->prefix
.prefixlen
), len
- 6);
1847 stream_get(&rv
->prefix
.prefix
.s6_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
1848 struct in6_addr orig_prefix
= rv
->prefix
.prefix
;
1849 apply_mask_ipv6(&rv
->prefix
);
1850 if (memcmp(&orig_prefix
, &rv
->prefix
.prefix
, sizeof(orig_prefix
)))
1851 sbuf_push(log
, indent
+ 2,
1852 "WARNING: Prefix had hostbits set.\n");
1853 format_item_ipv6_reach(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1855 if (control
& ISIS_IPV6_REACH_SUBTLV
) {
1857 if (len
< consume
) {
1858 sbuf_push(log
, indent
,
1859 "Expected 1 byte of subtlv len, but no more data persent.\n");
1862 subtlv_len
= stream_getc(s
);
1865 sbuf_push(log
, indent
+ 2,
1866 " WARNING: subtlv bit set, but there are no subtlvs.\n");
1868 consume
+= subtlv_len
;
1869 if (len
< consume
) {
1870 sbuf_push(log
, indent
,
1872 " bytes of subtlvs, but only %u bytes available.\n",
1874 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
1878 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
1879 bool unpacked_known_tlvs
= false;
1881 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
, subtlv_len
, s
,
1882 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
1885 if (!unpacked_known_tlvs
) {
1886 isis_free_subtlvs(rv
->subtlvs
);
1891 append_item(items
, (struct isis_item
*)rv
);
1895 free_item_ipv6_reach((struct isis_item
*)rv
);
1899 /* Functions related to TLV 10 Authentication */
1900 static struct isis_item
*copy_item_auth(struct isis_item
*i
)
1902 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1903 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1905 rv
->type
= auth
->type
;
1906 rv
->length
= auth
->length
;
1907 memcpy(rv
->value
, auth
->value
, sizeof(rv
->value
));
1908 return (struct isis_item
*)rv
;
1911 static void format_item_auth(uint16_t mtid
, struct isis_item
*i
,
1912 struct sbuf
*buf
, int indent
)
1914 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1917 sbuf_push(buf
, indent
, "Authentication:\n");
1918 switch (auth
->type
) {
1919 case ISIS_PASSWD_TYPE_CLEARTXT
:
1920 zlog_sanitize(obuf
, sizeof(obuf
), auth
->value
, auth
->length
);
1921 sbuf_push(buf
, indent
, " Password: %s\n", obuf
);
1923 case ISIS_PASSWD_TYPE_HMAC_MD5
:
1924 for (unsigned int j
= 0; j
< 16; j
++) {
1925 snprintf(obuf
+ 2 * j
, sizeof(obuf
) - 2 * j
,
1926 "%02" PRIx8
, auth
->value
[j
]);
1928 sbuf_push(buf
, indent
, " HMAC-MD5: %s\n", obuf
);
1931 sbuf_push(buf
, indent
, " Unknown (%" PRIu8
")\n", auth
->type
);
1936 static void free_item_auth(struct isis_item
*i
)
1938 XFREE(MTYPE_ISIS_TLV
, i
);
1941 static int pack_item_auth(struct isis_item
*i
, struct stream
*s
)
1943 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1945 if (STREAM_WRITEABLE(s
) < 1)
1947 stream_putc(s
, auth
->type
);
1949 switch (auth
->type
) {
1950 case ISIS_PASSWD_TYPE_CLEARTXT
:
1951 if (STREAM_WRITEABLE(s
) < auth
->length
)
1953 stream_put(s
, auth
->passwd
, auth
->length
);
1955 case ISIS_PASSWD_TYPE_HMAC_MD5
:
1956 if (STREAM_WRITEABLE(s
) < 16)
1958 auth
->offset
= stream_get_endp(s
);
1959 stream_put(s
, NULL
, 16);
1968 static int unpack_item_auth(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1969 struct sbuf
*log
, void *dest
, int indent
)
1971 struct isis_tlvs
*tlvs
= dest
;
1973 sbuf_push(log
, indent
, "Unpack Auth TLV...\n");
1977 "Not enough data left.(Expected 1 bytes of auth type, got %" PRIu8
1983 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1985 rv
->type
= stream_getc(s
);
1986 rv
->length
= len
- 1;
1988 if (rv
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
&& rv
->length
!= 16) {
1991 "Unexpected auth length for HMAC-MD5 (expected 16, got %" PRIu8
1994 XFREE(MTYPE_ISIS_TLV
, rv
);
1998 rv
->offset
= stream_get_getp(s
);
1999 stream_get(rv
->value
, s
, rv
->length
);
2000 format_item_auth(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
2001 append_item(&tlvs
->isis_auth
, (struct isis_item
*)rv
);
2005 /* Functions related to TLV 13 Purge Originator */
2007 static struct isis_purge_originator
*copy_tlv_purge_originator(
2008 struct isis_purge_originator
*poi
)
2013 struct isis_purge_originator
*rv
;
2015 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2016 rv
->sender_set
= poi
->sender_set
;
2017 memcpy(rv
->generator
, poi
->generator
, sizeof(rv
->generator
));
2018 if (poi
->sender_set
)
2019 memcpy(rv
->sender
, poi
->sender
, sizeof(rv
->sender
));
2023 static void format_tlv_purge_originator(struct isis_purge_originator
*poi
,
2024 struct sbuf
*buf
, int indent
)
2029 sbuf_push(buf
, indent
, "Purge Originator Identification:\n");
2030 sbuf_push(buf
, indent
, " Generator: %s\n",
2031 isis_format_id(poi
->generator
, sizeof(poi
->generator
)));
2032 if (poi
->sender_set
) {
2033 sbuf_push(buf
, indent
, " Received-From: %s\n",
2034 isis_format_id(poi
->sender
, sizeof(poi
->sender
)));
2038 static void free_tlv_purge_originator(struct isis_purge_originator
*poi
)
2040 XFREE(MTYPE_ISIS_TLV
, poi
);
2043 static int pack_tlv_purge_originator(struct isis_purge_originator
*poi
,
2049 uint8_t data_len
= 1 + sizeof(poi
->generator
);
2051 if (poi
->sender_set
)
2052 data_len
+= sizeof(poi
->sender
);
2054 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + data_len
))
2057 stream_putc(s
, ISIS_TLV_PURGE_ORIGINATOR
);
2058 stream_putc(s
, data_len
);
2059 stream_putc(s
, poi
->sender_set
? 2 : 1);
2060 stream_put(s
, poi
->generator
, sizeof(poi
->generator
));
2061 if (poi
->sender_set
)
2062 stream_put(s
, poi
->sender
, sizeof(poi
->sender
));
2066 static int unpack_tlv_purge_originator(enum isis_tlv_context context
,
2067 uint8_t tlv_type
, uint8_t tlv_len
,
2068 struct stream
*s
, struct sbuf
*log
,
2069 void *dest
, int indent
)
2071 struct isis_tlvs
*tlvs
= dest
;
2072 struct isis_purge_originator poi
= {};
2074 sbuf_push(log
, indent
, "Unpacking Purge Originator Identification TLV...\n");
2076 sbuf_push(log
, indent
, "Not enough data left. (Expected at least 7 bytes, got %"
2077 PRIu8
")\n", tlv_len
);
2081 uint8_t number_of_ids
= stream_getc(s
);
2083 if (number_of_ids
== 1) {
2084 poi
.sender_set
= false;
2085 } else if (number_of_ids
== 2) {
2086 poi
.sender_set
= true;
2088 sbuf_push(log
, indent
, "Got invalid value for number of system IDs: %"
2089 PRIu8
")\n", number_of_ids
);
2093 if (tlv_len
!= 1 + 6 * number_of_ids
) {
2094 sbuf_push(log
, indent
, "Incorrect tlv len for number of IDs.\n");
2098 stream_get(poi
.generator
, s
, sizeof(poi
.generator
));
2100 stream_get(poi
.sender
, s
, sizeof(poi
.sender
));
2102 if (tlvs
->purge_originator
) {
2103 sbuf_push(log
, indent
,
2104 "WARNING: Purge originator present multiple times, ignoring.\n");
2108 tlvs
->purge_originator
= copy_tlv_purge_originator(&poi
);
2113 /* Functions relating to item TLVs */
2115 static void init_item_list(struct isis_item_list
*items
)
2118 items
->tail
= &items
->head
;
2122 static struct isis_item
*copy_item(enum isis_tlv_context context
,
2123 enum isis_tlv_type type
,
2124 struct isis_item
*item
)
2126 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
2128 if (ops
&& ops
->copy_item
)
2129 return ops
->copy_item(item
);
2131 assert(!"Unknown item tlv type!");
2135 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
2136 struct isis_item_list
*src
, struct isis_item_list
*dest
)
2138 struct isis_item
*item
;
2140 init_item_list(dest
);
2142 for (item
= src
->head
; item
; item
= item
->next
) {
2143 append_item(dest
, copy_item(context
, type
, item
));
2147 static void format_item(uint16_t mtid
, enum isis_tlv_context context
,
2148 enum isis_tlv_type type
, struct isis_item
*i
,
2149 struct sbuf
*buf
, int indent
)
2151 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
2153 if (ops
&& ops
->format_item
) {
2154 ops
->format_item(mtid
, i
, buf
, indent
);
2158 assert(!"Unknown item tlv type!");
2161 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
2162 enum isis_tlv_type type
, struct isis_item_list
*items
,
2163 struct sbuf
*buf
, int indent
)
2165 struct isis_item
*i
;
2167 for (i
= items
->head
; i
; i
= i
->next
)
2168 format_item(mtid
, context
, type
, i
, buf
, indent
);
2171 static void free_item(enum isis_tlv_context tlv_context
,
2172 enum isis_tlv_type tlv_type
, struct isis_item
*item
)
2174 const struct tlv_ops
*ops
= tlv_table
[tlv_context
][tlv_type
];
2176 if (ops
&& ops
->free_item
) {
2177 ops
->free_item(item
);
2181 assert(!"Unknown item tlv type!");
2184 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
2185 struct isis_item_list
*items
)
2187 struct isis_item
*item
, *next_item
;
2189 for (item
= items
->head
; item
; item
= next_item
) {
2190 next_item
= item
->next
;
2191 free_item(context
, type
, item
);
2195 static int pack_item(enum isis_tlv_context context
, enum isis_tlv_type type
,
2196 struct isis_item
*i
, struct stream
*s
,
2197 struct isis_tlvs
**fragment_tlvs
,
2198 struct pack_order_entry
*pe
, uint16_t mtid
)
2200 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
2202 if (ops
&& ops
->pack_item
) {
2203 return ops
->pack_item(i
, s
);
2206 assert(!"Unknown item tlv type!");
2210 static void add_item_to_fragment(struct isis_item
*i
, struct pack_order_entry
*pe
,
2211 struct isis_tlvs
*fragment_tlvs
, uint16_t mtid
)
2213 struct isis_item_list
*l
;
2215 if (pe
->how_to_pack
== ISIS_ITEMS
) {
2216 l
= (struct isis_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
2218 struct isis_mt_item_list
*m
;
2219 m
= (struct isis_mt_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
2220 l
= isis_get_mt_items(m
, mtid
);
2223 append_item(l
, copy_item(pe
->context
, pe
->type
, i
));
2226 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
2227 enum isis_tlv_type type
, struct isis_item_list
*items
,
2228 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
2229 struct pack_order_entry
*pe
,
2230 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2231 struct list
*new_fragment_arg
)
2233 size_t len_pos
, last_len
, len
;
2234 struct isis_item
*item
= NULL
;
2241 if (STREAM_WRITEABLE(s
) < 2)
2244 stream_putc(s
, type
);
2245 len_pos
= stream_get_endp(s
);
2246 stream_putc(s
, 0); /* Put 0 as length for now */
2248 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(type
)
2249 && mtid
!= ISIS_MT_IPV4_UNICAST
) {
2250 if (STREAM_WRITEABLE(s
) < 2)
2252 stream_putw(s
, mtid
);
2255 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_OLDSTYLE_REACH
) {
2256 if (STREAM_WRITEABLE(s
) < 1)
2258 stream_putc(s
, 0); /* Virtual flag is set to 0 */
2262 for (item
= item
? item
: items
->head
; item
; item
= item
->next
) {
2263 rv
= pack_item(context
, type
, item
, s
, fragment_tlvs
, pe
, mtid
);
2267 len
= stream_get_endp(s
) - len_pos
- 1;
2269 /* Multiple auths don't go into one TLV, so always break */
2270 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_AUTH
) {
2275 /* Multiple prefix-sids don't go into one TLV, so always break */
2276 if (type
== ISIS_SUBTLV_PREFIX_SID
2277 && (context
== ISIS_CONTEXT_SUBTLV_IP_REACH
2278 || context
== ISIS_CONTEXT_SUBTLV_IPV6_REACH
)) {
2284 if (!last_len
) /* strange, not a single item fit */
2286 /* drop last tlv, otherwise, its too long */
2287 stream_set_endp(s
, len_pos
+ 1 + last_len
);
2293 add_item_to_fragment(item
, pe
, *fragment_tlvs
, mtid
);
2298 stream_putc_at(s
, len_pos
, len
);
2307 *fragment_tlvs
= new_fragment(new_fragment_arg
);
2310 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
2312 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
)
2315 dest
->tail
= &(*dest
->tail
)->next
;
2319 static struct isis_item
*last_item(struct isis_item_list
*list
)
2321 return container_of(list
->tail
, struct isis_item
, next
);
2324 static int unpack_item(uint16_t mtid
, enum isis_tlv_context context
,
2325 uint8_t tlv_type
, uint8_t len
, struct stream
*s
,
2326 struct sbuf
*log
, void *dest
, int indent
)
2328 const struct tlv_ops
*ops
= tlv_table
[context
][tlv_type
];
2330 if (ops
&& ops
->unpack_item
)
2331 return ops
->unpack_item(mtid
, len
, s
, log
, dest
, indent
);
2333 assert(!"Unknown item tlv type!");
2334 sbuf_push(log
, indent
, "Unknown item tlv type!\n");
2338 static int unpack_tlv_with_items(enum isis_tlv_context context
,
2339 uint8_t tlv_type
, uint8_t tlv_len
,
2340 struct stream
*s
, struct sbuf
*log
, void *dest
,
2348 tlv_start
= stream_get_getp(s
);
2351 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(tlv_type
)) {
2353 sbuf_push(log
, indent
,
2354 "TLV is too short to contain MTID\n");
2357 mtid
= stream_getw(s
) & ISIS_MT_MASK
;
2359 sbuf_push(log
, indent
, "Unpacking as MT %s item TLV...\n",
2360 isis_mtid2str(mtid
));
2362 sbuf_push(log
, indent
, "Unpacking as item TLV...\n");
2363 mtid
= ISIS_MT_IPV4_UNICAST
;
2366 if (context
== ISIS_CONTEXT_LSP
2367 && tlv_type
== ISIS_TLV_OLDSTYLE_REACH
) {
2368 if (tlv_len
- tlv_pos
< 1) {
2369 sbuf_push(log
, indent
,
2370 "TLV is too short for old style reach\n");
2373 stream_forward_getp(s
, 1);
2377 if (context
== ISIS_CONTEXT_LSP
2378 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH
) {
2379 struct isis_tlvs
*tlvs
= dest
;
2380 dest
= &tlvs
->oldstyle_ip_reach
;
2381 } else if (context
== ISIS_CONTEXT_LSP
2382 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH_EXT
) {
2383 struct isis_tlvs
*tlvs
= dest
;
2384 dest
= &tlvs
->oldstyle_ip_reach_ext
;
2387 if (context
== ISIS_CONTEXT_LSP
2388 && tlv_type
== ISIS_TLV_MT_ROUTER_INFO
) {
2389 struct isis_tlvs
*tlvs
= dest
;
2390 tlvs
->mt_router_info_empty
= (tlv_pos
>= (size_t)tlv_len
);
2393 while (tlv_pos
< (size_t)tlv_len
) {
2394 rv
= unpack_item(mtid
, context
, tlv_type
, tlv_len
- tlv_pos
, s
,
2395 log
, dest
, indent
+ 2);
2399 tlv_pos
= stream_get_getp(s
) - tlv_start
;
2405 /* Functions to manipulate mt_item_lists */
2407 static int isis_mt_item_list_cmp(const struct isis_item_list
*a
,
2408 const struct isis_item_list
*b
)
2410 if (a
->mtid
< b
->mtid
)
2412 if (a
->mtid
> b
->mtid
)
2417 RB_PROTOTYPE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
2418 RB_GENERATE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
2420 struct isis_item_list
*isis_get_mt_items(struct isis_mt_item_list
*m
,
2423 struct isis_item_list
*rv
;
2425 rv
= isis_lookup_mt_items(m
, mtid
);
2427 rv
= XCALLOC(MTYPE_ISIS_MT_ITEM_LIST
, sizeof(*rv
));
2430 RB_INSERT(isis_mt_item_list
, m
, rv
);
2436 struct isis_item_list
*isis_lookup_mt_items(struct isis_mt_item_list
*m
,
2439 struct isis_item_list key
= {.mtid
= mtid
};
2441 return RB_FIND(isis_mt_item_list
, m
, &key
);
2444 static void free_mt_items(enum isis_tlv_context context
,
2445 enum isis_tlv_type type
, struct isis_mt_item_list
*m
)
2447 struct isis_item_list
*n
, *nnext
;
2449 RB_FOREACH_SAFE (n
, isis_mt_item_list
, m
, nnext
) {
2450 free_items(context
, type
, n
);
2451 RB_REMOVE(isis_mt_item_list
, m
, n
);
2452 XFREE(MTYPE_ISIS_MT_ITEM_LIST
, n
);
2456 static void format_mt_items(enum isis_tlv_context context
,
2457 enum isis_tlv_type type
,
2458 struct isis_mt_item_list
*m
, struct sbuf
*buf
,
2461 struct isis_item_list
*n
;
2463 RB_FOREACH (n
, isis_mt_item_list
, m
) {
2464 format_items_(n
->mtid
, context
, type
, n
, buf
, indent
);
2468 static int pack_mt_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
2469 struct isis_mt_item_list
*m
, struct stream
*s
,
2470 struct isis_tlvs
**fragment_tlvs
,
2471 struct pack_order_entry
*pe
,
2472 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2473 struct list
*new_fragment_arg
)
2475 struct isis_item_list
*n
;
2477 RB_FOREACH (n
, isis_mt_item_list
, m
) {
2480 rv
= pack_items_(n
->mtid
, context
, type
, n
, s
, fragment_tlvs
,
2481 pe
, new_fragment
, new_fragment_arg
);
2489 static void copy_mt_items(enum isis_tlv_context context
,
2490 enum isis_tlv_type type
,
2491 struct isis_mt_item_list
*src
,
2492 struct isis_mt_item_list
*dest
)
2494 struct isis_item_list
*n
;
2496 RB_INIT(isis_mt_item_list
, dest
);
2498 RB_FOREACH (n
, isis_mt_item_list
, src
) {
2499 copy_items(context
, type
, n
, isis_get_mt_items(dest
, n
->mtid
));
2503 /* Functions related to tlvs in general */
2505 struct isis_tlvs
*isis_alloc_tlvs(void)
2507 struct isis_tlvs
*result
;
2509 result
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*result
));
2511 init_item_list(&result
->isis_auth
);
2512 init_item_list(&result
->area_addresses
);
2513 init_item_list(&result
->mt_router_info
);
2514 init_item_list(&result
->oldstyle_reach
);
2515 init_item_list(&result
->lan_neighbor
);
2516 init_item_list(&result
->lsp_entries
);
2517 init_item_list(&result
->extended_reach
);
2518 RB_INIT(isis_mt_item_list
, &result
->mt_reach
);
2519 init_item_list(&result
->oldstyle_ip_reach
);
2520 init_item_list(&result
->oldstyle_ip_reach_ext
);
2521 init_item_list(&result
->ipv4_address
);
2522 init_item_list(&result
->ipv6_address
);
2523 init_item_list(&result
->extended_ip_reach
);
2524 RB_INIT(isis_mt_item_list
, &result
->mt_ip_reach
);
2525 init_item_list(&result
->ipv6_reach
);
2526 RB_INIT(isis_mt_item_list
, &result
->mt_ipv6_reach
);
2531 struct isis_tlvs
*isis_copy_tlvs(struct isis_tlvs
*tlvs
)
2533 struct isis_tlvs
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2535 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
,
2538 rv
->purge_originator
=
2539 copy_tlv_purge_originator(tlvs
->purge_originator
);
2541 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2542 &tlvs
->area_addresses
, &rv
->area_addresses
);
2544 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2545 &tlvs
->mt_router_info
, &rv
->mt_router_info
);
2547 rv
->mt_router_info_empty
= tlvs
->mt_router_info_empty
;
2549 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2550 &tlvs
->oldstyle_reach
, &rv
->oldstyle_reach
);
2552 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2553 &tlvs
->lan_neighbor
, &rv
->lan_neighbor
);
2555 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
2558 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2559 &tlvs
->extended_reach
, &rv
->extended_reach
);
2561 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
2564 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2565 &tlvs
->oldstyle_ip_reach
, &rv
->oldstyle_ip_reach
);
2567 copy_tlv_protocols_supported(&tlvs
->protocols_supported
,
2568 &rv
->protocols_supported
);
2570 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2571 &tlvs
->oldstyle_ip_reach_ext
, &rv
->oldstyle_ip_reach_ext
);
2573 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
, &tlvs
->ipv4_address
,
2576 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
, &tlvs
->ipv6_address
,
2579 rv
->te_router_id
= copy_tlv_te_router_id(tlvs
->te_router_id
);
2581 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2582 &tlvs
->extended_ip_reach
, &rv
->extended_ip_reach
);
2584 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2585 &tlvs
->mt_ip_reach
, &rv
->mt_ip_reach
);
2587 rv
->hostname
= copy_tlv_dynamic_hostname(tlvs
->hostname
);
2589 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
2592 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2593 &tlvs
->mt_ipv6_reach
, &rv
->mt_ipv6_reach
);
2595 rv
->threeway_adj
= copy_tlv_threeway_adj(tlvs
->threeway_adj
);
2597 rv
->spine_leaf
= copy_tlv_spine_leaf(tlvs
->spine_leaf
);
2602 static void format_tlvs(struct isis_tlvs
*tlvs
, struct sbuf
*buf
, int indent
)
2604 format_tlv_protocols_supported(&tlvs
->protocols_supported
, buf
, indent
);
2606 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
, buf
,
2609 format_tlv_purge_originator(tlvs
->purge_originator
, buf
, indent
);
2611 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2612 &tlvs
->area_addresses
, buf
, indent
);
2614 if (tlvs
->mt_router_info_empty
) {
2615 sbuf_push(buf
, indent
, "MT Router Info: None\n");
2617 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2618 &tlvs
->mt_router_info
, buf
, indent
);
2621 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2622 &tlvs
->oldstyle_reach
, buf
, indent
);
2624 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2625 &tlvs
->lan_neighbor
, buf
, indent
);
2627 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
2630 format_tlv_dynamic_hostname(tlvs
->hostname
, buf
, indent
);
2631 format_tlv_te_router_id(tlvs
->te_router_id
, buf
, indent
);
2633 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2634 &tlvs
->extended_reach
, buf
, indent
);
2636 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
2639 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2640 &tlvs
->oldstyle_ip_reach
, buf
, indent
);
2642 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2643 &tlvs
->oldstyle_ip_reach_ext
, buf
, indent
);
2645 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
2646 &tlvs
->ipv4_address
, buf
, indent
);
2648 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
2649 &tlvs
->ipv6_address
, buf
, indent
);
2651 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2652 &tlvs
->extended_ip_reach
, buf
, indent
);
2654 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2655 &tlvs
->mt_ip_reach
, buf
, indent
);
2657 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
2660 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2661 &tlvs
->mt_ipv6_reach
, buf
, indent
);
2663 format_tlv_threeway_adj(tlvs
->threeway_adj
, buf
, indent
);
2665 format_tlv_spine_leaf(tlvs
->spine_leaf
, buf
, indent
);
2668 const char *isis_format_tlvs(struct isis_tlvs
*tlvs
)
2670 static struct sbuf buf
;
2672 if (!sbuf_buf(&buf
))
2673 sbuf_init(&buf
, NULL
, 0);
2676 format_tlvs(tlvs
, &buf
, 0);
2677 return sbuf_buf(&buf
);
2680 void isis_free_tlvs(struct isis_tlvs
*tlvs
)
2685 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
2686 free_tlv_purge_originator(tlvs
->purge_originator
);
2687 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2688 &tlvs
->area_addresses
);
2689 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2690 &tlvs
->mt_router_info
);
2691 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2692 &tlvs
->oldstyle_reach
);
2693 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2694 &tlvs
->lan_neighbor
);
2695 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
);
2696 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2697 &tlvs
->extended_reach
);
2698 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
);
2699 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2700 &tlvs
->oldstyle_ip_reach
);
2701 free_tlv_protocols_supported(&tlvs
->protocols_supported
);
2702 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2703 &tlvs
->oldstyle_ip_reach_ext
);
2704 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
2705 &tlvs
->ipv4_address
);
2706 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
2707 &tlvs
->ipv6_address
);
2708 free_tlv_te_router_id(tlvs
->te_router_id
);
2709 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2710 &tlvs
->extended_ip_reach
);
2711 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2712 &tlvs
->mt_ip_reach
);
2713 free_tlv_dynamic_hostname(tlvs
->hostname
);
2714 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
);
2715 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2716 &tlvs
->mt_ipv6_reach
);
2717 free_tlv_threeway_adj(tlvs
->threeway_adj
);
2718 free_tlv_spine_leaf(tlvs
->spine_leaf
);
2720 XFREE(MTYPE_ISIS_TLV
, tlvs
);
2723 static void add_padding(struct stream
*s
)
2725 while (STREAM_WRITEABLE(s
)) {
2726 if (STREAM_WRITEABLE(s
) == 1)
2728 uint32_t padding_len
= STREAM_WRITEABLE(s
) - 2;
2730 if (padding_len
> 255) {
2731 if (padding_len
== 256)
2737 stream_putc(s
, ISIS_TLV_PADDING
);
2738 stream_putc(s
, padding_len
);
2739 stream_put(s
, NULL
, padding_len
);
2743 #define LSP_REM_LIFETIME_OFF 10
2744 #define LSP_CHECKSUM_OFF 24
2745 static void safe_auth_md5(struct stream
*s
, uint16_t *checksum
,
2746 uint16_t *rem_lifetime
)
2748 memcpy(rem_lifetime
, STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
,
2749 sizeof(*rem_lifetime
));
2750 memset(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, 0, sizeof(*rem_lifetime
));
2751 memcpy(checksum
, STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, sizeof(*checksum
));
2752 memset(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, 0, sizeof(*checksum
));
2755 static void restore_auth_md5(struct stream
*s
, uint16_t checksum
,
2756 uint16_t rem_lifetime
)
2758 memcpy(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, &rem_lifetime
,
2759 sizeof(rem_lifetime
));
2760 memcpy(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, &checksum
, sizeof(checksum
));
2763 static void update_auth_hmac_md5(struct isis_auth
*auth
, struct stream
*s
,
2767 uint16_t checksum
, rem_lifetime
;
2770 safe_auth_md5(s
, &checksum
, &rem_lifetime
);
2772 memset(STREAM_DATA(s
) + auth
->offset
, 0, 16);
2773 hmac_md5(STREAM_DATA(s
), stream_get_endp(s
), auth
->passwd
,
2774 auth
->plength
, digest
);
2775 memcpy(auth
->value
, digest
, 16);
2776 memcpy(STREAM_DATA(s
) + auth
->offset
, digest
, 16);
2779 restore_auth_md5(s
, checksum
, rem_lifetime
);
2782 static void update_auth(struct isis_tlvs
*tlvs
, struct stream
*s
, bool is_lsp
)
2784 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
2786 for (struct isis_auth
*auth
= auth_head
; auth
; auth
= auth
->next
) {
2787 if (auth
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
2788 update_auth_hmac_md5(auth
, s
, is_lsp
);
2792 static int handle_pack_entry(struct pack_order_entry
*pe
,
2793 struct isis_tlvs
*tlvs
, struct stream
*stream
,
2794 struct isis_tlvs
**fragment_tlvs
,
2795 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2796 struct list
*new_fragment_arg
)
2800 if (pe
->how_to_pack
== ISIS_ITEMS
) {
2801 struct isis_item_list
*l
;
2802 l
= (struct isis_item_list
*)(((char *)tlvs
)
2803 + pe
->what_to_pack
);
2804 rv
= pack_items(pe
->context
, pe
->type
, l
, stream
, fragment_tlvs
,
2805 pe
, new_fragment
, new_fragment_arg
);
2807 struct isis_mt_item_list
*l
;
2808 l
= (struct isis_mt_item_list
*)(((char *)tlvs
)
2809 + pe
->what_to_pack
);
2810 rv
= pack_mt_items(pe
->context
, pe
->type
, l
, stream
,
2811 fragment_tlvs
, pe
, new_fragment
,
2818 static int pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
2819 struct isis_tlvs
*fragment_tlvs
,
2820 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2821 struct list
*new_fragment_arg
)
2825 /* When fragmenting, don't add auth as it's already accounted for in the
2826 * size we are given. */
2827 if (!fragment_tlvs
) {
2828 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
,
2829 &tlvs
->isis_auth
, stream
, NULL
, NULL
, NULL
,
2835 rv
= pack_tlv_purge_originator(tlvs
->purge_originator
, stream
);
2838 if (fragment_tlvs
) {
2839 fragment_tlvs
->purge_originator
=
2840 copy_tlv_purge_originator(tlvs
->purge_originator
);
2843 rv
= pack_tlv_protocols_supported(&tlvs
->protocols_supported
, stream
);
2846 if (fragment_tlvs
) {
2847 copy_tlv_protocols_supported(
2848 &tlvs
->protocols_supported
,
2849 &fragment_tlvs
->protocols_supported
);
2852 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2853 &tlvs
->area_addresses
, stream
, NULL
, NULL
, NULL
, NULL
);
2856 if (fragment_tlvs
) {
2857 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2858 &tlvs
->area_addresses
,
2859 &fragment_tlvs
->area_addresses
);
2863 if (tlvs
->mt_router_info_empty
) {
2864 if (STREAM_WRITEABLE(stream
) < 2)
2866 stream_putc(stream
, ISIS_TLV_MT_ROUTER_INFO
);
2867 stream_putc(stream
, 0);
2869 fragment_tlvs
->mt_router_info_empty
= true;
2871 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2872 &tlvs
->mt_router_info
, stream
, NULL
, NULL
, NULL
,
2876 if (fragment_tlvs
) {
2877 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2878 &tlvs
->mt_router_info
,
2879 &fragment_tlvs
->mt_router_info
);
2883 rv
= pack_tlv_dynamic_hostname(tlvs
->hostname
, stream
);
2887 fragment_tlvs
->hostname
=
2888 copy_tlv_dynamic_hostname(tlvs
->hostname
);
2890 rv
= pack_tlv_te_router_id(tlvs
->te_router_id
, stream
);
2893 if (fragment_tlvs
) {
2894 fragment_tlvs
->te_router_id
=
2895 copy_tlv_te_router_id(tlvs
->te_router_id
);
2898 rv
= pack_tlv_threeway_adj(tlvs
->threeway_adj
, stream
);
2901 if (fragment_tlvs
) {
2902 fragment_tlvs
->threeway_adj
=
2903 copy_tlv_threeway_adj(tlvs
->threeway_adj
);
2906 rv
= pack_tlv_spine_leaf(tlvs
->spine_leaf
, stream
);
2909 if (fragment_tlvs
) {
2910 fragment_tlvs
->spine_leaf
=
2911 copy_tlv_spine_leaf(tlvs
->spine_leaf
);
2914 for (size_t pack_idx
= 0; pack_idx
< array_size(pack_order
);
2916 rv
= handle_pack_entry(&pack_order
[pack_idx
], tlvs
, stream
,
2917 fragment_tlvs
? &fragment_tlvs
: NULL
,
2918 new_fragment
, new_fragment_arg
);
2927 int isis_pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
2928 size_t len_pointer
, bool pad
, bool is_lsp
)
2932 rv
= pack_tlvs(tlvs
, stream
, NULL
, NULL
, NULL
);
2937 add_padding(stream
);
2939 if (len_pointer
!= (size_t)-1) {
2940 stream_putw_at(stream
, len_pointer
, stream_get_endp(stream
));
2943 update_auth(tlvs
, stream
, is_lsp
);
2948 static struct isis_tlvs
*new_fragment(struct list
*l
)
2950 struct isis_tlvs
*rv
= isis_alloc_tlvs();
2952 listnode_add(l
, rv
);
2956 struct list
*isis_fragment_tlvs(struct isis_tlvs
*tlvs
, size_t size
)
2958 struct stream
*dummy_stream
= stream_new(size
);
2959 struct list
*rv
= list_new();
2960 struct isis_tlvs
*fragment_tlvs
= new_fragment(rv
);
2962 if (pack_tlvs(tlvs
, dummy_stream
, fragment_tlvs
, new_fragment
, rv
)) {
2963 struct listnode
*node
;
2964 for (ALL_LIST_ELEMENTS_RO(rv
, node
, fragment_tlvs
))
2965 isis_free_tlvs(fragment_tlvs
);
2969 stream_free(dummy_stream
);
2973 static int unpack_tlv_unknown(enum isis_tlv_context context
, uint8_t tlv_type
,
2974 uint8_t tlv_len
, struct stream
*s
,
2975 struct sbuf
*log
, int indent
)
2977 stream_forward_getp(s
, tlv_len
);
2978 sbuf_push(log
, indent
,
2979 "Skipping unknown TLV %" PRIu8
" (%" PRIu8
" bytes)\n",
2984 static int unpack_tlv(enum isis_tlv_context context
, size_t avail_len
,
2985 struct stream
*stream
, struct sbuf
*log
, void *dest
,
2986 int indent
, bool *unpacked_known_tlvs
)
2988 uint8_t tlv_type
, tlv_len
;
2989 const struct tlv_ops
*ops
;
2991 sbuf_push(log
, indent
, "Unpacking TLV...\n");
2993 if (avail_len
< 2) {
2996 "Available data %zu too short to contain a TLV header.\n",
3001 tlv_type
= stream_getc(stream
);
3002 tlv_len
= stream_getc(stream
);
3004 sbuf_push(log
, indent
+ 2,
3005 "Found TLV of type %" PRIu8
" and len %" PRIu8
".\n",
3008 if (avail_len
< ((size_t)tlv_len
) + 2) {
3009 sbuf_push(log
, indent
+ 2,
3010 "Available data %zu too short for claimed TLV len %" PRIu8
".\n",
3011 avail_len
- 2, tlv_len
);
3015 ops
= tlv_table
[context
][tlv_type
];
3016 if (ops
&& ops
->unpack
) {
3017 if (unpacked_known_tlvs
)
3018 *unpacked_known_tlvs
= true;
3019 return ops
->unpack(context
, tlv_type
, tlv_len
, stream
, log
,
3023 return unpack_tlv_unknown(context
, tlv_type
, tlv_len
, stream
, log
,
3027 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
3028 struct stream
*stream
, struct sbuf
*log
, void *dest
,
3029 int indent
, bool *unpacked_known_tlvs
)
3032 size_t tlv_start
, tlv_pos
;
3034 tlv_start
= stream_get_getp(stream
);
3037 sbuf_push(log
, indent
, "Unpacking %zu bytes of %s...\n", avail_len
,
3038 (context
== ISIS_CONTEXT_LSP
) ? "TLVs" : "sub-TLVs");
3040 while (tlv_pos
< avail_len
) {
3041 rv
= unpack_tlv(context
, avail_len
- tlv_pos
, stream
, log
, dest
,
3042 indent
+ 2, unpacked_known_tlvs
);
3046 tlv_pos
= stream_get_getp(stream
) - tlv_start
;
3052 int isis_unpack_tlvs(size_t avail_len
, struct stream
*stream
,
3053 struct isis_tlvs
**dest
, const char **log
)
3055 static struct sbuf logbuf
;
3058 struct isis_tlvs
*result
;
3060 if (!sbuf_buf(&logbuf
))
3061 sbuf_init(&logbuf
, NULL
, 0);
3063 sbuf_reset(&logbuf
);
3064 if (avail_len
> STREAM_READABLE(stream
)) {
3065 sbuf_push(&logbuf
, indent
,
3066 "Stream doesn't contain sufficient data. "
3067 "Claimed %zu, available %zu\n",
3068 avail_len
, STREAM_READABLE(stream
));
3072 result
= isis_alloc_tlvs();
3073 rv
= unpack_tlvs(ISIS_CONTEXT_LSP
, avail_len
, stream
, &logbuf
, result
,
3076 *log
= sbuf_buf(&logbuf
);
3082 #define TLV_OPS(_name_, _desc_) \
3083 static const struct tlv_ops tlv_##_name_##_ops = { \
3084 .name = _desc_, .unpack = unpack_tlv_##_name_, \
3087 #define ITEM_TLV_OPS(_name_, _desc_) \
3088 static const struct tlv_ops tlv_##_name_##_ops = { \
3090 .unpack = unpack_tlv_with_items, \
3092 .pack_item = pack_item_##_name_, \
3093 .free_item = free_item_##_name_, \
3094 .unpack_item = unpack_item_##_name_, \
3095 .format_item = format_item_##_name_, \
3096 .copy_item = copy_item_##_name_}
3098 #define SUBTLV_OPS(_name_, _desc_) \
3099 static const struct tlv_ops subtlv_##_name_##_ops = { \
3100 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
3103 #define ITEM_SUBTLV_OPS(_name_, _desc_) \
3104 ITEM_TLV_OPS(_name_, _desc_)
3106 ITEM_TLV_OPS(area_address
, "TLV 1 Area Addresses");
3107 ITEM_TLV_OPS(oldstyle_reach
, "TLV 2 IS Reachability");
3108 ITEM_TLV_OPS(lan_neighbor
, "TLV 6 LAN Neighbors");
3109 ITEM_TLV_OPS(lsp_entry
, "TLV 9 LSP Entries");
3110 ITEM_TLV_OPS(auth
, "TLV 10 IS-IS Auth");
3111 TLV_OPS(purge_originator
, "TLV 13 Purge Originator Identification");
3112 ITEM_TLV_OPS(extended_reach
, "TLV 22 Extended Reachability");
3113 ITEM_TLV_OPS(oldstyle_ip_reach
, "TLV 128/130 IP Reachability");
3114 TLV_OPS(protocols_supported
, "TLV 129 Protocols Supported");
3115 ITEM_TLV_OPS(ipv4_address
, "TLV 132 IPv4 Interface Address");
3116 TLV_OPS(te_router_id
, "TLV 134 TE Router ID");
3117 ITEM_TLV_OPS(extended_ip_reach
, "TLV 135 Extended IP Reachability");
3118 TLV_OPS(dynamic_hostname
, "TLV 137 Dynamic Hostname");
3119 TLV_OPS(spine_leaf
, "TLV 150 Spine Leaf Extensions");
3120 ITEM_TLV_OPS(mt_router_info
, "TLV 229 MT Router Information");
3121 TLV_OPS(threeway_adj
, "TLV 240 P2P Three-Way Adjacency");
3122 ITEM_TLV_OPS(ipv6_address
, "TLV 232 IPv6 Interface Address");
3123 ITEM_TLV_OPS(ipv6_reach
, "TLV 236 IPv6 Reachability");
3125 ITEM_SUBTLV_OPS(prefix_sid
, "Sub-TLV 3 SR Prefix-SID");
3126 SUBTLV_OPS(ipv6_source_prefix
, "Sub-TLV 22 IPv6 Source Prefix");
3128 static const struct tlv_ops
*tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
] = {
3129 [ISIS_CONTEXT_LSP
] = {
3130 [ISIS_TLV_AREA_ADDRESSES
] = &tlv_area_address_ops
,
3131 [ISIS_TLV_OLDSTYLE_REACH
] = &tlv_oldstyle_reach_ops
,
3132 [ISIS_TLV_LAN_NEIGHBORS
] = &tlv_lan_neighbor_ops
,
3133 [ISIS_TLV_LSP_ENTRY
] = &tlv_lsp_entry_ops
,
3134 [ISIS_TLV_AUTH
] = &tlv_auth_ops
,
3135 [ISIS_TLV_PURGE_ORIGINATOR
] = &tlv_purge_originator_ops
,
3136 [ISIS_TLV_EXTENDED_REACH
] = &tlv_extended_reach_ops
,
3137 [ISIS_TLV_MT_REACH
] = &tlv_extended_reach_ops
,
3138 [ISIS_TLV_OLDSTYLE_IP_REACH
] = &tlv_oldstyle_ip_reach_ops
,
3139 [ISIS_TLV_PROTOCOLS_SUPPORTED
] = &tlv_protocols_supported_ops
,
3140 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT
] = &tlv_oldstyle_ip_reach_ops
,
3141 [ISIS_TLV_IPV4_ADDRESS
] = &tlv_ipv4_address_ops
,
3142 [ISIS_TLV_TE_ROUTER_ID
] = &tlv_te_router_id_ops
,
3143 [ISIS_TLV_EXTENDED_IP_REACH
] = &tlv_extended_ip_reach_ops
,
3144 [ISIS_TLV_MT_IP_REACH
] = &tlv_extended_ip_reach_ops
,
3145 [ISIS_TLV_DYNAMIC_HOSTNAME
] = &tlv_dynamic_hostname_ops
,
3146 [ISIS_TLV_SPINE_LEAF_EXT
] = &tlv_spine_leaf_ops
,
3147 [ISIS_TLV_MT_ROUTER_INFO
] = &tlv_mt_router_info_ops
,
3148 [ISIS_TLV_THREE_WAY_ADJ
] = &tlv_threeway_adj_ops
,
3149 [ISIS_TLV_IPV6_ADDRESS
] = &tlv_ipv6_address_ops
,
3150 [ISIS_TLV_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
3151 [ISIS_TLV_MT_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
3153 [ISIS_CONTEXT_SUBTLV_NE_REACH
] = {},
3154 [ISIS_CONTEXT_SUBTLV_IP_REACH
] = {
3155 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
3157 [ISIS_CONTEXT_SUBTLV_IPV6_REACH
] = {
3158 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
3159 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX
] = &subtlv_ipv6_source_prefix_ops
,
3163 /* Accessor functions */
3165 void isis_tlvs_add_auth(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
)
3167 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
3168 init_item_list(&tlvs
->isis_auth
);
3170 if (passwd
->type
== ISIS_PASSWD_TYPE_UNUSED
)
3173 struct isis_auth
*auth
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*auth
));
3175 auth
->type
= passwd
->type
;
3177 auth
->plength
= passwd
->len
;
3178 memcpy(auth
->passwd
, passwd
->passwd
,
3179 MIN(sizeof(auth
->passwd
), sizeof(passwd
->passwd
)));
3181 if (auth
->type
== ISIS_PASSWD_TYPE_CLEARTXT
) {
3182 auth
->length
= passwd
->len
;
3183 memcpy(auth
->value
, passwd
->passwd
,
3184 MIN(sizeof(auth
->value
), sizeof(passwd
->passwd
)));
3187 append_item(&tlvs
->isis_auth
, (struct isis_item
*)auth
);
3190 void isis_tlvs_add_area_addresses(struct isis_tlvs
*tlvs
,
3191 struct list
*addresses
)
3193 struct listnode
*node
;
3194 struct area_addr
*area_addr
;
3196 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, area_addr
)) {
3197 struct isis_area_address
*a
=
3198 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
3200 a
->len
= area_addr
->addr_len
;
3201 memcpy(a
->addr
, area_addr
->area_addr
, 20);
3202 append_item(&tlvs
->area_addresses
, (struct isis_item
*)a
);
3206 void isis_tlvs_add_lan_neighbors(struct isis_tlvs
*tlvs
, struct list
*neighbors
)
3208 struct listnode
*node
;
3211 for (ALL_LIST_ELEMENTS_RO(neighbors
, node
, snpa
)) {
3212 struct isis_lan_neighbor
*n
=
3213 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*n
));
3215 memcpy(n
->mac
, snpa
, 6);
3216 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)n
);
3220 void isis_tlvs_set_protocols_supported(struct isis_tlvs
*tlvs
,
3221 struct nlpids
*nlpids
)
3223 tlvs
->protocols_supported
.count
= nlpids
->count
;
3224 XFREE(MTYPE_ISIS_TLV
, tlvs
->protocols_supported
.protocols
);
3225 if (nlpids
->count
) {
3226 tlvs
->protocols_supported
.protocols
=
3227 XCALLOC(MTYPE_ISIS_TLV
, nlpids
->count
);
3228 memcpy(tlvs
->protocols_supported
.protocols
, nlpids
->nlpids
,
3231 tlvs
->protocols_supported
.protocols
= NULL
;
3235 void isis_tlvs_add_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3236 bool overload
, bool attached
)
3238 struct isis_mt_router_info
*i
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*i
));
3240 i
->overload
= overload
;
3241 i
->attached
= attached
;
3243 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)i
);
3246 void isis_tlvs_add_ipv4_address(struct isis_tlvs
*tlvs
, struct in_addr
*addr
)
3248 struct isis_ipv4_address
*a
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
3250 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)a
);
3254 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs
*tlvs
,
3255 struct list
*addresses
)
3257 struct listnode
*node
;
3258 struct prefix_ipv4
*ip_addr
;
3259 unsigned int addr_count
= 0;
3261 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
3262 isis_tlvs_add_ipv4_address(tlvs
, &ip_addr
->prefix
);
3264 if (addr_count
>= 63)
3269 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs
*tlvs
,
3270 struct list
*addresses
)
3272 struct listnode
*node
;
3273 struct prefix_ipv6
*ip_addr
;
3275 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
3276 struct isis_ipv6_address
*a
=
3277 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
3279 a
->addr
= ip_addr
->prefix
;
3280 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)a
);
3284 typedef bool (*auth_validator_func
)(struct isis_passwd
*passwd
,
3285 struct stream
*stream
,
3286 struct isis_auth
*auth
, bool is_lsp
);
3288 static bool auth_validator_cleartxt(struct isis_passwd
*passwd
,
3289 struct stream
*stream
,
3290 struct isis_auth
*auth
, bool is_lsp
)
3292 return (auth
->length
== passwd
->len
3293 && !memcmp(auth
->value
, passwd
->passwd
, passwd
->len
));
3296 static bool auth_validator_hmac_md5(struct isis_passwd
*passwd
,
3297 struct stream
*stream
,
3298 struct isis_auth
*auth
, bool is_lsp
)
3302 uint16_t rem_lifetime
;
3305 safe_auth_md5(stream
, &checksum
, &rem_lifetime
);
3307 memset(STREAM_DATA(stream
) + auth
->offset
, 0, 16);
3308 hmac_md5(STREAM_DATA(stream
), stream_get_endp(stream
), passwd
->passwd
,
3309 passwd
->len
, digest
);
3310 memcpy(STREAM_DATA(stream
) + auth
->offset
, auth
->value
, 16);
3312 bool rv
= !memcmp(digest
, auth
->value
, 16);
3315 restore_auth_md5(stream
, checksum
, rem_lifetime
);
3320 static const auth_validator_func auth_validators
[] = {
3321 [ISIS_PASSWD_TYPE_CLEARTXT
] = auth_validator_cleartxt
,
3322 [ISIS_PASSWD_TYPE_HMAC_MD5
] = auth_validator_hmac_md5
,
3325 int isis_tlvs_auth_is_valid(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
,
3326 struct stream
*stream
, bool is_lsp
)
3328 /* If no auth is set, always pass authentication */
3330 return ISIS_AUTH_OK
;
3332 /* If we don't known how to validate the auth, return invalid */
3333 if (passwd
->type
>= array_size(auth_validators
)
3334 || !auth_validators
[passwd
->type
])
3335 return ISIS_AUTH_NO_VALIDATOR
;
3337 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
3338 struct isis_auth
*auth
;
3339 for (auth
= auth_head
; auth
; auth
= auth
->next
) {
3340 if (auth
->type
== passwd
->type
)
3344 /* If matching auth TLV could not be found, return invalid */
3346 return ISIS_AUTH_TYPE_FAILURE
;
3349 /* Perform validation and return result */
3350 if (auth_validators
[passwd
->type
](passwd
, stream
, auth
, is_lsp
))
3351 return ISIS_AUTH_OK
;
3353 return ISIS_AUTH_FAILURE
;
3356 bool isis_tlvs_area_addresses_match(struct isis_tlvs
*tlvs
,
3357 struct list
*addresses
)
3359 struct isis_area_address
*addr_head
;
3361 addr_head
= (struct isis_area_address
*)tlvs
->area_addresses
.head
;
3362 for (struct isis_area_address
*addr
= addr_head
; addr
;
3363 addr
= addr
->next
) {
3364 struct listnode
*node
;
3365 struct area_addr
*a
;
3367 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, a
)) {
3368 if (a
->addr_len
== addr
->len
3369 && !memcmp(a
->area_addr
, addr
->addr
, addr
->len
))
3377 static void tlvs_area_addresses_to_adj(struct isis_tlvs
*tlvs
,
3378 struct isis_adjacency
*adj
,
3381 if (adj
->area_address_count
!= tlvs
->area_addresses
.count
) {
3383 adj
->area_address_count
= tlvs
->area_addresses
.count
;
3384 adj
->area_addresses
= XREALLOC(
3385 MTYPE_ISIS_ADJACENCY_INFO
, adj
->area_addresses
,
3386 adj
->area_address_count
* sizeof(*adj
->area_addresses
));
3389 struct isis_area_address
*addr
= NULL
;
3390 for (unsigned int i
= 0; i
< tlvs
->area_addresses
.count
; i
++) {
3392 addr
= (struct isis_area_address
*)
3393 tlvs
->area_addresses
.head
;
3397 if (adj
->area_addresses
[i
].addr_len
== addr
->len
3398 && !memcmp(adj
->area_addresses
[i
].area_addr
, addr
->addr
,
3404 adj
->area_addresses
[i
].addr_len
= addr
->len
;
3405 memcpy(adj
->area_addresses
[i
].area_addr
, addr
->addr
, addr
->len
);
3409 static void tlvs_protocols_supported_to_adj(struct isis_tlvs
*tlvs
,
3410 struct isis_adjacency
*adj
,
3413 bool ipv4_supported
= false, ipv6_supported
= false;
3415 for (uint8_t i
= 0; i
< tlvs
->protocols_supported
.count
; i
++) {
3416 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IP
)
3417 ipv4_supported
= true;
3418 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IPV6
)
3419 ipv6_supported
= true;
3422 struct nlpids reduced
= {};
3424 if (ipv4_supported
&& ipv6_supported
) {
3426 reduced
.nlpids
[0] = NLPID_IP
;
3427 reduced
.nlpids
[1] = NLPID_IPV6
;
3428 } else if (ipv4_supported
) {
3430 reduced
.nlpids
[0] = NLPID_IP
;
3431 } else if (ipv6_supported
) {
3433 reduced
.nlpids
[0] = NLPID_IPV6
;
3438 if (adj
->nlpids
.count
== reduced
.count
3439 && !memcmp(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
))
3443 adj
->nlpids
.count
= reduced
.count
;
3444 memcpy(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
);
3447 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs
*tlvs
,
3448 struct isis_adjacency
*adj
,
3451 if (adj
->ipv4_address_count
!= tlvs
->ipv4_address
.count
) {
3453 adj
->ipv4_address_count
= tlvs
->ipv4_address
.count
;
3454 adj
->ipv4_addresses
= XREALLOC(
3455 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv4_addresses
,
3456 adj
->ipv4_address_count
* sizeof(*adj
->ipv4_addresses
));
3459 struct isis_ipv4_address
*addr
= NULL
;
3460 for (unsigned int i
= 0; i
< tlvs
->ipv4_address
.count
; i
++) {
3462 addr
= (struct isis_ipv4_address
*)
3463 tlvs
->ipv4_address
.head
;
3467 if (!memcmp(&adj
->ipv4_addresses
[i
], &addr
->addr
,
3468 sizeof(addr
->addr
)))
3472 adj
->ipv4_addresses
[i
] = addr
->addr
;
3476 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
3477 struct isis_adjacency
*adj
,
3480 if (adj
->ipv6_address_count
!= tlvs
->ipv6_address
.count
) {
3482 adj
->ipv6_address_count
= tlvs
->ipv6_address
.count
;
3483 adj
->ipv6_addresses
= XREALLOC(
3484 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv6_addresses
,
3485 adj
->ipv6_address_count
* sizeof(*adj
->ipv6_addresses
));
3488 struct isis_ipv6_address
*addr
= NULL
;
3489 for (unsigned int i
= 0; i
< tlvs
->ipv6_address
.count
; i
++) {
3491 addr
= (struct isis_ipv6_address
*)
3492 tlvs
->ipv6_address
.head
;
3496 if (!memcmp(&adj
->ipv6_addresses
[i
], &addr
->addr
,
3497 sizeof(addr
->addr
)))
3501 adj
->ipv6_addresses
[i
] = addr
->addr
;
3505 void isis_tlvs_to_adj(struct isis_tlvs
*tlvs
, struct isis_adjacency
*adj
,
3510 tlvs_area_addresses_to_adj(tlvs
, adj
, changed
);
3511 tlvs_protocols_supported_to_adj(tlvs
, adj
, changed
);
3512 tlvs_ipv4_addresses_to_adj(tlvs
, adj
, changed
);
3513 tlvs_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
3516 bool isis_tlvs_own_snpa_found(struct isis_tlvs
*tlvs
, uint8_t *snpa
)
3518 struct isis_lan_neighbor
*ne_head
;
3520 ne_head
= (struct isis_lan_neighbor
*)tlvs
->lan_neighbor
.head
;
3521 for (struct isis_lan_neighbor
*ne
= ne_head
; ne
; ne
= ne
->next
) {
3522 if (!memcmp(ne
->mac
, snpa
, ETH_ALEN
))
3529 void isis_tlvs_add_lsp_entry(struct isis_tlvs
*tlvs
, struct isis_lsp
*lsp
)
3531 struct isis_lsp_entry
*entry
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*entry
));
3533 entry
->rem_lifetime
= lsp
->hdr
.rem_lifetime
;
3534 memcpy(entry
->id
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 2);
3535 entry
->checksum
= lsp
->hdr
.checksum
;
3536 entry
->seqno
= lsp
->hdr
.seqno
;
3539 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)entry
);
3542 void isis_tlvs_add_csnp_entries(struct isis_tlvs
*tlvs
, uint8_t *start_id
,
3543 uint8_t *stop_id
, uint16_t num_lsps
,
3544 struct lspdb_head
*head
,
3545 struct isis_lsp
**last_lsp
)
3547 struct isis_lsp searchfor
;
3548 struct isis_lsp
*first
, *lsp
;
3550 memcpy(&searchfor
.hdr
.lsp_id
, start_id
, sizeof(searchfor
.hdr
.lsp_id
));
3551 first
= lspdb_find_gteq(head
, &searchfor
);
3555 frr_each_from (lspdb
, head
, lsp
, first
) {
3556 if (memcmp(lsp
->hdr
.lsp_id
, stop_id
, sizeof(lsp
->hdr
.lsp_id
))
3557 > 0 || tlvs
->lsp_entries
.count
== num_lsps
)
3560 isis_tlvs_add_lsp_entry(tlvs
, lsp
);
3565 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs
*tlvs
,
3566 const char *hostname
)
3568 XFREE(MTYPE_ISIS_TLV
, tlvs
->hostname
);
3570 tlvs
->hostname
= XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
3573 void isis_tlvs_set_te_router_id(struct isis_tlvs
*tlvs
,
3574 const struct in_addr
*id
)
3576 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id
);
3579 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
3580 memcpy(tlvs
->te_router_id
, id
, sizeof(*id
));
3583 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs
*tlvs
,
3584 struct prefix_ipv4
*dest
, uint8_t metric
)
3586 struct isis_oldstyle_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3589 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3590 apply_mask_ipv4(&r
->prefix
);
3591 append_item(&tlvs
->oldstyle_ip_reach
, (struct isis_item
*)r
);
3594 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs
*tlvs
,
3595 struct prefix_ipv4
*dest
, uint32_t metric
)
3597 struct isis_extended_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3600 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3601 apply_mask_ipv4(&r
->prefix
);
3602 append_item(&tlvs
->extended_ip_reach
, (struct isis_item
*)r
);
3605 void isis_tlvs_add_ipv6_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3606 struct prefix_ipv6
*dest
, uint32_t metric
)
3608 struct isis_ipv6_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3611 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3612 apply_mask_ipv6(&r
->prefix
);
3614 struct isis_item_list
*l
;
3615 l
= (mtid
== ISIS_MT_IPV4_UNICAST
)
3617 : isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
3618 append_item(l
, (struct isis_item
*)r
);
3621 void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3622 struct prefix_ipv6
*dest
,
3623 struct prefix_ipv6
*src
,
3626 isis_tlvs_add_ipv6_reach(tlvs
, mtid
, dest
, metric
);
3627 struct isis_item_list
*l
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
,
3630 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)last_item(l
);
3631 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
3632 r
->subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*src
));
3633 memcpy(r
->subtlvs
->source_prefix
, src
, sizeof(*src
));
3636 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs
*tlvs
, uint8_t *id
,
3639 struct isis_oldstyle_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3642 memcpy(r
->id
, id
, sizeof(r
->id
));
3643 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)r
);
3646 void isis_tlvs_add_extended_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3647 uint8_t *id
, uint32_t metric
,
3648 uint8_t *subtlvs
, uint8_t subtlv_len
)
3650 struct isis_extended_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3652 memcpy(r
->id
, id
, sizeof(r
->id
));
3654 if (subtlvs
&& subtlv_len
) {
3655 r
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, subtlv_len
);
3656 memcpy(r
->subtlvs
, subtlvs
, subtlv_len
);
3657 r
->subtlv_len
= subtlv_len
;
3660 struct isis_item_list
*l
;
3661 if (mtid
== ISIS_MT_IPV4_UNICAST
)
3662 l
= &tlvs
->extended_reach
;
3664 l
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
3665 append_item(l
, (struct isis_item
*)r
);
3668 void isis_tlvs_add_threeway_adj(struct isis_tlvs
*tlvs
,
3669 enum isis_threeway_state state
,
3670 uint32_t local_circuit_id
,
3671 const uint8_t *neighbor_id
,
3672 uint32_t neighbor_circuit_id
)
3674 assert(!tlvs
->threeway_adj
);
3676 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
3677 tlvs
->threeway_adj
->state
= state
;
3678 tlvs
->threeway_adj
->local_circuit_id
= local_circuit_id
;
3681 tlvs
->threeway_adj
->neighbor_set
= true;
3682 memcpy(tlvs
->threeway_adj
->neighbor_id
, neighbor_id
, 6);
3683 tlvs
->threeway_adj
->neighbor_circuit_id
= neighbor_circuit_id
;
3687 void isis_tlvs_add_spine_leaf(struct isis_tlvs
*tlvs
, uint8_t tier
,
3688 bool has_tier
, bool is_leaf
, bool is_spine
,
3691 assert(!tlvs
->spine_leaf
);
3693 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
3696 tlvs
->spine_leaf
->tier
= tier
;
3699 tlvs
->spine_leaf
->has_tier
= has_tier
;
3700 tlvs
->spine_leaf
->is_leaf
= is_leaf
;
3701 tlvs
->spine_leaf
->is_spine
= is_spine
;
3702 tlvs
->spine_leaf
->is_backup
= is_backup
;
3705 struct isis_mt_router_info
*
3706 isis_tlvs_lookup_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
)
3708 if (tlvs
->mt_router_info_empty
)
3711 struct isis_mt_router_info
*rv
;
3712 for (rv
= (struct isis_mt_router_info
*)tlvs
->mt_router_info
.head
; rv
;
3714 if (rv
->mtid
== mtid
)
3721 void isis_tlvs_set_purge_originator(struct isis_tlvs
*tlvs
,
3722 const uint8_t *generator
,
3723 const uint8_t *sender
)
3725 assert(!tlvs
->purge_originator
);
3727 tlvs
->purge_originator
= XCALLOC(MTYPE_ISIS_TLV
,
3728 sizeof(*tlvs
->purge_originator
));
3729 memcpy(tlvs
->purge_originator
->generator
, generator
,
3730 sizeof(tlvs
->purge_originator
->generator
));
3732 tlvs
->purge_originator
->sender_set
= true;
3733 memcpy(tlvs
->purge_originator
->sender
, sender
,
3734 sizeof(tlvs
->purge_originator
->sender
));