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