]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_tlvs.c
Merge pull request #4996 from opensourcerouting/build-tags
[mirror_frr.git] / isisd / isis_tlvs.c
1 /*
2 * IS-IS TLV Serializer/Deserializer
3 *
4 * Copyright (C) 2015,2017 Christian Franke
5 *
6 * This file is part of FRR.
7 *
8 * FRR is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * FRR is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with FRR; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 * 02111-1307, USA.
22 */
23 #include <zebra.h>
24
25 #ifdef CRYPTO_INTERNAL
26 #include "md5.h"
27 #endif
28 #include "memory.h"
29 #include "stream.h"
30 #include "sbuf.h"
31
32 #include "isisd/isisd.h"
33 #include "isisd/isis_memory.h"
34 #include "isisd/isis_tlvs.h"
35 #include "isisd/isis_common.h"
36 #include "isisd/isis_mt.h"
37 #include "isisd/isis_misc.h"
38 #include "isisd/isis_adjacency.h"
39 #include "isisd/isis_circuit.h"
40 #include "isisd/isis_pdu.h"
41 #include "isisd/isis_lsp.h"
42 #include "isisd/isis_te.h"
43
44 DEFINE_MTYPE_STATIC(ISISD, ISIS_TLV, "ISIS TLVs")
45 DEFINE_MTYPE_STATIC(ISISD, ISIS_SUBTLV, "ISIS Sub-TLVs")
46 DEFINE_MTYPE_STATIC(ISISD, ISIS_MT_ITEM_LIST, "ISIS MT Item Lists")
47
48 typedef int (*unpack_tlv_func)(enum isis_tlv_context context, uint8_t tlv_type,
49 uint8_t tlv_len, struct stream *s,
50 struct sbuf *log, void *dest, int indent);
51 typedef int (*pack_item_func)(struct isis_item *item, struct stream *s);
52 typedef void (*free_item_func)(struct isis_item *i);
53 typedef int (*unpack_item_func)(uint16_t mtid, uint8_t len, struct stream *s,
54 struct sbuf *log, void *dest, int indent);
55 typedef void (*format_item_func)(uint16_t mtid, struct isis_item *i,
56 struct sbuf *buf, int indent);
57 typedef struct isis_item *(*copy_item_func)(struct isis_item *i);
58
59 struct tlv_ops {
60 const char *name;
61 unpack_tlv_func unpack;
62
63 pack_item_func pack_item;
64 free_item_func free_item;
65 unpack_item_func unpack_item;
66 format_item_func format_item;
67 copy_item_func copy_item;
68 };
69
70 enum how_to_pack {
71 ISIS_ITEMS,
72 ISIS_MT_ITEMS,
73 };
74
75 struct pack_order_entry {
76 enum isis_tlv_context context;
77 enum isis_tlv_type type;
78 enum how_to_pack how_to_pack;
79 size_t what_to_pack;
80 };
81 #define PACK_ENTRY(t, h, w) \
82 { \
83 .context = ISIS_CONTEXT_LSP, .type = ISIS_TLV_##t, \
84 .how_to_pack = (h), \
85 .what_to_pack = offsetof(struct isis_tlvs, w), \
86 }
87
88 static struct pack_order_entry pack_order[] = {
89 PACK_ENTRY(OLDSTYLE_REACH, ISIS_ITEMS, oldstyle_reach),
90 PACK_ENTRY(LAN_NEIGHBORS, ISIS_ITEMS, lan_neighbor),
91 PACK_ENTRY(LSP_ENTRY, ISIS_ITEMS, lsp_entries),
92 PACK_ENTRY(EXTENDED_REACH, ISIS_ITEMS, extended_reach),
93 PACK_ENTRY(MT_REACH, ISIS_MT_ITEMS, mt_reach),
94 PACK_ENTRY(OLDSTYLE_IP_REACH, ISIS_ITEMS, oldstyle_ip_reach),
95 PACK_ENTRY(OLDSTYLE_IP_REACH_EXT, ISIS_ITEMS, oldstyle_ip_reach_ext),
96 PACK_ENTRY(IPV4_ADDRESS, ISIS_ITEMS, ipv4_address),
97 PACK_ENTRY(IPV6_ADDRESS, ISIS_ITEMS, ipv6_address),
98 PACK_ENTRY(EXTENDED_IP_REACH, ISIS_ITEMS, extended_ip_reach),
99 PACK_ENTRY(MT_IP_REACH, ISIS_MT_ITEMS, mt_ip_reach),
100 PACK_ENTRY(IPV6_REACH, ISIS_ITEMS, ipv6_reach),
101 PACK_ENTRY(MT_IPV6_REACH, ISIS_MT_ITEMS, mt_ipv6_reach)};
102
103 /* This is a forward definition. The table is actually initialized
104 * in at the bottom. */
105 static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX];
106
107 /* End of _ops forward definition. */
108
109 /* Prototypes */
110 static void append_item(struct isis_item_list *dest, struct isis_item *item);
111
112 /* Functions for Sub-TLV 3 SR Prefix-SID */
113
114 static struct isis_item *copy_item_prefix_sid(struct isis_item *i)
115 {
116 struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
117 struct isis_prefix_sid *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
118
119 rv->flags = sid->flags;
120 rv->algorithm = sid->algorithm;
121 rv->value = sid->value;
122 return (struct isis_item *)rv;
123 }
124
125 static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i,
126 struct sbuf *buf, int indent)
127 {
128 struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
129
130 sbuf_push(buf, indent, "SR Prefix-SID:\n");
131 sbuf_push(buf, indent, " Flags:%s%s%s%s%s%s\n",
132 sid->flags & ISIS_PREFIX_SID_READVERTISED ? " READVERTISED" : "",
133 sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "",
134 sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO_PHP" : "",
135 sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL ? " EXPLICIT-NULL" : "",
136 sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "",
137 sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : "");
138 sbuf_push(buf, indent, " Algorithm: %" PRIu8 "\n", sid->algorithm);
139 if (sid->flags & ISIS_PREFIX_SID_VALUE) {
140 sbuf_push(buf, indent, "Label: %" PRIu32 "\n", sid->value);
141 } else {
142 sbuf_push(buf, indent, "Index: %" PRIu32 "\n", sid->value);
143 }
144 }
145
146 static void free_item_prefix_sid(struct isis_item *i)
147 {
148 XFREE(MTYPE_ISIS_SUBTLV, i);
149 }
150
151 static int pack_item_prefix_sid(struct isis_item *i, struct stream *s)
152 {
153 struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
154
155 uint8_t size = (sid->flags & ISIS_PREFIX_SID_VALUE) ? 5 : 6;
156
157 if (STREAM_WRITEABLE(s) < size)
158 return 1;
159
160 stream_putc(s, sid->flags);
161 stream_putc(s, sid->algorithm);
162
163 if (sid->flags & ISIS_PREFIX_SID_VALUE) {
164 stream_put3(s, sid->value);
165 } else {
166 stream_putl(s, sid->value);
167 }
168
169 return 0;
170 }
171
172 static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s,
173 struct sbuf *log, void *dest, int indent)
174 {
175 struct isis_subtlvs *subtlvs = dest;
176 struct isis_prefix_sid sid = {
177 };
178
179 sbuf_push(log, indent, "Unpacking SR Prefix-SID...\n");
180
181 if (len < 5) {
182 sbuf_push(log, indent,
183 "Not enough data left. (expected 5 or more bytes, got %" PRIu8 ")\n",
184 len);
185 return 1;
186 }
187
188 sid.flags = stream_getc(s);
189 if (!!(sid.flags & ISIS_PREFIX_SID_VALUE)
190 != !!(sid.flags & ISIS_PREFIX_SID_LOCAL)) {
191 sbuf_push(log, indent, "Flags inplausible: Local Flag needs to match Value Flag\n");
192 return 1;
193 }
194
195 sid.algorithm = stream_getc(s);
196
197 uint8_t expected_size = (sid.flags & ISIS_PREFIX_SID_VALUE) ? 5 : 6;
198 if (len != expected_size) {
199 sbuf_push(log, indent,
200 "TLV size differs from expected size. "
201 "(expected %u but got %" PRIu8 ")\n",
202 expected_size, len);
203 return 1;
204 }
205
206 if (sid.flags & ISIS_PREFIX_SID_VALUE) {
207 sid.value = stream_get3(s);
208 } else {
209 sid.value = stream_getl(s);
210 }
211
212 format_item_prefix_sid(mtid, (struct isis_item *)&sid, log, indent + 2);
213 append_item(&subtlvs->prefix_sids, copy_item_prefix_sid((struct isis_item *)&sid));
214 return 0;
215 }
216
217 /* Functions for Sub-TVL ??? IPv6 Source Prefix */
218
219 static struct prefix_ipv6 *copy_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p)
220 {
221 if (!p)
222 return NULL;
223
224 struct prefix_ipv6 *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
225 rv->family = p->family;
226 rv->prefixlen = p->prefixlen;
227 memcpy(&rv->prefix, &p->prefix, sizeof(rv->prefix));
228 return rv;
229 }
230
231 static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p,
232 struct sbuf *buf, int indent)
233 {
234 if (!p)
235 return;
236
237 char prefixbuf[PREFIX2STR_BUFFER];
238 sbuf_push(buf, indent, "IPv6 Source Prefix: %s\n",
239 prefix2str(p, prefixbuf, sizeof(prefixbuf)));
240 }
241
242 static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p,
243 struct stream *s)
244 {
245 if (!p)
246 return 0;
247
248 if (STREAM_WRITEABLE(s) < 3 + (unsigned)PSIZE(p->prefixlen))
249 return 1;
250
251 stream_putc(s, ISIS_SUBTLV_IPV6_SOURCE_PREFIX);
252 stream_putc(s, 1 + PSIZE(p->prefixlen));
253 stream_putc(s, p->prefixlen);
254 stream_put(s, &p->prefix, PSIZE(p->prefixlen));
255 return 0;
256 }
257
258 static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context,
259 uint8_t tlv_type, uint8_t tlv_len,
260 struct stream *s, struct sbuf *log,
261 void *dest, int indent)
262 {
263 struct isis_subtlvs *subtlvs = dest;
264 struct prefix_ipv6 p = {
265 .family = AF_INET6,
266 };
267
268 sbuf_push(log, indent, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
269
270 if (tlv_len < 1) {
271 sbuf_push(log, indent,
272 "Not enough data left. (expected 1 or more bytes, got %" PRIu8 ")\n",
273 tlv_len);
274 return 1;
275 }
276
277 p.prefixlen = stream_getc(s);
278 if (p.prefixlen > 128) {
279 sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv6\n",
280 p.prefixlen);
281 return 1;
282 }
283
284 if (tlv_len != 1 + PSIZE(p.prefixlen)) {
285 sbuf_push(
286 log, indent,
287 "TLV size differs from expected size for the prefixlen. "
288 "(expected %u but got %" PRIu8 ")\n",
289 1 + PSIZE(p.prefixlen), tlv_len);
290 return 1;
291 }
292
293 stream_get(&p.prefix, s, PSIZE(p.prefixlen));
294
295 if (subtlvs->source_prefix) {
296 sbuf_push(
297 log, indent,
298 "WARNING: source prefix Sub-TLV present multiple times.\n");
299 /* Ignore all but first occurrence of the source prefix Sub-TLV
300 */
301 return 0;
302 }
303
304 subtlvs->source_prefix = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(p));
305 memcpy(subtlvs->source_prefix, &p, sizeof(p));
306 return 0;
307 }
308 static void init_item_list(struct isis_item_list *items);
309 static struct isis_item *copy_item(enum isis_tlv_context context,
310 enum isis_tlv_type type,
311 struct isis_item *item);
312 static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type,
313 struct isis_item_list *src, struct isis_item_list *dest);
314 static void format_items_(uint16_t mtid, enum isis_tlv_context context,
315 enum isis_tlv_type type, struct isis_item_list *items,
316 struct sbuf *buf, int indent);
317 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
318 static void free_items(enum isis_tlv_context context, enum isis_tlv_type type,
319 struct isis_item_list *items);
320 static int pack_items_(uint16_t mtid, enum isis_tlv_context context,
321 enum isis_tlv_type type, struct isis_item_list *items,
322 struct stream *s, struct isis_tlvs **fragment_tlvs,
323 struct pack_order_entry *pe,
324 struct isis_tlvs *(*new_fragment)(struct list *l),
325 struct list *new_fragment_arg);
326 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
327
328 /* Functions related to subtlvs */
329
330 static struct isis_subtlvs *isis_alloc_subtlvs(enum isis_tlv_context context)
331 {
332 struct isis_subtlvs *result;
333
334 result = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*result));
335 result->context = context;
336
337 init_item_list(&result->prefix_sids);
338
339 return result;
340 }
341
342 static struct isis_subtlvs *copy_subtlvs(struct isis_subtlvs *subtlvs)
343 {
344 if (!subtlvs)
345 return NULL;
346
347 struct isis_subtlvs *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
348
349 rv->context = subtlvs->context;
350
351 copy_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
352 &subtlvs->prefix_sids, &rv->prefix_sids);
353
354 rv->source_prefix =
355 copy_subtlv_ipv6_source_prefix(subtlvs->source_prefix);
356 return rv;
357 }
358
359 static void format_subtlvs(struct isis_subtlvs *subtlvs, struct sbuf *buf,
360 int indent)
361 {
362 format_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
363 &subtlvs->prefix_sids, buf, indent);
364
365 format_subtlv_ipv6_source_prefix(subtlvs->source_prefix, buf, indent);
366 }
367
368 static void isis_free_subtlvs(struct isis_subtlvs *subtlvs)
369 {
370 if (!subtlvs)
371 return;
372
373 free_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
374 &subtlvs->prefix_sids);
375
376 XFREE(MTYPE_ISIS_SUBTLV, subtlvs->source_prefix);
377
378 XFREE(MTYPE_ISIS_SUBTLV, subtlvs);
379 }
380
381 static int pack_subtlvs(struct isis_subtlvs *subtlvs, struct stream *s)
382 {
383 int rv;
384 size_t subtlv_len_pos = stream_get_endp(s);
385
386 if (STREAM_WRITEABLE(s) < 1)
387 return 1;
388
389 stream_putc(s, 0); /* Put 0 as subtlvs length, filled in later */
390
391 rv = pack_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
392 &subtlvs->prefix_sids, s, NULL, NULL, NULL, NULL);
393 if (rv)
394 return rv;
395
396 rv = pack_subtlv_ipv6_source_prefix(subtlvs->source_prefix, s);
397 if (rv)
398 return rv;
399
400 size_t subtlv_len = stream_get_endp(s) - subtlv_len_pos - 1;
401 if (subtlv_len > 255)
402 return 1;
403
404 stream_putc_at(s, subtlv_len_pos, subtlv_len);
405 return 0;
406 }
407
408 static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len,
409 struct stream *stream, struct sbuf *log, void *dest,
410 int indent, bool *unpacked_known_tlvs);
411
412 /* Functions related to TLVs 1 Area Addresses */
413
414 static struct isis_item *copy_item_area_address(struct isis_item *i)
415 {
416 struct isis_area_address *addr = (struct isis_area_address *)i;
417 struct isis_area_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
418
419 rv->len = addr->len;
420 memcpy(rv->addr, addr->addr, addr->len);
421 return (struct isis_item *)rv;
422 }
423
424 static void format_item_area_address(uint16_t mtid, struct isis_item *i,
425 struct sbuf *buf, int indent)
426 {
427 struct isis_area_address *addr = (struct isis_area_address *)i;
428
429 sbuf_push(buf, indent, "Area Address: %s\n",
430 isonet_print(addr->addr, addr->len));
431 }
432
433 static void free_item_area_address(struct isis_item *i)
434 {
435 XFREE(MTYPE_ISIS_TLV, i);
436 }
437
438 static int pack_item_area_address(struct isis_item *i, struct stream *s)
439 {
440 struct isis_area_address *addr = (struct isis_area_address *)i;
441
442 if (STREAM_WRITEABLE(s) < (unsigned)1 + addr->len)
443 return 1;
444 stream_putc(s, addr->len);
445 stream_put(s, addr->addr, addr->len);
446 return 0;
447 }
448
449 static int unpack_item_area_address(uint16_t mtid, uint8_t len,
450 struct stream *s, struct sbuf *log,
451 void *dest, int indent)
452 {
453 struct isis_tlvs *tlvs = dest;
454 struct isis_area_address *rv = NULL;
455
456 sbuf_push(log, indent, "Unpack area address...\n");
457 if (len < 1) {
458 sbuf_push(
459 log, indent,
460 "Not enough data left. (Expected 1 byte of address length, got %" PRIu8
461 ")\n",
462 len);
463 goto out;
464 }
465
466 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
467 rv->len = stream_getc(s);
468
469 if (len < 1 + rv->len) {
470 sbuf_push(log, indent, "Not enough data left. (Expected %" PRIu8
471 " bytes of address, got %" PRIu8 ")\n",
472 rv->len, len - 1);
473 goto out;
474 }
475
476 if (rv->len < 1 || rv->len > 20) {
477 sbuf_push(log, indent,
478 "Implausible area address length %" PRIu8 "\n",
479 rv->len);
480 goto out;
481 }
482
483 stream_get(rv->addr, s, rv->len);
484
485 format_item_area_address(ISIS_MT_IPV4_UNICAST, (struct isis_item *)rv,
486 log, indent + 2);
487 append_item(&tlvs->area_addresses, (struct isis_item *)rv);
488 return 0;
489 out:
490 XFREE(MTYPE_ISIS_TLV, rv);
491 return 1;
492 }
493
494 /* Functions related to TLV 2 (Old-Style) IS Reach */
495 static struct isis_item *copy_item_oldstyle_reach(struct isis_item *i)
496 {
497 struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i;
498 struct isis_oldstyle_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
499
500 memcpy(rv->id, r->id, 7);
501 rv->metric = r->metric;
502 return (struct isis_item *)rv;
503 }
504
505 static void format_item_oldstyle_reach(uint16_t mtid, struct isis_item *i,
506 struct sbuf *buf, int indent)
507 {
508 struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i;
509
510 sbuf_push(buf, indent, "IS Reachability: %s (Metric: %" PRIu8 ")\n",
511 isis_format_id(r->id, 7), r->metric);
512 }
513
514 static void free_item_oldstyle_reach(struct isis_item *i)
515 {
516 XFREE(MTYPE_ISIS_TLV, i);
517 }
518
519 static int pack_item_oldstyle_reach(struct isis_item *i, struct stream *s)
520 {
521 struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i;
522
523 if (STREAM_WRITEABLE(s) < 11)
524 return 1;
525
526 stream_putc(s, r->metric);
527 stream_putc(s, 0x80); /* delay metric - unsupported */
528 stream_putc(s, 0x80); /* expense metric - unsupported */
529 stream_putc(s, 0x80); /* error metric - unsupported */
530 stream_put(s, r->id, 7);
531
532 return 0;
533 }
534
535 static int unpack_item_oldstyle_reach(uint16_t mtid, uint8_t len,
536 struct stream *s, struct sbuf *log,
537 void *dest, int indent)
538 {
539 struct isis_tlvs *tlvs = dest;
540
541 sbuf_push(log, indent, "Unpack oldstyle reach...\n");
542 if (len < 11) {
543 sbuf_push(
544 log, indent,
545 "Not enough data left.(Expected 11 bytes of reach information, got %" PRIu8
546 ")\n",
547 len);
548 return 1;
549 }
550
551 struct isis_oldstyle_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
552 rv->metric = stream_getc(s);
553 if ((rv->metric & 0x3f) != rv->metric) {
554 sbuf_push(log, indent, "Metric has unplausible format\n");
555 rv->metric &= 0x3f;
556 }
557 stream_forward_getp(s, 3); /* Skip other metrics */
558 stream_get(rv->id, s, 7);
559
560 format_item_oldstyle_reach(mtid, (struct isis_item *)rv, log,
561 indent + 2);
562 append_item(&tlvs->oldstyle_reach, (struct isis_item *)rv);
563 return 0;
564 }
565
566 /* Functions related to TLV 6 LAN Neighbors */
567 static struct isis_item *copy_item_lan_neighbor(struct isis_item *i)
568 {
569 struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i;
570 struct isis_lan_neighbor *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
571
572 memcpy(rv->mac, n->mac, 6);
573 return (struct isis_item *)rv;
574 }
575
576 static void format_item_lan_neighbor(uint16_t mtid, struct isis_item *i,
577 struct sbuf *buf, int indent)
578 {
579 struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i;
580
581 sbuf_push(buf, indent, "LAN Neighbor: %s\n", isis_format_id(n->mac, 6));
582 }
583
584 static void free_item_lan_neighbor(struct isis_item *i)
585 {
586 XFREE(MTYPE_ISIS_TLV, i);
587 }
588
589 static int pack_item_lan_neighbor(struct isis_item *i, struct stream *s)
590 {
591 struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i;
592
593 if (STREAM_WRITEABLE(s) < 6)
594 return 1;
595
596 stream_put(s, n->mac, 6);
597
598 return 0;
599 }
600
601 static int unpack_item_lan_neighbor(uint16_t mtid, uint8_t len,
602 struct stream *s, struct sbuf *log,
603 void *dest, int indent)
604 {
605 struct isis_tlvs *tlvs = dest;
606
607 sbuf_push(log, indent, "Unpack LAN neighbor...\n");
608 if (len < 6) {
609 sbuf_push(
610 log, indent,
611 "Not enough data left.(Expected 6 bytes of mac, got %" PRIu8
612 ")\n",
613 len);
614 return 1;
615 }
616
617 struct isis_lan_neighbor *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
618 stream_get(rv->mac, s, 6);
619
620 format_item_lan_neighbor(mtid, (struct isis_item *)rv, log, indent + 2);
621 append_item(&tlvs->lan_neighbor, (struct isis_item *)rv);
622 return 0;
623 }
624
625 /* Functions related to TLV 9 LSP Entry */
626 static struct isis_item *copy_item_lsp_entry(struct isis_item *i)
627 {
628 struct isis_lsp_entry *e = (struct isis_lsp_entry *)i;
629 struct isis_lsp_entry *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
630
631 rv->rem_lifetime = e->rem_lifetime;
632 memcpy(rv->id, e->id, sizeof(rv->id));
633 rv->seqno = e->seqno;
634 rv->checksum = e->checksum;
635
636 return (struct isis_item *)rv;
637 }
638
639 static void format_item_lsp_entry(uint16_t mtid, struct isis_item *i,
640 struct sbuf *buf, int indent)
641 {
642 struct isis_lsp_entry *e = (struct isis_lsp_entry *)i;
643
644 sbuf_push(buf, indent,
645 "LSP Entry: %s, seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16
646 ", lifetime %" PRIu16 "s\n",
647 isis_format_id(e->id, 8), e->seqno, e->checksum,
648 e->rem_lifetime);
649 }
650
651 static void free_item_lsp_entry(struct isis_item *i)
652 {
653 XFREE(MTYPE_ISIS_TLV, i);
654 }
655
656 static int pack_item_lsp_entry(struct isis_item *i, struct stream *s)
657 {
658 struct isis_lsp_entry *e = (struct isis_lsp_entry *)i;
659
660 if (STREAM_WRITEABLE(s) < 16)
661 return 1;
662
663 stream_putw(s, e->rem_lifetime);
664 stream_put(s, e->id, 8);
665 stream_putl(s, e->seqno);
666 stream_putw(s, e->checksum);
667
668 return 0;
669 }
670
671 static int unpack_item_lsp_entry(uint16_t mtid, uint8_t len, struct stream *s,
672 struct sbuf *log, void *dest, int indent)
673 {
674 struct isis_tlvs *tlvs = dest;
675
676 sbuf_push(log, indent, "Unpack LSP entry...\n");
677 if (len < 16) {
678 sbuf_push(
679 log, indent,
680 "Not enough data left. (Expected 16 bytes of LSP info, got %" PRIu8,
681 len);
682 return 1;
683 }
684
685 struct isis_lsp_entry *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
686 rv->rem_lifetime = stream_getw(s);
687 stream_get(rv->id, s, 8);
688 rv->seqno = stream_getl(s);
689 rv->checksum = stream_getw(s);
690
691 format_item_lsp_entry(mtid, (struct isis_item *)rv, log, indent + 2);
692 append_item(&tlvs->lsp_entries, (struct isis_item *)rv);
693 return 0;
694 }
695
696 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
697
698 static struct isis_item *copy_item_extended_reach(struct isis_item *i)
699 {
700 struct isis_extended_reach *r = (struct isis_extended_reach *)i;
701 struct isis_extended_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
702
703 memcpy(rv->id, r->id, 7);
704 rv->metric = r->metric;
705
706 if (r->subtlvs && r->subtlv_len) {
707 rv->subtlvs = XCALLOC(MTYPE_ISIS_TLV, r->subtlv_len);
708 memcpy(rv->subtlvs, r->subtlvs, r->subtlv_len);
709 rv->subtlv_len = r->subtlv_len;
710 }
711
712 return (struct isis_item *)rv;
713 }
714
715 static void format_item_extended_reach(uint16_t mtid, struct isis_item *i,
716 struct sbuf *buf, int indent)
717 {
718 struct isis_extended_reach *r = (struct isis_extended_reach *)i;
719
720 sbuf_push(buf, indent, "%s Reachability: %s (Metric: %u)",
721 (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT",
722 isis_format_id(r->id, 7), r->metric);
723 if (mtid != ISIS_MT_IPV4_UNICAST)
724 sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
725 sbuf_push(buf, 0, "\n");
726
727 if (r->subtlv_len && r->subtlvs)
728 mpls_te_print_detail(buf, indent + 2, r->subtlvs,
729 r->subtlv_len);
730 }
731
732 static void free_item_extended_reach(struct isis_item *i)
733 {
734 struct isis_extended_reach *item = (struct isis_extended_reach *)i;
735 XFREE(MTYPE_ISIS_TLV, item->subtlvs);
736 XFREE(MTYPE_ISIS_TLV, item);
737 }
738
739 static int pack_item_extended_reach(struct isis_item *i, struct stream *s)
740 {
741 struct isis_extended_reach *r = (struct isis_extended_reach *)i;
742
743 if (STREAM_WRITEABLE(s) < 11 + (unsigned)r->subtlv_len)
744 return 1;
745 stream_put(s, r->id, sizeof(r->id));
746 stream_put3(s, r->metric);
747 stream_putc(s, r->subtlv_len);
748 stream_put(s, r->subtlvs, r->subtlv_len);
749 return 0;
750 }
751
752 static int unpack_item_extended_reach(uint16_t mtid, uint8_t len,
753 struct stream *s, struct sbuf *log,
754 void *dest, int indent)
755 {
756 struct isis_tlvs *tlvs = dest;
757 struct isis_extended_reach *rv = NULL;
758 uint8_t subtlv_len;
759 struct isis_item_list *items;
760
761 if (mtid == ISIS_MT_IPV4_UNICAST) {
762 items = &tlvs->extended_reach;
763 } else {
764 items = isis_get_mt_items(&tlvs->mt_reach, mtid);
765 }
766
767 sbuf_push(log, indent, "Unpacking %s reachability...\n",
768 (mtid == ISIS_MT_IPV4_UNICAST) ? "extended" : "mt");
769
770 if (len < 11) {
771 sbuf_push(log, indent,
772 "Not enough data left. (expected 11 or more bytes, got %"
773 PRIu8 ")\n",
774 len);
775 goto out;
776 }
777
778 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
779 stream_get(rv->id, s, 7);
780 rv->metric = stream_get3(s);
781 subtlv_len = stream_getc(s);
782
783 format_item_extended_reach(mtid, (struct isis_item *)rv, log,
784 indent + 2);
785
786 if ((size_t)len < ((size_t)11) + subtlv_len) {
787 sbuf_push(log, indent,
788 "Not enough data left for subtlv size %" PRIu8
789 ", there are only %" PRIu8 " bytes left.\n",
790 subtlv_len, len - 11);
791 goto out;
792 }
793
794 sbuf_push(log, indent, "Storing %" PRIu8 " bytes of subtlvs\n",
795 subtlv_len);
796
797 if (subtlv_len) {
798 size_t subtlv_start = stream_get_getp(s);
799
800 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_NE_REACH, subtlv_len, s,
801 log, NULL, indent + 4, NULL)) {
802 goto out;
803 }
804
805 stream_set_getp(s, subtlv_start);
806
807 rv->subtlvs = XCALLOC(MTYPE_ISIS_TLV, subtlv_len);
808 stream_get(rv->subtlvs, s, subtlv_len);
809 rv->subtlv_len = subtlv_len;
810 }
811
812 append_item(items, (struct isis_item *)rv);
813 return 0;
814 out:
815 if (rv)
816 free_item_extended_reach((struct isis_item *)rv);
817
818 return 1;
819 }
820
821 /* Functions related to TLV 128 (Old-Style) IP Reach */
822 static struct isis_item *copy_item_oldstyle_ip_reach(struct isis_item *i)
823 {
824 struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i;
825 struct isis_oldstyle_ip_reach *rv =
826 XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
827
828 rv->metric = r->metric;
829 rv->prefix = r->prefix;
830 return (struct isis_item *)rv;
831 }
832
833 static void format_item_oldstyle_ip_reach(uint16_t mtid, struct isis_item *i,
834 struct sbuf *buf, int indent)
835 {
836 struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i;
837 char prefixbuf[PREFIX2STR_BUFFER];
838
839 sbuf_push(buf, indent, "IP Reachability: %s (Metric: %" PRIu8 ")\n",
840 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)),
841 r->metric);
842 }
843
844 static void free_item_oldstyle_ip_reach(struct isis_item *i)
845 {
846 XFREE(MTYPE_ISIS_TLV, i);
847 }
848
849 static int pack_item_oldstyle_ip_reach(struct isis_item *i, struct stream *s)
850 {
851 struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i;
852
853 if (STREAM_WRITEABLE(s) < 12)
854 return 1;
855
856 stream_putc(s, r->metric);
857 stream_putc(s, 0x80); /* delay metric - unsupported */
858 stream_putc(s, 0x80); /* expense metric - unsupported */
859 stream_putc(s, 0x80); /* error metric - unsupported */
860 stream_put(s, &r->prefix.prefix, 4);
861
862 struct in_addr mask;
863 masklen2ip(r->prefix.prefixlen, &mask);
864 stream_put(s, &mask, sizeof(mask));
865
866 return 0;
867 }
868
869 static int unpack_item_oldstyle_ip_reach(uint16_t mtid, uint8_t len,
870 struct stream *s, struct sbuf *log,
871 void *dest, int indent)
872 {
873 sbuf_push(log, indent, "Unpack oldstyle ip reach...\n");
874 if (len < 12) {
875 sbuf_push(
876 log, indent,
877 "Not enough data left.(Expected 12 bytes of reach information, got %" PRIu8
878 ")\n",
879 len);
880 return 1;
881 }
882
883 struct isis_oldstyle_ip_reach *rv =
884 XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
885 rv->metric = stream_getc(s);
886 if ((rv->metric & 0x7f) != rv->metric) {
887 sbuf_push(log, indent, "Metric has unplausible format\n");
888 rv->metric &= 0x7f;
889 }
890 stream_forward_getp(s, 3); /* Skip other metrics */
891 rv->prefix.family = AF_INET;
892 stream_get(&rv->prefix.prefix, s, 4);
893
894 struct in_addr mask;
895 stream_get(&mask, s, 4);
896 rv->prefix.prefixlen = ip_masklen(mask);
897
898 format_item_oldstyle_ip_reach(mtid, (struct isis_item *)rv, log,
899 indent + 2);
900 append_item(dest, (struct isis_item *)rv);
901 return 0;
902 }
903
904
905 /* Functions related to TLV 129 protocols supported */
906
907 static void copy_tlv_protocols_supported(struct isis_protocols_supported *src,
908 struct isis_protocols_supported *dest)
909 {
910 if (!src->protocols || !src->count)
911 return;
912 dest->count = src->count;
913 dest->protocols = XCALLOC(MTYPE_ISIS_TLV, src->count);
914 memcpy(dest->protocols, src->protocols, src->count);
915 }
916
917 static void format_tlv_protocols_supported(struct isis_protocols_supported *p,
918 struct sbuf *buf, int indent)
919 {
920 if (!p || !p->count || !p->protocols)
921 return;
922
923 sbuf_push(buf, indent, "Protocols Supported: ");
924 for (uint8_t i = 0; i < p->count; i++) {
925 sbuf_push(buf, 0, "%s%s", nlpid2str(p->protocols[i]),
926 (i + 1 < p->count) ? ", " : "");
927 }
928 sbuf_push(buf, 0, "\n");
929 }
930
931 static void free_tlv_protocols_supported(struct isis_protocols_supported *p)
932 {
933 XFREE(MTYPE_ISIS_TLV, p->protocols);
934 }
935
936 static int pack_tlv_protocols_supported(struct isis_protocols_supported *p,
937 struct stream *s)
938 {
939 if (!p || !p->count || !p->protocols)
940 return 0;
941
942 if (STREAM_WRITEABLE(s) < (unsigned)(p->count + 2))
943 return 1;
944
945 stream_putc(s, ISIS_TLV_PROTOCOLS_SUPPORTED);
946 stream_putc(s, p->count);
947 stream_put(s, p->protocols, p->count);
948 return 0;
949 }
950
951 static int unpack_tlv_protocols_supported(enum isis_tlv_context context,
952 uint8_t tlv_type, uint8_t tlv_len,
953 struct stream *s, struct sbuf *log,
954 void *dest, int indent)
955 {
956 struct isis_tlvs *tlvs = dest;
957
958 sbuf_push(log, indent, "Unpacking Protocols Supported TLV...\n");
959 if (!tlv_len) {
960 sbuf_push(log, indent, "WARNING: No protocols included\n");
961 return 0;
962 }
963 if (tlvs->protocols_supported.protocols) {
964 sbuf_push(
965 log, indent,
966 "WARNING: protocols supported TLV present multiple times.\n");
967 stream_forward_getp(s, tlv_len);
968 return 0;
969 }
970
971 tlvs->protocols_supported.count = tlv_len;
972 tlvs->protocols_supported.protocols = XCALLOC(MTYPE_ISIS_TLV, tlv_len);
973 stream_get(tlvs->protocols_supported.protocols, s, tlv_len);
974
975 format_tlv_protocols_supported(&tlvs->protocols_supported, log,
976 indent + 2);
977 return 0;
978 }
979
980 /* Functions related to TLV 132 IPv4 Interface addresses */
981 static struct isis_item *copy_item_ipv4_address(struct isis_item *i)
982 {
983 struct isis_ipv4_address *a = (struct isis_ipv4_address *)i;
984 struct isis_ipv4_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
985
986 rv->addr = a->addr;
987 return (struct isis_item *)rv;
988 }
989
990 static void format_item_ipv4_address(uint16_t mtid, struct isis_item *i,
991 struct sbuf *buf, int indent)
992 {
993 struct isis_ipv4_address *a = (struct isis_ipv4_address *)i;
994 char addrbuf[INET_ADDRSTRLEN];
995
996 inet_ntop(AF_INET, &a->addr, addrbuf, sizeof(addrbuf));
997 sbuf_push(buf, indent, "IPv4 Interface Address: %s\n", addrbuf);
998 }
999
1000 static void free_item_ipv4_address(struct isis_item *i)
1001 {
1002 XFREE(MTYPE_ISIS_TLV, i);
1003 }
1004
1005 static int pack_item_ipv4_address(struct isis_item *i, struct stream *s)
1006 {
1007 struct isis_ipv4_address *a = (struct isis_ipv4_address *)i;
1008
1009 if (STREAM_WRITEABLE(s) < 4)
1010 return 1;
1011
1012 stream_put(s, &a->addr, 4);
1013
1014 return 0;
1015 }
1016
1017 static int unpack_item_ipv4_address(uint16_t mtid, uint8_t len,
1018 struct stream *s, struct sbuf *log,
1019 void *dest, int indent)
1020 {
1021 struct isis_tlvs *tlvs = dest;
1022
1023 sbuf_push(log, indent, "Unpack IPv4 Interface address...\n");
1024 if (len < 4) {
1025 sbuf_push(
1026 log, indent,
1027 "Not enough data left.(Expected 4 bytes of IPv4 address, got %" PRIu8
1028 ")\n",
1029 len);
1030 return 1;
1031 }
1032
1033 struct isis_ipv4_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1034 stream_get(&rv->addr, s, 4);
1035
1036 format_item_ipv4_address(mtid, (struct isis_item *)rv, log, indent + 2);
1037 append_item(&tlvs->ipv4_address, (struct isis_item *)rv);
1038 return 0;
1039 }
1040
1041
1042 /* Functions related to TLV 232 IPv6 Interface addresses */
1043 static struct isis_item *copy_item_ipv6_address(struct isis_item *i)
1044 {
1045 struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
1046 struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1047
1048 rv->addr = a->addr;
1049 return (struct isis_item *)rv;
1050 }
1051
1052 static void format_item_ipv6_address(uint16_t mtid, struct isis_item *i,
1053 struct sbuf *buf, int indent)
1054 {
1055 struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
1056 char addrbuf[INET6_ADDRSTRLEN];
1057
1058 inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf));
1059 sbuf_push(buf, indent, "IPv6 Interface Address: %s\n", addrbuf);
1060 }
1061
1062 static void free_item_ipv6_address(struct isis_item *i)
1063 {
1064 XFREE(MTYPE_ISIS_TLV, i);
1065 }
1066
1067 static int pack_item_ipv6_address(struct isis_item *i, struct stream *s)
1068 {
1069 struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
1070
1071 if (STREAM_WRITEABLE(s) < 16)
1072 return 1;
1073
1074 stream_put(s, &a->addr, 16);
1075
1076 return 0;
1077 }
1078
1079 static int unpack_item_ipv6_address(uint16_t mtid, uint8_t len,
1080 struct stream *s, struct sbuf *log,
1081 void *dest, int indent)
1082 {
1083 struct isis_tlvs *tlvs = dest;
1084
1085 sbuf_push(log, indent, "Unpack IPv6 Interface address...\n");
1086 if (len < 16) {
1087 sbuf_push(
1088 log, indent,
1089 "Not enough data left.(Expected 16 bytes of IPv6 address, got %" PRIu8
1090 ")\n",
1091 len);
1092 return 1;
1093 }
1094
1095 struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1096 stream_get(&rv->addr, s, 16);
1097
1098 format_item_ipv6_address(mtid, (struct isis_item *)rv, log, indent + 2);
1099 append_item(&tlvs->ipv6_address, (struct isis_item *)rv);
1100 return 0;
1101 }
1102
1103
1104 /* Functions related to TLV 229 MT Router information */
1105 static struct isis_item *copy_item_mt_router_info(struct isis_item *i)
1106 {
1107 struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
1108 struct isis_mt_router_info *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1109
1110 rv->overload = info->overload;
1111 rv->attached = info->attached;
1112 rv->mtid = info->mtid;
1113 return (struct isis_item *)rv;
1114 }
1115
1116 static void format_item_mt_router_info(uint16_t mtid, struct isis_item *i,
1117 struct sbuf *buf, int indent)
1118 {
1119 struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
1120
1121 sbuf_push(buf, indent, "MT Router Info: %s%s%s\n",
1122 isis_mtid2str(info->mtid),
1123 info->overload ? " Overload" : "",
1124 info->attached ? " Attached" : "");
1125 }
1126
1127 static void free_item_mt_router_info(struct isis_item *i)
1128 {
1129 XFREE(MTYPE_ISIS_TLV, i);
1130 }
1131
1132 static int pack_item_mt_router_info(struct isis_item *i, struct stream *s)
1133 {
1134 struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
1135
1136 if (STREAM_WRITEABLE(s) < 2)
1137 return 1;
1138
1139 uint16_t entry = info->mtid;
1140
1141 if (info->overload)
1142 entry |= ISIS_MT_OL_MASK;
1143 if (info->attached)
1144 entry |= ISIS_MT_AT_MASK;
1145
1146 stream_putw(s, entry);
1147
1148 return 0;
1149 }
1150
1151 static int unpack_item_mt_router_info(uint16_t mtid, uint8_t len,
1152 struct stream *s, struct sbuf *log,
1153 void *dest, int indent)
1154 {
1155 struct isis_tlvs *tlvs = dest;
1156
1157 sbuf_push(log, indent, "Unpack MT Router info...\n");
1158 if (len < 2) {
1159 sbuf_push(
1160 log, indent,
1161 "Not enough data left.(Expected 2 bytes of MT info, got %" PRIu8
1162 ")\n",
1163 len);
1164 return 1;
1165 }
1166
1167 struct isis_mt_router_info *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1168
1169 uint16_t entry = stream_getw(s);
1170 rv->overload = entry & ISIS_MT_OL_MASK;
1171 rv->attached = entry & ISIS_MT_AT_MASK;
1172 rv->mtid = entry & ISIS_MT_MASK;
1173
1174 format_item_mt_router_info(mtid, (struct isis_item *)rv, log,
1175 indent + 2);
1176 append_item(&tlvs->mt_router_info, (struct isis_item *)rv);
1177 return 0;
1178 }
1179
1180 /* Functions related to TLV 134 TE Router ID */
1181
1182 static struct in_addr *copy_tlv_te_router_id(const struct in_addr *id)
1183 {
1184 if (!id)
1185 return NULL;
1186
1187 struct in_addr *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1188 memcpy(rv, id, sizeof(*rv));
1189 return rv;
1190 }
1191
1192 static void format_tlv_te_router_id(const struct in_addr *id, struct sbuf *buf,
1193 int indent)
1194 {
1195 if (!id)
1196 return;
1197
1198 char addrbuf[INET_ADDRSTRLEN];
1199 inet_ntop(AF_INET, id, addrbuf, sizeof(addrbuf));
1200 sbuf_push(buf, indent, "TE Router ID: %s\n", addrbuf);
1201 }
1202
1203 static void free_tlv_te_router_id(struct in_addr *id)
1204 {
1205 XFREE(MTYPE_ISIS_TLV, id);
1206 }
1207
1208 static int pack_tlv_te_router_id(const struct in_addr *id, struct stream *s)
1209 {
1210 if (!id)
1211 return 0;
1212
1213 if (STREAM_WRITEABLE(s) < (unsigned)(2 + sizeof(*id)))
1214 return 1;
1215
1216 stream_putc(s, ISIS_TLV_TE_ROUTER_ID);
1217 stream_putc(s, 4);
1218 stream_put(s, id, 4);
1219 return 0;
1220 }
1221
1222 static int unpack_tlv_te_router_id(enum isis_tlv_context context,
1223 uint8_t tlv_type, uint8_t tlv_len,
1224 struct stream *s, struct sbuf *log,
1225 void *dest, int indent)
1226 {
1227 struct isis_tlvs *tlvs = dest;
1228
1229 sbuf_push(log, indent, "Unpacking TE Router ID TLV...\n");
1230 if (tlv_len != 4) {
1231 sbuf_push(log, indent, "WARNING: Length invalid\n");
1232 return 1;
1233 }
1234
1235 if (tlvs->te_router_id) {
1236 sbuf_push(log, indent,
1237 "WARNING: TE Router ID present multiple times.\n");
1238 stream_forward_getp(s, tlv_len);
1239 return 0;
1240 }
1241
1242 tlvs->te_router_id = XCALLOC(MTYPE_ISIS_TLV, 4);
1243 stream_get(tlvs->te_router_id, s, 4);
1244 format_tlv_te_router_id(tlvs->te_router_id, log, indent + 2);
1245 return 0;
1246 }
1247
1248
1249 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
1250
1251 static struct isis_item *copy_item_extended_ip_reach(struct isis_item *i)
1252 {
1253 struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
1254 struct isis_extended_ip_reach *rv =
1255 XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1256
1257 rv->metric = r->metric;
1258 rv->down = r->down;
1259 rv->prefix = r->prefix;
1260
1261 return (struct isis_item *)rv;
1262 }
1263
1264 static void format_item_extended_ip_reach(uint16_t mtid, struct isis_item *i,
1265 struct sbuf *buf, int indent)
1266 {
1267 struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
1268 char prefixbuf[PREFIX2STR_BUFFER];
1269
1270 sbuf_push(buf, indent, "%s IP Reachability: %s (Metric: %u)%s",
1271 (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT",
1272 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), r->metric,
1273 r->down ? " Down" : "");
1274 if (mtid != ISIS_MT_IPV4_UNICAST)
1275 sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
1276 sbuf_push(buf, 0, "\n");
1277
1278 if (r->subtlvs) {
1279 sbuf_push(buf, indent, " Subtlvs:\n");
1280 format_subtlvs(r->subtlvs, buf, indent + 4);
1281 }
1282 }
1283
1284 static void free_item_extended_ip_reach(struct isis_item *i)
1285 {
1286 struct isis_extended_ip_reach *item =
1287 (struct isis_extended_ip_reach *)i;
1288 isis_free_subtlvs(item->subtlvs);
1289 XFREE(MTYPE_ISIS_TLV, item);
1290 }
1291
1292 static int pack_item_extended_ip_reach(struct isis_item *i, struct stream *s)
1293 {
1294 struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
1295 uint8_t control;
1296
1297 if (STREAM_WRITEABLE(s) < 5)
1298 return 1;
1299 stream_putl(s, r->metric);
1300
1301 control = r->down ? ISIS_EXTENDED_IP_REACH_DOWN : 0;
1302 control |= r->prefix.prefixlen;
1303 control |= r->subtlvs ? ISIS_EXTENDED_IP_REACH_SUBTLV : 0;
1304
1305 stream_putc(s, control);
1306
1307 if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen))
1308 return 1;
1309 stream_put(s, &r->prefix.prefix.s_addr, PSIZE(r->prefix.prefixlen));
1310
1311 if (r->subtlvs)
1312 return pack_subtlvs(r->subtlvs, s);
1313 return 0;
1314 }
1315
1316 static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len,
1317 struct stream *s, struct sbuf *log,
1318 void *dest, int indent)
1319 {
1320 struct isis_tlvs *tlvs = dest;
1321 struct isis_extended_ip_reach *rv = NULL;
1322 size_t consume;
1323 uint8_t control, subtlv_len;
1324 struct isis_item_list *items;
1325
1326 if (mtid == ISIS_MT_IPV4_UNICAST) {
1327 items = &tlvs->extended_ip_reach;
1328 } else {
1329 items = isis_get_mt_items(&tlvs->mt_ip_reach, mtid);
1330 }
1331
1332 sbuf_push(log, indent, "Unpacking %s IPv4 reachability...\n",
1333 (mtid == ISIS_MT_IPV4_UNICAST) ? "extended" : "mt");
1334
1335 consume = 5;
1336 if (len < consume) {
1337 sbuf_push(log, indent,
1338 "Not enough data left. (expected 5 or more bytes, got %" PRIu8 ")\n",
1339 len);
1340 goto out;
1341 }
1342
1343 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1344
1345 rv->metric = stream_getl(s);
1346 control = stream_getc(s);
1347 rv->down = (control & ISIS_EXTENDED_IP_REACH_DOWN);
1348 rv->prefix.family = AF_INET;
1349 rv->prefix.prefixlen = control & 0x3f;
1350 if (rv->prefix.prefixlen > 32) {
1351 sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv4\n",
1352 rv->prefix.prefixlen);
1353 goto out;
1354 }
1355
1356 consume += PSIZE(rv->prefix.prefixlen);
1357 if (len < consume) {
1358 sbuf_push(log, indent,
1359 "Expected %u bytes of prefix, but only %u bytes available.\n",
1360 PSIZE(rv->prefix.prefixlen), len - 5);
1361 goto out;
1362 }
1363 stream_get(&rv->prefix.prefix.s_addr, s, PSIZE(rv->prefix.prefixlen));
1364 in_addr_t orig_prefix = rv->prefix.prefix.s_addr;
1365 apply_mask_ipv4(&rv->prefix);
1366 if (orig_prefix != rv->prefix.prefix.s_addr)
1367 sbuf_push(log, indent + 2,
1368 "WARNING: Prefix had hostbits set.\n");
1369 format_item_extended_ip_reach(mtid, (struct isis_item *)rv, log,
1370 indent + 2);
1371
1372 if (control & ISIS_EXTENDED_IP_REACH_SUBTLV) {
1373 consume += 1;
1374 if (len < consume) {
1375 sbuf_push(log, indent,
1376 "Expected 1 byte of subtlv len, but no more data present.\n");
1377 goto out;
1378 }
1379 subtlv_len = stream_getc(s);
1380
1381 if (!subtlv_len) {
1382 sbuf_push(log, indent + 2,
1383 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
1384 }
1385 consume += subtlv_len;
1386 if (len < consume) {
1387 sbuf_push(log, indent,
1388 "Expected %" PRIu8
1389 " bytes of subtlvs, but only %u bytes available.\n",
1390 subtlv_len,
1391 len - 6 - PSIZE(rv->prefix.prefixlen));
1392 goto out;
1393 }
1394
1395 rv->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH);
1396 bool unpacked_known_tlvs = false;
1397
1398 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH, subtlv_len, s,
1399 log, rv->subtlvs, indent + 4, &unpacked_known_tlvs)) {
1400 goto out;
1401 }
1402 if (!unpacked_known_tlvs) {
1403 isis_free_subtlvs(rv->subtlvs);
1404 rv->subtlvs = NULL;
1405 }
1406 }
1407
1408 append_item(items, (struct isis_item *)rv);
1409 return 0;
1410 out:
1411 if (rv)
1412 free_item_extended_ip_reach((struct isis_item *)rv);
1413 return 1;
1414 }
1415
1416 /* Functions related to TLV 137 Dynamic Hostname */
1417
1418 static char *copy_tlv_dynamic_hostname(const char *hostname)
1419 {
1420 if (!hostname)
1421 return NULL;
1422
1423 return XSTRDUP(MTYPE_ISIS_TLV, hostname);
1424 }
1425
1426 static void format_tlv_dynamic_hostname(const char *hostname, struct sbuf *buf,
1427 int indent)
1428 {
1429 if (!hostname)
1430 return;
1431
1432 sbuf_push(buf, indent, "Hostname: %s\n", hostname);
1433 }
1434
1435 static void free_tlv_dynamic_hostname(char *hostname)
1436 {
1437 XFREE(MTYPE_ISIS_TLV, hostname);
1438 }
1439
1440 static int pack_tlv_dynamic_hostname(const char *hostname, struct stream *s)
1441 {
1442 if (!hostname)
1443 return 0;
1444
1445 uint8_t name_len = strlen(hostname);
1446
1447 if (STREAM_WRITEABLE(s) < (unsigned)(2 + name_len))
1448 return 1;
1449
1450 stream_putc(s, ISIS_TLV_DYNAMIC_HOSTNAME);
1451 stream_putc(s, name_len);
1452 stream_put(s, hostname, name_len);
1453 return 0;
1454 }
1455
1456 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context,
1457 uint8_t tlv_type, uint8_t tlv_len,
1458 struct stream *s, struct sbuf *log,
1459 void *dest, int indent)
1460 {
1461 struct isis_tlvs *tlvs = dest;
1462
1463 sbuf_push(log, indent, "Unpacking Dynamic Hostname TLV...\n");
1464 if (!tlv_len) {
1465 sbuf_push(log, indent, "WARNING: No hostname included\n");
1466 return 0;
1467 }
1468
1469 if (tlvs->hostname) {
1470 sbuf_push(log, indent,
1471 "WARNING: Hostname present multiple times.\n");
1472 stream_forward_getp(s, tlv_len);
1473 return 0;
1474 }
1475
1476 tlvs->hostname = XCALLOC(MTYPE_ISIS_TLV, tlv_len + 1);
1477 stream_get(tlvs->hostname, s, tlv_len);
1478 tlvs->hostname[tlv_len] = '\0';
1479
1480 bool sane = true;
1481 for (uint8_t i = 0; i < tlv_len; i++) {
1482 if ((unsigned char)tlvs->hostname[i] > 127
1483 || !isprint((unsigned char)tlvs->hostname[i])) {
1484 sane = false;
1485 tlvs->hostname[i] = '?';
1486 }
1487 }
1488 if (!sane) {
1489 sbuf_push(
1490 log, indent,
1491 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
1492 }
1493
1494 return 0;
1495 }
1496
1497 /* Functions related to TLV 150 Spine-Leaf-Extension */
1498
1499 static struct isis_spine_leaf *copy_tlv_spine_leaf(
1500 const struct isis_spine_leaf *spine_leaf)
1501 {
1502 if (!spine_leaf)
1503 return NULL;
1504
1505 struct isis_spine_leaf *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1506 memcpy(rv, spine_leaf, sizeof(*rv));
1507
1508 return rv;
1509 }
1510
1511 static void format_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf,
1512 struct sbuf *buf, int indent)
1513 {
1514 if (!spine_leaf)
1515 return;
1516
1517 sbuf_push(buf, indent, "Spine-Leaf-Extension:\n");
1518 if (spine_leaf->has_tier) {
1519 if (spine_leaf->tier == ISIS_TIER_UNDEFINED) {
1520 sbuf_push(buf, indent, " Tier: undefined\n");
1521 } else {
1522 sbuf_push(buf, indent, " Tier: %" PRIu8 "\n",
1523 spine_leaf->tier);
1524 }
1525 }
1526
1527 sbuf_push(buf, indent, " Flags:%s%s%s\n",
1528 spine_leaf->is_leaf ? " LEAF" : "",
1529 spine_leaf->is_spine ? " SPINE" : "",
1530 spine_leaf->is_backup ? " BACKUP" : "");
1531
1532 }
1533
1534 static void free_tlv_spine_leaf(struct isis_spine_leaf *spine_leaf)
1535 {
1536 XFREE(MTYPE_ISIS_TLV, spine_leaf);
1537 }
1538
1539 #define ISIS_SPINE_LEAF_FLAG_TIER 0x08
1540 #define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
1541 #define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
1542 #define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
1543
1544 static int pack_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf,
1545 struct stream *s)
1546 {
1547 if (!spine_leaf)
1548 return 0;
1549
1550 uint8_t tlv_len = 2;
1551
1552 if (STREAM_WRITEABLE(s) < (unsigned)(2 + tlv_len))
1553 return 1;
1554
1555 stream_putc(s, ISIS_TLV_SPINE_LEAF_EXT);
1556 stream_putc(s, tlv_len);
1557
1558 uint16_t spine_leaf_flags = 0;
1559
1560 if (spine_leaf->has_tier) {
1561 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_TIER;
1562 spine_leaf_flags |= spine_leaf->tier << 12;
1563 }
1564
1565 if (spine_leaf->is_leaf)
1566 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_LEAF;
1567
1568 if (spine_leaf->is_spine)
1569 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_SPINE;
1570
1571 if (spine_leaf->is_backup)
1572 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_BACKUP;
1573
1574 stream_putw(s, spine_leaf_flags);
1575
1576 return 0;
1577 }
1578
1579 static int unpack_tlv_spine_leaf(enum isis_tlv_context context,
1580 uint8_t tlv_type, uint8_t tlv_len,
1581 struct stream *s, struct sbuf *log,
1582 void *dest, int indent)
1583 {
1584 struct isis_tlvs *tlvs = dest;
1585
1586 sbuf_push(log, indent, "Unpacking Spine Leaf Extension TLV...\n");
1587 if (tlv_len < 2) {
1588 sbuf_push(log, indent, "WARNING: Unexepected TLV size\n");
1589 stream_forward_getp(s, tlv_len);
1590 return 0;
1591 }
1592
1593 if (tlvs->spine_leaf) {
1594 sbuf_push(log, indent,
1595 "WARNING: Spine Leaf Extension TLV present multiple times.\n");
1596 stream_forward_getp(s, tlv_len);
1597 return 0;
1598 }
1599
1600 tlvs->spine_leaf = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->spine_leaf));
1601
1602 uint16_t spine_leaf_flags = stream_getw(s);
1603
1604 if (spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_TIER) {
1605 tlvs->spine_leaf->has_tier = true;
1606 tlvs->spine_leaf->tier = spine_leaf_flags >> 12;
1607 }
1608
1609 tlvs->spine_leaf->is_leaf = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_LEAF;
1610 tlvs->spine_leaf->is_spine = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_SPINE;
1611 tlvs->spine_leaf->is_backup = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_BACKUP;
1612
1613 stream_forward_getp(s, tlv_len - 2);
1614 return 0;
1615 }
1616
1617 /* Functions related to TLV 240 P2P Three-Way Adjacency */
1618
1619 const char *isis_threeway_state_name(enum isis_threeway_state state)
1620 {
1621 switch (state) {
1622 case ISIS_THREEWAY_DOWN:
1623 return "Down";
1624 case ISIS_THREEWAY_INITIALIZING:
1625 return "Initializing";
1626 case ISIS_THREEWAY_UP:
1627 return "Up";
1628 default:
1629 return "Invalid!";
1630 }
1631 }
1632
1633 static struct isis_threeway_adj *copy_tlv_threeway_adj(
1634 const struct isis_threeway_adj *threeway_adj)
1635 {
1636 if (!threeway_adj)
1637 return NULL;
1638
1639 struct isis_threeway_adj *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1640 memcpy(rv, threeway_adj, sizeof(*rv));
1641
1642 return rv;
1643 }
1644
1645 static void format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj,
1646 struct sbuf *buf, int indent)
1647 {
1648 if (!threeway_adj)
1649 return;
1650
1651 sbuf_push(buf, indent, "P2P Three-Way Adjacency:\n");
1652 sbuf_push(buf, indent, " State: %s (%d)\n",
1653 isis_threeway_state_name(threeway_adj->state),
1654 threeway_adj->state);
1655 sbuf_push(buf, indent, " Extended Local Circuit ID: %" PRIu32 "\n",
1656 threeway_adj->local_circuit_id);
1657 if (!threeway_adj->neighbor_set)
1658 return;
1659
1660 sbuf_push(buf, indent, " Neighbor System ID: %s\n",
1661 isis_format_id(threeway_adj->neighbor_id, 6));
1662 sbuf_push(buf, indent, " Neighbor Extended Circuit ID: %" PRIu32 "\n",
1663 threeway_adj->neighbor_circuit_id);
1664 }
1665
1666 static void free_tlv_threeway_adj(struct isis_threeway_adj *threeway_adj)
1667 {
1668 XFREE(MTYPE_ISIS_TLV, threeway_adj);
1669 }
1670
1671 static int pack_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj,
1672 struct stream *s)
1673 {
1674 if (!threeway_adj)
1675 return 0;
1676
1677 uint8_t tlv_len = (threeway_adj->neighbor_set) ? 15 : 5;
1678
1679 if (STREAM_WRITEABLE(s) < (unsigned)(2 + tlv_len))
1680 return 1;
1681
1682 stream_putc(s, ISIS_TLV_THREE_WAY_ADJ);
1683 stream_putc(s, tlv_len);
1684 stream_putc(s, threeway_adj->state);
1685 stream_putl(s, threeway_adj->local_circuit_id);
1686
1687 if (threeway_adj->neighbor_set) {
1688 stream_put(s, threeway_adj->neighbor_id, 6);
1689 stream_putl(s, threeway_adj->neighbor_circuit_id);
1690 }
1691
1692 return 0;
1693 }
1694
1695 static int unpack_tlv_threeway_adj(enum isis_tlv_context context,
1696 uint8_t tlv_type, uint8_t tlv_len,
1697 struct stream *s, struct sbuf *log,
1698 void *dest, int indent)
1699 {
1700 struct isis_tlvs *tlvs = dest;
1701
1702 sbuf_push(log, indent, "Unpacking P2P Three-Way Adjacency TLV...\n");
1703 if (tlv_len != 5 && tlv_len != 15) {
1704 sbuf_push(log, indent, "WARNING: Unexepected TLV size\n");
1705 stream_forward_getp(s, tlv_len);
1706 return 0;
1707 }
1708
1709 if (tlvs->threeway_adj) {
1710 sbuf_push(log, indent,
1711 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
1712 stream_forward_getp(s, tlv_len);
1713 return 0;
1714 }
1715
1716 tlvs->threeway_adj = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->threeway_adj));
1717
1718 tlvs->threeway_adj->state = stream_getc(s);
1719 tlvs->threeway_adj->local_circuit_id = stream_getl(s);
1720
1721 if (tlv_len == 15) {
1722 tlvs->threeway_adj->neighbor_set = true;
1723 stream_get(tlvs->threeway_adj->neighbor_id, s, 6);
1724 tlvs->threeway_adj->neighbor_circuit_id = stream_getl(s);
1725 }
1726
1727 return 0;
1728 }
1729
1730 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
1731
1732 static struct isis_item *copy_item_ipv6_reach(struct isis_item *i)
1733 {
1734 struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
1735 struct isis_ipv6_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1736 rv->metric = r->metric;
1737 rv->down = r->down;
1738 rv->external = r->external;
1739 rv->prefix = r->prefix;
1740 rv->subtlvs = copy_subtlvs(r->subtlvs);
1741
1742 return (struct isis_item *)rv;
1743 }
1744
1745 static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i,
1746 struct sbuf *buf, int indent)
1747 {
1748 struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
1749 char prefixbuf[PREFIX2STR_BUFFER];
1750
1751 sbuf_push(buf, indent, "%sIPv6 Reachability: %s (Metric: %u)%s%s",
1752 (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "MT ",
1753 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)),
1754 r->metric,
1755 r->down ? " Down" : "",
1756 r->external ? " External" : "");
1757 if (mtid != ISIS_MT_IPV4_UNICAST)
1758 sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
1759 sbuf_push(buf, 0, "\n");
1760
1761 if (r->subtlvs) {
1762 sbuf_push(buf, indent, " Subtlvs:\n");
1763 format_subtlvs(r->subtlvs, buf, indent + 4);
1764 }
1765 }
1766
1767 static void free_item_ipv6_reach(struct isis_item *i)
1768 {
1769 struct isis_ipv6_reach *item = (struct isis_ipv6_reach *)i;
1770
1771 isis_free_subtlvs(item->subtlvs);
1772 XFREE(MTYPE_ISIS_TLV, item);
1773 }
1774
1775 static int pack_item_ipv6_reach(struct isis_item *i, struct stream *s)
1776 {
1777 struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
1778 uint8_t control;
1779
1780 if (STREAM_WRITEABLE(s) < 6)
1781 return 1;
1782 stream_putl(s, r->metric);
1783
1784 control = r->down ? ISIS_IPV6_REACH_DOWN : 0;
1785 control |= r->external ? ISIS_IPV6_REACH_EXTERNAL : 0;
1786 control |= r->subtlvs ? ISIS_IPV6_REACH_SUBTLV : 0;
1787
1788 stream_putc(s, control);
1789 stream_putc(s, r->prefix.prefixlen);
1790
1791 if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen))
1792 return 1;
1793 stream_put(s, &r->prefix.prefix.s6_addr, PSIZE(r->prefix.prefixlen));
1794
1795 if (r->subtlvs)
1796 return pack_subtlvs(r->subtlvs, s);
1797
1798 return 0;
1799 }
1800
1801 static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s,
1802 struct sbuf *log, void *dest, int indent)
1803 {
1804 struct isis_tlvs *tlvs = dest;
1805 struct isis_ipv6_reach *rv = NULL;
1806 size_t consume;
1807 uint8_t control, subtlv_len;
1808 struct isis_item_list *items;
1809
1810 if (mtid == ISIS_MT_IPV4_UNICAST) {
1811 items = &tlvs->ipv6_reach;
1812 } else {
1813 items = isis_get_mt_items(&tlvs->mt_ipv6_reach, mtid);
1814 }
1815
1816 sbuf_push(log, indent, "Unpacking %sIPv6 reachability...\n",
1817 (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "mt ");
1818 consume = 6;
1819 if (len < consume) {
1820 sbuf_push(log, indent,
1821 "Not enough data left. (expected 6 or more bytes, got %"
1822 PRIu8 ")\n",
1823 len);
1824 goto out;
1825 }
1826
1827 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1828
1829 rv->metric = stream_getl(s);
1830 control = stream_getc(s);
1831 rv->down = (control & ISIS_IPV6_REACH_DOWN);
1832 rv->external = (control & ISIS_IPV6_REACH_EXTERNAL);
1833
1834 rv->prefix.family = AF_INET6;
1835 rv->prefix.prefixlen = stream_getc(s);
1836 if (rv->prefix.prefixlen > 128) {
1837 sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv6\n",
1838 rv->prefix.prefixlen);
1839 goto out;
1840 }
1841
1842 consume += PSIZE(rv->prefix.prefixlen);
1843 if (len < consume) {
1844 sbuf_push(log, indent,
1845 "Expected %u bytes of prefix, but only %u bytes available.\n",
1846 PSIZE(rv->prefix.prefixlen), len - 6);
1847 goto out;
1848 }
1849 stream_get(&rv->prefix.prefix.s6_addr, s, PSIZE(rv->prefix.prefixlen));
1850 struct in6_addr orig_prefix = rv->prefix.prefix;
1851 apply_mask_ipv6(&rv->prefix);
1852 if (memcmp(&orig_prefix, &rv->prefix.prefix, sizeof(orig_prefix)))
1853 sbuf_push(log, indent + 2,
1854 "WARNING: Prefix had hostbits set.\n");
1855 format_item_ipv6_reach(mtid, (struct isis_item *)rv, log, indent + 2);
1856
1857 if (control & ISIS_IPV6_REACH_SUBTLV) {
1858 consume += 1;
1859 if (len < consume) {
1860 sbuf_push(log, indent,
1861 "Expected 1 byte of subtlv len, but no more data persent.\n");
1862 goto out;
1863 }
1864 subtlv_len = stream_getc(s);
1865
1866 if (!subtlv_len) {
1867 sbuf_push(log, indent + 2,
1868 " WARNING: subtlv bit set, but there are no subtlvs.\n");
1869 }
1870 consume += subtlv_len;
1871 if (len < consume) {
1872 sbuf_push(log, indent,
1873 "Expected %" PRIu8
1874 " bytes of subtlvs, but only %u bytes available.\n",
1875 subtlv_len,
1876 len - 6 - PSIZE(rv->prefix.prefixlen));
1877 goto out;
1878 }
1879
1880 rv->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH);
1881 bool unpacked_known_tlvs = false;
1882
1883 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH, subtlv_len, s,
1884 log, rv->subtlvs, indent + 4, &unpacked_known_tlvs)) {
1885 goto out;
1886 }
1887 if (!unpacked_known_tlvs) {
1888 isis_free_subtlvs(rv->subtlvs);
1889 rv->subtlvs = NULL;
1890 }
1891 }
1892
1893 append_item(items, (struct isis_item *)rv);
1894 return 0;
1895 out:
1896 if (rv)
1897 free_item_ipv6_reach((struct isis_item *)rv);
1898 return 1;
1899 }
1900
1901 /* Functions related to TLV 10 Authentication */
1902 static struct isis_item *copy_item_auth(struct isis_item *i)
1903 {
1904 struct isis_auth *auth = (struct isis_auth *)i;
1905 struct isis_auth *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1906
1907 rv->type = auth->type;
1908 rv->length = auth->length;
1909 memcpy(rv->value, auth->value, sizeof(rv->value));
1910 return (struct isis_item *)rv;
1911 }
1912
1913 static void format_item_auth(uint16_t mtid, struct isis_item *i,
1914 struct sbuf *buf, int indent)
1915 {
1916 struct isis_auth *auth = (struct isis_auth *)i;
1917 char obuf[768];
1918
1919 sbuf_push(buf, indent, "Authentication:\n");
1920 switch (auth->type) {
1921 case ISIS_PASSWD_TYPE_CLEARTXT:
1922 zlog_sanitize(obuf, sizeof(obuf), auth->value, auth->length);
1923 sbuf_push(buf, indent, " Password: %s\n", obuf);
1924 break;
1925 case ISIS_PASSWD_TYPE_HMAC_MD5:
1926 for (unsigned int j = 0; j < 16; j++) {
1927 snprintf(obuf + 2 * j, sizeof(obuf) - 2 * j,
1928 "%02" PRIx8, auth->value[j]);
1929 }
1930 sbuf_push(buf, indent, " HMAC-MD5: %s\n", obuf);
1931 break;
1932 default:
1933 sbuf_push(buf, indent, " Unknown (%" PRIu8 ")\n", auth->type);
1934 break;
1935 }
1936 }
1937
1938 static void free_item_auth(struct isis_item *i)
1939 {
1940 XFREE(MTYPE_ISIS_TLV, i);
1941 }
1942
1943 static int pack_item_auth(struct isis_item *i, struct stream *s)
1944 {
1945 struct isis_auth *auth = (struct isis_auth *)i;
1946
1947 if (STREAM_WRITEABLE(s) < 1)
1948 return 1;
1949 stream_putc(s, auth->type);
1950
1951 switch (auth->type) {
1952 case ISIS_PASSWD_TYPE_CLEARTXT:
1953 if (STREAM_WRITEABLE(s) < auth->length)
1954 return 1;
1955 stream_put(s, auth->passwd, auth->length);
1956 break;
1957 case ISIS_PASSWD_TYPE_HMAC_MD5:
1958 if (STREAM_WRITEABLE(s) < 16)
1959 return 1;
1960 auth->offset = stream_get_endp(s);
1961 stream_put(s, NULL, 16);
1962 break;
1963 default:
1964 return 1;
1965 }
1966
1967 return 0;
1968 }
1969
1970 static int unpack_item_auth(uint16_t mtid, uint8_t len, struct stream *s,
1971 struct sbuf *log, void *dest, int indent)
1972 {
1973 struct isis_tlvs *tlvs = dest;
1974
1975 sbuf_push(log, indent, "Unpack Auth TLV...\n");
1976 if (len < 1) {
1977 sbuf_push(
1978 log, indent,
1979 "Not enough data left.(Expected 1 bytes of auth type, got %" PRIu8
1980 ")\n",
1981 len);
1982 return 1;
1983 }
1984
1985 struct isis_auth *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1986
1987 rv->type = stream_getc(s);
1988 rv->length = len - 1;
1989
1990 if (rv->type == ISIS_PASSWD_TYPE_HMAC_MD5 && rv->length != 16) {
1991 sbuf_push(
1992 log, indent,
1993 "Unexpected auth length for HMAC-MD5 (expected 16, got %" PRIu8
1994 ")\n",
1995 rv->length);
1996 XFREE(MTYPE_ISIS_TLV, rv);
1997 return 1;
1998 }
1999
2000 rv->offset = stream_get_getp(s);
2001 stream_get(rv->value, s, rv->length);
2002 format_item_auth(mtid, (struct isis_item *)rv, log, indent + 2);
2003 append_item(&tlvs->isis_auth, (struct isis_item *)rv);
2004 return 0;
2005 }
2006
2007 /* Functions related to TLV 13 Purge Originator */
2008
2009 static struct isis_purge_originator *copy_tlv_purge_originator(
2010 struct isis_purge_originator *poi)
2011 {
2012 if (!poi)
2013 return NULL;
2014
2015 struct isis_purge_originator *rv;
2016
2017 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2018 rv->sender_set = poi->sender_set;
2019 memcpy(rv->generator, poi->generator, sizeof(rv->generator));
2020 if (poi->sender_set)
2021 memcpy(rv->sender, poi->sender, sizeof(rv->sender));
2022 return rv;
2023 }
2024
2025 static void format_tlv_purge_originator(struct isis_purge_originator *poi,
2026 struct sbuf *buf, int indent)
2027 {
2028 if (!poi)
2029 return;
2030
2031 sbuf_push(buf, indent, "Purge Originator Identification:\n");
2032 sbuf_push(buf, indent, " Generator: %s\n",
2033 isis_format_id(poi->generator, sizeof(poi->generator)));
2034 if (poi->sender_set) {
2035 sbuf_push(buf, indent, " Received-From: %s\n",
2036 isis_format_id(poi->sender, sizeof(poi->sender)));
2037 }
2038 }
2039
2040 static void free_tlv_purge_originator(struct isis_purge_originator *poi)
2041 {
2042 XFREE(MTYPE_ISIS_TLV, poi);
2043 }
2044
2045 static int pack_tlv_purge_originator(struct isis_purge_originator *poi,
2046 struct stream *s)
2047 {
2048 if (!poi)
2049 return 0;
2050
2051 uint8_t data_len = 1 + sizeof(poi->generator);
2052
2053 if (poi->sender_set)
2054 data_len += sizeof(poi->sender);
2055
2056 if (STREAM_WRITEABLE(s) < (unsigned)(2 + data_len))
2057 return 1;
2058
2059 stream_putc(s, ISIS_TLV_PURGE_ORIGINATOR);
2060 stream_putc(s, data_len);
2061 stream_putc(s, poi->sender_set ? 2 : 1);
2062 stream_put(s, poi->generator, sizeof(poi->generator));
2063 if (poi->sender_set)
2064 stream_put(s, poi->sender, sizeof(poi->sender));
2065 return 0;
2066 }
2067
2068 static int unpack_tlv_purge_originator(enum isis_tlv_context context,
2069 uint8_t tlv_type, uint8_t tlv_len,
2070 struct stream *s, struct sbuf *log,
2071 void *dest, int indent)
2072 {
2073 struct isis_tlvs *tlvs = dest;
2074 struct isis_purge_originator poi = {};
2075
2076 sbuf_push(log, indent, "Unpacking Purge Originator Identification TLV...\n");
2077 if (tlv_len < 7) {
2078 sbuf_push(log, indent, "Not enough data left. (Expected at least 7 bytes, got %"
2079 PRIu8 ")\n", tlv_len);
2080 return 1;
2081 }
2082
2083 uint8_t number_of_ids = stream_getc(s);
2084
2085 if (number_of_ids == 1) {
2086 poi.sender_set = false;
2087 } else if (number_of_ids == 2) {
2088 poi.sender_set = true;
2089 } else {
2090 sbuf_push(log, indent, "Got invalid value for number of system IDs: %"
2091 PRIu8 ")\n", number_of_ids);
2092 return 1;
2093 }
2094
2095 if (tlv_len != 1 + 6 * number_of_ids) {
2096 sbuf_push(log, indent, "Incorrect tlv len for number of IDs.\n");
2097 return 1;
2098 }
2099
2100 stream_get(poi.generator, s, sizeof(poi.generator));
2101 if (poi.sender_set)
2102 stream_get(poi.sender, s, sizeof(poi.sender));
2103
2104 if (tlvs->purge_originator) {
2105 sbuf_push(log, indent,
2106 "WARNING: Purge originator present multiple times, ignoring.\n");
2107 return 0;
2108 }
2109
2110 tlvs->purge_originator = copy_tlv_purge_originator(&poi);
2111 return 0;
2112 }
2113
2114
2115 /* Functions relating to item TLVs */
2116
2117 static void init_item_list(struct isis_item_list *items)
2118 {
2119 items->head = NULL;
2120 items->tail = &items->head;
2121 items->count = 0;
2122 }
2123
2124 static struct isis_item *copy_item(enum isis_tlv_context context,
2125 enum isis_tlv_type type,
2126 struct isis_item *item)
2127 {
2128 const struct tlv_ops *ops = tlv_table[context][type];
2129
2130 if (ops && ops->copy_item)
2131 return ops->copy_item(item);
2132
2133 assert(!"Unknown item tlv type!");
2134 return NULL;
2135 }
2136
2137 static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type,
2138 struct isis_item_list *src, struct isis_item_list *dest)
2139 {
2140 struct isis_item *item;
2141
2142 init_item_list(dest);
2143
2144 for (item = src->head; item; item = item->next) {
2145 append_item(dest, copy_item(context, type, item));
2146 }
2147 }
2148
2149 static void format_item(uint16_t mtid, enum isis_tlv_context context,
2150 enum isis_tlv_type type, struct isis_item *i,
2151 struct sbuf *buf, int indent)
2152 {
2153 const struct tlv_ops *ops = tlv_table[context][type];
2154
2155 if (ops && ops->format_item) {
2156 ops->format_item(mtid, i, buf, indent);
2157 return;
2158 }
2159
2160 assert(!"Unknown item tlv type!");
2161 }
2162
2163 static void format_items_(uint16_t mtid, enum isis_tlv_context context,
2164 enum isis_tlv_type type, struct isis_item_list *items,
2165 struct sbuf *buf, int indent)
2166 {
2167 struct isis_item *i;
2168
2169 for (i = items->head; i; i = i->next)
2170 format_item(mtid, context, type, i, buf, indent);
2171 }
2172
2173 static void free_item(enum isis_tlv_context tlv_context,
2174 enum isis_tlv_type tlv_type, struct isis_item *item)
2175 {
2176 const struct tlv_ops *ops = tlv_table[tlv_context][tlv_type];
2177
2178 if (ops && ops->free_item) {
2179 ops->free_item(item);
2180 return;
2181 }
2182
2183 assert(!"Unknown item tlv type!");
2184 }
2185
2186 static void free_items(enum isis_tlv_context context, enum isis_tlv_type type,
2187 struct isis_item_list *items)
2188 {
2189 struct isis_item *item, *next_item;
2190
2191 for (item = items->head; item; item = next_item) {
2192 next_item = item->next;
2193 free_item(context, type, item);
2194 }
2195 }
2196
2197 static int pack_item(enum isis_tlv_context context, enum isis_tlv_type type,
2198 struct isis_item *i, struct stream *s,
2199 struct isis_tlvs **fragment_tlvs,
2200 struct pack_order_entry *pe, uint16_t mtid)
2201 {
2202 const struct tlv_ops *ops = tlv_table[context][type];
2203
2204 if (ops && ops->pack_item) {
2205 return ops->pack_item(i, s);
2206 }
2207
2208 assert(!"Unknown item tlv type!");
2209 return 1;
2210 }
2211
2212 static void add_item_to_fragment(struct isis_item *i, struct pack_order_entry *pe,
2213 struct isis_tlvs *fragment_tlvs, uint16_t mtid)
2214 {
2215 struct isis_item_list *l;
2216
2217 if (pe->how_to_pack == ISIS_ITEMS) {
2218 l = (struct isis_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack);
2219 } else {
2220 struct isis_mt_item_list *m;
2221 m = (struct isis_mt_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack);
2222 l = isis_get_mt_items(m, mtid);
2223 }
2224
2225 append_item(l, copy_item(pe->context, pe->type, i));
2226 }
2227
2228 static int pack_items_(uint16_t mtid, enum isis_tlv_context context,
2229 enum isis_tlv_type type, struct isis_item_list *items,
2230 struct stream *s, struct isis_tlvs **fragment_tlvs,
2231 struct pack_order_entry *pe,
2232 struct isis_tlvs *(*new_fragment)(struct list *l),
2233 struct list *new_fragment_arg)
2234 {
2235 size_t len_pos, last_len, len;
2236 struct isis_item *item = NULL;
2237 int rv;
2238
2239 if (!items->head)
2240 return 0;
2241
2242 top:
2243 if (STREAM_WRITEABLE(s) < 2)
2244 goto too_long;
2245
2246 stream_putc(s, type);
2247 len_pos = stream_get_endp(s);
2248 stream_putc(s, 0); /* Put 0 as length for now */
2249
2250 if (context == ISIS_CONTEXT_LSP && IS_COMPAT_MT_TLV(type)
2251 && mtid != ISIS_MT_IPV4_UNICAST) {
2252 if (STREAM_WRITEABLE(s) < 2)
2253 goto too_long;
2254 stream_putw(s, mtid);
2255 }
2256
2257 if (context == ISIS_CONTEXT_LSP && type == ISIS_TLV_OLDSTYLE_REACH) {
2258 if (STREAM_WRITEABLE(s) < 1)
2259 goto too_long;
2260 stream_putc(s, 0); /* Virtual flag is set to 0 */
2261 }
2262
2263 last_len = len = 0;
2264 for (item = item ? item : items->head; item; item = item->next) {
2265 rv = pack_item(context, type, item, s, fragment_tlvs, pe, mtid);
2266 if (rv)
2267 goto too_long;
2268
2269 len = stream_get_endp(s) - len_pos - 1;
2270
2271 /* Multiple auths don't go into one TLV, so always break */
2272 if (context == ISIS_CONTEXT_LSP && type == ISIS_TLV_AUTH) {
2273 item = item->next;
2274 break;
2275 }
2276
2277 /* Multiple prefix-sids don't go into one TLV, so always break */
2278 if (type == ISIS_SUBTLV_PREFIX_SID
2279 && (context == ISIS_CONTEXT_SUBTLV_IP_REACH
2280 || context == ISIS_CONTEXT_SUBTLV_IPV6_REACH)) {
2281 item = item->next;
2282 break;
2283 }
2284
2285 if (len > 255) {
2286 if (!last_len) /* strange, not a single item fit */
2287 return 1;
2288 /* drop last tlv, otherwise, its too long */
2289 stream_set_endp(s, len_pos + 1 + last_len);
2290 len = last_len;
2291 break;
2292 }
2293
2294 if (fragment_tlvs)
2295 add_item_to_fragment(item, pe, *fragment_tlvs, mtid);
2296
2297 last_len = len;
2298 }
2299
2300 stream_putc_at(s, len_pos, len);
2301 if (item)
2302 goto top;
2303
2304 return 0;
2305 too_long:
2306 if (!fragment_tlvs)
2307 return 1;
2308 stream_reset(s);
2309 *fragment_tlvs = new_fragment(new_fragment_arg);
2310 goto top;
2311 }
2312 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
2313
2314 static void append_item(struct isis_item_list *dest, struct isis_item *item)
2315 {
2316 *dest->tail = item;
2317 dest->tail = &(*dest->tail)->next;
2318 dest->count++;
2319 }
2320
2321 static struct isis_item *last_item(struct isis_item_list *list)
2322 {
2323 return container_of(list->tail, struct isis_item, next);
2324 }
2325
2326 static int unpack_item(uint16_t mtid, enum isis_tlv_context context,
2327 uint8_t tlv_type, uint8_t len, struct stream *s,
2328 struct sbuf *log, void *dest, int indent)
2329 {
2330 const struct tlv_ops *ops = tlv_table[context][tlv_type];
2331
2332 if (ops && ops->unpack_item)
2333 return ops->unpack_item(mtid, len, s, log, dest, indent);
2334
2335 assert(!"Unknown item tlv type!");
2336 sbuf_push(log, indent, "Unknown item tlv type!\n");
2337 return 1;
2338 }
2339
2340 static int unpack_tlv_with_items(enum isis_tlv_context context,
2341 uint8_t tlv_type, uint8_t tlv_len,
2342 struct stream *s, struct sbuf *log, void *dest,
2343 int indent)
2344 {
2345 size_t tlv_start;
2346 size_t tlv_pos;
2347 int rv;
2348 uint16_t mtid;
2349
2350 tlv_start = stream_get_getp(s);
2351 tlv_pos = 0;
2352
2353 if (context == ISIS_CONTEXT_LSP && IS_COMPAT_MT_TLV(tlv_type)) {
2354 if (tlv_len < 2) {
2355 sbuf_push(log, indent,
2356 "TLV is too short to contain MTID\n");
2357 return 1;
2358 }
2359 mtid = stream_getw(s) & ISIS_MT_MASK;
2360 tlv_pos += 2;
2361 sbuf_push(log, indent, "Unpacking as MT %s item TLV...\n",
2362 isis_mtid2str(mtid));
2363 } else {
2364 sbuf_push(log, indent, "Unpacking as item TLV...\n");
2365 mtid = ISIS_MT_IPV4_UNICAST;
2366 }
2367
2368 if (context == ISIS_CONTEXT_LSP
2369 && tlv_type == ISIS_TLV_OLDSTYLE_REACH) {
2370 if (tlv_len - tlv_pos < 1) {
2371 sbuf_push(log, indent,
2372 "TLV is too short for old style reach\n");
2373 return 1;
2374 }
2375 stream_forward_getp(s, 1);
2376 tlv_pos += 1;
2377 }
2378
2379 if (context == ISIS_CONTEXT_LSP
2380 && tlv_type == ISIS_TLV_OLDSTYLE_IP_REACH) {
2381 struct isis_tlvs *tlvs = dest;
2382 dest = &tlvs->oldstyle_ip_reach;
2383 } else if (context == ISIS_CONTEXT_LSP
2384 && tlv_type == ISIS_TLV_OLDSTYLE_IP_REACH_EXT) {
2385 struct isis_tlvs *tlvs = dest;
2386 dest = &tlvs->oldstyle_ip_reach_ext;
2387 }
2388
2389 if (context == ISIS_CONTEXT_LSP
2390 && tlv_type == ISIS_TLV_MT_ROUTER_INFO) {
2391 struct isis_tlvs *tlvs = dest;
2392 tlvs->mt_router_info_empty = (tlv_pos >= (size_t)tlv_len);
2393 }
2394
2395 while (tlv_pos < (size_t)tlv_len) {
2396 rv = unpack_item(mtid, context, tlv_type, tlv_len - tlv_pos, s,
2397 log, dest, indent + 2);
2398 if (rv)
2399 return rv;
2400
2401 tlv_pos = stream_get_getp(s) - tlv_start;
2402 }
2403
2404 return 0;
2405 }
2406
2407 /* Functions to manipulate mt_item_lists */
2408
2409 static int isis_mt_item_list_cmp(const struct isis_item_list *a,
2410 const struct isis_item_list *b)
2411 {
2412 if (a->mtid < b->mtid)
2413 return -1;
2414 if (a->mtid > b->mtid)
2415 return 1;
2416 return 0;
2417 }
2418
2419 RB_PROTOTYPE(isis_mt_item_list, isis_item_list, mt_tree, isis_mt_item_list_cmp);
2420 RB_GENERATE(isis_mt_item_list, isis_item_list, mt_tree, isis_mt_item_list_cmp);
2421
2422 struct isis_item_list *isis_get_mt_items(struct isis_mt_item_list *m,
2423 uint16_t mtid)
2424 {
2425 struct isis_item_list *rv;
2426
2427 rv = isis_lookup_mt_items(m, mtid);
2428 if (!rv) {
2429 rv = XCALLOC(MTYPE_ISIS_MT_ITEM_LIST, sizeof(*rv));
2430 init_item_list(rv);
2431 rv->mtid = mtid;
2432 RB_INSERT(isis_mt_item_list, m, rv);
2433 }
2434
2435 return rv;
2436 }
2437
2438 struct isis_item_list *isis_lookup_mt_items(struct isis_mt_item_list *m,
2439 uint16_t mtid)
2440 {
2441 struct isis_item_list key = {.mtid = mtid};
2442
2443 return RB_FIND(isis_mt_item_list, m, &key);
2444 }
2445
2446 static void free_mt_items(enum isis_tlv_context context,
2447 enum isis_tlv_type type, struct isis_mt_item_list *m)
2448 {
2449 struct isis_item_list *n, *nnext;
2450
2451 RB_FOREACH_SAFE (n, isis_mt_item_list, m, nnext) {
2452 free_items(context, type, n);
2453 RB_REMOVE(isis_mt_item_list, m, n);
2454 XFREE(MTYPE_ISIS_MT_ITEM_LIST, n);
2455 }
2456 }
2457
2458 static void format_mt_items(enum isis_tlv_context context,
2459 enum isis_tlv_type type,
2460 struct isis_mt_item_list *m, struct sbuf *buf,
2461 int indent)
2462 {
2463 struct isis_item_list *n;
2464
2465 RB_FOREACH (n, isis_mt_item_list, m) {
2466 format_items_(n->mtid, context, type, n, buf, indent);
2467 }
2468 }
2469
2470 static int pack_mt_items(enum isis_tlv_context context, enum isis_tlv_type type,
2471 struct isis_mt_item_list *m, struct stream *s,
2472 struct isis_tlvs **fragment_tlvs,
2473 struct pack_order_entry *pe,
2474 struct isis_tlvs *(*new_fragment)(struct list *l),
2475 struct list *new_fragment_arg)
2476 {
2477 struct isis_item_list *n;
2478
2479 RB_FOREACH (n, isis_mt_item_list, m) {
2480 int rv;
2481
2482 rv = pack_items_(n->mtid, context, type, n, s, fragment_tlvs,
2483 pe, new_fragment, new_fragment_arg);
2484 if (rv)
2485 return rv;
2486 }
2487
2488 return 0;
2489 }
2490
2491 static void copy_mt_items(enum isis_tlv_context context,
2492 enum isis_tlv_type type,
2493 struct isis_mt_item_list *src,
2494 struct isis_mt_item_list *dest)
2495 {
2496 struct isis_item_list *n;
2497
2498 RB_INIT(isis_mt_item_list, dest);
2499
2500 RB_FOREACH (n, isis_mt_item_list, src) {
2501 copy_items(context, type, n, isis_get_mt_items(dest, n->mtid));
2502 }
2503 }
2504
2505 /* Functions related to tlvs in general */
2506
2507 struct isis_tlvs *isis_alloc_tlvs(void)
2508 {
2509 struct isis_tlvs *result;
2510
2511 result = XCALLOC(MTYPE_ISIS_TLV, sizeof(*result));
2512
2513 init_item_list(&result->isis_auth);
2514 init_item_list(&result->area_addresses);
2515 init_item_list(&result->mt_router_info);
2516 init_item_list(&result->oldstyle_reach);
2517 init_item_list(&result->lan_neighbor);
2518 init_item_list(&result->lsp_entries);
2519 init_item_list(&result->extended_reach);
2520 RB_INIT(isis_mt_item_list, &result->mt_reach);
2521 init_item_list(&result->oldstyle_ip_reach);
2522 init_item_list(&result->oldstyle_ip_reach_ext);
2523 init_item_list(&result->ipv4_address);
2524 init_item_list(&result->ipv6_address);
2525 init_item_list(&result->extended_ip_reach);
2526 RB_INIT(isis_mt_item_list, &result->mt_ip_reach);
2527 init_item_list(&result->ipv6_reach);
2528 RB_INIT(isis_mt_item_list, &result->mt_ipv6_reach);
2529
2530 return result;
2531 }
2532
2533 struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs)
2534 {
2535 struct isis_tlvs *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2536
2537 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth,
2538 &rv->isis_auth);
2539
2540 rv->purge_originator =
2541 copy_tlv_purge_originator(tlvs->purge_originator);
2542
2543 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
2544 &tlvs->area_addresses, &rv->area_addresses);
2545
2546 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
2547 &tlvs->mt_router_info, &rv->mt_router_info);
2548
2549 rv->mt_router_info_empty = tlvs->mt_router_info_empty;
2550
2551 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
2552 &tlvs->oldstyle_reach, &rv->oldstyle_reach);
2553
2554 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
2555 &tlvs->lan_neighbor, &rv->lan_neighbor);
2556
2557 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries,
2558 &rv->lsp_entries);
2559
2560 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
2561 &tlvs->extended_reach, &rv->extended_reach);
2562
2563 copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach,
2564 &rv->mt_reach);
2565
2566 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
2567 &tlvs->oldstyle_ip_reach, &rv->oldstyle_ip_reach);
2568
2569 copy_tlv_protocols_supported(&tlvs->protocols_supported,
2570 &rv->protocols_supported);
2571
2572 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
2573 &tlvs->oldstyle_ip_reach_ext, &rv->oldstyle_ip_reach_ext);
2574
2575 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS, &tlvs->ipv4_address,
2576 &rv->ipv4_address);
2577
2578 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS, &tlvs->ipv6_address,
2579 &rv->ipv6_address);
2580
2581 rv->te_router_id = copy_tlv_te_router_id(tlvs->te_router_id);
2582
2583 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
2584 &tlvs->extended_ip_reach, &rv->extended_ip_reach);
2585
2586 copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
2587 &tlvs->mt_ip_reach, &rv->mt_ip_reach);
2588
2589 rv->hostname = copy_tlv_dynamic_hostname(tlvs->hostname);
2590
2591 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach,
2592 &rv->ipv6_reach);
2593
2594 copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
2595 &tlvs->mt_ipv6_reach, &rv->mt_ipv6_reach);
2596
2597 rv->threeway_adj = copy_tlv_threeway_adj(tlvs->threeway_adj);
2598
2599 rv->spine_leaf = copy_tlv_spine_leaf(tlvs->spine_leaf);
2600
2601 return rv;
2602 }
2603
2604 static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent)
2605 {
2606 format_tlv_protocols_supported(&tlvs->protocols_supported, buf, indent);
2607
2608 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth, buf,
2609 indent);
2610
2611 format_tlv_purge_originator(tlvs->purge_originator, buf, indent);
2612
2613 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
2614 &tlvs->area_addresses, buf, indent);
2615
2616 if (tlvs->mt_router_info_empty) {
2617 sbuf_push(buf, indent, "MT Router Info: None\n");
2618 } else {
2619 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
2620 &tlvs->mt_router_info, buf, indent);
2621 }
2622
2623 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
2624 &tlvs->oldstyle_reach, buf, indent);
2625
2626 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
2627 &tlvs->lan_neighbor, buf, indent);
2628
2629 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries,
2630 buf, indent);
2631
2632 format_tlv_dynamic_hostname(tlvs->hostname, buf, indent);
2633 format_tlv_te_router_id(tlvs->te_router_id, buf, indent);
2634
2635 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
2636 &tlvs->extended_reach, buf, indent);
2637
2638 format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach,
2639 buf, indent);
2640
2641 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
2642 &tlvs->oldstyle_ip_reach, buf, indent);
2643
2644 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
2645 &tlvs->oldstyle_ip_reach_ext, buf, indent);
2646
2647 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS,
2648 &tlvs->ipv4_address, buf, indent);
2649
2650 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS,
2651 &tlvs->ipv6_address, buf, indent);
2652
2653 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
2654 &tlvs->extended_ip_reach, buf, indent);
2655
2656 format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
2657 &tlvs->mt_ip_reach, buf, indent);
2658
2659 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach,
2660 buf, indent);
2661
2662 format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
2663 &tlvs->mt_ipv6_reach, buf, indent);
2664
2665 format_tlv_threeway_adj(tlvs->threeway_adj, buf, indent);
2666
2667 format_tlv_spine_leaf(tlvs->spine_leaf, buf, indent);
2668 }
2669
2670 const char *isis_format_tlvs(struct isis_tlvs *tlvs)
2671 {
2672 static struct sbuf buf;
2673
2674 if (!sbuf_buf(&buf))
2675 sbuf_init(&buf, NULL, 0);
2676
2677 sbuf_reset(&buf);
2678 format_tlvs(tlvs, &buf, 0);
2679 return sbuf_buf(&buf);
2680 }
2681
2682 void isis_free_tlvs(struct isis_tlvs *tlvs)
2683 {
2684 if (!tlvs)
2685 return;
2686
2687 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth);
2688 free_tlv_purge_originator(tlvs->purge_originator);
2689 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
2690 &tlvs->area_addresses);
2691 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
2692 &tlvs->mt_router_info);
2693 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
2694 &tlvs->oldstyle_reach);
2695 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
2696 &tlvs->lan_neighbor);
2697 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries);
2698 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
2699 &tlvs->extended_reach);
2700 free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach);
2701 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
2702 &tlvs->oldstyle_ip_reach);
2703 free_tlv_protocols_supported(&tlvs->protocols_supported);
2704 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
2705 &tlvs->oldstyle_ip_reach_ext);
2706 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS,
2707 &tlvs->ipv4_address);
2708 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS,
2709 &tlvs->ipv6_address);
2710 free_tlv_te_router_id(tlvs->te_router_id);
2711 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
2712 &tlvs->extended_ip_reach);
2713 free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
2714 &tlvs->mt_ip_reach);
2715 free_tlv_dynamic_hostname(tlvs->hostname);
2716 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach);
2717 free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
2718 &tlvs->mt_ipv6_reach);
2719 free_tlv_threeway_adj(tlvs->threeway_adj);
2720 free_tlv_spine_leaf(tlvs->spine_leaf);
2721
2722 XFREE(MTYPE_ISIS_TLV, tlvs);
2723 }
2724
2725 static void add_padding(struct stream *s)
2726 {
2727 while (STREAM_WRITEABLE(s)) {
2728 if (STREAM_WRITEABLE(s) == 1)
2729 break;
2730 uint32_t padding_len = STREAM_WRITEABLE(s) - 2;
2731
2732 if (padding_len > 255) {
2733 if (padding_len == 256)
2734 padding_len = 254;
2735 else
2736 padding_len = 255;
2737 }
2738
2739 stream_putc(s, ISIS_TLV_PADDING);
2740 stream_putc(s, padding_len);
2741 stream_put(s, NULL, padding_len);
2742 }
2743 }
2744
2745 #define LSP_REM_LIFETIME_OFF 10
2746 #define LSP_CHECKSUM_OFF 24
2747 static void safe_auth_md5(struct stream *s, uint16_t *checksum,
2748 uint16_t *rem_lifetime)
2749 {
2750 memcpy(rem_lifetime, STREAM_DATA(s) + LSP_REM_LIFETIME_OFF,
2751 sizeof(*rem_lifetime));
2752 memset(STREAM_DATA(s) + LSP_REM_LIFETIME_OFF, 0, sizeof(*rem_lifetime));
2753 memcpy(checksum, STREAM_DATA(s) + LSP_CHECKSUM_OFF, sizeof(*checksum));
2754 memset(STREAM_DATA(s) + LSP_CHECKSUM_OFF, 0, sizeof(*checksum));
2755 }
2756
2757 static void restore_auth_md5(struct stream *s, uint16_t checksum,
2758 uint16_t rem_lifetime)
2759 {
2760 memcpy(STREAM_DATA(s) + LSP_REM_LIFETIME_OFF, &rem_lifetime,
2761 sizeof(rem_lifetime));
2762 memcpy(STREAM_DATA(s) + LSP_CHECKSUM_OFF, &checksum, sizeof(checksum));
2763 }
2764
2765 static void update_auth_hmac_md5(struct isis_auth *auth, struct stream *s,
2766 bool is_lsp)
2767 {
2768 uint8_t digest[16];
2769 uint16_t checksum, rem_lifetime;
2770
2771 if (is_lsp)
2772 safe_auth_md5(s, &checksum, &rem_lifetime);
2773
2774 memset(STREAM_DATA(s) + auth->offset, 0, 16);
2775 #ifdef CRYPTO_OPENSSL
2776 uint8_t *result = (uint8_t *)HMAC(EVP_md5(), auth->passwd,
2777 auth->plength, STREAM_DATA(s),
2778 stream_get_endp(s), NULL, NULL);
2779
2780 memcpy(digest, result, 16);
2781 #elif CRYPTO_INTERNAL
2782 hmac_md5(STREAM_DATA(s), stream_get_endp(s), auth->passwd,
2783 auth->plength, digest);
2784 #endif
2785 memcpy(auth->value, digest, 16);
2786 memcpy(STREAM_DATA(s) + auth->offset, digest, 16);
2787
2788 if (is_lsp)
2789 restore_auth_md5(s, checksum, rem_lifetime);
2790 }
2791
2792 static void update_auth(struct isis_tlvs *tlvs, struct stream *s, bool is_lsp)
2793 {
2794 struct isis_auth *auth_head = (struct isis_auth *)tlvs->isis_auth.head;
2795
2796 for (struct isis_auth *auth = auth_head; auth; auth = auth->next) {
2797 if (auth->type == ISIS_PASSWD_TYPE_HMAC_MD5)
2798 update_auth_hmac_md5(auth, s, is_lsp);
2799 }
2800 }
2801
2802 static int handle_pack_entry(struct pack_order_entry *pe,
2803 struct isis_tlvs *tlvs, struct stream *stream,
2804 struct isis_tlvs **fragment_tlvs,
2805 struct isis_tlvs *(*new_fragment)(struct list *l),
2806 struct list *new_fragment_arg)
2807 {
2808 int rv;
2809
2810 if (pe->how_to_pack == ISIS_ITEMS) {
2811 struct isis_item_list *l;
2812 l = (struct isis_item_list *)(((char *)tlvs)
2813 + pe->what_to_pack);
2814 rv = pack_items(pe->context, pe->type, l, stream, fragment_tlvs,
2815 pe, new_fragment, new_fragment_arg);
2816 } else {
2817 struct isis_mt_item_list *l;
2818 l = (struct isis_mt_item_list *)(((char *)tlvs)
2819 + pe->what_to_pack);
2820 rv = pack_mt_items(pe->context, pe->type, l, stream,
2821 fragment_tlvs, pe, new_fragment,
2822 new_fragment_arg);
2823 }
2824
2825 return rv;
2826 }
2827
2828 static int pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
2829 struct isis_tlvs *fragment_tlvs,
2830 struct isis_tlvs *(*new_fragment)(struct list *l),
2831 struct list *new_fragment_arg)
2832 {
2833 int rv;
2834
2835 /* When fragmenting, don't add auth as it's already accounted for in the
2836 * size we are given. */
2837 if (!fragment_tlvs) {
2838 rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH,
2839 &tlvs->isis_auth, stream, NULL, NULL, NULL,
2840 NULL);
2841 if (rv)
2842 return rv;
2843 }
2844
2845 rv = pack_tlv_purge_originator(tlvs->purge_originator, stream);
2846 if (rv)
2847 return rv;
2848 if (fragment_tlvs) {
2849 fragment_tlvs->purge_originator =
2850 copy_tlv_purge_originator(tlvs->purge_originator);
2851 }
2852
2853 rv = pack_tlv_protocols_supported(&tlvs->protocols_supported, stream);
2854 if (rv)
2855 return rv;
2856 if (fragment_tlvs) {
2857 copy_tlv_protocols_supported(
2858 &tlvs->protocols_supported,
2859 &fragment_tlvs->protocols_supported);
2860 }
2861
2862 rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
2863 &tlvs->area_addresses, stream, NULL, NULL, NULL, NULL);
2864 if (rv)
2865 return rv;
2866 if (fragment_tlvs) {
2867 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
2868 &tlvs->area_addresses,
2869 &fragment_tlvs->area_addresses);
2870 }
2871
2872
2873 if (tlvs->mt_router_info_empty) {
2874 if (STREAM_WRITEABLE(stream) < 2)
2875 return 1;
2876 stream_putc(stream, ISIS_TLV_MT_ROUTER_INFO);
2877 stream_putc(stream, 0);
2878 if (fragment_tlvs)
2879 fragment_tlvs->mt_router_info_empty = true;
2880 } else {
2881 rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
2882 &tlvs->mt_router_info, stream, NULL, NULL, NULL,
2883 NULL);
2884 if (rv)
2885 return rv;
2886 if (fragment_tlvs) {
2887 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
2888 &tlvs->mt_router_info,
2889 &fragment_tlvs->mt_router_info);
2890 }
2891 }
2892
2893 rv = pack_tlv_dynamic_hostname(tlvs->hostname, stream);
2894 if (rv)
2895 return rv;
2896 if (fragment_tlvs)
2897 fragment_tlvs->hostname =
2898 copy_tlv_dynamic_hostname(tlvs->hostname);
2899
2900 rv = pack_tlv_te_router_id(tlvs->te_router_id, stream);
2901 if (rv)
2902 return rv;
2903 if (fragment_tlvs) {
2904 fragment_tlvs->te_router_id =
2905 copy_tlv_te_router_id(tlvs->te_router_id);
2906 }
2907
2908 rv = pack_tlv_threeway_adj(tlvs->threeway_adj, stream);
2909 if (rv)
2910 return rv;
2911 if (fragment_tlvs) {
2912 fragment_tlvs->threeway_adj =
2913 copy_tlv_threeway_adj(tlvs->threeway_adj);
2914 }
2915
2916 rv = pack_tlv_spine_leaf(tlvs->spine_leaf, stream);
2917 if (rv)
2918 return rv;
2919 if (fragment_tlvs) {
2920 fragment_tlvs->spine_leaf =
2921 copy_tlv_spine_leaf(tlvs->spine_leaf);
2922 }
2923
2924 for (size_t pack_idx = 0; pack_idx < array_size(pack_order);
2925 pack_idx++) {
2926 rv = handle_pack_entry(&pack_order[pack_idx], tlvs, stream,
2927 fragment_tlvs ? &fragment_tlvs : NULL,
2928 new_fragment, new_fragment_arg);
2929
2930 if (rv)
2931 return rv;
2932 }
2933
2934 return 0;
2935 }
2936
2937 int isis_pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
2938 size_t len_pointer, bool pad, bool is_lsp)
2939 {
2940 int rv;
2941
2942 rv = pack_tlvs(tlvs, stream, NULL, NULL, NULL);
2943 if (rv)
2944 return rv;
2945
2946 if (pad)
2947 add_padding(stream);
2948
2949 if (len_pointer != (size_t)-1) {
2950 stream_putw_at(stream, len_pointer, stream_get_endp(stream));
2951 }
2952
2953 update_auth(tlvs, stream, is_lsp);
2954
2955 return 0;
2956 }
2957
2958 static struct isis_tlvs *new_fragment(struct list *l)
2959 {
2960 struct isis_tlvs *rv = isis_alloc_tlvs();
2961
2962 listnode_add(l, rv);
2963 return rv;
2964 }
2965
2966 struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size)
2967 {
2968 struct stream *dummy_stream = stream_new(size);
2969 struct list *rv = list_new();
2970 struct isis_tlvs *fragment_tlvs = new_fragment(rv);
2971
2972 if (pack_tlvs(tlvs, dummy_stream, fragment_tlvs, new_fragment, rv)) {
2973 struct listnode *node;
2974 for (ALL_LIST_ELEMENTS_RO(rv, node, fragment_tlvs))
2975 isis_free_tlvs(fragment_tlvs);
2976 list_delete(&rv);
2977 }
2978
2979 stream_free(dummy_stream);
2980 return rv;
2981 }
2982
2983 static int unpack_tlv_unknown(enum isis_tlv_context context, uint8_t tlv_type,
2984 uint8_t tlv_len, struct stream *s,
2985 struct sbuf *log, int indent)
2986 {
2987 stream_forward_getp(s, tlv_len);
2988 sbuf_push(log, indent,
2989 "Skipping unknown TLV %" PRIu8 " (%" PRIu8 " bytes)\n",
2990 tlv_type, tlv_len);
2991 return 0;
2992 }
2993
2994 static int unpack_tlv(enum isis_tlv_context context, size_t avail_len,
2995 struct stream *stream, struct sbuf *log, void *dest,
2996 int indent, bool *unpacked_known_tlvs)
2997 {
2998 uint8_t tlv_type, tlv_len;
2999 const struct tlv_ops *ops;
3000
3001 sbuf_push(log, indent, "Unpacking TLV...\n");
3002
3003 if (avail_len < 2) {
3004 sbuf_push(
3005 log, indent + 2,
3006 "Available data %zu too short to contain a TLV header.\n",
3007 avail_len);
3008 return 1;
3009 }
3010
3011 tlv_type = stream_getc(stream);
3012 tlv_len = stream_getc(stream);
3013
3014 sbuf_push(log, indent + 2,
3015 "Found TLV of type %" PRIu8 " and len %" PRIu8 ".\n",
3016 tlv_type, tlv_len);
3017
3018 if (avail_len < ((size_t)tlv_len) + 2) {
3019 sbuf_push(log, indent + 2,
3020 "Available data %zu too short for claimed TLV len %" PRIu8 ".\n",
3021 avail_len - 2, tlv_len);
3022 return 1;
3023 }
3024
3025 ops = tlv_table[context][tlv_type];
3026 if (ops && ops->unpack) {
3027 if (unpacked_known_tlvs)
3028 *unpacked_known_tlvs = true;
3029 return ops->unpack(context, tlv_type, tlv_len, stream, log,
3030 dest, indent + 2);
3031 }
3032
3033 return unpack_tlv_unknown(context, tlv_type, tlv_len, stream, log,
3034 indent + 2);
3035 }
3036
3037 static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len,
3038 struct stream *stream, struct sbuf *log, void *dest,
3039 int indent, bool *unpacked_known_tlvs)
3040 {
3041 int rv;
3042 size_t tlv_start, tlv_pos;
3043
3044 tlv_start = stream_get_getp(stream);
3045 tlv_pos = 0;
3046
3047 sbuf_push(log, indent, "Unpacking %zu bytes of %s...\n", avail_len,
3048 (context == ISIS_CONTEXT_LSP) ? "TLVs" : "sub-TLVs");
3049
3050 while (tlv_pos < avail_len) {
3051 rv = unpack_tlv(context, avail_len - tlv_pos, stream, log, dest,
3052 indent + 2, unpacked_known_tlvs);
3053 if (rv)
3054 return rv;
3055
3056 tlv_pos = stream_get_getp(stream) - tlv_start;
3057 }
3058
3059 return 0;
3060 }
3061
3062 int isis_unpack_tlvs(size_t avail_len, struct stream *stream,
3063 struct isis_tlvs **dest, const char **log)
3064 {
3065 static struct sbuf logbuf;
3066 int indent = 0;
3067 int rv;
3068 struct isis_tlvs *result;
3069
3070 if (!sbuf_buf(&logbuf))
3071 sbuf_init(&logbuf, NULL, 0);
3072
3073 sbuf_reset(&logbuf);
3074 if (avail_len > STREAM_READABLE(stream)) {
3075 sbuf_push(&logbuf, indent,
3076 "Stream doesn't contain sufficient data. "
3077 "Claimed %zu, available %zu\n",
3078 avail_len, STREAM_READABLE(stream));
3079 return 1;
3080 }
3081
3082 result = isis_alloc_tlvs();
3083 rv = unpack_tlvs(ISIS_CONTEXT_LSP, avail_len, stream, &logbuf, result,
3084 indent, NULL);
3085
3086 *log = sbuf_buf(&logbuf);
3087 *dest = result;
3088
3089 return rv;
3090 }
3091
3092 #define TLV_OPS(_name_, _desc_) \
3093 static const struct tlv_ops tlv_##_name_##_ops = { \
3094 .name = _desc_, .unpack = unpack_tlv_##_name_, \
3095 }
3096
3097 #define ITEM_TLV_OPS(_name_, _desc_) \
3098 static const struct tlv_ops tlv_##_name_##_ops = { \
3099 .name = _desc_, \
3100 .unpack = unpack_tlv_with_items, \
3101 \
3102 .pack_item = pack_item_##_name_, \
3103 .free_item = free_item_##_name_, \
3104 .unpack_item = unpack_item_##_name_, \
3105 .format_item = format_item_##_name_, \
3106 .copy_item = copy_item_##_name_}
3107
3108 #define SUBTLV_OPS(_name_, _desc_) \
3109 static const struct tlv_ops subtlv_##_name_##_ops = { \
3110 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
3111 }
3112
3113 #define ITEM_SUBTLV_OPS(_name_, _desc_) \
3114 ITEM_TLV_OPS(_name_, _desc_)
3115
3116 ITEM_TLV_OPS(area_address, "TLV 1 Area Addresses");
3117 ITEM_TLV_OPS(oldstyle_reach, "TLV 2 IS Reachability");
3118 ITEM_TLV_OPS(lan_neighbor, "TLV 6 LAN Neighbors");
3119 ITEM_TLV_OPS(lsp_entry, "TLV 9 LSP Entries");
3120 ITEM_TLV_OPS(auth, "TLV 10 IS-IS Auth");
3121 TLV_OPS(purge_originator, "TLV 13 Purge Originator Identification");
3122 ITEM_TLV_OPS(extended_reach, "TLV 22 Extended Reachability");
3123 ITEM_TLV_OPS(oldstyle_ip_reach, "TLV 128/130 IP Reachability");
3124 TLV_OPS(protocols_supported, "TLV 129 Protocols Supported");
3125 ITEM_TLV_OPS(ipv4_address, "TLV 132 IPv4 Interface Address");
3126 TLV_OPS(te_router_id, "TLV 134 TE Router ID");
3127 ITEM_TLV_OPS(extended_ip_reach, "TLV 135 Extended IP Reachability");
3128 TLV_OPS(dynamic_hostname, "TLV 137 Dynamic Hostname");
3129 TLV_OPS(spine_leaf, "TLV 150 Spine Leaf Extensions");
3130 ITEM_TLV_OPS(mt_router_info, "TLV 229 MT Router Information");
3131 TLV_OPS(threeway_adj, "TLV 240 P2P Three-Way Adjacency");
3132 ITEM_TLV_OPS(ipv6_address, "TLV 232 IPv6 Interface Address");
3133 ITEM_TLV_OPS(ipv6_reach, "TLV 236 IPv6 Reachability");
3134
3135 ITEM_SUBTLV_OPS(prefix_sid, "Sub-TLV 3 SR Prefix-SID");
3136 SUBTLV_OPS(ipv6_source_prefix, "Sub-TLV 22 IPv6 Source Prefix");
3137
3138 static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
3139 [ISIS_CONTEXT_LSP] = {
3140 [ISIS_TLV_AREA_ADDRESSES] = &tlv_area_address_ops,
3141 [ISIS_TLV_OLDSTYLE_REACH] = &tlv_oldstyle_reach_ops,
3142 [ISIS_TLV_LAN_NEIGHBORS] = &tlv_lan_neighbor_ops,
3143 [ISIS_TLV_LSP_ENTRY] = &tlv_lsp_entry_ops,
3144 [ISIS_TLV_AUTH] = &tlv_auth_ops,
3145 [ISIS_TLV_PURGE_ORIGINATOR] = &tlv_purge_originator_ops,
3146 [ISIS_TLV_EXTENDED_REACH] = &tlv_extended_reach_ops,
3147 [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops,
3148 [ISIS_TLV_OLDSTYLE_IP_REACH] = &tlv_oldstyle_ip_reach_ops,
3149 [ISIS_TLV_PROTOCOLS_SUPPORTED] = &tlv_protocols_supported_ops,
3150 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT] = &tlv_oldstyle_ip_reach_ops,
3151 [ISIS_TLV_IPV4_ADDRESS] = &tlv_ipv4_address_ops,
3152 [ISIS_TLV_TE_ROUTER_ID] = &tlv_te_router_id_ops,
3153 [ISIS_TLV_EXTENDED_IP_REACH] = &tlv_extended_ip_reach_ops,
3154 [ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops,
3155 [ISIS_TLV_DYNAMIC_HOSTNAME] = &tlv_dynamic_hostname_ops,
3156 [ISIS_TLV_SPINE_LEAF_EXT] = &tlv_spine_leaf_ops,
3157 [ISIS_TLV_MT_ROUTER_INFO] = &tlv_mt_router_info_ops,
3158 [ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops,
3159 [ISIS_TLV_IPV6_ADDRESS] = &tlv_ipv6_address_ops,
3160 [ISIS_TLV_IPV6_REACH] = &tlv_ipv6_reach_ops,
3161 [ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops,
3162 },
3163 [ISIS_CONTEXT_SUBTLV_NE_REACH] = {},
3164 [ISIS_CONTEXT_SUBTLV_IP_REACH] = {
3165 [ISIS_SUBTLV_PREFIX_SID] = &tlv_prefix_sid_ops,
3166 },
3167 [ISIS_CONTEXT_SUBTLV_IPV6_REACH] = {
3168 [ISIS_SUBTLV_PREFIX_SID] = &tlv_prefix_sid_ops,
3169 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX] = &subtlv_ipv6_source_prefix_ops,
3170 }
3171 };
3172
3173 /* Accessor functions */
3174
3175 void isis_tlvs_add_auth(struct isis_tlvs *tlvs, struct isis_passwd *passwd)
3176 {
3177 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth);
3178 init_item_list(&tlvs->isis_auth);
3179
3180 if (passwd->type == ISIS_PASSWD_TYPE_UNUSED)
3181 return;
3182
3183 struct isis_auth *auth = XCALLOC(MTYPE_ISIS_TLV, sizeof(*auth));
3184
3185 auth->type = passwd->type;
3186
3187 auth->plength = passwd->len;
3188 memcpy(auth->passwd, passwd->passwd,
3189 MIN(sizeof(auth->passwd), sizeof(passwd->passwd)));
3190
3191 if (auth->type == ISIS_PASSWD_TYPE_CLEARTXT) {
3192 auth->length = passwd->len;
3193 memcpy(auth->value, passwd->passwd,
3194 MIN(sizeof(auth->value), sizeof(passwd->passwd)));
3195 }
3196
3197 append_item(&tlvs->isis_auth, (struct isis_item *)auth);
3198 }
3199
3200 void isis_tlvs_add_area_addresses(struct isis_tlvs *tlvs,
3201 struct list *addresses)
3202 {
3203 struct listnode *node;
3204 struct area_addr *area_addr;
3205
3206 for (ALL_LIST_ELEMENTS_RO(addresses, node, area_addr)) {
3207 struct isis_area_address *a =
3208 XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
3209
3210 a->len = area_addr->addr_len;
3211 memcpy(a->addr, area_addr->area_addr, 20);
3212 append_item(&tlvs->area_addresses, (struct isis_item *)a);
3213 }
3214 }
3215
3216 void isis_tlvs_add_lan_neighbors(struct isis_tlvs *tlvs, struct list *neighbors)
3217 {
3218 struct listnode *node;
3219 uint8_t *snpa;
3220
3221 for (ALL_LIST_ELEMENTS_RO(neighbors, node, snpa)) {
3222 struct isis_lan_neighbor *n =
3223 XCALLOC(MTYPE_ISIS_TLV, sizeof(*n));
3224
3225 memcpy(n->mac, snpa, 6);
3226 append_item(&tlvs->lan_neighbor, (struct isis_item *)n);
3227 }
3228 }
3229
3230 void isis_tlvs_set_protocols_supported(struct isis_tlvs *tlvs,
3231 struct nlpids *nlpids)
3232 {
3233 tlvs->protocols_supported.count = nlpids->count;
3234 XFREE(MTYPE_ISIS_TLV, tlvs->protocols_supported.protocols);
3235 if (nlpids->count) {
3236 tlvs->protocols_supported.protocols =
3237 XCALLOC(MTYPE_ISIS_TLV, nlpids->count);
3238 memcpy(tlvs->protocols_supported.protocols, nlpids->nlpids,
3239 nlpids->count);
3240 } else {
3241 tlvs->protocols_supported.protocols = NULL;
3242 }
3243 }
3244
3245 void isis_tlvs_add_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid,
3246 bool overload, bool attached)
3247 {
3248 struct isis_mt_router_info *i = XCALLOC(MTYPE_ISIS_TLV, sizeof(*i));
3249
3250 i->overload = overload;
3251 i->attached = attached;
3252 i->mtid = mtid;
3253 append_item(&tlvs->mt_router_info, (struct isis_item *)i);
3254 }
3255
3256 void isis_tlvs_add_ipv4_address(struct isis_tlvs *tlvs, struct in_addr *addr)
3257 {
3258 struct isis_ipv4_address *a = XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
3259 a->addr = *addr;
3260 append_item(&tlvs->ipv4_address, (struct isis_item *)a);
3261 }
3262
3263
3264 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs *tlvs,
3265 struct list *addresses)
3266 {
3267 struct listnode *node;
3268 struct prefix_ipv4 *ip_addr;
3269 unsigned int addr_count = 0;
3270
3271 for (ALL_LIST_ELEMENTS_RO(addresses, node, ip_addr)) {
3272 isis_tlvs_add_ipv4_address(tlvs, &ip_addr->prefix);
3273 addr_count++;
3274 if (addr_count >= 63)
3275 break;
3276 }
3277 }
3278
3279 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs *tlvs,
3280 struct list *addresses)
3281 {
3282 struct listnode *node;
3283 struct prefix_ipv6 *ip_addr;
3284 unsigned int addr_count = 0;
3285
3286 for (ALL_LIST_ELEMENTS_RO(addresses, node, ip_addr)) {
3287 if (addr_count >= 15)
3288 break;
3289
3290 struct isis_ipv6_address *a =
3291 XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
3292
3293 a->addr = ip_addr->prefix;
3294 append_item(&tlvs->ipv6_address, (struct isis_item *)a);
3295 addr_count++;
3296 }
3297 }
3298
3299 typedef bool (*auth_validator_func)(struct isis_passwd *passwd,
3300 struct stream *stream,
3301 struct isis_auth *auth, bool is_lsp);
3302
3303 static bool auth_validator_cleartxt(struct isis_passwd *passwd,
3304 struct stream *stream,
3305 struct isis_auth *auth, bool is_lsp)
3306 {
3307 return (auth->length == passwd->len
3308 && !memcmp(auth->value, passwd->passwd, passwd->len));
3309 }
3310
3311 static bool auth_validator_hmac_md5(struct isis_passwd *passwd,
3312 struct stream *stream,
3313 struct isis_auth *auth, bool is_lsp)
3314 {
3315 uint8_t digest[16];
3316 uint16_t checksum;
3317 uint16_t rem_lifetime;
3318
3319 if (is_lsp)
3320 safe_auth_md5(stream, &checksum, &rem_lifetime);
3321
3322 memset(STREAM_DATA(stream) + auth->offset, 0, 16);
3323 #ifdef CRYPTO_OPENSSL
3324 uint8_t *result = (uint8_t *)HMAC(EVP_md5(), passwd->passwd,
3325 passwd->len, STREAM_DATA(stream),
3326 stream_get_endp(stream), NULL, NULL);
3327
3328 memcpy(digest, result, 16);
3329 #elif CRYPTO_INTERNAL
3330 hmac_md5(STREAM_DATA(stream), stream_get_endp(stream), passwd->passwd,
3331 passwd->len, digest);
3332 #endif
3333 memcpy(STREAM_DATA(stream) + auth->offset, auth->value, 16);
3334
3335 bool rv = !memcmp(digest, auth->value, 16);
3336
3337 if (is_lsp)
3338 restore_auth_md5(stream, checksum, rem_lifetime);
3339
3340 return rv;
3341 }
3342
3343 static const auth_validator_func auth_validators[] = {
3344 [ISIS_PASSWD_TYPE_CLEARTXT] = auth_validator_cleartxt,
3345 [ISIS_PASSWD_TYPE_HMAC_MD5] = auth_validator_hmac_md5,
3346 };
3347
3348 int isis_tlvs_auth_is_valid(struct isis_tlvs *tlvs, struct isis_passwd *passwd,
3349 struct stream *stream, bool is_lsp)
3350 {
3351 /* If no auth is set, always pass authentication */
3352 if (!passwd->type)
3353 return ISIS_AUTH_OK;
3354
3355 /* If we don't known how to validate the auth, return invalid */
3356 if (passwd->type >= array_size(auth_validators)
3357 || !auth_validators[passwd->type])
3358 return ISIS_AUTH_NO_VALIDATOR;
3359
3360 struct isis_auth *auth_head = (struct isis_auth *)tlvs->isis_auth.head;
3361 struct isis_auth *auth;
3362 for (auth = auth_head; auth; auth = auth->next) {
3363 if (auth->type == passwd->type)
3364 break;
3365 }
3366
3367 /* If matching auth TLV could not be found, return invalid */
3368 if (!auth)
3369 return ISIS_AUTH_TYPE_FAILURE;
3370
3371
3372 /* Perform validation and return result */
3373 if (auth_validators[passwd->type](passwd, stream, auth, is_lsp))
3374 return ISIS_AUTH_OK;
3375 else
3376 return ISIS_AUTH_FAILURE;
3377 }
3378
3379 bool isis_tlvs_area_addresses_match(struct isis_tlvs *tlvs,
3380 struct list *addresses)
3381 {
3382 struct isis_area_address *addr_head;
3383
3384 addr_head = (struct isis_area_address *)tlvs->area_addresses.head;
3385 for (struct isis_area_address *addr = addr_head; addr;
3386 addr = addr->next) {
3387 struct listnode *node;
3388 struct area_addr *a;
3389
3390 for (ALL_LIST_ELEMENTS_RO(addresses, node, a)) {
3391 if (a->addr_len == addr->len
3392 && !memcmp(a->area_addr, addr->addr, addr->len))
3393 return true;
3394 }
3395 }
3396
3397 return false;
3398 }
3399
3400 static void tlvs_area_addresses_to_adj(struct isis_tlvs *tlvs,
3401 struct isis_adjacency *adj,
3402 bool *changed)
3403 {
3404 if (adj->area_address_count != tlvs->area_addresses.count) {
3405 *changed = true;
3406 adj->area_address_count = tlvs->area_addresses.count;
3407 adj->area_addresses = XREALLOC(
3408 MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses,
3409 adj->area_address_count * sizeof(*adj->area_addresses));
3410 }
3411
3412 struct isis_area_address *addr = NULL;
3413 for (unsigned int i = 0; i < tlvs->area_addresses.count; i++) {
3414 if (!addr)
3415 addr = (struct isis_area_address *)
3416 tlvs->area_addresses.head;
3417 else
3418 addr = addr->next;
3419
3420 if (adj->area_addresses[i].addr_len == addr->len
3421 && !memcmp(adj->area_addresses[i].area_addr, addr->addr,
3422 addr->len)) {
3423 continue;
3424 }
3425
3426 *changed = true;
3427 adj->area_addresses[i].addr_len = addr->len;
3428 memcpy(adj->area_addresses[i].area_addr, addr->addr, addr->len);
3429 }
3430 }
3431
3432 static void tlvs_protocols_supported_to_adj(struct isis_tlvs *tlvs,
3433 struct isis_adjacency *adj,
3434 bool *changed)
3435 {
3436 bool ipv4_supported = false, ipv6_supported = false;
3437
3438 for (uint8_t i = 0; i < tlvs->protocols_supported.count; i++) {
3439 if (tlvs->protocols_supported.protocols[i] == NLPID_IP)
3440 ipv4_supported = true;
3441 if (tlvs->protocols_supported.protocols[i] == NLPID_IPV6)
3442 ipv6_supported = true;
3443 }
3444
3445 struct nlpids reduced = {};
3446
3447 if (ipv4_supported && ipv6_supported) {
3448 reduced.count = 2;
3449 reduced.nlpids[0] = NLPID_IP;
3450 reduced.nlpids[1] = NLPID_IPV6;
3451 } else if (ipv4_supported) {
3452 reduced.count = 1;
3453 reduced.nlpids[0] = NLPID_IP;
3454 } else if (ipv6_supported) {
3455 reduced.count = 1;
3456 reduced.nlpids[0] = NLPID_IPV6;
3457 } else {
3458 reduced.count = 0;
3459 }
3460
3461 if (adj->nlpids.count == reduced.count
3462 && !memcmp(adj->nlpids.nlpids, reduced.nlpids, reduced.count))
3463 return;
3464
3465 *changed = true;
3466 adj->nlpids.count = reduced.count;
3467 memcpy(adj->nlpids.nlpids, reduced.nlpids, reduced.count);
3468 }
3469
3470 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs *tlvs,
3471 struct isis_adjacency *adj,
3472 bool *changed)
3473 {
3474 if (adj->ipv4_address_count != tlvs->ipv4_address.count) {
3475 *changed = true;
3476 adj->ipv4_address_count = tlvs->ipv4_address.count;
3477 adj->ipv4_addresses = XREALLOC(
3478 MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses,
3479 adj->ipv4_address_count * sizeof(*adj->ipv4_addresses));
3480 }
3481
3482 struct isis_ipv4_address *addr = NULL;
3483 for (unsigned int i = 0; i < tlvs->ipv4_address.count; i++) {
3484 if (!addr)
3485 addr = (struct isis_ipv4_address *)
3486 tlvs->ipv4_address.head;
3487 else
3488 addr = addr->next;
3489
3490 if (!memcmp(&adj->ipv4_addresses[i], &addr->addr,
3491 sizeof(addr->addr)))
3492 continue;
3493
3494 *changed = true;
3495 adj->ipv4_addresses[i] = addr->addr;
3496 }
3497 }
3498
3499 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs *tlvs,
3500 struct isis_adjacency *adj,
3501 bool *changed)
3502 {
3503 if (adj->ipv6_address_count != tlvs->ipv6_address.count) {
3504 *changed = true;
3505 adj->ipv6_address_count = tlvs->ipv6_address.count;
3506 adj->ipv6_addresses = XREALLOC(
3507 MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses,
3508 adj->ipv6_address_count * sizeof(*adj->ipv6_addresses));
3509 }
3510
3511 struct isis_ipv6_address *addr = NULL;
3512 for (unsigned int i = 0; i < tlvs->ipv6_address.count; i++) {
3513 if (!addr)
3514 addr = (struct isis_ipv6_address *)
3515 tlvs->ipv6_address.head;
3516 else
3517 addr = addr->next;
3518
3519 if (!memcmp(&adj->ipv6_addresses[i], &addr->addr,
3520 sizeof(addr->addr)))
3521 continue;
3522
3523 *changed = true;
3524 adj->ipv6_addresses[i] = addr->addr;
3525 }
3526 }
3527
3528 void isis_tlvs_to_adj(struct isis_tlvs *tlvs, struct isis_adjacency *adj,
3529 bool *changed)
3530 {
3531 *changed = false;
3532
3533 tlvs_area_addresses_to_adj(tlvs, adj, changed);
3534 tlvs_protocols_supported_to_adj(tlvs, adj, changed);
3535 tlvs_ipv4_addresses_to_adj(tlvs, adj, changed);
3536 tlvs_ipv6_addresses_to_adj(tlvs, adj, changed);
3537 }
3538
3539 bool isis_tlvs_own_snpa_found(struct isis_tlvs *tlvs, uint8_t *snpa)
3540 {
3541 struct isis_lan_neighbor *ne_head;
3542
3543 ne_head = (struct isis_lan_neighbor *)tlvs->lan_neighbor.head;
3544 for (struct isis_lan_neighbor *ne = ne_head; ne; ne = ne->next) {
3545 if (!memcmp(ne->mac, snpa, ETH_ALEN))
3546 return true;
3547 }
3548
3549 return false;
3550 }
3551
3552 void isis_tlvs_add_lsp_entry(struct isis_tlvs *tlvs, struct isis_lsp *lsp)
3553 {
3554 struct isis_lsp_entry *entry = XCALLOC(MTYPE_ISIS_TLV, sizeof(*entry));
3555
3556 entry->rem_lifetime = lsp->hdr.rem_lifetime;
3557 memcpy(entry->id, lsp->hdr.lsp_id, ISIS_SYS_ID_LEN + 2);
3558 entry->checksum = lsp->hdr.checksum;
3559 entry->seqno = lsp->hdr.seqno;
3560 entry->lsp = lsp;
3561
3562 append_item(&tlvs->lsp_entries, (struct isis_item *)entry);
3563 }
3564
3565 void isis_tlvs_add_csnp_entries(struct isis_tlvs *tlvs, uint8_t *start_id,
3566 uint8_t *stop_id, uint16_t num_lsps,
3567 struct lspdb_head *head,
3568 struct isis_lsp **last_lsp)
3569 {
3570 struct isis_lsp searchfor;
3571 struct isis_lsp *first, *lsp;
3572
3573 memcpy(&searchfor.hdr.lsp_id, start_id, sizeof(searchfor.hdr.lsp_id));
3574 first = lspdb_find_gteq(head, &searchfor);
3575 if (!first)
3576 return;
3577
3578 frr_each_from (lspdb, head, lsp, first) {
3579 if (memcmp(lsp->hdr.lsp_id, stop_id, sizeof(lsp->hdr.lsp_id))
3580 > 0 || tlvs->lsp_entries.count == num_lsps)
3581 break;
3582
3583 isis_tlvs_add_lsp_entry(tlvs, lsp);
3584 *last_lsp = lsp;
3585 }
3586 }
3587
3588 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs,
3589 const char *hostname)
3590 {
3591 XFREE(MTYPE_ISIS_TLV, tlvs->hostname);
3592 if (hostname)
3593 tlvs->hostname = XSTRDUP(MTYPE_ISIS_TLV, hostname);
3594 }
3595
3596 void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs,
3597 const struct in_addr *id)
3598 {
3599 XFREE(MTYPE_ISIS_TLV, tlvs->te_router_id);
3600 if (!id)
3601 return;
3602 tlvs->te_router_id = XCALLOC(MTYPE_ISIS_TLV, sizeof(*id));
3603 memcpy(tlvs->te_router_id, id, sizeof(*id));
3604 }
3605
3606 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs,
3607 struct prefix_ipv4 *dest, uint8_t metric)
3608 {
3609 struct isis_oldstyle_ip_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
3610
3611 r->metric = metric;
3612 memcpy(&r->prefix, dest, sizeof(*dest));
3613 apply_mask_ipv4(&r->prefix);
3614 append_item(&tlvs->oldstyle_ip_reach, (struct isis_item *)r);
3615 }
3616
3617 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs,
3618 struct prefix_ipv4 *dest, uint32_t metric)
3619 {
3620 struct isis_extended_ip_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
3621
3622 r->metric = metric;
3623 memcpy(&r->prefix, dest, sizeof(*dest));
3624 apply_mask_ipv4(&r->prefix);
3625 append_item(&tlvs->extended_ip_reach, (struct isis_item *)r);
3626 }
3627
3628 void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid,
3629 struct prefix_ipv6 *dest, uint32_t metric)
3630 {
3631 struct isis_ipv6_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
3632
3633 r->metric = metric;
3634 memcpy(&r->prefix, dest, sizeof(*dest));
3635 apply_mask_ipv6(&r->prefix);
3636
3637 struct isis_item_list *l;
3638 l = (mtid == ISIS_MT_IPV4_UNICAST)
3639 ? &tlvs->ipv6_reach
3640 : isis_get_mt_items(&tlvs->mt_ipv6_reach, mtid);
3641 append_item(l, (struct isis_item *)r);
3642 }
3643
3644 void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid,
3645 struct prefix_ipv6 *dest,
3646 struct prefix_ipv6 *src,
3647 uint32_t metric)
3648 {
3649 isis_tlvs_add_ipv6_reach(tlvs, mtid, dest, metric);
3650 struct isis_item_list *l = isis_get_mt_items(&tlvs->mt_ipv6_reach,
3651 mtid);
3652
3653 struct isis_ipv6_reach *r = (struct isis_ipv6_reach*)last_item(l);
3654 r->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH);
3655 r->subtlvs->source_prefix = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*src));
3656 memcpy(r->subtlvs->source_prefix, src, sizeof(*src));
3657 }
3658
3659 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id,
3660 uint8_t metric)
3661 {
3662 struct isis_oldstyle_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
3663
3664 r->metric = metric;
3665 memcpy(r->id, id, sizeof(r->id));
3666 append_item(&tlvs->oldstyle_reach, (struct isis_item *)r);
3667 }
3668
3669 void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid,
3670 uint8_t *id, uint32_t metric,
3671 uint8_t *subtlvs, uint8_t subtlv_len)
3672 {
3673 struct isis_extended_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
3674
3675 memcpy(r->id, id, sizeof(r->id));
3676 r->metric = metric;
3677 if (subtlvs && subtlv_len) {
3678 r->subtlvs = XCALLOC(MTYPE_ISIS_TLV, subtlv_len);
3679 memcpy(r->subtlvs, subtlvs, subtlv_len);
3680 r->subtlv_len = subtlv_len;
3681 }
3682
3683 struct isis_item_list *l;
3684 if (mtid == ISIS_MT_IPV4_UNICAST)
3685 l = &tlvs->extended_reach;
3686 else
3687 l = isis_get_mt_items(&tlvs->mt_reach, mtid);
3688 append_item(l, (struct isis_item *)r);
3689 }
3690
3691 void isis_tlvs_add_threeway_adj(struct isis_tlvs *tlvs,
3692 enum isis_threeway_state state,
3693 uint32_t local_circuit_id,
3694 const uint8_t *neighbor_id,
3695 uint32_t neighbor_circuit_id)
3696 {
3697 assert(!tlvs->threeway_adj);
3698
3699 tlvs->threeway_adj = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->threeway_adj));
3700 tlvs->threeway_adj->state = state;
3701 tlvs->threeway_adj->local_circuit_id = local_circuit_id;
3702
3703 if (neighbor_id) {
3704 tlvs->threeway_adj->neighbor_set = true;
3705 memcpy(tlvs->threeway_adj->neighbor_id, neighbor_id, 6);
3706 tlvs->threeway_adj->neighbor_circuit_id = neighbor_circuit_id;
3707 }
3708 }
3709
3710 void isis_tlvs_add_spine_leaf(struct isis_tlvs *tlvs, uint8_t tier,
3711 bool has_tier, bool is_leaf, bool is_spine,
3712 bool is_backup)
3713 {
3714 assert(!tlvs->spine_leaf);
3715
3716 tlvs->spine_leaf = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->spine_leaf));
3717
3718 if (has_tier) {
3719 tlvs->spine_leaf->tier = tier;
3720 }
3721
3722 tlvs->spine_leaf->has_tier = has_tier;
3723 tlvs->spine_leaf->is_leaf = is_leaf;
3724 tlvs->spine_leaf->is_spine = is_spine;
3725 tlvs->spine_leaf->is_backup = is_backup;
3726 }
3727
3728 struct isis_mt_router_info *
3729 isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid)
3730 {
3731 if (tlvs->mt_router_info_empty)
3732 return NULL;
3733
3734 struct isis_mt_router_info *rv;
3735 for (rv = (struct isis_mt_router_info *)tlvs->mt_router_info.head; rv;
3736 rv = rv->next) {
3737 if (rv->mtid == mtid)
3738 return rv;
3739 }
3740
3741 return NULL;
3742 }
3743
3744 void isis_tlvs_set_purge_originator(struct isis_tlvs *tlvs,
3745 const uint8_t *generator,
3746 const uint8_t *sender)
3747 {
3748 assert(!tlvs->purge_originator);
3749
3750 tlvs->purge_originator = XCALLOC(MTYPE_ISIS_TLV,
3751 sizeof(*tlvs->purge_originator));
3752 memcpy(tlvs->purge_originator->generator, generator,
3753 sizeof(tlvs->purge_originator->generator));
3754 if (sender) {
3755 tlvs->purge_originator->sender_set = true;
3756 memcpy(tlvs->purge_originator->sender, sender,
3757 sizeof(tlvs->purge_originator->sender));
3758 }
3759 }