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