]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_tlvs.c
Merge pull request #7261 from Niral-Networks/niral_dev_vrf_ospf6
[mirror_frr.git] / isisd / isis_tlvs.c
CommitLineData
7ef5fefc
CF
1/*
2 * IS-IS TLV Serializer/Deserializer
3 *
4 * Copyright (C) 2015,2017 Christian Franke
5 *
1b3f47d0
OD
6 * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR)
7 *
7ef5fefc
CF
8 * This file is part of FRR.
9 *
10 * FRR is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2, or (at your option) any
13 * later version.
14 *
15 * FRR is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with FRR; see the file COPYING. If not, write to the Free
22 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23 * 02111-1307, USA.
24 */
25#include <zebra.h>
26
6252100f 27#ifdef CRYPTO_INTERNAL
7ef5fefc 28#include "md5.h"
6252100f 29#endif
7ef5fefc
CF
30#include "memory.h"
31#include "stream.h"
32#include "sbuf.h"
1b3f47d0 33#include "network.h"
7ef5fefc
CF
34
35#include "isisd/isisd.h"
36#include "isisd/isis_memory.h"
841791b6 37#include "isisd/isis_tlvs.h"
7ef5fefc
CF
38#include "isisd/isis_common.h"
39#include "isisd/isis_mt.h"
40#include "isisd/isis_misc.h"
41#include "isisd/isis_adjacency.h"
42#include "isisd/isis_circuit.h"
43#include "isisd/isis_pdu.h"
44#include "isisd/isis_lsp.h"
45#include "isisd/isis_te.h"
26f6acaf 46#include "isisd/isis_sr.h"
7ef5fefc 47
841791b6 48DEFINE_MTYPE_STATIC(ISISD, ISIS_TLV, "ISIS TLVs")
26f6acaf 49DEFINE_MTYPE(ISISD, ISIS_SUBTLV, "ISIS Sub-TLVs")
7ef5fefc
CF
50DEFINE_MTYPE_STATIC(ISISD, ISIS_MT_ITEM_LIST, "ISIS MT Item Lists")
51
52typedef int (*unpack_tlv_func)(enum isis_tlv_context context, uint8_t tlv_type,
53 uint8_t tlv_len, struct stream *s,
54 struct sbuf *log, void *dest, int indent);
55typedef int (*pack_item_func)(struct isis_item *item, struct stream *s);
56typedef void (*free_item_func)(struct isis_item *i);
57typedef int (*unpack_item_func)(uint16_t mtid, uint8_t len, struct stream *s,
58 struct sbuf *log, void *dest, int indent);
59typedef void (*format_item_func)(uint16_t mtid, struct isis_item *i,
60 struct sbuf *buf, int indent);
61typedef struct isis_item *(*copy_item_func)(struct isis_item *i);
62
63struct tlv_ops {
64 const char *name;
65 unpack_tlv_func unpack;
66
67 pack_item_func pack_item;
68 free_item_func free_item;
69 unpack_item_func unpack_item;
70 format_item_func format_item;
71 copy_item_func copy_item;
72};
73
74enum how_to_pack {
75 ISIS_ITEMS,
76 ISIS_MT_ITEMS,
77};
78
79struct pack_order_entry {
80 enum isis_tlv_context context;
81 enum isis_tlv_type type;
82 enum how_to_pack how_to_pack;
83 size_t what_to_pack;
84};
85#define PACK_ENTRY(t, h, w) \
86 { \
87 .context = ISIS_CONTEXT_LSP, .type = ISIS_TLV_##t, \
88 .how_to_pack = (h), \
89 .what_to_pack = offsetof(struct isis_tlvs, w), \
90 }
91
2b64873d 92static const struct pack_order_entry pack_order[] = {
7ef5fefc
CF
93 PACK_ENTRY(OLDSTYLE_REACH, ISIS_ITEMS, oldstyle_reach),
94 PACK_ENTRY(LAN_NEIGHBORS, ISIS_ITEMS, lan_neighbor),
95 PACK_ENTRY(LSP_ENTRY, ISIS_ITEMS, lsp_entries),
96 PACK_ENTRY(EXTENDED_REACH, ISIS_ITEMS, extended_reach),
97 PACK_ENTRY(MT_REACH, ISIS_MT_ITEMS, mt_reach),
98 PACK_ENTRY(OLDSTYLE_IP_REACH, ISIS_ITEMS, oldstyle_ip_reach),
99 PACK_ENTRY(OLDSTYLE_IP_REACH_EXT, ISIS_ITEMS, oldstyle_ip_reach_ext),
100 PACK_ENTRY(IPV4_ADDRESS, ISIS_ITEMS, ipv4_address),
101 PACK_ENTRY(IPV6_ADDRESS, ISIS_ITEMS, ipv6_address),
102 PACK_ENTRY(EXTENDED_IP_REACH, ISIS_ITEMS, extended_ip_reach),
103 PACK_ENTRY(MT_IP_REACH, ISIS_MT_ITEMS, mt_ip_reach),
104 PACK_ENTRY(IPV6_REACH, ISIS_ITEMS, ipv6_reach),
1b3f47d0
OD
105 PACK_ENTRY(MT_IPV6_REACH, ISIS_MT_ITEMS, mt_ipv6_reach)
106};
7ef5fefc
CF
107
108/* This is a forward definition. The table is actually initialized
109 * in at the bottom. */
2b64873d 110static const struct tlv_ops *const tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX];
7ef5fefc
CF
111
112/* End of _ops forward definition. */
113
114/* Prototypes */
115static void append_item(struct isis_item_list *dest, struct isis_item *item);
1b3f47d0 116static void init_item_list(struct isis_item_list *items);
7ef5fefc 117
1b3f47d0
OD
118/* Functions for Extended IS Reachability SubTLVs a.k.a Traffic Engineering */
119struct isis_ext_subtlvs *isis_alloc_ext_subtlvs(void)
120{
121 struct isis_ext_subtlvs *ext;
122
123 ext = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_ext_subtlvs));
124 init_item_list(&ext->adj_sid);
125 init_item_list(&ext->lan_sid);
126
127 return ext;
128}
129
130/*
131 * mtid parameter is used to determine if Adjacency is related to IPv4 or IPv6.
132 * A negative value could be used to skip copy of Adjacency SID.
133 */
134static struct isis_ext_subtlvs *
135copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, int16_t mtid)
136{
137 struct isis_ext_subtlvs *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
138 struct isis_adj_sid *adj;
139 struct isis_lan_adj_sid *lan;
140
141 memcpy(rv, exts, sizeof(struct isis_ext_subtlvs));
142 init_item_list(&rv->adj_sid);
143 init_item_list(&rv->lan_sid);
144
145 UNSET_SUBTLV(rv, EXT_ADJ_SID);
146 UNSET_SUBTLV(rv, EXT_LAN_ADJ_SID);
147
148 /* Copy Adj SID and LAN Adj SID list for IPv4 if needed */
149 for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj != NULL;
150 adj = adj->next) {
151 if ((mtid != -1)
152 && (((mtid == ISIS_MT_IPV4_UNICAST)
153 && (adj->family != AF_INET))
154 || ((mtid == ISIS_MT_IPV6_UNICAST)
155 && (adj->family != AF_INET6))))
156 continue;
157
158 struct isis_adj_sid *new;
159
160 new = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_adj_sid));
161 new->family = adj->family;
162 new->flags = adj->flags;
163 new->weight = adj->weight;
164 new->sid = adj->sid;
165 append_item(&rv->adj_sid, (struct isis_item *)new);
166 SET_SUBTLV(rv, EXT_ADJ_SID);
167 }
bd507085 168
1b3f47d0
OD
169 for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; lan != NULL;
170 lan = lan->next) {
171 if ((mtid != -1)
172 && (((mtid == ISIS_MT_IPV4_UNICAST)
173 && (lan->family != AF_INET))
174 || ((mtid == ISIS_MT_IPV6_UNICAST)
175 && (lan->family != AF_INET6))))
176 continue;
177
178 struct isis_lan_adj_sid *new;
179
180 new = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_lan_adj_sid));
181 new->family = lan->family;
182 new->flags = lan->flags;
183 new->weight = lan->weight;
184 memcpy(new->neighbor_id, lan->neighbor_id, 6);
185 new->sid = lan->sid;
186 append_item(&rv->lan_sid, (struct isis_item *)new);
187 SET_SUBTLV(rv, EXT_LAN_ADJ_SID);
188 }
189
190 return rv;
191}
192
193/* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */
194static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
195 struct sbuf *buf, int indent,
196 uint16_t mtid)
197{
198
199 char ibuf[PREFIX2STR_BUFFER];
200
201 /* Standard metrics */
202 if (IS_SUBTLV(exts, EXT_ADM_GRP))
6cde4b45 203 sbuf_push(buf, indent, "Administrative Group: 0x%x\n",
1b3f47d0
OD
204 exts->adm_group);
205 if (IS_SUBTLV(exts, EXT_LLRI)) {
6cde4b45 206 sbuf_push(buf, indent, "Link Local ID: %u\n",
1b3f47d0 207 exts->local_llri);
6cde4b45 208 sbuf_push(buf, indent, "Link Remote ID: %u\n",
1b3f47d0
OD
209 exts->remote_llri);
210 }
211 if (IS_SUBTLV(exts, EXT_LOCAL_ADDR))
a854ea43
MS
212 sbuf_push(buf, indent, "Local Interface IP Address(es): %pI4\n",
213 &exts->local_addr);
1b3f47d0 214 if (IS_SUBTLV(exts, EXT_NEIGH_ADDR))
a854ea43
MS
215 sbuf_push(buf, indent, "Remote Interface IP Address(es): %pI4\n",
216 &exts->neigh_addr);
1b3f47d0
OD
217 if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6))
218 sbuf_push(buf, indent, "Local Interface IPv6 Address(es): %s\n",
219 inet_ntop(AF_INET6, &exts->local_addr6, ibuf,
220 PREFIX2STR_BUFFER));
221 if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6))
222 sbuf_push(buf, indent, "Remote Interface IPv6 Address(es): %s\n",
223 inet_ntop(AF_INET6, &exts->local_addr6, ibuf,
224 PREFIX2STR_BUFFER));
225 if (IS_SUBTLV(exts, EXT_MAX_BW))
226 sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n",
227 exts->max_bw);
228 if (IS_SUBTLV(exts, EXT_MAX_RSV_BW))
229 sbuf_push(buf, indent,
230 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
231 exts->max_rsv_bw);
232 if (IS_SUBTLV(exts, EXT_UNRSV_BW)) {
233 sbuf_push(buf, indent, "Unreserved Bandwidth:\n");
234 for (int j = 0; j < MAX_CLASS_TYPE; j += 2) {
235 sbuf_push(buf, indent + 2,
236 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
237 j, exts->unrsv_bw[j],
238 j + 1, exts->unrsv_bw[j + 1]);
239 }
240 }
241 if (IS_SUBTLV(exts, EXT_TE_METRIC))
242 sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n",
243 exts->te_metric);
244 if (IS_SUBTLV(exts, EXT_RMT_AS))
245 sbuf_push(buf, indent,
6cde4b45 246 "Inter-AS TE Remote AS number: %u\n",
1b3f47d0
OD
247 exts->remote_as);
248 if (IS_SUBTLV(exts, EXT_RMT_IP))
249 sbuf_push(buf, indent,
a854ea43
MS
250 "Inter-AS TE Remote ASBR IP address: %pI4\n",
251 &exts->remote_ip);
1b3f47d0
OD
252 /* Extended metrics */
253 if (IS_SUBTLV(exts, EXT_DELAY))
254 sbuf_push(buf, indent,
6cde4b45 255 "%s Average Link Delay: %u (micro-sec)\n",
1b3f47d0
OD
256 IS_ANORMAL(exts->delay) ? "Anomalous" : "Normal",
257 exts->delay);
258 if (IS_SUBTLV(exts, EXT_MM_DELAY)) {
6cde4b45 259 sbuf_push(buf, indent, "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
1b3f47d0
OD
260 IS_ANORMAL(exts->min_delay) ? "Anomalous" : "Normal",
261 exts->min_delay & TE_EXT_MASK,
262 exts->max_delay & TE_EXT_MASK);
263 }
264 if (IS_SUBTLV(exts, EXT_DELAY_VAR)) {
265 sbuf_push(buf, indent,
6cde4b45 266 "Delay Variation: %u (micro-sec)\n",
1b3f47d0
OD
267 exts->delay_var & TE_EXT_MASK);
268 }
269 if (IS_SUBTLV(exts, EXT_PKT_LOSS))
270 sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n",
271 IS_ANORMAL(exts->pkt_loss) ? "Anomalous" : "Normal",
272 (float)((exts->pkt_loss & TE_EXT_MASK)
273 * LOSS_PRECISION));
274 if (IS_SUBTLV(exts, EXT_RES_BW))
275 sbuf_push(buf, indent,
276 "Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
277 exts->res_bw);
278 if (IS_SUBTLV(exts, EXT_AVA_BW))
279 sbuf_push(buf, indent,
280 "Unidir. Available Bandwidth: %g (Bytes/sec)\n",
281 exts->ava_bw);
282 if (IS_SUBTLV(exts, EXT_USE_BW))
283 sbuf_push(buf, indent,
284 "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
285 exts->use_bw);
f2333421 286 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
1b3f47d0
OD
287 if (IS_SUBTLV(exts, EXT_ADJ_SID)) {
288 struct isis_adj_sid *adj;
289
290 for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj;
291 adj = adj->next) {
292 if (((mtid == ISIS_MT_IPV4_UNICAST)
293 && (adj->family != AF_INET))
294 || ((mtid == ISIS_MT_IPV6_UNICAST)
295 && (adj->family != AF_INET6)))
296 continue;
297 sbuf_push(
298 buf, indent,
6cde4b45 299 "Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n",
1b3f47d0
OD
300 adj->sid, adj->weight,
301 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? '1'
302 : '0',
303 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? '1'
304 : '0',
305 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG ? '1'
306 : '0',
307 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG ? '1'
308 : '0',
309 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG ? '1'
310 : '0',
311 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
312 ? '1'
313 : '0');
314 }
315 }
f2333421 316 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
1b3f47d0
OD
317 if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) {
318 struct isis_lan_adj_sid *lan;
319
320 for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head;
321 lan; lan = lan->next) {
322 if (((mtid == ISIS_MT_IPV4_UNICAST)
323 && (lan->family != AF_INET))
324 || ((mtid == ISIS_MT_IPV6_UNICAST)
325 && (lan->family != AF_INET6)))
326 continue;
327 sbuf_push(buf, indent,
6cde4b45 328 "Lan-Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n"
1b3f47d0
OD
329 " Neighbor-ID: %s\n",
330 lan->sid, lan->weight,
331 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
332 ? '1'
333 : '0',
334 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
335 ? '1'
336 : '0',
337 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
338 ? '1'
339 : '0',
340 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
341 ? '1'
342 : '0',
343 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
344 ? '1'
345 : '0',
346 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
347 ? '1'
348 : '0',
349 isis_format_id(lan->neighbor_id, 6));
350 }
351 }
352}
353
354static void free_item_ext_subtlvs(struct isis_ext_subtlvs *exts)
355{
356 struct isis_item *item, *next_item;
357
358 /* First, free Adj SID and LAN Adj SID list if needed */
359 for (item = exts->adj_sid.head; item; item = next_item) {
360 next_item = item->next;
361 XFREE(MTYPE_ISIS_SUBTLV, item);
362 }
363 for (item = exts->lan_sid.head; item; item = next_item) {
364 next_item = item->next;
365 XFREE(MTYPE_ISIS_SUBTLV, item);
366 }
367 XFREE(MTYPE_ISIS_SUBTLV, exts);
368}
369
370static int pack_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
371 struct stream *s)
372{
373 uint8_t size;
374
375 if (STREAM_WRITEABLE(s) < ISIS_SUBTLV_MAX_SIZE)
376 return 1;
377
378 if (IS_SUBTLV(exts, EXT_ADM_GRP)) {
379 stream_putc(s, ISIS_SUBTLV_ADMIN_GRP);
380 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
381 stream_putl(s, exts->adm_group);
382 }
383 if (IS_SUBTLV(exts, EXT_LLRI)) {
384 stream_putc(s, ISIS_SUBTLV_LLRI);
385 stream_putc(s, ISIS_SUBTLV_LLRI_SIZE);
386 stream_putl(s, exts->local_llri);
387 stream_putl(s, exts->remote_llri);
388 }
389 if (IS_SUBTLV(exts, EXT_LOCAL_ADDR)) {
390 stream_putc(s, ISIS_SUBTLV_LOCAL_IPADDR);
391 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
392 stream_put(s, &exts->local_addr.s_addr, 4);
393 }
394 if (IS_SUBTLV(exts, EXT_NEIGH_ADDR)) {
395 stream_putc(s, ISIS_SUBTLV_RMT_IPADDR);
396 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
397 stream_put(s, &exts->neigh_addr.s_addr, 4);
398 }
399 if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6)) {
400 stream_putc(s, ISIS_SUBTLV_LOCAL_IPADDR6);
401 stream_putc(s, ISIS_SUBTLV_IPV6_ADDR_SIZE);
402 stream_put(s, &exts->local_addr6, 16);
403 }
404 if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6)) {
405 stream_putc(s, ISIS_SUBTLV_RMT_IPADDR6);
406 stream_putc(s, ISIS_SUBTLV_IPV6_ADDR_SIZE);
407 stream_put(s, &exts->neigh_addr6, 16);
408 }
409 if (IS_SUBTLV(exts, EXT_MAX_BW)) {
410 stream_putc(s, ISIS_SUBTLV_MAX_BW);
411 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
412 stream_putf(s, exts->max_bw);
413 }
414 if (IS_SUBTLV(exts, EXT_MAX_RSV_BW)) {
415 stream_putc(s, ISIS_SUBTLV_MAX_RSV_BW);
416 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
417 stream_putf(s, exts->max_rsv_bw);
418 }
419 if (IS_SUBTLV(exts, EXT_UNRSV_BW)) {
420 stream_putc(s, ISIS_SUBTLV_UNRSV_BW);
421 stream_putc(s, ISIS_SUBTLV_UNRSV_BW_SIZE);
422 for (int j = 0; j < MAX_CLASS_TYPE; j++)
423 stream_putf(s, exts->unrsv_bw[j]);
424 }
425 if (IS_SUBTLV(exts, EXT_TE_METRIC)) {
426 stream_putc(s, ISIS_SUBTLV_TE_METRIC);
427 stream_putc(s, ISIS_SUBTLV_TE_METRIC_SIZE);
428 stream_put3(s, exts->te_metric);
429 }
430 if (IS_SUBTLV(exts, EXT_RMT_AS)) {
431 stream_putc(s, ISIS_SUBTLV_RAS);
432 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
433 stream_putl(s, exts->remote_as);
434 }
435 if (IS_SUBTLV(exts, EXT_RMT_IP)) {
436 stream_putc(s, ISIS_SUBTLV_RIP);
437 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
438 stream_put(s, &exts->remote_ip.s_addr, 4);
439 }
440 if (IS_SUBTLV(exts, EXT_DELAY)) {
441 stream_putc(s, ISIS_SUBTLV_AV_DELAY);
442 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
443 stream_putl(s, exts->delay);
444 }
445 if (IS_SUBTLV(exts, EXT_MM_DELAY)) {
446 stream_putc(s, ISIS_SUBTLV_MM_DELAY);
447 stream_putc(s, ISIS_SUBTLV_MM_DELAY_SIZE);
448 stream_putl(s, exts->min_delay);
449 stream_putl(s, exts->max_delay);
450 }
451 if (IS_SUBTLV(exts, EXT_DELAY_VAR)) {
452 stream_putc(s, ISIS_SUBTLV_DELAY_VAR);
453 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
454 stream_putl(s, exts->delay_var);
455 }
456 if (IS_SUBTLV(exts, EXT_PKT_LOSS)) {
457 stream_putc(s, ISIS_SUBTLV_PKT_LOSS);
458 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
459 stream_putl(s, exts->pkt_loss);
460 }
461 if (IS_SUBTLV(exts, EXT_RES_BW)) {
462 stream_putc(s, ISIS_SUBTLV_RES_BW);
463 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
464 stream_putf(s, exts->res_bw);
465 }
466 if (IS_SUBTLV(exts, EXT_AVA_BW)) {
467 stream_putc(s, ISIS_SUBTLV_AVA_BW);
468 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
469 stream_putf(s, exts->ava_bw);
470 }
471 if (IS_SUBTLV(exts, EXT_USE_BW)) {
472 stream_putc(s, ISIS_SUBTLV_USE_BW);
473 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
474 stream_putf(s, exts->use_bw);
475 }
f2333421 476 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
1b3f47d0
OD
477 if (IS_SUBTLV(exts, EXT_ADJ_SID)) {
478 struct isis_adj_sid *adj;
479
480 for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj;
481 adj = adj->next) {
482 stream_putc(s, ISIS_SUBTLV_ADJ_SID);
483 size = ISIS_SUBTLV_ADJ_SID_SIZE;
484 if (!(adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG))
485 size++;
486 stream_putc(s, size);
487 stream_putc(s, adj->flags);
488 stream_putc(s, adj->weight);
489 if (adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG)
490 stream_put3(s, adj->sid);
491 else
492 stream_putl(s, adj->sid);
493
494 }
495 }
f2333421 496 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
1b3f47d0
OD
497 if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) {
498 struct isis_lan_adj_sid *lan;
499
500 for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; lan;
501 lan = lan->next) {
502 stream_putc(s, ISIS_SUBTLV_LAN_ADJ_SID);
503 size = ISIS_SUBTLV_LAN_ADJ_SID_SIZE;
504 if (!(lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG))
505 size++;
506 stream_putc(s, size);
507 stream_putc(s, lan->flags);
508 stream_putc(s, lan->weight);
509 stream_put(s, lan->neighbor_id, 6);
510 if (lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG)
511 stream_put3(s, lan->sid);
512 else
513 stream_putl(s, lan->sid);
514 }
515 }
516
517 return 0;
518}
519
520static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s,
521 struct sbuf *log, void *dest, int indent)
522{
523 uint8_t sum = 0;
524 uint8_t subtlv_type;
525 uint8_t subtlv_len;
526
527 struct isis_extended_reach *rv = dest;
528 struct isis_ext_subtlvs *exts = isis_alloc_ext_subtlvs();
529
530 rv->subtlvs = exts;
531
532 /*
533 * Parse subTLVs until reach subTLV length
534 * Check that it remains at least 2 bytes: subTLV Type & Length
535 */
536 while (len > sum + 2) {
537 /* Read SubTLV Type and Length */
538 subtlv_type = stream_getc(s);
539 subtlv_len = stream_getc(s);
540 if (subtlv_len > len - sum) {
47b13e9b 541 sbuf_push(log, indent, "TLV %hhu: Available data %u is less than TLV size %u !\n",
1b3f47d0
OD
542 subtlv_type, len - sum, subtlv_len);
543 return 1;
544 }
545
546 switch (subtlv_type) {
547 /* Standard Metric as defined in RFC5305 */
548 case ISIS_SUBTLV_ADMIN_GRP:
549 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
550 sbuf_push(log, indent,
551 "TLV size does not match expected size for Administrative Group!\n");
552 } else {
553 exts->adm_group = stream_getl(s);
554 SET_SUBTLV(exts, EXT_ADM_GRP);
555 }
556 break;
557 case ISIS_SUBTLV_LLRI:
558 if (subtlv_len != ISIS_SUBTLV_LLRI_SIZE) {
559 sbuf_push(log, indent,
560 "TLV size does not match expected size for Link ID!\n");
561 } else {
562 exts->local_llri = stream_getl(s);
563 exts->remote_llri = stream_getl(s);
564 SET_SUBTLV(exts, EXT_LLRI);
565 }
566 break;
567 case ISIS_SUBTLV_LOCAL_IPADDR:
568 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
569 sbuf_push(log, indent,
570 "TLV size does not match expected size for Local IP address!\n");
571 } else {
572 stream_get(&exts->local_addr.s_addr, s, 4);
573 SET_SUBTLV(exts, EXT_LOCAL_ADDR);
574 }
575 break;
576 case ISIS_SUBTLV_RMT_IPADDR:
577 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
578 sbuf_push(log, indent,
579 "TLV size does not match expected size for Remote IP address!\n");
580 } else {
581 stream_get(&exts->neigh_addr.s_addr, s, 4);
582 SET_SUBTLV(exts, EXT_NEIGH_ADDR);
583 }
584 break;
585 case ISIS_SUBTLV_LOCAL_IPADDR6:
586 if (subtlv_len != ISIS_SUBTLV_IPV6_ADDR_SIZE) {
587 sbuf_push(log, indent,
588 "TLV size does not match expected size for Local IPv6 address!\n");
589 } else {
590 stream_get(&exts->local_addr6, s, 16);
591 SET_SUBTLV(exts, EXT_LOCAL_ADDR6);
592 }
593 break;
594 case ISIS_SUBTLV_RMT_IPADDR6:
595 if (subtlv_len != ISIS_SUBTLV_IPV6_ADDR_SIZE) {
596 sbuf_push(log, indent,
597 "TLV size does not match expected size for Remote IPv6 address!\n");
598 } else {
599 stream_get(&exts->neigh_addr6, s, 16);
600 SET_SUBTLV(exts, EXT_NEIGH_ADDR6);
601 }
602 break;
603 case ISIS_SUBTLV_MAX_BW:
604 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
605 sbuf_push(log, indent,
606 "TLV size does not match expected size for Maximum Bandwidth!\n");
607 } else {
608 exts->max_bw = stream_getf(s);
609 SET_SUBTLV(exts, EXT_MAX_BW);
610 }
611 break;
612 case ISIS_SUBTLV_MAX_RSV_BW:
613 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
614 sbuf_push(log, indent,
615 "TLV size does not match expected size for Maximum Reservable Bandwidth!\n");
616 } else {
617 exts->max_rsv_bw = stream_getf(s);
618 SET_SUBTLV(exts, EXT_MAX_RSV_BW);
619 }
620 break;
621 case ISIS_SUBTLV_UNRSV_BW:
622 if (subtlv_len != ISIS_SUBTLV_UNRSV_BW_SIZE) {
623 sbuf_push(log, indent,
624 "TLV size does not match expected size for Unreserved Bandwidth!\n");
625 } else {
626 for (int i = 0; i < MAX_CLASS_TYPE; i++)
627 exts->unrsv_bw[i] = stream_getf(s);
628 SET_SUBTLV(exts, EXT_UNRSV_BW);
629 }
630 break;
631 case ISIS_SUBTLV_TE_METRIC:
632 if (subtlv_len != ISIS_SUBTLV_TE_METRIC_SIZE) {
633 sbuf_push(log, indent,
634 "TLV size does not match expected size for Traffic Engineering Metric!\n");
635 } else {
636 exts->te_metric = stream_get3(s);
637 SET_SUBTLV(exts, EXT_TE_METRIC);
638 }
639 break;
640 case ISIS_SUBTLV_RAS:
641 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
642 sbuf_push(log, indent,
643 "TLV size does not match expected size for Remote AS number!\n");
644 } else {
645 exts->remote_as = stream_getl(s);
646 SET_SUBTLV(exts, EXT_RMT_AS);
647 }
648 break;
649 case ISIS_SUBTLV_RIP:
650 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
651 sbuf_push(log, indent,
652 "TLV size does not match expected size for Remote ASBR IP Address!\n");
653 } else {
654 stream_get(&exts->remote_ip.s_addr, s, 4);
655 SET_SUBTLV(exts, EXT_RMT_IP);
656 }
657 break;
658 /* Extended Metrics as defined in RFC 7810 */
659 case ISIS_SUBTLV_AV_DELAY:
660 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
661 sbuf_push(log, indent,
662 "TLV size does not match expected size for Average Link Delay!\n");
663 } else {
664 exts->delay = stream_getl(s);
665 SET_SUBTLV(exts, EXT_DELAY);
666 }
667 break;
668 case ISIS_SUBTLV_MM_DELAY:
669 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
670 sbuf_push(log, indent,
671 "TLV size does not match expected size for Min/Max Link Delay!\n");
672 } else {
673 exts->min_delay = stream_getl(s);
674 exts->max_delay = stream_getl(s);
675 SET_SUBTLV(exts, EXT_MM_DELAY);
676 }
677 break;
678 case ISIS_SUBTLV_DELAY_VAR:
679 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
680 sbuf_push(log, indent,
681 "TLV size does not match expected size for Delay Variation!\n");
682 } else {
683 exts->delay_var = stream_getl(s);
684 SET_SUBTLV(exts, EXT_DELAY_VAR);
685 }
686 break;
687 case ISIS_SUBTLV_PKT_LOSS:
688 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
689 sbuf_push(log, indent,
690 "TLV size does not match expected size for Link Packet Loss!\n");
691 } else {
692 exts->pkt_loss = stream_getl(s);
693 SET_SUBTLV(exts, EXT_PKT_LOSS);
694 }
695 break;
696 case ISIS_SUBTLV_RES_BW:
697 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
698 sbuf_push(log, indent,
699 "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n");
700 } else {
701 exts->res_bw = stream_getf(s);
702 SET_SUBTLV(exts, EXT_RES_BW);
703 }
704 break;
705 case ISIS_SUBTLV_AVA_BW:
706 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
707 sbuf_push(log, indent,
708 "TLV size does not match expected size for Unidirectional Available Bandwidth!\n");
709 } else {
710 exts->ava_bw = stream_getf(s);
711 SET_SUBTLV(exts, EXT_AVA_BW);
712 }
713 break;
714 case ISIS_SUBTLV_USE_BW:
715 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
716 sbuf_push(log, indent,
717 "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n");
718 } else {
719 exts->use_bw = stream_getf(s);
720 SET_SUBTLV(exts, EXT_USE_BW);
721 }
722 break;
f2333421 723 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
1b3f47d0
OD
724 case ISIS_SUBTLV_ADJ_SID:
725 if (subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE
726 && subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE + 1) {
727 sbuf_push(log, indent,
728 "TLV size does not match expected size for Adjacency SID!\n");
729 } else {
730 struct isis_adj_sid *adj;
731
732 adj = XCALLOC(MTYPE_ISIS_SUBTLV,
733 sizeof(struct isis_adj_sid));
734 adj->flags = stream_getc(s);
735 adj->weight = stream_getc(s);
736 if (adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) {
737 adj->sid = stream_get3(s);
738 adj->sid &= MPLS_LABEL_VALUE_MASK;
739 } else {
740 adj->sid = stream_getl(s);
741 }
742 if (mtid == ISIS_MT_IPV4_UNICAST)
743 adj->family = AF_INET;
744 if (mtid == ISIS_MT_IPV6_UNICAST)
745 adj->family = AF_INET6;
746 append_item(&exts->adj_sid,
747 (struct isis_item *)adj);
748 SET_SUBTLV(exts, EXT_ADJ_SID);
749 }
750 break;
f2333421 751 /* Segment Routing LAN-Adjacency as per RFC8667 section 2.2.2 */
1b3f47d0
OD
752 case ISIS_SUBTLV_LAN_ADJ_SID:
753 if (subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
754 && subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE + 1) {
755 sbuf_push(log, indent,
756 "TLV size does not match expected size for LAN-Adjacency SID!\n");
757 } else {
758 struct isis_lan_adj_sid *lan;
759
760 lan = XCALLOC(MTYPE_ISIS_SUBTLV,
761 sizeof(struct isis_lan_adj_sid));
762 lan->flags = stream_getc(s);
763 lan->weight = stream_getc(s);
764 stream_get(&(lan->neighbor_id), s,
765 ISIS_SYS_ID_LEN);
766 if (lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) {
767 lan->sid = stream_get3(s);
768 lan->sid &= MPLS_LABEL_VALUE_MASK;
769 } else {
770 lan->sid = stream_getl(s);
771 }
772 if (mtid == ISIS_MT_IPV4_UNICAST)
773 lan->family = AF_INET;
774 if (mtid == ISIS_MT_IPV6_UNICAST)
775 lan->family = AF_INET6;
776 append_item(&exts->lan_sid,
777 (struct isis_item *)lan);
778 SET_SUBTLV(exts, EXT_LAN_ADJ_SID);
779 }
780 break;
781 default:
782 /* Skip unknown TLV */
783 stream_forward_getp(s, subtlv_len);
784 break;
785 }
786 sum += subtlv_len + ISIS_SUBTLV_HDR_SIZE;
787 }
788
789 return 0;
790}
791
f2333421 792/* Functions for Sub-TLV 3 SR Prefix-SID as per RFC8667 section 2.1 */
bd507085
CF
793static struct isis_item *copy_item_prefix_sid(struct isis_item *i)
794{
795 struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
796 struct isis_prefix_sid *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
797
798 rv->flags = sid->flags;
799 rv->algorithm = sid->algorithm;
800 rv->value = sid->value;
801 return (struct isis_item *)rv;
802}
803
804static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i,
805 struct sbuf *buf, int indent)
806{
807 struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
808
1b3f47d0 809 sbuf_push(buf, indent, "SR Prefix-SID ");
bd507085 810 if (sid->flags & ISIS_PREFIX_SID_VALUE) {
6cde4b45 811 sbuf_push(buf, 0, "Label: %u, ", sid->value);
bd507085 812 } else {
6cde4b45 813 sbuf_push(buf, 0, "Index: %u, ", sid->value);
bd507085 814 }
6cde4b45 815 sbuf_push(buf, 0, "Algorithm: %hhu, ", sid->algorithm);
1b3f47d0
OD
816 sbuf_push(buf, 0, "Flags:%s%s%s%s%s%s\n",
817 sid->flags & ISIS_PREFIX_SID_READVERTISED ? " READVERTISED"
818 : "",
819 sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "",
820 sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO-PHP" : " PHP",
821 sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL ? " EXPLICIT-NULL"
822 : "",
823 sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "",
824 sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : "");
bd507085
CF
825}
826
827static void free_item_prefix_sid(struct isis_item *i)
828{
829 XFREE(MTYPE_ISIS_SUBTLV, i);
830}
831
832static int pack_item_prefix_sid(struct isis_item *i, struct stream *s)
833{
834 struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
835
836 uint8_t size = (sid->flags & ISIS_PREFIX_SID_VALUE) ? 5 : 6;
837
838 if (STREAM_WRITEABLE(s) < size)
839 return 1;
840
841 stream_putc(s, sid->flags);
842 stream_putc(s, sid->algorithm);
843
844 if (sid->flags & ISIS_PREFIX_SID_VALUE) {
845 stream_put3(s, sid->value);
846 } else {
847 stream_putl(s, sid->value);
848 }
849
850 return 0;
851}
852
853static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s,
854 struct sbuf *log, void *dest, int indent)
855{
856 struct isis_subtlvs *subtlvs = dest;
3e300703
DL
857 struct isis_prefix_sid sid = {
858 };
bd507085
CF
859
860 sbuf_push(log, indent, "Unpacking SR Prefix-SID...\n");
861
862 if (len < 5) {
863 sbuf_push(log, indent,
6cde4b45 864 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
bd507085
CF
865 len);
866 return 1;
867 }
868
869 sid.flags = stream_getc(s);
8b1e3453
RW
870 if (!!(sid.flags & ISIS_PREFIX_SID_VALUE)
871 != !!(sid.flags & ISIS_PREFIX_SID_LOCAL)) {
1b3f47d0 872 sbuf_push(log, indent, "Flags implausible: Local Flag needs to match Value Flag\n");
8b1e3453 873 return 1;
bd507085
CF
874 }
875
876 sid.algorithm = stream_getc(s);
877
1b3f47d0
OD
878 uint8_t expected_size = (sid.flags & ISIS_PREFIX_SID_VALUE)
879 ? ISIS_SUBTLV_PREFIX_SID_SIZE
880 : ISIS_SUBTLV_PREFIX_SID_SIZE + 1;
bd507085
CF
881 if (len != expected_size) {
882 sbuf_push(log, indent,
6cde4b45 883 "TLV size differs from expected size. (expected %u but got %hhu)\n",
bd507085
CF
884 expected_size, len);
885 return 1;
886 }
887
888 if (sid.flags & ISIS_PREFIX_SID_VALUE) {
889 sid.value = stream_get3(s);
26f6acaf
RW
890 if (!IS_MPLS_UNRESERVED_LABEL(sid.value)) {
891 sbuf_push(log, indent, "Invalid absolute SID %u\n",
892 sid.value);
893 return 1;
894 }
bd507085
CF
895 } else {
896 sid.value = stream_getl(s);
897 }
898
899 format_item_prefix_sid(mtid, (struct isis_item *)&sid, log, indent + 2);
900 append_item(&subtlvs->prefix_sids, copy_item_prefix_sid((struct isis_item *)&sid));
901 return 0;
902}
903
7ef5fefc
CF
904/* Functions for Sub-TVL ??? IPv6 Source Prefix */
905
906static struct prefix_ipv6 *copy_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p)
907{
908 if (!p)
909 return NULL;
910
911 struct prefix_ipv6 *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
912 rv->family = p->family;
913 rv->prefixlen = p->prefixlen;
914 memcpy(&rv->prefix, &p->prefix, sizeof(rv->prefix));
915 return rv;
916}
917
918static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p,
919 struct sbuf *buf, int indent)
920{
921 if (!p)
922 return;
923
924 char prefixbuf[PREFIX2STR_BUFFER];
925 sbuf_push(buf, indent, "IPv6 Source Prefix: %s\n",
926 prefix2str(p, prefixbuf, sizeof(prefixbuf)));
927}
928
929static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p,
930 struct stream *s)
931{
932 if (!p)
933 return 0;
934
935 if (STREAM_WRITEABLE(s) < 3 + (unsigned)PSIZE(p->prefixlen))
936 return 1;
937
938 stream_putc(s, ISIS_SUBTLV_IPV6_SOURCE_PREFIX);
939 stream_putc(s, 1 + PSIZE(p->prefixlen));
940 stream_putc(s, p->prefixlen);
941 stream_put(s, &p->prefix, PSIZE(p->prefixlen));
942 return 0;
943}
944
945static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context,
946 uint8_t tlv_type, uint8_t tlv_len,
947 struct stream *s, struct sbuf *log,
948 void *dest, int indent)
949{
950 struct isis_subtlvs *subtlvs = dest;
951 struct prefix_ipv6 p = {
952 .family = AF_INET6,
953 };
954
955 sbuf_push(log, indent, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
956
957 if (tlv_len < 1) {
98c5bc15 958 sbuf_push(log, indent,
6cde4b45 959 "Not enough data left. (expected 1 or more bytes, got %hhu)\n",
98c5bc15 960 tlv_len);
7ef5fefc
CF
961 return 1;
962 }
963
964 p.prefixlen = stream_getc(s);
965 if (p.prefixlen > 128) {
1b3f47d0 966 sbuf_push(log, indent, "Prefixlen %u is implausible for IPv6\n",
7ef5fefc
CF
967 p.prefixlen);
968 return 1;
969 }
970
971 if (tlv_len != 1 + PSIZE(p.prefixlen)) {
972 sbuf_push(
973 log, indent,
6cde4b45 974 "TLV size differs from expected size for the prefixlen. (expected %u but got %hhu)\n",
7ef5fefc
CF
975 1 + PSIZE(p.prefixlen), tlv_len);
976 return 1;
977 }
978
979 stream_get(&p.prefix, s, PSIZE(p.prefixlen));
980
981 if (subtlvs->source_prefix) {
982 sbuf_push(
983 log, indent,
984 "WARNING: source prefix Sub-TLV present multiple times.\n");
985 /* Ignore all but first occurrence of the source prefix Sub-TLV
986 */
987 return 0;
988 }
989
990 subtlvs->source_prefix = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(p));
991 memcpy(subtlvs->source_prefix, &p, sizeof(p));
992 return 0;
993}
1b3f47d0 994
bd507085
CF
995static struct isis_item *copy_item(enum isis_tlv_context context,
996 enum isis_tlv_type type,
997 struct isis_item *item);
998static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type,
999 struct isis_item_list *src, struct isis_item_list *dest);
1000static void format_items_(uint16_t mtid, enum isis_tlv_context context,
1001 enum isis_tlv_type type, struct isis_item_list *items,
1002 struct sbuf *buf, int indent);
1003#define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1004static void free_items(enum isis_tlv_context context, enum isis_tlv_type type,
1005 struct isis_item_list *items);
1006static int pack_items_(uint16_t mtid, enum isis_tlv_context context,
1007 enum isis_tlv_type type, struct isis_item_list *items,
1008 struct stream *s, struct isis_tlvs **fragment_tlvs,
2b64873d 1009 const struct pack_order_entry *pe,
bd507085
CF
1010 struct isis_tlvs *(*new_fragment)(struct list *l),
1011 struct list *new_fragment_arg);
1012#define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
7ef5fefc
CF
1013
1014/* Functions related to subtlvs */
1015
bd507085 1016static struct isis_subtlvs *isis_alloc_subtlvs(enum isis_tlv_context context)
7ef5fefc
CF
1017{
1018 struct isis_subtlvs *result;
1019
1020 result = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*result));
bd507085
CF
1021 result->context = context;
1022
1023 init_item_list(&result->prefix_sids);
7ef5fefc
CF
1024
1025 return result;
1026}
1027
1028static struct isis_subtlvs *copy_subtlvs(struct isis_subtlvs *subtlvs)
1029{
1030 if (!subtlvs)
1031 return NULL;
1032
1033 struct isis_subtlvs *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
1034
bd507085
CF
1035 rv->context = subtlvs->context;
1036
1037 copy_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
1038 &subtlvs->prefix_sids, &rv->prefix_sids);
1039
7ef5fefc
CF
1040 rv->source_prefix =
1041 copy_subtlv_ipv6_source_prefix(subtlvs->source_prefix);
1042 return rv;
1043}
1044
1045static void format_subtlvs(struct isis_subtlvs *subtlvs, struct sbuf *buf,
1046 int indent)
1047{
bd507085
CF
1048 format_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
1049 &subtlvs->prefix_sids, buf, indent);
1050
7ef5fefc
CF
1051 format_subtlv_ipv6_source_prefix(subtlvs->source_prefix, buf, indent);
1052}
1053
1054static void isis_free_subtlvs(struct isis_subtlvs *subtlvs)
1055{
1056 if (!subtlvs)
1057 return;
1058
bd507085
CF
1059 free_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
1060 &subtlvs->prefix_sids);
1061
7ef5fefc
CF
1062 XFREE(MTYPE_ISIS_SUBTLV, subtlvs->source_prefix);
1063
1064 XFREE(MTYPE_ISIS_SUBTLV, subtlvs);
1065}
1066
1067static int pack_subtlvs(struct isis_subtlvs *subtlvs, struct stream *s)
1068{
1069 int rv;
1070 size_t subtlv_len_pos = stream_get_endp(s);
1071
1072 if (STREAM_WRITEABLE(s) < 1)
1073 return 1;
1074
1075 stream_putc(s, 0); /* Put 0 as subtlvs length, filled in later */
1076
bd507085
CF
1077 rv = pack_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
1078 &subtlvs->prefix_sids, s, NULL, NULL, NULL, NULL);
1079 if (rv)
1080 return rv;
1081
7ef5fefc
CF
1082 rv = pack_subtlv_ipv6_source_prefix(subtlvs->source_prefix, s);
1083 if (rv)
1084 return rv;
1085
1086 size_t subtlv_len = stream_get_endp(s) - subtlv_len_pos - 1;
1087 if (subtlv_len > 255)
1088 return 1;
1089
1090 stream_putc_at(s, subtlv_len_pos, subtlv_len);
1091 return 0;
1092}
1093
1094static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len,
1095 struct stream *stream, struct sbuf *log, void *dest,
bf555bf0 1096 int indent, bool *unpacked_known_tlvs);
7ef5fefc
CF
1097
1098/* Functions related to TLVs 1 Area Addresses */
1099
1100static struct isis_item *copy_item_area_address(struct isis_item *i)
1101{
1102 struct isis_area_address *addr = (struct isis_area_address *)i;
841791b6 1103 struct isis_area_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1104
1105 rv->len = addr->len;
1106 memcpy(rv->addr, addr->addr, addr->len);
1107 return (struct isis_item *)rv;
1108}
1109
1110static void format_item_area_address(uint16_t mtid, struct isis_item *i,
1111 struct sbuf *buf, int indent)
1112{
1113 struct isis_area_address *addr = (struct isis_area_address *)i;
1114
1115 sbuf_push(buf, indent, "Area Address: %s\n",
1116 isonet_print(addr->addr, addr->len));
1117}
1118
1119static void free_item_area_address(struct isis_item *i)
1120{
841791b6 1121 XFREE(MTYPE_ISIS_TLV, i);
7ef5fefc
CF
1122}
1123
1124static int pack_item_area_address(struct isis_item *i, struct stream *s)
1125{
1126 struct isis_area_address *addr = (struct isis_area_address *)i;
1127
1128 if (STREAM_WRITEABLE(s) < (unsigned)1 + addr->len)
1129 return 1;
1130 stream_putc(s, addr->len);
1131 stream_put(s, addr->addr, addr->len);
1132 return 0;
1133}
1134
1135static int unpack_item_area_address(uint16_t mtid, uint8_t len,
1136 struct stream *s, struct sbuf *log,
1137 void *dest, int indent)
1138{
1139 struct isis_tlvs *tlvs = dest;
1140 struct isis_area_address *rv = NULL;
1141
1142 sbuf_push(log, indent, "Unpack area address...\n");
1143 if (len < 1) {
1144 sbuf_push(
1145 log, indent,
6cde4b45 1146 "Not enough data left. (Expected 1 byte of address length, got %hhu)\n",
7ef5fefc
CF
1147 len);
1148 goto out;
1149 }
1150
841791b6 1151 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1152 rv->len = stream_getc(s);
1153
1154 if (len < 1 + rv->len) {
47b13e9b 1155 sbuf_push(log, indent, "Not enough data left. (Expected %hhu bytes of address, got %u)\n",
7ef5fefc
CF
1156 rv->len, len - 1);
1157 goto out;
1158 }
1159
1160 if (rv->len < 1 || rv->len > 20) {
1161 sbuf_push(log, indent,
6cde4b45 1162 "Implausible area address length %hhu\n",
7ef5fefc
CF
1163 rv->len);
1164 goto out;
1165 }
1166
1167 stream_get(rv->addr, s, rv->len);
1168
1169 format_item_area_address(ISIS_MT_IPV4_UNICAST, (struct isis_item *)rv,
1170 log, indent + 2);
1171 append_item(&tlvs->area_addresses, (struct isis_item *)rv);
1172 return 0;
1173out:
841791b6 1174 XFREE(MTYPE_ISIS_TLV, rv);
7ef5fefc
CF
1175 return 1;
1176}
1177
1178/* Functions related to TLV 2 (Old-Style) IS Reach */
1179static struct isis_item *copy_item_oldstyle_reach(struct isis_item *i)
1180{
1181 struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i;
841791b6 1182 struct isis_oldstyle_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1183
1184 memcpy(rv->id, r->id, 7);
1185 rv->metric = r->metric;
1186 return (struct isis_item *)rv;
1187}
1188
1189static void format_item_oldstyle_reach(uint16_t mtid, struct isis_item *i,
1190 struct sbuf *buf, int indent)
1191{
1192 struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i;
1193
6cde4b45 1194 sbuf_push(buf, indent, "IS Reachability: %s (Metric: %hhu)\n",
7ef5fefc
CF
1195 isis_format_id(r->id, 7), r->metric);
1196}
1197
1198static void free_item_oldstyle_reach(struct isis_item *i)
1199{
841791b6 1200 XFREE(MTYPE_ISIS_TLV, i);
7ef5fefc
CF
1201}
1202
1203static int pack_item_oldstyle_reach(struct isis_item *i, struct stream *s)
1204{
1205 struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i;
1206
1207 if (STREAM_WRITEABLE(s) < 11)
1208 return 1;
1209
1210 stream_putc(s, r->metric);
1211 stream_putc(s, 0x80); /* delay metric - unsupported */
1212 stream_putc(s, 0x80); /* expense metric - unsupported */
1213 stream_putc(s, 0x80); /* error metric - unsupported */
1214 stream_put(s, r->id, 7);
1215
1216 return 0;
1217}
1218
1219static int unpack_item_oldstyle_reach(uint16_t mtid, uint8_t len,
1220 struct stream *s, struct sbuf *log,
1221 void *dest, int indent)
1222{
1223 struct isis_tlvs *tlvs = dest;
1224
1225 sbuf_push(log, indent, "Unpack oldstyle reach...\n");
1226 if (len < 11) {
1227 sbuf_push(
1228 log, indent,
6cde4b45 1229 "Not enough data left.(Expected 11 bytes of reach information, got %hhu)\n",
7ef5fefc
CF
1230 len);
1231 return 1;
1232 }
1233
841791b6 1234 struct isis_oldstyle_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1235 rv->metric = stream_getc(s);
1236 if ((rv->metric & 0x3f) != rv->metric) {
1237 sbuf_push(log, indent, "Metric has unplausible format\n");
1238 rv->metric &= 0x3f;
1239 }
1240 stream_forward_getp(s, 3); /* Skip other metrics */
1241 stream_get(rv->id, s, 7);
1242
1243 format_item_oldstyle_reach(mtid, (struct isis_item *)rv, log,
1244 indent + 2);
1245 append_item(&tlvs->oldstyle_reach, (struct isis_item *)rv);
1246 return 0;
1247}
1248
1249/* Functions related to TLV 6 LAN Neighbors */
1250static struct isis_item *copy_item_lan_neighbor(struct isis_item *i)
1251{
1252 struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i;
841791b6 1253 struct isis_lan_neighbor *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1254
1255 memcpy(rv->mac, n->mac, 6);
1256 return (struct isis_item *)rv;
1257}
1258
1259static void format_item_lan_neighbor(uint16_t mtid, struct isis_item *i,
1260 struct sbuf *buf, int indent)
1261{
1262 struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i;
1263
1264 sbuf_push(buf, indent, "LAN Neighbor: %s\n", isis_format_id(n->mac, 6));
1265}
1266
1267static void free_item_lan_neighbor(struct isis_item *i)
1268{
841791b6 1269 XFREE(MTYPE_ISIS_TLV, i);
7ef5fefc
CF
1270}
1271
1272static int pack_item_lan_neighbor(struct isis_item *i, struct stream *s)
1273{
1274 struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i;
1275
1276 if (STREAM_WRITEABLE(s) < 6)
1277 return 1;
1278
1279 stream_put(s, n->mac, 6);
1280
1281 return 0;
1282}
1283
1284static int unpack_item_lan_neighbor(uint16_t mtid, uint8_t len,
1285 struct stream *s, struct sbuf *log,
1286 void *dest, int indent)
1287{
1288 struct isis_tlvs *tlvs = dest;
1289
1290 sbuf_push(log, indent, "Unpack LAN neighbor...\n");
1291 if (len < 6) {
1292 sbuf_push(
1293 log, indent,
6cde4b45 1294 "Not enough data left.(Expected 6 bytes of mac, got %hhu)\n",
7ef5fefc
CF
1295 len);
1296 return 1;
1297 }
1298
841791b6 1299 struct isis_lan_neighbor *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1300 stream_get(rv->mac, s, 6);
1301
1302 format_item_lan_neighbor(mtid, (struct isis_item *)rv, log, indent + 2);
1303 append_item(&tlvs->lan_neighbor, (struct isis_item *)rv);
1304 return 0;
1305}
1306
1307/* Functions related to TLV 9 LSP Entry */
1308static struct isis_item *copy_item_lsp_entry(struct isis_item *i)
1309{
1310 struct isis_lsp_entry *e = (struct isis_lsp_entry *)i;
841791b6 1311 struct isis_lsp_entry *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1312
1313 rv->rem_lifetime = e->rem_lifetime;
1314 memcpy(rv->id, e->id, sizeof(rv->id));
1315 rv->seqno = e->seqno;
1316 rv->checksum = e->checksum;
1317
1318 return (struct isis_item *)rv;
1319}
1320
1321static void format_item_lsp_entry(uint16_t mtid, struct isis_item *i,
1322 struct sbuf *buf, int indent)
1323{
1324 struct isis_lsp_entry *e = (struct isis_lsp_entry *)i;
1325
996c9314 1326 sbuf_push(buf, indent,
6cde4b45 1327 "LSP Entry: %s, seq 0x%08x, cksum 0x%04hx, lifetime %hus\n",
7ef5fefc
CF
1328 isis_format_id(e->id, 8), e->seqno, e->checksum,
1329 e->rem_lifetime);
1330}
1331
1332static void free_item_lsp_entry(struct isis_item *i)
1333{
841791b6 1334 XFREE(MTYPE_ISIS_TLV, i);
7ef5fefc
CF
1335}
1336
1337static int pack_item_lsp_entry(struct isis_item *i, struct stream *s)
1338{
1339 struct isis_lsp_entry *e = (struct isis_lsp_entry *)i;
1340
1341 if (STREAM_WRITEABLE(s) < 16)
1342 return 1;
1343
1344 stream_putw(s, e->rem_lifetime);
1345 stream_put(s, e->id, 8);
1346 stream_putl(s, e->seqno);
1347 stream_putw(s, e->checksum);
1348
1349 return 0;
1350}
1351
1352static int unpack_item_lsp_entry(uint16_t mtid, uint8_t len, struct stream *s,
1353 struct sbuf *log, void *dest, int indent)
1354{
1355 struct isis_tlvs *tlvs = dest;
1356
1357 sbuf_push(log, indent, "Unpack LSP entry...\n");
1358 if (len < 16) {
1359 sbuf_push(
1360 log, indent,
6cde4b45 1361 "Not enough data left. (Expected 16 bytes of LSP info, got %hhu",
7ef5fefc
CF
1362 len);
1363 return 1;
1364 }
1365
841791b6 1366 struct isis_lsp_entry *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1367 rv->rem_lifetime = stream_getw(s);
1368 stream_get(rv->id, s, 8);
1369 rv->seqno = stream_getl(s);
1370 rv->checksum = stream_getw(s);
1371
1372 format_item_lsp_entry(mtid, (struct isis_item *)rv, log, indent + 2);
1373 append_item(&tlvs->lsp_entries, (struct isis_item *)rv);
1374 return 0;
1375}
1376
1377/* Functions related to TLVs 22/222 Extended Reach/MT Reach */
1378
1379static struct isis_item *copy_item_extended_reach(struct isis_item *i)
1380{
1381 struct isis_extended_reach *r = (struct isis_extended_reach *)i;
841791b6 1382 struct isis_extended_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1383
1384 memcpy(rv->id, r->id, 7);
1385 rv->metric = r->metric;
1386
1b3f47d0
OD
1387 if (r->subtlvs)
1388 rv->subtlvs = copy_item_ext_subtlvs(r->subtlvs, -1);
7ef5fefc
CF
1389
1390 return (struct isis_item *)rv;
1391}
1392
1393static void format_item_extended_reach(uint16_t mtid, struct isis_item *i,
1394 struct sbuf *buf, int indent)
1395{
1396 struct isis_extended_reach *r = (struct isis_extended_reach *)i;
1397
1398 sbuf_push(buf, indent, "%s Reachability: %s (Metric: %u)",
1399 (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT",
1400 isis_format_id(r->id, 7), r->metric);
1401 if (mtid != ISIS_MT_IPV4_UNICAST)
1402 sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
1403 sbuf_push(buf, 0, "\n");
1404
1b3f47d0
OD
1405 if (r->subtlvs)
1406 format_item_ext_subtlvs(r->subtlvs, buf, indent + 2, mtid);
7ef5fefc
CF
1407}
1408
1409static void free_item_extended_reach(struct isis_item *i)
1410{
1411 struct isis_extended_reach *item = (struct isis_extended_reach *)i;
1b3f47d0
OD
1412 if (item->subtlvs != NULL)
1413 free_item_ext_subtlvs(item->subtlvs);
841791b6 1414 XFREE(MTYPE_ISIS_TLV, item);
7ef5fefc
CF
1415}
1416
1417static int pack_item_extended_reach(struct isis_item *i, struct stream *s)
1418{
1419 struct isis_extended_reach *r = (struct isis_extended_reach *)i;
1b3f47d0
OD
1420 size_t len;
1421 size_t len_pos;
7ef5fefc 1422
1b3f47d0 1423 if (STREAM_WRITEABLE(s) < 11 + ISIS_SUBTLV_MAX_SIZE)
7ef5fefc 1424 return 1;
1b3f47d0 1425
7ef5fefc
CF
1426 stream_put(s, r->id, sizeof(r->id));
1427 stream_put3(s, r->metric);
1b3f47d0
OD
1428 len_pos = stream_get_endp(s);
1429 /* Real length will be adjust after adding subTLVs */
1430 stream_putc(s, 11);
1431 if (r->subtlvs)
1432 pack_item_ext_subtlvs(r->subtlvs, s);
1433 /* Adjust length */
1434 len = stream_get_endp(s) - len_pos - 1;
1435 stream_putc_at(s, len_pos, len);
7ef5fefc
CF
1436 return 0;
1437}
1438
1439static int unpack_item_extended_reach(uint16_t mtid, uint8_t len,
1440 struct stream *s, struct sbuf *log,
1441 void *dest, int indent)
1442{
1443 struct isis_tlvs *tlvs = dest;
1444 struct isis_extended_reach *rv = NULL;
1445 uint8_t subtlv_len;
1446 struct isis_item_list *items;
1447
1448 if (mtid == ISIS_MT_IPV4_UNICAST) {
1449 items = &tlvs->extended_reach;
1450 } else {
1451 items = isis_get_mt_items(&tlvs->mt_reach, mtid);
1452 }
1453
1454 sbuf_push(log, indent, "Unpacking %s reachability...\n",
1455 (mtid == ISIS_MT_IPV4_UNICAST) ? "extended" : "mt");
1456
1457 if (len < 11) {
98c5bc15 1458 sbuf_push(log, indent,
6cde4b45 1459 "Not enough data left. (expected 11 or more bytes, got %hhu)\n",
98c5bc15 1460 len);
7ef5fefc
CF
1461 goto out;
1462 }
1463
841791b6 1464 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1465 stream_get(rv->id, s, 7);
1466 rv->metric = stream_get3(s);
1467 subtlv_len = stream_getc(s);
1468
7ef5fefc
CF
1469 if ((size_t)len < ((size_t)11) + subtlv_len) {
1470 sbuf_push(log, indent,
47b13e9b 1471 "Not enough data left for subtlv size %hhu, there are only %u bytes left.\n",
7ef5fefc
CF
1472 subtlv_len, len - 11);
1473 goto out;
1474 }
1475
6cde4b45 1476 sbuf_push(log, indent, "Storing %hhu bytes of subtlvs\n",
7ef5fefc
CF
1477 subtlv_len);
1478
1479 if (subtlv_len) {
1b3f47d0
OD
1480 if (unpack_item_ext_subtlvs(mtid, subtlv_len, s, log, rv,
1481 indent + 4)) {
7ef5fefc
CF
1482 goto out;
1483 }
7ef5fefc
CF
1484 }
1485
1b3f47d0
OD
1486 format_item_extended_reach(mtid, (struct isis_item *)rv, log,
1487 indent + 2);
7ef5fefc
CF
1488 append_item(items, (struct isis_item *)rv);
1489 return 0;
1490out:
1491 if (rv)
1492 free_item_extended_reach((struct isis_item *)rv);
1493
1494 return 1;
1495}
1496
1497/* Functions related to TLV 128 (Old-Style) IP Reach */
1498static struct isis_item *copy_item_oldstyle_ip_reach(struct isis_item *i)
1499{
1500 struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i;
1501 struct isis_oldstyle_ip_reach *rv =
841791b6 1502 XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1503
1504 rv->metric = r->metric;
1505 rv->prefix = r->prefix;
1506 return (struct isis_item *)rv;
1507}
1508
1509static void format_item_oldstyle_ip_reach(uint16_t mtid, struct isis_item *i,
1510 struct sbuf *buf, int indent)
1511{
1512 struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i;
1513 char prefixbuf[PREFIX2STR_BUFFER];
1514
6cde4b45 1515 sbuf_push(buf, indent, "IP Reachability: %s (Metric: %hhu)\n",
996c9314
LB
1516 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)),
1517 r->metric);
7ef5fefc
CF
1518}
1519
1520static void free_item_oldstyle_ip_reach(struct isis_item *i)
1521{
841791b6 1522 XFREE(MTYPE_ISIS_TLV, i);
7ef5fefc
CF
1523}
1524
1525static int pack_item_oldstyle_ip_reach(struct isis_item *i, struct stream *s)
1526{
1527 struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i;
1528
1529 if (STREAM_WRITEABLE(s) < 12)
1530 return 1;
1531
1532 stream_putc(s, r->metric);
1533 stream_putc(s, 0x80); /* delay metric - unsupported */
1534 stream_putc(s, 0x80); /* expense metric - unsupported */
1535 stream_putc(s, 0x80); /* error metric - unsupported */
1536 stream_put(s, &r->prefix.prefix, 4);
1537
1538 struct in_addr mask;
1539 masklen2ip(r->prefix.prefixlen, &mask);
1540 stream_put(s, &mask, sizeof(mask));
1541
1542 return 0;
1543}
1544
1545static int unpack_item_oldstyle_ip_reach(uint16_t mtid, uint8_t len,
1546 struct stream *s, struct sbuf *log,
1547 void *dest, int indent)
1548{
1549 sbuf_push(log, indent, "Unpack oldstyle ip reach...\n");
1550 if (len < 12) {
1551 sbuf_push(
1552 log, indent,
6cde4b45 1553 "Not enough data left.(Expected 12 bytes of reach information, got %hhu)\n",
7ef5fefc
CF
1554 len);
1555 return 1;
1556 }
1557
1558 struct isis_oldstyle_ip_reach *rv =
841791b6 1559 XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1560 rv->metric = stream_getc(s);
1561 if ((rv->metric & 0x7f) != rv->metric) {
1562 sbuf_push(log, indent, "Metric has unplausible format\n");
1563 rv->metric &= 0x7f;
1564 }
1565 stream_forward_getp(s, 3); /* Skip other metrics */
1566 rv->prefix.family = AF_INET;
1567 stream_get(&rv->prefix.prefix, s, 4);
1568
1569 struct in_addr mask;
1570 stream_get(&mask, s, 4);
1571 rv->prefix.prefixlen = ip_masklen(mask);
1572
1573 format_item_oldstyle_ip_reach(mtid, (struct isis_item *)rv, log,
1574 indent + 2);
1575 append_item(dest, (struct isis_item *)rv);
1576 return 0;
1577}
1578
1579
1580/* Functions related to TLV 129 protocols supported */
1581
1582static void copy_tlv_protocols_supported(struct isis_protocols_supported *src,
1583 struct isis_protocols_supported *dest)
1584{
1585 if (!src->protocols || !src->count)
1586 return;
1587 dest->count = src->count;
841791b6 1588 dest->protocols = XCALLOC(MTYPE_ISIS_TLV, src->count);
7ef5fefc
CF
1589 memcpy(dest->protocols, src->protocols, src->count);
1590}
1591
1592static void format_tlv_protocols_supported(struct isis_protocols_supported *p,
1593 struct sbuf *buf, int indent)
1594{
1595 if (!p || !p->count || !p->protocols)
1596 return;
1597
1598 sbuf_push(buf, indent, "Protocols Supported: ");
1599 for (uint8_t i = 0; i < p->count; i++) {
1600 sbuf_push(buf, 0, "%s%s", nlpid2str(p->protocols[i]),
1601 (i + 1 < p->count) ? ", " : "");
1602 }
1603 sbuf_push(buf, 0, "\n");
1604}
1605
1606static void free_tlv_protocols_supported(struct isis_protocols_supported *p)
1607{
841791b6 1608 XFREE(MTYPE_ISIS_TLV, p->protocols);
7ef5fefc
CF
1609}
1610
1611static int pack_tlv_protocols_supported(struct isis_protocols_supported *p,
1612 struct stream *s)
1613{
1614 if (!p || !p->count || !p->protocols)
1615 return 0;
1616
1617 if (STREAM_WRITEABLE(s) < (unsigned)(p->count + 2))
1618 return 1;
1619
1620 stream_putc(s, ISIS_TLV_PROTOCOLS_SUPPORTED);
1621 stream_putc(s, p->count);
1622 stream_put(s, p->protocols, p->count);
1623 return 0;
1624}
1625
1626static int unpack_tlv_protocols_supported(enum isis_tlv_context context,
1627 uint8_t tlv_type, uint8_t tlv_len,
1628 struct stream *s, struct sbuf *log,
1629 void *dest, int indent)
1630{
1631 struct isis_tlvs *tlvs = dest;
1632
1633 sbuf_push(log, indent, "Unpacking Protocols Supported TLV...\n");
1634 if (!tlv_len) {
1635 sbuf_push(log, indent, "WARNING: No protocols included\n");
1636 return 0;
1637 }
1638 if (tlvs->protocols_supported.protocols) {
1639 sbuf_push(
1640 log, indent,
1641 "WARNING: protocols supported TLV present multiple times.\n");
1642 stream_forward_getp(s, tlv_len);
1643 return 0;
1644 }
1645
1646 tlvs->protocols_supported.count = tlv_len;
841791b6 1647 tlvs->protocols_supported.protocols = XCALLOC(MTYPE_ISIS_TLV, tlv_len);
7ef5fefc
CF
1648 stream_get(tlvs->protocols_supported.protocols, s, tlv_len);
1649
1650 format_tlv_protocols_supported(&tlvs->protocols_supported, log,
1651 indent + 2);
1652 return 0;
1653}
1654
1655/* Functions related to TLV 132 IPv4 Interface addresses */
1656static struct isis_item *copy_item_ipv4_address(struct isis_item *i)
1657{
1658 struct isis_ipv4_address *a = (struct isis_ipv4_address *)i;
841791b6 1659 struct isis_ipv4_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1660
1661 rv->addr = a->addr;
1662 return (struct isis_item *)rv;
1663}
1664
1665static void format_item_ipv4_address(uint16_t mtid, struct isis_item *i,
1666 struct sbuf *buf, int indent)
1667{
1668 struct isis_ipv4_address *a = (struct isis_ipv4_address *)i;
1669 char addrbuf[INET_ADDRSTRLEN];
1670
1671 inet_ntop(AF_INET, &a->addr, addrbuf, sizeof(addrbuf));
1672 sbuf_push(buf, indent, "IPv4 Interface Address: %s\n", addrbuf);
1673}
1674
1675static void free_item_ipv4_address(struct isis_item *i)
1676{
841791b6 1677 XFREE(MTYPE_ISIS_TLV, i);
7ef5fefc
CF
1678}
1679
1680static int pack_item_ipv4_address(struct isis_item *i, struct stream *s)
1681{
1682 struct isis_ipv4_address *a = (struct isis_ipv4_address *)i;
1683
1684 if (STREAM_WRITEABLE(s) < 4)
1685 return 1;
1686
1687 stream_put(s, &a->addr, 4);
1688
1689 return 0;
1690}
1691
1692static int unpack_item_ipv4_address(uint16_t mtid, uint8_t len,
1693 struct stream *s, struct sbuf *log,
1694 void *dest, int indent)
1695{
1696 struct isis_tlvs *tlvs = dest;
1697
1698 sbuf_push(log, indent, "Unpack IPv4 Interface address...\n");
1699 if (len < 4) {
1700 sbuf_push(
1701 log, indent,
6cde4b45 1702 "Not enough data left.(Expected 4 bytes of IPv4 address, got %hhu)\n",
7ef5fefc
CF
1703 len);
1704 return 1;
1705 }
1706
841791b6 1707 struct isis_ipv4_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1708 stream_get(&rv->addr, s, 4);
1709
1710 format_item_ipv4_address(mtid, (struct isis_item *)rv, log, indent + 2);
1711 append_item(&tlvs->ipv4_address, (struct isis_item *)rv);
1712 return 0;
1713}
1714
1715
1716/* Functions related to TLV 232 IPv6 Interface addresses */
1717static struct isis_item *copy_item_ipv6_address(struct isis_item *i)
1718{
1719 struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
841791b6 1720 struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1721
1722 rv->addr = a->addr;
1723 return (struct isis_item *)rv;
1724}
1725
1726static void format_item_ipv6_address(uint16_t mtid, struct isis_item *i,
1727 struct sbuf *buf, int indent)
1728{
1729 struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
1730 char addrbuf[INET6_ADDRSTRLEN];
1731
1732 inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf));
1733 sbuf_push(buf, indent, "IPv6 Interface Address: %s\n", addrbuf);
1734}
1735
1736static void free_item_ipv6_address(struct isis_item *i)
1737{
841791b6 1738 XFREE(MTYPE_ISIS_TLV, i);
7ef5fefc
CF
1739}
1740
1741static int pack_item_ipv6_address(struct isis_item *i, struct stream *s)
1742{
1743 struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
1744
1745 if (STREAM_WRITEABLE(s) < 16)
1746 return 1;
1747
1748 stream_put(s, &a->addr, 16);
1749
1750 return 0;
1751}
1752
1753static int unpack_item_ipv6_address(uint16_t mtid, uint8_t len,
1754 struct stream *s, struct sbuf *log,
1755 void *dest, int indent)
1756{
1757 struct isis_tlvs *tlvs = dest;
1758
1759 sbuf_push(log, indent, "Unpack IPv6 Interface address...\n");
1760 if (len < 16) {
1761 sbuf_push(
1762 log, indent,
6cde4b45 1763 "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
7ef5fefc
CF
1764 len);
1765 return 1;
1766 }
1767
841791b6 1768 struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1769 stream_get(&rv->addr, s, 16);
1770
1771 format_item_ipv6_address(mtid, (struct isis_item *)rv, log, indent + 2);
1772 append_item(&tlvs->ipv6_address, (struct isis_item *)rv);
1773 return 0;
1774}
1775
1776
1777/* Functions related to TLV 229 MT Router information */
1778static struct isis_item *copy_item_mt_router_info(struct isis_item *i)
1779{
1780 struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
841791b6 1781 struct isis_mt_router_info *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1782
1783 rv->overload = info->overload;
1784 rv->attached = info->attached;
1785 rv->mtid = info->mtid;
1786 return (struct isis_item *)rv;
1787}
1788
1789static void format_item_mt_router_info(uint16_t mtid, struct isis_item *i,
1790 struct sbuf *buf, int indent)
1791{
1792 struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
1793
1794 sbuf_push(buf, indent, "MT Router Info: %s%s%s\n",
98c5bc15
CF
1795 isis_mtid2str(info->mtid),
1796 info->overload ? " Overload" : "",
7ef5fefc
CF
1797 info->attached ? " Attached" : "");
1798}
1799
1800static void free_item_mt_router_info(struct isis_item *i)
1801{
841791b6 1802 XFREE(MTYPE_ISIS_TLV, i);
7ef5fefc
CF
1803}
1804
1805static int pack_item_mt_router_info(struct isis_item *i, struct stream *s)
1806{
1807 struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
1808
1809 if (STREAM_WRITEABLE(s) < 2)
1810 return 1;
1811
1812 uint16_t entry = info->mtid;
1813
1814 if (info->overload)
1815 entry |= ISIS_MT_OL_MASK;
1816 if (info->attached)
1817 entry |= ISIS_MT_AT_MASK;
1818
1819 stream_putw(s, entry);
1820
1821 return 0;
1822}
1823
1824static int unpack_item_mt_router_info(uint16_t mtid, uint8_t len,
1825 struct stream *s, struct sbuf *log,
1826 void *dest, int indent)
1827{
1828 struct isis_tlvs *tlvs = dest;
1829
1830 sbuf_push(log, indent, "Unpack MT Router info...\n");
1831 if (len < 2) {
1832 sbuf_push(
1833 log, indent,
6cde4b45 1834 "Not enough data left.(Expected 2 bytes of MT info, got %hhu)\n",
7ef5fefc
CF
1835 len);
1836 return 1;
1837 }
1838
841791b6 1839 struct isis_mt_router_info *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1840
1841 uint16_t entry = stream_getw(s);
1842 rv->overload = entry & ISIS_MT_OL_MASK;
1843 rv->attached = entry & ISIS_MT_AT_MASK;
1844 rv->mtid = entry & ISIS_MT_MASK;
1845
1846 format_item_mt_router_info(mtid, (struct isis_item *)rv, log,
1847 indent + 2);
1848 append_item(&tlvs->mt_router_info, (struct isis_item *)rv);
1849 return 0;
1850}
1851
1852/* Functions related to TLV 134 TE Router ID */
1853
1854static struct in_addr *copy_tlv_te_router_id(const struct in_addr *id)
1855{
1856 if (!id)
1857 return NULL;
1858
841791b6 1859 struct in_addr *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1860 memcpy(rv, id, sizeof(*rv));
1861 return rv;
1862}
1863
1864static void format_tlv_te_router_id(const struct in_addr *id, struct sbuf *buf,
1865 int indent)
1866{
1867 if (!id)
1868 return;
1869
1870 char addrbuf[INET_ADDRSTRLEN];
1871 inet_ntop(AF_INET, id, addrbuf, sizeof(addrbuf));
1872 sbuf_push(buf, indent, "TE Router ID: %s\n", addrbuf);
1873}
1874
1875static void free_tlv_te_router_id(struct in_addr *id)
1876{
841791b6 1877 XFREE(MTYPE_ISIS_TLV, id);
7ef5fefc
CF
1878}
1879
1880static int pack_tlv_te_router_id(const struct in_addr *id, struct stream *s)
1881{
1882 if (!id)
1883 return 0;
1884
1885 if (STREAM_WRITEABLE(s) < (unsigned)(2 + sizeof(*id)))
1886 return 1;
1887
1888 stream_putc(s, ISIS_TLV_TE_ROUTER_ID);
1889 stream_putc(s, 4);
1890 stream_put(s, id, 4);
1891 return 0;
1892}
1893
1894static int unpack_tlv_te_router_id(enum isis_tlv_context context,
1895 uint8_t tlv_type, uint8_t tlv_len,
1896 struct stream *s, struct sbuf *log,
1897 void *dest, int indent)
1898{
1899 struct isis_tlvs *tlvs = dest;
1900
1901 sbuf_push(log, indent, "Unpacking TE Router ID TLV...\n");
1902 if (tlv_len != 4) {
1903 sbuf_push(log, indent, "WARNING: Length invalid\n");
1904 return 1;
1905 }
1906
1907 if (tlvs->te_router_id) {
1908 sbuf_push(log, indent,
1909 "WARNING: TE Router ID present multiple times.\n");
1910 stream_forward_getp(s, tlv_len);
1911 return 0;
1912 }
1913
841791b6 1914 tlvs->te_router_id = XCALLOC(MTYPE_ISIS_TLV, 4);
7ef5fefc
CF
1915 stream_get(tlvs->te_router_id, s, 4);
1916 format_tlv_te_router_id(tlvs->te_router_id, log, indent + 2);
1917 return 0;
1918}
1919
1920
1921/* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
1922
1923static struct isis_item *copy_item_extended_ip_reach(struct isis_item *i)
1924{
1925 struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
1926 struct isis_extended_ip_reach *rv =
841791b6 1927 XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
1928
1929 rv->metric = r->metric;
1930 rv->down = r->down;
1931 rv->prefix = r->prefix;
1b3f47d0 1932 rv->subtlvs = copy_subtlvs(r->subtlvs);
7ef5fefc
CF
1933
1934 return (struct isis_item *)rv;
1935}
1936
1937static void format_item_extended_ip_reach(uint16_t mtid, struct isis_item *i,
1938 struct sbuf *buf, int indent)
1939{
1940 struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
1941 char prefixbuf[PREFIX2STR_BUFFER];
1942
1943 sbuf_push(buf, indent, "%s IP Reachability: %s (Metric: %u)%s",
1944 (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT",
98c5bc15
CF
1945 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), r->metric,
1946 r->down ? " Down" : "");
7ef5fefc
CF
1947 if (mtid != ISIS_MT_IPV4_UNICAST)
1948 sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
1949 sbuf_push(buf, 0, "\n");
9826647e
RW
1950
1951 if (r->subtlvs) {
1952 sbuf_push(buf, indent, " Subtlvs:\n");
1953 format_subtlvs(r->subtlvs, buf, indent + 4);
1954 }
7ef5fefc
CF
1955}
1956
1957static void free_item_extended_ip_reach(struct isis_item *i)
1958{
1959 struct isis_extended_ip_reach *item =
1960 (struct isis_extended_ip_reach *)i;
bd507085 1961 isis_free_subtlvs(item->subtlvs);
841791b6 1962 XFREE(MTYPE_ISIS_TLV, item);
7ef5fefc
CF
1963}
1964
1965static int pack_item_extended_ip_reach(struct isis_item *i, struct stream *s)
1966{
1967 struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
1968 uint8_t control;
1969
1970 if (STREAM_WRITEABLE(s) < 5)
1971 return 1;
1972 stream_putl(s, r->metric);
1973
1974 control = r->down ? ISIS_EXTENDED_IP_REACH_DOWN : 0;
1975 control |= r->prefix.prefixlen;
bd507085
CF
1976 control |= r->subtlvs ? ISIS_EXTENDED_IP_REACH_SUBTLV : 0;
1977
7ef5fefc
CF
1978 stream_putc(s, control);
1979
1980 if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen))
1981 return 1;
1982 stream_put(s, &r->prefix.prefix.s_addr, PSIZE(r->prefix.prefixlen));
bd507085
CF
1983
1984 if (r->subtlvs)
1985 return pack_subtlvs(r->subtlvs, s);
7ef5fefc
CF
1986 return 0;
1987}
1988
1989static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len,
1990 struct stream *s, struct sbuf *log,
1991 void *dest, int indent)
1992{
1993 struct isis_tlvs *tlvs = dest;
1994 struct isis_extended_ip_reach *rv = NULL;
1995 size_t consume;
1996 uint8_t control, subtlv_len;
1997 struct isis_item_list *items;
1998
1999 if (mtid == ISIS_MT_IPV4_UNICAST) {
2000 items = &tlvs->extended_ip_reach;
2001 } else {
2002 items = isis_get_mt_items(&tlvs->mt_ip_reach, mtid);
2003 }
2004
2005 sbuf_push(log, indent, "Unpacking %s IPv4 reachability...\n",
2006 (mtid == ISIS_MT_IPV4_UNICAST) ? "extended" : "mt");
2007
2008 consume = 5;
2009 if (len < consume) {
98c5bc15 2010 sbuf_push(log, indent,
6cde4b45 2011 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
98c5bc15 2012 len);
7ef5fefc
CF
2013 goto out;
2014 }
2015
841791b6 2016 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
2017
2018 rv->metric = stream_getl(s);
2019 control = stream_getc(s);
2020 rv->down = (control & ISIS_EXTENDED_IP_REACH_DOWN);
2021 rv->prefix.family = AF_INET;
2022 rv->prefix.prefixlen = control & 0x3f;
2023 if (rv->prefix.prefixlen > 32) {
1b3f47d0 2024 sbuf_push(log, indent, "Prefixlen %u is implausible for IPv4\n",
7ef5fefc
CF
2025 rv->prefix.prefixlen);
2026 goto out;
2027 }
2028
2029 consume += PSIZE(rv->prefix.prefixlen);
2030 if (len < consume) {
98c5bc15
CF
2031 sbuf_push(log, indent,
2032 "Expected %u bytes of prefix, but only %u bytes available.\n",
2033 PSIZE(rv->prefix.prefixlen), len - 5);
7ef5fefc
CF
2034 goto out;
2035 }
2036 stream_get(&rv->prefix.prefix.s_addr, s, PSIZE(rv->prefix.prefixlen));
2037 in_addr_t orig_prefix = rv->prefix.prefix.s_addr;
2038 apply_mask_ipv4(&rv->prefix);
2039 if (orig_prefix != rv->prefix.prefix.s_addr)
2040 sbuf_push(log, indent + 2,
2041 "WARNING: Prefix had hostbits set.\n");
2042 format_item_extended_ip_reach(mtid, (struct isis_item *)rv, log,
2043 indent + 2);
2044
2045 if (control & ISIS_EXTENDED_IP_REACH_SUBTLV) {
2046 consume += 1;
2047 if (len < consume) {
98c5bc15
CF
2048 sbuf_push(log, indent,
2049 "Expected 1 byte of subtlv len, but no more data present.\n");
7ef5fefc
CF
2050 goto out;
2051 }
2052 subtlv_len = stream_getc(s);
2053
2054 if (!subtlv_len) {
98c5bc15
CF
2055 sbuf_push(log, indent + 2,
2056 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
7ef5fefc
CF
2057 }
2058 consume += subtlv_len;
2059 if (len < consume) {
98c5bc15 2060 sbuf_push(log, indent,
6cde4b45 2061 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
98c5bc15
CF
2062 subtlv_len,
2063 len - 6 - PSIZE(rv->prefix.prefixlen));
7ef5fefc
CF
2064 goto out;
2065 }
bd507085
CF
2066
2067 rv->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH);
bf555bf0
CF
2068 bool unpacked_known_tlvs = false;
2069
bd507085 2070 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH, subtlv_len, s,
bf555bf0 2071 log, rv->subtlvs, indent + 4, &unpacked_known_tlvs)) {
bd507085
CF
2072 goto out;
2073 }
bf555bf0
CF
2074 if (!unpacked_known_tlvs) {
2075 isis_free_subtlvs(rv->subtlvs);
2076 rv->subtlvs = NULL;
2077 }
7ef5fefc
CF
2078 }
2079
2080 append_item(items, (struct isis_item *)rv);
2081 return 0;
2082out:
2083 if (rv)
2084 free_item_extended_ip_reach((struct isis_item *)rv);
2085 return 1;
2086}
2087
2088/* Functions related to TLV 137 Dynamic Hostname */
2089
2090static char *copy_tlv_dynamic_hostname(const char *hostname)
2091{
2092 if (!hostname)
2093 return NULL;
2094
841791b6 2095 return XSTRDUP(MTYPE_ISIS_TLV, hostname);
7ef5fefc
CF
2096}
2097
2098static void format_tlv_dynamic_hostname(const char *hostname, struct sbuf *buf,
2099 int indent)
2100{
2101 if (!hostname)
2102 return;
2103
2104 sbuf_push(buf, indent, "Hostname: %s\n", hostname);
2105}
2106
2107static void free_tlv_dynamic_hostname(char *hostname)
2108{
841791b6 2109 XFREE(MTYPE_ISIS_TLV, hostname);
7ef5fefc
CF
2110}
2111
2112static int pack_tlv_dynamic_hostname(const char *hostname, struct stream *s)
2113{
2114 if (!hostname)
2115 return 0;
2116
2117 uint8_t name_len = strlen(hostname);
2118
2119 if (STREAM_WRITEABLE(s) < (unsigned)(2 + name_len))
2120 return 1;
2121
2122 stream_putc(s, ISIS_TLV_DYNAMIC_HOSTNAME);
2123 stream_putc(s, name_len);
2124 stream_put(s, hostname, name_len);
2125 return 0;
2126}
2127
2128static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context,
2129 uint8_t tlv_type, uint8_t tlv_len,
2130 struct stream *s, struct sbuf *log,
2131 void *dest, int indent)
2132{
2133 struct isis_tlvs *tlvs = dest;
2134
2135 sbuf_push(log, indent, "Unpacking Dynamic Hostname TLV...\n");
2136 if (!tlv_len) {
2137 sbuf_push(log, indent, "WARNING: No hostname included\n");
2138 return 0;
2139 }
2140
2141 if (tlvs->hostname) {
2142 sbuf_push(log, indent,
2143 "WARNING: Hostname present multiple times.\n");
2144 stream_forward_getp(s, tlv_len);
2145 return 0;
2146 }
2147
841791b6 2148 tlvs->hostname = XCALLOC(MTYPE_ISIS_TLV, tlv_len + 1);
7ef5fefc
CF
2149 stream_get(tlvs->hostname, s, tlv_len);
2150 tlvs->hostname[tlv_len] = '\0';
2151
2152 bool sane = true;
2153 for (uint8_t i = 0; i < tlv_len; i++) {
2154 if ((unsigned char)tlvs->hostname[i] > 127
fefa5e0f 2155 || !isprint((unsigned char)tlvs->hostname[i])) {
7ef5fefc
CF
2156 sane = false;
2157 tlvs->hostname[i] = '?';
2158 }
2159 }
2160 if (!sane) {
2161 sbuf_push(
2162 log, indent,
2163 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
2164 }
2165
2166 return 0;
2167}
2168
41a145f1
CF
2169/* Functions related to TLV 150 Spine-Leaf-Extension */
2170
2171static struct isis_spine_leaf *copy_tlv_spine_leaf(
2172 const struct isis_spine_leaf *spine_leaf)
2173{
2174 if (!spine_leaf)
2175 return NULL;
2176
2177 struct isis_spine_leaf *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2178 memcpy(rv, spine_leaf, sizeof(*rv));
2179
2180 return rv;
2181}
2182
2183static void format_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf,
2184 struct sbuf *buf, int indent)
2185{
2186 if (!spine_leaf)
2187 return;
2188
2189 sbuf_push(buf, indent, "Spine-Leaf-Extension:\n");
2190 if (spine_leaf->has_tier) {
2191 if (spine_leaf->tier == ISIS_TIER_UNDEFINED) {
2192 sbuf_push(buf, indent, " Tier: undefined\n");
2193 } else {
6cde4b45 2194 sbuf_push(buf, indent, " Tier: %hhu\n",
41a145f1
CF
2195 spine_leaf->tier);
2196 }
2197 }
2198
2199 sbuf_push(buf, indent, " Flags:%s%s%s\n",
2200 spine_leaf->is_leaf ? " LEAF" : "",
2201 spine_leaf->is_spine ? " SPINE" : "",
2202 spine_leaf->is_backup ? " BACKUP" : "");
2203
2204}
2205
2206static void free_tlv_spine_leaf(struct isis_spine_leaf *spine_leaf)
2207{
2208 XFREE(MTYPE_ISIS_TLV, spine_leaf);
2209}
2210
2211#define ISIS_SPINE_LEAF_FLAG_TIER 0x08
2212#define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
2213#define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
2214#define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
2215
2216static int pack_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf,
2217 struct stream *s)
2218{
2219 if (!spine_leaf)
2220 return 0;
2221
2222 uint8_t tlv_len = 2;
2223
2224 if (STREAM_WRITEABLE(s) < (unsigned)(2 + tlv_len))
2225 return 1;
2226
2227 stream_putc(s, ISIS_TLV_SPINE_LEAF_EXT);
2228 stream_putc(s, tlv_len);
2229
2230 uint16_t spine_leaf_flags = 0;
2231
2232 if (spine_leaf->has_tier) {
2233 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_TIER;
2234 spine_leaf_flags |= spine_leaf->tier << 12;
2235 }
2236
2237 if (spine_leaf->is_leaf)
2238 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_LEAF;
2239
2240 if (spine_leaf->is_spine)
2241 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_SPINE;
2242
2243 if (spine_leaf->is_backup)
2244 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_BACKUP;
2245
2246 stream_putw(s, spine_leaf_flags);
2247
2248 return 0;
2249}
2250
2251static int unpack_tlv_spine_leaf(enum isis_tlv_context context,
2252 uint8_t tlv_type, uint8_t tlv_len,
2253 struct stream *s, struct sbuf *log,
2254 void *dest, int indent)
2255{
2256 struct isis_tlvs *tlvs = dest;
2257
2258 sbuf_push(log, indent, "Unpacking Spine Leaf Extension TLV...\n");
2259 if (tlv_len < 2) {
377e2dd3 2260 sbuf_push(log, indent, "WARNING: Unexpected TLV size\n");
41a145f1
CF
2261 stream_forward_getp(s, tlv_len);
2262 return 0;
2263 }
2264
2265 if (tlvs->spine_leaf) {
2266 sbuf_push(log, indent,
2267 "WARNING: Spine Leaf Extension TLV present multiple times.\n");
2268 stream_forward_getp(s, tlv_len);
2269 return 0;
2270 }
2271
2272 tlvs->spine_leaf = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->spine_leaf));
2273
2274 uint16_t spine_leaf_flags = stream_getw(s);
2275
2276 if (spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_TIER) {
2277 tlvs->spine_leaf->has_tier = true;
2278 tlvs->spine_leaf->tier = spine_leaf_flags >> 12;
2279 }
2280
2281 tlvs->spine_leaf->is_leaf = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_LEAF;
2282 tlvs->spine_leaf->is_spine = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_SPINE;
2283 tlvs->spine_leaf->is_backup = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_BACKUP;
2284
2285 stream_forward_getp(s, tlv_len - 2);
2286 return 0;
2287}
2288
9fe21208
CF
2289/* Functions related to TLV 240 P2P Three-Way Adjacency */
2290
2291const char *isis_threeway_state_name(enum isis_threeway_state state)
2292{
2293 switch (state) {
2294 case ISIS_THREEWAY_DOWN:
2295 return "Down";
2296 case ISIS_THREEWAY_INITIALIZING:
2297 return "Initializing";
2298 case ISIS_THREEWAY_UP:
2299 return "Up";
2300 default:
2301 return "Invalid!";
2302 }
2303}
2304
2305static struct isis_threeway_adj *copy_tlv_threeway_adj(
2306 const struct isis_threeway_adj *threeway_adj)
2307{
2308 if (!threeway_adj)
2309 return NULL;
2310
2311 struct isis_threeway_adj *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2312 memcpy(rv, threeway_adj, sizeof(*rv));
2313
2314 return rv;
2315}
2316
2317static void format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj,
2318 struct sbuf *buf, int indent)
2319{
2320 if (!threeway_adj)
2321 return;
2322
2323 sbuf_push(buf, indent, "P2P Three-Way Adjacency:\n");
2324 sbuf_push(buf, indent, " State: %s (%d)\n",
2325 isis_threeway_state_name(threeway_adj->state),
2326 threeway_adj->state);
6cde4b45 2327 sbuf_push(buf, indent, " Extended Local Circuit ID: %u\n",
9fe21208
CF
2328 threeway_adj->local_circuit_id);
2329 if (!threeway_adj->neighbor_set)
2330 return;
2331
2332 sbuf_push(buf, indent, " Neighbor System ID: %s\n",
2333 isis_format_id(threeway_adj->neighbor_id, 6));
6cde4b45 2334 sbuf_push(buf, indent, " Neighbor Extended Circuit ID: %u\n",
9fe21208
CF
2335 threeway_adj->neighbor_circuit_id);
2336}
2337
2338static void free_tlv_threeway_adj(struct isis_threeway_adj *threeway_adj)
2339{
2340 XFREE(MTYPE_ISIS_TLV, threeway_adj);
2341}
2342
2343static int pack_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj,
2344 struct stream *s)
2345{
2346 if (!threeway_adj)
2347 return 0;
2348
2349 uint8_t tlv_len = (threeway_adj->neighbor_set) ? 15 : 5;
2350
2351 if (STREAM_WRITEABLE(s) < (unsigned)(2 + tlv_len))
2352 return 1;
2353
2354 stream_putc(s, ISIS_TLV_THREE_WAY_ADJ);
2355 stream_putc(s, tlv_len);
2356 stream_putc(s, threeway_adj->state);
2357 stream_putl(s, threeway_adj->local_circuit_id);
2358
2359 if (threeway_adj->neighbor_set) {
2360 stream_put(s, threeway_adj->neighbor_id, 6);
2361 stream_putl(s, threeway_adj->neighbor_circuit_id);
2362 }
2363
2364 return 0;
2365}
2366
2367static int unpack_tlv_threeway_adj(enum isis_tlv_context context,
2368 uint8_t tlv_type, uint8_t tlv_len,
2369 struct stream *s, struct sbuf *log,
2370 void *dest, int indent)
2371{
2372 struct isis_tlvs *tlvs = dest;
2373
2374 sbuf_push(log, indent, "Unpacking P2P Three-Way Adjacency TLV...\n");
2375 if (tlv_len != 5 && tlv_len != 15) {
377e2dd3 2376 sbuf_push(log, indent, "WARNING: Unexpected TLV size\n");
9fe21208
CF
2377 stream_forward_getp(s, tlv_len);
2378 return 0;
2379 }
2380
2381 if (tlvs->threeway_adj) {
2382 sbuf_push(log, indent,
2383 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
2384 stream_forward_getp(s, tlv_len);
2385 return 0;
2386 }
2387
2388 tlvs->threeway_adj = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->threeway_adj));
2389
2390 tlvs->threeway_adj->state = stream_getc(s);
2391 tlvs->threeway_adj->local_circuit_id = stream_getl(s);
2392
2393 if (tlv_len == 15) {
2394 tlvs->threeway_adj->neighbor_set = true;
2395 stream_get(tlvs->threeway_adj->neighbor_id, s, 6);
2396 tlvs->threeway_adj->neighbor_circuit_id = stream_getl(s);
2397 }
2398
2399 return 0;
2400}
2401
7ef5fefc 2402/* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
7ef5fefc
CF
2403static struct isis_item *copy_item_ipv6_reach(struct isis_item *i)
2404{
2405 struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
841791b6 2406 struct isis_ipv6_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
a064a7b8 2407
7ef5fefc
CF
2408 rv->metric = r->metric;
2409 rv->down = r->down;
2410 rv->external = r->external;
2411 rv->prefix = r->prefix;
2412 rv->subtlvs = copy_subtlvs(r->subtlvs);
2413
2414 return (struct isis_item *)rv;
2415}
2416
2417static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i,
2418 struct sbuf *buf, int indent)
2419{
2420 struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
2421 char prefixbuf[PREFIX2STR_BUFFER];
2422
2423 sbuf_push(buf, indent, "%sIPv6 Reachability: %s (Metric: %u)%s%s",
2424 (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "MT ",
2425 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)),
98c5bc15
CF
2426 r->metric,
2427 r->down ? " Down" : "",
7ef5fefc
CF
2428 r->external ? " External" : "");
2429 if (mtid != ISIS_MT_IPV4_UNICAST)
2430 sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
2431 sbuf_push(buf, 0, "\n");
2432
2433 if (r->subtlvs) {
2434 sbuf_push(buf, indent, " Subtlvs:\n");
2435 format_subtlvs(r->subtlvs, buf, indent + 4);
2436 }
2437}
2438
2439static void free_item_ipv6_reach(struct isis_item *i)
2440{
2441 struct isis_ipv6_reach *item = (struct isis_ipv6_reach *)i;
2442
2443 isis_free_subtlvs(item->subtlvs);
841791b6 2444 XFREE(MTYPE_ISIS_TLV, item);
7ef5fefc
CF
2445}
2446
2447static int pack_item_ipv6_reach(struct isis_item *i, struct stream *s)
2448{
2449 struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
2450 uint8_t control;
2451
2452 if (STREAM_WRITEABLE(s) < 6)
2453 return 1;
2454 stream_putl(s, r->metric);
2455
2456 control = r->down ? ISIS_IPV6_REACH_DOWN : 0;
2457 control |= r->external ? ISIS_IPV6_REACH_EXTERNAL : 0;
2458 control |= r->subtlvs ? ISIS_IPV6_REACH_SUBTLV : 0;
2459
2460 stream_putc(s, control);
2461 stream_putc(s, r->prefix.prefixlen);
2462
2463 if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen))
2464 return 1;
2465 stream_put(s, &r->prefix.prefix.s6_addr, PSIZE(r->prefix.prefixlen));
2466
2467 if (r->subtlvs)
2468 return pack_subtlvs(r->subtlvs, s);
2469
2470 return 0;
2471}
2472
2473static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s,
2474 struct sbuf *log, void *dest, int indent)
2475{
2476 struct isis_tlvs *tlvs = dest;
2477 struct isis_ipv6_reach *rv = NULL;
2478 size_t consume;
2479 uint8_t control, subtlv_len;
2480 struct isis_item_list *items;
2481
2482 if (mtid == ISIS_MT_IPV4_UNICAST) {
2483 items = &tlvs->ipv6_reach;
2484 } else {
2485 items = isis_get_mt_items(&tlvs->mt_ipv6_reach, mtid);
2486 }
2487
2488 sbuf_push(log, indent, "Unpacking %sIPv6 reachability...\n",
2489 (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "mt ");
2490 consume = 6;
2491 if (len < consume) {
98c5bc15 2492 sbuf_push(log, indent,
6cde4b45 2493 "Not enough data left. (expected 6 or more bytes, got %hhu)\n",
98c5bc15 2494 len);
7ef5fefc
CF
2495 goto out;
2496 }
2497
841791b6 2498 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
2499
2500 rv->metric = stream_getl(s);
2501 control = stream_getc(s);
2502 rv->down = (control & ISIS_IPV6_REACH_DOWN);
2503 rv->external = (control & ISIS_IPV6_REACH_EXTERNAL);
2504
2505 rv->prefix.family = AF_INET6;
2506 rv->prefix.prefixlen = stream_getc(s);
2507 if (rv->prefix.prefixlen > 128) {
1b3f47d0 2508 sbuf_push(log, indent, "Prefixlen %u is implausible for IPv6\n",
7ef5fefc
CF
2509 rv->prefix.prefixlen);
2510 goto out;
2511 }
2512
2513 consume += PSIZE(rv->prefix.prefixlen);
2514 if (len < consume) {
98c5bc15
CF
2515 sbuf_push(log, indent,
2516 "Expected %u bytes of prefix, but only %u bytes available.\n",
2517 PSIZE(rv->prefix.prefixlen), len - 6);
7ef5fefc
CF
2518 goto out;
2519 }
2520 stream_get(&rv->prefix.prefix.s6_addr, s, PSIZE(rv->prefix.prefixlen));
2521 struct in6_addr orig_prefix = rv->prefix.prefix;
1b3f47d0 2522
7ef5fefc
CF
2523 apply_mask_ipv6(&rv->prefix);
2524 if (memcmp(&orig_prefix, &rv->prefix.prefix, sizeof(orig_prefix)))
2525 sbuf_push(log, indent + 2,
2526 "WARNING: Prefix had hostbits set.\n");
2527 format_item_ipv6_reach(mtid, (struct isis_item *)rv, log, indent + 2);
2528
2529 if (control & ISIS_IPV6_REACH_SUBTLV) {
2530 consume += 1;
2531 if (len < consume) {
98c5bc15
CF
2532 sbuf_push(log, indent,
2533 "Expected 1 byte of subtlv len, but no more data persent.\n");
7ef5fefc
CF
2534 goto out;
2535 }
2536 subtlv_len = stream_getc(s);
2537
2538 if (!subtlv_len) {
98c5bc15
CF
2539 sbuf_push(log, indent + 2,
2540 " WARNING: subtlv bit set, but there are no subtlvs.\n");
7ef5fefc
CF
2541 }
2542 consume += subtlv_len;
2543 if (len < consume) {
98c5bc15 2544 sbuf_push(log, indent,
6cde4b45 2545 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
98c5bc15
CF
2546 subtlv_len,
2547 len - 6 - PSIZE(rv->prefix.prefixlen));
7ef5fefc
CF
2548 goto out;
2549 }
2550
bd507085 2551 rv->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH);
bf555bf0
CF
2552 bool unpacked_known_tlvs = false;
2553
7ef5fefc 2554 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH, subtlv_len, s,
bf555bf0 2555 log, rv->subtlvs, indent + 4, &unpacked_known_tlvs)) {
7ef5fefc
CF
2556 goto out;
2557 }
bf555bf0
CF
2558 if (!unpacked_known_tlvs) {
2559 isis_free_subtlvs(rv->subtlvs);
2560 rv->subtlvs = NULL;
2561 }
7ef5fefc
CF
2562 }
2563
2564 append_item(items, (struct isis_item *)rv);
2565 return 0;
2566out:
2567 if (rv)
2568 free_item_ipv6_reach((struct isis_item *)rv);
2569 return 1;
2570}
2571
f2333421 2572/* Functions related to TLV 242 Router Capability as per RFC7981 */
1b3f47d0
OD
2573static struct isis_router_cap *copy_tlv_router_cap(
2574 const struct isis_router_cap *router_cap)
2575{
a064a7b8 2576 struct isis_router_cap *rv;
1b3f47d0
OD
2577
2578 if (!router_cap)
2579 return NULL;
2580
a064a7b8
DS
2581 rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2582
1b3f47d0
OD
2583 memcpy(rv, router_cap, sizeof(*rv));
2584
2585 return rv;
2586}
2587
2588static void format_tlv_router_cap(const struct isis_router_cap *router_cap,
2589 struct sbuf *buf, int indent)
2590{
2591 char addrbuf[INET_ADDRSTRLEN];
2592
2593 if (!router_cap)
2594 return;
2595
2596 /* Router ID and Flags */
2597 inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf));
2598 sbuf_push(buf, indent, "Router Capability:");
2599 sbuf_push(buf, indent, " %s , D:%c, S:%c\n", addrbuf,
2600 router_cap->flags & ISIS_ROUTER_CAP_FLAG_D ? '1' : '0',
2601 router_cap->flags & ISIS_ROUTER_CAP_FLAG_S ? '1' : '0');
2602
f2333421 2603 /* Segment Routing Global Block as per RFC8667 section #3.1 */
1b3f47d0 2604 if (router_cap->srgb.range_size != 0)
d8391312
OD
2605 sbuf_push(
2606 buf, indent,
2607 " Segment Routing: I:%s V:%s, Global Block Base: %u Range: %u\n",
d47d6089
RW
2608 IS_SR_IPV4(&router_cap->srgb) ? "1" : "0",
2609 IS_SR_IPV6(&router_cap->srgb) ? "1" : "0",
1b3f47d0
OD
2610 router_cap->srgb.lower_bound,
2611 router_cap->srgb.range_size);
2612
d8391312
OD
2613 /* Segment Routing Local Block as per RFC8667 section #3.3 */
2614 if (router_cap->srlb.range_size != 0)
2615 sbuf_push(buf, indent, " SR Local Block Base: %u Range: %u\n",
2616 router_cap->srlb.lower_bound,
2617 router_cap->srlb.range_size);
2618
f2333421 2619 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
1b3f47d0 2620 if (router_cap->algo[0] != SR_ALGORITHM_UNSET) {
d8391312
OD
2621 sbuf_push(buf, indent, " SR Algorithm:\n");
2622 for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
1b3f47d0 2623 if (router_cap->algo[i] != SR_ALGORITHM_UNSET)
d8391312
OD
2624 sbuf_push(buf, indent, " %u: %s\n", i,
2625 router_cap->algo[i] == 0
2626 ? "SPF"
2627 : "Strict SPF");
1b3f47d0
OD
2628 }
2629
f2333421 2630 /* Segment Routing Node MSD as per RFC8491 section #2 */
1b3f47d0 2631 if (router_cap->msd != 0)
d8391312
OD
2632 sbuf_push(buf, indent, " Node Maximum SID Depth: %u\n",
2633 router_cap->msd);
1b3f47d0
OD
2634}
2635
2636static void free_tlv_router_cap(struct isis_router_cap *router_cap)
2637{
2638 XFREE(MTYPE_ISIS_TLV, router_cap);
2639}
2640
2641static int pack_tlv_router_cap(const struct isis_router_cap *router_cap,
2642 struct stream *s)
2643{
2644 size_t tlv_len = ISIS_ROUTER_CAP_SIZE;
2645 size_t len_pos;
2646 uint8_t nb_algo;
2647
2648 if (!router_cap)
2649 return 0;
2650
2651 /* Compute Maximum TLV size */
2652 tlv_len += ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
2653 + ISIS_SUBTLV_HDR_SIZE
2654 + ISIS_SUBTLV_ALGORITHM_SIZE
2655 + ISIS_SUBTLV_NODE_MSD_SIZE;
2656
2657 if (STREAM_WRITEABLE(s) < (unsigned int)(2 + tlv_len))
2658 return 1;
2659
2660 /* Add Router Capability TLV 242 with Router ID and Flags */
2661 stream_putc(s, ISIS_TLV_ROUTER_CAPABILITY);
2662 /* Real length will be adjusted later */
2663 len_pos = stream_get_endp(s);
2664 stream_putc(s, tlv_len);
2665 stream_put_ipv4(s, router_cap->router_id.s_addr);
2666 stream_putc(s, router_cap->flags);
2667
f2333421 2668 /* Add SRGB if set as per RFC8667 section #3.1 */
1b3f47d0
OD
2669 if ((router_cap->srgb.range_size != 0)
2670 && (router_cap->srgb.lower_bound != 0)) {
2671 stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE);
2672 stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE);
2673 stream_putc(s, router_cap->srgb.flags);
2674 stream_put3(s, router_cap->srgb.range_size);
2675 stream_putc(s, ISIS_SUBTLV_SID_LABEL);
2676 stream_putc(s, ISIS_SUBTLV_SID_LABEL_SIZE);
2677 stream_put3(s, router_cap->srgb.lower_bound);
2678
f2333421 2679 /* Then SR Algorithm if set as per RFC8667 section #3.2 */
1b3f47d0
OD
2680 for (nb_algo = 0; nb_algo < SR_ALGORITHM_COUNT; nb_algo++)
2681 if (router_cap->algo[nb_algo] == SR_ALGORITHM_UNSET)
2682 break;
2683 if (nb_algo > 0) {
2684 stream_putc(s, ISIS_SUBTLV_ALGORITHM);
2685 stream_putc(s, nb_algo);
2686 for (int i = 0; i < nb_algo; i++)
2687 stream_putc(s, router_cap->algo[i]);
2688 }
d8391312
OD
2689
2690 /* Local Block if defined as per RFC8667 section #3.3 */
2691 if ((router_cap->srlb.range_size != 0)
2692 && (router_cap->srlb.lower_bound != 0)) {
2693 stream_putc(s, ISIS_SUBTLV_SRLB);
2694 stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE);
2695 /* No Flags are defined for SRLB */
2696 stream_putc(s, 0);
2697 stream_put3(s, router_cap->srlb.range_size);
2698 stream_putc(s, ISIS_SUBTLV_SID_LABEL);
2699 stream_putc(s, ISIS_SUBTLV_SID_LABEL_SIZE);
2700 stream_put3(s, router_cap->srlb.lower_bound);
2701 }
2702
f2333421 2703 /* And finish with MSD if set as per RFC8491 section #2 */
1b3f47d0
OD
2704 if (router_cap->msd != 0) {
2705 stream_putc(s, ISIS_SUBTLV_NODE_MSD);
2706 stream_putc(s, ISIS_SUBTLV_NODE_MSD_SIZE);
2707 stream_putc(s, MSD_TYPE_BASE_MPLS_IMPOSITION);
2708 stream_putc(s, router_cap->msd);
2709 }
2710 }
2711
2712 /* Adjust TLV length which depends on subTLVs presence */
2713 tlv_len = stream_get_endp(s) - len_pos - 1;
2714 stream_putc_at(s, len_pos, tlv_len);
2715
2716 return 0;
2717}
2718
2719static int unpack_tlv_router_cap(enum isis_tlv_context context,
2720 uint8_t tlv_type, uint8_t tlv_len,
2721 struct stream *s, struct sbuf *log,
2722 void *dest, int indent)
2723{
2724 struct isis_tlvs *tlvs = dest;
d8391312 2725 struct isis_router_cap *rcap;
1b3f47d0
OD
2726 uint8_t type;
2727 uint8_t length;
2728 uint8_t subtlv_len;
e075df3a 2729 uint8_t size;
1b3f47d0
OD
2730
2731 sbuf_push(log, indent, "Unpacking Router Capability TLV...\n");
2732 if (tlv_len < ISIS_ROUTER_CAP_SIZE) {
2733 sbuf_push(log, indent, "WARNING: Unexpected TLV size\n");
2734 stream_forward_getp(s, tlv_len);
2735 return 0;
2736 }
2737
2738 if (tlvs->router_cap) {
2739 sbuf_push(log, indent,
2740 "WARNING: Router Capability TLV present multiple times.\n");
2741 stream_forward_getp(s, tlv_len);
2742 return 0;
2743 }
2744
2745 /* Allocate router cap structure and initialize SR Algorithms */
d8391312 2746 rcap = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct isis_router_cap));
1b3f47d0 2747 for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
d8391312 2748 rcap->algo[i] = SR_ALGORITHM_UNSET;
1b3f47d0
OD
2749
2750 /* Get Router ID and Flags */
d8391312
OD
2751 rcap->router_id.s_addr = stream_get_ipv4(s);
2752 rcap->flags = stream_getc(s);
1b3f47d0
OD
2753
2754 /* Parse remaining part of the TLV if present */
2755 subtlv_len = tlv_len - ISIS_ROUTER_CAP_SIZE;
2756 while (subtlv_len > 2) {
1b3f47d0
OD
2757 uint8_t msd_type;
2758
2759 type = stream_getc(s);
2760 length = stream_getc(s);
2761 switch (type) {
2762 case ISIS_SUBTLV_SID_LABEL_RANGE:
e075df3a
OD
2763 /* Check that SRGB is correctly formated */
2764 if (length < SUBTLV_RANGE_LABEL_SIZE
2765 || length > SUBTLV_RANGE_INDEX_SIZE) {
2766 stream_forward_getp(s, length);
2767 continue;
2768 }
d8391312
OD
2769 /* Only one SRGB is supported. Skip subsequent one */
2770 if (rcap->srgb.range_size != 0) {
2771 stream_forward_getp(s, length);
2772 continue;
2773 }
2774 rcap->srgb.flags = stream_getc(s);
2775 rcap->srgb.range_size = stream_get3(s);
1b3f47d0
OD
2776 /* Skip Type and get Length of SID Label */
2777 stream_getc(s);
e075df3a
OD
2778 size = stream_getc(s);
2779 if (size == ISIS_SUBTLV_SID_LABEL_SIZE)
d8391312 2780 rcap->srgb.lower_bound = stream_get3(s);
1b3f47d0 2781 else
d8391312 2782 rcap->srgb.lower_bound = stream_getl(s);
1b3f47d0
OD
2783
2784 /* SRGB sanity checks. */
d8391312
OD
2785 if (rcap->srgb.range_size == 0
2786 || (rcap->srgb.lower_bound <= MPLS_LABEL_RESERVED_MAX)
2787 || ((rcap->srgb.lower_bound + rcap->srgb.range_size - 1)
1b3f47d0
OD
2788 > MPLS_LABEL_UNRESERVED_MAX)) {
2789 sbuf_push(log, indent, "Invalid label range. Reset SRGB\n");
d8391312
OD
2790 rcap->srgb.lower_bound = 0;
2791 rcap->srgb.range_size = 0;
1b3f47d0 2792 }
e075df3a
OD
2793 /* Only one range is supported. Skip subsequent one */
2794 size = length - (size + SUBTLV_SR_BLOCK_SIZE);
2795 if (size > 0)
2796 stream_forward_getp(s, length);
1b3f47d0
OD
2797 break;
2798 case ISIS_SUBTLV_ALGORITHM:
2799 /* Only 2 algorithms are supported: SPF & Strict SPF */
d8391312 2800 stream_get(&rcap->algo, s,
1b3f47d0
OD
2801 length > SR_ALGORITHM_COUNT
2802 ? SR_ALGORITHM_COUNT
2803 : length);
2804 if (length > SR_ALGORITHM_COUNT)
2805 stream_forward_getp(
2806 s, length - SR_ALGORITHM_COUNT);
2807 break;
d8391312 2808 case ISIS_SUBTLV_SRLB:
e075df3a
OD
2809 /* Check that SRLB is correctly formated */
2810 if (length < SUBTLV_RANGE_LABEL_SIZE
2811 || length > SUBTLV_RANGE_INDEX_SIZE) {
2812 stream_forward_getp(s, length);
2813 continue;
2814 }
d8391312
OD
2815 /* RFC 8667 section #3.3: Only one SRLB is authorized */
2816 if (rcap->srlb.range_size != 0) {
2817 stream_forward_getp(s, length);
2818 continue;
2819 }
2820 /* Ignore Flags which are not defined */
2821 stream_getc(s);
2822 rcap->srlb.range_size = stream_get3(s);
2823 /* Skip Type and get Length of SID Label */
2824 stream_getc(s);
e075df3a
OD
2825 size = stream_getc(s);
2826 if (size == ISIS_SUBTLV_SID_LABEL_SIZE)
d8391312
OD
2827 rcap->srlb.lower_bound = stream_get3(s);
2828 else
2829 rcap->srlb.lower_bound = stream_getl(s);
2830
2831 /* SRLB sanity checks. */
2832 if (rcap->srlb.range_size == 0
2833 || (rcap->srlb.lower_bound <= MPLS_LABEL_RESERVED_MAX)
2834 || ((rcap->srlb.lower_bound + rcap->srlb.range_size - 1)
2835 > MPLS_LABEL_UNRESERVED_MAX)) {
2836 sbuf_push(log, indent, "Invalid label range. Reset SRLB\n");
2837 rcap->srlb.lower_bound = 0;
2838 rcap->srlb.range_size = 0;
2839 }
e075df3a
OD
2840 /* Only one range is supported. Skip subsequent one */
2841 size = length - (size + SUBTLV_SR_BLOCK_SIZE);
2842 if (size > 0)
2843 stream_forward_getp(s, length);
d8391312 2844 break;
1b3f47d0 2845 case ISIS_SUBTLV_NODE_MSD:
e075df3a
OD
2846 /* Check that MSD is correctly formated */
2847 if (length < MSD_TLV_SIZE) {
2848 stream_forward_getp(s, length);
2849 continue;
2850 }
1b3f47d0 2851 msd_type = stream_getc(s);
d8391312 2852 rcap->msd = stream_getc(s);
1b3f47d0
OD
2853 /* Only BMI-MSD type has been defined in RFC 8491 */
2854 if (msd_type != MSD_TYPE_BASE_MPLS_IMPOSITION)
d8391312 2855 rcap->msd = 0;
e075df3a
OD
2856 /* Only one MSD is standardized. Skip others */
2857 if (length > MSD_TLV_SIZE)
2858 stream_forward_getp(s, length - MSD_TLV_SIZE);
1b3f47d0
OD
2859 break;
2860 default:
2861 stream_forward_getp(s, length);
2862 break;
2863 }
2864 subtlv_len = subtlv_len - length - 2;
2865 }
d8391312 2866 tlvs->router_cap = rcap;
1b3f47d0
OD
2867 return 0;
2868}
2869
7ef5fefc
CF
2870/* Functions related to TLV 10 Authentication */
2871static struct isis_item *copy_item_auth(struct isis_item *i)
2872{
2873 struct isis_auth *auth = (struct isis_auth *)i;
841791b6 2874 struct isis_auth *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
2875
2876 rv->type = auth->type;
2877 rv->length = auth->length;
2878 memcpy(rv->value, auth->value, sizeof(rv->value));
2879 return (struct isis_item *)rv;
2880}
2881
2882static void format_item_auth(uint16_t mtid, struct isis_item *i,
2883 struct sbuf *buf, int indent)
2884{
2885 struct isis_auth *auth = (struct isis_auth *)i;
2886 char obuf[768];
2887
2888 sbuf_push(buf, indent, "Authentication:\n");
2889 switch (auth->type) {
2890 case ISIS_PASSWD_TYPE_CLEARTXT:
2891 zlog_sanitize(obuf, sizeof(obuf), auth->value, auth->length);
2892 sbuf_push(buf, indent, " Password: %s\n", obuf);
2893 break;
2894 case ISIS_PASSWD_TYPE_HMAC_MD5:
f7813c7c
A
2895 for (unsigned int j = 0; j < 16; j++) {
2896 snprintf(obuf + 2 * j, sizeof(obuf) - 2 * j,
6cde4b45 2897 "%02hhx", auth->value[j]);
7ef5fefc
CF
2898 }
2899 sbuf_push(buf, indent, " HMAC-MD5: %s\n", obuf);
2900 break;
2901 default:
6cde4b45 2902 sbuf_push(buf, indent, " Unknown (%hhu)\n", auth->type);
7ef5fefc 2903 break;
5b94ec50 2904 }
7ef5fefc
CF
2905}
2906
2907static void free_item_auth(struct isis_item *i)
2908{
841791b6 2909 XFREE(MTYPE_ISIS_TLV, i);
7ef5fefc
CF
2910}
2911
2912static int pack_item_auth(struct isis_item *i, struct stream *s)
2913{
2914 struct isis_auth *auth = (struct isis_auth *)i;
2915
2916 if (STREAM_WRITEABLE(s) < 1)
2917 return 1;
2918 stream_putc(s, auth->type);
2919
2920 switch (auth->type) {
2921 case ISIS_PASSWD_TYPE_CLEARTXT:
2922 if (STREAM_WRITEABLE(s) < auth->length)
2923 return 1;
2924 stream_put(s, auth->passwd, auth->length);
2925 break;
2926 case ISIS_PASSWD_TYPE_HMAC_MD5:
2927 if (STREAM_WRITEABLE(s) < 16)
2928 return 1;
2929 auth->offset = stream_get_endp(s);
2930 stream_put(s, NULL, 16);
2931 break;
2932 default:
2933 return 1;
2934 }
2935
2936 return 0;
2937}
2938
2939static int unpack_item_auth(uint16_t mtid, uint8_t len, struct stream *s,
2940 struct sbuf *log, void *dest, int indent)
2941{
2942 struct isis_tlvs *tlvs = dest;
2943
2944 sbuf_push(log, indent, "Unpack Auth TLV...\n");
2945 if (len < 1) {
2946 sbuf_push(
2947 log, indent,
6cde4b45 2948 "Not enough data left.(Expected 1 bytes of auth type, got %hhu)\n",
7ef5fefc
CF
2949 len);
2950 return 1;
2951 }
2952
841791b6 2953 struct isis_auth *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
2954
2955 rv->type = stream_getc(s);
2956 rv->length = len - 1;
2957
2958 if (rv->type == ISIS_PASSWD_TYPE_HMAC_MD5 && rv->length != 16) {
2959 sbuf_push(
2960 log, indent,
6cde4b45 2961 "Unexpected auth length for HMAC-MD5 (expected 16, got %hhu)\n",
7ef5fefc 2962 rv->length);
841791b6 2963 XFREE(MTYPE_ISIS_TLV, rv);
7ef5fefc
CF
2964 return 1;
2965 }
2966
2967 rv->offset = stream_get_getp(s);
2968 stream_get(rv->value, s, rv->length);
2969 format_item_auth(mtid, (struct isis_item *)rv, log, indent + 2);
2970 append_item(&tlvs->isis_auth, (struct isis_item *)rv);
2971 return 0;
2972}
2973
5f77d901
CF
2974/* Functions related to TLV 13 Purge Originator */
2975
2976static struct isis_purge_originator *copy_tlv_purge_originator(
2977 struct isis_purge_originator *poi)
2978{
2979 if (!poi)
2980 return NULL;
2981
2982 struct isis_purge_originator *rv;
2983
2984 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2985 rv->sender_set = poi->sender_set;
2986 memcpy(rv->generator, poi->generator, sizeof(rv->generator));
2987 if (poi->sender_set)
2988 memcpy(rv->sender, poi->sender, sizeof(rv->sender));
2989 return rv;
2990}
2991
2992static void format_tlv_purge_originator(struct isis_purge_originator *poi,
2993 struct sbuf *buf, int indent)
2994{
2995 if (!poi)
2996 return;
2997
2998 sbuf_push(buf, indent, "Purge Originator Identification:\n");
2999 sbuf_push(buf, indent, " Generator: %s\n",
3000 isis_format_id(poi->generator, sizeof(poi->generator)));
3001 if (poi->sender_set) {
3002 sbuf_push(buf, indent, " Received-From: %s\n",
3003 isis_format_id(poi->sender, sizeof(poi->sender)));
3004 }
3005}
3006
3007static void free_tlv_purge_originator(struct isis_purge_originator *poi)
3008{
3009 XFREE(MTYPE_ISIS_TLV, poi);
3010}
3011
3012static int pack_tlv_purge_originator(struct isis_purge_originator *poi,
3013 struct stream *s)
3014{
3015 if (!poi)
3016 return 0;
3017
3018 uint8_t data_len = 1 + sizeof(poi->generator);
3019
3020 if (poi->sender_set)
3021 data_len += sizeof(poi->sender);
3022
3023 if (STREAM_WRITEABLE(s) < (unsigned)(2 + data_len))
3024 return 1;
3025
3026 stream_putc(s, ISIS_TLV_PURGE_ORIGINATOR);
3027 stream_putc(s, data_len);
3028 stream_putc(s, poi->sender_set ? 2 : 1);
3029 stream_put(s, poi->generator, sizeof(poi->generator));
3030 if (poi->sender_set)
3031 stream_put(s, poi->sender, sizeof(poi->sender));
3032 return 0;
3033}
3034
3035static int unpack_tlv_purge_originator(enum isis_tlv_context context,
3036 uint8_t tlv_type, uint8_t tlv_len,
3037 struct stream *s, struct sbuf *log,
3038 void *dest, int indent)
3039{
3040 struct isis_tlvs *tlvs = dest;
3e300703 3041 struct isis_purge_originator poi = {};
5f77d901
CF
3042
3043 sbuf_push(log, indent, "Unpacking Purge Originator Identification TLV...\n");
3044 if (tlv_len < 7) {
6cde4b45 3045 sbuf_push(log, indent, "Not enough data left. (Expected at least 7 bytes, got %hhu)\n", tlv_len);
5f77d901
CF
3046 return 1;
3047 }
3048
3049 uint8_t number_of_ids = stream_getc(s);
3050
3051 if (number_of_ids == 1) {
3052 poi.sender_set = false;
3053 } else if (number_of_ids == 2) {
3054 poi.sender_set = true;
3055 } else {
6cde4b45 3056 sbuf_push(log, indent, "Got invalid value for number of system IDs: %hhu)\n", number_of_ids);
5f77d901
CF
3057 return 1;
3058 }
3059
3060 if (tlv_len != 1 + 6 * number_of_ids) {
3061 sbuf_push(log, indent, "Incorrect tlv len for number of IDs.\n");
3062 return 1;
3063 }
3064
3065 stream_get(poi.generator, s, sizeof(poi.generator));
3066 if (poi.sender_set)
3067 stream_get(poi.sender, s, sizeof(poi.sender));
3068
3069 if (tlvs->purge_originator) {
3070 sbuf_push(log, indent,
3071 "WARNING: Purge originator present multiple times, ignoring.\n");
3072 return 0;
3073 }
3074
3075 tlvs->purge_originator = copy_tlv_purge_originator(&poi);
3076 return 0;
3077}
3078
3079
7ef5fefc
CF
3080/* Functions relating to item TLVs */
3081
3082static void init_item_list(struct isis_item_list *items)
3083{
3084 items->head = NULL;
3085 items->tail = &items->head;
3086 items->count = 0;
3087}
3088
3089static struct isis_item *copy_item(enum isis_tlv_context context,
3090 enum isis_tlv_type type,
3091 struct isis_item *item)
3092{
3093 const struct tlv_ops *ops = tlv_table[context][type];
3094
3095 if (ops && ops->copy_item)
3096 return ops->copy_item(item);
3097
3098 assert(!"Unknown item tlv type!");
3099 return NULL;
3100}
3101
3102static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type,
3103 struct isis_item_list *src, struct isis_item_list *dest)
3104{
3105 struct isis_item *item;
3106
3107 init_item_list(dest);
3108
3109 for (item = src->head; item; item = item->next) {
3110 append_item(dest, copy_item(context, type, item));
3111 }
3112}
3113
3114static void format_item(uint16_t mtid, enum isis_tlv_context context,
3115 enum isis_tlv_type type, struct isis_item *i,
3116 struct sbuf *buf, int indent)
3117{
3118 const struct tlv_ops *ops = tlv_table[context][type];
3119
3120 if (ops && ops->format_item) {
3121 ops->format_item(mtid, i, buf, indent);
3122 return;
3123 }
3124
3125 assert(!"Unknown item tlv type!");
3126}
3127
3128static void format_items_(uint16_t mtid, enum isis_tlv_context context,
3129 enum isis_tlv_type type, struct isis_item_list *items,
3130 struct sbuf *buf, int indent)
3131{
3132 struct isis_item *i;
3133
3134 for (i = items->head; i; i = i->next)
3135 format_item(mtid, context, type, i, buf, indent);
3136}
7ef5fefc
CF
3137
3138static void free_item(enum isis_tlv_context tlv_context,
3139 enum isis_tlv_type tlv_type, struct isis_item *item)
3140{
3141 const struct tlv_ops *ops = tlv_table[tlv_context][tlv_type];
3142
3143 if (ops && ops->free_item) {
3144 ops->free_item(item);
3145 return;
3146 }
3147
3148 assert(!"Unknown item tlv type!");
3149}
3150
3151static void free_items(enum isis_tlv_context context, enum isis_tlv_type type,
3152 struct isis_item_list *items)
3153{
3154 struct isis_item *item, *next_item;
3155
3156 for (item = items->head; item; item = next_item) {
3157 next_item = item->next;
3158 free_item(context, type, item);
3159 }
3160}
3161
3162static int pack_item(enum isis_tlv_context context, enum isis_tlv_type type,
3163 struct isis_item *i, struct stream *s,
3164 struct isis_tlvs **fragment_tlvs,
2b64873d 3165 const struct pack_order_entry *pe, uint16_t mtid)
7ef5fefc
CF
3166{
3167 const struct tlv_ops *ops = tlv_table[context][type];
3168
3169 if (ops && ops->pack_item) {
3170 return ops->pack_item(i, s);
3171 }
3172
3173 assert(!"Unknown item tlv type!");
3174 return 1;
3175}
3176
2b64873d
DL
3177static void add_item_to_fragment(struct isis_item *i,
3178 const struct pack_order_entry *pe,
7ef5fefc
CF
3179 struct isis_tlvs *fragment_tlvs, uint16_t mtid)
3180{
3181 struct isis_item_list *l;
3182
3183 if (pe->how_to_pack == ISIS_ITEMS) {
98c5bc15 3184 l = (struct isis_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack);
7ef5fefc
CF
3185 } else {
3186 struct isis_mt_item_list *m;
98c5bc15 3187 m = (struct isis_mt_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack);
7ef5fefc
CF
3188 l = isis_get_mt_items(m, mtid);
3189 }
3190
3191 append_item(l, copy_item(pe->context, pe->type, i));
3192}
3193
3194static int pack_items_(uint16_t mtid, enum isis_tlv_context context,
3195 enum isis_tlv_type type, struct isis_item_list *items,
3196 struct stream *s, struct isis_tlvs **fragment_tlvs,
2b64873d 3197 const struct pack_order_entry *pe,
7ef5fefc
CF
3198 struct isis_tlvs *(*new_fragment)(struct list *l),
3199 struct list *new_fragment_arg)
3200{
3201 size_t len_pos, last_len, len;
3202 struct isis_item *item = NULL;
3203 int rv;
3204
3205 if (!items->head)
3206 return 0;
3207
3208top:
3209 if (STREAM_WRITEABLE(s) < 2)
3210 goto too_long;
3211
3212 stream_putc(s, type);
3213 len_pos = stream_get_endp(s);
3214 stream_putc(s, 0); /* Put 0 as length for now */
3215
3216 if (context == ISIS_CONTEXT_LSP && IS_COMPAT_MT_TLV(type)
3217 && mtid != ISIS_MT_IPV4_UNICAST) {
3218 if (STREAM_WRITEABLE(s) < 2)
3219 goto too_long;
3220 stream_putw(s, mtid);
3221 }
3222
3223 if (context == ISIS_CONTEXT_LSP && type == ISIS_TLV_OLDSTYLE_REACH) {
3224 if (STREAM_WRITEABLE(s) < 1)
3225 goto too_long;
3226 stream_putc(s, 0); /* Virtual flag is set to 0 */
3227 }
3228
3229 last_len = len = 0;
3230 for (item = item ? item : items->head; item; item = item->next) {
3231 rv = pack_item(context, type, item, s, fragment_tlvs, pe, mtid);
3232 if (rv)
3233 goto too_long;
3234
3235 len = stream_get_endp(s) - len_pos - 1;
3236
3237 /* Multiple auths don't go into one TLV, so always break */
3238 if (context == ISIS_CONTEXT_LSP && type == ISIS_TLV_AUTH) {
3239 item = item->next;
3240 break;
3241 }
3242
bd507085
CF
3243 /* Multiple prefix-sids don't go into one TLV, so always break */
3244 if (type == ISIS_SUBTLV_PREFIX_SID
3245 && (context == ISIS_CONTEXT_SUBTLV_IP_REACH
3246 || context == ISIS_CONTEXT_SUBTLV_IPV6_REACH)) {
3247 item = item->next;
3248 break;
3249 }
3250
7ef5fefc
CF
3251 if (len > 255) {
3252 if (!last_len) /* strange, not a single item fit */
3253 return 1;
3254 /* drop last tlv, otherwise, its too long */
3255 stream_set_endp(s, len_pos + 1 + last_len);
3256 len = last_len;
3257 break;
3258 }
3259
3260 if (fragment_tlvs)
3261 add_item_to_fragment(item, pe, *fragment_tlvs, mtid);
3262
3263 last_len = len;
3264 }
3265
3266 stream_putc_at(s, len_pos, len);
3267 if (item)
3268 goto top;
3269
3270 return 0;
3271too_long:
3272 if (!fragment_tlvs)
3273 return 1;
3274 stream_reset(s);
3275 *fragment_tlvs = new_fragment(new_fragment_arg);
3276 goto top;
3277}
3278#define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
3279
3280static void append_item(struct isis_item_list *dest, struct isis_item *item)
3281{
3282 *dest->tail = item;
3283 dest->tail = &(*dest->tail)->next;
3284 dest->count++;
3285}
3286
1b3f47d0
OD
3287static void delete_item(struct isis_item_list *dest, struct isis_item *del)
3288{
3289 struct isis_item *item, *prev = NULL, *next;
3290
3291 /* Sanity Check */
3292 if ((dest == NULL) || (del == NULL))
3293 return;
3294
3295 /*
3296 * TODO: delete is tricky because "dest" is a singly linked list.
3297 * We need to switch a doubly linked list.
3298 */
3299 for (item = dest->head; item; item = next) {
3300 if (item->next == del) {
3301 prev = item;
3302 break;
3303 }
3304 next = item->next;
3305 }
3306 if (prev)
3307 prev->next = del->next;
3308 if (dest->head == del)
3309 dest->head = del->next;
3310 if ((struct isis_item *)dest->tail == del) {
3311 *dest->tail = prev;
3312 if (prev)
3313 dest->tail = &(*dest->tail)->next;
3314 else
3315 dest->tail = &dest->head;
3316 }
3317 dest->count--;
3318}
3319
d43d2df5
CF
3320static struct isis_item *last_item(struct isis_item_list *list)
3321{
3322 return container_of(list->tail, struct isis_item, next);
3323}
3324
7ef5fefc
CF
3325static int unpack_item(uint16_t mtid, enum isis_tlv_context context,
3326 uint8_t tlv_type, uint8_t len, struct stream *s,
3327 struct sbuf *log, void *dest, int indent)
3328{
3329 const struct tlv_ops *ops = tlv_table[context][tlv_type];
3330
3331 if (ops && ops->unpack_item)
3332 return ops->unpack_item(mtid, len, s, log, dest, indent);
3333
3334 assert(!"Unknown item tlv type!");
3335 sbuf_push(log, indent, "Unknown item tlv type!\n");
3336 return 1;
3337}
3338
3339static int unpack_tlv_with_items(enum isis_tlv_context context,
3340 uint8_t tlv_type, uint8_t tlv_len,
3341 struct stream *s, struct sbuf *log, void *dest,
3342 int indent)
3343{
3344 size_t tlv_start;
3345 size_t tlv_pos;
3346 int rv;
3347 uint16_t mtid;
3348
3349 tlv_start = stream_get_getp(s);
3350 tlv_pos = 0;
3351
3352 if (context == ISIS_CONTEXT_LSP && IS_COMPAT_MT_TLV(tlv_type)) {
3353 if (tlv_len < 2) {
3354 sbuf_push(log, indent,
3355 "TLV is too short to contain MTID\n");
3356 return 1;
3357 }
3358 mtid = stream_getw(s) & ISIS_MT_MASK;
3359 tlv_pos += 2;
3360 sbuf_push(log, indent, "Unpacking as MT %s item TLV...\n",
3361 isis_mtid2str(mtid));
3362 } else {
3363 sbuf_push(log, indent, "Unpacking as item TLV...\n");
3364 mtid = ISIS_MT_IPV4_UNICAST;
3365 }
3366
3367 if (context == ISIS_CONTEXT_LSP
3368 && tlv_type == ISIS_TLV_OLDSTYLE_REACH) {
3369 if (tlv_len - tlv_pos < 1) {
3370 sbuf_push(log, indent,
3371 "TLV is too short for old style reach\n");
3372 return 1;
3373 }
3374 stream_forward_getp(s, 1);
3375 tlv_pos += 1;
3376 }
3377
3378 if (context == ISIS_CONTEXT_LSP
3379 && tlv_type == ISIS_TLV_OLDSTYLE_IP_REACH) {
3380 struct isis_tlvs *tlvs = dest;
3381 dest = &tlvs->oldstyle_ip_reach;
3382 } else if (context == ISIS_CONTEXT_LSP
3383 && tlv_type == ISIS_TLV_OLDSTYLE_IP_REACH_EXT) {
3384 struct isis_tlvs *tlvs = dest;
3385 dest = &tlvs->oldstyle_ip_reach_ext;
3386 }
3387
3388 if (context == ISIS_CONTEXT_LSP
3389 && tlv_type == ISIS_TLV_MT_ROUTER_INFO) {
3390 struct isis_tlvs *tlvs = dest;
3391 tlvs->mt_router_info_empty = (tlv_pos >= (size_t)tlv_len);
3392 }
3393
3394 while (tlv_pos < (size_t)tlv_len) {
3395 rv = unpack_item(mtid, context, tlv_type, tlv_len - tlv_pos, s,
3396 log, dest, indent + 2);
3397 if (rv)
3398 return rv;
3399
3400 tlv_pos = stream_get_getp(s) - tlv_start;
3401 }
3402
3403 return 0;
3404}
3405
3406/* Functions to manipulate mt_item_lists */
3407
3408static int isis_mt_item_list_cmp(const struct isis_item_list *a,
3409 const struct isis_item_list *b)
3410{
3411 if (a->mtid < b->mtid)
3412 return -1;
3413 if (a->mtid > b->mtid)
3414 return 1;
3415 return 0;
3416}
3417
3418RB_PROTOTYPE(isis_mt_item_list, isis_item_list, mt_tree, isis_mt_item_list_cmp);
3419RB_GENERATE(isis_mt_item_list, isis_item_list, mt_tree, isis_mt_item_list_cmp);
3420
3421struct isis_item_list *isis_get_mt_items(struct isis_mt_item_list *m,
3422 uint16_t mtid)
3423{
3424 struct isis_item_list *rv;
3425
3426 rv = isis_lookup_mt_items(m, mtid);
3427 if (!rv) {
3428 rv = XCALLOC(MTYPE_ISIS_MT_ITEM_LIST, sizeof(*rv));
3429 init_item_list(rv);
3430 rv->mtid = mtid;
3431 RB_INSERT(isis_mt_item_list, m, rv);
3432 }
3433
3434 return rv;
3435}
3436
3437struct isis_item_list *isis_lookup_mt_items(struct isis_mt_item_list *m,
3438 uint16_t mtid)
3439{
3440 struct isis_item_list key = {.mtid = mtid};
3441
3442 return RB_FIND(isis_mt_item_list, m, &key);
3443}
3444
3445static void free_mt_items(enum isis_tlv_context context,
3446 enum isis_tlv_type type, struct isis_mt_item_list *m)
3447{
3448 struct isis_item_list *n, *nnext;
3449
a2addae8 3450 RB_FOREACH_SAFE (n, isis_mt_item_list, m, nnext) {
7ef5fefc
CF
3451 free_items(context, type, n);
3452 RB_REMOVE(isis_mt_item_list, m, n);
3453 XFREE(MTYPE_ISIS_MT_ITEM_LIST, n);
3454 }
3455}
3456
3457static void format_mt_items(enum isis_tlv_context context,
3458 enum isis_tlv_type type,
3459 struct isis_mt_item_list *m, struct sbuf *buf,
3460 int indent)
3461{
3462 struct isis_item_list *n;
3463
a2addae8 3464 RB_FOREACH (n, isis_mt_item_list, m) {
7ef5fefc
CF
3465 format_items_(n->mtid, context, type, n, buf, indent);
3466 }
3467}
3468
3469static int pack_mt_items(enum isis_tlv_context context, enum isis_tlv_type type,
3470 struct isis_mt_item_list *m, struct stream *s,
3471 struct isis_tlvs **fragment_tlvs,
2b64873d 3472 const struct pack_order_entry *pe,
7ef5fefc
CF
3473 struct isis_tlvs *(*new_fragment)(struct list *l),
3474 struct list *new_fragment_arg)
3475{
3476 struct isis_item_list *n;
3477
a2addae8 3478 RB_FOREACH (n, isis_mt_item_list, m) {
7ef5fefc
CF
3479 int rv;
3480
3481 rv = pack_items_(n->mtid, context, type, n, s, fragment_tlvs,
3482 pe, new_fragment, new_fragment_arg);
3483 if (rv)
3484 return rv;
3485 }
3486
3487 return 0;
3488}
3489
3490static void copy_mt_items(enum isis_tlv_context context,
3491 enum isis_tlv_type type,
3492 struct isis_mt_item_list *src,
3493 struct isis_mt_item_list *dest)
3494{
3495 struct isis_item_list *n;
3496
3497 RB_INIT(isis_mt_item_list, dest);
3498
a2addae8 3499 RB_FOREACH (n, isis_mt_item_list, src) {
7ef5fefc
CF
3500 copy_items(context, type, n, isis_get_mt_items(dest, n->mtid));
3501 }
3502}
3503
3504/* Functions related to tlvs in general */
3505
3506struct isis_tlvs *isis_alloc_tlvs(void)
3507{
3508 struct isis_tlvs *result;
3509
841791b6 3510 result = XCALLOC(MTYPE_ISIS_TLV, sizeof(*result));
7ef5fefc
CF
3511
3512 init_item_list(&result->isis_auth);
3513 init_item_list(&result->area_addresses);
3514 init_item_list(&result->mt_router_info);
3515 init_item_list(&result->oldstyle_reach);
3516 init_item_list(&result->lan_neighbor);
3517 init_item_list(&result->lsp_entries);
3518 init_item_list(&result->extended_reach);
3519 RB_INIT(isis_mt_item_list, &result->mt_reach);
3520 init_item_list(&result->oldstyle_ip_reach);
3521 init_item_list(&result->oldstyle_ip_reach_ext);
3522 init_item_list(&result->ipv4_address);
3523 init_item_list(&result->ipv6_address);
3524 init_item_list(&result->extended_ip_reach);
3525 RB_INIT(isis_mt_item_list, &result->mt_ip_reach);
3526 init_item_list(&result->ipv6_reach);
3527 RB_INIT(isis_mt_item_list, &result->mt_ipv6_reach);
3528
3529 return result;
3530}
3531
3532struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs)
3533{
841791b6 3534 struct isis_tlvs *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
7ef5fefc
CF
3535
3536 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth,
3537 &rv->isis_auth);
3538
5f77d901
CF
3539 rv->purge_originator =
3540 copy_tlv_purge_originator(tlvs->purge_originator);
3541
7ef5fefc
CF
3542 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
3543 &tlvs->area_addresses, &rv->area_addresses);
3544
3545 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
3546 &tlvs->mt_router_info, &rv->mt_router_info);
3547
b9d4a380 3548 rv->mt_router_info_empty = tlvs->mt_router_info_empty;
7ef5fefc
CF
3549
3550 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
3551 &tlvs->oldstyle_reach, &rv->oldstyle_reach);
3552
3553 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
3554 &tlvs->lan_neighbor, &rv->lan_neighbor);
3555
3556 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries,
3557 &rv->lsp_entries);
3558
3559 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
3560 &tlvs->extended_reach, &rv->extended_reach);
3561
3562 copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach,
3563 &rv->mt_reach);
3564
3565 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
3566 &tlvs->oldstyle_ip_reach, &rv->oldstyle_ip_reach);
3567
3568 copy_tlv_protocols_supported(&tlvs->protocols_supported,
3569 &rv->protocols_supported);
3570
3571 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
3572 &tlvs->oldstyle_ip_reach_ext, &rv->oldstyle_ip_reach_ext);
3573
3574 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS, &tlvs->ipv4_address,
3575 &rv->ipv4_address);
3576
3577 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS, &tlvs->ipv6_address,
3578 &rv->ipv6_address);
3579
3580 rv->te_router_id = copy_tlv_te_router_id(tlvs->te_router_id);
3581
3582 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
3583 &tlvs->extended_ip_reach, &rv->extended_ip_reach);
3584
3585 copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
3586 &tlvs->mt_ip_reach, &rv->mt_ip_reach);
3587
3588 rv->hostname = copy_tlv_dynamic_hostname(tlvs->hostname);
3589
3590 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach,
3591 &rv->ipv6_reach);
3592
3593 copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
3594 &tlvs->mt_ipv6_reach, &rv->mt_ipv6_reach);
3595
9fe21208
CF
3596 rv->threeway_adj = copy_tlv_threeway_adj(tlvs->threeway_adj);
3597
1b3f47d0
OD
3598 rv->router_cap = copy_tlv_router_cap(tlvs->router_cap);
3599
41a145f1
CF
3600 rv->spine_leaf = copy_tlv_spine_leaf(tlvs->spine_leaf);
3601
7ef5fefc
CF
3602 return rv;
3603}
3604
3605static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent)
3606{
3607 format_tlv_protocols_supported(&tlvs->protocols_supported, buf, indent);
3608
3609 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth, buf,
3610 indent);
3611
5f77d901
CF
3612 format_tlv_purge_originator(tlvs->purge_originator, buf, indent);
3613
7ef5fefc
CF
3614 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
3615 &tlvs->area_addresses, buf, indent);
3616
3617 if (tlvs->mt_router_info_empty) {
3618 sbuf_push(buf, indent, "MT Router Info: None\n");
3619 } else {
3620 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
3621 &tlvs->mt_router_info, buf, indent);
3622 }
3623
3624 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
3625 &tlvs->oldstyle_reach, buf, indent);
3626
3627 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
3628 &tlvs->lan_neighbor, buf, indent);
3629
3630 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries,
3631 buf, indent);
3632
3633 format_tlv_dynamic_hostname(tlvs->hostname, buf, indent);
3634 format_tlv_te_router_id(tlvs->te_router_id, buf, indent);
1b3f47d0 3635 format_tlv_router_cap(tlvs->router_cap, buf, indent);
7ef5fefc
CF
3636
3637 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
3638 &tlvs->extended_reach, buf, indent);
3639
3640 format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach,
3641 buf, indent);
3642
3643 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
3644 &tlvs->oldstyle_ip_reach, buf, indent);
3645
3646 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
3647 &tlvs->oldstyle_ip_reach_ext, buf, indent);
3648
3649 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS,
3650 &tlvs->ipv4_address, buf, indent);
3651
3652 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS,
3653 &tlvs->ipv6_address, buf, indent);
3654
3655 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
3656 &tlvs->extended_ip_reach, buf, indent);
3657
3658 format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
3659 &tlvs->mt_ip_reach, buf, indent);
3660
3661 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach,
3662 buf, indent);
3663
3664 format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
3665 &tlvs->mt_ipv6_reach, buf, indent);
9fe21208
CF
3666
3667 format_tlv_threeway_adj(tlvs->threeway_adj, buf, indent);
41a145f1
CF
3668
3669 format_tlv_spine_leaf(tlvs->spine_leaf, buf, indent);
7ef5fefc
CF
3670}
3671
3672const char *isis_format_tlvs(struct isis_tlvs *tlvs)
3673{
3674 static struct sbuf buf;
3675
3676 if (!sbuf_buf(&buf))
3677 sbuf_init(&buf, NULL, 0);
3678
3679 sbuf_reset(&buf);
3680 format_tlvs(tlvs, &buf, 0);
3681 return sbuf_buf(&buf);
3682}
3683
3684void isis_free_tlvs(struct isis_tlvs *tlvs)
3685{
3686 if (!tlvs)
3687 return;
3688
3689 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth);
5f77d901 3690 free_tlv_purge_originator(tlvs->purge_originator);
7ef5fefc
CF
3691 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
3692 &tlvs->area_addresses);
3693 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
3694 &tlvs->mt_router_info);
3695 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
3696 &tlvs->oldstyle_reach);
3697 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
3698 &tlvs->lan_neighbor);
3699 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries);
3700 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
3701 &tlvs->extended_reach);
3702 free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach);
3703 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
3704 &tlvs->oldstyle_ip_reach);
3705 free_tlv_protocols_supported(&tlvs->protocols_supported);
3706 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
3707 &tlvs->oldstyle_ip_reach_ext);
3708 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS,
3709 &tlvs->ipv4_address);
3710 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS,
3711 &tlvs->ipv6_address);
3712 free_tlv_te_router_id(tlvs->te_router_id);
3713 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
3714 &tlvs->extended_ip_reach);
3715 free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
3716 &tlvs->mt_ip_reach);
3717 free_tlv_dynamic_hostname(tlvs->hostname);
3718 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach);
3719 free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
3720 &tlvs->mt_ipv6_reach);
9fe21208 3721 free_tlv_threeway_adj(tlvs->threeway_adj);
1b3f47d0 3722 free_tlv_router_cap(tlvs->router_cap);
41a145f1 3723 free_tlv_spine_leaf(tlvs->spine_leaf);
7ef5fefc 3724
841791b6 3725 XFREE(MTYPE_ISIS_TLV, tlvs);
7ef5fefc
CF
3726}
3727
3728static void add_padding(struct stream *s)
3729{
3730 while (STREAM_WRITEABLE(s)) {
3731 if (STREAM_WRITEABLE(s) == 1)
3732 break;
3733 uint32_t padding_len = STREAM_WRITEABLE(s) - 2;
3734
3735 if (padding_len > 255) {
3736 if (padding_len == 256)
3737 padding_len = 254;
3738 else
3739 padding_len = 255;
3740 }
3741
3742 stream_putc(s, ISIS_TLV_PADDING);
3743 stream_putc(s, padding_len);
3744 stream_put(s, NULL, padding_len);
3745 }
3746}
3747
3748#define LSP_REM_LIFETIME_OFF 10
3749#define LSP_CHECKSUM_OFF 24
3750static void safe_auth_md5(struct stream *s, uint16_t *checksum,
3751 uint16_t *rem_lifetime)
3752{
3753 memcpy(rem_lifetime, STREAM_DATA(s) + LSP_REM_LIFETIME_OFF,
3754 sizeof(*rem_lifetime));
3755 memset(STREAM_DATA(s) + LSP_REM_LIFETIME_OFF, 0, sizeof(*rem_lifetime));
3756 memcpy(checksum, STREAM_DATA(s) + LSP_CHECKSUM_OFF, sizeof(*checksum));
3757 memset(STREAM_DATA(s) + LSP_CHECKSUM_OFF, 0, sizeof(*checksum));
3758}
3759
3760static void restore_auth_md5(struct stream *s, uint16_t checksum,
3761 uint16_t rem_lifetime)
3762{
3763 memcpy(STREAM_DATA(s) + LSP_REM_LIFETIME_OFF, &rem_lifetime,
3764 sizeof(rem_lifetime));
3765 memcpy(STREAM_DATA(s) + LSP_CHECKSUM_OFF, &checksum, sizeof(checksum));
3766}
3767
3768static void update_auth_hmac_md5(struct isis_auth *auth, struct stream *s,
3769 bool is_lsp)
3770{
3771 uint8_t digest[16];
3772 uint16_t checksum, rem_lifetime;
3773
3774 if (is_lsp)
3775 safe_auth_md5(s, &checksum, &rem_lifetime);
3776
3777 memset(STREAM_DATA(s) + auth->offset, 0, 16);
6252100f
MR
3778#ifdef CRYPTO_OPENSSL
3779 uint8_t *result = (uint8_t *)HMAC(EVP_md5(), auth->passwd,
3780 auth->plength, STREAM_DATA(s),
3781 stream_get_endp(s), NULL, NULL);
3782
3783 memcpy(digest, result, 16);
3784#elif CRYPTO_INTERNAL
7ef5fefc
CF
3785 hmac_md5(STREAM_DATA(s), stream_get_endp(s), auth->passwd,
3786 auth->plength, digest);
6252100f 3787#endif
7ef5fefc
CF
3788 memcpy(auth->value, digest, 16);
3789 memcpy(STREAM_DATA(s) + auth->offset, digest, 16);
3790
3791 if (is_lsp)
3792 restore_auth_md5(s, checksum, rem_lifetime);
3793}
3794
3795static void update_auth(struct isis_tlvs *tlvs, struct stream *s, bool is_lsp)
3796{
3797 struct isis_auth *auth_head = (struct isis_auth *)tlvs->isis_auth.head;
3798
3799 for (struct isis_auth *auth = auth_head; auth; auth = auth->next) {
3800 if (auth->type == ISIS_PASSWD_TYPE_HMAC_MD5)
3801 update_auth_hmac_md5(auth, s, is_lsp);
3802 }
3803}
3804
2b64873d 3805static int handle_pack_entry(const struct pack_order_entry *pe,
7ef5fefc
CF
3806 struct isis_tlvs *tlvs, struct stream *stream,
3807 struct isis_tlvs **fragment_tlvs,
3808 struct isis_tlvs *(*new_fragment)(struct list *l),
3809 struct list *new_fragment_arg)
3810{
3811 int rv;
3812
3813 if (pe->how_to_pack == ISIS_ITEMS) {
3814 struct isis_item_list *l;
3815 l = (struct isis_item_list *)(((char *)tlvs)
3816 + pe->what_to_pack);
3817 rv = pack_items(pe->context, pe->type, l, stream, fragment_tlvs,
3818 pe, new_fragment, new_fragment_arg);
3819 } else {
3820 struct isis_mt_item_list *l;
3821 l = (struct isis_mt_item_list *)(((char *)tlvs)
3822 + pe->what_to_pack);
3823 rv = pack_mt_items(pe->context, pe->type, l, stream,
3824 fragment_tlvs, pe, new_fragment,
3825 new_fragment_arg);
3826 }
3827
3828 return rv;
3829}
3830
3831static int pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
3832 struct isis_tlvs *fragment_tlvs,
3833 struct isis_tlvs *(*new_fragment)(struct list *l),
3834 struct list *new_fragment_arg)
3835{
3836 int rv;
3837
3838 /* When fragmenting, don't add auth as it's already accounted for in the
3839 * size we are given. */
3840 if (!fragment_tlvs) {
996c9314
LB
3841 rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH,
3842 &tlvs->isis_auth, stream, NULL, NULL, NULL,
3843 NULL);
7ef5fefc
CF
3844 if (rv)
3845 return rv;
3846 }
3847
5f77d901
CF
3848 rv = pack_tlv_purge_originator(tlvs->purge_originator, stream);
3849 if (rv)
3850 return rv;
3851 if (fragment_tlvs) {
3852 fragment_tlvs->purge_originator =
3853 copy_tlv_purge_originator(tlvs->purge_originator);
3854 }
3855
7ef5fefc
CF
3856 rv = pack_tlv_protocols_supported(&tlvs->protocols_supported, stream);
3857 if (rv)
3858 return rv;
3859 if (fragment_tlvs) {
3860 copy_tlv_protocols_supported(
3861 &tlvs->protocols_supported,
3862 &fragment_tlvs->protocols_supported);
3863 }
3864
3865 rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
3866 &tlvs->area_addresses, stream, NULL, NULL, NULL, NULL);
3867 if (rv)
3868 return rv;
3869 if (fragment_tlvs) {
3870 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
3871 &tlvs->area_addresses,
3872 &fragment_tlvs->area_addresses);
3873 }
3874
3875
3876 if (tlvs->mt_router_info_empty) {
3877 if (STREAM_WRITEABLE(stream) < 2)
3878 return 1;
3879 stream_putc(stream, ISIS_TLV_MT_ROUTER_INFO);
3880 stream_putc(stream, 0);
3881 if (fragment_tlvs)
3882 fragment_tlvs->mt_router_info_empty = true;
3883 } else {
3884 rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
3885 &tlvs->mt_router_info, stream, NULL, NULL, NULL,
3886 NULL);
3887 if (rv)
3888 return rv;
3889 if (fragment_tlvs) {
3890 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
3891 &tlvs->mt_router_info,
3892 &fragment_tlvs->mt_router_info);
3893 }
3894 }
3895
3896 rv = pack_tlv_dynamic_hostname(tlvs->hostname, stream);
3897 if (rv)
3898 return rv;
3899 if (fragment_tlvs)
3900 fragment_tlvs->hostname =
3901 copy_tlv_dynamic_hostname(tlvs->hostname);
3902
1b3f47d0
OD
3903 rv = pack_tlv_router_cap(tlvs->router_cap, stream);
3904 if (rv)
3905 return rv;
3906 if (fragment_tlvs) {
3907 fragment_tlvs->router_cap =
3908 copy_tlv_router_cap(tlvs->router_cap);
3909 }
3910
7ef5fefc
CF
3911 rv = pack_tlv_te_router_id(tlvs->te_router_id, stream);
3912 if (rv)
3913 return rv;
3914 if (fragment_tlvs) {
3915 fragment_tlvs->te_router_id =
3916 copy_tlv_te_router_id(tlvs->te_router_id);
3917 }
3918
9fe21208
CF
3919 rv = pack_tlv_threeway_adj(tlvs->threeway_adj, stream);
3920 if (rv)
3921 return rv;
3922 if (fragment_tlvs) {
3923 fragment_tlvs->threeway_adj =
3924 copy_tlv_threeway_adj(tlvs->threeway_adj);
3925 }
3926
41a145f1
CF
3927 rv = pack_tlv_spine_leaf(tlvs->spine_leaf, stream);
3928 if (rv)
3929 return rv;
3930 if (fragment_tlvs) {
3931 fragment_tlvs->spine_leaf =
3932 copy_tlv_spine_leaf(tlvs->spine_leaf);
3933 }
3934
7ef5fefc
CF
3935 for (size_t pack_idx = 0; pack_idx < array_size(pack_order);
3936 pack_idx++) {
3937 rv = handle_pack_entry(&pack_order[pack_idx], tlvs, stream,
3938 fragment_tlvs ? &fragment_tlvs : NULL,
3939 new_fragment, new_fragment_arg);
3940
3941 if (rv)
3942 return rv;
3943 }
3944
3945 return 0;
3946}
3947
3948int isis_pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
3949 size_t len_pointer, bool pad, bool is_lsp)
3950{
3951 int rv;
3952
3953 rv = pack_tlvs(tlvs, stream, NULL, NULL, NULL);
3954 if (rv)
3955 return rv;
3956
3957 if (pad)
3958 add_padding(stream);
3959
3960 if (len_pointer != (size_t)-1) {
3961 stream_putw_at(stream, len_pointer, stream_get_endp(stream));
3962 }
3963
3964 update_auth(tlvs, stream, is_lsp);
3965
3966 return 0;
3967}
3968
3969static struct isis_tlvs *new_fragment(struct list *l)
3970{
3971 struct isis_tlvs *rv = isis_alloc_tlvs();
3972
3973 listnode_add(l, rv);
3974 return rv;
3975}
3976
3977struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size)
3978{
3979 struct stream *dummy_stream = stream_new(size);
3980 struct list *rv = list_new();
3981 struct isis_tlvs *fragment_tlvs = new_fragment(rv);
3982
3983 if (pack_tlvs(tlvs, dummy_stream, fragment_tlvs, new_fragment, rv)) {
3984 struct listnode *node;
3985 for (ALL_LIST_ELEMENTS_RO(rv, node, fragment_tlvs))
3986 isis_free_tlvs(fragment_tlvs);
6a154c88 3987 list_delete(&rv);
7ef5fefc
CF
3988 }
3989
3990 stream_free(dummy_stream);
3991 return rv;
3992}
3993
3994static int unpack_tlv_unknown(enum isis_tlv_context context, uint8_t tlv_type,
3995 uint8_t tlv_len, struct stream *s,
3996 struct sbuf *log, int indent)
3997{
3998 stream_forward_getp(s, tlv_len);
3999 sbuf_push(log, indent,
6cde4b45 4000 "Skipping unknown TLV %hhu (%hhu bytes)\n",
7ef5fefc
CF
4001 tlv_type, tlv_len);
4002 return 0;
4003}
4004
4005static int unpack_tlv(enum isis_tlv_context context, size_t avail_len,
4006 struct stream *stream, struct sbuf *log, void *dest,
bf555bf0 4007 int indent, bool *unpacked_known_tlvs)
7ef5fefc
CF
4008{
4009 uint8_t tlv_type, tlv_len;
4010 const struct tlv_ops *ops;
4011
4012 sbuf_push(log, indent, "Unpacking TLV...\n");
4013
4014 if (avail_len < 2) {
4015 sbuf_push(
4016 log, indent + 2,
4017 "Available data %zu too short to contain a TLV header.\n",
4018 avail_len);
4019 return 1;
4020 }
4021
4022 tlv_type = stream_getc(stream);
4023 tlv_len = stream_getc(stream);
4024
4025 sbuf_push(log, indent + 2,
6cde4b45 4026 "Found TLV of type %hhu and len %hhu.\n",
7ef5fefc
CF
4027 tlv_type, tlv_len);
4028
4029 if (avail_len < ((size_t)tlv_len) + 2) {
98c5bc15 4030 sbuf_push(log, indent + 2,
6cde4b45 4031 "Available data %zu too short for claimed TLV len %hhu.\n",
98c5bc15 4032 avail_len - 2, tlv_len);
7ef5fefc
CF
4033 return 1;
4034 }
4035
4036 ops = tlv_table[context][tlv_type];
4037 if (ops && ops->unpack) {
bf555bf0
CF
4038 if (unpacked_known_tlvs)
4039 *unpacked_known_tlvs = true;
7ef5fefc
CF
4040 return ops->unpack(context, tlv_type, tlv_len, stream, log,
4041 dest, indent + 2);
4042 }
4043
4044 return unpack_tlv_unknown(context, tlv_type, tlv_len, stream, log,
4045 indent + 2);
4046}
4047
4048static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len,
4049 struct stream *stream, struct sbuf *log, void *dest,
bf555bf0 4050 int indent, bool *unpacked_known_tlvs)
7ef5fefc
CF
4051{
4052 int rv;
4053 size_t tlv_start, tlv_pos;
4054
4055 tlv_start = stream_get_getp(stream);
4056 tlv_pos = 0;
4057
4058 sbuf_push(log, indent, "Unpacking %zu bytes of %s...\n", avail_len,
4059 (context == ISIS_CONTEXT_LSP) ? "TLVs" : "sub-TLVs");
4060
4061 while (tlv_pos < avail_len) {
4062 rv = unpack_tlv(context, avail_len - tlv_pos, stream, log, dest,
bf555bf0 4063 indent + 2, unpacked_known_tlvs);
7ef5fefc
CF
4064 if (rv)
4065 return rv;
4066
4067 tlv_pos = stream_get_getp(stream) - tlv_start;
4068 }
4069
4070 return 0;
4071}
4072
4073int isis_unpack_tlvs(size_t avail_len, struct stream *stream,
4074 struct isis_tlvs **dest, const char **log)
4075{
4076 static struct sbuf logbuf;
4077 int indent = 0;
4078 int rv;
4079 struct isis_tlvs *result;
4080
4081 if (!sbuf_buf(&logbuf))
4082 sbuf_init(&logbuf, NULL, 0);
4083
4084 sbuf_reset(&logbuf);
4085 if (avail_len > STREAM_READABLE(stream)) {
4086 sbuf_push(&logbuf, indent,
3efd0893 4087 "Stream doesn't contain sufficient data. Claimed %zu, available %zu\n",
7ef5fefc
CF
4088 avail_len, STREAM_READABLE(stream));
4089 return 1;
4090 }
4091
4092 result = isis_alloc_tlvs();
4093 rv = unpack_tlvs(ISIS_CONTEXT_LSP, avail_len, stream, &logbuf, result,
bf555bf0 4094 indent, NULL);
7ef5fefc
CF
4095
4096 *log = sbuf_buf(&logbuf);
4097 *dest = result;
4098
4099 return rv;
4100}
4101
4102#define TLV_OPS(_name_, _desc_) \
4103 static const struct tlv_ops tlv_##_name_##_ops = { \
4104 .name = _desc_, .unpack = unpack_tlv_##_name_, \
4105 }
4106
4107#define ITEM_TLV_OPS(_name_, _desc_) \
4108 static const struct tlv_ops tlv_##_name_##_ops = { \
4109 .name = _desc_, \
4110 .unpack = unpack_tlv_with_items, \
98c5bc15 4111 \
7ef5fefc
CF
4112 .pack_item = pack_item_##_name_, \
4113 .free_item = free_item_##_name_, \
4114 .unpack_item = unpack_item_##_name_, \
4115 .format_item = format_item_##_name_, \
4116 .copy_item = copy_item_##_name_}
4117
4118#define SUBTLV_OPS(_name_, _desc_) \
4119 static const struct tlv_ops subtlv_##_name_##_ops = { \
4120 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
4121 }
4122
bd507085
CF
4123#define ITEM_SUBTLV_OPS(_name_, _desc_) \
4124 ITEM_TLV_OPS(_name_, _desc_)
4125
7ef5fefc
CF
4126ITEM_TLV_OPS(area_address, "TLV 1 Area Addresses");
4127ITEM_TLV_OPS(oldstyle_reach, "TLV 2 IS Reachability");
4128ITEM_TLV_OPS(lan_neighbor, "TLV 6 LAN Neighbors");
4129ITEM_TLV_OPS(lsp_entry, "TLV 9 LSP Entries");
4130ITEM_TLV_OPS(auth, "TLV 10 IS-IS Auth");
5f77d901 4131TLV_OPS(purge_originator, "TLV 13 Purge Originator Identification");
7ef5fefc
CF
4132ITEM_TLV_OPS(extended_reach, "TLV 22 Extended Reachability");
4133ITEM_TLV_OPS(oldstyle_ip_reach, "TLV 128/130 IP Reachability");
4134TLV_OPS(protocols_supported, "TLV 129 Protocols Supported");
4135ITEM_TLV_OPS(ipv4_address, "TLV 132 IPv4 Interface Address");
4136TLV_OPS(te_router_id, "TLV 134 TE Router ID");
4137ITEM_TLV_OPS(extended_ip_reach, "TLV 135 Extended IP Reachability");
4138TLV_OPS(dynamic_hostname, "TLV 137 Dynamic Hostname");
41a145f1 4139TLV_OPS(spine_leaf, "TLV 150 Spine Leaf Extensions");
7ef5fefc 4140ITEM_TLV_OPS(mt_router_info, "TLV 229 MT Router Information");
9fe21208 4141TLV_OPS(threeway_adj, "TLV 240 P2P Three-Way Adjacency");
7ef5fefc
CF
4142ITEM_TLV_OPS(ipv6_address, "TLV 232 IPv6 Interface Address");
4143ITEM_TLV_OPS(ipv6_reach, "TLV 236 IPv6 Reachability");
1b3f47d0 4144TLV_OPS(router_cap, "TLV 242 Router Capability");
7ef5fefc 4145
bd507085 4146ITEM_SUBTLV_OPS(prefix_sid, "Sub-TLV 3 SR Prefix-SID");
7ef5fefc
CF
4147SUBTLV_OPS(ipv6_source_prefix, "Sub-TLV 22 IPv6 Source Prefix");
4148
2b64873d 4149static const struct tlv_ops *const tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
98c5bc15
CF
4150 [ISIS_CONTEXT_LSP] = {
4151 [ISIS_TLV_AREA_ADDRESSES] = &tlv_area_address_ops,
4152 [ISIS_TLV_OLDSTYLE_REACH] = &tlv_oldstyle_reach_ops,
4153 [ISIS_TLV_LAN_NEIGHBORS] = &tlv_lan_neighbor_ops,
4154 [ISIS_TLV_LSP_ENTRY] = &tlv_lsp_entry_ops,
4155 [ISIS_TLV_AUTH] = &tlv_auth_ops,
5f77d901 4156 [ISIS_TLV_PURGE_ORIGINATOR] = &tlv_purge_originator_ops,
98c5bc15 4157 [ISIS_TLV_EXTENDED_REACH] = &tlv_extended_reach_ops,
98c5bc15
CF
4158 [ISIS_TLV_OLDSTYLE_IP_REACH] = &tlv_oldstyle_ip_reach_ops,
4159 [ISIS_TLV_PROTOCOLS_SUPPORTED] = &tlv_protocols_supported_ops,
4160 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT] = &tlv_oldstyle_ip_reach_ops,
4161 [ISIS_TLV_IPV4_ADDRESS] = &tlv_ipv4_address_ops,
4162 [ISIS_TLV_TE_ROUTER_ID] = &tlv_te_router_id_ops,
4163 [ISIS_TLV_EXTENDED_IP_REACH] = &tlv_extended_ip_reach_ops,
98c5bc15 4164 [ISIS_TLV_DYNAMIC_HOSTNAME] = &tlv_dynamic_hostname_ops,
41a145f1 4165 [ISIS_TLV_SPINE_LEAF_EXT] = &tlv_spine_leaf_ops,
1b3f47d0 4166 [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops,
98c5bc15
CF
4167 [ISIS_TLV_MT_ROUTER_INFO] = &tlv_mt_router_info_ops,
4168 [ISIS_TLV_IPV6_ADDRESS] = &tlv_ipv6_address_ops,
1b3f47d0 4169 [ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops,
98c5bc15
CF
4170 [ISIS_TLV_IPV6_REACH] = &tlv_ipv6_reach_ops,
4171 [ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops,
1b3f47d0
OD
4172 [ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops,
4173 [ISIS_TLV_ROUTER_CAPABILITY] = &tlv_router_cap_ops,
98c5bc15 4174 },
3e300703 4175 [ISIS_CONTEXT_SUBTLV_NE_REACH] = {},
bd507085
CF
4176 [ISIS_CONTEXT_SUBTLV_IP_REACH] = {
4177 [ISIS_SUBTLV_PREFIX_SID] = &tlv_prefix_sid_ops,
4178 },
98c5bc15 4179 [ISIS_CONTEXT_SUBTLV_IPV6_REACH] = {
bd507085 4180 [ISIS_SUBTLV_PREFIX_SID] = &tlv_prefix_sid_ops,
98c5bc15
CF
4181 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX] = &subtlv_ipv6_source_prefix_ops,
4182 }
4183};
7ef5fefc
CF
4184
4185/* Accessor functions */
4186
4187void isis_tlvs_add_auth(struct isis_tlvs *tlvs, struct isis_passwd *passwd)
4188{
4189 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth);
4190 init_item_list(&tlvs->isis_auth);
4191
4192 if (passwd->type == ISIS_PASSWD_TYPE_UNUSED)
4193 return;
4194
841791b6 4195 struct isis_auth *auth = XCALLOC(MTYPE_ISIS_TLV, sizeof(*auth));
7ef5fefc
CF
4196
4197 auth->type = passwd->type;
4198
4199 auth->plength = passwd->len;
4200 memcpy(auth->passwd, passwd->passwd,
4201 MIN(sizeof(auth->passwd), sizeof(passwd->passwd)));
4202
4203 if (auth->type == ISIS_PASSWD_TYPE_CLEARTXT) {
4204 auth->length = passwd->len;
4205 memcpy(auth->value, passwd->passwd,
4206 MIN(sizeof(auth->value), sizeof(passwd->passwd)));
4207 }
4208
4209 append_item(&tlvs->isis_auth, (struct isis_item *)auth);
4210}
4211
4212void isis_tlvs_add_area_addresses(struct isis_tlvs *tlvs,
4213 struct list *addresses)
4214{
4215 struct listnode *node;
4216 struct area_addr *area_addr;
4217
4218 for (ALL_LIST_ELEMENTS_RO(addresses, node, area_addr)) {
4219 struct isis_area_address *a =
841791b6 4220 XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
7ef5fefc
CF
4221
4222 a->len = area_addr->addr_len;
4223 memcpy(a->addr, area_addr->area_addr, 20);
4224 append_item(&tlvs->area_addresses, (struct isis_item *)a);
4225 }
4226}
4227
4228void isis_tlvs_add_lan_neighbors(struct isis_tlvs *tlvs, struct list *neighbors)
4229{
4230 struct listnode *node;
d7c0a89a 4231 uint8_t *snpa;
7ef5fefc
CF
4232
4233 for (ALL_LIST_ELEMENTS_RO(neighbors, node, snpa)) {
4234 struct isis_lan_neighbor *n =
841791b6 4235 XCALLOC(MTYPE_ISIS_TLV, sizeof(*n));
7ef5fefc
CF
4236
4237 memcpy(n->mac, snpa, 6);
4238 append_item(&tlvs->lan_neighbor, (struct isis_item *)n);
4239 }
4240}
4241
4242void isis_tlvs_set_protocols_supported(struct isis_tlvs *tlvs,
4243 struct nlpids *nlpids)
4244{
4245 tlvs->protocols_supported.count = nlpids->count;
0a22ddfb 4246 XFREE(MTYPE_ISIS_TLV, tlvs->protocols_supported.protocols);
7ef5fefc
CF
4247 if (nlpids->count) {
4248 tlvs->protocols_supported.protocols =
841791b6 4249 XCALLOC(MTYPE_ISIS_TLV, nlpids->count);
7ef5fefc
CF
4250 memcpy(tlvs->protocols_supported.protocols, nlpids->nlpids,
4251 nlpids->count);
4252 } else {
4253 tlvs->protocols_supported.protocols = NULL;
4254 }
4255}
4256
4257void isis_tlvs_add_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid,
4258 bool overload, bool attached)
4259{
841791b6 4260 struct isis_mt_router_info *i = XCALLOC(MTYPE_ISIS_TLV, sizeof(*i));
7ef5fefc
CF
4261
4262 i->overload = overload;
4263 i->attached = attached;
4264 i->mtid = mtid;
4265 append_item(&tlvs->mt_router_info, (struct isis_item *)i);
4266}
4267
4268void isis_tlvs_add_ipv4_address(struct isis_tlvs *tlvs, struct in_addr *addr)
4269{
841791b6 4270 struct isis_ipv4_address *a = XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
7ef5fefc
CF
4271 a->addr = *addr;
4272 append_item(&tlvs->ipv4_address, (struct isis_item *)a);
4273}
4274
4275
4276void isis_tlvs_add_ipv4_addresses(struct isis_tlvs *tlvs,
4277 struct list *addresses)
4278{
4279 struct listnode *node;
4280 struct prefix_ipv4 *ip_addr;
bb5c77d7 4281 unsigned int addr_count = 0;
7ef5fefc 4282
bb5c77d7 4283 for (ALL_LIST_ELEMENTS_RO(addresses, node, ip_addr)) {
7ef5fefc 4284 isis_tlvs_add_ipv4_address(tlvs, &ip_addr->prefix);
bb5c77d7
CF
4285 addr_count++;
4286 if (addr_count >= 63)
4287 break;
4288 }
7ef5fefc
CF
4289}
4290
4291void isis_tlvs_add_ipv6_addresses(struct isis_tlvs *tlvs,
4292 struct list *addresses)
4293{
4294 struct listnode *node;
4295 struct prefix_ipv6 *ip_addr;
1f8286c9 4296 unsigned int addr_count = 0;
7ef5fefc
CF
4297
4298 for (ALL_LIST_ELEMENTS_RO(addresses, node, ip_addr)) {
1f8286c9
DS
4299 if (addr_count >= 15)
4300 break;
4301
7ef5fefc 4302 struct isis_ipv6_address *a =
841791b6 4303 XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
7ef5fefc
CF
4304
4305 a->addr = ip_addr->prefix;
4306 append_item(&tlvs->ipv6_address, (struct isis_item *)a);
1f8286c9 4307 addr_count++;
7ef5fefc
CF
4308 }
4309}
4310
4311typedef bool (*auth_validator_func)(struct isis_passwd *passwd,
4312 struct stream *stream,
4313 struct isis_auth *auth, bool is_lsp);
4314
4315static bool auth_validator_cleartxt(struct isis_passwd *passwd,
4316 struct stream *stream,
4317 struct isis_auth *auth, bool is_lsp)
4318{
4319 return (auth->length == passwd->len
4320 && !memcmp(auth->value, passwd->passwd, passwd->len));
4321}
4322
4323static bool auth_validator_hmac_md5(struct isis_passwd *passwd,
4324 struct stream *stream,
4325 struct isis_auth *auth, bool is_lsp)
4326{
4327 uint8_t digest[16];
4328 uint16_t checksum;
4329 uint16_t rem_lifetime;
4330
4331 if (is_lsp)
4332 safe_auth_md5(stream, &checksum, &rem_lifetime);
4333
4334 memset(STREAM_DATA(stream) + auth->offset, 0, 16);
6252100f
MR
4335#ifdef CRYPTO_OPENSSL
4336 uint8_t *result = (uint8_t *)HMAC(EVP_md5(), passwd->passwd,
4337 passwd->len, STREAM_DATA(stream),
4338 stream_get_endp(stream), NULL, NULL);
4339
4340 memcpy(digest, result, 16);
4341#elif CRYPTO_INTERNAL
7ef5fefc
CF
4342 hmac_md5(STREAM_DATA(stream), stream_get_endp(stream), passwd->passwd,
4343 passwd->len, digest);
6252100f 4344#endif
7ef5fefc
CF
4345 memcpy(STREAM_DATA(stream) + auth->offset, auth->value, 16);
4346
4347 bool rv = !memcmp(digest, auth->value, 16);
4348
4349 if (is_lsp)
4350 restore_auth_md5(stream, checksum, rem_lifetime);
4351
4352 return rv;
4353}
4354
4355static const auth_validator_func auth_validators[] = {
4356 [ISIS_PASSWD_TYPE_CLEARTXT] = auth_validator_cleartxt,
4357 [ISIS_PASSWD_TYPE_HMAC_MD5] = auth_validator_hmac_md5,
4358};
4359
3380c990
EDP
4360int isis_tlvs_auth_is_valid(struct isis_tlvs *tlvs, struct isis_passwd *passwd,
4361 struct stream *stream, bool is_lsp)
7ef5fefc
CF
4362{
4363 /* If no auth is set, always pass authentication */
4364 if (!passwd->type)
3380c990 4365 return ISIS_AUTH_OK;
7ef5fefc
CF
4366
4367 /* If we don't known how to validate the auth, return invalid */
4368 if (passwd->type >= array_size(auth_validators)
4369 || !auth_validators[passwd->type])
3380c990 4370 return ISIS_AUTH_NO_VALIDATOR;
7ef5fefc
CF
4371
4372 struct isis_auth *auth_head = (struct isis_auth *)tlvs->isis_auth.head;
4373 struct isis_auth *auth;
4374 for (auth = auth_head; auth; auth = auth->next) {
4375 if (auth->type == passwd->type)
4376 break;
4377 }
4378
4379 /* If matching auth TLV could not be found, return invalid */
4380 if (!auth)
3380c990
EDP
4381 return ISIS_AUTH_TYPE_FAILURE;
4382
7ef5fefc
CF
4383
4384 /* Perform validation and return result */
3380c990
EDP
4385 if (auth_validators[passwd->type](passwd, stream, auth, is_lsp))
4386 return ISIS_AUTH_OK;
4387 else
4388 return ISIS_AUTH_FAILURE;
7ef5fefc
CF
4389}
4390
4391bool isis_tlvs_area_addresses_match(struct isis_tlvs *tlvs,
4392 struct list *addresses)
4393{
4394 struct isis_area_address *addr_head;
4395
4396 addr_head = (struct isis_area_address *)tlvs->area_addresses.head;
4397 for (struct isis_area_address *addr = addr_head; addr;
4398 addr = addr->next) {
4399 struct listnode *node;
4400 struct area_addr *a;
4401
4402 for (ALL_LIST_ELEMENTS_RO(addresses, node, a)) {
4403 if (a->addr_len == addr->len
4404 && !memcmp(a->area_addr, addr->addr, addr->len))
4405 return true;
4406 }
4407 }
4408
4409 return false;
4410}
4411
4412static void tlvs_area_addresses_to_adj(struct isis_tlvs *tlvs,
4413 struct isis_adjacency *adj,
4414 bool *changed)
4415{
4416 if (adj->area_address_count != tlvs->area_addresses.count) {
033c6d28
DS
4417 uint32_t oc = adj->area_address_count;
4418
7ef5fefc
CF
4419 *changed = true;
4420 adj->area_address_count = tlvs->area_addresses.count;
4421 adj->area_addresses = XREALLOC(
4422 MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses,
4423 adj->area_address_count * sizeof(*adj->area_addresses));
033c6d28
DS
4424
4425 for (; oc < adj->area_address_count; oc++) {
4426 adj->area_addresses[oc].addr_len = 0;
4427 memset(&adj->area_addresses[oc].area_addr, 0,
4428 sizeof(adj->area_addresses[oc].area_addr));
4429 }
7ef5fefc
CF
4430 }
4431
4432 struct isis_area_address *addr = NULL;
4433 for (unsigned int i = 0; i < tlvs->area_addresses.count; i++) {
4434 if (!addr)
4435 addr = (struct isis_area_address *)
4436 tlvs->area_addresses.head;
4437 else
4438 addr = addr->next;
4439
4440 if (adj->area_addresses[i].addr_len == addr->len
4441 && !memcmp(adj->area_addresses[i].area_addr, addr->addr,
4442 addr->len)) {
4443 continue;
4444 }
4445
4446 *changed = true;
4447 adj->area_addresses[i].addr_len = addr->len;
4448 memcpy(adj->area_addresses[i].area_addr, addr->addr, addr->len);
4449 }
4450}
4451
4452static void tlvs_protocols_supported_to_adj(struct isis_tlvs *tlvs,
4453 struct isis_adjacency *adj,
4454 bool *changed)
4455{
4456 bool ipv4_supported = false, ipv6_supported = false;
4457
4458 for (uint8_t i = 0; i < tlvs->protocols_supported.count; i++) {
4459 if (tlvs->protocols_supported.protocols[i] == NLPID_IP)
4460 ipv4_supported = true;
4461 if (tlvs->protocols_supported.protocols[i] == NLPID_IPV6)
4462 ipv6_supported = true;
4463 }
4464
3e300703 4465 struct nlpids reduced = {};
7ef5fefc
CF
4466
4467 if (ipv4_supported && ipv6_supported) {
4468 reduced.count = 2;
4469 reduced.nlpids[0] = NLPID_IP;
4470 reduced.nlpids[1] = NLPID_IPV6;
4471 } else if (ipv4_supported) {
4472 reduced.count = 1;
4473 reduced.nlpids[0] = NLPID_IP;
4474 } else if (ipv6_supported) {
4475 reduced.count = 1;
4773e4f8 4476 reduced.nlpids[0] = NLPID_IPV6;
7ef5fefc
CF
4477 } else {
4478 reduced.count = 0;
4479 }
4480
4481 if (adj->nlpids.count == reduced.count
4482 && !memcmp(adj->nlpids.nlpids, reduced.nlpids, reduced.count))
4483 return;
4484
4485 *changed = true;
4486 adj->nlpids.count = reduced.count;
4487 memcpy(adj->nlpids.nlpids, reduced.nlpids, reduced.count);
4488}
4489
30563683
RW
4490DEFINE_HOOK(isis_adj_ip_enabled_hook, (struct isis_adjacency *adj, int family),
4491 (adj, family))
4492DEFINE_HOOK(isis_adj_ip_disabled_hook,
4493 (struct isis_adjacency *adj, int family), (adj, family))
4494
7ef5fefc
CF
4495static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs *tlvs,
4496 struct isis_adjacency *adj,
4497 bool *changed)
4498{
30563683
RW
4499 bool ipv4_enabled = false;
4500
4501 if (adj->ipv4_address_count == 0 && tlvs->ipv4_address.count > 0)
4502 ipv4_enabled = true;
4503 else if (adj->ipv4_address_count > 0 && tlvs->ipv4_address.count == 0)
4504 hook_call(isis_adj_ip_disabled_hook, adj, AF_INET);
4505
7ef5fefc 4506 if (adj->ipv4_address_count != tlvs->ipv4_address.count) {
033c6d28
DS
4507 uint32_t oc = adj->ipv4_address_count;
4508
7ef5fefc
CF
4509 *changed = true;
4510 adj->ipv4_address_count = tlvs->ipv4_address.count;
4511 adj->ipv4_addresses = XREALLOC(
4512 MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses,
4513 adj->ipv4_address_count * sizeof(*adj->ipv4_addresses));
033c6d28
DS
4514
4515 for (; oc < adj->ipv4_address_count; oc++) {
4516 memset(&adj->ipv4_addresses[oc], 0,
4517 sizeof(adj->ipv4_addresses[oc]));
4518 }
7ef5fefc
CF
4519 }
4520
4521 struct isis_ipv4_address *addr = NULL;
4522 for (unsigned int i = 0; i < tlvs->ipv4_address.count; i++) {
4523 if (!addr)
4524 addr = (struct isis_ipv4_address *)
4525 tlvs->ipv4_address.head;
4526 else
4527 addr = addr->next;
4528
4529 if (!memcmp(&adj->ipv4_addresses[i], &addr->addr,
4530 sizeof(addr->addr)))
4531 continue;
4532
4533 *changed = true;
4534 adj->ipv4_addresses[i] = addr->addr;
4535 }
30563683
RW
4536
4537 if (ipv4_enabled)
4538 hook_call(isis_adj_ip_enabled_hook, adj, AF_INET);
7ef5fefc
CF
4539}
4540
4541static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs *tlvs,
4542 struct isis_adjacency *adj,
4543 bool *changed)
4544{
30563683
RW
4545 bool ipv6_enabled = false;
4546
4547 if (adj->ipv6_address_count == 0 && tlvs->ipv6_address.count > 0)
4548 ipv6_enabled = true;
4549 else if (adj->ipv6_address_count > 0 && tlvs->ipv6_address.count == 0)
4550 hook_call(isis_adj_ip_disabled_hook, adj, AF_INET6);
4551
7ef5fefc 4552 if (adj->ipv6_address_count != tlvs->ipv6_address.count) {
033c6d28
DS
4553 uint32_t oc = adj->ipv6_address_count;
4554
7ef5fefc
CF
4555 *changed = true;
4556 adj->ipv6_address_count = tlvs->ipv6_address.count;
4557 adj->ipv6_addresses = XREALLOC(
4558 MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses,
4559 adj->ipv6_address_count * sizeof(*adj->ipv6_addresses));
033c6d28
DS
4560
4561 for (; oc < adj->ipv6_address_count; oc++) {
4562 memset(&adj->ipv6_addresses[oc], 0,
4563 sizeof(adj->ipv6_addresses[oc]));
4564 }
7ef5fefc
CF
4565 }
4566
4567 struct isis_ipv6_address *addr = NULL;
4568 for (unsigned int i = 0; i < tlvs->ipv6_address.count; i++) {
4569 if (!addr)
4570 addr = (struct isis_ipv6_address *)
4571 tlvs->ipv6_address.head;
4572 else
4573 addr = addr->next;
4574
4575 if (!memcmp(&adj->ipv6_addresses[i], &addr->addr,
4576 sizeof(addr->addr)))
4577 continue;
4578
4579 *changed = true;
4580 adj->ipv6_addresses[i] = addr->addr;
4581 }
30563683
RW
4582
4583 if (ipv6_enabled)
4584 hook_call(isis_adj_ip_enabled_hook, adj, AF_INET6);
7ef5fefc
CF
4585}
4586
4587void isis_tlvs_to_adj(struct isis_tlvs *tlvs, struct isis_adjacency *adj,
4588 bool *changed)
4589{
4590 *changed = false;
4591
4592 tlvs_area_addresses_to_adj(tlvs, adj, changed);
4593 tlvs_protocols_supported_to_adj(tlvs, adj, changed);
4594 tlvs_ipv4_addresses_to_adj(tlvs, adj, changed);
4595 tlvs_ipv6_addresses_to_adj(tlvs, adj, changed);
4596}
4597
4598bool isis_tlvs_own_snpa_found(struct isis_tlvs *tlvs, uint8_t *snpa)
4599{
4600 struct isis_lan_neighbor *ne_head;
4601
4602 ne_head = (struct isis_lan_neighbor *)tlvs->lan_neighbor.head;
4603 for (struct isis_lan_neighbor *ne = ne_head; ne; ne = ne->next) {
4604 if (!memcmp(ne->mac, snpa, ETH_ALEN))
4605 return true;
4606 }
4607
4608 return false;
4609}
4610
4611void isis_tlvs_add_lsp_entry(struct isis_tlvs *tlvs, struct isis_lsp *lsp)
4612{
841791b6 4613 struct isis_lsp_entry *entry = XCALLOC(MTYPE_ISIS_TLV, sizeof(*entry));
7ef5fefc
CF
4614
4615 entry->rem_lifetime = lsp->hdr.rem_lifetime;
4616 memcpy(entry->id, lsp->hdr.lsp_id, ISIS_SYS_ID_LEN + 2);
4617 entry->checksum = lsp->hdr.checksum;
4618 entry->seqno = lsp->hdr.seqno;
4619 entry->lsp = lsp;
4620
4621 append_item(&tlvs->lsp_entries, (struct isis_item *)entry);
4622}
4623
4624void isis_tlvs_add_csnp_entries(struct isis_tlvs *tlvs, uint8_t *start_id,
4625 uint8_t *stop_id, uint16_t num_lsps,
4bef0ec4
DL
4626 struct lspdb_head *head,
4627 struct isis_lsp **last_lsp)
7ef5fefc 4628{
4bef0ec4
DL
4629 struct isis_lsp searchfor;
4630 struct isis_lsp *first, *lsp;
4631
4632 memcpy(&searchfor.hdr.lsp_id, start_id, sizeof(searchfor.hdr.lsp_id));
4633 first = lspdb_find_gteq(head, &searchfor);
7ef5fefc
CF
4634 if (!first)
4635 return;
4636
81fddbe7 4637 frr_each_from (lspdb, head, lsp, first) {
4bef0ec4
DL
4638 if (memcmp(lsp->hdr.lsp_id, stop_id, sizeof(lsp->hdr.lsp_id))
4639 > 0 || tlvs->lsp_entries.count == num_lsps)
7ef5fefc 4640 break;
4bef0ec4
DL
4641
4642 isis_tlvs_add_lsp_entry(tlvs, lsp);
4643 *last_lsp = lsp;
7ef5fefc
CF
4644 }
4645}
4646
4647void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs,
4648 const char *hostname)
4649{
841791b6 4650 XFREE(MTYPE_ISIS_TLV, tlvs->hostname);
7ef5fefc 4651 if (hostname)
841791b6 4652 tlvs->hostname = XSTRDUP(MTYPE_ISIS_TLV, hostname);
7ef5fefc
CF
4653}
4654
1b3f47d0
OD
4655/* Set Router Capability TLV parameters */
4656void isis_tlvs_set_router_capability(struct isis_tlvs *tlvs,
4657 const struct isis_router_cap *cap)
4658{
4659 XFREE(MTYPE_ISIS_TLV, tlvs->router_cap);
4660 if (!cap)
4661 return;
4662
4663 tlvs->router_cap = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->router_cap));
4664 *tlvs->router_cap = *cap;
4665}
4666
7ef5fefc
CF
4667void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs,
4668 const struct in_addr *id)
4669{
841791b6 4670 XFREE(MTYPE_ISIS_TLV, tlvs->te_router_id);
7ef5fefc
CF
4671 if (!id)
4672 return;
841791b6 4673 tlvs->te_router_id = XCALLOC(MTYPE_ISIS_TLV, sizeof(*id));
7ef5fefc
CF
4674 memcpy(tlvs->te_router_id, id, sizeof(*id));
4675}
4676
4677void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs,
4678 struct prefix_ipv4 *dest, uint8_t metric)
4679{
841791b6 4680 struct isis_oldstyle_ip_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
7ef5fefc
CF
4681
4682 r->metric = metric;
4683 memcpy(&r->prefix, dest, sizeof(*dest));
4684 apply_mask_ipv4(&r->prefix);
4685 append_item(&tlvs->oldstyle_ip_reach, (struct isis_item *)r);
4686}
4687
f2333421 4688/* Add IS-IS SR Adjacency-SID subTLVs */
1b3f47d0
OD
4689void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs *exts,
4690 struct isis_adj_sid *adj)
4691{
4692 append_item(&exts->adj_sid, (struct isis_item *)adj);
4693 SET_SUBTLV(exts, EXT_ADJ_SID);
4694}
4695
f2333421 4696/* Delete IS-IS SR Adjacency-SID subTLVs */
1b3f47d0
OD
4697void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs *exts,
4698 struct isis_adj_sid *adj)
4699{
4700 delete_item(&exts->adj_sid, (struct isis_item *)adj);
4701 XFREE(MTYPE_ISIS_SUBTLV, adj);
4702 if (exts->adj_sid.count == 0)
4703 UNSET_SUBTLV(exts, EXT_ADJ_SID);
4704}
4705
f2333421 4706/* Add IS-IS SR LAN-Adjacency-SID subTLVs */
1b3f47d0
OD
4707void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs *exts,
4708 struct isis_lan_adj_sid *lan)
4709{
4710 append_item(&exts->lan_sid, (struct isis_item *)lan);
4711 SET_SUBTLV(exts, EXT_LAN_ADJ_SID);
4712}
4713
f2333421 4714/* Delete IS-IS SR LAN-Adjacency-SID subTLVs */
1b3f47d0
OD
4715void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs *exts,
4716 struct isis_lan_adj_sid *lan)
4717{
4718 delete_item(&exts->lan_sid, (struct isis_item *)lan);
4719 XFREE(MTYPE_ISIS_SUBTLV, lan);
4720 if (exts->lan_sid.count == 0)
4721 UNSET_SUBTLV(exts, EXT_LAN_ADJ_SID);
4722}
4723
7ef5fefc 4724void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs,
26f6acaf
RW
4725 struct prefix_ipv4 *dest, uint32_t metric,
4726 bool external, struct sr_prefix_cfg *pcfg)
7ef5fefc 4727{
841791b6 4728 struct isis_extended_ip_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
7ef5fefc
CF
4729
4730 r->metric = metric;
4731 memcpy(&r->prefix, dest, sizeof(*dest));
4732 apply_mask_ipv4(&r->prefix);
26f6acaf
RW
4733 if (pcfg) {
4734 struct isis_prefix_sid *psid =
4735 XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*psid));
4736
4737 isis_sr_prefix_cfg2subtlv(pcfg, external, psid);
4738 r->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH);
4739 append_item(&r->subtlvs->prefix_sids, (struct isis_item *)psid);
4740 }
7ef5fefc
CF
4741 append_item(&tlvs->extended_ip_reach, (struct isis_item *)r);
4742}
4743
4744void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid,
26f6acaf
RW
4745 struct prefix_ipv6 *dest, uint32_t metric,
4746 bool external, struct sr_prefix_cfg *pcfg)
7ef5fefc 4747{
841791b6 4748 struct isis_ipv6_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
7ef5fefc
CF
4749
4750 r->metric = metric;
4751 memcpy(&r->prefix, dest, sizeof(*dest));
4752 apply_mask_ipv6(&r->prefix);
26f6acaf
RW
4753 if (pcfg) {
4754 struct isis_prefix_sid *psid =
4755 XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*psid));
4756
4757 isis_sr_prefix_cfg2subtlv(pcfg, external, psid);
4758 r->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH);
4759 append_item(&r->subtlvs->prefix_sids, (struct isis_item *)psid);
4760 }
7ef5fefc
CF
4761
4762 struct isis_item_list *l;
4763 l = (mtid == ISIS_MT_IPV4_UNICAST)
4764 ? &tlvs->ipv6_reach
4765 : isis_get_mt_items(&tlvs->mt_ipv6_reach, mtid);
4766 append_item(l, (struct isis_item *)r);
4767}
4768
d43d2df5
CF
4769void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid,
4770 struct prefix_ipv6 *dest,
4771 struct prefix_ipv6 *src,
4772 uint32_t metric)
4773{
26f6acaf 4774 isis_tlvs_add_ipv6_reach(tlvs, mtid, dest, metric, false, NULL);
d43d2df5
CF
4775 struct isis_item_list *l = isis_get_mt_items(&tlvs->mt_ipv6_reach,
4776 mtid);
4777
4778 struct isis_ipv6_reach *r = (struct isis_ipv6_reach*)last_item(l);
bd507085 4779 r->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH);
d43d2df5
CF
4780 r->subtlvs->source_prefix = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*src));
4781 memcpy(r->subtlvs->source_prefix, src, sizeof(*src));
4782}
4783
7ef5fefc
CF
4784void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id,
4785 uint8_t metric)
4786{
841791b6 4787 struct isis_oldstyle_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
7ef5fefc
CF
4788
4789 r->metric = metric;
4790 memcpy(r->id, id, sizeof(r->id));
4791 append_item(&tlvs->oldstyle_reach, (struct isis_item *)r);
4792}
4793
4794void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid,
4795 uint8_t *id, uint32_t metric,
1b3f47d0 4796 struct isis_ext_subtlvs *exts)
7ef5fefc 4797{
841791b6 4798 struct isis_extended_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
7ef5fefc
CF
4799
4800 memcpy(r->id, id, sizeof(r->id));
4801 r->metric = metric;
1b3f47d0
OD
4802 if (exts)
4803 r->subtlvs = copy_item_ext_subtlvs(exts, mtid);
7ef5fefc
CF
4804
4805 struct isis_item_list *l;
4806 if (mtid == ISIS_MT_IPV4_UNICAST)
4807 l = &tlvs->extended_reach;
4808 else
4809 l = isis_get_mt_items(&tlvs->mt_reach, mtid);
4810 append_item(l, (struct isis_item *)r);
4811}
4812
9fe21208
CF
4813void isis_tlvs_add_threeway_adj(struct isis_tlvs *tlvs,
4814 enum isis_threeway_state state,
4815 uint32_t local_circuit_id,
4816 const uint8_t *neighbor_id,
4817 uint32_t neighbor_circuit_id)
4818{
4819 assert(!tlvs->threeway_adj);
4820
4821 tlvs->threeway_adj = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->threeway_adj));
4822 tlvs->threeway_adj->state = state;
4823 tlvs->threeway_adj->local_circuit_id = local_circuit_id;
4824
4825 if (neighbor_id) {
4826 tlvs->threeway_adj->neighbor_set = true;
4827 memcpy(tlvs->threeway_adj->neighbor_id, neighbor_id, 6);
4828 tlvs->threeway_adj->neighbor_circuit_id = neighbor_circuit_id;
4829 }
4830}
4831
41a145f1
CF
4832void isis_tlvs_add_spine_leaf(struct isis_tlvs *tlvs, uint8_t tier,
4833 bool has_tier, bool is_leaf, bool is_spine,
4834 bool is_backup)
4835{
4836 assert(!tlvs->spine_leaf);
4837
4838 tlvs->spine_leaf = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->spine_leaf));
4839
4840 if (has_tier) {
4841 tlvs->spine_leaf->tier = tier;
4842 }
4843
4844 tlvs->spine_leaf->has_tier = has_tier;
4845 tlvs->spine_leaf->is_leaf = is_leaf;
4846 tlvs->spine_leaf->is_spine = is_spine;
4847 tlvs->spine_leaf->is_backup = is_backup;
4848}
4849
7ef5fefc
CF
4850struct isis_mt_router_info *
4851isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid)
4852{
4853 if (tlvs->mt_router_info_empty)
4854 return NULL;
4855
4856 struct isis_mt_router_info *rv;
4857 for (rv = (struct isis_mt_router_info *)tlvs->mt_router_info.head; rv;
4858 rv = rv->next) {
4859 if (rv->mtid == mtid)
4860 return rv;
4861 }
4862
4863 return NULL;
4864}
2c92bee4
CF
4865
4866void isis_tlvs_set_purge_originator(struct isis_tlvs *tlvs,
4867 const uint8_t *generator,
4868 const uint8_t *sender)
4869{
4870 assert(!tlvs->purge_originator);
4871
4872 tlvs->purge_originator = XCALLOC(MTYPE_ISIS_TLV,
4873 sizeof(*tlvs->purge_originator));
4874 memcpy(tlvs->purge_originator->generator, generator,
4875 sizeof(tlvs->purge_originator->generator));
4876 if (sender) {
4877 tlvs->purge_originator->sender_set = true;
4878 memcpy(tlvs->purge_originator->sender, sender,
4879 sizeof(tlvs->purge_originator->sender));
4880 }
4881}