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