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