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