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