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