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