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
25 #ifdef CRYPTO_INTERNAL
32 #include "isisd/isisd.h"
33 #include "isisd/isis_memory.h"
34 #include "isisd/isis_tlvs.h"
35 #include "isisd/isis_common.h"
36 #include "isisd/isis_mt.h"
37 #include "isisd/isis_misc.h"
38 #include "isisd/isis_adjacency.h"
39 #include "isisd/isis_circuit.h"
40 #include "isisd/isis_pdu.h"
41 #include "isisd/isis_lsp.h"
42 #include "isisd/isis_te.h"
44 DEFINE_MTYPE_STATIC(ISISD
, ISIS_TLV
, "ISIS TLVs")
45 DEFINE_MTYPE_STATIC(ISISD
, ISIS_SUBTLV
, "ISIS Sub-TLVs")
46 DEFINE_MTYPE_STATIC(ISISD
, ISIS_MT_ITEM_LIST
, "ISIS MT Item Lists")
48 typedef int (*unpack_tlv_func
)(enum isis_tlv_context context
, uint8_t tlv_type
,
49 uint8_t tlv_len
, struct stream
*s
,
50 struct sbuf
*log
, void *dest
, int indent
);
51 typedef int (*pack_item_func
)(struct isis_item
*item
, struct stream
*s
);
52 typedef void (*free_item_func
)(struct isis_item
*i
);
53 typedef int (*unpack_item_func
)(uint16_t mtid
, uint8_t len
, struct stream
*s
,
54 struct sbuf
*log
, void *dest
, int indent
);
55 typedef void (*format_item_func
)(uint16_t mtid
, struct isis_item
*i
,
56 struct sbuf
*buf
, int indent
);
57 typedef struct isis_item
*(*copy_item_func
)(struct isis_item
*i
);
61 unpack_tlv_func unpack
;
63 pack_item_func pack_item
;
64 free_item_func free_item
;
65 unpack_item_func unpack_item
;
66 format_item_func format_item
;
67 copy_item_func copy_item
;
75 struct pack_order_entry
{
76 enum isis_tlv_context context
;
77 enum isis_tlv_type type
;
78 enum how_to_pack how_to_pack
;
81 #define PACK_ENTRY(t, h, w) \
83 .context = ISIS_CONTEXT_LSP, .type = ISIS_TLV_##t, \
85 .what_to_pack = offsetof(struct isis_tlvs, w), \
88 static struct pack_order_entry pack_order
[] = {
89 PACK_ENTRY(OLDSTYLE_REACH
, ISIS_ITEMS
, oldstyle_reach
),
90 PACK_ENTRY(LAN_NEIGHBORS
, ISIS_ITEMS
, lan_neighbor
),
91 PACK_ENTRY(LSP_ENTRY
, ISIS_ITEMS
, lsp_entries
),
92 PACK_ENTRY(EXTENDED_REACH
, ISIS_ITEMS
, extended_reach
),
93 PACK_ENTRY(MT_REACH
, ISIS_MT_ITEMS
, mt_reach
),
94 PACK_ENTRY(OLDSTYLE_IP_REACH
, ISIS_ITEMS
, oldstyle_ip_reach
),
95 PACK_ENTRY(OLDSTYLE_IP_REACH_EXT
, ISIS_ITEMS
, oldstyle_ip_reach_ext
),
96 PACK_ENTRY(IPV4_ADDRESS
, ISIS_ITEMS
, ipv4_address
),
97 PACK_ENTRY(IPV6_ADDRESS
, ISIS_ITEMS
, ipv6_address
),
98 PACK_ENTRY(EXTENDED_IP_REACH
, ISIS_ITEMS
, extended_ip_reach
),
99 PACK_ENTRY(MT_IP_REACH
, ISIS_MT_ITEMS
, mt_ip_reach
),
100 PACK_ENTRY(IPV6_REACH
, ISIS_ITEMS
, ipv6_reach
),
101 PACK_ENTRY(MT_IPV6_REACH
, ISIS_MT_ITEMS
, mt_ipv6_reach
)};
103 /* This is a forward definition. The table is actually initialized
104 * in at the bottom. */
105 static const struct tlv_ops
*tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
];
107 /* End of _ops forward definition. */
110 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
);
112 /* Functions for Sub-TLV 3 SR Prefix-SID */
114 static struct isis_item
*copy_item_prefix_sid(struct isis_item
*i
)
116 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
117 struct isis_prefix_sid
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
119 rv
->flags
= sid
->flags
;
120 rv
->algorithm
= sid
->algorithm
;
121 rv
->value
= sid
->value
;
122 return (struct isis_item
*)rv
;
125 static void format_item_prefix_sid(uint16_t mtid
, struct isis_item
*i
,
126 struct sbuf
*buf
, int indent
)
128 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
130 sbuf_push(buf
, indent
, "SR Prefix-SID:\n");
131 sbuf_push(buf
, indent
, " Flags:%s%s%s%s%s%s\n",
132 sid
->flags
& ISIS_PREFIX_SID_READVERTISED
? " READVERTISED" : "",
133 sid
->flags
& ISIS_PREFIX_SID_NODE
? " NODE" : "",
134 sid
->flags
& ISIS_PREFIX_SID_NO_PHP
? " NO_PHP" : "",
135 sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
? " EXPLICIT-NULL" : "",
136 sid
->flags
& ISIS_PREFIX_SID_VALUE
? " VALUE" : "",
137 sid
->flags
& ISIS_PREFIX_SID_LOCAL
? " LOCAL" : "");
138 sbuf_push(buf
, indent
, " Algorithm: %" PRIu8
"\n", sid
->algorithm
);
139 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
140 sbuf_push(buf
, indent
, "Label: %" PRIu32
"\n", sid
->value
);
142 sbuf_push(buf
, indent
, "Index: %" PRIu32
"\n", sid
->value
);
146 static void free_item_prefix_sid(struct isis_item
*i
)
148 XFREE(MTYPE_ISIS_SUBTLV
, i
);
151 static int pack_item_prefix_sid(struct isis_item
*i
, struct stream
*s
)
153 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
155 uint8_t size
= (sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? 5 : 6;
157 if (STREAM_WRITEABLE(s
) < size
)
160 stream_putc(s
, sid
->flags
);
161 stream_putc(s
, sid
->algorithm
);
163 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
164 stream_put3(s
, sid
->value
);
166 stream_putl(s
, sid
->value
);
172 static int unpack_item_prefix_sid(uint16_t mtid
, uint8_t len
, struct stream
*s
,
173 struct sbuf
*log
, void *dest
, int indent
)
175 struct isis_subtlvs
*subtlvs
= dest
;
176 struct isis_prefix_sid sid
= {
179 sbuf_push(log
, indent
, "Unpacking SR Prefix-SID...\n");
182 sbuf_push(log
, indent
,
183 "Not enough data left. (expected 5 or more bytes, got %" PRIu8
")\n",
188 sid
.flags
= stream_getc(s
);
189 if ((sid
.flags
& ISIS_PREFIX_SID_VALUE
)
190 != (sid
.flags
& ISIS_PREFIX_SID_LOCAL
)) {
191 sbuf_push(log
, indent
, "Flags inplausible: Local Flag needs to match Value Flag\n");
195 sid
.algorithm
= stream_getc(s
);
197 uint8_t expected_size
= (sid
.flags
& ISIS_PREFIX_SID_VALUE
) ? 5 : 6;
198 if (len
!= expected_size
) {
199 sbuf_push(log
, indent
,
200 "TLV size differs from expected size. "
201 "(expected %u but got %" PRIu8
")\n",
206 if (sid
.flags
& ISIS_PREFIX_SID_VALUE
) {
207 sid
.value
= stream_get3(s
);
209 sid
.value
= stream_getl(s
);
212 format_item_prefix_sid(mtid
, (struct isis_item
*)&sid
, log
, indent
+ 2);
213 append_item(&subtlvs
->prefix_sids
, copy_item_prefix_sid((struct isis_item
*)&sid
));
217 /* Functions for Sub-TVL ??? IPv6 Source Prefix */
219 static struct prefix_ipv6
*copy_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
)
224 struct prefix_ipv6
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
225 rv
->family
= p
->family
;
226 rv
->prefixlen
= p
->prefixlen
;
227 memcpy(&rv
->prefix
, &p
->prefix
, sizeof(rv
->prefix
));
231 static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
232 struct sbuf
*buf
, int indent
)
237 char prefixbuf
[PREFIX2STR_BUFFER
];
238 sbuf_push(buf
, indent
, "IPv6 Source Prefix: %s\n",
239 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
)));
242 static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
248 if (STREAM_WRITEABLE(s
) < 3 + (unsigned)PSIZE(p
->prefixlen
))
251 stream_putc(s
, ISIS_SUBTLV_IPV6_SOURCE_PREFIX
);
252 stream_putc(s
, 1 + PSIZE(p
->prefixlen
));
253 stream_putc(s
, p
->prefixlen
);
254 stream_put(s
, &p
->prefix
, PSIZE(p
->prefixlen
));
258 static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context
,
259 uint8_t tlv_type
, uint8_t tlv_len
,
260 struct stream
*s
, struct sbuf
*log
,
261 void *dest
, int indent
)
263 struct isis_subtlvs
*subtlvs
= dest
;
264 struct prefix_ipv6 p
= {
268 sbuf_push(log
, indent
, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
271 sbuf_push(log
, indent
,
272 "Not enough data left. (expected 1 or more bytes, got %" PRIu8
")\n",
277 p
.prefixlen
= stream_getc(s
);
278 if (p
.prefixlen
> 128) {
279 sbuf_push(log
, indent
, "Prefixlen %u is inplausible for IPv6\n",
284 if (tlv_len
!= 1 + PSIZE(p
.prefixlen
)) {
287 "TLV size differs from expected size for the prefixlen. "
288 "(expected %u but got %" PRIu8
")\n",
289 1 + PSIZE(p
.prefixlen
), tlv_len
);
293 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
295 if (subtlvs
->source_prefix
) {
298 "WARNING: source prefix Sub-TLV present multiple times.\n");
299 /* Ignore all but first occurrence of the source prefix Sub-TLV
304 subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(p
));
305 memcpy(subtlvs
->source_prefix
, &p
, sizeof(p
));
308 static void init_item_list(struct isis_item_list
*items
);
309 static struct isis_item
*copy_item(enum isis_tlv_context context
,
310 enum isis_tlv_type type
,
311 struct isis_item
*item
);
312 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
313 struct isis_item_list
*src
, struct isis_item_list
*dest
);
314 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
315 enum isis_tlv_type type
, struct isis_item_list
*items
,
316 struct sbuf
*buf
, int indent
);
317 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
318 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
319 struct isis_item_list
*items
);
320 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
321 enum isis_tlv_type type
, struct isis_item_list
*items
,
322 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
323 struct pack_order_entry
*pe
,
324 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
325 struct list
*new_fragment_arg
);
326 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
328 /* Functions related to subtlvs */
330 static struct isis_subtlvs
*isis_alloc_subtlvs(enum isis_tlv_context context
)
332 struct isis_subtlvs
*result
;
334 result
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*result
));
335 result
->context
= context
;
337 init_item_list(&result
->prefix_sids
);
342 static struct isis_subtlvs
*copy_subtlvs(struct isis_subtlvs
*subtlvs
)
347 struct isis_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
349 rv
->context
= subtlvs
->context
;
351 copy_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
352 &subtlvs
->prefix_sids
, &rv
->prefix_sids
);
355 copy_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
);
359 static void format_subtlvs(struct isis_subtlvs
*subtlvs
, struct sbuf
*buf
,
362 format_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
363 &subtlvs
->prefix_sids
, buf
, indent
);
365 format_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, buf
, indent
);
368 static void isis_free_subtlvs(struct isis_subtlvs
*subtlvs
)
373 free_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
374 &subtlvs
->prefix_sids
);
376 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
->source_prefix
);
378 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
);
381 static int pack_subtlvs(struct isis_subtlvs
*subtlvs
, struct stream
*s
)
384 size_t subtlv_len_pos
= stream_get_endp(s
);
386 if (STREAM_WRITEABLE(s
) < 1)
389 stream_putc(s
, 0); /* Put 0 as subtlvs length, filled in later */
391 rv
= pack_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
392 &subtlvs
->prefix_sids
, s
, NULL
, NULL
, NULL
, NULL
);
396 rv
= pack_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, s
);
400 size_t subtlv_len
= stream_get_endp(s
) - subtlv_len_pos
- 1;
401 if (subtlv_len
> 255)
404 stream_putc_at(s
, subtlv_len_pos
, subtlv_len
);
408 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
409 struct stream
*stream
, struct sbuf
*log
, void *dest
,
410 int indent
, bool *unpacked_known_tlvs
);
412 /* Functions related to TLVs 1 Area Addresses */
414 static struct isis_item
*copy_item_area_address(struct isis_item
*i
)
416 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
417 struct isis_area_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
420 memcpy(rv
->addr
, addr
->addr
, addr
->len
);
421 return (struct isis_item
*)rv
;
424 static void format_item_area_address(uint16_t mtid
, struct isis_item
*i
,
425 struct sbuf
*buf
, int indent
)
427 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
429 sbuf_push(buf
, indent
, "Area Address: %s\n",
430 isonet_print(addr
->addr
, addr
->len
));
433 static void free_item_area_address(struct isis_item
*i
)
435 XFREE(MTYPE_ISIS_TLV
, i
);
438 static int pack_item_area_address(struct isis_item
*i
, struct stream
*s
)
440 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
442 if (STREAM_WRITEABLE(s
) < (unsigned)1 + addr
->len
)
444 stream_putc(s
, addr
->len
);
445 stream_put(s
, addr
->addr
, addr
->len
);
449 static int unpack_item_area_address(uint16_t mtid
, uint8_t len
,
450 struct stream
*s
, struct sbuf
*log
,
451 void *dest
, int indent
)
453 struct isis_tlvs
*tlvs
= dest
;
454 struct isis_area_address
*rv
= NULL
;
456 sbuf_push(log
, indent
, "Unpack area address...\n");
460 "Not enough data left. (Expected 1 byte of address length, got %" PRIu8
466 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
467 rv
->len
= stream_getc(s
);
469 if (len
< 1 + rv
->len
) {
470 sbuf_push(log
, indent
, "Not enough data left. (Expected %" PRIu8
471 " bytes of address, got %" PRIu8
")\n",
476 if (rv
->len
< 1 || rv
->len
> 20) {
477 sbuf_push(log
, indent
,
478 "Implausible area address length %" PRIu8
"\n",
483 stream_get(rv
->addr
, s
, rv
->len
);
485 format_item_area_address(ISIS_MT_IPV4_UNICAST
, (struct isis_item
*)rv
,
487 append_item(&tlvs
->area_addresses
, (struct isis_item
*)rv
);
490 XFREE(MTYPE_ISIS_TLV
, rv
);
494 /* Functions related to TLV 2 (Old-Style) IS Reach */
495 static struct isis_item
*copy_item_oldstyle_reach(struct isis_item
*i
)
497 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
498 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
500 memcpy(rv
->id
, r
->id
, 7);
501 rv
->metric
= r
->metric
;
502 return (struct isis_item
*)rv
;
505 static void format_item_oldstyle_reach(uint16_t mtid
, struct isis_item
*i
,
506 struct sbuf
*buf
, int indent
)
508 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
510 sbuf_push(buf
, indent
, "IS Reachability: %s (Metric: %" PRIu8
")\n",
511 isis_format_id(r
->id
, 7), r
->metric
);
514 static void free_item_oldstyle_reach(struct isis_item
*i
)
516 XFREE(MTYPE_ISIS_TLV
, i
);
519 static int pack_item_oldstyle_reach(struct isis_item
*i
, struct stream
*s
)
521 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
523 if (STREAM_WRITEABLE(s
) < 11)
526 stream_putc(s
, r
->metric
);
527 stream_putc(s
, 0x80); /* delay metric - unsupported */
528 stream_putc(s
, 0x80); /* expense metric - unsupported */
529 stream_putc(s
, 0x80); /* error metric - unsupported */
530 stream_put(s
, r
->id
, 7);
535 static int unpack_item_oldstyle_reach(uint16_t mtid
, uint8_t len
,
536 struct stream
*s
, struct sbuf
*log
,
537 void *dest
, int indent
)
539 struct isis_tlvs
*tlvs
= dest
;
541 sbuf_push(log
, indent
, "Unpack oldstyle reach...\n");
545 "Not enough data left.(Expected 11 bytes of reach information, got %" PRIu8
551 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
552 rv
->metric
= stream_getc(s
);
553 if ((rv
->metric
& 0x3f) != rv
->metric
) {
554 sbuf_push(log
, indent
, "Metric has unplausible format\n");
557 stream_forward_getp(s
, 3); /* Skip other metrics */
558 stream_get(rv
->id
, s
, 7);
560 format_item_oldstyle_reach(mtid
, (struct isis_item
*)rv
, log
,
562 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)rv
);
566 /* Functions related to TLV 6 LAN Neighbors */
567 static struct isis_item
*copy_item_lan_neighbor(struct isis_item
*i
)
569 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
570 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
572 memcpy(rv
->mac
, n
->mac
, 6);
573 return (struct isis_item
*)rv
;
576 static void format_item_lan_neighbor(uint16_t mtid
, struct isis_item
*i
,
577 struct sbuf
*buf
, int indent
)
579 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
581 sbuf_push(buf
, indent
, "LAN Neighbor: %s\n", isis_format_id(n
->mac
, 6));
584 static void free_item_lan_neighbor(struct isis_item
*i
)
586 XFREE(MTYPE_ISIS_TLV
, i
);
589 static int pack_item_lan_neighbor(struct isis_item
*i
, struct stream
*s
)
591 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
593 if (STREAM_WRITEABLE(s
) < 6)
596 stream_put(s
, n
->mac
, 6);
601 static int unpack_item_lan_neighbor(uint16_t mtid
, uint8_t len
,
602 struct stream
*s
, struct sbuf
*log
,
603 void *dest
, int indent
)
605 struct isis_tlvs
*tlvs
= dest
;
607 sbuf_push(log
, indent
, "Unpack LAN neighbor...\n");
611 "Not enough data left.(Expected 6 bytes of mac, got %" PRIu8
617 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
618 stream_get(rv
->mac
, s
, 6);
620 format_item_lan_neighbor(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
621 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)rv
);
625 /* Functions related to TLV 9 LSP Entry */
626 static struct isis_item
*copy_item_lsp_entry(struct isis_item
*i
)
628 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
629 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
631 rv
->rem_lifetime
= e
->rem_lifetime
;
632 memcpy(rv
->id
, e
->id
, sizeof(rv
->id
));
633 rv
->seqno
= e
->seqno
;
634 rv
->checksum
= e
->checksum
;
636 return (struct isis_item
*)rv
;
639 static void format_item_lsp_entry(uint16_t mtid
, struct isis_item
*i
,
640 struct sbuf
*buf
, int indent
)
642 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
644 sbuf_push(buf
, indent
,
645 "LSP Entry: %s, seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
646 ", lifetime %" PRIu16
"s\n",
647 isis_format_id(e
->id
, 8), e
->seqno
, e
->checksum
,
651 static void free_item_lsp_entry(struct isis_item
*i
)
653 XFREE(MTYPE_ISIS_TLV
, i
);
656 static int pack_item_lsp_entry(struct isis_item
*i
, struct stream
*s
)
658 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
660 if (STREAM_WRITEABLE(s
) < 16)
663 stream_putw(s
, e
->rem_lifetime
);
664 stream_put(s
, e
->id
, 8);
665 stream_putl(s
, e
->seqno
);
666 stream_putw(s
, e
->checksum
);
671 static int unpack_item_lsp_entry(uint16_t mtid
, uint8_t len
, struct stream
*s
,
672 struct sbuf
*log
, void *dest
, int indent
)
674 struct isis_tlvs
*tlvs
= dest
;
676 sbuf_push(log
, indent
, "Unpack LSP entry...\n");
680 "Not enough data left. (Expected 16 bytes of LSP info, got %" PRIu8
,
685 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
686 rv
->rem_lifetime
= stream_getw(s
);
687 stream_get(rv
->id
, s
, 8);
688 rv
->seqno
= stream_getl(s
);
689 rv
->checksum
= stream_getw(s
);
691 format_item_lsp_entry(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
692 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)rv
);
696 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
698 static struct isis_item
*copy_item_extended_reach(struct isis_item
*i
)
700 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
701 struct isis_extended_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
703 memcpy(rv
->id
, r
->id
, 7);
704 rv
->metric
= r
->metric
;
706 if (r
->subtlvs
&& r
->subtlv_len
) {
707 rv
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, r
->subtlv_len
);
708 memcpy(rv
->subtlvs
, r
->subtlvs
, r
->subtlv_len
);
709 rv
->subtlv_len
= r
->subtlv_len
;
712 return (struct isis_item
*)rv
;
715 static void format_item_extended_reach(uint16_t mtid
, struct isis_item
*i
,
716 struct sbuf
*buf
, int indent
)
718 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
720 sbuf_push(buf
, indent
, "%s Reachability: %s (Metric: %u)",
721 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
722 isis_format_id(r
->id
, 7), r
->metric
);
723 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
724 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
725 sbuf_push(buf
, 0, "\n");
727 if (r
->subtlv_len
&& r
->subtlvs
)
728 mpls_te_print_detail(buf
, indent
+ 2, r
->subtlvs
,
732 static void free_item_extended_reach(struct isis_item
*i
)
734 struct isis_extended_reach
*item
= (struct isis_extended_reach
*)i
;
735 XFREE(MTYPE_ISIS_TLV
, item
->subtlvs
);
736 XFREE(MTYPE_ISIS_TLV
, item
);
739 static int pack_item_extended_reach(struct isis_item
*i
, struct stream
*s
)
741 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
743 if (STREAM_WRITEABLE(s
) < 11 + (unsigned)r
->subtlv_len
)
745 stream_put(s
, r
->id
, sizeof(r
->id
));
746 stream_put3(s
, r
->metric
);
747 stream_putc(s
, r
->subtlv_len
);
748 stream_put(s
, r
->subtlvs
, r
->subtlv_len
);
752 static int unpack_item_extended_reach(uint16_t mtid
, uint8_t len
,
753 struct stream
*s
, struct sbuf
*log
,
754 void *dest
, int indent
)
756 struct isis_tlvs
*tlvs
= dest
;
757 struct isis_extended_reach
*rv
= NULL
;
759 struct isis_item_list
*items
;
761 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
762 items
= &tlvs
->extended_reach
;
764 items
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
767 sbuf_push(log
, indent
, "Unpacking %s reachability...\n",
768 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
771 sbuf_push(log
, indent
,
772 "Not enough data left. (expected 11 or more bytes, got %"
778 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
779 stream_get(rv
->id
, s
, 7);
780 rv
->metric
= stream_get3(s
);
781 subtlv_len
= stream_getc(s
);
783 format_item_extended_reach(mtid
, (struct isis_item
*)rv
, log
,
786 if ((size_t)len
< ((size_t)11) + subtlv_len
) {
787 sbuf_push(log
, indent
,
788 "Not enough data left for subtlv size %" PRIu8
789 ", there are only %" PRIu8
" bytes left.\n",
790 subtlv_len
, len
- 11);
794 sbuf_push(log
, indent
, "Storing %" PRIu8
" bytes of subtlvs\n",
798 size_t subtlv_start
= stream_get_getp(s
);
800 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_NE_REACH
, subtlv_len
, s
,
801 log
, NULL
, indent
+ 4, NULL
)) {
805 stream_set_getp(s
, subtlv_start
);
807 rv
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, subtlv_len
);
808 stream_get(rv
->subtlvs
, s
, subtlv_len
);
809 rv
->subtlv_len
= subtlv_len
;
812 append_item(items
, (struct isis_item
*)rv
);
816 free_item_extended_reach((struct isis_item
*)rv
);
821 /* Functions related to TLV 128 (Old-Style) IP Reach */
822 static struct isis_item
*copy_item_oldstyle_ip_reach(struct isis_item
*i
)
824 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
825 struct isis_oldstyle_ip_reach
*rv
=
826 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
828 rv
->metric
= r
->metric
;
829 rv
->prefix
= r
->prefix
;
830 return (struct isis_item
*)rv
;
833 static void format_item_oldstyle_ip_reach(uint16_t mtid
, struct isis_item
*i
,
834 struct sbuf
*buf
, int indent
)
836 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
837 char prefixbuf
[PREFIX2STR_BUFFER
];
839 sbuf_push(buf
, indent
, "IP Reachability: %s (Metric: %" PRIu8
")\n",
840 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
844 static void free_item_oldstyle_ip_reach(struct isis_item
*i
)
846 XFREE(MTYPE_ISIS_TLV
, i
);
849 static int pack_item_oldstyle_ip_reach(struct isis_item
*i
, struct stream
*s
)
851 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
853 if (STREAM_WRITEABLE(s
) < 12)
856 stream_putc(s
, r
->metric
);
857 stream_putc(s
, 0x80); /* delay metric - unsupported */
858 stream_putc(s
, 0x80); /* expense metric - unsupported */
859 stream_putc(s
, 0x80); /* error metric - unsupported */
860 stream_put(s
, &r
->prefix
.prefix
, 4);
863 masklen2ip(r
->prefix
.prefixlen
, &mask
);
864 stream_put(s
, &mask
, sizeof(mask
));
869 static int unpack_item_oldstyle_ip_reach(uint16_t mtid
, uint8_t len
,
870 struct stream
*s
, struct sbuf
*log
,
871 void *dest
, int indent
)
873 sbuf_push(log
, indent
, "Unpack oldstyle ip reach...\n");
877 "Not enough data left.(Expected 12 bytes of reach information, got %" PRIu8
883 struct isis_oldstyle_ip_reach
*rv
=
884 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
885 rv
->metric
= stream_getc(s
);
886 if ((rv
->metric
& 0x7f) != rv
->metric
) {
887 sbuf_push(log
, indent
, "Metric has unplausible format\n");
890 stream_forward_getp(s
, 3); /* Skip other metrics */
891 rv
->prefix
.family
= AF_INET
;
892 stream_get(&rv
->prefix
.prefix
, s
, 4);
895 stream_get(&mask
, s
, 4);
896 rv
->prefix
.prefixlen
= ip_masklen(mask
);
898 format_item_oldstyle_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
900 append_item(dest
, (struct isis_item
*)rv
);
905 /* Functions related to TLV 129 protocols supported */
907 static void copy_tlv_protocols_supported(struct isis_protocols_supported
*src
,
908 struct isis_protocols_supported
*dest
)
910 if (!src
->protocols
|| !src
->count
)
912 dest
->count
= src
->count
;
913 dest
->protocols
= XCALLOC(MTYPE_ISIS_TLV
, src
->count
);
914 memcpy(dest
->protocols
, src
->protocols
, src
->count
);
917 static void format_tlv_protocols_supported(struct isis_protocols_supported
*p
,
918 struct sbuf
*buf
, int indent
)
920 if (!p
|| !p
->count
|| !p
->protocols
)
923 sbuf_push(buf
, indent
, "Protocols Supported: ");
924 for (uint8_t i
= 0; i
< p
->count
; i
++) {
925 sbuf_push(buf
, 0, "%s%s", nlpid2str(p
->protocols
[i
]),
926 (i
+ 1 < p
->count
) ? ", " : "");
928 sbuf_push(buf
, 0, "\n");
931 static void free_tlv_protocols_supported(struct isis_protocols_supported
*p
)
933 XFREE(MTYPE_ISIS_TLV
, p
->protocols
);
936 static int pack_tlv_protocols_supported(struct isis_protocols_supported
*p
,
939 if (!p
|| !p
->count
|| !p
->protocols
)
942 if (STREAM_WRITEABLE(s
) < (unsigned)(p
->count
+ 2))
945 stream_putc(s
, ISIS_TLV_PROTOCOLS_SUPPORTED
);
946 stream_putc(s
, p
->count
);
947 stream_put(s
, p
->protocols
, p
->count
);
951 static int unpack_tlv_protocols_supported(enum isis_tlv_context context
,
952 uint8_t tlv_type
, uint8_t tlv_len
,
953 struct stream
*s
, struct sbuf
*log
,
954 void *dest
, int indent
)
956 struct isis_tlvs
*tlvs
= dest
;
958 sbuf_push(log
, indent
, "Unpacking Protocols Supported TLV...\n");
960 sbuf_push(log
, indent
, "WARNING: No protocols included\n");
963 if (tlvs
->protocols_supported
.protocols
) {
966 "WARNING: protocols supported TLV present multiple times.\n");
967 stream_forward_getp(s
, tlv_len
);
971 tlvs
->protocols_supported
.count
= tlv_len
;
972 tlvs
->protocols_supported
.protocols
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
);
973 stream_get(tlvs
->protocols_supported
.protocols
, s
, tlv_len
);
975 format_tlv_protocols_supported(&tlvs
->protocols_supported
, log
,
980 /* Functions related to TLV 132 IPv4 Interface addresses */
981 static struct isis_item
*copy_item_ipv4_address(struct isis_item
*i
)
983 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
984 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
987 return (struct isis_item
*)rv
;
990 static void format_item_ipv4_address(uint16_t mtid
, struct isis_item
*i
,
991 struct sbuf
*buf
, int indent
)
993 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
994 char addrbuf
[INET_ADDRSTRLEN
];
996 inet_ntop(AF_INET
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
997 sbuf_push(buf
, indent
, "IPv4 Interface Address: %s\n", addrbuf
);
1000 static void free_item_ipv4_address(struct isis_item
*i
)
1002 XFREE(MTYPE_ISIS_TLV
, i
);
1005 static int pack_item_ipv4_address(struct isis_item
*i
, struct stream
*s
)
1007 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
1009 if (STREAM_WRITEABLE(s
) < 4)
1012 stream_put(s
, &a
->addr
, 4);
1017 static int unpack_item_ipv4_address(uint16_t mtid
, uint8_t len
,
1018 struct stream
*s
, struct sbuf
*log
,
1019 void *dest
, int indent
)
1021 struct isis_tlvs
*tlvs
= dest
;
1023 sbuf_push(log
, indent
, "Unpack IPv4 Interface address...\n");
1027 "Not enough data left.(Expected 4 bytes of IPv4 address, got %" PRIu8
1033 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1034 stream_get(&rv
->addr
, s
, 4);
1036 format_item_ipv4_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1037 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)rv
);
1042 /* Functions related to TLV 232 IPv6 Interface addresses */
1043 static struct isis_item
*copy_item_ipv6_address(struct isis_item
*i
)
1045 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1046 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1049 return (struct isis_item
*)rv
;
1052 static void format_item_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
1053 struct sbuf
*buf
, int indent
)
1055 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1056 char addrbuf
[INET6_ADDRSTRLEN
];
1058 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
1059 sbuf_push(buf
, indent
, "IPv6 Interface Address: %s\n", addrbuf
);
1062 static void free_item_ipv6_address(struct isis_item
*i
)
1064 XFREE(MTYPE_ISIS_TLV
, i
);
1067 static int pack_item_ipv6_address(struct isis_item
*i
, struct stream
*s
)
1069 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1071 if (STREAM_WRITEABLE(s
) < 16)
1074 stream_put(s
, &a
->addr
, 16);
1079 static int unpack_item_ipv6_address(uint16_t mtid
, uint8_t len
,
1080 struct stream
*s
, struct sbuf
*log
,
1081 void *dest
, int indent
)
1083 struct isis_tlvs
*tlvs
= dest
;
1085 sbuf_push(log
, indent
, "Unpack IPv6 Interface address...\n");
1089 "Not enough data left.(Expected 16 bytes of IPv6 address, got %" PRIu8
1095 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1096 stream_get(&rv
->addr
, s
, 16);
1098 format_item_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1099 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)rv
);
1104 /* Functions related to TLV 229 MT Router information */
1105 static struct isis_item
*copy_item_mt_router_info(struct isis_item
*i
)
1107 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1108 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1110 rv
->overload
= info
->overload
;
1111 rv
->attached
= info
->attached
;
1112 rv
->mtid
= info
->mtid
;
1113 return (struct isis_item
*)rv
;
1116 static void format_item_mt_router_info(uint16_t mtid
, struct isis_item
*i
,
1117 struct sbuf
*buf
, int indent
)
1119 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1121 sbuf_push(buf
, indent
, "MT Router Info: %s%s%s\n",
1122 isis_mtid2str(info
->mtid
),
1123 info
->overload
? " Overload" : "",
1124 info
->attached
? " Attached" : "");
1127 static void free_item_mt_router_info(struct isis_item
*i
)
1129 XFREE(MTYPE_ISIS_TLV
, i
);
1132 static int pack_item_mt_router_info(struct isis_item
*i
, struct stream
*s
)
1134 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1136 if (STREAM_WRITEABLE(s
) < 2)
1139 uint16_t entry
= info
->mtid
;
1142 entry
|= ISIS_MT_OL_MASK
;
1144 entry
|= ISIS_MT_AT_MASK
;
1146 stream_putw(s
, entry
);
1151 static int unpack_item_mt_router_info(uint16_t mtid
, uint8_t len
,
1152 struct stream
*s
, struct sbuf
*log
,
1153 void *dest
, int indent
)
1155 struct isis_tlvs
*tlvs
= dest
;
1157 sbuf_push(log
, indent
, "Unpack MT Router info...\n");
1161 "Not enough data left.(Expected 2 bytes of MT info, got %" PRIu8
1167 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1169 uint16_t entry
= stream_getw(s
);
1170 rv
->overload
= entry
& ISIS_MT_OL_MASK
;
1171 rv
->attached
= entry
& ISIS_MT_AT_MASK
;
1172 rv
->mtid
= entry
& ISIS_MT_MASK
;
1174 format_item_mt_router_info(mtid
, (struct isis_item
*)rv
, log
,
1176 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)rv
);
1180 /* Functions related to TLV 134 TE Router ID */
1182 static struct in_addr
*copy_tlv_te_router_id(const struct in_addr
*id
)
1187 struct in_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1188 memcpy(rv
, id
, sizeof(*rv
));
1192 static void format_tlv_te_router_id(const struct in_addr
*id
, struct sbuf
*buf
,
1198 char addrbuf
[INET_ADDRSTRLEN
];
1199 inet_ntop(AF_INET
, id
, addrbuf
, sizeof(addrbuf
));
1200 sbuf_push(buf
, indent
, "TE Router ID: %s\n", addrbuf
);
1203 static void free_tlv_te_router_id(struct in_addr
*id
)
1205 XFREE(MTYPE_ISIS_TLV
, id
);
1208 static int pack_tlv_te_router_id(const struct in_addr
*id
, struct stream
*s
)
1213 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
1216 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID
);
1218 stream_put(s
, id
, 4);
1222 static int unpack_tlv_te_router_id(enum isis_tlv_context context
,
1223 uint8_t tlv_type
, uint8_t tlv_len
,
1224 struct stream
*s
, struct sbuf
*log
,
1225 void *dest
, int indent
)
1227 struct isis_tlvs
*tlvs
= dest
;
1229 sbuf_push(log
, indent
, "Unpacking TE Router ID TLV...\n");
1231 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
1235 if (tlvs
->te_router_id
) {
1236 sbuf_push(log
, indent
,
1237 "WARNING: TE Router ID present multiple times.\n");
1238 stream_forward_getp(s
, tlv_len
);
1242 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, 4);
1243 stream_get(tlvs
->te_router_id
, s
, 4);
1244 format_tlv_te_router_id(tlvs
->te_router_id
, log
, indent
+ 2);
1249 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
1251 static struct isis_item
*copy_item_extended_ip_reach(struct isis_item
*i
)
1253 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1254 struct isis_extended_ip_reach
*rv
=
1255 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1257 rv
->metric
= r
->metric
;
1259 rv
->prefix
= r
->prefix
;
1261 return (struct isis_item
*)rv
;
1264 static void format_item_extended_ip_reach(uint16_t mtid
, struct isis_item
*i
,
1265 struct sbuf
*buf
, int indent
)
1267 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1268 char prefixbuf
[PREFIX2STR_BUFFER
];
1270 sbuf_push(buf
, indent
, "%s IP Reachability: %s (Metric: %u)%s",
1271 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
1272 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)), r
->metric
,
1273 r
->down
? " Down" : "");
1274 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1275 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1276 sbuf_push(buf
, 0, "\n");
1279 sbuf_push(buf
, indent
, " Subtlvs:\n");
1280 format_subtlvs(r
->subtlvs
, buf
, indent
+ 4);
1284 static void free_item_extended_ip_reach(struct isis_item
*i
)
1286 struct isis_extended_ip_reach
*item
=
1287 (struct isis_extended_ip_reach
*)i
;
1288 isis_free_subtlvs(item
->subtlvs
);
1289 XFREE(MTYPE_ISIS_TLV
, item
);
1292 static int pack_item_extended_ip_reach(struct isis_item
*i
, struct stream
*s
)
1294 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1297 if (STREAM_WRITEABLE(s
) < 5)
1299 stream_putl(s
, r
->metric
);
1301 control
= r
->down
? ISIS_EXTENDED_IP_REACH_DOWN
: 0;
1302 control
|= r
->prefix
.prefixlen
;
1303 control
|= r
->subtlvs
? ISIS_EXTENDED_IP_REACH_SUBTLV
: 0;
1305 stream_putc(s
, control
);
1307 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
))
1309 stream_put(s
, &r
->prefix
.prefix
.s_addr
, PSIZE(r
->prefix
.prefixlen
));
1312 return pack_subtlvs(r
->subtlvs
, s
);
1316 static int unpack_item_extended_ip_reach(uint16_t mtid
, uint8_t len
,
1317 struct stream
*s
, struct sbuf
*log
,
1318 void *dest
, int indent
)
1320 struct isis_tlvs
*tlvs
= dest
;
1321 struct isis_extended_ip_reach
*rv
= NULL
;
1323 uint8_t control
, subtlv_len
;
1324 struct isis_item_list
*items
;
1326 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1327 items
= &tlvs
->extended_ip_reach
;
1329 items
= isis_get_mt_items(&tlvs
->mt_ip_reach
, mtid
);
1332 sbuf_push(log
, indent
, "Unpacking %s IPv4 reachability...\n",
1333 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
1336 if (len
< consume
) {
1337 sbuf_push(log
, indent
,
1338 "Not enough data left. (expected 5 or more bytes, got %" PRIu8
")\n",
1343 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1345 rv
->metric
= stream_getl(s
);
1346 control
= stream_getc(s
);
1347 rv
->down
= (control
& ISIS_EXTENDED_IP_REACH_DOWN
);
1348 rv
->prefix
.family
= AF_INET
;
1349 rv
->prefix
.prefixlen
= control
& 0x3f;
1350 if (rv
->prefix
.prefixlen
> 32) {
1351 sbuf_push(log
, indent
, "Prefixlen %u is inplausible for IPv4\n",
1352 rv
->prefix
.prefixlen
);
1356 consume
+= PSIZE(rv
->prefix
.prefixlen
);
1357 if (len
< consume
) {
1358 sbuf_push(log
, indent
,
1359 "Expected %u bytes of prefix, but only %u bytes available.\n",
1360 PSIZE(rv
->prefix
.prefixlen
), len
- 5);
1363 stream_get(&rv
->prefix
.prefix
.s_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
1364 in_addr_t orig_prefix
= rv
->prefix
.prefix
.s_addr
;
1365 apply_mask_ipv4(&rv
->prefix
);
1366 if (orig_prefix
!= rv
->prefix
.prefix
.s_addr
)
1367 sbuf_push(log
, indent
+ 2,
1368 "WARNING: Prefix had hostbits set.\n");
1369 format_item_extended_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
1372 if (control
& ISIS_EXTENDED_IP_REACH_SUBTLV
) {
1374 if (len
< consume
) {
1375 sbuf_push(log
, indent
,
1376 "Expected 1 byte of subtlv len, but no more data present.\n");
1379 subtlv_len
= stream_getc(s
);
1382 sbuf_push(log
, indent
+ 2,
1383 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
1385 consume
+= subtlv_len
;
1386 if (len
< consume
) {
1387 sbuf_push(log
, indent
,
1389 " bytes of subtlvs, but only %u bytes available.\n",
1391 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
1395 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
1396 bool unpacked_known_tlvs
= false;
1398 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
, subtlv_len
, s
,
1399 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
1402 if (!unpacked_known_tlvs
) {
1403 isis_free_subtlvs(rv
->subtlvs
);
1408 append_item(items
, (struct isis_item
*)rv
);
1412 free_item_extended_ip_reach((struct isis_item
*)rv
);
1416 /* Functions related to TLV 137 Dynamic Hostname */
1418 static char *copy_tlv_dynamic_hostname(const char *hostname
)
1423 return XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
1426 static void format_tlv_dynamic_hostname(const char *hostname
, struct sbuf
*buf
,
1432 sbuf_push(buf
, indent
, "Hostname: %s\n", hostname
);
1435 static void free_tlv_dynamic_hostname(char *hostname
)
1437 XFREE(MTYPE_ISIS_TLV
, hostname
);
1440 static int pack_tlv_dynamic_hostname(const char *hostname
, struct stream
*s
)
1445 uint8_t name_len
= strlen(hostname
);
1447 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + name_len
))
1450 stream_putc(s
, ISIS_TLV_DYNAMIC_HOSTNAME
);
1451 stream_putc(s
, name_len
);
1452 stream_put(s
, hostname
, name_len
);
1456 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context
,
1457 uint8_t tlv_type
, uint8_t tlv_len
,
1458 struct stream
*s
, struct sbuf
*log
,
1459 void *dest
, int indent
)
1461 struct isis_tlvs
*tlvs
= dest
;
1463 sbuf_push(log
, indent
, "Unpacking Dynamic Hostname TLV...\n");
1465 sbuf_push(log
, indent
, "WARNING: No hostname included\n");
1469 if (tlvs
->hostname
) {
1470 sbuf_push(log
, indent
,
1471 "WARNING: Hostname present multiple times.\n");
1472 stream_forward_getp(s
, tlv_len
);
1476 tlvs
->hostname
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
+ 1);
1477 stream_get(tlvs
->hostname
, s
, tlv_len
);
1478 tlvs
->hostname
[tlv_len
] = '\0';
1481 for (uint8_t i
= 0; i
< tlv_len
; i
++) {
1482 if ((unsigned char)tlvs
->hostname
[i
] > 127
1483 || !isprint((unsigned char)tlvs
->hostname
[i
])) {
1485 tlvs
->hostname
[i
] = '?';
1491 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
1497 /* Functions related to TLV 150 Spine-Leaf-Extension */
1499 static struct isis_spine_leaf
*copy_tlv_spine_leaf(
1500 const struct isis_spine_leaf
*spine_leaf
)
1505 struct isis_spine_leaf
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1506 memcpy(rv
, spine_leaf
, sizeof(*rv
));
1511 static void format_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
1512 struct sbuf
*buf
, int indent
)
1517 sbuf_push(buf
, indent
, "Spine-Leaf-Extension:\n");
1518 if (spine_leaf
->has_tier
) {
1519 if (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
) {
1520 sbuf_push(buf
, indent
, " Tier: undefined\n");
1522 sbuf_push(buf
, indent
, " Tier: %" PRIu8
"\n",
1527 sbuf_push(buf
, indent
, " Flags:%s%s%s\n",
1528 spine_leaf
->is_leaf
? " LEAF" : "",
1529 spine_leaf
->is_spine
? " SPINE" : "",
1530 spine_leaf
->is_backup
? " BACKUP" : "");
1534 static void free_tlv_spine_leaf(struct isis_spine_leaf
*spine_leaf
)
1536 XFREE(MTYPE_ISIS_TLV
, spine_leaf
);
1539 #define ISIS_SPINE_LEAF_FLAG_TIER 0x08
1540 #define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
1541 #define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
1542 #define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
1544 static int pack_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
1550 uint8_t tlv_len
= 2;
1552 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
1555 stream_putc(s
, ISIS_TLV_SPINE_LEAF_EXT
);
1556 stream_putc(s
, tlv_len
);
1558 uint16_t spine_leaf_flags
= 0;
1560 if (spine_leaf
->has_tier
) {
1561 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_TIER
;
1562 spine_leaf_flags
|= spine_leaf
->tier
<< 12;
1565 if (spine_leaf
->is_leaf
)
1566 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_LEAF
;
1568 if (spine_leaf
->is_spine
)
1569 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_SPINE
;
1571 if (spine_leaf
->is_backup
)
1572 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_BACKUP
;
1574 stream_putw(s
, spine_leaf_flags
);
1579 static int unpack_tlv_spine_leaf(enum isis_tlv_context context
,
1580 uint8_t tlv_type
, uint8_t tlv_len
,
1581 struct stream
*s
, struct sbuf
*log
,
1582 void *dest
, int indent
)
1584 struct isis_tlvs
*tlvs
= dest
;
1586 sbuf_push(log
, indent
, "Unpacking Spine Leaf Extension TLV...\n");
1588 sbuf_push(log
, indent
, "WARNING: Unexepected TLV size\n");
1589 stream_forward_getp(s
, tlv_len
);
1593 if (tlvs
->spine_leaf
) {
1594 sbuf_push(log
, indent
,
1595 "WARNING: Spine Leaf Extension TLV present multiple times.\n");
1596 stream_forward_getp(s
, tlv_len
);
1600 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
1602 uint16_t spine_leaf_flags
= stream_getw(s
);
1604 if (spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_TIER
) {
1605 tlvs
->spine_leaf
->has_tier
= true;
1606 tlvs
->spine_leaf
->tier
= spine_leaf_flags
>> 12;
1609 tlvs
->spine_leaf
->is_leaf
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_LEAF
;
1610 tlvs
->spine_leaf
->is_spine
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_SPINE
;
1611 tlvs
->spine_leaf
->is_backup
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_BACKUP
;
1613 stream_forward_getp(s
, tlv_len
- 2);
1617 /* Functions related to TLV 240 P2P Three-Way Adjacency */
1619 const char *isis_threeway_state_name(enum isis_threeway_state state
)
1622 case ISIS_THREEWAY_DOWN
:
1624 case ISIS_THREEWAY_INITIALIZING
:
1625 return "Initializing";
1626 case ISIS_THREEWAY_UP
:
1633 static struct isis_threeway_adj
*copy_tlv_threeway_adj(
1634 const struct isis_threeway_adj
*threeway_adj
)
1639 struct isis_threeway_adj
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1640 memcpy(rv
, threeway_adj
, sizeof(*rv
));
1645 static void format_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
1646 struct sbuf
*buf
, int indent
)
1651 sbuf_push(buf
, indent
, "P2P Three-Way Adjacency:\n");
1652 sbuf_push(buf
, indent
, " State: %s (%d)\n",
1653 isis_threeway_state_name(threeway_adj
->state
),
1654 threeway_adj
->state
);
1655 sbuf_push(buf
, indent
, " Extended Local Circuit ID: %" PRIu32
"\n",
1656 threeway_adj
->local_circuit_id
);
1657 if (!threeway_adj
->neighbor_set
)
1660 sbuf_push(buf
, indent
, " Neighbor System ID: %s\n",
1661 isis_format_id(threeway_adj
->neighbor_id
, 6));
1662 sbuf_push(buf
, indent
, " Neighbor Extended Circuit ID: %" PRIu32
"\n",
1663 threeway_adj
->neighbor_circuit_id
);
1666 static void free_tlv_threeway_adj(struct isis_threeway_adj
*threeway_adj
)
1668 XFREE(MTYPE_ISIS_TLV
, threeway_adj
);
1671 static int pack_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
1677 uint8_t tlv_len
= (threeway_adj
->neighbor_set
) ? 15 : 5;
1679 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
1682 stream_putc(s
, ISIS_TLV_THREE_WAY_ADJ
);
1683 stream_putc(s
, tlv_len
);
1684 stream_putc(s
, threeway_adj
->state
);
1685 stream_putl(s
, threeway_adj
->local_circuit_id
);
1687 if (threeway_adj
->neighbor_set
) {
1688 stream_put(s
, threeway_adj
->neighbor_id
, 6);
1689 stream_putl(s
, threeway_adj
->neighbor_circuit_id
);
1695 static int unpack_tlv_threeway_adj(enum isis_tlv_context context
,
1696 uint8_t tlv_type
, uint8_t tlv_len
,
1697 struct stream
*s
, struct sbuf
*log
,
1698 void *dest
, int indent
)
1700 struct isis_tlvs
*tlvs
= dest
;
1702 sbuf_push(log
, indent
, "Unpacking P2P Three-Way Adjacency TLV...\n");
1703 if (tlv_len
!= 5 && tlv_len
!= 15) {
1704 sbuf_push(log
, indent
, "WARNING: Unexepected TLV size\n");
1705 stream_forward_getp(s
, tlv_len
);
1709 if (tlvs
->threeway_adj
) {
1710 sbuf_push(log
, indent
,
1711 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
1712 stream_forward_getp(s
, tlv_len
);
1716 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
1718 tlvs
->threeway_adj
->state
= stream_getc(s
);
1719 tlvs
->threeway_adj
->local_circuit_id
= stream_getl(s
);
1721 if (tlv_len
== 15) {
1722 tlvs
->threeway_adj
->neighbor_set
= true;
1723 stream_get(tlvs
->threeway_adj
->neighbor_id
, s
, 6);
1724 tlvs
->threeway_adj
->neighbor_circuit_id
= stream_getl(s
);
1730 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
1732 static struct isis_item
*copy_item_ipv6_reach(struct isis_item
*i
)
1734 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1735 struct isis_ipv6_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1736 rv
->metric
= r
->metric
;
1738 rv
->external
= r
->external
;
1739 rv
->prefix
= r
->prefix
;
1740 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
1742 return (struct isis_item
*)rv
;
1745 static void format_item_ipv6_reach(uint16_t mtid
, struct isis_item
*i
,
1746 struct sbuf
*buf
, int indent
)
1748 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1749 char prefixbuf
[PREFIX2STR_BUFFER
];
1751 sbuf_push(buf
, indent
, "%sIPv6 Reachability: %s (Metric: %u)%s%s",
1752 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "MT ",
1753 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
1755 r
->down
? " Down" : "",
1756 r
->external
? " External" : "");
1757 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1758 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1759 sbuf_push(buf
, 0, "\n");
1762 sbuf_push(buf
, indent
, " Subtlvs:\n");
1763 format_subtlvs(r
->subtlvs
, buf
, indent
+ 4);
1767 static void free_item_ipv6_reach(struct isis_item
*i
)
1769 struct isis_ipv6_reach
*item
= (struct isis_ipv6_reach
*)i
;
1771 isis_free_subtlvs(item
->subtlvs
);
1772 XFREE(MTYPE_ISIS_TLV
, item
);
1775 static int pack_item_ipv6_reach(struct isis_item
*i
, struct stream
*s
)
1777 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1780 if (STREAM_WRITEABLE(s
) < 6)
1782 stream_putl(s
, r
->metric
);
1784 control
= r
->down
? ISIS_IPV6_REACH_DOWN
: 0;
1785 control
|= r
->external
? ISIS_IPV6_REACH_EXTERNAL
: 0;
1786 control
|= r
->subtlvs
? ISIS_IPV6_REACH_SUBTLV
: 0;
1788 stream_putc(s
, control
);
1789 stream_putc(s
, r
->prefix
.prefixlen
);
1791 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
))
1793 stream_put(s
, &r
->prefix
.prefix
.s6_addr
, PSIZE(r
->prefix
.prefixlen
));
1796 return pack_subtlvs(r
->subtlvs
, s
);
1801 static int unpack_item_ipv6_reach(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1802 struct sbuf
*log
, void *dest
, int indent
)
1804 struct isis_tlvs
*tlvs
= dest
;
1805 struct isis_ipv6_reach
*rv
= NULL
;
1807 uint8_t control
, subtlv_len
;
1808 struct isis_item_list
*items
;
1810 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1811 items
= &tlvs
->ipv6_reach
;
1813 items
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
1816 sbuf_push(log
, indent
, "Unpacking %sIPv6 reachability...\n",
1817 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "mt ");
1819 if (len
< consume
) {
1820 sbuf_push(log
, indent
,
1821 "Not enough data left. (expected 6 or more bytes, got %"
1827 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1829 rv
->metric
= stream_getl(s
);
1830 control
= stream_getc(s
);
1831 rv
->down
= (control
& ISIS_IPV6_REACH_DOWN
);
1832 rv
->external
= (control
& ISIS_IPV6_REACH_EXTERNAL
);
1834 rv
->prefix
.family
= AF_INET6
;
1835 rv
->prefix
.prefixlen
= stream_getc(s
);
1836 if (rv
->prefix
.prefixlen
> 128) {
1837 sbuf_push(log
, indent
, "Prefixlen %u is inplausible for IPv6\n",
1838 rv
->prefix
.prefixlen
);
1842 consume
+= PSIZE(rv
->prefix
.prefixlen
);
1843 if (len
< consume
) {
1844 sbuf_push(log
, indent
,
1845 "Expected %u bytes of prefix, but only %u bytes available.\n",
1846 PSIZE(rv
->prefix
.prefixlen
), len
- 6);
1849 stream_get(&rv
->prefix
.prefix
.s6_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
1850 struct in6_addr orig_prefix
= rv
->prefix
.prefix
;
1851 apply_mask_ipv6(&rv
->prefix
);
1852 if (memcmp(&orig_prefix
, &rv
->prefix
.prefix
, sizeof(orig_prefix
)))
1853 sbuf_push(log
, indent
+ 2,
1854 "WARNING: Prefix had hostbits set.\n");
1855 format_item_ipv6_reach(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1857 if (control
& ISIS_IPV6_REACH_SUBTLV
) {
1859 if (len
< consume
) {
1860 sbuf_push(log
, indent
,
1861 "Expected 1 byte of subtlv len, but no more data persent.\n");
1864 subtlv_len
= stream_getc(s
);
1867 sbuf_push(log
, indent
+ 2,
1868 " WARNING: subtlv bit set, but there are no subtlvs.\n");
1870 consume
+= subtlv_len
;
1871 if (len
< consume
) {
1872 sbuf_push(log
, indent
,
1874 " bytes of subtlvs, but only %u bytes available.\n",
1876 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
1880 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
1881 bool unpacked_known_tlvs
= false;
1883 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
, subtlv_len
, s
,
1884 log
, rv
->subtlvs
, indent
+ 4, &unpacked_known_tlvs
)) {
1887 if (!unpacked_known_tlvs
) {
1888 isis_free_subtlvs(rv
->subtlvs
);
1893 append_item(items
, (struct isis_item
*)rv
);
1897 free_item_ipv6_reach((struct isis_item
*)rv
);
1901 /* Functions related to TLV 10 Authentication */
1902 static struct isis_item
*copy_item_auth(struct isis_item
*i
)
1904 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1905 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1907 rv
->type
= auth
->type
;
1908 rv
->length
= auth
->length
;
1909 memcpy(rv
->value
, auth
->value
, sizeof(rv
->value
));
1910 return (struct isis_item
*)rv
;
1913 static void format_item_auth(uint16_t mtid
, struct isis_item
*i
,
1914 struct sbuf
*buf
, int indent
)
1916 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1919 sbuf_push(buf
, indent
, "Authentication:\n");
1920 switch (auth
->type
) {
1921 case ISIS_PASSWD_TYPE_CLEARTXT
:
1922 zlog_sanitize(obuf
, sizeof(obuf
), auth
->value
, auth
->length
);
1923 sbuf_push(buf
, indent
, " Password: %s\n", obuf
);
1925 case ISIS_PASSWD_TYPE_HMAC_MD5
:
1926 for (unsigned int j
= 0; j
< 16; j
++) {
1927 snprintf(obuf
+ 2 * j
, sizeof(obuf
) - 2 * j
,
1928 "%02" PRIx8
, auth
->value
[j
]);
1930 sbuf_push(buf
, indent
, " HMAC-MD5: %s\n", obuf
);
1933 sbuf_push(buf
, indent
, " Unknown (%" PRIu8
")\n", auth
->type
);
1938 static void free_item_auth(struct isis_item
*i
)
1940 XFREE(MTYPE_ISIS_TLV
, i
);
1943 static int pack_item_auth(struct isis_item
*i
, struct stream
*s
)
1945 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1947 if (STREAM_WRITEABLE(s
) < 1)
1949 stream_putc(s
, auth
->type
);
1951 switch (auth
->type
) {
1952 case ISIS_PASSWD_TYPE_CLEARTXT
:
1953 if (STREAM_WRITEABLE(s
) < auth
->length
)
1955 stream_put(s
, auth
->passwd
, auth
->length
);
1957 case ISIS_PASSWD_TYPE_HMAC_MD5
:
1958 if (STREAM_WRITEABLE(s
) < 16)
1960 auth
->offset
= stream_get_endp(s
);
1961 stream_put(s
, NULL
, 16);
1970 static int unpack_item_auth(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1971 struct sbuf
*log
, void *dest
, int indent
)
1973 struct isis_tlvs
*tlvs
= dest
;
1975 sbuf_push(log
, indent
, "Unpack Auth TLV...\n");
1979 "Not enough data left.(Expected 1 bytes of auth type, got %" PRIu8
1985 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1987 rv
->type
= stream_getc(s
);
1988 rv
->length
= len
- 1;
1990 if (rv
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
&& rv
->length
!= 16) {
1993 "Unexpected auth length for HMAC-MD5 (expected 16, got %" PRIu8
1996 XFREE(MTYPE_ISIS_TLV
, rv
);
2000 rv
->offset
= stream_get_getp(s
);
2001 stream_get(rv
->value
, s
, rv
->length
);
2002 format_item_auth(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
2003 append_item(&tlvs
->isis_auth
, (struct isis_item
*)rv
);
2007 /* Functions related to TLV 13 Purge Originator */
2009 static struct isis_purge_originator
*copy_tlv_purge_originator(
2010 struct isis_purge_originator
*poi
)
2015 struct isis_purge_originator
*rv
;
2017 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2018 rv
->sender_set
= poi
->sender_set
;
2019 memcpy(rv
->generator
, poi
->generator
, sizeof(rv
->generator
));
2020 if (poi
->sender_set
)
2021 memcpy(rv
->sender
, poi
->sender
, sizeof(rv
->sender
));
2025 static void format_tlv_purge_originator(struct isis_purge_originator
*poi
,
2026 struct sbuf
*buf
, int indent
)
2031 sbuf_push(buf
, indent
, "Purge Originator Identification:\n");
2032 sbuf_push(buf
, indent
, " Generator: %s\n",
2033 isis_format_id(poi
->generator
, sizeof(poi
->generator
)));
2034 if (poi
->sender_set
) {
2035 sbuf_push(buf
, indent
, " Received-From: %s\n",
2036 isis_format_id(poi
->sender
, sizeof(poi
->sender
)));
2040 static void free_tlv_purge_originator(struct isis_purge_originator
*poi
)
2042 XFREE(MTYPE_ISIS_TLV
, poi
);
2045 static int pack_tlv_purge_originator(struct isis_purge_originator
*poi
,
2051 uint8_t data_len
= 1 + sizeof(poi
->generator
);
2053 if (poi
->sender_set
)
2054 data_len
+= sizeof(poi
->sender
);
2056 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + data_len
))
2059 stream_putc(s
, ISIS_TLV_PURGE_ORIGINATOR
);
2060 stream_putc(s
, data_len
);
2061 stream_putc(s
, poi
->sender_set
? 2 : 1);
2062 stream_put(s
, poi
->generator
, sizeof(poi
->generator
));
2063 if (poi
->sender_set
)
2064 stream_put(s
, poi
->sender
, sizeof(poi
->sender
));
2068 static int unpack_tlv_purge_originator(enum isis_tlv_context context
,
2069 uint8_t tlv_type
, uint8_t tlv_len
,
2070 struct stream
*s
, struct sbuf
*log
,
2071 void *dest
, int indent
)
2073 struct isis_tlvs
*tlvs
= dest
;
2074 struct isis_purge_originator poi
= {};
2076 sbuf_push(log
, indent
, "Unpacking Purge Originator Identification TLV...\n");
2078 sbuf_push(log
, indent
, "Not enough data left. (Expected at least 7 bytes, got %"
2079 PRIu8
")\n", tlv_len
);
2083 uint8_t number_of_ids
= stream_getc(s
);
2085 if (number_of_ids
== 1) {
2086 poi
.sender_set
= false;
2087 } else if (number_of_ids
== 2) {
2088 poi
.sender_set
= true;
2090 sbuf_push(log
, indent
, "Got invalid value for number of system IDs: %"
2091 PRIu8
")\n", number_of_ids
);
2095 if (tlv_len
!= 1 + 6 * number_of_ids
) {
2096 sbuf_push(log
, indent
, "Incorrect tlv len for number of IDs.\n");
2100 stream_get(poi
.generator
, s
, sizeof(poi
.generator
));
2102 stream_get(poi
.sender
, s
, sizeof(poi
.sender
));
2104 if (tlvs
->purge_originator
) {
2105 sbuf_push(log
, indent
,
2106 "WARNING: Purge originator present multiple times, ignoring.\n");
2110 tlvs
->purge_originator
= copy_tlv_purge_originator(&poi
);
2115 /* Functions relating to item TLVs */
2117 static void init_item_list(struct isis_item_list
*items
)
2120 items
->tail
= &items
->head
;
2124 static struct isis_item
*copy_item(enum isis_tlv_context context
,
2125 enum isis_tlv_type type
,
2126 struct isis_item
*item
)
2128 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
2130 if (ops
&& ops
->copy_item
)
2131 return ops
->copy_item(item
);
2133 assert(!"Unknown item tlv type!");
2137 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
2138 struct isis_item_list
*src
, struct isis_item_list
*dest
)
2140 struct isis_item
*item
;
2142 init_item_list(dest
);
2144 for (item
= src
->head
; item
; item
= item
->next
) {
2145 append_item(dest
, copy_item(context
, type
, item
));
2149 static void format_item(uint16_t mtid
, enum isis_tlv_context context
,
2150 enum isis_tlv_type type
, struct isis_item
*i
,
2151 struct sbuf
*buf
, int indent
)
2153 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
2155 if (ops
&& ops
->format_item
) {
2156 ops
->format_item(mtid
, i
, buf
, indent
);
2160 assert(!"Unknown item tlv type!");
2163 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
2164 enum isis_tlv_type type
, struct isis_item_list
*items
,
2165 struct sbuf
*buf
, int indent
)
2167 struct isis_item
*i
;
2169 for (i
= items
->head
; i
; i
= i
->next
)
2170 format_item(mtid
, context
, type
, i
, buf
, indent
);
2173 static void free_item(enum isis_tlv_context tlv_context
,
2174 enum isis_tlv_type tlv_type
, struct isis_item
*item
)
2176 const struct tlv_ops
*ops
= tlv_table
[tlv_context
][tlv_type
];
2178 if (ops
&& ops
->free_item
) {
2179 ops
->free_item(item
);
2183 assert(!"Unknown item tlv type!");
2186 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
2187 struct isis_item_list
*items
)
2189 struct isis_item
*item
, *next_item
;
2191 for (item
= items
->head
; item
; item
= next_item
) {
2192 next_item
= item
->next
;
2193 free_item(context
, type
, item
);
2197 static int pack_item(enum isis_tlv_context context
, enum isis_tlv_type type
,
2198 struct isis_item
*i
, struct stream
*s
,
2199 struct isis_tlvs
**fragment_tlvs
,
2200 struct pack_order_entry
*pe
, uint16_t mtid
)
2202 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
2204 if (ops
&& ops
->pack_item
) {
2205 return ops
->pack_item(i
, s
);
2208 assert(!"Unknown item tlv type!");
2212 static void add_item_to_fragment(struct isis_item
*i
, struct pack_order_entry
*pe
,
2213 struct isis_tlvs
*fragment_tlvs
, uint16_t mtid
)
2215 struct isis_item_list
*l
;
2217 if (pe
->how_to_pack
== ISIS_ITEMS
) {
2218 l
= (struct isis_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
2220 struct isis_mt_item_list
*m
;
2221 m
= (struct isis_mt_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
2222 l
= isis_get_mt_items(m
, mtid
);
2225 append_item(l
, copy_item(pe
->context
, pe
->type
, i
));
2228 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
2229 enum isis_tlv_type type
, struct isis_item_list
*items
,
2230 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
2231 struct pack_order_entry
*pe
,
2232 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2233 struct list
*new_fragment_arg
)
2235 size_t len_pos
, last_len
, len
;
2236 struct isis_item
*item
= NULL
;
2243 if (STREAM_WRITEABLE(s
) < 2)
2246 stream_putc(s
, type
);
2247 len_pos
= stream_get_endp(s
);
2248 stream_putc(s
, 0); /* Put 0 as length for now */
2250 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(type
)
2251 && mtid
!= ISIS_MT_IPV4_UNICAST
) {
2252 if (STREAM_WRITEABLE(s
) < 2)
2254 stream_putw(s
, mtid
);
2257 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_OLDSTYLE_REACH
) {
2258 if (STREAM_WRITEABLE(s
) < 1)
2260 stream_putc(s
, 0); /* Virtual flag is set to 0 */
2264 for (item
= item
? item
: items
->head
; item
; item
= item
->next
) {
2265 rv
= pack_item(context
, type
, item
, s
, fragment_tlvs
, pe
, mtid
);
2269 len
= stream_get_endp(s
) - len_pos
- 1;
2271 /* Multiple auths don't go into one TLV, so always break */
2272 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_AUTH
) {
2277 /* Multiple prefix-sids don't go into one TLV, so always break */
2278 if (type
== ISIS_SUBTLV_PREFIX_SID
2279 && (context
== ISIS_CONTEXT_SUBTLV_IP_REACH
2280 || context
== ISIS_CONTEXT_SUBTLV_IPV6_REACH
)) {
2286 if (!last_len
) /* strange, not a single item fit */
2288 /* drop last tlv, otherwise, its too long */
2289 stream_set_endp(s
, len_pos
+ 1 + last_len
);
2295 add_item_to_fragment(item
, pe
, *fragment_tlvs
, mtid
);
2300 stream_putc_at(s
, len_pos
, len
);
2309 *fragment_tlvs
= new_fragment(new_fragment_arg
);
2312 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
2314 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
)
2317 dest
->tail
= &(*dest
->tail
)->next
;
2321 static struct isis_item
*last_item(struct isis_item_list
*list
)
2323 return container_of(list
->tail
, struct isis_item
, next
);
2326 static int unpack_item(uint16_t mtid
, enum isis_tlv_context context
,
2327 uint8_t tlv_type
, uint8_t len
, struct stream
*s
,
2328 struct sbuf
*log
, void *dest
, int indent
)
2330 const struct tlv_ops
*ops
= tlv_table
[context
][tlv_type
];
2332 if (ops
&& ops
->unpack_item
)
2333 return ops
->unpack_item(mtid
, len
, s
, log
, dest
, indent
);
2335 assert(!"Unknown item tlv type!");
2336 sbuf_push(log
, indent
, "Unknown item tlv type!\n");
2340 static int unpack_tlv_with_items(enum isis_tlv_context context
,
2341 uint8_t tlv_type
, uint8_t tlv_len
,
2342 struct stream
*s
, struct sbuf
*log
, void *dest
,
2350 tlv_start
= stream_get_getp(s
);
2353 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(tlv_type
)) {
2355 sbuf_push(log
, indent
,
2356 "TLV is too short to contain MTID\n");
2359 mtid
= stream_getw(s
) & ISIS_MT_MASK
;
2361 sbuf_push(log
, indent
, "Unpacking as MT %s item TLV...\n",
2362 isis_mtid2str(mtid
));
2364 sbuf_push(log
, indent
, "Unpacking as item TLV...\n");
2365 mtid
= ISIS_MT_IPV4_UNICAST
;
2368 if (context
== ISIS_CONTEXT_LSP
2369 && tlv_type
== ISIS_TLV_OLDSTYLE_REACH
) {
2370 if (tlv_len
- tlv_pos
< 1) {
2371 sbuf_push(log
, indent
,
2372 "TLV is too short for old style reach\n");
2375 stream_forward_getp(s
, 1);
2379 if (context
== ISIS_CONTEXT_LSP
2380 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH
) {
2381 struct isis_tlvs
*tlvs
= dest
;
2382 dest
= &tlvs
->oldstyle_ip_reach
;
2383 } else if (context
== ISIS_CONTEXT_LSP
2384 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH_EXT
) {
2385 struct isis_tlvs
*tlvs
= dest
;
2386 dest
= &tlvs
->oldstyle_ip_reach_ext
;
2389 if (context
== ISIS_CONTEXT_LSP
2390 && tlv_type
== ISIS_TLV_MT_ROUTER_INFO
) {
2391 struct isis_tlvs
*tlvs
= dest
;
2392 tlvs
->mt_router_info_empty
= (tlv_pos
>= (size_t)tlv_len
);
2395 while (tlv_pos
< (size_t)tlv_len
) {
2396 rv
= unpack_item(mtid
, context
, tlv_type
, tlv_len
- tlv_pos
, s
,
2397 log
, dest
, indent
+ 2);
2401 tlv_pos
= stream_get_getp(s
) - tlv_start
;
2407 /* Functions to manipulate mt_item_lists */
2409 static int isis_mt_item_list_cmp(const struct isis_item_list
*a
,
2410 const struct isis_item_list
*b
)
2412 if (a
->mtid
< b
->mtid
)
2414 if (a
->mtid
> b
->mtid
)
2419 RB_PROTOTYPE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
2420 RB_GENERATE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
2422 struct isis_item_list
*isis_get_mt_items(struct isis_mt_item_list
*m
,
2425 struct isis_item_list
*rv
;
2427 rv
= isis_lookup_mt_items(m
, mtid
);
2429 rv
= XCALLOC(MTYPE_ISIS_MT_ITEM_LIST
, sizeof(*rv
));
2432 RB_INSERT(isis_mt_item_list
, m
, rv
);
2438 struct isis_item_list
*isis_lookup_mt_items(struct isis_mt_item_list
*m
,
2441 struct isis_item_list key
= {.mtid
= mtid
};
2443 return RB_FIND(isis_mt_item_list
, m
, &key
);
2446 static void free_mt_items(enum isis_tlv_context context
,
2447 enum isis_tlv_type type
, struct isis_mt_item_list
*m
)
2449 struct isis_item_list
*n
, *nnext
;
2451 RB_FOREACH_SAFE (n
, isis_mt_item_list
, m
, nnext
) {
2452 free_items(context
, type
, n
);
2453 RB_REMOVE(isis_mt_item_list
, m
, n
);
2454 XFREE(MTYPE_ISIS_MT_ITEM_LIST
, n
);
2458 static void format_mt_items(enum isis_tlv_context context
,
2459 enum isis_tlv_type type
,
2460 struct isis_mt_item_list
*m
, struct sbuf
*buf
,
2463 struct isis_item_list
*n
;
2465 RB_FOREACH (n
, isis_mt_item_list
, m
) {
2466 format_items_(n
->mtid
, context
, type
, n
, buf
, indent
);
2470 static int pack_mt_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
2471 struct isis_mt_item_list
*m
, struct stream
*s
,
2472 struct isis_tlvs
**fragment_tlvs
,
2473 struct pack_order_entry
*pe
,
2474 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2475 struct list
*new_fragment_arg
)
2477 struct isis_item_list
*n
;
2479 RB_FOREACH (n
, isis_mt_item_list
, m
) {
2482 rv
= pack_items_(n
->mtid
, context
, type
, n
, s
, fragment_tlvs
,
2483 pe
, new_fragment
, new_fragment_arg
);
2491 static void copy_mt_items(enum isis_tlv_context context
,
2492 enum isis_tlv_type type
,
2493 struct isis_mt_item_list
*src
,
2494 struct isis_mt_item_list
*dest
)
2496 struct isis_item_list
*n
;
2498 RB_INIT(isis_mt_item_list
, dest
);
2500 RB_FOREACH (n
, isis_mt_item_list
, src
) {
2501 copy_items(context
, type
, n
, isis_get_mt_items(dest
, n
->mtid
));
2505 /* Functions related to tlvs in general */
2507 struct isis_tlvs
*isis_alloc_tlvs(void)
2509 struct isis_tlvs
*result
;
2511 result
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*result
));
2513 init_item_list(&result
->isis_auth
);
2514 init_item_list(&result
->area_addresses
);
2515 init_item_list(&result
->mt_router_info
);
2516 init_item_list(&result
->oldstyle_reach
);
2517 init_item_list(&result
->lan_neighbor
);
2518 init_item_list(&result
->lsp_entries
);
2519 init_item_list(&result
->extended_reach
);
2520 RB_INIT(isis_mt_item_list
, &result
->mt_reach
);
2521 init_item_list(&result
->oldstyle_ip_reach
);
2522 init_item_list(&result
->oldstyle_ip_reach_ext
);
2523 init_item_list(&result
->ipv4_address
);
2524 init_item_list(&result
->ipv6_address
);
2525 init_item_list(&result
->extended_ip_reach
);
2526 RB_INIT(isis_mt_item_list
, &result
->mt_ip_reach
);
2527 init_item_list(&result
->ipv6_reach
);
2528 RB_INIT(isis_mt_item_list
, &result
->mt_ipv6_reach
);
2533 struct isis_tlvs
*isis_copy_tlvs(struct isis_tlvs
*tlvs
)
2535 struct isis_tlvs
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2537 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
,
2540 rv
->purge_originator
=
2541 copy_tlv_purge_originator(tlvs
->purge_originator
);
2543 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2544 &tlvs
->area_addresses
, &rv
->area_addresses
);
2546 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2547 &tlvs
->mt_router_info
, &rv
->mt_router_info
);
2549 rv
->mt_router_info_empty
= tlvs
->mt_router_info_empty
;
2551 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2552 &tlvs
->oldstyle_reach
, &rv
->oldstyle_reach
);
2554 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2555 &tlvs
->lan_neighbor
, &rv
->lan_neighbor
);
2557 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
2560 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2561 &tlvs
->extended_reach
, &rv
->extended_reach
);
2563 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
2566 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2567 &tlvs
->oldstyle_ip_reach
, &rv
->oldstyle_ip_reach
);
2569 copy_tlv_protocols_supported(&tlvs
->protocols_supported
,
2570 &rv
->protocols_supported
);
2572 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2573 &tlvs
->oldstyle_ip_reach_ext
, &rv
->oldstyle_ip_reach_ext
);
2575 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
, &tlvs
->ipv4_address
,
2578 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
, &tlvs
->ipv6_address
,
2581 rv
->te_router_id
= copy_tlv_te_router_id(tlvs
->te_router_id
);
2583 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2584 &tlvs
->extended_ip_reach
, &rv
->extended_ip_reach
);
2586 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2587 &tlvs
->mt_ip_reach
, &rv
->mt_ip_reach
);
2589 rv
->hostname
= copy_tlv_dynamic_hostname(tlvs
->hostname
);
2591 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
2594 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2595 &tlvs
->mt_ipv6_reach
, &rv
->mt_ipv6_reach
);
2597 rv
->threeway_adj
= copy_tlv_threeway_adj(tlvs
->threeway_adj
);
2599 rv
->spine_leaf
= copy_tlv_spine_leaf(tlvs
->spine_leaf
);
2604 static void format_tlvs(struct isis_tlvs
*tlvs
, struct sbuf
*buf
, int indent
)
2606 format_tlv_protocols_supported(&tlvs
->protocols_supported
, buf
, indent
);
2608 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
, buf
,
2611 format_tlv_purge_originator(tlvs
->purge_originator
, buf
, indent
);
2613 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2614 &tlvs
->area_addresses
, buf
, indent
);
2616 if (tlvs
->mt_router_info_empty
) {
2617 sbuf_push(buf
, indent
, "MT Router Info: None\n");
2619 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2620 &tlvs
->mt_router_info
, buf
, indent
);
2623 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2624 &tlvs
->oldstyle_reach
, buf
, indent
);
2626 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2627 &tlvs
->lan_neighbor
, buf
, indent
);
2629 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
2632 format_tlv_dynamic_hostname(tlvs
->hostname
, buf
, indent
);
2633 format_tlv_te_router_id(tlvs
->te_router_id
, buf
, indent
);
2635 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2636 &tlvs
->extended_reach
, buf
, indent
);
2638 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
2641 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2642 &tlvs
->oldstyle_ip_reach
, buf
, indent
);
2644 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2645 &tlvs
->oldstyle_ip_reach_ext
, buf
, indent
);
2647 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
2648 &tlvs
->ipv4_address
, buf
, indent
);
2650 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
2651 &tlvs
->ipv6_address
, buf
, indent
);
2653 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2654 &tlvs
->extended_ip_reach
, buf
, indent
);
2656 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2657 &tlvs
->mt_ip_reach
, buf
, indent
);
2659 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
2662 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2663 &tlvs
->mt_ipv6_reach
, buf
, indent
);
2665 format_tlv_threeway_adj(tlvs
->threeway_adj
, buf
, indent
);
2667 format_tlv_spine_leaf(tlvs
->spine_leaf
, buf
, indent
);
2670 const char *isis_format_tlvs(struct isis_tlvs
*tlvs
)
2672 static struct sbuf buf
;
2674 if (!sbuf_buf(&buf
))
2675 sbuf_init(&buf
, NULL
, 0);
2678 format_tlvs(tlvs
, &buf
, 0);
2679 return sbuf_buf(&buf
);
2682 void isis_free_tlvs(struct isis_tlvs
*tlvs
)
2687 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
2688 free_tlv_purge_originator(tlvs
->purge_originator
);
2689 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2690 &tlvs
->area_addresses
);
2691 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2692 &tlvs
->mt_router_info
);
2693 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2694 &tlvs
->oldstyle_reach
);
2695 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2696 &tlvs
->lan_neighbor
);
2697 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
);
2698 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2699 &tlvs
->extended_reach
);
2700 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
);
2701 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2702 &tlvs
->oldstyle_ip_reach
);
2703 free_tlv_protocols_supported(&tlvs
->protocols_supported
);
2704 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2705 &tlvs
->oldstyle_ip_reach_ext
);
2706 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
2707 &tlvs
->ipv4_address
);
2708 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
2709 &tlvs
->ipv6_address
);
2710 free_tlv_te_router_id(tlvs
->te_router_id
);
2711 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2712 &tlvs
->extended_ip_reach
);
2713 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2714 &tlvs
->mt_ip_reach
);
2715 free_tlv_dynamic_hostname(tlvs
->hostname
);
2716 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
);
2717 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2718 &tlvs
->mt_ipv6_reach
);
2719 free_tlv_threeway_adj(tlvs
->threeway_adj
);
2720 free_tlv_spine_leaf(tlvs
->spine_leaf
);
2722 XFREE(MTYPE_ISIS_TLV
, tlvs
);
2725 static void add_padding(struct stream
*s
)
2727 while (STREAM_WRITEABLE(s
)) {
2728 if (STREAM_WRITEABLE(s
) == 1)
2730 uint32_t padding_len
= STREAM_WRITEABLE(s
) - 2;
2732 if (padding_len
> 255) {
2733 if (padding_len
== 256)
2739 stream_putc(s
, ISIS_TLV_PADDING
);
2740 stream_putc(s
, padding_len
);
2741 stream_put(s
, NULL
, padding_len
);
2745 #define LSP_REM_LIFETIME_OFF 10
2746 #define LSP_CHECKSUM_OFF 24
2747 static void safe_auth_md5(struct stream
*s
, uint16_t *checksum
,
2748 uint16_t *rem_lifetime
)
2750 memcpy(rem_lifetime
, STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
,
2751 sizeof(*rem_lifetime
));
2752 memset(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, 0, sizeof(*rem_lifetime
));
2753 memcpy(checksum
, STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, sizeof(*checksum
));
2754 memset(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, 0, sizeof(*checksum
));
2757 static void restore_auth_md5(struct stream
*s
, uint16_t checksum
,
2758 uint16_t rem_lifetime
)
2760 memcpy(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, &rem_lifetime
,
2761 sizeof(rem_lifetime
));
2762 memcpy(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, &checksum
, sizeof(checksum
));
2765 static void update_auth_hmac_md5(struct isis_auth
*auth
, struct stream
*s
,
2769 uint16_t checksum
, rem_lifetime
;
2772 safe_auth_md5(s
, &checksum
, &rem_lifetime
);
2774 memset(STREAM_DATA(s
) + auth
->offset
, 0, 16);
2775 #ifdef CRYPTO_OPENSSL
2776 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), auth
->passwd
,
2777 auth
->plength
, STREAM_DATA(s
),
2778 stream_get_endp(s
), NULL
, NULL
);
2780 memcpy(digest
, result
, 16);
2781 #elif CRYPTO_INTERNAL
2782 hmac_md5(STREAM_DATA(s
), stream_get_endp(s
), auth
->passwd
,
2783 auth
->plength
, digest
);
2785 memcpy(auth
->value
, digest
, 16);
2786 memcpy(STREAM_DATA(s
) + auth
->offset
, digest
, 16);
2789 restore_auth_md5(s
, checksum
, rem_lifetime
);
2792 static void update_auth(struct isis_tlvs
*tlvs
, struct stream
*s
, bool is_lsp
)
2794 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
2796 for (struct isis_auth
*auth
= auth_head
; auth
; auth
= auth
->next
) {
2797 if (auth
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
2798 update_auth_hmac_md5(auth
, s
, is_lsp
);
2802 static int handle_pack_entry(struct pack_order_entry
*pe
,
2803 struct isis_tlvs
*tlvs
, struct stream
*stream
,
2804 struct isis_tlvs
**fragment_tlvs
,
2805 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2806 struct list
*new_fragment_arg
)
2810 if (pe
->how_to_pack
== ISIS_ITEMS
) {
2811 struct isis_item_list
*l
;
2812 l
= (struct isis_item_list
*)(((char *)tlvs
)
2813 + pe
->what_to_pack
);
2814 rv
= pack_items(pe
->context
, pe
->type
, l
, stream
, fragment_tlvs
,
2815 pe
, new_fragment
, new_fragment_arg
);
2817 struct isis_mt_item_list
*l
;
2818 l
= (struct isis_mt_item_list
*)(((char *)tlvs
)
2819 + pe
->what_to_pack
);
2820 rv
= pack_mt_items(pe
->context
, pe
->type
, l
, stream
,
2821 fragment_tlvs
, pe
, new_fragment
,
2828 static int pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
2829 struct isis_tlvs
*fragment_tlvs
,
2830 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2831 struct list
*new_fragment_arg
)
2835 /* When fragmenting, don't add auth as it's already accounted for in the
2836 * size we are given. */
2837 if (!fragment_tlvs
) {
2838 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
,
2839 &tlvs
->isis_auth
, stream
, NULL
, NULL
, NULL
,
2845 rv
= pack_tlv_purge_originator(tlvs
->purge_originator
, stream
);
2848 if (fragment_tlvs
) {
2849 fragment_tlvs
->purge_originator
=
2850 copy_tlv_purge_originator(tlvs
->purge_originator
);
2853 rv
= pack_tlv_protocols_supported(&tlvs
->protocols_supported
, stream
);
2856 if (fragment_tlvs
) {
2857 copy_tlv_protocols_supported(
2858 &tlvs
->protocols_supported
,
2859 &fragment_tlvs
->protocols_supported
);
2862 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2863 &tlvs
->area_addresses
, stream
, NULL
, NULL
, NULL
, NULL
);
2866 if (fragment_tlvs
) {
2867 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2868 &tlvs
->area_addresses
,
2869 &fragment_tlvs
->area_addresses
);
2873 if (tlvs
->mt_router_info_empty
) {
2874 if (STREAM_WRITEABLE(stream
) < 2)
2876 stream_putc(stream
, ISIS_TLV_MT_ROUTER_INFO
);
2877 stream_putc(stream
, 0);
2879 fragment_tlvs
->mt_router_info_empty
= true;
2881 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2882 &tlvs
->mt_router_info
, stream
, NULL
, NULL
, NULL
,
2886 if (fragment_tlvs
) {
2887 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2888 &tlvs
->mt_router_info
,
2889 &fragment_tlvs
->mt_router_info
);
2893 rv
= pack_tlv_dynamic_hostname(tlvs
->hostname
, stream
);
2897 fragment_tlvs
->hostname
=
2898 copy_tlv_dynamic_hostname(tlvs
->hostname
);
2900 rv
= pack_tlv_te_router_id(tlvs
->te_router_id
, stream
);
2903 if (fragment_tlvs
) {
2904 fragment_tlvs
->te_router_id
=
2905 copy_tlv_te_router_id(tlvs
->te_router_id
);
2908 rv
= pack_tlv_threeway_adj(tlvs
->threeway_adj
, stream
);
2911 if (fragment_tlvs
) {
2912 fragment_tlvs
->threeway_adj
=
2913 copy_tlv_threeway_adj(tlvs
->threeway_adj
);
2916 rv
= pack_tlv_spine_leaf(tlvs
->spine_leaf
, stream
);
2919 if (fragment_tlvs
) {
2920 fragment_tlvs
->spine_leaf
=
2921 copy_tlv_spine_leaf(tlvs
->spine_leaf
);
2924 for (size_t pack_idx
= 0; pack_idx
< array_size(pack_order
);
2926 rv
= handle_pack_entry(&pack_order
[pack_idx
], tlvs
, stream
,
2927 fragment_tlvs
? &fragment_tlvs
: NULL
,
2928 new_fragment
, new_fragment_arg
);
2937 int isis_pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
2938 size_t len_pointer
, bool pad
, bool is_lsp
)
2942 rv
= pack_tlvs(tlvs
, stream
, NULL
, NULL
, NULL
);
2947 add_padding(stream
);
2949 if (len_pointer
!= (size_t)-1) {
2950 stream_putw_at(stream
, len_pointer
, stream_get_endp(stream
));
2953 update_auth(tlvs
, stream
, is_lsp
);
2958 static struct isis_tlvs
*new_fragment(struct list
*l
)
2960 struct isis_tlvs
*rv
= isis_alloc_tlvs();
2962 listnode_add(l
, rv
);
2966 struct list
*isis_fragment_tlvs(struct isis_tlvs
*tlvs
, size_t size
)
2968 struct stream
*dummy_stream
= stream_new(size
);
2969 struct list
*rv
= list_new();
2970 struct isis_tlvs
*fragment_tlvs
= new_fragment(rv
);
2972 if (pack_tlvs(tlvs
, dummy_stream
, fragment_tlvs
, new_fragment
, rv
)) {
2973 struct listnode
*node
;
2974 for (ALL_LIST_ELEMENTS_RO(rv
, node
, fragment_tlvs
))
2975 isis_free_tlvs(fragment_tlvs
);
2979 stream_free(dummy_stream
);
2983 static int unpack_tlv_unknown(enum isis_tlv_context context
, uint8_t tlv_type
,
2984 uint8_t tlv_len
, struct stream
*s
,
2985 struct sbuf
*log
, int indent
)
2987 stream_forward_getp(s
, tlv_len
);
2988 sbuf_push(log
, indent
,
2989 "Skipping unknown TLV %" PRIu8
" (%" PRIu8
" bytes)\n",
2994 static int unpack_tlv(enum isis_tlv_context context
, size_t avail_len
,
2995 struct stream
*stream
, struct sbuf
*log
, void *dest
,
2996 int indent
, bool *unpacked_known_tlvs
)
2998 uint8_t tlv_type
, tlv_len
;
2999 const struct tlv_ops
*ops
;
3001 sbuf_push(log
, indent
, "Unpacking TLV...\n");
3003 if (avail_len
< 2) {
3006 "Available data %zu too short to contain a TLV header.\n",
3011 tlv_type
= stream_getc(stream
);
3012 tlv_len
= stream_getc(stream
);
3014 sbuf_push(log
, indent
+ 2,
3015 "Found TLV of type %" PRIu8
" and len %" PRIu8
".\n",
3018 if (avail_len
< ((size_t)tlv_len
) + 2) {
3019 sbuf_push(log
, indent
+ 2,
3020 "Available data %zu too short for claimed TLV len %" PRIu8
".\n",
3021 avail_len
- 2, tlv_len
);
3025 ops
= tlv_table
[context
][tlv_type
];
3026 if (ops
&& ops
->unpack
) {
3027 if (unpacked_known_tlvs
)
3028 *unpacked_known_tlvs
= true;
3029 return ops
->unpack(context
, tlv_type
, tlv_len
, stream
, log
,
3033 return unpack_tlv_unknown(context
, tlv_type
, tlv_len
, stream
, log
,
3037 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
3038 struct stream
*stream
, struct sbuf
*log
, void *dest
,
3039 int indent
, bool *unpacked_known_tlvs
)
3042 size_t tlv_start
, tlv_pos
;
3044 tlv_start
= stream_get_getp(stream
);
3047 sbuf_push(log
, indent
, "Unpacking %zu bytes of %s...\n", avail_len
,
3048 (context
== ISIS_CONTEXT_LSP
) ? "TLVs" : "sub-TLVs");
3050 while (tlv_pos
< avail_len
) {
3051 rv
= unpack_tlv(context
, avail_len
- tlv_pos
, stream
, log
, dest
,
3052 indent
+ 2, unpacked_known_tlvs
);
3056 tlv_pos
= stream_get_getp(stream
) - tlv_start
;
3062 int isis_unpack_tlvs(size_t avail_len
, struct stream
*stream
,
3063 struct isis_tlvs
**dest
, const char **log
)
3065 static struct sbuf logbuf
;
3068 struct isis_tlvs
*result
;
3070 if (!sbuf_buf(&logbuf
))
3071 sbuf_init(&logbuf
, NULL
, 0);
3073 sbuf_reset(&logbuf
);
3074 if (avail_len
> STREAM_READABLE(stream
)) {
3075 sbuf_push(&logbuf
, indent
,
3076 "Stream doesn't contain sufficient data. "
3077 "Claimed %zu, available %zu\n",
3078 avail_len
, STREAM_READABLE(stream
));
3082 result
= isis_alloc_tlvs();
3083 rv
= unpack_tlvs(ISIS_CONTEXT_LSP
, avail_len
, stream
, &logbuf
, result
,
3086 *log
= sbuf_buf(&logbuf
);
3092 #define TLV_OPS(_name_, _desc_) \
3093 static const struct tlv_ops tlv_##_name_##_ops = { \
3094 .name = _desc_, .unpack = unpack_tlv_##_name_, \
3097 #define ITEM_TLV_OPS(_name_, _desc_) \
3098 static const struct tlv_ops tlv_##_name_##_ops = { \
3100 .unpack = unpack_tlv_with_items, \
3102 .pack_item = pack_item_##_name_, \
3103 .free_item = free_item_##_name_, \
3104 .unpack_item = unpack_item_##_name_, \
3105 .format_item = format_item_##_name_, \
3106 .copy_item = copy_item_##_name_}
3108 #define SUBTLV_OPS(_name_, _desc_) \
3109 static const struct tlv_ops subtlv_##_name_##_ops = { \
3110 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
3113 #define ITEM_SUBTLV_OPS(_name_, _desc_) \
3114 ITEM_TLV_OPS(_name_, _desc_)
3116 ITEM_TLV_OPS(area_address
, "TLV 1 Area Addresses");
3117 ITEM_TLV_OPS(oldstyle_reach
, "TLV 2 IS Reachability");
3118 ITEM_TLV_OPS(lan_neighbor
, "TLV 6 LAN Neighbors");
3119 ITEM_TLV_OPS(lsp_entry
, "TLV 9 LSP Entries");
3120 ITEM_TLV_OPS(auth
, "TLV 10 IS-IS Auth");
3121 TLV_OPS(purge_originator
, "TLV 13 Purge Originator Identification");
3122 ITEM_TLV_OPS(extended_reach
, "TLV 22 Extended Reachability");
3123 ITEM_TLV_OPS(oldstyle_ip_reach
, "TLV 128/130 IP Reachability");
3124 TLV_OPS(protocols_supported
, "TLV 129 Protocols Supported");
3125 ITEM_TLV_OPS(ipv4_address
, "TLV 132 IPv4 Interface Address");
3126 TLV_OPS(te_router_id
, "TLV 134 TE Router ID");
3127 ITEM_TLV_OPS(extended_ip_reach
, "TLV 135 Extended IP Reachability");
3128 TLV_OPS(dynamic_hostname
, "TLV 137 Dynamic Hostname");
3129 TLV_OPS(spine_leaf
, "TLV 150 Spine Leaf Extensions");
3130 ITEM_TLV_OPS(mt_router_info
, "TLV 229 MT Router Information");
3131 TLV_OPS(threeway_adj
, "TLV 240 P2P Three-Way Adjacency");
3132 ITEM_TLV_OPS(ipv6_address
, "TLV 232 IPv6 Interface Address");
3133 ITEM_TLV_OPS(ipv6_reach
, "TLV 236 IPv6 Reachability");
3135 ITEM_SUBTLV_OPS(prefix_sid
, "Sub-TLV 3 SR Prefix-SID");
3136 SUBTLV_OPS(ipv6_source_prefix
, "Sub-TLV 22 IPv6 Source Prefix");
3138 static const struct tlv_ops
*tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
] = {
3139 [ISIS_CONTEXT_LSP
] = {
3140 [ISIS_TLV_AREA_ADDRESSES
] = &tlv_area_address_ops
,
3141 [ISIS_TLV_OLDSTYLE_REACH
] = &tlv_oldstyle_reach_ops
,
3142 [ISIS_TLV_LAN_NEIGHBORS
] = &tlv_lan_neighbor_ops
,
3143 [ISIS_TLV_LSP_ENTRY
] = &tlv_lsp_entry_ops
,
3144 [ISIS_TLV_AUTH
] = &tlv_auth_ops
,
3145 [ISIS_TLV_PURGE_ORIGINATOR
] = &tlv_purge_originator_ops
,
3146 [ISIS_TLV_EXTENDED_REACH
] = &tlv_extended_reach_ops
,
3147 [ISIS_TLV_MT_REACH
] = &tlv_extended_reach_ops
,
3148 [ISIS_TLV_OLDSTYLE_IP_REACH
] = &tlv_oldstyle_ip_reach_ops
,
3149 [ISIS_TLV_PROTOCOLS_SUPPORTED
] = &tlv_protocols_supported_ops
,
3150 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT
] = &tlv_oldstyle_ip_reach_ops
,
3151 [ISIS_TLV_IPV4_ADDRESS
] = &tlv_ipv4_address_ops
,
3152 [ISIS_TLV_TE_ROUTER_ID
] = &tlv_te_router_id_ops
,
3153 [ISIS_TLV_EXTENDED_IP_REACH
] = &tlv_extended_ip_reach_ops
,
3154 [ISIS_TLV_MT_IP_REACH
] = &tlv_extended_ip_reach_ops
,
3155 [ISIS_TLV_DYNAMIC_HOSTNAME
] = &tlv_dynamic_hostname_ops
,
3156 [ISIS_TLV_SPINE_LEAF_EXT
] = &tlv_spine_leaf_ops
,
3157 [ISIS_TLV_MT_ROUTER_INFO
] = &tlv_mt_router_info_ops
,
3158 [ISIS_TLV_THREE_WAY_ADJ
] = &tlv_threeway_adj_ops
,
3159 [ISIS_TLV_IPV6_ADDRESS
] = &tlv_ipv6_address_ops
,
3160 [ISIS_TLV_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
3161 [ISIS_TLV_MT_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
3163 [ISIS_CONTEXT_SUBTLV_NE_REACH
] = {},
3164 [ISIS_CONTEXT_SUBTLV_IP_REACH
] = {
3165 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
3167 [ISIS_CONTEXT_SUBTLV_IPV6_REACH
] = {
3168 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
3169 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX
] = &subtlv_ipv6_source_prefix_ops
,
3173 /* Accessor functions */
3175 void isis_tlvs_add_auth(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
)
3177 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
3178 init_item_list(&tlvs
->isis_auth
);
3180 if (passwd
->type
== ISIS_PASSWD_TYPE_UNUSED
)
3183 struct isis_auth
*auth
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*auth
));
3185 auth
->type
= passwd
->type
;
3187 auth
->plength
= passwd
->len
;
3188 memcpy(auth
->passwd
, passwd
->passwd
,
3189 MIN(sizeof(auth
->passwd
), sizeof(passwd
->passwd
)));
3191 if (auth
->type
== ISIS_PASSWD_TYPE_CLEARTXT
) {
3192 auth
->length
= passwd
->len
;
3193 memcpy(auth
->value
, passwd
->passwd
,
3194 MIN(sizeof(auth
->value
), sizeof(passwd
->passwd
)));
3197 append_item(&tlvs
->isis_auth
, (struct isis_item
*)auth
);
3200 void isis_tlvs_add_area_addresses(struct isis_tlvs
*tlvs
,
3201 struct list
*addresses
)
3203 struct listnode
*node
;
3204 struct area_addr
*area_addr
;
3206 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, area_addr
)) {
3207 struct isis_area_address
*a
=
3208 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
3210 a
->len
= area_addr
->addr_len
;
3211 memcpy(a
->addr
, area_addr
->area_addr
, 20);
3212 append_item(&tlvs
->area_addresses
, (struct isis_item
*)a
);
3216 void isis_tlvs_add_lan_neighbors(struct isis_tlvs
*tlvs
, struct list
*neighbors
)
3218 struct listnode
*node
;
3221 for (ALL_LIST_ELEMENTS_RO(neighbors
, node
, snpa
)) {
3222 struct isis_lan_neighbor
*n
=
3223 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*n
));
3225 memcpy(n
->mac
, snpa
, 6);
3226 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)n
);
3230 void isis_tlvs_set_protocols_supported(struct isis_tlvs
*tlvs
,
3231 struct nlpids
*nlpids
)
3233 tlvs
->protocols_supported
.count
= nlpids
->count
;
3234 XFREE(MTYPE_ISIS_TLV
, tlvs
->protocols_supported
.protocols
);
3235 if (nlpids
->count
) {
3236 tlvs
->protocols_supported
.protocols
=
3237 XCALLOC(MTYPE_ISIS_TLV
, nlpids
->count
);
3238 memcpy(tlvs
->protocols_supported
.protocols
, nlpids
->nlpids
,
3241 tlvs
->protocols_supported
.protocols
= NULL
;
3245 void isis_tlvs_add_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3246 bool overload
, bool attached
)
3248 struct isis_mt_router_info
*i
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*i
));
3250 i
->overload
= overload
;
3251 i
->attached
= attached
;
3253 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)i
);
3256 void isis_tlvs_add_ipv4_address(struct isis_tlvs
*tlvs
, struct in_addr
*addr
)
3258 struct isis_ipv4_address
*a
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
3260 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)a
);
3264 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs
*tlvs
,
3265 struct list
*addresses
)
3267 struct listnode
*node
;
3268 struct prefix_ipv4
*ip_addr
;
3269 unsigned int addr_count
= 0;
3271 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
3272 isis_tlvs_add_ipv4_address(tlvs
, &ip_addr
->prefix
);
3274 if (addr_count
>= 63)
3279 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs
*tlvs
,
3280 struct list
*addresses
)
3282 struct listnode
*node
;
3283 struct prefix_ipv6
*ip_addr
;
3284 unsigned int addr_count
= 0;
3286 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
3287 if (addr_count
>= 15)
3290 struct isis_ipv6_address
*a
=
3291 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
3293 a
->addr
= ip_addr
->prefix
;
3294 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)a
);
3299 typedef bool (*auth_validator_func
)(struct isis_passwd
*passwd
,
3300 struct stream
*stream
,
3301 struct isis_auth
*auth
, bool is_lsp
);
3303 static bool auth_validator_cleartxt(struct isis_passwd
*passwd
,
3304 struct stream
*stream
,
3305 struct isis_auth
*auth
, bool is_lsp
)
3307 return (auth
->length
== passwd
->len
3308 && !memcmp(auth
->value
, passwd
->passwd
, passwd
->len
));
3311 static bool auth_validator_hmac_md5(struct isis_passwd
*passwd
,
3312 struct stream
*stream
,
3313 struct isis_auth
*auth
, bool is_lsp
)
3317 uint16_t rem_lifetime
;
3320 safe_auth_md5(stream
, &checksum
, &rem_lifetime
);
3322 memset(STREAM_DATA(stream
) + auth
->offset
, 0, 16);
3323 #ifdef CRYPTO_OPENSSL
3324 uint8_t *result
= (uint8_t *)HMAC(EVP_md5(), passwd
->passwd
,
3325 passwd
->len
, STREAM_DATA(stream
),
3326 stream_get_endp(stream
), NULL
, NULL
);
3328 memcpy(digest
, result
, 16);
3329 #elif CRYPTO_INTERNAL
3330 hmac_md5(STREAM_DATA(stream
), stream_get_endp(stream
), passwd
->passwd
,
3331 passwd
->len
, digest
);
3333 memcpy(STREAM_DATA(stream
) + auth
->offset
, auth
->value
, 16);
3335 bool rv
= !memcmp(digest
, auth
->value
, 16);
3338 restore_auth_md5(stream
, checksum
, rem_lifetime
);
3343 static const auth_validator_func auth_validators
[] = {
3344 [ISIS_PASSWD_TYPE_CLEARTXT
] = auth_validator_cleartxt
,
3345 [ISIS_PASSWD_TYPE_HMAC_MD5
] = auth_validator_hmac_md5
,
3348 int isis_tlvs_auth_is_valid(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
,
3349 struct stream
*stream
, bool is_lsp
)
3351 /* If no auth is set, always pass authentication */
3353 return ISIS_AUTH_OK
;
3355 /* If we don't known how to validate the auth, return invalid */
3356 if (passwd
->type
>= array_size(auth_validators
)
3357 || !auth_validators
[passwd
->type
])
3358 return ISIS_AUTH_NO_VALIDATOR
;
3360 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
3361 struct isis_auth
*auth
;
3362 for (auth
= auth_head
; auth
; auth
= auth
->next
) {
3363 if (auth
->type
== passwd
->type
)
3367 /* If matching auth TLV could not be found, return invalid */
3369 return ISIS_AUTH_TYPE_FAILURE
;
3372 /* Perform validation and return result */
3373 if (auth_validators
[passwd
->type
](passwd
, stream
, auth
, is_lsp
))
3374 return ISIS_AUTH_OK
;
3376 return ISIS_AUTH_FAILURE
;
3379 bool isis_tlvs_area_addresses_match(struct isis_tlvs
*tlvs
,
3380 struct list
*addresses
)
3382 struct isis_area_address
*addr_head
;
3384 addr_head
= (struct isis_area_address
*)tlvs
->area_addresses
.head
;
3385 for (struct isis_area_address
*addr
= addr_head
; addr
;
3386 addr
= addr
->next
) {
3387 struct listnode
*node
;
3388 struct area_addr
*a
;
3390 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, a
)) {
3391 if (a
->addr_len
== addr
->len
3392 && !memcmp(a
->area_addr
, addr
->addr
, addr
->len
))
3400 static void tlvs_area_addresses_to_adj(struct isis_tlvs
*tlvs
,
3401 struct isis_adjacency
*adj
,
3404 if (adj
->area_address_count
!= tlvs
->area_addresses
.count
) {
3406 adj
->area_address_count
= tlvs
->area_addresses
.count
;
3407 adj
->area_addresses
= XREALLOC(
3408 MTYPE_ISIS_ADJACENCY_INFO
, adj
->area_addresses
,
3409 adj
->area_address_count
* sizeof(*adj
->area_addresses
));
3412 struct isis_area_address
*addr
= NULL
;
3413 for (unsigned int i
= 0; i
< tlvs
->area_addresses
.count
; i
++) {
3415 addr
= (struct isis_area_address
*)
3416 tlvs
->area_addresses
.head
;
3420 if (adj
->area_addresses
[i
].addr_len
== addr
->len
3421 && !memcmp(adj
->area_addresses
[i
].area_addr
, addr
->addr
,
3427 adj
->area_addresses
[i
].addr_len
= addr
->len
;
3428 memcpy(adj
->area_addresses
[i
].area_addr
, addr
->addr
, addr
->len
);
3432 static void tlvs_protocols_supported_to_adj(struct isis_tlvs
*tlvs
,
3433 struct isis_adjacency
*adj
,
3436 bool ipv4_supported
= false, ipv6_supported
= false;
3438 for (uint8_t i
= 0; i
< tlvs
->protocols_supported
.count
; i
++) {
3439 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IP
)
3440 ipv4_supported
= true;
3441 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IPV6
)
3442 ipv6_supported
= true;
3445 struct nlpids reduced
= {};
3447 if (ipv4_supported
&& ipv6_supported
) {
3449 reduced
.nlpids
[0] = NLPID_IP
;
3450 reduced
.nlpids
[1] = NLPID_IPV6
;
3451 } else if (ipv4_supported
) {
3453 reduced
.nlpids
[0] = NLPID_IP
;
3454 } else if (ipv6_supported
) {
3456 reduced
.nlpids
[0] = NLPID_IPV6
;
3461 if (adj
->nlpids
.count
== reduced
.count
3462 && !memcmp(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
))
3466 adj
->nlpids
.count
= reduced
.count
;
3467 memcpy(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
);
3470 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs
*tlvs
,
3471 struct isis_adjacency
*adj
,
3474 if (adj
->ipv4_address_count
!= tlvs
->ipv4_address
.count
) {
3476 adj
->ipv4_address_count
= tlvs
->ipv4_address
.count
;
3477 adj
->ipv4_addresses
= XREALLOC(
3478 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv4_addresses
,
3479 adj
->ipv4_address_count
* sizeof(*adj
->ipv4_addresses
));
3482 struct isis_ipv4_address
*addr
= NULL
;
3483 for (unsigned int i
= 0; i
< tlvs
->ipv4_address
.count
; i
++) {
3485 addr
= (struct isis_ipv4_address
*)
3486 tlvs
->ipv4_address
.head
;
3490 if (!memcmp(&adj
->ipv4_addresses
[i
], &addr
->addr
,
3491 sizeof(addr
->addr
)))
3495 adj
->ipv4_addresses
[i
] = addr
->addr
;
3499 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
3500 struct isis_adjacency
*adj
,
3503 if (adj
->ipv6_address_count
!= tlvs
->ipv6_address
.count
) {
3505 adj
->ipv6_address_count
= tlvs
->ipv6_address
.count
;
3506 adj
->ipv6_addresses
= XREALLOC(
3507 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv6_addresses
,
3508 adj
->ipv6_address_count
* sizeof(*adj
->ipv6_addresses
));
3511 struct isis_ipv6_address
*addr
= NULL
;
3512 for (unsigned int i
= 0; i
< tlvs
->ipv6_address
.count
; i
++) {
3514 addr
= (struct isis_ipv6_address
*)
3515 tlvs
->ipv6_address
.head
;
3519 if (!memcmp(&adj
->ipv6_addresses
[i
], &addr
->addr
,
3520 sizeof(addr
->addr
)))
3524 adj
->ipv6_addresses
[i
] = addr
->addr
;
3528 void isis_tlvs_to_adj(struct isis_tlvs
*tlvs
, struct isis_adjacency
*adj
,
3533 tlvs_area_addresses_to_adj(tlvs
, adj
, changed
);
3534 tlvs_protocols_supported_to_adj(tlvs
, adj
, changed
);
3535 tlvs_ipv4_addresses_to_adj(tlvs
, adj
, changed
);
3536 tlvs_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
3539 bool isis_tlvs_own_snpa_found(struct isis_tlvs
*tlvs
, uint8_t *snpa
)
3541 struct isis_lan_neighbor
*ne_head
;
3543 ne_head
= (struct isis_lan_neighbor
*)tlvs
->lan_neighbor
.head
;
3544 for (struct isis_lan_neighbor
*ne
= ne_head
; ne
; ne
= ne
->next
) {
3545 if (!memcmp(ne
->mac
, snpa
, ETH_ALEN
))
3552 void isis_tlvs_add_lsp_entry(struct isis_tlvs
*tlvs
, struct isis_lsp
*lsp
)
3554 struct isis_lsp_entry
*entry
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*entry
));
3556 entry
->rem_lifetime
= lsp
->hdr
.rem_lifetime
;
3557 memcpy(entry
->id
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 2);
3558 entry
->checksum
= lsp
->hdr
.checksum
;
3559 entry
->seqno
= lsp
->hdr
.seqno
;
3562 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)entry
);
3565 void isis_tlvs_add_csnp_entries(struct isis_tlvs
*tlvs
, uint8_t *start_id
,
3566 uint8_t *stop_id
, uint16_t num_lsps
,
3567 struct lspdb_head
*head
,
3568 struct isis_lsp
**last_lsp
)
3570 struct isis_lsp searchfor
;
3571 struct isis_lsp
*first
, *lsp
;
3573 memcpy(&searchfor
.hdr
.lsp_id
, start_id
, sizeof(searchfor
.hdr
.lsp_id
));
3574 first
= lspdb_find_gteq(head
, &searchfor
);
3578 frr_each_from (lspdb
, head
, lsp
, first
) {
3579 if (memcmp(lsp
->hdr
.lsp_id
, stop_id
, sizeof(lsp
->hdr
.lsp_id
))
3580 > 0 || tlvs
->lsp_entries
.count
== num_lsps
)
3583 isis_tlvs_add_lsp_entry(tlvs
, lsp
);
3588 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs
*tlvs
,
3589 const char *hostname
)
3591 XFREE(MTYPE_ISIS_TLV
, tlvs
->hostname
);
3593 tlvs
->hostname
= XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
3596 void isis_tlvs_set_te_router_id(struct isis_tlvs
*tlvs
,
3597 const struct in_addr
*id
)
3599 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id
);
3602 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
3603 memcpy(tlvs
->te_router_id
, id
, sizeof(*id
));
3606 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs
*tlvs
,
3607 struct prefix_ipv4
*dest
, uint8_t metric
)
3609 struct isis_oldstyle_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3612 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3613 apply_mask_ipv4(&r
->prefix
);
3614 append_item(&tlvs
->oldstyle_ip_reach
, (struct isis_item
*)r
);
3617 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs
*tlvs
,
3618 struct prefix_ipv4
*dest
, uint32_t metric
)
3620 struct isis_extended_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3623 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3624 apply_mask_ipv4(&r
->prefix
);
3625 append_item(&tlvs
->extended_ip_reach
, (struct isis_item
*)r
);
3628 void isis_tlvs_add_ipv6_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3629 struct prefix_ipv6
*dest
, uint32_t metric
)
3631 struct isis_ipv6_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3634 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3635 apply_mask_ipv6(&r
->prefix
);
3637 struct isis_item_list
*l
;
3638 l
= (mtid
== ISIS_MT_IPV4_UNICAST
)
3640 : isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
3641 append_item(l
, (struct isis_item
*)r
);
3644 void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3645 struct prefix_ipv6
*dest
,
3646 struct prefix_ipv6
*src
,
3649 isis_tlvs_add_ipv6_reach(tlvs
, mtid
, dest
, metric
);
3650 struct isis_item_list
*l
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
,
3653 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)last_item(l
);
3654 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
3655 r
->subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*src
));
3656 memcpy(r
->subtlvs
->source_prefix
, src
, sizeof(*src
));
3659 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs
*tlvs
, uint8_t *id
,
3662 struct isis_oldstyle_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3665 memcpy(r
->id
, id
, sizeof(r
->id
));
3666 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)r
);
3669 void isis_tlvs_add_extended_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3670 uint8_t *id
, uint32_t metric
,
3671 uint8_t *subtlvs
, uint8_t subtlv_len
)
3673 struct isis_extended_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3675 memcpy(r
->id
, id
, sizeof(r
->id
));
3677 if (subtlvs
&& subtlv_len
) {
3678 r
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, subtlv_len
);
3679 memcpy(r
->subtlvs
, subtlvs
, subtlv_len
);
3680 r
->subtlv_len
= subtlv_len
;
3683 struct isis_item_list
*l
;
3684 if (mtid
== ISIS_MT_IPV4_UNICAST
)
3685 l
= &tlvs
->extended_reach
;
3687 l
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
3688 append_item(l
, (struct isis_item
*)r
);
3691 void isis_tlvs_add_threeway_adj(struct isis_tlvs
*tlvs
,
3692 enum isis_threeway_state state
,
3693 uint32_t local_circuit_id
,
3694 const uint8_t *neighbor_id
,
3695 uint32_t neighbor_circuit_id
)
3697 assert(!tlvs
->threeway_adj
);
3699 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
3700 tlvs
->threeway_adj
->state
= state
;
3701 tlvs
->threeway_adj
->local_circuit_id
= local_circuit_id
;
3704 tlvs
->threeway_adj
->neighbor_set
= true;
3705 memcpy(tlvs
->threeway_adj
->neighbor_id
, neighbor_id
, 6);
3706 tlvs
->threeway_adj
->neighbor_circuit_id
= neighbor_circuit_id
;
3710 void isis_tlvs_add_spine_leaf(struct isis_tlvs
*tlvs
, uint8_t tier
,
3711 bool has_tier
, bool is_leaf
, bool is_spine
,
3714 assert(!tlvs
->spine_leaf
);
3716 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
3719 tlvs
->spine_leaf
->tier
= tier
;
3722 tlvs
->spine_leaf
->has_tier
= has_tier
;
3723 tlvs
->spine_leaf
->is_leaf
= is_leaf
;
3724 tlvs
->spine_leaf
->is_spine
= is_spine
;
3725 tlvs
->spine_leaf
->is_backup
= is_backup
;
3728 struct isis_mt_router_info
*
3729 isis_tlvs_lookup_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
)
3731 if (tlvs
->mt_router_info_empty
)
3734 struct isis_mt_router_info
*rv
;
3735 for (rv
= (struct isis_mt_router_info
*)tlvs
->mt_router_info
.head
; rv
;
3737 if (rv
->mtid
== mtid
)
3744 void isis_tlvs_set_purge_originator(struct isis_tlvs
*tlvs
,
3745 const uint8_t *generator
,
3746 const uint8_t *sender
)
3748 assert(!tlvs
->purge_originator
);
3750 tlvs
->purge_originator
= XCALLOC(MTYPE_ISIS_TLV
,
3751 sizeof(*tlvs
->purge_originator
));
3752 memcpy(tlvs
->purge_originator
->generator
, generator
,
3753 sizeof(tlvs
->purge_originator
->generator
));
3755 tlvs
->purge_originator
->sender_set
= true;
3756 memcpy(tlvs
->purge_originator
->sender
, sender
,
3757 sizeof(tlvs
->purge_originator
->sender
));