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