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