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