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