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