2 * IS-IS TLV Serializer/Deserializer
4 * Copyright (C) 2015,2017 Christian Franke
6 * This file is part of FRR.
8 * FRR is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
13 * FRR is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with FRR; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
30 #include "isisd/isisd.h"
31 #include "isisd/isis_memory.h"
32 #include "isisd/isis_tlvs.h"
33 #include "isisd/isis_common.h"
34 #include "isisd/isis_mt.h"
35 #include "isisd/isis_misc.h"
36 #include "isisd/isis_adjacency.h"
37 #include "isisd/isis_circuit.h"
38 #include "isisd/isis_pdu.h"
39 #include "isisd/isis_lsp.h"
40 #include "isisd/isis_te.h"
42 DEFINE_MTYPE_STATIC(ISISD
, ISIS_TLV
, "ISIS TLVs")
43 DEFINE_MTYPE_STATIC(ISISD
, ISIS_SUBTLV
, "ISIS Sub-TLVs")
44 DEFINE_MTYPE_STATIC(ISISD
, ISIS_MT_ITEM_LIST
, "ISIS MT Item Lists")
46 typedef int (*unpack_tlv_func
)(enum isis_tlv_context context
, uint8_t tlv_type
,
47 uint8_t tlv_len
, struct stream
*s
,
48 struct sbuf
*log
, void *dest
, int indent
);
49 typedef int (*pack_item_func
)(struct isis_item
*item
, struct stream
*s
);
50 typedef void (*free_item_func
)(struct isis_item
*i
);
51 typedef int (*unpack_item_func
)(uint16_t mtid
, uint8_t len
, struct stream
*s
,
52 struct sbuf
*log
, void *dest
, int indent
);
53 typedef void (*format_item_func
)(uint16_t mtid
, struct isis_item
*i
,
54 struct sbuf
*buf
, int indent
);
55 typedef struct isis_item
*(*copy_item_func
)(struct isis_item
*i
);
59 unpack_tlv_func unpack
;
61 pack_item_func pack_item
;
62 free_item_func free_item
;
63 unpack_item_func unpack_item
;
64 format_item_func format_item
;
65 copy_item_func copy_item
;
73 struct pack_order_entry
{
74 enum isis_tlv_context context
;
75 enum isis_tlv_type type
;
76 enum how_to_pack how_to_pack
;
79 #define PACK_ENTRY(t, h, w) \
81 .context = ISIS_CONTEXT_LSP, .type = ISIS_TLV_##t, \
83 .what_to_pack = offsetof(struct isis_tlvs, w), \
86 static struct pack_order_entry pack_order
[] = {
87 PACK_ENTRY(OLDSTYLE_REACH
, ISIS_ITEMS
, oldstyle_reach
),
88 PACK_ENTRY(LAN_NEIGHBORS
, ISIS_ITEMS
, lan_neighbor
),
89 PACK_ENTRY(LSP_ENTRY
, ISIS_ITEMS
, lsp_entries
),
90 PACK_ENTRY(EXTENDED_REACH
, ISIS_ITEMS
, extended_reach
),
91 PACK_ENTRY(MT_REACH
, ISIS_MT_ITEMS
, mt_reach
),
92 PACK_ENTRY(OLDSTYLE_IP_REACH
, ISIS_ITEMS
, oldstyle_ip_reach
),
93 PACK_ENTRY(OLDSTYLE_IP_REACH_EXT
, ISIS_ITEMS
, oldstyle_ip_reach_ext
),
94 PACK_ENTRY(IPV4_ADDRESS
, ISIS_ITEMS
, ipv4_address
),
95 PACK_ENTRY(IPV6_ADDRESS
, ISIS_ITEMS
, ipv6_address
),
96 PACK_ENTRY(EXTENDED_IP_REACH
, ISIS_ITEMS
, extended_ip_reach
),
97 PACK_ENTRY(MT_IP_REACH
, ISIS_MT_ITEMS
, mt_ip_reach
),
98 PACK_ENTRY(IPV6_REACH
, ISIS_ITEMS
, ipv6_reach
),
99 PACK_ENTRY(MT_IPV6_REACH
, ISIS_MT_ITEMS
, mt_ipv6_reach
)};
101 /* This is a forward definition. The table is actually initialized
102 * in at the bottom. */
103 static const struct tlv_ops
*tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
];
105 /* End of _ops forward definition. */
108 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
);
110 /* Functions for Sub-TLV 3 SR Prefix-SID */
112 static struct isis_item
*copy_item_prefix_sid(struct isis_item
*i
)
114 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
115 struct isis_prefix_sid
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
117 rv
->flags
= sid
->flags
;
118 rv
->algorithm
= sid
->algorithm
;
119 rv
->value
= sid
->value
;
120 return (struct isis_item
*)rv
;
123 static void format_item_prefix_sid(uint16_t mtid
, struct isis_item
*i
,
124 struct sbuf
*buf
, int indent
)
126 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
128 sbuf_push(buf
, indent
, "SR Prefix-SID:\n");
129 sbuf_push(buf
, indent
, " Flags:%s%s%s%s%s%s\n",
130 sid
->flags
& ISIS_PREFIX_SID_READVERTISED
? " READVERTISED" : "",
131 sid
->flags
& ISIS_PREFIX_SID_NODE
? " NODE" : "",
132 sid
->flags
& ISIS_PREFIX_SID_NO_PHP
? " NO_PHP" : "",
133 sid
->flags
& ISIS_PREFIX_SID_EXPLICIT_NULL
? " EXPLICIT-NULL" : "",
134 sid
->flags
& ISIS_PREFIX_SID_VALUE
? " VALUE" : "",
135 sid
->flags
& ISIS_PREFIX_SID_LOCAL
? " LOCAL" : "");
136 sbuf_push(buf
, indent
, " Algorithm: %" PRIu8
"\n", sid
->algorithm
);
137 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
138 sbuf_push(buf
, indent
, "Label: %" PRIu32
"\n", sid
->value
);
140 sbuf_push(buf
, indent
, "Index: %" PRIu32
"\n", sid
->value
);
144 static void free_item_prefix_sid(struct isis_item
*i
)
146 XFREE(MTYPE_ISIS_SUBTLV
, i
);
149 static int pack_item_prefix_sid(struct isis_item
*i
, struct stream
*s
)
151 struct isis_prefix_sid
*sid
= (struct isis_prefix_sid
*)i
;
153 uint8_t size
= (sid
->flags
& ISIS_PREFIX_SID_VALUE
) ? 5 : 6;
155 if (STREAM_WRITEABLE(s
) < size
)
158 stream_putc(s
, sid
->flags
);
159 stream_putc(s
, sid
->algorithm
);
161 if (sid
->flags
& ISIS_PREFIX_SID_VALUE
) {
162 stream_put3(s
, sid
->value
);
164 stream_putl(s
, sid
->value
);
170 static int unpack_item_prefix_sid(uint16_t mtid
, uint8_t len
, struct stream
*s
,
171 struct sbuf
*log
, void *dest
, int indent
)
173 struct isis_subtlvs
*subtlvs
= dest
;
174 struct isis_prefix_sid sid
= {0};
176 sbuf_push(log
, indent
, "Unpacking SR Prefix-SID...\n");
179 sbuf_push(log
, indent
,
180 "Not enough data left. (expected 5 or more bytes, got %" PRIu8
")\n",
185 sid
.flags
= stream_getc(s
);
186 if ((sid
.flags
& ISIS_PREFIX_SID_VALUE
)
187 != (sid
.flags
& ISIS_PREFIX_SID_LOCAL
)) {
188 sbuf_push(log
, indent
, "Flags inplausible: Local Flag needs to match Value Flag\n");
192 sid
.algorithm
= stream_getc(s
);
194 uint8_t expected_size
= (sid
.flags
& ISIS_PREFIX_SID_VALUE
) ? 5 : 6;
195 if (len
!= expected_size
) {
196 sbuf_push(log
, indent
,
197 "TLV size differs from expected size. "
198 "(expected %u but got %" PRIu8
")\n",
203 if (sid
.flags
& ISIS_PREFIX_SID_VALUE
) {
204 sid
.value
= stream_get3(s
);
206 sid
.value
= stream_getl(s
);
209 format_item_prefix_sid(mtid
, (struct isis_item
*)&sid
, log
, indent
+ 2);
210 append_item(&subtlvs
->prefix_sids
, copy_item_prefix_sid((struct isis_item
*)&sid
));
214 /* Functions for Sub-TVL ??? IPv6 Source Prefix */
216 static struct prefix_ipv6
*copy_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
)
221 struct prefix_ipv6
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
222 rv
->family
= p
->family
;
223 rv
->prefixlen
= p
->prefixlen
;
224 memcpy(&rv
->prefix
, &p
->prefix
, sizeof(rv
->prefix
));
228 static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
229 struct sbuf
*buf
, int indent
)
234 char prefixbuf
[PREFIX2STR_BUFFER
];
235 sbuf_push(buf
, indent
, "IPv6 Source Prefix: %s\n",
236 prefix2str(p
, prefixbuf
, sizeof(prefixbuf
)));
239 static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6
*p
,
245 if (STREAM_WRITEABLE(s
) < 3 + (unsigned)PSIZE(p
->prefixlen
))
248 stream_putc(s
, ISIS_SUBTLV_IPV6_SOURCE_PREFIX
);
249 stream_putc(s
, 1 + PSIZE(p
->prefixlen
));
250 stream_putc(s
, p
->prefixlen
);
251 stream_put(s
, &p
->prefix
, PSIZE(p
->prefixlen
));
255 static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context
,
256 uint8_t tlv_type
, uint8_t tlv_len
,
257 struct stream
*s
, struct sbuf
*log
,
258 void *dest
, int indent
)
260 struct isis_subtlvs
*subtlvs
= dest
;
261 struct prefix_ipv6 p
= {
265 sbuf_push(log
, indent
, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
268 sbuf_push(log
, indent
,
269 "Not enough data left. (expected 1 or more bytes, got %" PRIu8
")\n",
274 p
.prefixlen
= stream_getc(s
);
275 if (p
.prefixlen
> 128) {
276 sbuf_push(log
, indent
, "Prefixlen %u is inplausible for IPv6\n",
281 if (tlv_len
!= 1 + PSIZE(p
.prefixlen
)) {
284 "TLV size differs from expected size for the prefixlen. "
285 "(expected %u but got %" PRIu8
")\n",
286 1 + PSIZE(p
.prefixlen
), tlv_len
);
290 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
292 if (subtlvs
->source_prefix
) {
295 "WARNING: source prefix Sub-TLV present multiple times.\n");
296 /* Ignore all but first occurrence of the source prefix Sub-TLV
301 subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(p
));
302 memcpy(subtlvs
->source_prefix
, &p
, sizeof(p
));
305 static void init_item_list(struct isis_item_list
*items
);
306 static struct isis_item
*copy_item(enum isis_tlv_context context
,
307 enum isis_tlv_type type
,
308 struct isis_item
*item
);
309 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
310 struct isis_item_list
*src
, struct isis_item_list
*dest
);
311 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
312 enum isis_tlv_type type
, struct isis_item_list
*items
,
313 struct sbuf
*buf
, int indent
);
314 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
315 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
316 struct isis_item_list
*items
);
317 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
318 enum isis_tlv_type type
, struct isis_item_list
*items
,
319 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
320 struct pack_order_entry
*pe
,
321 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
322 struct list
*new_fragment_arg
);
323 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
325 /* Functions related to subtlvs */
327 static struct isis_subtlvs
*isis_alloc_subtlvs(enum isis_tlv_context context
)
329 struct isis_subtlvs
*result
;
331 result
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*result
));
332 result
->context
= context
;
334 init_item_list(&result
->prefix_sids
);
339 static struct isis_subtlvs
*copy_subtlvs(struct isis_subtlvs
*subtlvs
)
344 struct isis_subtlvs
*rv
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*rv
));
346 rv
->context
= subtlvs
->context
;
348 copy_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
349 &subtlvs
->prefix_sids
, &rv
->prefix_sids
);
352 copy_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
);
356 static void format_subtlvs(struct isis_subtlvs
*subtlvs
, struct sbuf
*buf
,
359 format_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
360 &subtlvs
->prefix_sids
, buf
, indent
);
362 format_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, buf
, indent
);
365 static void isis_free_subtlvs(struct isis_subtlvs
*subtlvs
)
370 free_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
371 &subtlvs
->prefix_sids
);
373 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
->source_prefix
);
375 XFREE(MTYPE_ISIS_SUBTLV
, subtlvs
);
378 static int pack_subtlvs(struct isis_subtlvs
*subtlvs
, struct stream
*s
)
381 size_t subtlv_len_pos
= stream_get_endp(s
);
383 if (STREAM_WRITEABLE(s
) < 1)
386 stream_putc(s
, 0); /* Put 0 as subtlvs length, filled in later */
388 rv
= pack_items(subtlvs
->context
, ISIS_SUBTLV_PREFIX_SID
,
389 &subtlvs
->prefix_sids
, s
, NULL
, NULL
, NULL
, NULL
);
393 rv
= pack_subtlv_ipv6_source_prefix(subtlvs
->source_prefix
, s
);
397 size_t subtlv_len
= stream_get_endp(s
) - subtlv_len_pos
- 1;
398 if (subtlv_len
> 255)
401 stream_putc_at(s
, subtlv_len_pos
, subtlv_len
);
405 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
406 struct stream
*stream
, struct sbuf
*log
, void *dest
,
409 /* Functions related to TLVs 1 Area Addresses */
411 static struct isis_item
*copy_item_area_address(struct isis_item
*i
)
413 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
414 struct isis_area_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
417 memcpy(rv
->addr
, addr
->addr
, addr
->len
);
418 return (struct isis_item
*)rv
;
421 static void format_item_area_address(uint16_t mtid
, struct isis_item
*i
,
422 struct sbuf
*buf
, int indent
)
424 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
426 sbuf_push(buf
, indent
, "Area Address: %s\n",
427 isonet_print(addr
->addr
, addr
->len
));
430 static void free_item_area_address(struct isis_item
*i
)
432 XFREE(MTYPE_ISIS_TLV
, i
);
435 static int pack_item_area_address(struct isis_item
*i
, struct stream
*s
)
437 struct isis_area_address
*addr
= (struct isis_area_address
*)i
;
439 if (STREAM_WRITEABLE(s
) < (unsigned)1 + addr
->len
)
441 stream_putc(s
, addr
->len
);
442 stream_put(s
, addr
->addr
, addr
->len
);
446 static int unpack_item_area_address(uint16_t mtid
, uint8_t len
,
447 struct stream
*s
, struct sbuf
*log
,
448 void *dest
, int indent
)
450 struct isis_tlvs
*tlvs
= dest
;
451 struct isis_area_address
*rv
= NULL
;
453 sbuf_push(log
, indent
, "Unpack area address...\n");
457 "Not enough data left. (Expected 1 byte of address length, got %" PRIu8
463 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
464 rv
->len
= stream_getc(s
);
466 if (len
< 1 + rv
->len
) {
467 sbuf_push(log
, indent
, "Not enough data left. (Expected %" PRIu8
468 " bytes of address, got %" PRIu8
")\n",
473 if (rv
->len
< 1 || rv
->len
> 20) {
474 sbuf_push(log
, indent
,
475 "Implausible area address length %" PRIu8
"\n",
480 stream_get(rv
->addr
, s
, rv
->len
);
482 format_item_area_address(ISIS_MT_IPV4_UNICAST
, (struct isis_item
*)rv
,
484 append_item(&tlvs
->area_addresses
, (struct isis_item
*)rv
);
487 XFREE(MTYPE_ISIS_TLV
, rv
);
491 /* Functions related to TLV 2 (Old-Style) IS Reach */
492 static struct isis_item
*copy_item_oldstyle_reach(struct isis_item
*i
)
494 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
495 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
497 memcpy(rv
->id
, r
->id
, 7);
498 rv
->metric
= r
->metric
;
499 return (struct isis_item
*)rv
;
502 static void format_item_oldstyle_reach(uint16_t mtid
, struct isis_item
*i
,
503 struct sbuf
*buf
, int indent
)
505 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
507 sbuf_push(buf
, indent
, "IS Reachability: %s (Metric: %" PRIu8
")\n",
508 isis_format_id(r
->id
, 7), r
->metric
);
511 static void free_item_oldstyle_reach(struct isis_item
*i
)
513 XFREE(MTYPE_ISIS_TLV
, i
);
516 static int pack_item_oldstyle_reach(struct isis_item
*i
, struct stream
*s
)
518 struct isis_oldstyle_reach
*r
= (struct isis_oldstyle_reach
*)i
;
520 if (STREAM_WRITEABLE(s
) < 11)
523 stream_putc(s
, r
->metric
);
524 stream_putc(s
, 0x80); /* delay metric - unsupported */
525 stream_putc(s
, 0x80); /* expense metric - unsupported */
526 stream_putc(s
, 0x80); /* error metric - unsupported */
527 stream_put(s
, r
->id
, 7);
532 static int unpack_item_oldstyle_reach(uint16_t mtid
, uint8_t len
,
533 struct stream
*s
, struct sbuf
*log
,
534 void *dest
, int indent
)
536 struct isis_tlvs
*tlvs
= dest
;
538 sbuf_push(log
, indent
, "Unpack oldstyle reach...\n");
542 "Not enough data left.(Expected 11 bytes of reach information, got %" PRIu8
548 struct isis_oldstyle_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
549 rv
->metric
= stream_getc(s
);
550 if ((rv
->metric
& 0x3f) != rv
->metric
) {
551 sbuf_push(log
, indent
, "Metric has unplausible format\n");
554 stream_forward_getp(s
, 3); /* Skip other metrics */
555 stream_get(rv
->id
, s
, 7);
557 format_item_oldstyle_reach(mtid
, (struct isis_item
*)rv
, log
,
559 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)rv
);
563 /* Functions related to TLV 6 LAN Neighbors */
564 static struct isis_item
*copy_item_lan_neighbor(struct isis_item
*i
)
566 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
567 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
569 memcpy(rv
->mac
, n
->mac
, 6);
570 return (struct isis_item
*)rv
;
573 static void format_item_lan_neighbor(uint16_t mtid
, struct isis_item
*i
,
574 struct sbuf
*buf
, int indent
)
576 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
578 sbuf_push(buf
, indent
, "LAN Neighbor: %s\n", isis_format_id(n
->mac
, 6));
581 static void free_item_lan_neighbor(struct isis_item
*i
)
583 XFREE(MTYPE_ISIS_TLV
, i
);
586 static int pack_item_lan_neighbor(struct isis_item
*i
, struct stream
*s
)
588 struct isis_lan_neighbor
*n
= (struct isis_lan_neighbor
*)i
;
590 if (STREAM_WRITEABLE(s
) < 6)
593 stream_put(s
, n
->mac
, 6);
598 static int unpack_item_lan_neighbor(uint16_t mtid
, uint8_t len
,
599 struct stream
*s
, struct sbuf
*log
,
600 void *dest
, int indent
)
602 struct isis_tlvs
*tlvs
= dest
;
604 sbuf_push(log
, indent
, "Unpack LAN neighbor...\n");
608 "Not enough data left.(Expected 6 bytes of mac, got %" PRIu8
614 struct isis_lan_neighbor
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
615 stream_get(rv
->mac
, s
, 6);
617 format_item_lan_neighbor(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
618 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)rv
);
622 /* Functions related to TLV 9 LSP Entry */
623 static struct isis_item
*copy_item_lsp_entry(struct isis_item
*i
)
625 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
626 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
628 rv
->rem_lifetime
= e
->rem_lifetime
;
629 memcpy(rv
->id
, e
->id
, sizeof(rv
->id
));
630 rv
->seqno
= e
->seqno
;
631 rv
->checksum
= e
->checksum
;
633 return (struct isis_item
*)rv
;
636 static void format_item_lsp_entry(uint16_t mtid
, struct isis_item
*i
,
637 struct sbuf
*buf
, int indent
)
639 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
641 sbuf_push(buf
, indent
,
642 "LSP Entry: %s, seq 0x%08" PRIx32
", cksum 0x%04" PRIx16
643 ", lifetime %" PRIu16
"s\n",
644 isis_format_id(e
->id
, 8), e
->seqno
, e
->checksum
,
648 static void free_item_lsp_entry(struct isis_item
*i
)
650 XFREE(MTYPE_ISIS_TLV
, i
);
653 static int pack_item_lsp_entry(struct isis_item
*i
, struct stream
*s
)
655 struct isis_lsp_entry
*e
= (struct isis_lsp_entry
*)i
;
657 if (STREAM_WRITEABLE(s
) < 16)
660 stream_putw(s
, e
->rem_lifetime
);
661 stream_put(s
, e
->id
, 8);
662 stream_putl(s
, e
->seqno
);
663 stream_putw(s
, e
->checksum
);
668 static int unpack_item_lsp_entry(uint16_t mtid
, uint8_t len
, struct stream
*s
,
669 struct sbuf
*log
, void *dest
, int indent
)
671 struct isis_tlvs
*tlvs
= dest
;
673 sbuf_push(log
, indent
, "Unpack LSP entry...\n");
677 "Not enough data left. (Expected 16 bytes of LSP info, got %" PRIu8
,
682 struct isis_lsp_entry
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
683 rv
->rem_lifetime
= stream_getw(s
);
684 stream_get(rv
->id
, s
, 8);
685 rv
->seqno
= stream_getl(s
);
686 rv
->checksum
= stream_getw(s
);
688 format_item_lsp_entry(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
689 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)rv
);
693 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
695 static struct isis_item
*copy_item_extended_reach(struct isis_item
*i
)
697 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
698 struct isis_extended_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
700 memcpy(rv
->id
, r
->id
, 7);
701 rv
->metric
= r
->metric
;
703 if (r
->subtlvs
&& r
->subtlv_len
) {
704 rv
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, r
->subtlv_len
);
705 memcpy(rv
->subtlvs
, r
->subtlvs
, r
->subtlv_len
);
706 rv
->subtlv_len
= r
->subtlv_len
;
709 return (struct isis_item
*)rv
;
712 static void format_item_extended_reach(uint16_t mtid
, struct isis_item
*i
,
713 struct sbuf
*buf
, int indent
)
715 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
717 sbuf_push(buf
, indent
, "%s Reachability: %s (Metric: %u)",
718 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
719 isis_format_id(r
->id
, 7), r
->metric
);
720 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
721 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
722 sbuf_push(buf
, 0, "\n");
724 if (r
->subtlv_len
&& r
->subtlvs
)
725 mpls_te_print_detail(buf
, indent
+ 2, r
->subtlvs
,
729 static void free_item_extended_reach(struct isis_item
*i
)
731 struct isis_extended_reach
*item
= (struct isis_extended_reach
*)i
;
732 XFREE(MTYPE_ISIS_TLV
, item
->subtlvs
);
733 XFREE(MTYPE_ISIS_TLV
, item
);
736 static int pack_item_extended_reach(struct isis_item
*i
, struct stream
*s
)
738 struct isis_extended_reach
*r
= (struct isis_extended_reach
*)i
;
740 if (STREAM_WRITEABLE(s
) < 11 + (unsigned)r
->subtlv_len
)
742 stream_put(s
, r
->id
, sizeof(r
->id
));
743 stream_put3(s
, r
->metric
);
744 stream_putc(s
, r
->subtlv_len
);
745 stream_put(s
, r
->subtlvs
, r
->subtlv_len
);
749 static int unpack_item_extended_reach(uint16_t mtid
, uint8_t len
,
750 struct stream
*s
, struct sbuf
*log
,
751 void *dest
, int indent
)
753 struct isis_tlvs
*tlvs
= dest
;
754 struct isis_extended_reach
*rv
= NULL
;
756 struct isis_item_list
*items
;
758 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
759 items
= &tlvs
->extended_reach
;
761 items
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
764 sbuf_push(log
, indent
, "Unpacking %s reachability...\n",
765 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
768 sbuf_push(log
, indent
,
769 "Not enough data left. (expected 11 or more bytes, got %"
775 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
776 stream_get(rv
->id
, s
, 7);
777 rv
->metric
= stream_get3(s
);
778 subtlv_len
= stream_getc(s
);
780 format_item_extended_reach(mtid
, (struct isis_item
*)rv
, log
,
783 if ((size_t)len
< ((size_t)11) + subtlv_len
) {
784 sbuf_push(log
, indent
,
785 "Not enough data left for subtlv size %" PRIu8
786 ", there are only %" PRIu8
" bytes left.\n",
787 subtlv_len
, len
- 11);
791 sbuf_push(log
, indent
, "Storing %" PRIu8
" bytes of subtlvs\n",
795 size_t subtlv_start
= stream_get_getp(s
);
797 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_NE_REACH
, subtlv_len
, s
,
798 log
, NULL
, indent
+ 4)) {
802 stream_set_getp(s
, subtlv_start
);
804 rv
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, subtlv_len
);
805 stream_get(rv
->subtlvs
, s
, subtlv_len
);
806 rv
->subtlv_len
= subtlv_len
;
809 append_item(items
, (struct isis_item
*)rv
);
813 free_item_extended_reach((struct isis_item
*)rv
);
818 /* Functions related to TLV 128 (Old-Style) IP Reach */
819 static struct isis_item
*copy_item_oldstyle_ip_reach(struct isis_item
*i
)
821 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
822 struct isis_oldstyle_ip_reach
*rv
=
823 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
825 rv
->metric
= r
->metric
;
826 rv
->prefix
= r
->prefix
;
827 return (struct isis_item
*)rv
;
830 static void format_item_oldstyle_ip_reach(uint16_t mtid
, struct isis_item
*i
,
831 struct sbuf
*buf
, int indent
)
833 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
834 char prefixbuf
[PREFIX2STR_BUFFER
];
836 sbuf_push(buf
, indent
, "IP Reachability: %s (Metric: %" PRIu8
")\n",
837 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
841 static void free_item_oldstyle_ip_reach(struct isis_item
*i
)
843 XFREE(MTYPE_ISIS_TLV
, i
);
846 static int pack_item_oldstyle_ip_reach(struct isis_item
*i
, struct stream
*s
)
848 struct isis_oldstyle_ip_reach
*r
= (struct isis_oldstyle_ip_reach
*)i
;
850 if (STREAM_WRITEABLE(s
) < 12)
853 stream_putc(s
, r
->metric
);
854 stream_putc(s
, 0x80); /* delay metric - unsupported */
855 stream_putc(s
, 0x80); /* expense metric - unsupported */
856 stream_putc(s
, 0x80); /* error metric - unsupported */
857 stream_put(s
, &r
->prefix
.prefix
, 4);
860 masklen2ip(r
->prefix
.prefixlen
, &mask
);
861 stream_put(s
, &mask
, sizeof(mask
));
866 static int unpack_item_oldstyle_ip_reach(uint16_t mtid
, uint8_t len
,
867 struct stream
*s
, struct sbuf
*log
,
868 void *dest
, int indent
)
870 sbuf_push(log
, indent
, "Unpack oldstyle ip reach...\n");
874 "Not enough data left.(Expected 12 bytes of reach information, got %" PRIu8
880 struct isis_oldstyle_ip_reach
*rv
=
881 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
882 rv
->metric
= stream_getc(s
);
883 if ((rv
->metric
& 0x7f) != rv
->metric
) {
884 sbuf_push(log
, indent
, "Metric has unplausible format\n");
887 stream_forward_getp(s
, 3); /* Skip other metrics */
888 rv
->prefix
.family
= AF_INET
;
889 stream_get(&rv
->prefix
.prefix
, s
, 4);
892 stream_get(&mask
, s
, 4);
893 rv
->prefix
.prefixlen
= ip_masklen(mask
);
895 format_item_oldstyle_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
897 append_item(dest
, (struct isis_item
*)rv
);
902 /* Functions related to TLV 129 protocols supported */
904 static void copy_tlv_protocols_supported(struct isis_protocols_supported
*src
,
905 struct isis_protocols_supported
*dest
)
907 if (!src
->protocols
|| !src
->count
)
909 dest
->count
= src
->count
;
910 dest
->protocols
= XCALLOC(MTYPE_ISIS_TLV
, src
->count
);
911 memcpy(dest
->protocols
, src
->protocols
, src
->count
);
914 static void format_tlv_protocols_supported(struct isis_protocols_supported
*p
,
915 struct sbuf
*buf
, int indent
)
917 if (!p
|| !p
->count
|| !p
->protocols
)
920 sbuf_push(buf
, indent
, "Protocols Supported: ");
921 for (uint8_t i
= 0; i
< p
->count
; i
++) {
922 sbuf_push(buf
, 0, "%s%s", nlpid2str(p
->protocols
[i
]),
923 (i
+ 1 < p
->count
) ? ", " : "");
925 sbuf_push(buf
, 0, "\n");
928 static void free_tlv_protocols_supported(struct isis_protocols_supported
*p
)
930 XFREE(MTYPE_ISIS_TLV
, p
->protocols
);
933 static int pack_tlv_protocols_supported(struct isis_protocols_supported
*p
,
936 if (!p
|| !p
->count
|| !p
->protocols
)
939 if (STREAM_WRITEABLE(s
) < (unsigned)(p
->count
+ 2))
942 stream_putc(s
, ISIS_TLV_PROTOCOLS_SUPPORTED
);
943 stream_putc(s
, p
->count
);
944 stream_put(s
, p
->protocols
, p
->count
);
948 static int unpack_tlv_protocols_supported(enum isis_tlv_context context
,
949 uint8_t tlv_type
, uint8_t tlv_len
,
950 struct stream
*s
, struct sbuf
*log
,
951 void *dest
, int indent
)
953 struct isis_tlvs
*tlvs
= dest
;
955 sbuf_push(log
, indent
, "Unpacking Protocols Supported TLV...\n");
957 sbuf_push(log
, indent
, "WARNING: No protocols included\n");
960 if (tlvs
->protocols_supported
.protocols
) {
963 "WARNING: protocols supported TLV present multiple times.\n");
964 stream_forward_getp(s
, tlv_len
);
968 tlvs
->protocols_supported
.count
= tlv_len
;
969 tlvs
->protocols_supported
.protocols
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
);
970 stream_get(tlvs
->protocols_supported
.protocols
, s
, tlv_len
);
972 format_tlv_protocols_supported(&tlvs
->protocols_supported
, log
,
977 /* Functions related to TLV 132 IPv4 Interface addresses */
978 static struct isis_item
*copy_item_ipv4_address(struct isis_item
*i
)
980 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
981 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
984 return (struct isis_item
*)rv
;
987 static void format_item_ipv4_address(uint16_t mtid
, struct isis_item
*i
,
988 struct sbuf
*buf
, int indent
)
990 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
991 char addrbuf
[INET_ADDRSTRLEN
];
993 inet_ntop(AF_INET
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
994 sbuf_push(buf
, indent
, "IPv4 Interface Address: %s\n", addrbuf
);
997 static void free_item_ipv4_address(struct isis_item
*i
)
999 XFREE(MTYPE_ISIS_TLV
, i
);
1002 static int pack_item_ipv4_address(struct isis_item
*i
, struct stream
*s
)
1004 struct isis_ipv4_address
*a
= (struct isis_ipv4_address
*)i
;
1006 if (STREAM_WRITEABLE(s
) < 4)
1009 stream_put(s
, &a
->addr
, 4);
1014 static int unpack_item_ipv4_address(uint16_t mtid
, uint8_t len
,
1015 struct stream
*s
, struct sbuf
*log
,
1016 void *dest
, int indent
)
1018 struct isis_tlvs
*tlvs
= dest
;
1020 sbuf_push(log
, indent
, "Unpack IPv4 Interface address...\n");
1024 "Not enough data left.(Expected 4 bytes of IPv4 address, got %" PRIu8
1030 struct isis_ipv4_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1031 stream_get(&rv
->addr
, s
, 4);
1033 format_item_ipv4_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1034 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)rv
);
1039 /* Functions related to TLV 232 IPv6 Interface addresses */
1040 static struct isis_item
*copy_item_ipv6_address(struct isis_item
*i
)
1042 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1043 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1046 return (struct isis_item
*)rv
;
1049 static void format_item_ipv6_address(uint16_t mtid
, struct isis_item
*i
,
1050 struct sbuf
*buf
, int indent
)
1052 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1053 char addrbuf
[INET6_ADDRSTRLEN
];
1055 inet_ntop(AF_INET6
, &a
->addr
, addrbuf
, sizeof(addrbuf
));
1056 sbuf_push(buf
, indent
, "IPv6 Interface Address: %s\n", addrbuf
);
1059 static void free_item_ipv6_address(struct isis_item
*i
)
1061 XFREE(MTYPE_ISIS_TLV
, i
);
1064 static int pack_item_ipv6_address(struct isis_item
*i
, struct stream
*s
)
1066 struct isis_ipv6_address
*a
= (struct isis_ipv6_address
*)i
;
1068 if (STREAM_WRITEABLE(s
) < 16)
1071 stream_put(s
, &a
->addr
, 16);
1076 static int unpack_item_ipv6_address(uint16_t mtid
, uint8_t len
,
1077 struct stream
*s
, struct sbuf
*log
,
1078 void *dest
, int indent
)
1080 struct isis_tlvs
*tlvs
= dest
;
1082 sbuf_push(log
, indent
, "Unpack IPv6 Interface address...\n");
1086 "Not enough data left.(Expected 16 bytes of IPv6 address, got %" PRIu8
1092 struct isis_ipv6_address
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1093 stream_get(&rv
->addr
, s
, 16);
1095 format_item_ipv6_address(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1096 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)rv
);
1101 /* Functions related to TLV 229 MT Router information */
1102 static struct isis_item
*copy_item_mt_router_info(struct isis_item
*i
)
1104 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1105 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1107 rv
->overload
= info
->overload
;
1108 rv
->attached
= info
->attached
;
1109 rv
->mtid
= info
->mtid
;
1110 return (struct isis_item
*)rv
;
1113 static void format_item_mt_router_info(uint16_t mtid
, struct isis_item
*i
,
1114 struct sbuf
*buf
, int indent
)
1116 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1118 sbuf_push(buf
, indent
, "MT Router Info: %s%s%s\n",
1119 isis_mtid2str(info
->mtid
),
1120 info
->overload
? " Overload" : "",
1121 info
->attached
? " Attached" : "");
1124 static void free_item_mt_router_info(struct isis_item
*i
)
1126 XFREE(MTYPE_ISIS_TLV
, i
);
1129 static int pack_item_mt_router_info(struct isis_item
*i
, struct stream
*s
)
1131 struct isis_mt_router_info
*info
= (struct isis_mt_router_info
*)i
;
1133 if (STREAM_WRITEABLE(s
) < 2)
1136 uint16_t entry
= info
->mtid
;
1139 entry
|= ISIS_MT_OL_MASK
;
1141 entry
|= ISIS_MT_AT_MASK
;
1143 stream_putw(s
, entry
);
1148 static int unpack_item_mt_router_info(uint16_t mtid
, uint8_t len
,
1149 struct stream
*s
, struct sbuf
*log
,
1150 void *dest
, int indent
)
1152 struct isis_tlvs
*tlvs
= dest
;
1154 sbuf_push(log
, indent
, "Unpack MT Router info...\n");
1158 "Not enough data left.(Expected 2 bytes of MT info, got %" PRIu8
1164 struct isis_mt_router_info
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1166 uint16_t entry
= stream_getw(s
);
1167 rv
->overload
= entry
& ISIS_MT_OL_MASK
;
1168 rv
->attached
= entry
& ISIS_MT_AT_MASK
;
1169 rv
->mtid
= entry
& ISIS_MT_MASK
;
1171 format_item_mt_router_info(mtid
, (struct isis_item
*)rv
, log
,
1173 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)rv
);
1177 /* Functions related to TLV 134 TE Router ID */
1179 static struct in_addr
*copy_tlv_te_router_id(const struct in_addr
*id
)
1184 struct in_addr
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1185 memcpy(rv
, id
, sizeof(*rv
));
1189 static void format_tlv_te_router_id(const struct in_addr
*id
, struct sbuf
*buf
,
1195 char addrbuf
[INET_ADDRSTRLEN
];
1196 inet_ntop(AF_INET
, id
, addrbuf
, sizeof(addrbuf
));
1197 sbuf_push(buf
, indent
, "TE Router ID: %s\n", addrbuf
);
1200 static void free_tlv_te_router_id(struct in_addr
*id
)
1202 XFREE(MTYPE_ISIS_TLV
, id
);
1205 static int pack_tlv_te_router_id(const struct in_addr
*id
, struct stream
*s
)
1210 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + sizeof(*id
)))
1213 stream_putc(s
, ISIS_TLV_TE_ROUTER_ID
);
1215 stream_put(s
, id
, 4);
1219 static int unpack_tlv_te_router_id(enum isis_tlv_context context
,
1220 uint8_t tlv_type
, uint8_t tlv_len
,
1221 struct stream
*s
, struct sbuf
*log
,
1222 void *dest
, int indent
)
1224 struct isis_tlvs
*tlvs
= dest
;
1226 sbuf_push(log
, indent
, "Unpacking TE Router ID TLV...\n");
1228 sbuf_push(log
, indent
, "WARNING: Length invalid\n");
1232 if (tlvs
->te_router_id
) {
1233 sbuf_push(log
, indent
,
1234 "WARNING: TE Router ID present multiple times.\n");
1235 stream_forward_getp(s
, tlv_len
);
1239 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, 4);
1240 stream_get(tlvs
->te_router_id
, s
, 4);
1241 format_tlv_te_router_id(tlvs
->te_router_id
, log
, indent
+ 2);
1246 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
1248 static struct isis_item
*copy_item_extended_ip_reach(struct isis_item
*i
)
1250 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1251 struct isis_extended_ip_reach
*rv
=
1252 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1254 rv
->metric
= r
->metric
;
1256 rv
->prefix
= r
->prefix
;
1258 return (struct isis_item
*)rv
;
1261 static void format_item_extended_ip_reach(uint16_t mtid
, struct isis_item
*i
,
1262 struct sbuf
*buf
, int indent
)
1264 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1265 char prefixbuf
[PREFIX2STR_BUFFER
];
1267 sbuf_push(buf
, indent
, "%s IP Reachability: %s (Metric: %u)%s",
1268 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "Extended" : "MT",
1269 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)), r
->metric
,
1270 r
->down
? " Down" : "");
1271 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1272 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1273 sbuf_push(buf
, 0, "\n");
1276 static void free_item_extended_ip_reach(struct isis_item
*i
)
1278 struct isis_extended_ip_reach
*item
=
1279 (struct isis_extended_ip_reach
*)i
;
1280 isis_free_subtlvs(item
->subtlvs
);
1281 XFREE(MTYPE_ISIS_TLV
, item
);
1284 static int pack_item_extended_ip_reach(struct isis_item
*i
, struct stream
*s
)
1286 struct isis_extended_ip_reach
*r
= (struct isis_extended_ip_reach
*)i
;
1289 if (STREAM_WRITEABLE(s
) < 5)
1291 stream_putl(s
, r
->metric
);
1293 control
= r
->down
? ISIS_EXTENDED_IP_REACH_DOWN
: 0;
1294 control
|= r
->prefix
.prefixlen
;
1295 control
|= r
->subtlvs
? ISIS_EXTENDED_IP_REACH_SUBTLV
: 0;
1297 stream_putc(s
, control
);
1299 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
))
1301 stream_put(s
, &r
->prefix
.prefix
.s_addr
, PSIZE(r
->prefix
.prefixlen
));
1304 return pack_subtlvs(r
->subtlvs
, s
);
1308 static int unpack_item_extended_ip_reach(uint16_t mtid
, uint8_t len
,
1309 struct stream
*s
, struct sbuf
*log
,
1310 void *dest
, int indent
)
1312 struct isis_tlvs
*tlvs
= dest
;
1313 struct isis_extended_ip_reach
*rv
= NULL
;
1315 uint8_t control
, subtlv_len
;
1316 struct isis_item_list
*items
;
1318 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1319 items
= &tlvs
->extended_ip_reach
;
1321 items
= isis_get_mt_items(&tlvs
->mt_ip_reach
, mtid
);
1324 sbuf_push(log
, indent
, "Unpacking %s IPv4 reachability...\n",
1325 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "extended" : "mt");
1328 if (len
< consume
) {
1329 sbuf_push(log
, indent
,
1330 "Not enough data left. (expected 5 or more bytes, got %" PRIu8
")\n",
1335 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1337 rv
->metric
= stream_getl(s
);
1338 control
= stream_getc(s
);
1339 rv
->down
= (control
& ISIS_EXTENDED_IP_REACH_DOWN
);
1340 rv
->prefix
.family
= AF_INET
;
1341 rv
->prefix
.prefixlen
= control
& 0x3f;
1342 if (rv
->prefix
.prefixlen
> 32) {
1343 sbuf_push(log
, indent
, "Prefixlen %u is inplausible for IPv4\n",
1344 rv
->prefix
.prefixlen
);
1348 consume
+= PSIZE(rv
->prefix
.prefixlen
);
1349 if (len
< consume
) {
1350 sbuf_push(log
, indent
,
1351 "Expected %u bytes of prefix, but only %u bytes available.\n",
1352 PSIZE(rv
->prefix
.prefixlen
), len
- 5);
1355 stream_get(&rv
->prefix
.prefix
.s_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
1356 in_addr_t orig_prefix
= rv
->prefix
.prefix
.s_addr
;
1357 apply_mask_ipv4(&rv
->prefix
);
1358 if (orig_prefix
!= rv
->prefix
.prefix
.s_addr
)
1359 sbuf_push(log
, indent
+ 2,
1360 "WARNING: Prefix had hostbits set.\n");
1361 format_item_extended_ip_reach(mtid
, (struct isis_item
*)rv
, log
,
1364 if (control
& ISIS_EXTENDED_IP_REACH_SUBTLV
) {
1366 if (len
< consume
) {
1367 sbuf_push(log
, indent
,
1368 "Expected 1 byte of subtlv len, but no more data present.\n");
1371 subtlv_len
= stream_getc(s
);
1374 sbuf_push(log
, indent
+ 2,
1375 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
1377 consume
+= subtlv_len
;
1378 if (len
< consume
) {
1379 sbuf_push(log
, indent
,
1381 " bytes of subtlvs, but only %u bytes available.\n",
1383 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
1387 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
);
1388 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH
, subtlv_len
, s
,
1389 log
, rv
->subtlvs
, indent
+ 4)) {
1394 append_item(items
, (struct isis_item
*)rv
);
1398 free_item_extended_ip_reach((struct isis_item
*)rv
);
1402 /* Functions related to TLV 137 Dynamic Hostname */
1404 static char *copy_tlv_dynamic_hostname(const char *hostname
)
1409 return XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
1412 static void format_tlv_dynamic_hostname(const char *hostname
, struct sbuf
*buf
,
1418 sbuf_push(buf
, indent
, "Hostname: %s\n", hostname
);
1421 static void free_tlv_dynamic_hostname(char *hostname
)
1423 XFREE(MTYPE_ISIS_TLV
, hostname
);
1426 static int pack_tlv_dynamic_hostname(const char *hostname
, struct stream
*s
)
1431 uint8_t name_len
= strlen(hostname
);
1433 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + name_len
))
1436 stream_putc(s
, ISIS_TLV_DYNAMIC_HOSTNAME
);
1437 stream_putc(s
, name_len
);
1438 stream_put(s
, hostname
, name_len
);
1442 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context
,
1443 uint8_t tlv_type
, uint8_t tlv_len
,
1444 struct stream
*s
, struct sbuf
*log
,
1445 void *dest
, int indent
)
1447 struct isis_tlvs
*tlvs
= dest
;
1449 sbuf_push(log
, indent
, "Unpacking Dynamic Hostname TLV...\n");
1451 sbuf_push(log
, indent
, "WARNING: No hostname included\n");
1455 if (tlvs
->hostname
) {
1456 sbuf_push(log
, indent
,
1457 "WARNING: Hostname present multiple times.\n");
1458 stream_forward_getp(s
, tlv_len
);
1462 tlvs
->hostname
= XCALLOC(MTYPE_ISIS_TLV
, tlv_len
+ 1);
1463 stream_get(tlvs
->hostname
, s
, tlv_len
);
1464 tlvs
->hostname
[tlv_len
] = '\0';
1467 for (uint8_t i
= 0; i
< tlv_len
; i
++) {
1468 if ((unsigned char)tlvs
->hostname
[i
] > 127
1469 || !isprint((int)tlvs
->hostname
[i
])) {
1471 tlvs
->hostname
[i
] = '?';
1477 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
1483 /* Functions related to TLV 150 Spine-Leaf-Extension */
1485 static struct isis_spine_leaf
*copy_tlv_spine_leaf(
1486 const struct isis_spine_leaf
*spine_leaf
)
1491 struct isis_spine_leaf
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1492 memcpy(rv
, spine_leaf
, sizeof(*rv
));
1497 static void format_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
1498 struct sbuf
*buf
, int indent
)
1503 sbuf_push(buf
, indent
, "Spine-Leaf-Extension:\n");
1504 if (spine_leaf
->has_tier
) {
1505 if (spine_leaf
->tier
== ISIS_TIER_UNDEFINED
) {
1506 sbuf_push(buf
, indent
, " Tier: undefined\n");
1508 sbuf_push(buf
, indent
, " Tier: %" PRIu8
"\n",
1513 sbuf_push(buf
, indent
, " Flags:%s%s%s\n",
1514 spine_leaf
->is_leaf
? " LEAF" : "",
1515 spine_leaf
->is_spine
? " SPINE" : "",
1516 spine_leaf
->is_backup
? " BACKUP" : "");
1520 static void free_tlv_spine_leaf(struct isis_spine_leaf
*spine_leaf
)
1522 XFREE(MTYPE_ISIS_TLV
, spine_leaf
);
1525 #define ISIS_SPINE_LEAF_FLAG_TIER 0x08
1526 #define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
1527 #define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
1528 #define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
1530 static int pack_tlv_spine_leaf(const struct isis_spine_leaf
*spine_leaf
,
1536 uint8_t tlv_len
= 2;
1538 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
1541 stream_putc(s
, ISIS_TLV_SPINE_LEAF_EXT
);
1542 stream_putc(s
, tlv_len
);
1544 uint16_t spine_leaf_flags
= 0;
1546 if (spine_leaf
->has_tier
) {
1547 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_TIER
;
1548 spine_leaf_flags
|= spine_leaf
->tier
<< 12;
1551 if (spine_leaf
->is_leaf
)
1552 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_LEAF
;
1554 if (spine_leaf
->is_spine
)
1555 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_SPINE
;
1557 if (spine_leaf
->is_backup
)
1558 spine_leaf_flags
|= ISIS_SPINE_LEAF_FLAG_BACKUP
;
1560 stream_putw(s
, spine_leaf_flags
);
1565 static int unpack_tlv_spine_leaf(enum isis_tlv_context context
,
1566 uint8_t tlv_type
, uint8_t tlv_len
,
1567 struct stream
*s
, struct sbuf
*log
,
1568 void *dest
, int indent
)
1570 struct isis_tlvs
*tlvs
= dest
;
1572 sbuf_push(log
, indent
, "Unpacking Spine Leaf Extension TLV...\n");
1574 sbuf_push(log
, indent
, "WARNING: Unexepected TLV size\n");
1575 stream_forward_getp(s
, tlv_len
);
1579 if (tlvs
->spine_leaf
) {
1580 sbuf_push(log
, indent
,
1581 "WARNING: Spine Leaf Extension TLV present multiple times.\n");
1582 stream_forward_getp(s
, tlv_len
);
1586 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
1588 uint16_t spine_leaf_flags
= stream_getw(s
);
1590 if (spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_TIER
) {
1591 tlvs
->spine_leaf
->has_tier
= true;
1592 tlvs
->spine_leaf
->tier
= spine_leaf_flags
>> 12;
1595 tlvs
->spine_leaf
->is_leaf
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_LEAF
;
1596 tlvs
->spine_leaf
->is_spine
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_SPINE
;
1597 tlvs
->spine_leaf
->is_backup
= spine_leaf_flags
& ISIS_SPINE_LEAF_FLAG_BACKUP
;
1599 stream_forward_getp(s
, tlv_len
- 2);
1603 /* Functions related to TLV 240 P2P Three-Way Adjacency */
1605 const char *isis_threeway_state_name(enum isis_threeway_state state
)
1608 case ISIS_THREEWAY_DOWN
:
1610 case ISIS_THREEWAY_INITIALIZING
:
1611 return "Initializing";
1612 case ISIS_THREEWAY_UP
:
1619 static struct isis_threeway_adj
*copy_tlv_threeway_adj(
1620 const struct isis_threeway_adj
*threeway_adj
)
1625 struct isis_threeway_adj
*rv
= XMALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1626 memcpy(rv
, threeway_adj
, sizeof(*rv
));
1631 static void format_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
1632 struct sbuf
*buf
, int indent
)
1637 sbuf_push(buf
, indent
, "P2P Three-Way Adjacency:\n");
1638 sbuf_push(buf
, indent
, " State: %s (%d)\n",
1639 isis_threeway_state_name(threeway_adj
->state
),
1640 threeway_adj
->state
);
1641 sbuf_push(buf
, indent
, " Extended Local Circuit ID: %" PRIu32
"\n",
1642 threeway_adj
->local_circuit_id
);
1643 if (!threeway_adj
->neighbor_set
)
1646 sbuf_push(buf
, indent
, " Neighbor System ID: %s\n",
1647 isis_format_id(threeway_adj
->neighbor_id
, 6));
1648 sbuf_push(buf
, indent
, " Neighbor Extended Circuit ID: %" PRIu32
"\n",
1649 threeway_adj
->neighbor_circuit_id
);
1652 static void free_tlv_threeway_adj(struct isis_threeway_adj
*threeway_adj
)
1654 XFREE(MTYPE_ISIS_TLV
, threeway_adj
);
1657 static int pack_tlv_threeway_adj(const struct isis_threeway_adj
*threeway_adj
,
1663 uint8_t tlv_len
= (threeway_adj
->neighbor_set
) ? 15 : 5;
1665 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + tlv_len
))
1668 stream_putc(s
, ISIS_TLV_THREE_WAY_ADJ
);
1669 stream_putc(s
, tlv_len
);
1670 stream_putc(s
, threeway_adj
->state
);
1671 stream_putl(s
, threeway_adj
->local_circuit_id
);
1673 if (threeway_adj
->neighbor_set
) {
1674 stream_put(s
, threeway_adj
->neighbor_id
, 6);
1675 stream_putl(s
, threeway_adj
->neighbor_circuit_id
);
1681 static int unpack_tlv_threeway_adj(enum isis_tlv_context context
,
1682 uint8_t tlv_type
, uint8_t tlv_len
,
1683 struct stream
*s
, struct sbuf
*log
,
1684 void *dest
, int indent
)
1686 struct isis_tlvs
*tlvs
= dest
;
1688 sbuf_push(log
, indent
, "Unpacking P2P Three-Way Adjacency TLV...\n");
1689 if (tlv_len
!= 5 && tlv_len
!= 15) {
1690 sbuf_push(log
, indent
, "WARNING: Unexepected TLV size\n");
1691 stream_forward_getp(s
, tlv_len
);
1695 if (tlvs
->threeway_adj
) {
1696 sbuf_push(log
, indent
,
1697 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
1698 stream_forward_getp(s
, tlv_len
);
1702 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
1704 tlvs
->threeway_adj
->state
= stream_getc(s
);
1705 tlvs
->threeway_adj
->local_circuit_id
= stream_getl(s
);
1707 if (tlv_len
== 15) {
1708 tlvs
->threeway_adj
->neighbor_set
= true;
1709 stream_get(tlvs
->threeway_adj
->neighbor_id
, s
, 6);
1710 tlvs
->threeway_adj
->neighbor_circuit_id
= stream_getl(s
);
1716 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
1718 static struct isis_item
*copy_item_ipv6_reach(struct isis_item
*i
)
1720 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1721 struct isis_ipv6_reach
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1722 rv
->metric
= r
->metric
;
1724 rv
->external
= r
->external
;
1725 rv
->prefix
= r
->prefix
;
1726 rv
->subtlvs
= copy_subtlvs(r
->subtlvs
);
1728 return (struct isis_item
*)rv
;
1731 static void format_item_ipv6_reach(uint16_t mtid
, struct isis_item
*i
,
1732 struct sbuf
*buf
, int indent
)
1734 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1735 char prefixbuf
[PREFIX2STR_BUFFER
];
1737 sbuf_push(buf
, indent
, "%sIPv6 Reachability: %s (Metric: %u)%s%s",
1738 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "MT ",
1739 prefix2str(&r
->prefix
, prefixbuf
, sizeof(prefixbuf
)),
1741 r
->down
? " Down" : "",
1742 r
->external
? " External" : "");
1743 if (mtid
!= ISIS_MT_IPV4_UNICAST
)
1744 sbuf_push(buf
, 0, " %s", isis_mtid2str(mtid
));
1745 sbuf_push(buf
, 0, "\n");
1748 sbuf_push(buf
, indent
, " Subtlvs:\n");
1749 format_subtlvs(r
->subtlvs
, buf
, indent
+ 4);
1753 static void free_item_ipv6_reach(struct isis_item
*i
)
1755 struct isis_ipv6_reach
*item
= (struct isis_ipv6_reach
*)i
;
1757 isis_free_subtlvs(item
->subtlvs
);
1758 XFREE(MTYPE_ISIS_TLV
, item
);
1761 static int pack_item_ipv6_reach(struct isis_item
*i
, struct stream
*s
)
1763 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)i
;
1766 if (STREAM_WRITEABLE(s
) < 6)
1768 stream_putl(s
, r
->metric
);
1770 control
= r
->down
? ISIS_IPV6_REACH_DOWN
: 0;
1771 control
|= r
->external
? ISIS_IPV6_REACH_EXTERNAL
: 0;
1772 control
|= r
->subtlvs
? ISIS_IPV6_REACH_SUBTLV
: 0;
1774 stream_putc(s
, control
);
1775 stream_putc(s
, r
->prefix
.prefixlen
);
1777 if (STREAM_WRITEABLE(s
) < (unsigned)PSIZE(r
->prefix
.prefixlen
))
1779 stream_put(s
, &r
->prefix
.prefix
.s6_addr
, PSIZE(r
->prefix
.prefixlen
));
1782 return pack_subtlvs(r
->subtlvs
, s
);
1787 static int unpack_item_ipv6_reach(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1788 struct sbuf
*log
, void *dest
, int indent
)
1790 struct isis_tlvs
*tlvs
= dest
;
1791 struct isis_ipv6_reach
*rv
= NULL
;
1793 uint8_t control
, subtlv_len
;
1794 struct isis_item_list
*items
;
1796 if (mtid
== ISIS_MT_IPV4_UNICAST
) {
1797 items
= &tlvs
->ipv6_reach
;
1799 items
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
1802 sbuf_push(log
, indent
, "Unpacking %sIPv6 reachability...\n",
1803 (mtid
== ISIS_MT_IPV4_UNICAST
) ? "" : "mt ");
1805 if (len
< consume
) {
1806 sbuf_push(log
, indent
,
1807 "Not enough data left. (expected 6 or more bytes, got %"
1813 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1815 rv
->metric
= stream_getl(s
);
1816 control
= stream_getc(s
);
1817 rv
->down
= (control
& ISIS_IPV6_REACH_DOWN
);
1818 rv
->external
= (control
& ISIS_IPV6_REACH_EXTERNAL
);
1820 rv
->prefix
.family
= AF_INET6
;
1821 rv
->prefix
.prefixlen
= stream_getc(s
);
1822 if (rv
->prefix
.prefixlen
> 128) {
1823 sbuf_push(log
, indent
, "Prefixlen %u is inplausible for IPv6\n",
1824 rv
->prefix
.prefixlen
);
1828 consume
+= PSIZE(rv
->prefix
.prefixlen
);
1829 if (len
< consume
) {
1830 sbuf_push(log
, indent
,
1831 "Expected %u bytes of prefix, but only %u bytes available.\n",
1832 PSIZE(rv
->prefix
.prefixlen
), len
- 6);
1835 stream_get(&rv
->prefix
.prefix
.s6_addr
, s
, PSIZE(rv
->prefix
.prefixlen
));
1836 struct in6_addr orig_prefix
= rv
->prefix
.prefix
;
1837 apply_mask_ipv6(&rv
->prefix
);
1838 if (memcmp(&orig_prefix
, &rv
->prefix
.prefix
, sizeof(orig_prefix
)))
1839 sbuf_push(log
, indent
+ 2,
1840 "WARNING: Prefix had hostbits set.\n");
1841 format_item_ipv6_reach(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1843 if (control
& ISIS_IPV6_REACH_SUBTLV
) {
1845 if (len
< consume
) {
1846 sbuf_push(log
, indent
,
1847 "Expected 1 byte of subtlv len, but no more data persent.\n");
1850 subtlv_len
= stream_getc(s
);
1853 sbuf_push(log
, indent
+ 2,
1854 " WARNING: subtlv bit set, but there are no subtlvs.\n");
1856 consume
+= subtlv_len
;
1857 if (len
< consume
) {
1858 sbuf_push(log
, indent
,
1860 " bytes of subtlvs, but only %u bytes available.\n",
1862 len
- 6 - PSIZE(rv
->prefix
.prefixlen
));
1866 rv
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
1867 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
, subtlv_len
, s
,
1868 log
, rv
->subtlvs
, indent
+ 4)) {
1873 append_item(items
, (struct isis_item
*)rv
);
1877 free_item_ipv6_reach((struct isis_item
*)rv
);
1881 /* Functions related to TLV 10 Authentication */
1882 static struct isis_item
*copy_item_auth(struct isis_item
*i
)
1884 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1885 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1887 rv
->type
= auth
->type
;
1888 rv
->length
= auth
->length
;
1889 memcpy(rv
->value
, auth
->value
, sizeof(rv
->value
));
1890 return (struct isis_item
*)rv
;
1893 static void format_item_auth(uint16_t mtid
, struct isis_item
*i
,
1894 struct sbuf
*buf
, int indent
)
1896 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1899 sbuf_push(buf
, indent
, "Authentication:\n");
1900 switch (auth
->type
) {
1901 case ISIS_PASSWD_TYPE_CLEARTXT
:
1902 zlog_sanitize(obuf
, sizeof(obuf
), auth
->value
, auth
->length
);
1903 sbuf_push(buf
, indent
, " Password: %s\n", obuf
);
1905 case ISIS_PASSWD_TYPE_HMAC_MD5
:
1906 for (unsigned int j
= 0; j
< 16; j
++) {
1907 snprintf(obuf
+ 2 * j
, sizeof(obuf
) - 2 * j
,
1908 "%02" PRIx8
, auth
->value
[j
]);
1910 sbuf_push(buf
, indent
, " HMAC-MD5: %s\n", obuf
);
1913 sbuf_push(buf
, indent
, " Unknown (%" PRIu8
")\n", auth
->type
);
1918 static void free_item_auth(struct isis_item
*i
)
1920 XFREE(MTYPE_ISIS_TLV
, i
);
1923 static int pack_item_auth(struct isis_item
*i
, struct stream
*s
)
1925 struct isis_auth
*auth
= (struct isis_auth
*)i
;
1927 if (STREAM_WRITEABLE(s
) < 1)
1929 stream_putc(s
, auth
->type
);
1931 switch (auth
->type
) {
1932 case ISIS_PASSWD_TYPE_CLEARTXT
:
1933 if (STREAM_WRITEABLE(s
) < auth
->length
)
1935 stream_put(s
, auth
->passwd
, auth
->length
);
1937 case ISIS_PASSWD_TYPE_HMAC_MD5
:
1938 if (STREAM_WRITEABLE(s
) < 16)
1940 auth
->offset
= stream_get_endp(s
);
1941 stream_put(s
, NULL
, 16);
1950 static int unpack_item_auth(uint16_t mtid
, uint8_t len
, struct stream
*s
,
1951 struct sbuf
*log
, void *dest
, int indent
)
1953 struct isis_tlvs
*tlvs
= dest
;
1955 sbuf_push(log
, indent
, "Unpack Auth TLV...\n");
1959 "Not enough data left.(Expected 1 bytes of auth type, got %" PRIu8
1965 struct isis_auth
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1967 rv
->type
= stream_getc(s
);
1968 rv
->length
= len
- 1;
1970 if (rv
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
&& rv
->length
!= 16) {
1973 "Unexpected auth length for HMAC-MD5 (expected 16, got %" PRIu8
1976 XFREE(MTYPE_ISIS_TLV
, rv
);
1980 rv
->offset
= stream_get_getp(s
);
1981 stream_get(rv
->value
, s
, rv
->length
);
1982 format_item_auth(mtid
, (struct isis_item
*)rv
, log
, indent
+ 2);
1983 append_item(&tlvs
->isis_auth
, (struct isis_item
*)rv
);
1987 /* Functions related to TLV 13 Purge Originator */
1989 static struct isis_purge_originator
*copy_tlv_purge_originator(
1990 struct isis_purge_originator
*poi
)
1995 struct isis_purge_originator
*rv
;
1997 rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
1998 rv
->sender_set
= poi
->sender_set
;
1999 memcpy(rv
->generator
, poi
->generator
, sizeof(rv
->generator
));
2000 if (poi
->sender_set
)
2001 memcpy(rv
->sender
, poi
->sender
, sizeof(rv
->sender
));
2005 static void format_tlv_purge_originator(struct isis_purge_originator
*poi
,
2006 struct sbuf
*buf
, int indent
)
2011 sbuf_push(buf
, indent
, "Purge Originator Identification:\n");
2012 sbuf_push(buf
, indent
, " Generator: %s\n",
2013 isis_format_id(poi
->generator
, sizeof(poi
->generator
)));
2014 if (poi
->sender_set
) {
2015 sbuf_push(buf
, indent
, " Received-From: %s\n",
2016 isis_format_id(poi
->sender
, sizeof(poi
->sender
)));
2020 static void free_tlv_purge_originator(struct isis_purge_originator
*poi
)
2022 XFREE(MTYPE_ISIS_TLV
, poi
);
2025 static int pack_tlv_purge_originator(struct isis_purge_originator
*poi
,
2031 uint8_t data_len
= 1 + sizeof(poi
->generator
);
2033 if (poi
->sender_set
)
2034 data_len
+= sizeof(poi
->sender
);
2036 if (STREAM_WRITEABLE(s
) < (unsigned)(2 + data_len
))
2039 stream_putc(s
, ISIS_TLV_PURGE_ORIGINATOR
);
2040 stream_putc(s
, data_len
);
2041 stream_putc(s
, poi
->sender_set
? 2 : 1);
2042 stream_put(s
, poi
->generator
, sizeof(poi
->generator
));
2043 if (poi
->sender_set
)
2044 stream_put(s
, poi
->sender
, sizeof(poi
->sender
));
2048 static int unpack_tlv_purge_originator(enum isis_tlv_context context
,
2049 uint8_t tlv_type
, uint8_t tlv_len
,
2050 struct stream
*s
, struct sbuf
*log
,
2051 void *dest
, int indent
)
2053 struct isis_tlvs
*tlvs
= dest
;
2054 struct isis_purge_originator poi
= {0};
2056 sbuf_push(log
, indent
, "Unpacking Purge Originator Identification TLV...\n");
2058 sbuf_push(log
, indent
, "Not enough data left. (Expected at least 7 bytes, got %"
2059 PRIu8
")\n", tlv_len
);
2063 uint8_t number_of_ids
= stream_getc(s
);
2065 if (number_of_ids
== 1) {
2066 poi
.sender_set
= false;
2067 } else if (number_of_ids
== 2) {
2068 poi
.sender_set
= true;
2070 sbuf_push(log
, indent
, "Got invalid value for number of system IDs: %"
2071 PRIu8
")\n", number_of_ids
);
2075 if (tlv_len
!= 1 + 6 * number_of_ids
) {
2076 sbuf_push(log
, indent
, "Incorrect tlv len for number of IDs.\n");
2080 stream_get(poi
.generator
, s
, sizeof(poi
.generator
));
2082 stream_get(poi
.sender
, s
, sizeof(poi
.sender
));
2084 if (tlvs
->purge_originator
) {
2085 sbuf_push(log
, indent
,
2086 "WARNING: Purge originator present multiple times, ignoring.\n");
2090 tlvs
->purge_originator
= copy_tlv_purge_originator(&poi
);
2095 /* Functions relating to item TLVs */
2097 static void init_item_list(struct isis_item_list
*items
)
2100 items
->tail
= &items
->head
;
2104 static struct isis_item
*copy_item(enum isis_tlv_context context
,
2105 enum isis_tlv_type type
,
2106 struct isis_item
*item
)
2108 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
2110 if (ops
&& ops
->copy_item
)
2111 return ops
->copy_item(item
);
2113 assert(!"Unknown item tlv type!");
2117 static void copy_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
2118 struct isis_item_list
*src
, struct isis_item_list
*dest
)
2120 struct isis_item
*item
;
2122 init_item_list(dest
);
2124 for (item
= src
->head
; item
; item
= item
->next
) {
2125 append_item(dest
, copy_item(context
, type
, item
));
2129 static void format_item(uint16_t mtid
, enum isis_tlv_context context
,
2130 enum isis_tlv_type type
, struct isis_item
*i
,
2131 struct sbuf
*buf
, int indent
)
2133 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
2135 if (ops
&& ops
->format_item
) {
2136 ops
->format_item(mtid
, i
, buf
, indent
);
2140 assert(!"Unknown item tlv type!");
2143 static void format_items_(uint16_t mtid
, enum isis_tlv_context context
,
2144 enum isis_tlv_type type
, struct isis_item_list
*items
,
2145 struct sbuf
*buf
, int indent
)
2147 struct isis_item
*i
;
2149 for (i
= items
->head
; i
; i
= i
->next
)
2150 format_item(mtid
, context
, type
, i
, buf
, indent
);
2153 static void free_item(enum isis_tlv_context tlv_context
,
2154 enum isis_tlv_type tlv_type
, struct isis_item
*item
)
2156 const struct tlv_ops
*ops
= tlv_table
[tlv_context
][tlv_type
];
2158 if (ops
&& ops
->free_item
) {
2159 ops
->free_item(item
);
2163 assert(!"Unknown item tlv type!");
2166 static void free_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
2167 struct isis_item_list
*items
)
2169 struct isis_item
*item
, *next_item
;
2171 for (item
= items
->head
; item
; item
= next_item
) {
2172 next_item
= item
->next
;
2173 free_item(context
, type
, item
);
2177 static int pack_item(enum isis_tlv_context context
, enum isis_tlv_type type
,
2178 struct isis_item
*i
, struct stream
*s
,
2179 struct isis_tlvs
**fragment_tlvs
,
2180 struct pack_order_entry
*pe
, uint16_t mtid
)
2182 const struct tlv_ops
*ops
= tlv_table
[context
][type
];
2184 if (ops
&& ops
->pack_item
) {
2185 return ops
->pack_item(i
, s
);
2188 assert(!"Unknown item tlv type!");
2192 static void add_item_to_fragment(struct isis_item
*i
, struct pack_order_entry
*pe
,
2193 struct isis_tlvs
*fragment_tlvs
, uint16_t mtid
)
2195 struct isis_item_list
*l
;
2197 if (pe
->how_to_pack
== ISIS_ITEMS
) {
2198 l
= (struct isis_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
2200 struct isis_mt_item_list
*m
;
2201 m
= (struct isis_mt_item_list
*)(((char *)fragment_tlvs
) + pe
->what_to_pack
);
2202 l
= isis_get_mt_items(m
, mtid
);
2205 append_item(l
, copy_item(pe
->context
, pe
->type
, i
));
2208 static int pack_items_(uint16_t mtid
, enum isis_tlv_context context
,
2209 enum isis_tlv_type type
, struct isis_item_list
*items
,
2210 struct stream
*s
, struct isis_tlvs
**fragment_tlvs
,
2211 struct pack_order_entry
*pe
,
2212 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2213 struct list
*new_fragment_arg
)
2215 size_t len_pos
, last_len
, len
;
2216 struct isis_item
*item
= NULL
;
2223 if (STREAM_WRITEABLE(s
) < 2)
2226 stream_putc(s
, type
);
2227 len_pos
= stream_get_endp(s
);
2228 stream_putc(s
, 0); /* Put 0 as length for now */
2230 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(type
)
2231 && mtid
!= ISIS_MT_IPV4_UNICAST
) {
2232 if (STREAM_WRITEABLE(s
) < 2)
2234 stream_putw(s
, mtid
);
2237 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_OLDSTYLE_REACH
) {
2238 if (STREAM_WRITEABLE(s
) < 1)
2240 stream_putc(s
, 0); /* Virtual flag is set to 0 */
2244 for (item
= item
? item
: items
->head
; item
; item
= item
->next
) {
2245 rv
= pack_item(context
, type
, item
, s
, fragment_tlvs
, pe
, mtid
);
2249 len
= stream_get_endp(s
) - len_pos
- 1;
2251 /* Multiple auths don't go into one TLV, so always break */
2252 if (context
== ISIS_CONTEXT_LSP
&& type
== ISIS_TLV_AUTH
) {
2257 /* Multiple prefix-sids don't go into one TLV, so always break */
2258 if (type
== ISIS_SUBTLV_PREFIX_SID
2259 && (context
== ISIS_CONTEXT_SUBTLV_IP_REACH
2260 || context
== ISIS_CONTEXT_SUBTLV_IPV6_REACH
)) {
2266 if (!last_len
) /* strange, not a single item fit */
2268 /* drop last tlv, otherwise, its too long */
2269 stream_set_endp(s
, len_pos
+ 1 + last_len
);
2275 add_item_to_fragment(item
, pe
, *fragment_tlvs
, mtid
);
2280 stream_putc_at(s
, len_pos
, len
);
2289 *fragment_tlvs
= new_fragment(new_fragment_arg
);
2292 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
2294 static void append_item(struct isis_item_list
*dest
, struct isis_item
*item
)
2297 dest
->tail
= &(*dest
->tail
)->next
;
2301 static struct isis_item
*last_item(struct isis_item_list
*list
)
2303 return container_of(list
->tail
, struct isis_item
, next
);
2306 static int unpack_item(uint16_t mtid
, enum isis_tlv_context context
,
2307 uint8_t tlv_type
, uint8_t len
, struct stream
*s
,
2308 struct sbuf
*log
, void *dest
, int indent
)
2310 const struct tlv_ops
*ops
= tlv_table
[context
][tlv_type
];
2312 if (ops
&& ops
->unpack_item
)
2313 return ops
->unpack_item(mtid
, len
, s
, log
, dest
, indent
);
2315 assert(!"Unknown item tlv type!");
2316 sbuf_push(log
, indent
, "Unknown item tlv type!\n");
2320 static int unpack_tlv_with_items(enum isis_tlv_context context
,
2321 uint8_t tlv_type
, uint8_t tlv_len
,
2322 struct stream
*s
, struct sbuf
*log
, void *dest
,
2330 tlv_start
= stream_get_getp(s
);
2333 if (context
== ISIS_CONTEXT_LSP
&& IS_COMPAT_MT_TLV(tlv_type
)) {
2335 sbuf_push(log
, indent
,
2336 "TLV is too short to contain MTID\n");
2339 mtid
= stream_getw(s
) & ISIS_MT_MASK
;
2341 sbuf_push(log
, indent
, "Unpacking as MT %s item TLV...\n",
2342 isis_mtid2str(mtid
));
2344 sbuf_push(log
, indent
, "Unpacking as item TLV...\n");
2345 mtid
= ISIS_MT_IPV4_UNICAST
;
2348 if (context
== ISIS_CONTEXT_LSP
2349 && tlv_type
== ISIS_TLV_OLDSTYLE_REACH
) {
2350 if (tlv_len
- tlv_pos
< 1) {
2351 sbuf_push(log
, indent
,
2352 "TLV is too short for old style reach\n");
2355 stream_forward_getp(s
, 1);
2359 if (context
== ISIS_CONTEXT_LSP
2360 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH
) {
2361 struct isis_tlvs
*tlvs
= dest
;
2362 dest
= &tlvs
->oldstyle_ip_reach
;
2363 } else if (context
== ISIS_CONTEXT_LSP
2364 && tlv_type
== ISIS_TLV_OLDSTYLE_IP_REACH_EXT
) {
2365 struct isis_tlvs
*tlvs
= dest
;
2366 dest
= &tlvs
->oldstyle_ip_reach_ext
;
2369 if (context
== ISIS_CONTEXT_LSP
2370 && tlv_type
== ISIS_TLV_MT_ROUTER_INFO
) {
2371 struct isis_tlvs
*tlvs
= dest
;
2372 tlvs
->mt_router_info_empty
= (tlv_pos
>= (size_t)tlv_len
);
2375 while (tlv_pos
< (size_t)tlv_len
) {
2376 rv
= unpack_item(mtid
, context
, tlv_type
, tlv_len
- tlv_pos
, s
,
2377 log
, dest
, indent
+ 2);
2381 tlv_pos
= stream_get_getp(s
) - tlv_start
;
2387 /* Functions to manipulate mt_item_lists */
2389 static int isis_mt_item_list_cmp(const struct isis_item_list
*a
,
2390 const struct isis_item_list
*b
)
2392 if (a
->mtid
< b
->mtid
)
2394 if (a
->mtid
> b
->mtid
)
2399 RB_PROTOTYPE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
2400 RB_GENERATE(isis_mt_item_list
, isis_item_list
, mt_tree
, isis_mt_item_list_cmp
);
2402 struct isis_item_list
*isis_get_mt_items(struct isis_mt_item_list
*m
,
2405 struct isis_item_list
*rv
;
2407 rv
= isis_lookup_mt_items(m
, mtid
);
2409 rv
= XCALLOC(MTYPE_ISIS_MT_ITEM_LIST
, sizeof(*rv
));
2412 RB_INSERT(isis_mt_item_list
, m
, rv
);
2418 struct isis_item_list
*isis_lookup_mt_items(struct isis_mt_item_list
*m
,
2421 struct isis_item_list key
= {.mtid
= mtid
};
2423 return RB_FIND(isis_mt_item_list
, m
, &key
);
2426 static void free_mt_items(enum isis_tlv_context context
,
2427 enum isis_tlv_type type
, struct isis_mt_item_list
*m
)
2429 struct isis_item_list
*n
, *nnext
;
2431 RB_FOREACH_SAFE (n
, isis_mt_item_list
, m
, nnext
) {
2432 free_items(context
, type
, n
);
2433 RB_REMOVE(isis_mt_item_list
, m
, n
);
2434 XFREE(MTYPE_ISIS_MT_ITEM_LIST
, n
);
2438 static void format_mt_items(enum isis_tlv_context context
,
2439 enum isis_tlv_type type
,
2440 struct isis_mt_item_list
*m
, struct sbuf
*buf
,
2443 struct isis_item_list
*n
;
2445 RB_FOREACH (n
, isis_mt_item_list
, m
) {
2446 format_items_(n
->mtid
, context
, type
, n
, buf
, indent
);
2450 static int pack_mt_items(enum isis_tlv_context context
, enum isis_tlv_type type
,
2451 struct isis_mt_item_list
*m
, struct stream
*s
,
2452 struct isis_tlvs
**fragment_tlvs
,
2453 struct pack_order_entry
*pe
,
2454 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2455 struct list
*new_fragment_arg
)
2457 struct isis_item_list
*n
;
2459 RB_FOREACH (n
, isis_mt_item_list
, m
) {
2462 rv
= pack_items_(n
->mtid
, context
, type
, n
, s
, fragment_tlvs
,
2463 pe
, new_fragment
, new_fragment_arg
);
2471 static void copy_mt_items(enum isis_tlv_context context
,
2472 enum isis_tlv_type type
,
2473 struct isis_mt_item_list
*src
,
2474 struct isis_mt_item_list
*dest
)
2476 struct isis_item_list
*n
;
2478 RB_INIT(isis_mt_item_list
, dest
);
2480 RB_FOREACH (n
, isis_mt_item_list
, src
) {
2481 copy_items(context
, type
, n
, isis_get_mt_items(dest
, n
->mtid
));
2485 /* Functions related to tlvs in general */
2487 struct isis_tlvs
*isis_alloc_tlvs(void)
2489 struct isis_tlvs
*result
;
2491 result
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*result
));
2493 init_item_list(&result
->isis_auth
);
2494 init_item_list(&result
->area_addresses
);
2495 init_item_list(&result
->mt_router_info
);
2496 init_item_list(&result
->oldstyle_reach
);
2497 init_item_list(&result
->lan_neighbor
);
2498 init_item_list(&result
->lsp_entries
);
2499 init_item_list(&result
->extended_reach
);
2500 RB_INIT(isis_mt_item_list
, &result
->mt_reach
);
2501 init_item_list(&result
->oldstyle_ip_reach
);
2502 init_item_list(&result
->oldstyle_ip_reach_ext
);
2503 init_item_list(&result
->ipv4_address
);
2504 init_item_list(&result
->ipv6_address
);
2505 init_item_list(&result
->extended_ip_reach
);
2506 RB_INIT(isis_mt_item_list
, &result
->mt_ip_reach
);
2507 init_item_list(&result
->ipv6_reach
);
2508 RB_INIT(isis_mt_item_list
, &result
->mt_ipv6_reach
);
2513 struct isis_tlvs
*isis_copy_tlvs(struct isis_tlvs
*tlvs
)
2515 struct isis_tlvs
*rv
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*rv
));
2517 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
,
2520 rv
->purge_originator
=
2521 copy_tlv_purge_originator(tlvs
->purge_originator
);
2523 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2524 &tlvs
->area_addresses
, &rv
->area_addresses
);
2526 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2527 &tlvs
->mt_router_info
, &rv
->mt_router_info
);
2529 rv
->mt_router_info_empty
= tlvs
->mt_router_info_empty
;
2531 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2532 &tlvs
->oldstyle_reach
, &rv
->oldstyle_reach
);
2534 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2535 &tlvs
->lan_neighbor
, &rv
->lan_neighbor
);
2537 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
2540 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2541 &tlvs
->extended_reach
, &rv
->extended_reach
);
2543 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
2546 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2547 &tlvs
->oldstyle_ip_reach
, &rv
->oldstyle_ip_reach
);
2549 copy_tlv_protocols_supported(&tlvs
->protocols_supported
,
2550 &rv
->protocols_supported
);
2552 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2553 &tlvs
->oldstyle_ip_reach_ext
, &rv
->oldstyle_ip_reach_ext
);
2555 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
, &tlvs
->ipv4_address
,
2558 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
, &tlvs
->ipv6_address
,
2561 rv
->te_router_id
= copy_tlv_te_router_id(tlvs
->te_router_id
);
2563 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2564 &tlvs
->extended_ip_reach
, &rv
->extended_ip_reach
);
2566 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2567 &tlvs
->mt_ip_reach
, &rv
->mt_ip_reach
);
2569 rv
->hostname
= copy_tlv_dynamic_hostname(tlvs
->hostname
);
2571 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
2574 copy_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2575 &tlvs
->mt_ipv6_reach
, &rv
->mt_ipv6_reach
);
2577 rv
->threeway_adj
= copy_tlv_threeway_adj(tlvs
->threeway_adj
);
2579 rv
->spine_leaf
= copy_tlv_spine_leaf(tlvs
->spine_leaf
);
2584 static void format_tlvs(struct isis_tlvs
*tlvs
, struct sbuf
*buf
, int indent
)
2586 format_tlv_protocols_supported(&tlvs
->protocols_supported
, buf
, indent
);
2588 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
, buf
,
2591 format_tlv_purge_originator(tlvs
->purge_originator
, buf
, indent
);
2593 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2594 &tlvs
->area_addresses
, buf
, indent
);
2596 if (tlvs
->mt_router_info_empty
) {
2597 sbuf_push(buf
, indent
, "MT Router Info: None\n");
2599 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2600 &tlvs
->mt_router_info
, buf
, indent
);
2603 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2604 &tlvs
->oldstyle_reach
, buf
, indent
);
2606 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2607 &tlvs
->lan_neighbor
, buf
, indent
);
2609 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
,
2612 format_tlv_dynamic_hostname(tlvs
->hostname
, buf
, indent
);
2613 format_tlv_te_router_id(tlvs
->te_router_id
, buf
, indent
);
2615 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2616 &tlvs
->extended_reach
, buf
, indent
);
2618 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
,
2621 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2622 &tlvs
->oldstyle_ip_reach
, buf
, indent
);
2624 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2625 &tlvs
->oldstyle_ip_reach_ext
, buf
, indent
);
2627 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
2628 &tlvs
->ipv4_address
, buf
, indent
);
2630 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
2631 &tlvs
->ipv6_address
, buf
, indent
);
2633 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2634 &tlvs
->extended_ip_reach
, buf
, indent
);
2636 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2637 &tlvs
->mt_ip_reach
, buf
, indent
);
2639 format_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
,
2642 format_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2643 &tlvs
->mt_ipv6_reach
, buf
, indent
);
2645 format_tlv_threeway_adj(tlvs
->threeway_adj
, buf
, indent
);
2647 format_tlv_spine_leaf(tlvs
->spine_leaf
, buf
, indent
);
2650 const char *isis_format_tlvs(struct isis_tlvs
*tlvs
)
2652 static struct sbuf buf
;
2654 if (!sbuf_buf(&buf
))
2655 sbuf_init(&buf
, NULL
, 0);
2658 format_tlvs(tlvs
, &buf
, 0);
2659 return sbuf_buf(&buf
);
2662 void isis_free_tlvs(struct isis_tlvs
*tlvs
)
2667 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
2668 free_tlv_purge_originator(tlvs
->purge_originator
);
2669 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2670 &tlvs
->area_addresses
);
2671 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2672 &tlvs
->mt_router_info
);
2673 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_REACH
,
2674 &tlvs
->oldstyle_reach
);
2675 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LAN_NEIGHBORS
,
2676 &tlvs
->lan_neighbor
);
2677 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_LSP_ENTRY
, &tlvs
->lsp_entries
);
2678 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_REACH
,
2679 &tlvs
->extended_reach
);
2680 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_REACH
, &tlvs
->mt_reach
);
2681 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH
,
2682 &tlvs
->oldstyle_ip_reach
);
2683 free_tlv_protocols_supported(&tlvs
->protocols_supported
);
2684 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_OLDSTYLE_IP_REACH_EXT
,
2685 &tlvs
->oldstyle_ip_reach_ext
);
2686 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV4_ADDRESS
,
2687 &tlvs
->ipv4_address
);
2688 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_ADDRESS
,
2689 &tlvs
->ipv6_address
);
2690 free_tlv_te_router_id(tlvs
->te_router_id
);
2691 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_EXTENDED_IP_REACH
,
2692 &tlvs
->extended_ip_reach
);
2693 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IP_REACH
,
2694 &tlvs
->mt_ip_reach
);
2695 free_tlv_dynamic_hostname(tlvs
->hostname
);
2696 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_IPV6_REACH
, &tlvs
->ipv6_reach
);
2697 free_mt_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_IPV6_REACH
,
2698 &tlvs
->mt_ipv6_reach
);
2699 free_tlv_threeway_adj(tlvs
->threeway_adj
);
2700 free_tlv_spine_leaf(tlvs
->spine_leaf
);
2702 XFREE(MTYPE_ISIS_TLV
, tlvs
);
2705 static void add_padding(struct stream
*s
)
2707 while (STREAM_WRITEABLE(s
)) {
2708 if (STREAM_WRITEABLE(s
) == 1)
2710 uint32_t padding_len
= STREAM_WRITEABLE(s
) - 2;
2712 if (padding_len
> 255) {
2713 if (padding_len
== 256)
2719 stream_putc(s
, ISIS_TLV_PADDING
);
2720 stream_putc(s
, padding_len
);
2721 stream_put(s
, NULL
, padding_len
);
2725 #define LSP_REM_LIFETIME_OFF 10
2726 #define LSP_CHECKSUM_OFF 24
2727 static void safe_auth_md5(struct stream
*s
, uint16_t *checksum
,
2728 uint16_t *rem_lifetime
)
2730 memcpy(rem_lifetime
, STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
,
2731 sizeof(*rem_lifetime
));
2732 memset(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, 0, sizeof(*rem_lifetime
));
2733 memcpy(checksum
, STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, sizeof(*checksum
));
2734 memset(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, 0, sizeof(*checksum
));
2737 static void restore_auth_md5(struct stream
*s
, uint16_t checksum
,
2738 uint16_t rem_lifetime
)
2740 memcpy(STREAM_DATA(s
) + LSP_REM_LIFETIME_OFF
, &rem_lifetime
,
2741 sizeof(rem_lifetime
));
2742 memcpy(STREAM_DATA(s
) + LSP_CHECKSUM_OFF
, &checksum
, sizeof(checksum
));
2745 static void update_auth_hmac_md5(struct isis_auth
*auth
, struct stream
*s
,
2749 uint16_t checksum
, rem_lifetime
;
2752 safe_auth_md5(s
, &checksum
, &rem_lifetime
);
2754 memset(STREAM_DATA(s
) + auth
->offset
, 0, 16);
2755 hmac_md5(STREAM_DATA(s
), stream_get_endp(s
), auth
->passwd
,
2756 auth
->plength
, digest
);
2757 memcpy(auth
->value
, digest
, 16);
2758 memcpy(STREAM_DATA(s
) + auth
->offset
, digest
, 16);
2761 restore_auth_md5(s
, checksum
, rem_lifetime
);
2764 static void update_auth(struct isis_tlvs
*tlvs
, struct stream
*s
, bool is_lsp
)
2766 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
2768 for (struct isis_auth
*auth
= auth_head
; auth
; auth
= auth
->next
) {
2769 if (auth
->type
== ISIS_PASSWD_TYPE_HMAC_MD5
)
2770 update_auth_hmac_md5(auth
, s
, is_lsp
);
2774 static int handle_pack_entry(struct pack_order_entry
*pe
,
2775 struct isis_tlvs
*tlvs
, struct stream
*stream
,
2776 struct isis_tlvs
**fragment_tlvs
,
2777 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2778 struct list
*new_fragment_arg
)
2782 if (pe
->how_to_pack
== ISIS_ITEMS
) {
2783 struct isis_item_list
*l
;
2784 l
= (struct isis_item_list
*)(((char *)tlvs
)
2785 + pe
->what_to_pack
);
2786 rv
= pack_items(pe
->context
, pe
->type
, l
, stream
, fragment_tlvs
,
2787 pe
, new_fragment
, new_fragment_arg
);
2789 struct isis_mt_item_list
*l
;
2790 l
= (struct isis_mt_item_list
*)(((char *)tlvs
)
2791 + pe
->what_to_pack
);
2792 rv
= pack_mt_items(pe
->context
, pe
->type
, l
, stream
,
2793 fragment_tlvs
, pe
, new_fragment
,
2800 static int pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
2801 struct isis_tlvs
*fragment_tlvs
,
2802 struct isis_tlvs
*(*new_fragment
)(struct list
*l
),
2803 struct list
*new_fragment_arg
)
2807 /* When fragmenting, don't add auth as it's already accounted for in the
2808 * size we are given. */
2809 if (!fragment_tlvs
) {
2810 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
,
2811 &tlvs
->isis_auth
, stream
, NULL
, NULL
, NULL
,
2817 rv
= pack_tlv_purge_originator(tlvs
->purge_originator
, stream
);
2820 if (fragment_tlvs
) {
2821 fragment_tlvs
->purge_originator
=
2822 copy_tlv_purge_originator(tlvs
->purge_originator
);
2825 rv
= pack_tlv_protocols_supported(&tlvs
->protocols_supported
, stream
);
2828 if (fragment_tlvs
) {
2829 copy_tlv_protocols_supported(
2830 &tlvs
->protocols_supported
,
2831 &fragment_tlvs
->protocols_supported
);
2834 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2835 &tlvs
->area_addresses
, stream
, NULL
, NULL
, NULL
, NULL
);
2838 if (fragment_tlvs
) {
2839 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AREA_ADDRESSES
,
2840 &tlvs
->area_addresses
,
2841 &fragment_tlvs
->area_addresses
);
2845 if (tlvs
->mt_router_info_empty
) {
2846 if (STREAM_WRITEABLE(stream
) < 2)
2848 stream_putc(stream
, ISIS_TLV_MT_ROUTER_INFO
);
2849 stream_putc(stream
, 0);
2851 fragment_tlvs
->mt_router_info_empty
= true;
2853 rv
= pack_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2854 &tlvs
->mt_router_info
, stream
, NULL
, NULL
, NULL
,
2858 if (fragment_tlvs
) {
2859 copy_items(ISIS_CONTEXT_LSP
, ISIS_TLV_MT_ROUTER_INFO
,
2860 &tlvs
->mt_router_info
,
2861 &fragment_tlvs
->mt_router_info
);
2865 rv
= pack_tlv_dynamic_hostname(tlvs
->hostname
, stream
);
2869 fragment_tlvs
->hostname
=
2870 copy_tlv_dynamic_hostname(tlvs
->hostname
);
2872 rv
= pack_tlv_te_router_id(tlvs
->te_router_id
, stream
);
2875 if (fragment_tlvs
) {
2876 fragment_tlvs
->te_router_id
=
2877 copy_tlv_te_router_id(tlvs
->te_router_id
);
2880 rv
= pack_tlv_threeway_adj(tlvs
->threeway_adj
, stream
);
2883 if (fragment_tlvs
) {
2884 fragment_tlvs
->threeway_adj
=
2885 copy_tlv_threeway_adj(tlvs
->threeway_adj
);
2888 rv
= pack_tlv_spine_leaf(tlvs
->spine_leaf
, stream
);
2891 if (fragment_tlvs
) {
2892 fragment_tlvs
->spine_leaf
=
2893 copy_tlv_spine_leaf(tlvs
->spine_leaf
);
2896 for (size_t pack_idx
= 0; pack_idx
< array_size(pack_order
);
2898 rv
= handle_pack_entry(&pack_order
[pack_idx
], tlvs
, stream
,
2899 fragment_tlvs
? &fragment_tlvs
: NULL
,
2900 new_fragment
, new_fragment_arg
);
2909 int isis_pack_tlvs(struct isis_tlvs
*tlvs
, struct stream
*stream
,
2910 size_t len_pointer
, bool pad
, bool is_lsp
)
2914 rv
= pack_tlvs(tlvs
, stream
, NULL
, NULL
, NULL
);
2919 add_padding(stream
);
2921 if (len_pointer
!= (size_t)-1) {
2922 stream_putw_at(stream
, len_pointer
, stream_get_endp(stream
));
2925 update_auth(tlvs
, stream
, is_lsp
);
2930 static struct isis_tlvs
*new_fragment(struct list
*l
)
2932 struct isis_tlvs
*rv
= isis_alloc_tlvs();
2934 listnode_add(l
, rv
);
2938 struct list
*isis_fragment_tlvs(struct isis_tlvs
*tlvs
, size_t size
)
2940 struct stream
*dummy_stream
= stream_new(size
);
2941 struct list
*rv
= list_new();
2942 struct isis_tlvs
*fragment_tlvs
= new_fragment(rv
);
2944 if (pack_tlvs(tlvs
, dummy_stream
, fragment_tlvs
, new_fragment
, rv
)) {
2945 struct listnode
*node
;
2946 for (ALL_LIST_ELEMENTS_RO(rv
, node
, fragment_tlvs
))
2947 isis_free_tlvs(fragment_tlvs
);
2951 stream_free(dummy_stream
);
2955 static int unpack_tlv_unknown(enum isis_tlv_context context
, uint8_t tlv_type
,
2956 uint8_t tlv_len
, struct stream
*s
,
2957 struct sbuf
*log
, int indent
)
2959 stream_forward_getp(s
, tlv_len
);
2960 sbuf_push(log
, indent
,
2961 "Skipping unknown TLV %" PRIu8
" (%" PRIu8
" bytes)\n",
2966 static int unpack_tlv(enum isis_tlv_context context
, size_t avail_len
,
2967 struct stream
*stream
, struct sbuf
*log
, void *dest
,
2970 uint8_t tlv_type
, tlv_len
;
2971 const struct tlv_ops
*ops
;
2973 sbuf_push(log
, indent
, "Unpacking TLV...\n");
2975 if (avail_len
< 2) {
2978 "Available data %zu too short to contain a TLV header.\n",
2983 tlv_type
= stream_getc(stream
);
2984 tlv_len
= stream_getc(stream
);
2986 sbuf_push(log
, indent
+ 2,
2987 "Found TLV of type %" PRIu8
" and len %" PRIu8
".\n",
2990 if (avail_len
< ((size_t)tlv_len
) + 2) {
2991 sbuf_push(log
, indent
+ 2,
2992 "Available data %zu too short for claimed TLV len %" PRIu8
".\n",
2993 avail_len
- 2, tlv_len
);
2997 ops
= tlv_table
[context
][tlv_type
];
2998 if (ops
&& ops
->unpack
) {
2999 return ops
->unpack(context
, tlv_type
, tlv_len
, stream
, log
,
3003 return unpack_tlv_unknown(context
, tlv_type
, tlv_len
, stream
, log
,
3007 static int unpack_tlvs(enum isis_tlv_context context
, size_t avail_len
,
3008 struct stream
*stream
, struct sbuf
*log
, void *dest
,
3012 size_t tlv_start
, tlv_pos
;
3014 tlv_start
= stream_get_getp(stream
);
3017 sbuf_push(log
, indent
, "Unpacking %zu bytes of %s...\n", avail_len
,
3018 (context
== ISIS_CONTEXT_LSP
) ? "TLVs" : "sub-TLVs");
3020 while (tlv_pos
< avail_len
) {
3021 rv
= unpack_tlv(context
, avail_len
- tlv_pos
, stream
, log
, dest
,
3026 tlv_pos
= stream_get_getp(stream
) - tlv_start
;
3032 int isis_unpack_tlvs(size_t avail_len
, struct stream
*stream
,
3033 struct isis_tlvs
**dest
, const char **log
)
3035 static struct sbuf logbuf
;
3038 struct isis_tlvs
*result
;
3040 if (!sbuf_buf(&logbuf
))
3041 sbuf_init(&logbuf
, NULL
, 0);
3043 sbuf_reset(&logbuf
);
3044 if (avail_len
> STREAM_READABLE(stream
)) {
3045 sbuf_push(&logbuf
, indent
,
3046 "Stream doesn't contain sufficient data. "
3047 "Claimed %zu, available %zu\n",
3048 avail_len
, STREAM_READABLE(stream
));
3052 result
= isis_alloc_tlvs();
3053 rv
= unpack_tlvs(ISIS_CONTEXT_LSP
, avail_len
, stream
, &logbuf
, result
,
3056 *log
= sbuf_buf(&logbuf
);
3062 #define TLV_OPS(_name_, _desc_) \
3063 static const struct tlv_ops tlv_##_name_##_ops = { \
3064 .name = _desc_, .unpack = unpack_tlv_##_name_, \
3067 #define ITEM_TLV_OPS(_name_, _desc_) \
3068 static const struct tlv_ops tlv_##_name_##_ops = { \
3070 .unpack = unpack_tlv_with_items, \
3072 .pack_item = pack_item_##_name_, \
3073 .free_item = free_item_##_name_, \
3074 .unpack_item = unpack_item_##_name_, \
3075 .format_item = format_item_##_name_, \
3076 .copy_item = copy_item_##_name_}
3078 #define SUBTLV_OPS(_name_, _desc_) \
3079 static const struct tlv_ops subtlv_##_name_##_ops = { \
3080 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
3083 #define ITEM_SUBTLV_OPS(_name_, _desc_) \
3084 ITEM_TLV_OPS(_name_, _desc_)
3086 ITEM_TLV_OPS(area_address
, "TLV 1 Area Addresses");
3087 ITEM_TLV_OPS(oldstyle_reach
, "TLV 2 IS Reachability");
3088 ITEM_TLV_OPS(lan_neighbor
, "TLV 6 LAN Neighbors");
3089 ITEM_TLV_OPS(lsp_entry
, "TLV 9 LSP Entries");
3090 ITEM_TLV_OPS(auth
, "TLV 10 IS-IS Auth");
3091 TLV_OPS(purge_originator
, "TLV 13 Purge Originator Identification");
3092 ITEM_TLV_OPS(extended_reach
, "TLV 22 Extended Reachability");
3093 ITEM_TLV_OPS(oldstyle_ip_reach
, "TLV 128/130 IP Reachability");
3094 TLV_OPS(protocols_supported
, "TLV 129 Protocols Supported");
3095 ITEM_TLV_OPS(ipv4_address
, "TLV 132 IPv4 Interface Address");
3096 TLV_OPS(te_router_id
, "TLV 134 TE Router ID");
3097 ITEM_TLV_OPS(extended_ip_reach
, "TLV 135 Extended IP Reachability");
3098 TLV_OPS(dynamic_hostname
, "TLV 137 Dynamic Hostname");
3099 TLV_OPS(spine_leaf
, "TLV 150 Spine Leaf Extensions");
3100 ITEM_TLV_OPS(mt_router_info
, "TLV 229 MT Router Information");
3101 TLV_OPS(threeway_adj
, "TLV 240 P2P Three-Way Adjacency");
3102 ITEM_TLV_OPS(ipv6_address
, "TLV 232 IPv6 Interface Address");
3103 ITEM_TLV_OPS(ipv6_reach
, "TLV 236 IPv6 Reachability");
3105 ITEM_SUBTLV_OPS(prefix_sid
, "Sub-TLV 3 SR Prefix-SID");
3106 SUBTLV_OPS(ipv6_source_prefix
, "Sub-TLV 22 IPv6 Source Prefix");
3108 static const struct tlv_ops
*tlv_table
[ISIS_CONTEXT_MAX
][ISIS_TLV_MAX
] = {
3109 [ISIS_CONTEXT_LSP
] = {
3110 [ISIS_TLV_AREA_ADDRESSES
] = &tlv_area_address_ops
,
3111 [ISIS_TLV_OLDSTYLE_REACH
] = &tlv_oldstyle_reach_ops
,
3112 [ISIS_TLV_LAN_NEIGHBORS
] = &tlv_lan_neighbor_ops
,
3113 [ISIS_TLV_LSP_ENTRY
] = &tlv_lsp_entry_ops
,
3114 [ISIS_TLV_AUTH
] = &tlv_auth_ops
,
3115 [ISIS_TLV_PURGE_ORIGINATOR
] = &tlv_purge_originator_ops
,
3116 [ISIS_TLV_EXTENDED_REACH
] = &tlv_extended_reach_ops
,
3117 [ISIS_TLV_MT_REACH
] = &tlv_extended_reach_ops
,
3118 [ISIS_TLV_OLDSTYLE_IP_REACH
] = &tlv_oldstyle_ip_reach_ops
,
3119 [ISIS_TLV_PROTOCOLS_SUPPORTED
] = &tlv_protocols_supported_ops
,
3120 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT
] = &tlv_oldstyle_ip_reach_ops
,
3121 [ISIS_TLV_IPV4_ADDRESS
] = &tlv_ipv4_address_ops
,
3122 [ISIS_TLV_TE_ROUTER_ID
] = &tlv_te_router_id_ops
,
3123 [ISIS_TLV_EXTENDED_IP_REACH
] = &tlv_extended_ip_reach_ops
,
3124 [ISIS_TLV_MT_IP_REACH
] = &tlv_extended_ip_reach_ops
,
3125 [ISIS_TLV_DYNAMIC_HOSTNAME
] = &tlv_dynamic_hostname_ops
,
3126 [ISIS_TLV_SPINE_LEAF_EXT
] = &tlv_spine_leaf_ops
,
3127 [ISIS_TLV_MT_ROUTER_INFO
] = &tlv_mt_router_info_ops
,
3128 [ISIS_TLV_THREE_WAY_ADJ
] = &tlv_threeway_adj_ops
,
3129 [ISIS_TLV_IPV6_ADDRESS
] = &tlv_ipv6_address_ops
,
3130 [ISIS_TLV_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
3131 [ISIS_TLV_MT_IPV6_REACH
] = &tlv_ipv6_reach_ops
,
3133 [ISIS_CONTEXT_SUBTLV_NE_REACH
] = {0},
3134 [ISIS_CONTEXT_SUBTLV_IP_REACH
] = {
3135 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
3137 [ISIS_CONTEXT_SUBTLV_IPV6_REACH
] = {
3138 [ISIS_SUBTLV_PREFIX_SID
] = &tlv_prefix_sid_ops
,
3139 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX
] = &subtlv_ipv6_source_prefix_ops
,
3143 /* Accessor functions */
3145 void isis_tlvs_add_auth(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
)
3147 free_items(ISIS_CONTEXT_LSP
, ISIS_TLV_AUTH
, &tlvs
->isis_auth
);
3148 init_item_list(&tlvs
->isis_auth
);
3150 if (passwd
->type
== ISIS_PASSWD_TYPE_UNUSED
)
3153 struct isis_auth
*auth
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*auth
));
3155 auth
->type
= passwd
->type
;
3157 auth
->plength
= passwd
->len
;
3158 memcpy(auth
->passwd
, passwd
->passwd
,
3159 MIN(sizeof(auth
->passwd
), sizeof(passwd
->passwd
)));
3161 if (auth
->type
== ISIS_PASSWD_TYPE_CLEARTXT
) {
3162 auth
->length
= passwd
->len
;
3163 memcpy(auth
->value
, passwd
->passwd
,
3164 MIN(sizeof(auth
->value
), sizeof(passwd
->passwd
)));
3167 append_item(&tlvs
->isis_auth
, (struct isis_item
*)auth
);
3170 void isis_tlvs_add_area_addresses(struct isis_tlvs
*tlvs
,
3171 struct list
*addresses
)
3173 struct listnode
*node
;
3174 struct area_addr
*area_addr
;
3176 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, area_addr
)) {
3177 struct isis_area_address
*a
=
3178 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
3180 a
->len
= area_addr
->addr_len
;
3181 memcpy(a
->addr
, area_addr
->area_addr
, 20);
3182 append_item(&tlvs
->area_addresses
, (struct isis_item
*)a
);
3186 void isis_tlvs_add_lan_neighbors(struct isis_tlvs
*tlvs
, struct list
*neighbors
)
3188 struct listnode
*node
;
3191 for (ALL_LIST_ELEMENTS_RO(neighbors
, node
, snpa
)) {
3192 struct isis_lan_neighbor
*n
=
3193 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*n
));
3195 memcpy(n
->mac
, snpa
, 6);
3196 append_item(&tlvs
->lan_neighbor
, (struct isis_item
*)n
);
3200 void isis_tlvs_set_protocols_supported(struct isis_tlvs
*tlvs
,
3201 struct nlpids
*nlpids
)
3203 tlvs
->protocols_supported
.count
= nlpids
->count
;
3204 if (tlvs
->protocols_supported
.protocols
)
3205 XFREE(MTYPE_ISIS_TLV
, tlvs
->protocols_supported
.protocols
);
3206 if (nlpids
->count
) {
3207 tlvs
->protocols_supported
.protocols
=
3208 XCALLOC(MTYPE_ISIS_TLV
, nlpids
->count
);
3209 memcpy(tlvs
->protocols_supported
.protocols
, nlpids
->nlpids
,
3212 tlvs
->protocols_supported
.protocols
= NULL
;
3216 void isis_tlvs_add_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3217 bool overload
, bool attached
)
3219 struct isis_mt_router_info
*i
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*i
));
3221 i
->overload
= overload
;
3222 i
->attached
= attached
;
3224 append_item(&tlvs
->mt_router_info
, (struct isis_item
*)i
);
3227 void isis_tlvs_add_ipv4_address(struct isis_tlvs
*tlvs
, struct in_addr
*addr
)
3229 struct isis_ipv4_address
*a
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
3231 append_item(&tlvs
->ipv4_address
, (struct isis_item
*)a
);
3235 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs
*tlvs
,
3236 struct list
*addresses
)
3238 struct listnode
*node
;
3239 struct prefix_ipv4
*ip_addr
;
3240 unsigned int addr_count
= 0;
3242 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
3243 isis_tlvs_add_ipv4_address(tlvs
, &ip_addr
->prefix
);
3245 if (addr_count
>= 63)
3250 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs
*tlvs
,
3251 struct list
*addresses
)
3253 struct listnode
*node
;
3254 struct prefix_ipv6
*ip_addr
;
3256 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, ip_addr
)) {
3257 struct isis_ipv6_address
*a
=
3258 XCALLOC(MTYPE_ISIS_TLV
, sizeof(*a
));
3260 a
->addr
= ip_addr
->prefix
;
3261 append_item(&tlvs
->ipv6_address
, (struct isis_item
*)a
);
3265 typedef bool (*auth_validator_func
)(struct isis_passwd
*passwd
,
3266 struct stream
*stream
,
3267 struct isis_auth
*auth
, bool is_lsp
);
3269 static bool auth_validator_cleartxt(struct isis_passwd
*passwd
,
3270 struct stream
*stream
,
3271 struct isis_auth
*auth
, bool is_lsp
)
3273 return (auth
->length
== passwd
->len
3274 && !memcmp(auth
->value
, passwd
->passwd
, passwd
->len
));
3277 static bool auth_validator_hmac_md5(struct isis_passwd
*passwd
,
3278 struct stream
*stream
,
3279 struct isis_auth
*auth
, bool is_lsp
)
3283 uint16_t rem_lifetime
;
3286 safe_auth_md5(stream
, &checksum
, &rem_lifetime
);
3288 memset(STREAM_DATA(stream
) + auth
->offset
, 0, 16);
3289 hmac_md5(STREAM_DATA(stream
), stream_get_endp(stream
), passwd
->passwd
,
3290 passwd
->len
, digest
);
3291 memcpy(STREAM_DATA(stream
) + auth
->offset
, auth
->value
, 16);
3293 bool rv
= !memcmp(digest
, auth
->value
, 16);
3296 restore_auth_md5(stream
, checksum
, rem_lifetime
);
3301 static const auth_validator_func auth_validators
[] = {
3302 [ISIS_PASSWD_TYPE_CLEARTXT
] = auth_validator_cleartxt
,
3303 [ISIS_PASSWD_TYPE_HMAC_MD5
] = auth_validator_hmac_md5
,
3306 bool isis_tlvs_auth_is_valid(struct isis_tlvs
*tlvs
, struct isis_passwd
*passwd
,
3307 struct stream
*stream
, bool is_lsp
)
3309 /* If no auth is set, always pass authentication */
3313 /* If we don't known how to validate the auth, return invalid */
3314 if (passwd
->type
>= array_size(auth_validators
)
3315 || !auth_validators
[passwd
->type
])
3318 struct isis_auth
*auth_head
= (struct isis_auth
*)tlvs
->isis_auth
.head
;
3319 struct isis_auth
*auth
;
3320 for (auth
= auth_head
; auth
; auth
= auth
->next
) {
3321 if (auth
->type
== passwd
->type
)
3325 /* If matching auth TLV could not be found, return invalid */
3329 /* Perform validation and return result */
3330 return auth_validators
[passwd
->type
](passwd
, stream
, auth
, is_lsp
);
3333 bool isis_tlvs_area_addresses_match(struct isis_tlvs
*tlvs
,
3334 struct list
*addresses
)
3336 struct isis_area_address
*addr_head
;
3338 addr_head
= (struct isis_area_address
*)tlvs
->area_addresses
.head
;
3339 for (struct isis_area_address
*addr
= addr_head
; addr
;
3340 addr
= addr
->next
) {
3341 struct listnode
*node
;
3342 struct area_addr
*a
;
3344 for (ALL_LIST_ELEMENTS_RO(addresses
, node
, a
)) {
3345 if (a
->addr_len
== addr
->len
3346 && !memcmp(a
->area_addr
, addr
->addr
, addr
->len
))
3354 static void tlvs_area_addresses_to_adj(struct isis_tlvs
*tlvs
,
3355 struct isis_adjacency
*adj
,
3358 if (adj
->area_address_count
!= tlvs
->area_addresses
.count
) {
3360 adj
->area_address_count
= tlvs
->area_addresses
.count
;
3361 adj
->area_addresses
= XREALLOC(
3362 MTYPE_ISIS_ADJACENCY_INFO
, adj
->area_addresses
,
3363 adj
->area_address_count
* sizeof(*adj
->area_addresses
));
3366 struct isis_area_address
*addr
= NULL
;
3367 for (unsigned int i
= 0; i
< tlvs
->area_addresses
.count
; i
++) {
3369 addr
= (struct isis_area_address
*)
3370 tlvs
->area_addresses
.head
;
3374 if (adj
->area_addresses
[i
].addr_len
== addr
->len
3375 && !memcmp(adj
->area_addresses
[i
].area_addr
, addr
->addr
,
3381 adj
->area_addresses
[i
].addr_len
= addr
->len
;
3382 memcpy(adj
->area_addresses
[i
].area_addr
, addr
->addr
, addr
->len
);
3386 static void tlvs_protocols_supported_to_adj(struct isis_tlvs
*tlvs
,
3387 struct isis_adjacency
*adj
,
3390 bool ipv4_supported
= false, ipv6_supported
= false;
3392 for (uint8_t i
= 0; i
< tlvs
->protocols_supported
.count
; i
++) {
3393 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IP
)
3394 ipv4_supported
= true;
3395 if (tlvs
->protocols_supported
.protocols
[i
] == NLPID_IPV6
)
3396 ipv6_supported
= true;
3399 struct nlpids reduced
= {0};
3401 if (ipv4_supported
&& ipv6_supported
) {
3403 reduced
.nlpids
[0] = NLPID_IP
;
3404 reduced
.nlpids
[1] = NLPID_IPV6
;
3405 } else if (ipv4_supported
) {
3407 reduced
.nlpids
[0] = NLPID_IP
;
3408 } else if (ipv6_supported
) {
3410 reduced
.nlpids
[1] = NLPID_IPV6
;
3415 if (adj
->nlpids
.count
== reduced
.count
3416 && !memcmp(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
))
3420 adj
->nlpids
.count
= reduced
.count
;
3421 memcpy(adj
->nlpids
.nlpids
, reduced
.nlpids
, reduced
.count
);
3424 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs
*tlvs
,
3425 struct isis_adjacency
*adj
,
3428 if (adj
->ipv4_address_count
!= tlvs
->ipv4_address
.count
) {
3430 adj
->ipv4_address_count
= tlvs
->ipv4_address
.count
;
3431 adj
->ipv4_addresses
= XREALLOC(
3432 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv4_addresses
,
3433 adj
->ipv4_address_count
* sizeof(*adj
->ipv4_addresses
));
3436 struct isis_ipv4_address
*addr
= NULL
;
3437 for (unsigned int i
= 0; i
< tlvs
->ipv4_address
.count
; i
++) {
3439 addr
= (struct isis_ipv4_address
*)
3440 tlvs
->ipv4_address
.head
;
3444 if (!memcmp(&adj
->ipv4_addresses
[i
], &addr
->addr
,
3445 sizeof(addr
->addr
)))
3449 adj
->ipv4_addresses
[i
] = addr
->addr
;
3453 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs
*tlvs
,
3454 struct isis_adjacency
*adj
,
3457 if (adj
->ipv6_address_count
!= tlvs
->ipv6_address
.count
) {
3459 adj
->ipv6_address_count
= tlvs
->ipv6_address
.count
;
3460 adj
->ipv6_addresses
= XREALLOC(
3461 MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv6_addresses
,
3462 adj
->ipv6_address_count
* sizeof(*adj
->ipv6_addresses
));
3465 struct isis_ipv6_address
*addr
= NULL
;
3466 for (unsigned int i
= 0; i
< tlvs
->ipv6_address
.count
; i
++) {
3468 addr
= (struct isis_ipv6_address
*)
3469 tlvs
->ipv6_address
.head
;
3473 if (!memcmp(&adj
->ipv6_addresses
[i
], &addr
->addr
,
3474 sizeof(addr
->addr
)))
3478 adj
->ipv6_addresses
[i
] = addr
->addr
;
3482 void isis_tlvs_to_adj(struct isis_tlvs
*tlvs
, struct isis_adjacency
*adj
,
3487 tlvs_area_addresses_to_adj(tlvs
, adj
, changed
);
3488 tlvs_protocols_supported_to_adj(tlvs
, adj
, changed
);
3489 tlvs_ipv4_addresses_to_adj(tlvs
, adj
, changed
);
3490 tlvs_ipv6_addresses_to_adj(tlvs
, adj
, changed
);
3493 bool isis_tlvs_own_snpa_found(struct isis_tlvs
*tlvs
, uint8_t *snpa
)
3495 struct isis_lan_neighbor
*ne_head
;
3497 ne_head
= (struct isis_lan_neighbor
*)tlvs
->lan_neighbor
.head
;
3498 for (struct isis_lan_neighbor
*ne
= ne_head
; ne
; ne
= ne
->next
) {
3499 if (!memcmp(ne
->mac
, snpa
, ETH_ALEN
))
3506 void isis_tlvs_add_lsp_entry(struct isis_tlvs
*tlvs
, struct isis_lsp
*lsp
)
3508 struct isis_lsp_entry
*entry
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*entry
));
3510 entry
->rem_lifetime
= lsp
->hdr
.rem_lifetime
;
3511 memcpy(entry
->id
, lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
+ 2);
3512 entry
->checksum
= lsp
->hdr
.checksum
;
3513 entry
->seqno
= lsp
->hdr
.seqno
;
3516 append_item(&tlvs
->lsp_entries
, (struct isis_item
*)entry
);
3519 void isis_tlvs_add_csnp_entries(struct isis_tlvs
*tlvs
, uint8_t *start_id
,
3520 uint8_t *stop_id
, uint16_t num_lsps
,
3521 dict_t
*lspdb
, struct isis_lsp
**last_lsp
)
3523 dnode_t
*first
= dict_lower_bound(lspdb
, start_id
);
3527 dnode_t
*last
= dict_upper_bound(lspdb
, stop_id
);
3528 dnode_t
*curr
= first
;
3530 isis_tlvs_add_lsp_entry(tlvs
, first
->dict_data
);
3531 *last_lsp
= first
->dict_data
;
3534 curr
= dict_next(lspdb
, curr
);
3536 isis_tlvs_add_lsp_entry(tlvs
, curr
->dict_data
);
3537 *last_lsp
= curr
->dict_data
;
3539 if (curr
== last
|| tlvs
->lsp_entries
.count
== num_lsps
)
3544 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs
*tlvs
,
3545 const char *hostname
)
3547 XFREE(MTYPE_ISIS_TLV
, tlvs
->hostname
);
3549 tlvs
->hostname
= XSTRDUP(MTYPE_ISIS_TLV
, hostname
);
3552 void isis_tlvs_set_te_router_id(struct isis_tlvs
*tlvs
,
3553 const struct in_addr
*id
)
3555 XFREE(MTYPE_ISIS_TLV
, tlvs
->te_router_id
);
3558 tlvs
->te_router_id
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*id
));
3559 memcpy(tlvs
->te_router_id
, id
, sizeof(*id
));
3562 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs
*tlvs
,
3563 struct prefix_ipv4
*dest
, uint8_t metric
)
3565 struct isis_oldstyle_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3568 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3569 apply_mask_ipv4(&r
->prefix
);
3570 append_item(&tlvs
->oldstyle_ip_reach
, (struct isis_item
*)r
);
3573 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs
*tlvs
,
3574 struct prefix_ipv4
*dest
, uint32_t metric
)
3576 struct isis_extended_ip_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3579 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3580 apply_mask_ipv4(&r
->prefix
);
3581 append_item(&tlvs
->extended_ip_reach
, (struct isis_item
*)r
);
3584 void isis_tlvs_add_ipv6_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3585 struct prefix_ipv6
*dest
, uint32_t metric
)
3587 struct isis_ipv6_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3590 memcpy(&r
->prefix
, dest
, sizeof(*dest
));
3591 apply_mask_ipv6(&r
->prefix
);
3593 struct isis_item_list
*l
;
3594 l
= (mtid
== ISIS_MT_IPV4_UNICAST
)
3596 : isis_get_mt_items(&tlvs
->mt_ipv6_reach
, mtid
);
3597 append_item(l
, (struct isis_item
*)r
);
3600 void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3601 struct prefix_ipv6
*dest
,
3602 struct prefix_ipv6
*src
,
3605 isis_tlvs_add_ipv6_reach(tlvs
, mtid
, dest
, metric
);
3606 struct isis_item_list
*l
= isis_get_mt_items(&tlvs
->mt_ipv6_reach
,
3609 struct isis_ipv6_reach
*r
= (struct isis_ipv6_reach
*)last_item(l
);
3610 r
->subtlvs
= isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH
);
3611 r
->subtlvs
->source_prefix
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*src
));
3612 memcpy(r
->subtlvs
->source_prefix
, src
, sizeof(*src
));
3615 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs
*tlvs
, uint8_t *id
,
3618 struct isis_oldstyle_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3621 memcpy(r
->id
, id
, sizeof(r
->id
));
3622 append_item(&tlvs
->oldstyle_reach
, (struct isis_item
*)r
);
3625 void isis_tlvs_add_extended_reach(struct isis_tlvs
*tlvs
, uint16_t mtid
,
3626 uint8_t *id
, uint32_t metric
,
3627 uint8_t *subtlvs
, uint8_t subtlv_len
)
3629 struct isis_extended_reach
*r
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*r
));
3631 memcpy(r
->id
, id
, sizeof(r
->id
));
3633 if (subtlvs
&& subtlv_len
) {
3634 r
->subtlvs
= XCALLOC(MTYPE_ISIS_TLV
, subtlv_len
);
3635 memcpy(r
->subtlvs
, subtlvs
, subtlv_len
);
3636 r
->subtlv_len
= subtlv_len
;
3639 struct isis_item_list
*l
;
3640 if (mtid
== ISIS_MT_IPV4_UNICAST
)
3641 l
= &tlvs
->extended_reach
;
3643 l
= isis_get_mt_items(&tlvs
->mt_reach
, mtid
);
3644 append_item(l
, (struct isis_item
*)r
);
3647 void isis_tlvs_add_threeway_adj(struct isis_tlvs
*tlvs
,
3648 enum isis_threeway_state state
,
3649 uint32_t local_circuit_id
,
3650 const uint8_t *neighbor_id
,
3651 uint32_t neighbor_circuit_id
)
3653 assert(!tlvs
->threeway_adj
);
3655 tlvs
->threeway_adj
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->threeway_adj
));
3656 tlvs
->threeway_adj
->state
= state
;
3657 tlvs
->threeway_adj
->local_circuit_id
= local_circuit_id
;
3660 tlvs
->threeway_adj
->neighbor_set
= true;
3661 memcpy(tlvs
->threeway_adj
->neighbor_id
, neighbor_id
, 6);
3662 tlvs
->threeway_adj
->neighbor_circuit_id
= neighbor_circuit_id
;
3666 void isis_tlvs_add_spine_leaf(struct isis_tlvs
*tlvs
, uint8_t tier
,
3667 bool has_tier
, bool is_leaf
, bool is_spine
,
3670 assert(!tlvs
->spine_leaf
);
3672 tlvs
->spine_leaf
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*tlvs
->spine_leaf
));
3675 tlvs
->spine_leaf
->tier
= tier
;
3678 tlvs
->spine_leaf
->has_tier
= has_tier
;
3679 tlvs
->spine_leaf
->is_leaf
= is_leaf
;
3680 tlvs
->spine_leaf
->is_spine
= is_spine
;
3681 tlvs
->spine_leaf
->is_backup
= is_backup
;
3684 struct isis_mt_router_info
*
3685 isis_tlvs_lookup_mt_router_info(struct isis_tlvs
*tlvs
, uint16_t mtid
)
3687 if (tlvs
->mt_router_info_empty
)
3690 struct isis_mt_router_info
*rv
;
3691 for (rv
= (struct isis_mt_router_info
*)tlvs
->mt_router_info
.head
; rv
;
3693 if (rv
->mtid
== mtid
)
3700 void isis_tlvs_set_purge_originator(struct isis_tlvs
*tlvs
,
3701 const uint8_t *generator
,
3702 const uint8_t *sender
)
3704 assert(!tlvs
->purge_originator
);
3706 tlvs
->purge_originator
= XCALLOC(MTYPE_ISIS_TLV
,
3707 sizeof(*tlvs
->purge_originator
));
3708 memcpy(tlvs
->purge_originator
->generator
, generator
,
3709 sizeof(tlvs
->purge_originator
->generator
));
3711 tlvs
->purge_originator
->sender_set
= true;
3712 memcpy(tlvs
->purge_originator
->sender
, sender
,
3713 sizeof(tlvs
->purge_originator
->sender
));