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