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