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