]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_tlvs.c
zebra: Allow ns delete to happen after under/over flow checks
[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);
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)) {
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
1277 static void free_item_extended_ip_reach(struct isis_item *i)
1278 {
1279 struct isis_extended_ip_reach *item =
1280 (struct isis_extended_ip_reach *)i;
1281 isis_free_subtlvs(item->subtlvs);
1282 XFREE(MTYPE_ISIS_TLV, item);
1283 }
1284
1285 static int pack_item_extended_ip_reach(struct isis_item *i, struct stream *s)
1286 {
1287 struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
1288 uint8_t control;
1289
1290 if (STREAM_WRITEABLE(s) < 5)
1291 return 1;
1292 stream_putl(s, r->metric);
1293
1294 control = r->down ? ISIS_EXTENDED_IP_REACH_DOWN : 0;
1295 control |= r->prefix.prefixlen;
1296 control |= r->subtlvs ? ISIS_EXTENDED_IP_REACH_SUBTLV : 0;
1297
1298 stream_putc(s, control);
1299
1300 if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen))
1301 return 1;
1302 stream_put(s, &r->prefix.prefix.s_addr, PSIZE(r->prefix.prefixlen));
1303
1304 if (r->subtlvs)
1305 return pack_subtlvs(r->subtlvs, s);
1306 return 0;
1307 }
1308
1309 static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len,
1310 struct stream *s, struct sbuf *log,
1311 void *dest, int indent)
1312 {
1313 struct isis_tlvs *tlvs = dest;
1314 struct isis_extended_ip_reach *rv = NULL;
1315 size_t consume;
1316 uint8_t control, subtlv_len;
1317 struct isis_item_list *items;
1318
1319 if (mtid == ISIS_MT_IPV4_UNICAST) {
1320 items = &tlvs->extended_ip_reach;
1321 } else {
1322 items = isis_get_mt_items(&tlvs->mt_ip_reach, mtid);
1323 }
1324
1325 sbuf_push(log, indent, "Unpacking %s IPv4 reachability...\n",
1326 (mtid == ISIS_MT_IPV4_UNICAST) ? "extended" : "mt");
1327
1328 consume = 5;
1329 if (len < consume) {
1330 sbuf_push(log, indent,
1331 "Not enough data left. (expected 5 or more bytes, got %" PRIu8 ")\n",
1332 len);
1333 goto out;
1334 }
1335
1336 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1337
1338 rv->metric = stream_getl(s);
1339 control = stream_getc(s);
1340 rv->down = (control & ISIS_EXTENDED_IP_REACH_DOWN);
1341 rv->prefix.family = AF_INET;
1342 rv->prefix.prefixlen = control & 0x3f;
1343 if (rv->prefix.prefixlen > 32) {
1344 sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv4\n",
1345 rv->prefix.prefixlen);
1346 goto out;
1347 }
1348
1349 consume += PSIZE(rv->prefix.prefixlen);
1350 if (len < consume) {
1351 sbuf_push(log, indent,
1352 "Expected %u bytes of prefix, but only %u bytes available.\n",
1353 PSIZE(rv->prefix.prefixlen), len - 5);
1354 goto out;
1355 }
1356 stream_get(&rv->prefix.prefix.s_addr, s, PSIZE(rv->prefix.prefixlen));
1357 in_addr_t orig_prefix = rv->prefix.prefix.s_addr;
1358 apply_mask_ipv4(&rv->prefix);
1359 if (orig_prefix != rv->prefix.prefix.s_addr)
1360 sbuf_push(log, indent + 2,
1361 "WARNING: Prefix had hostbits set.\n");
1362 format_item_extended_ip_reach(mtid, (struct isis_item *)rv, log,
1363 indent + 2);
1364
1365 if (control & ISIS_EXTENDED_IP_REACH_SUBTLV) {
1366 consume += 1;
1367 if (len < consume) {
1368 sbuf_push(log, indent,
1369 "Expected 1 byte of subtlv len, but no more data present.\n");
1370 goto out;
1371 }
1372 subtlv_len = stream_getc(s);
1373
1374 if (!subtlv_len) {
1375 sbuf_push(log, indent + 2,
1376 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
1377 }
1378 consume += subtlv_len;
1379 if (len < consume) {
1380 sbuf_push(log, indent,
1381 "Expected %" PRIu8
1382 " bytes of subtlvs, but only %u bytes available.\n",
1383 subtlv_len,
1384 len - 6 - PSIZE(rv->prefix.prefixlen));
1385 goto out;
1386 }
1387
1388 rv->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH);
1389 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH, subtlv_len, s,
1390 log, rv->subtlvs, indent + 4)) {
1391 goto out;
1392 }
1393 }
1394
1395 append_item(items, (struct isis_item *)rv);
1396 return 0;
1397 out:
1398 if (rv)
1399 free_item_extended_ip_reach((struct isis_item *)rv);
1400 return 1;
1401 }
1402
1403 /* Functions related to TLV 137 Dynamic Hostname */
1404
1405 static char *copy_tlv_dynamic_hostname(const char *hostname)
1406 {
1407 if (!hostname)
1408 return NULL;
1409
1410 return XSTRDUP(MTYPE_ISIS_TLV, hostname);
1411 }
1412
1413 static void format_tlv_dynamic_hostname(const char *hostname, struct sbuf *buf,
1414 int indent)
1415 {
1416 if (!hostname)
1417 return;
1418
1419 sbuf_push(buf, indent, "Hostname: %s\n", hostname);
1420 }
1421
1422 static void free_tlv_dynamic_hostname(char *hostname)
1423 {
1424 XFREE(MTYPE_ISIS_TLV, hostname);
1425 }
1426
1427 static int pack_tlv_dynamic_hostname(const char *hostname, struct stream *s)
1428 {
1429 if (!hostname)
1430 return 0;
1431
1432 uint8_t name_len = strlen(hostname);
1433
1434 if (STREAM_WRITEABLE(s) < (unsigned)(2 + name_len))
1435 return 1;
1436
1437 stream_putc(s, ISIS_TLV_DYNAMIC_HOSTNAME);
1438 stream_putc(s, name_len);
1439 stream_put(s, hostname, name_len);
1440 return 0;
1441 }
1442
1443 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context,
1444 uint8_t tlv_type, uint8_t tlv_len,
1445 struct stream *s, struct sbuf *log,
1446 void *dest, int indent)
1447 {
1448 struct isis_tlvs *tlvs = dest;
1449
1450 sbuf_push(log, indent, "Unpacking Dynamic Hostname TLV...\n");
1451 if (!tlv_len) {
1452 sbuf_push(log, indent, "WARNING: No hostname included\n");
1453 return 0;
1454 }
1455
1456 if (tlvs->hostname) {
1457 sbuf_push(log, indent,
1458 "WARNING: Hostname present multiple times.\n");
1459 stream_forward_getp(s, tlv_len);
1460 return 0;
1461 }
1462
1463 tlvs->hostname = XCALLOC(MTYPE_ISIS_TLV, tlv_len + 1);
1464 stream_get(tlvs->hostname, s, tlv_len);
1465 tlvs->hostname[tlv_len] = '\0';
1466
1467 bool sane = true;
1468 for (uint8_t i = 0; i < tlv_len; i++) {
1469 if ((unsigned char)tlvs->hostname[i] > 127
1470 || !isprint((int)tlvs->hostname[i])) {
1471 sane = false;
1472 tlvs->hostname[i] = '?';
1473 }
1474 }
1475 if (!sane) {
1476 sbuf_push(
1477 log, indent,
1478 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
1479 }
1480
1481 return 0;
1482 }
1483
1484 /* Functions related to TLV 150 Spine-Leaf-Extension */
1485
1486 static struct isis_spine_leaf *copy_tlv_spine_leaf(
1487 const struct isis_spine_leaf *spine_leaf)
1488 {
1489 if (!spine_leaf)
1490 return NULL;
1491
1492 struct isis_spine_leaf *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1493 memcpy(rv, spine_leaf, sizeof(*rv));
1494
1495 return rv;
1496 }
1497
1498 static void format_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf,
1499 struct sbuf *buf, int indent)
1500 {
1501 if (!spine_leaf)
1502 return;
1503
1504 sbuf_push(buf, indent, "Spine-Leaf-Extension:\n");
1505 if (spine_leaf->has_tier) {
1506 if (spine_leaf->tier == ISIS_TIER_UNDEFINED) {
1507 sbuf_push(buf, indent, " Tier: undefined\n");
1508 } else {
1509 sbuf_push(buf, indent, " Tier: %" PRIu8 "\n",
1510 spine_leaf->tier);
1511 }
1512 }
1513
1514 sbuf_push(buf, indent, " Flags:%s%s%s\n",
1515 spine_leaf->is_leaf ? " LEAF" : "",
1516 spine_leaf->is_spine ? " SPINE" : "",
1517 spine_leaf->is_backup ? " BACKUP" : "");
1518
1519 }
1520
1521 static void free_tlv_spine_leaf(struct isis_spine_leaf *spine_leaf)
1522 {
1523 XFREE(MTYPE_ISIS_TLV, spine_leaf);
1524 }
1525
1526 #define ISIS_SPINE_LEAF_FLAG_TIER 0x08
1527 #define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
1528 #define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
1529 #define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
1530
1531 static int pack_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf,
1532 struct stream *s)
1533 {
1534 if (!spine_leaf)
1535 return 0;
1536
1537 uint8_t tlv_len = 2;
1538
1539 if (STREAM_WRITEABLE(s) < (unsigned)(2 + tlv_len))
1540 return 1;
1541
1542 stream_putc(s, ISIS_TLV_SPINE_LEAF_EXT);
1543 stream_putc(s, tlv_len);
1544
1545 uint16_t spine_leaf_flags = 0;
1546
1547 if (spine_leaf->has_tier) {
1548 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_TIER;
1549 spine_leaf_flags |= spine_leaf->tier << 12;
1550 }
1551
1552 if (spine_leaf->is_leaf)
1553 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_LEAF;
1554
1555 if (spine_leaf->is_spine)
1556 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_SPINE;
1557
1558 if (spine_leaf->is_backup)
1559 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_BACKUP;
1560
1561 stream_putw(s, spine_leaf_flags);
1562
1563 return 0;
1564 }
1565
1566 static int unpack_tlv_spine_leaf(enum isis_tlv_context context,
1567 uint8_t tlv_type, uint8_t tlv_len,
1568 struct stream *s, struct sbuf *log,
1569 void *dest, int indent)
1570 {
1571 struct isis_tlvs *tlvs = dest;
1572
1573 sbuf_push(log, indent, "Unpacking Spine Leaf Extension TLV...\n");
1574 if (tlv_len < 2) {
1575 sbuf_push(log, indent, "WARNING: Unexepected TLV size\n");
1576 stream_forward_getp(s, tlv_len);
1577 return 0;
1578 }
1579
1580 if (tlvs->spine_leaf) {
1581 sbuf_push(log, indent,
1582 "WARNING: Spine Leaf Extension TLV present multiple times.\n");
1583 stream_forward_getp(s, tlv_len);
1584 return 0;
1585 }
1586
1587 tlvs->spine_leaf = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->spine_leaf));
1588
1589 uint16_t spine_leaf_flags = stream_getw(s);
1590
1591 if (spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_TIER) {
1592 tlvs->spine_leaf->has_tier = true;
1593 tlvs->spine_leaf->tier = spine_leaf_flags >> 12;
1594 }
1595
1596 tlvs->spine_leaf->is_leaf = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_LEAF;
1597 tlvs->spine_leaf->is_spine = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_SPINE;
1598 tlvs->spine_leaf->is_backup = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_BACKUP;
1599
1600 stream_forward_getp(s, tlv_len - 2);
1601 return 0;
1602 }
1603
1604 /* Functions related to TLV 240 P2P Three-Way Adjacency */
1605
1606 const char *isis_threeway_state_name(enum isis_threeway_state state)
1607 {
1608 switch (state) {
1609 case ISIS_THREEWAY_DOWN:
1610 return "Down";
1611 case ISIS_THREEWAY_INITIALIZING:
1612 return "Initializing";
1613 case ISIS_THREEWAY_UP:
1614 return "Up";
1615 default:
1616 return "Invalid!";
1617 }
1618 }
1619
1620 static struct isis_threeway_adj *copy_tlv_threeway_adj(
1621 const struct isis_threeway_adj *threeway_adj)
1622 {
1623 if (!threeway_adj)
1624 return NULL;
1625
1626 struct isis_threeway_adj *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1627 memcpy(rv, threeway_adj, sizeof(*rv));
1628
1629 return rv;
1630 }
1631
1632 static void format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj,
1633 struct sbuf *buf, int indent)
1634 {
1635 if (!threeway_adj)
1636 return;
1637
1638 sbuf_push(buf, indent, "P2P Three-Way Adjacency:\n");
1639 sbuf_push(buf, indent, " State: %s (%d)\n",
1640 isis_threeway_state_name(threeway_adj->state),
1641 threeway_adj->state);
1642 sbuf_push(buf, indent, " Extended Local Circuit ID: %" PRIu32 "\n",
1643 threeway_adj->local_circuit_id);
1644 if (!threeway_adj->neighbor_set)
1645 return;
1646
1647 sbuf_push(buf, indent, " Neighbor System ID: %s\n",
1648 isis_format_id(threeway_adj->neighbor_id, 6));
1649 sbuf_push(buf, indent, " Neighbor Extended Circuit ID: %" PRIu32 "\n",
1650 threeway_adj->neighbor_circuit_id);
1651 }
1652
1653 static void free_tlv_threeway_adj(struct isis_threeway_adj *threeway_adj)
1654 {
1655 XFREE(MTYPE_ISIS_TLV, threeway_adj);
1656 }
1657
1658 static int pack_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj,
1659 struct stream *s)
1660 {
1661 if (!threeway_adj)
1662 return 0;
1663
1664 uint8_t tlv_len = (threeway_adj->neighbor_set) ? 15 : 5;
1665
1666 if (STREAM_WRITEABLE(s) < (unsigned)(2 + tlv_len))
1667 return 1;
1668
1669 stream_putc(s, ISIS_TLV_THREE_WAY_ADJ);
1670 stream_putc(s, tlv_len);
1671 stream_putc(s, threeway_adj->state);
1672 stream_putl(s, threeway_adj->local_circuit_id);
1673
1674 if (threeway_adj->neighbor_set) {
1675 stream_put(s, threeway_adj->neighbor_id, 6);
1676 stream_putl(s, threeway_adj->neighbor_circuit_id);
1677 }
1678
1679 return 0;
1680 }
1681
1682 static int unpack_tlv_threeway_adj(enum isis_tlv_context context,
1683 uint8_t tlv_type, uint8_t tlv_len,
1684 struct stream *s, struct sbuf *log,
1685 void *dest, int indent)
1686 {
1687 struct isis_tlvs *tlvs = dest;
1688
1689 sbuf_push(log, indent, "Unpacking P2P Three-Way Adjacency TLV...\n");
1690 if (tlv_len != 5 && tlv_len != 15) {
1691 sbuf_push(log, indent, "WARNING: Unexepected TLV size\n");
1692 stream_forward_getp(s, tlv_len);
1693 return 0;
1694 }
1695
1696 if (tlvs->threeway_adj) {
1697 sbuf_push(log, indent,
1698 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
1699 stream_forward_getp(s, tlv_len);
1700 return 0;
1701 }
1702
1703 tlvs->threeway_adj = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->threeway_adj));
1704
1705 tlvs->threeway_adj->state = stream_getc(s);
1706 tlvs->threeway_adj->local_circuit_id = stream_getl(s);
1707
1708 if (tlv_len == 15) {
1709 tlvs->threeway_adj->neighbor_set = true;
1710 stream_get(tlvs->threeway_adj->neighbor_id, s, 6);
1711 tlvs->threeway_adj->neighbor_circuit_id = stream_getl(s);
1712 }
1713
1714 return 0;
1715 }
1716
1717 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
1718
1719 static struct isis_item *copy_item_ipv6_reach(struct isis_item *i)
1720 {
1721 struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
1722 struct isis_ipv6_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1723 rv->metric = r->metric;
1724 rv->down = r->down;
1725 rv->external = r->external;
1726 rv->prefix = r->prefix;
1727 rv->subtlvs = copy_subtlvs(r->subtlvs);
1728
1729 return (struct isis_item *)rv;
1730 }
1731
1732 static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i,
1733 struct sbuf *buf, int indent)
1734 {
1735 struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
1736 char prefixbuf[PREFIX2STR_BUFFER];
1737
1738 sbuf_push(buf, indent, "%sIPv6 Reachability: %s (Metric: %u)%s%s",
1739 (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "MT ",
1740 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)),
1741 r->metric,
1742 r->down ? " Down" : "",
1743 r->external ? " External" : "");
1744 if (mtid != ISIS_MT_IPV4_UNICAST)
1745 sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
1746 sbuf_push(buf, 0, "\n");
1747
1748 if (r->subtlvs) {
1749 sbuf_push(buf, indent, " Subtlvs:\n");
1750 format_subtlvs(r->subtlvs, buf, indent + 4);
1751 }
1752 }
1753
1754 static void free_item_ipv6_reach(struct isis_item *i)
1755 {
1756 struct isis_ipv6_reach *item = (struct isis_ipv6_reach *)i;
1757
1758 isis_free_subtlvs(item->subtlvs);
1759 XFREE(MTYPE_ISIS_TLV, item);
1760 }
1761
1762 static int pack_item_ipv6_reach(struct isis_item *i, struct stream *s)
1763 {
1764 struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
1765 uint8_t control;
1766
1767 if (STREAM_WRITEABLE(s) < 6)
1768 return 1;
1769 stream_putl(s, r->metric);
1770
1771 control = r->down ? ISIS_IPV6_REACH_DOWN : 0;
1772 control |= r->external ? ISIS_IPV6_REACH_EXTERNAL : 0;
1773 control |= r->subtlvs ? ISIS_IPV6_REACH_SUBTLV : 0;
1774
1775 stream_putc(s, control);
1776 stream_putc(s, r->prefix.prefixlen);
1777
1778 if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen))
1779 return 1;
1780 stream_put(s, &r->prefix.prefix.s6_addr, PSIZE(r->prefix.prefixlen));
1781
1782 if (r->subtlvs)
1783 return pack_subtlvs(r->subtlvs, s);
1784
1785 return 0;
1786 }
1787
1788 static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s,
1789 struct sbuf *log, void *dest, int indent)
1790 {
1791 struct isis_tlvs *tlvs = dest;
1792 struct isis_ipv6_reach *rv = NULL;
1793 size_t consume;
1794 uint8_t control, subtlv_len;
1795 struct isis_item_list *items;
1796
1797 if (mtid == ISIS_MT_IPV4_UNICAST) {
1798 items = &tlvs->ipv6_reach;
1799 } else {
1800 items = isis_get_mt_items(&tlvs->mt_ipv6_reach, mtid);
1801 }
1802
1803 sbuf_push(log, indent, "Unpacking %sIPv6 reachability...\n",
1804 (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "mt ");
1805 consume = 6;
1806 if (len < consume) {
1807 sbuf_push(log, indent,
1808 "Not enough data left. (expected 6 or more bytes, got %"
1809 PRIu8 ")\n",
1810 len);
1811 goto out;
1812 }
1813
1814 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1815
1816 rv->metric = stream_getl(s);
1817 control = stream_getc(s);
1818 rv->down = (control & ISIS_IPV6_REACH_DOWN);
1819 rv->external = (control & ISIS_IPV6_REACH_EXTERNAL);
1820
1821 rv->prefix.family = AF_INET6;
1822 rv->prefix.prefixlen = stream_getc(s);
1823 if (rv->prefix.prefixlen > 128) {
1824 sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv6\n",
1825 rv->prefix.prefixlen);
1826 goto out;
1827 }
1828
1829 consume += PSIZE(rv->prefix.prefixlen);
1830 if (len < consume) {
1831 sbuf_push(log, indent,
1832 "Expected %u bytes of prefix, but only %u bytes available.\n",
1833 PSIZE(rv->prefix.prefixlen), len - 6);
1834 goto out;
1835 }
1836 stream_get(&rv->prefix.prefix.s6_addr, s, PSIZE(rv->prefix.prefixlen));
1837 struct in6_addr orig_prefix = rv->prefix.prefix;
1838 apply_mask_ipv6(&rv->prefix);
1839 if (memcmp(&orig_prefix, &rv->prefix.prefix, sizeof(orig_prefix)))
1840 sbuf_push(log, indent + 2,
1841 "WARNING: Prefix had hostbits set.\n");
1842 format_item_ipv6_reach(mtid, (struct isis_item *)rv, log, indent + 2);
1843
1844 if (control & ISIS_IPV6_REACH_SUBTLV) {
1845 consume += 1;
1846 if (len < consume) {
1847 sbuf_push(log, indent,
1848 "Expected 1 byte of subtlv len, but no more data persent.\n");
1849 goto out;
1850 }
1851 subtlv_len = stream_getc(s);
1852
1853 if (!subtlv_len) {
1854 sbuf_push(log, indent + 2,
1855 " WARNING: subtlv bit set, but there are no subtlvs.\n");
1856 }
1857 consume += subtlv_len;
1858 if (len < consume) {
1859 sbuf_push(log, indent,
1860 "Expected %" PRIu8
1861 " bytes of subtlvs, but only %u bytes available.\n",
1862 subtlv_len,
1863 len - 6 - PSIZE(rv->prefix.prefixlen));
1864 goto out;
1865 }
1866
1867 rv->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH);
1868 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH, subtlv_len, s,
1869 log, rv->subtlvs, indent + 4)) {
1870 goto out;
1871 }
1872 }
1873
1874 append_item(items, (struct isis_item *)rv);
1875 return 0;
1876 out:
1877 if (rv)
1878 free_item_ipv6_reach((struct isis_item *)rv);
1879 return 1;
1880 }
1881
1882 /* Functions related to TLV 10 Authentication */
1883 static struct isis_item *copy_item_auth(struct isis_item *i)
1884 {
1885 struct isis_auth *auth = (struct isis_auth *)i;
1886 struct isis_auth *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1887
1888 rv->type = auth->type;
1889 rv->length = auth->length;
1890 memcpy(rv->value, auth->value, sizeof(rv->value));
1891 return (struct isis_item *)rv;
1892 }
1893
1894 static void format_item_auth(uint16_t mtid, struct isis_item *i,
1895 struct sbuf *buf, int indent)
1896 {
1897 struct isis_auth *auth = (struct isis_auth *)i;
1898 char obuf[768];
1899
1900 sbuf_push(buf, indent, "Authentication:\n");
1901 switch (auth->type) {
1902 case ISIS_PASSWD_TYPE_CLEARTXT:
1903 zlog_sanitize(obuf, sizeof(obuf), auth->value, auth->length);
1904 sbuf_push(buf, indent, " Password: %s\n", obuf);
1905 break;
1906 case ISIS_PASSWD_TYPE_HMAC_MD5:
1907 for (unsigned int j = 0; j < 16; j++) {
1908 snprintf(obuf + 2 * j, sizeof(obuf) - 2 * j,
1909 "%02" PRIx8, auth->value[j]);
1910 }
1911 sbuf_push(buf, indent, " HMAC-MD5: %s\n", obuf);
1912 break;
1913 default:
1914 sbuf_push(buf, indent, " Unknown (%" PRIu8 ")\n", auth->type);
1915 break;
1916 };
1917 }
1918
1919 static void free_item_auth(struct isis_item *i)
1920 {
1921 XFREE(MTYPE_ISIS_TLV, i);
1922 }
1923
1924 static int pack_item_auth(struct isis_item *i, struct stream *s)
1925 {
1926 struct isis_auth *auth = (struct isis_auth *)i;
1927
1928 if (STREAM_WRITEABLE(s) < 1)
1929 return 1;
1930 stream_putc(s, auth->type);
1931
1932 switch (auth->type) {
1933 case ISIS_PASSWD_TYPE_CLEARTXT:
1934 if (STREAM_WRITEABLE(s) < auth->length)
1935 return 1;
1936 stream_put(s, auth->passwd, auth->length);
1937 break;
1938 case ISIS_PASSWD_TYPE_HMAC_MD5:
1939 if (STREAM_WRITEABLE(s) < 16)
1940 return 1;
1941 auth->offset = stream_get_endp(s);
1942 stream_put(s, NULL, 16);
1943 break;
1944 default:
1945 return 1;
1946 }
1947
1948 return 0;
1949 }
1950
1951 static int unpack_item_auth(uint16_t mtid, uint8_t len, struct stream *s,
1952 struct sbuf *log, void *dest, int indent)
1953 {
1954 struct isis_tlvs *tlvs = dest;
1955
1956 sbuf_push(log, indent, "Unpack Auth TLV...\n");
1957 if (len < 1) {
1958 sbuf_push(
1959 log, indent,
1960 "Not enough data left.(Expected 1 bytes of auth type, got %" PRIu8
1961 ")\n",
1962 len);
1963 return 1;
1964 }
1965
1966 struct isis_auth *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1967
1968 rv->type = stream_getc(s);
1969 rv->length = len - 1;
1970
1971 if (rv->type == ISIS_PASSWD_TYPE_HMAC_MD5 && rv->length != 16) {
1972 sbuf_push(
1973 log, indent,
1974 "Unexpected auth length for HMAC-MD5 (expected 16, got %" PRIu8
1975 ")\n",
1976 rv->length);
1977 XFREE(MTYPE_ISIS_TLV, rv);
1978 return 1;
1979 }
1980
1981 rv->offset = stream_get_getp(s);
1982 stream_get(rv->value, s, rv->length);
1983 format_item_auth(mtid, (struct isis_item *)rv, log, indent + 2);
1984 append_item(&tlvs->isis_auth, (struct isis_item *)rv);
1985 return 0;
1986 }
1987
1988 /* Functions related to TLV 13 Purge Originator */
1989
1990 static struct isis_purge_originator *copy_tlv_purge_originator(
1991 struct isis_purge_originator *poi)
1992 {
1993 if (!poi)
1994 return NULL;
1995
1996 struct isis_purge_originator *rv;
1997
1998 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1999 rv->sender_set = poi->sender_set;
2000 memcpy(rv->generator, poi->generator, sizeof(rv->generator));
2001 if (poi->sender_set)
2002 memcpy(rv->sender, poi->sender, sizeof(rv->sender));
2003 return rv;
2004 }
2005
2006 static void format_tlv_purge_originator(struct isis_purge_originator *poi,
2007 struct sbuf *buf, int indent)
2008 {
2009 if (!poi)
2010 return;
2011
2012 sbuf_push(buf, indent, "Purge Originator Identification:\n");
2013 sbuf_push(buf, indent, " Generator: %s\n",
2014 isis_format_id(poi->generator, sizeof(poi->generator)));
2015 if (poi->sender_set) {
2016 sbuf_push(buf, indent, " Received-From: %s\n",
2017 isis_format_id(poi->sender, sizeof(poi->sender)));
2018 }
2019 }
2020
2021 static void free_tlv_purge_originator(struct isis_purge_originator *poi)
2022 {
2023 XFREE(MTYPE_ISIS_TLV, poi);
2024 }
2025
2026 static int pack_tlv_purge_originator(struct isis_purge_originator *poi,
2027 struct stream *s)
2028 {
2029 if (!poi)
2030 return 0;
2031
2032 uint8_t data_len = 1 + sizeof(poi->generator);
2033
2034 if (poi->sender_set)
2035 data_len += sizeof(poi->sender);
2036
2037 if (STREAM_WRITEABLE(s) < (unsigned)(2 + data_len))
2038 return 1;
2039
2040 stream_putc(s, ISIS_TLV_PURGE_ORIGINATOR);
2041 stream_putc(s, data_len);
2042 stream_putc(s, poi->sender_set ? 2 : 1);
2043 stream_put(s, poi->generator, sizeof(poi->generator));
2044 if (poi->sender_set)
2045 stream_put(s, poi->sender, sizeof(poi->sender));
2046 return 0;
2047 }
2048
2049 static int unpack_tlv_purge_originator(enum isis_tlv_context context,
2050 uint8_t tlv_type, uint8_t tlv_len,
2051 struct stream *s, struct sbuf *log,
2052 void *dest, int indent)
2053 {
2054 struct isis_tlvs *tlvs = dest;
2055 struct isis_purge_originator poi = {};
2056
2057 sbuf_push(log, indent, "Unpacking Purge Originator Identification TLV...\n");
2058 if (tlv_len < 7) {
2059 sbuf_push(log, indent, "Not enough data left. (Expected at least 7 bytes, got %"
2060 PRIu8 ")\n", tlv_len);
2061 return 1;
2062 }
2063
2064 uint8_t number_of_ids = stream_getc(s);
2065
2066 if (number_of_ids == 1) {
2067 poi.sender_set = false;
2068 } else if (number_of_ids == 2) {
2069 poi.sender_set = true;
2070 } else {
2071 sbuf_push(log, indent, "Got invalid value for number of system IDs: %"
2072 PRIu8 ")\n", number_of_ids);
2073 return 1;
2074 }
2075
2076 if (tlv_len != 1 + 6 * number_of_ids) {
2077 sbuf_push(log, indent, "Incorrect tlv len for number of IDs.\n");
2078 return 1;
2079 }
2080
2081 stream_get(poi.generator, s, sizeof(poi.generator));
2082 if (poi.sender_set)
2083 stream_get(poi.sender, s, sizeof(poi.sender));
2084
2085 if (tlvs->purge_originator) {
2086 sbuf_push(log, indent,
2087 "WARNING: Purge originator present multiple times, ignoring.\n");
2088 return 0;
2089 }
2090
2091 tlvs->purge_originator = copy_tlv_purge_originator(&poi);
2092 return 0;
2093 }
2094
2095
2096 /* Functions relating to item TLVs */
2097
2098 static void init_item_list(struct isis_item_list *items)
2099 {
2100 items->head = NULL;
2101 items->tail = &items->head;
2102 items->count = 0;
2103 }
2104
2105 static struct isis_item *copy_item(enum isis_tlv_context context,
2106 enum isis_tlv_type type,
2107 struct isis_item *item)
2108 {
2109 const struct tlv_ops *ops = tlv_table[context][type];
2110
2111 if (ops && ops->copy_item)
2112 return ops->copy_item(item);
2113
2114 assert(!"Unknown item tlv type!");
2115 return NULL;
2116 }
2117
2118 static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type,
2119 struct isis_item_list *src, struct isis_item_list *dest)
2120 {
2121 struct isis_item *item;
2122
2123 init_item_list(dest);
2124
2125 for (item = src->head; item; item = item->next) {
2126 append_item(dest, copy_item(context, type, item));
2127 }
2128 }
2129
2130 static void format_item(uint16_t mtid, enum isis_tlv_context context,
2131 enum isis_tlv_type type, struct isis_item *i,
2132 struct sbuf *buf, int indent)
2133 {
2134 const struct tlv_ops *ops = tlv_table[context][type];
2135
2136 if (ops && ops->format_item) {
2137 ops->format_item(mtid, i, buf, indent);
2138 return;
2139 }
2140
2141 assert(!"Unknown item tlv type!");
2142 }
2143
2144 static void format_items_(uint16_t mtid, enum isis_tlv_context context,
2145 enum isis_tlv_type type, struct isis_item_list *items,
2146 struct sbuf *buf, int indent)
2147 {
2148 struct isis_item *i;
2149
2150 for (i = items->head; i; i = i->next)
2151 format_item(mtid, context, type, i, buf, indent);
2152 }
2153
2154 static void free_item(enum isis_tlv_context tlv_context,
2155 enum isis_tlv_type tlv_type, struct isis_item *item)
2156 {
2157 const struct tlv_ops *ops = tlv_table[tlv_context][tlv_type];
2158
2159 if (ops && ops->free_item) {
2160 ops->free_item(item);
2161 return;
2162 }
2163
2164 assert(!"Unknown item tlv type!");
2165 }
2166
2167 static void free_items(enum isis_tlv_context context, enum isis_tlv_type type,
2168 struct isis_item_list *items)
2169 {
2170 struct isis_item *item, *next_item;
2171
2172 for (item = items->head; item; item = next_item) {
2173 next_item = item->next;
2174 free_item(context, type, item);
2175 }
2176 }
2177
2178 static int pack_item(enum isis_tlv_context context, enum isis_tlv_type type,
2179 struct isis_item *i, struct stream *s,
2180 struct isis_tlvs **fragment_tlvs,
2181 struct pack_order_entry *pe, uint16_t mtid)
2182 {
2183 const struct tlv_ops *ops = tlv_table[context][type];
2184
2185 if (ops && ops->pack_item) {
2186 return ops->pack_item(i, s);
2187 }
2188
2189 assert(!"Unknown item tlv type!");
2190 return 1;
2191 }
2192
2193 static void add_item_to_fragment(struct isis_item *i, struct pack_order_entry *pe,
2194 struct isis_tlvs *fragment_tlvs, uint16_t mtid)
2195 {
2196 struct isis_item_list *l;
2197
2198 if (pe->how_to_pack == ISIS_ITEMS) {
2199 l = (struct isis_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack);
2200 } else {
2201 struct isis_mt_item_list *m;
2202 m = (struct isis_mt_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack);
2203 l = isis_get_mt_items(m, mtid);
2204 }
2205
2206 append_item(l, copy_item(pe->context, pe->type, i));
2207 }
2208
2209 static int pack_items_(uint16_t mtid, enum isis_tlv_context context,
2210 enum isis_tlv_type type, struct isis_item_list *items,
2211 struct stream *s, struct isis_tlvs **fragment_tlvs,
2212 struct pack_order_entry *pe,
2213 struct isis_tlvs *(*new_fragment)(struct list *l),
2214 struct list *new_fragment_arg)
2215 {
2216 size_t len_pos, last_len, len;
2217 struct isis_item *item = NULL;
2218 int rv;
2219
2220 if (!items->head)
2221 return 0;
2222
2223 top:
2224 if (STREAM_WRITEABLE(s) < 2)
2225 goto too_long;
2226
2227 stream_putc(s, type);
2228 len_pos = stream_get_endp(s);
2229 stream_putc(s, 0); /* Put 0 as length for now */
2230
2231 if (context == ISIS_CONTEXT_LSP && IS_COMPAT_MT_TLV(type)
2232 && mtid != ISIS_MT_IPV4_UNICAST) {
2233 if (STREAM_WRITEABLE(s) < 2)
2234 goto too_long;
2235 stream_putw(s, mtid);
2236 }
2237
2238 if (context == ISIS_CONTEXT_LSP && type == ISIS_TLV_OLDSTYLE_REACH) {
2239 if (STREAM_WRITEABLE(s) < 1)
2240 goto too_long;
2241 stream_putc(s, 0); /* Virtual flag is set to 0 */
2242 }
2243
2244 last_len = len = 0;
2245 for (item = item ? item : items->head; item; item = item->next) {
2246 rv = pack_item(context, type, item, s, fragment_tlvs, pe, mtid);
2247 if (rv)
2248 goto too_long;
2249
2250 len = stream_get_endp(s) - len_pos - 1;
2251
2252 /* Multiple auths don't go into one TLV, so always break */
2253 if (context == ISIS_CONTEXT_LSP && type == ISIS_TLV_AUTH) {
2254 item = item->next;
2255 break;
2256 }
2257
2258 /* Multiple prefix-sids don't go into one TLV, so always break */
2259 if (type == ISIS_SUBTLV_PREFIX_SID
2260 && (context == ISIS_CONTEXT_SUBTLV_IP_REACH
2261 || context == ISIS_CONTEXT_SUBTLV_IPV6_REACH)) {
2262 item = item->next;
2263 break;
2264 }
2265
2266 if (len > 255) {
2267 if (!last_len) /* strange, not a single item fit */
2268 return 1;
2269 /* drop last tlv, otherwise, its too long */
2270 stream_set_endp(s, len_pos + 1 + last_len);
2271 len = last_len;
2272 break;
2273 }
2274
2275 if (fragment_tlvs)
2276 add_item_to_fragment(item, pe, *fragment_tlvs, mtid);
2277
2278 last_len = len;
2279 }
2280
2281 stream_putc_at(s, len_pos, len);
2282 if (item)
2283 goto top;
2284
2285 return 0;
2286 too_long:
2287 if (!fragment_tlvs)
2288 return 1;
2289 stream_reset(s);
2290 *fragment_tlvs = new_fragment(new_fragment_arg);
2291 goto top;
2292 }
2293 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
2294
2295 static void append_item(struct isis_item_list *dest, struct isis_item *item)
2296 {
2297 *dest->tail = item;
2298 dest->tail = &(*dest->tail)->next;
2299 dest->count++;
2300 }
2301
2302 static struct isis_item *last_item(struct isis_item_list *list)
2303 {
2304 return container_of(list->tail, struct isis_item, next);
2305 }
2306
2307 static int unpack_item(uint16_t mtid, enum isis_tlv_context context,
2308 uint8_t tlv_type, uint8_t len, struct stream *s,
2309 struct sbuf *log, void *dest, int indent)
2310 {
2311 const struct tlv_ops *ops = tlv_table[context][tlv_type];
2312
2313 if (ops && ops->unpack_item)
2314 return ops->unpack_item(mtid, len, s, log, dest, indent);
2315
2316 assert(!"Unknown item tlv type!");
2317 sbuf_push(log, indent, "Unknown item tlv type!\n");
2318 return 1;
2319 }
2320
2321 static int unpack_tlv_with_items(enum isis_tlv_context context,
2322 uint8_t tlv_type, uint8_t tlv_len,
2323 struct stream *s, struct sbuf *log, void *dest,
2324 int indent)
2325 {
2326 size_t tlv_start;
2327 size_t tlv_pos;
2328 int rv;
2329 uint16_t mtid;
2330
2331 tlv_start = stream_get_getp(s);
2332 tlv_pos = 0;
2333
2334 if (context == ISIS_CONTEXT_LSP && IS_COMPAT_MT_TLV(tlv_type)) {
2335 if (tlv_len < 2) {
2336 sbuf_push(log, indent,
2337 "TLV is too short to contain MTID\n");
2338 return 1;
2339 }
2340 mtid = stream_getw(s) & ISIS_MT_MASK;
2341 tlv_pos += 2;
2342 sbuf_push(log, indent, "Unpacking as MT %s item TLV...\n",
2343 isis_mtid2str(mtid));
2344 } else {
2345 sbuf_push(log, indent, "Unpacking as item TLV...\n");
2346 mtid = ISIS_MT_IPV4_UNICAST;
2347 }
2348
2349 if (context == ISIS_CONTEXT_LSP
2350 && tlv_type == ISIS_TLV_OLDSTYLE_REACH) {
2351 if (tlv_len - tlv_pos < 1) {
2352 sbuf_push(log, indent,
2353 "TLV is too short for old style reach\n");
2354 return 1;
2355 }
2356 stream_forward_getp(s, 1);
2357 tlv_pos += 1;
2358 }
2359
2360 if (context == ISIS_CONTEXT_LSP
2361 && tlv_type == ISIS_TLV_OLDSTYLE_IP_REACH) {
2362 struct isis_tlvs *tlvs = dest;
2363 dest = &tlvs->oldstyle_ip_reach;
2364 } else if (context == ISIS_CONTEXT_LSP
2365 && tlv_type == ISIS_TLV_OLDSTYLE_IP_REACH_EXT) {
2366 struct isis_tlvs *tlvs = dest;
2367 dest = &tlvs->oldstyle_ip_reach_ext;
2368 }
2369
2370 if (context == ISIS_CONTEXT_LSP
2371 && tlv_type == ISIS_TLV_MT_ROUTER_INFO) {
2372 struct isis_tlvs *tlvs = dest;
2373 tlvs->mt_router_info_empty = (tlv_pos >= (size_t)tlv_len);
2374 }
2375
2376 while (tlv_pos < (size_t)tlv_len) {
2377 rv = unpack_item(mtid, context, tlv_type, tlv_len - tlv_pos, s,
2378 log, dest, indent + 2);
2379 if (rv)
2380 return rv;
2381
2382 tlv_pos = stream_get_getp(s) - tlv_start;
2383 }
2384
2385 return 0;
2386 }
2387
2388 /* Functions to manipulate mt_item_lists */
2389
2390 static int isis_mt_item_list_cmp(const struct isis_item_list *a,
2391 const struct isis_item_list *b)
2392 {
2393 if (a->mtid < b->mtid)
2394 return -1;
2395 if (a->mtid > b->mtid)
2396 return 1;
2397 return 0;
2398 }
2399
2400 RB_PROTOTYPE(isis_mt_item_list, isis_item_list, mt_tree, isis_mt_item_list_cmp);
2401 RB_GENERATE(isis_mt_item_list, isis_item_list, mt_tree, isis_mt_item_list_cmp);
2402
2403 struct isis_item_list *isis_get_mt_items(struct isis_mt_item_list *m,
2404 uint16_t mtid)
2405 {
2406 struct isis_item_list *rv;
2407
2408 rv = isis_lookup_mt_items(m, mtid);
2409 if (!rv) {
2410 rv = XCALLOC(MTYPE_ISIS_MT_ITEM_LIST, sizeof(*rv));
2411 init_item_list(rv);
2412 rv->mtid = mtid;
2413 RB_INSERT(isis_mt_item_list, m, rv);
2414 }
2415
2416 return rv;
2417 }
2418
2419 struct isis_item_list *isis_lookup_mt_items(struct isis_mt_item_list *m,
2420 uint16_t mtid)
2421 {
2422 struct isis_item_list key = {.mtid = mtid};
2423
2424 return RB_FIND(isis_mt_item_list, m, &key);
2425 }
2426
2427 static void free_mt_items(enum isis_tlv_context context,
2428 enum isis_tlv_type type, struct isis_mt_item_list *m)
2429 {
2430 struct isis_item_list *n, *nnext;
2431
2432 RB_FOREACH_SAFE (n, isis_mt_item_list, m, nnext) {
2433 free_items(context, type, n);
2434 RB_REMOVE(isis_mt_item_list, m, n);
2435 XFREE(MTYPE_ISIS_MT_ITEM_LIST, n);
2436 }
2437 }
2438
2439 static void format_mt_items(enum isis_tlv_context context,
2440 enum isis_tlv_type type,
2441 struct isis_mt_item_list *m, struct sbuf *buf,
2442 int indent)
2443 {
2444 struct isis_item_list *n;
2445
2446 RB_FOREACH (n, isis_mt_item_list, m) {
2447 format_items_(n->mtid, context, type, n, buf, indent);
2448 }
2449 }
2450
2451 static int pack_mt_items(enum isis_tlv_context context, enum isis_tlv_type type,
2452 struct isis_mt_item_list *m, struct stream *s,
2453 struct isis_tlvs **fragment_tlvs,
2454 struct pack_order_entry *pe,
2455 struct isis_tlvs *(*new_fragment)(struct list *l),
2456 struct list *new_fragment_arg)
2457 {
2458 struct isis_item_list *n;
2459
2460 RB_FOREACH (n, isis_mt_item_list, m) {
2461 int rv;
2462
2463 rv = pack_items_(n->mtid, context, type, n, s, fragment_tlvs,
2464 pe, new_fragment, new_fragment_arg);
2465 if (rv)
2466 return rv;
2467 }
2468
2469 return 0;
2470 }
2471
2472 static void copy_mt_items(enum isis_tlv_context context,
2473 enum isis_tlv_type type,
2474 struct isis_mt_item_list *src,
2475 struct isis_mt_item_list *dest)
2476 {
2477 struct isis_item_list *n;
2478
2479 RB_INIT(isis_mt_item_list, dest);
2480
2481 RB_FOREACH (n, isis_mt_item_list, src) {
2482 copy_items(context, type, n, isis_get_mt_items(dest, n->mtid));
2483 }
2484 }
2485
2486 /* Functions related to tlvs in general */
2487
2488 struct isis_tlvs *isis_alloc_tlvs(void)
2489 {
2490 struct isis_tlvs *result;
2491
2492 result = XCALLOC(MTYPE_ISIS_TLV, sizeof(*result));
2493
2494 init_item_list(&result->isis_auth);
2495 init_item_list(&result->area_addresses);
2496 init_item_list(&result->mt_router_info);
2497 init_item_list(&result->oldstyle_reach);
2498 init_item_list(&result->lan_neighbor);
2499 init_item_list(&result->lsp_entries);
2500 init_item_list(&result->extended_reach);
2501 RB_INIT(isis_mt_item_list, &result->mt_reach);
2502 init_item_list(&result->oldstyle_ip_reach);
2503 init_item_list(&result->oldstyle_ip_reach_ext);
2504 init_item_list(&result->ipv4_address);
2505 init_item_list(&result->ipv6_address);
2506 init_item_list(&result->extended_ip_reach);
2507 RB_INIT(isis_mt_item_list, &result->mt_ip_reach);
2508 init_item_list(&result->ipv6_reach);
2509 RB_INIT(isis_mt_item_list, &result->mt_ipv6_reach);
2510
2511 return result;
2512 }
2513
2514 struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs)
2515 {
2516 struct isis_tlvs *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2517
2518 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth,
2519 &rv->isis_auth);
2520
2521 rv->purge_originator =
2522 copy_tlv_purge_originator(tlvs->purge_originator);
2523
2524 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
2525 &tlvs->area_addresses, &rv->area_addresses);
2526
2527 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
2528 &tlvs->mt_router_info, &rv->mt_router_info);
2529
2530 rv->mt_router_info_empty = tlvs->mt_router_info_empty;
2531
2532 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
2533 &tlvs->oldstyle_reach, &rv->oldstyle_reach);
2534
2535 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
2536 &tlvs->lan_neighbor, &rv->lan_neighbor);
2537
2538 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries,
2539 &rv->lsp_entries);
2540
2541 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
2542 &tlvs->extended_reach, &rv->extended_reach);
2543
2544 copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach,
2545 &rv->mt_reach);
2546
2547 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
2548 &tlvs->oldstyle_ip_reach, &rv->oldstyle_ip_reach);
2549
2550 copy_tlv_protocols_supported(&tlvs->protocols_supported,
2551 &rv->protocols_supported);
2552
2553 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
2554 &tlvs->oldstyle_ip_reach_ext, &rv->oldstyle_ip_reach_ext);
2555
2556 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS, &tlvs->ipv4_address,
2557 &rv->ipv4_address);
2558
2559 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS, &tlvs->ipv6_address,
2560 &rv->ipv6_address);
2561
2562 rv->te_router_id = copy_tlv_te_router_id(tlvs->te_router_id);
2563
2564 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
2565 &tlvs->extended_ip_reach, &rv->extended_ip_reach);
2566
2567 copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
2568 &tlvs->mt_ip_reach, &rv->mt_ip_reach);
2569
2570 rv->hostname = copy_tlv_dynamic_hostname(tlvs->hostname);
2571
2572 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach,
2573 &rv->ipv6_reach);
2574
2575 copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
2576 &tlvs->mt_ipv6_reach, &rv->mt_ipv6_reach);
2577
2578 rv->threeway_adj = copy_tlv_threeway_adj(tlvs->threeway_adj);
2579
2580 rv->spine_leaf = copy_tlv_spine_leaf(tlvs->spine_leaf);
2581
2582 return rv;
2583 }
2584
2585 static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent)
2586 {
2587 format_tlv_protocols_supported(&tlvs->protocols_supported, buf, indent);
2588
2589 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth, buf,
2590 indent);
2591
2592 format_tlv_purge_originator(tlvs->purge_originator, buf, indent);
2593
2594 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
2595 &tlvs->area_addresses, buf, indent);
2596
2597 if (tlvs->mt_router_info_empty) {
2598 sbuf_push(buf, indent, "MT Router Info: None\n");
2599 } else {
2600 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
2601 &tlvs->mt_router_info, buf, indent);
2602 }
2603
2604 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
2605 &tlvs->oldstyle_reach, buf, indent);
2606
2607 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
2608 &tlvs->lan_neighbor, buf, indent);
2609
2610 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries,
2611 buf, indent);
2612
2613 format_tlv_dynamic_hostname(tlvs->hostname, buf, indent);
2614 format_tlv_te_router_id(tlvs->te_router_id, buf, indent);
2615
2616 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
2617 &tlvs->extended_reach, buf, indent);
2618
2619 format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach,
2620 buf, indent);
2621
2622 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
2623 &tlvs->oldstyle_ip_reach, buf, indent);
2624
2625 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
2626 &tlvs->oldstyle_ip_reach_ext, buf, indent);
2627
2628 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS,
2629 &tlvs->ipv4_address, buf, indent);
2630
2631 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS,
2632 &tlvs->ipv6_address, buf, indent);
2633
2634 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
2635 &tlvs->extended_ip_reach, buf, indent);
2636
2637 format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
2638 &tlvs->mt_ip_reach, buf, indent);
2639
2640 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach,
2641 buf, indent);
2642
2643 format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
2644 &tlvs->mt_ipv6_reach, buf, indent);
2645
2646 format_tlv_threeway_adj(tlvs->threeway_adj, buf, indent);
2647
2648 format_tlv_spine_leaf(tlvs->spine_leaf, buf, indent);
2649 }
2650
2651 const char *isis_format_tlvs(struct isis_tlvs *tlvs)
2652 {
2653 static struct sbuf buf;
2654
2655 if (!sbuf_buf(&buf))
2656 sbuf_init(&buf, NULL, 0);
2657
2658 sbuf_reset(&buf);
2659 format_tlvs(tlvs, &buf, 0);
2660 return sbuf_buf(&buf);
2661 }
2662
2663 void isis_free_tlvs(struct isis_tlvs *tlvs)
2664 {
2665 if (!tlvs)
2666 return;
2667
2668 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth);
2669 free_tlv_purge_originator(tlvs->purge_originator);
2670 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
2671 &tlvs->area_addresses);
2672 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
2673 &tlvs->mt_router_info);
2674 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
2675 &tlvs->oldstyle_reach);
2676 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
2677 &tlvs->lan_neighbor);
2678 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries);
2679 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
2680 &tlvs->extended_reach);
2681 free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach);
2682 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
2683 &tlvs->oldstyle_ip_reach);
2684 free_tlv_protocols_supported(&tlvs->protocols_supported);
2685 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
2686 &tlvs->oldstyle_ip_reach_ext);
2687 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS,
2688 &tlvs->ipv4_address);
2689 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS,
2690 &tlvs->ipv6_address);
2691 free_tlv_te_router_id(tlvs->te_router_id);
2692 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
2693 &tlvs->extended_ip_reach);
2694 free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
2695 &tlvs->mt_ip_reach);
2696 free_tlv_dynamic_hostname(tlvs->hostname);
2697 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach);
2698 free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
2699 &tlvs->mt_ipv6_reach);
2700 free_tlv_threeway_adj(tlvs->threeway_adj);
2701 free_tlv_spine_leaf(tlvs->spine_leaf);
2702
2703 XFREE(MTYPE_ISIS_TLV, tlvs);
2704 }
2705
2706 static void add_padding(struct stream *s)
2707 {
2708 while (STREAM_WRITEABLE(s)) {
2709 if (STREAM_WRITEABLE(s) == 1)
2710 break;
2711 uint32_t padding_len = STREAM_WRITEABLE(s) - 2;
2712
2713 if (padding_len > 255) {
2714 if (padding_len == 256)
2715 padding_len = 254;
2716 else
2717 padding_len = 255;
2718 }
2719
2720 stream_putc(s, ISIS_TLV_PADDING);
2721 stream_putc(s, padding_len);
2722 stream_put(s, NULL, padding_len);
2723 }
2724 }
2725
2726 #define LSP_REM_LIFETIME_OFF 10
2727 #define LSP_CHECKSUM_OFF 24
2728 static void safe_auth_md5(struct stream *s, uint16_t *checksum,
2729 uint16_t *rem_lifetime)
2730 {
2731 memcpy(rem_lifetime, STREAM_DATA(s) + LSP_REM_LIFETIME_OFF,
2732 sizeof(*rem_lifetime));
2733 memset(STREAM_DATA(s) + LSP_REM_LIFETIME_OFF, 0, sizeof(*rem_lifetime));
2734 memcpy(checksum, STREAM_DATA(s) + LSP_CHECKSUM_OFF, sizeof(*checksum));
2735 memset(STREAM_DATA(s) + LSP_CHECKSUM_OFF, 0, sizeof(*checksum));
2736 }
2737
2738 static void restore_auth_md5(struct stream *s, uint16_t checksum,
2739 uint16_t rem_lifetime)
2740 {
2741 memcpy(STREAM_DATA(s) + LSP_REM_LIFETIME_OFF, &rem_lifetime,
2742 sizeof(rem_lifetime));
2743 memcpy(STREAM_DATA(s) + LSP_CHECKSUM_OFF, &checksum, sizeof(checksum));
2744 }
2745
2746 static void update_auth_hmac_md5(struct isis_auth *auth, struct stream *s,
2747 bool is_lsp)
2748 {
2749 uint8_t digest[16];
2750 uint16_t checksum, rem_lifetime;
2751
2752 if (is_lsp)
2753 safe_auth_md5(s, &checksum, &rem_lifetime);
2754
2755 memset(STREAM_DATA(s) + auth->offset, 0, 16);
2756 hmac_md5(STREAM_DATA(s), stream_get_endp(s), auth->passwd,
2757 auth->plength, digest);
2758 memcpy(auth->value, digest, 16);
2759 memcpy(STREAM_DATA(s) + auth->offset, digest, 16);
2760
2761 if (is_lsp)
2762 restore_auth_md5(s, checksum, rem_lifetime);
2763 }
2764
2765 static void update_auth(struct isis_tlvs *tlvs, struct stream *s, bool is_lsp)
2766 {
2767 struct isis_auth *auth_head = (struct isis_auth *)tlvs->isis_auth.head;
2768
2769 for (struct isis_auth *auth = auth_head; auth; auth = auth->next) {
2770 if (auth->type == ISIS_PASSWD_TYPE_HMAC_MD5)
2771 update_auth_hmac_md5(auth, s, is_lsp);
2772 }
2773 }
2774
2775 static int handle_pack_entry(struct pack_order_entry *pe,
2776 struct isis_tlvs *tlvs, struct stream *stream,
2777 struct isis_tlvs **fragment_tlvs,
2778 struct isis_tlvs *(*new_fragment)(struct list *l),
2779 struct list *new_fragment_arg)
2780 {
2781 int rv;
2782
2783 if (pe->how_to_pack == ISIS_ITEMS) {
2784 struct isis_item_list *l;
2785 l = (struct isis_item_list *)(((char *)tlvs)
2786 + pe->what_to_pack);
2787 rv = pack_items(pe->context, pe->type, l, stream, fragment_tlvs,
2788 pe, new_fragment, new_fragment_arg);
2789 } else {
2790 struct isis_mt_item_list *l;
2791 l = (struct isis_mt_item_list *)(((char *)tlvs)
2792 + pe->what_to_pack);
2793 rv = pack_mt_items(pe->context, pe->type, l, stream,
2794 fragment_tlvs, pe, new_fragment,
2795 new_fragment_arg);
2796 }
2797
2798 return rv;
2799 }
2800
2801 static int pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
2802 struct isis_tlvs *fragment_tlvs,
2803 struct isis_tlvs *(*new_fragment)(struct list *l),
2804 struct list *new_fragment_arg)
2805 {
2806 int rv;
2807
2808 /* When fragmenting, don't add auth as it's already accounted for in the
2809 * size we are given. */
2810 if (!fragment_tlvs) {
2811 rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH,
2812 &tlvs->isis_auth, stream, NULL, NULL, NULL,
2813 NULL);
2814 if (rv)
2815 return rv;
2816 }
2817
2818 rv = pack_tlv_purge_originator(tlvs->purge_originator, stream);
2819 if (rv)
2820 return rv;
2821 if (fragment_tlvs) {
2822 fragment_tlvs->purge_originator =
2823 copy_tlv_purge_originator(tlvs->purge_originator);
2824 }
2825
2826 rv = pack_tlv_protocols_supported(&tlvs->protocols_supported, stream);
2827 if (rv)
2828 return rv;
2829 if (fragment_tlvs) {
2830 copy_tlv_protocols_supported(
2831 &tlvs->protocols_supported,
2832 &fragment_tlvs->protocols_supported);
2833 }
2834
2835 rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
2836 &tlvs->area_addresses, stream, NULL, NULL, NULL, NULL);
2837 if (rv)
2838 return rv;
2839 if (fragment_tlvs) {
2840 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
2841 &tlvs->area_addresses,
2842 &fragment_tlvs->area_addresses);
2843 }
2844
2845
2846 if (tlvs->mt_router_info_empty) {
2847 if (STREAM_WRITEABLE(stream) < 2)
2848 return 1;
2849 stream_putc(stream, ISIS_TLV_MT_ROUTER_INFO);
2850 stream_putc(stream, 0);
2851 if (fragment_tlvs)
2852 fragment_tlvs->mt_router_info_empty = true;
2853 } else {
2854 rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
2855 &tlvs->mt_router_info, stream, NULL, NULL, NULL,
2856 NULL);
2857 if (rv)
2858 return rv;
2859 if (fragment_tlvs) {
2860 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
2861 &tlvs->mt_router_info,
2862 &fragment_tlvs->mt_router_info);
2863 }
2864 }
2865
2866 rv = pack_tlv_dynamic_hostname(tlvs->hostname, stream);
2867 if (rv)
2868 return rv;
2869 if (fragment_tlvs)
2870 fragment_tlvs->hostname =
2871 copy_tlv_dynamic_hostname(tlvs->hostname);
2872
2873 rv = pack_tlv_te_router_id(tlvs->te_router_id, stream);
2874 if (rv)
2875 return rv;
2876 if (fragment_tlvs) {
2877 fragment_tlvs->te_router_id =
2878 copy_tlv_te_router_id(tlvs->te_router_id);
2879 }
2880
2881 rv = pack_tlv_threeway_adj(tlvs->threeway_adj, stream);
2882 if (rv)
2883 return rv;
2884 if (fragment_tlvs) {
2885 fragment_tlvs->threeway_adj =
2886 copy_tlv_threeway_adj(tlvs->threeway_adj);
2887 }
2888
2889 rv = pack_tlv_spine_leaf(tlvs->spine_leaf, stream);
2890 if (rv)
2891 return rv;
2892 if (fragment_tlvs) {
2893 fragment_tlvs->spine_leaf =
2894 copy_tlv_spine_leaf(tlvs->spine_leaf);
2895 }
2896
2897 for (size_t pack_idx = 0; pack_idx < array_size(pack_order);
2898 pack_idx++) {
2899 rv = handle_pack_entry(&pack_order[pack_idx], tlvs, stream,
2900 fragment_tlvs ? &fragment_tlvs : NULL,
2901 new_fragment, new_fragment_arg);
2902
2903 if (rv)
2904 return rv;
2905 }
2906
2907 return 0;
2908 }
2909
2910 int isis_pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
2911 size_t len_pointer, bool pad, bool is_lsp)
2912 {
2913 int rv;
2914
2915 rv = pack_tlvs(tlvs, stream, NULL, NULL, NULL);
2916 if (rv)
2917 return rv;
2918
2919 if (pad)
2920 add_padding(stream);
2921
2922 if (len_pointer != (size_t)-1) {
2923 stream_putw_at(stream, len_pointer, stream_get_endp(stream));
2924 }
2925
2926 update_auth(tlvs, stream, is_lsp);
2927
2928 return 0;
2929 }
2930
2931 static struct isis_tlvs *new_fragment(struct list *l)
2932 {
2933 struct isis_tlvs *rv = isis_alloc_tlvs();
2934
2935 listnode_add(l, rv);
2936 return rv;
2937 }
2938
2939 struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size)
2940 {
2941 struct stream *dummy_stream = stream_new(size);
2942 struct list *rv = list_new();
2943 struct isis_tlvs *fragment_tlvs = new_fragment(rv);
2944
2945 if (pack_tlvs(tlvs, dummy_stream, fragment_tlvs, new_fragment, rv)) {
2946 struct listnode *node;
2947 for (ALL_LIST_ELEMENTS_RO(rv, node, fragment_tlvs))
2948 isis_free_tlvs(fragment_tlvs);
2949 list_delete(&rv);
2950 }
2951
2952 stream_free(dummy_stream);
2953 return rv;
2954 }
2955
2956 static int unpack_tlv_unknown(enum isis_tlv_context context, uint8_t tlv_type,
2957 uint8_t tlv_len, struct stream *s,
2958 struct sbuf *log, int indent)
2959 {
2960 stream_forward_getp(s, tlv_len);
2961 sbuf_push(log, indent,
2962 "Skipping unknown TLV %" PRIu8 " (%" PRIu8 " bytes)\n",
2963 tlv_type, tlv_len);
2964 return 0;
2965 }
2966
2967 static int unpack_tlv(enum isis_tlv_context context, size_t avail_len,
2968 struct stream *stream, struct sbuf *log, void *dest,
2969 int indent)
2970 {
2971 uint8_t tlv_type, tlv_len;
2972 const struct tlv_ops *ops;
2973
2974 sbuf_push(log, indent, "Unpacking TLV...\n");
2975
2976 if (avail_len < 2) {
2977 sbuf_push(
2978 log, indent + 2,
2979 "Available data %zu too short to contain a TLV header.\n",
2980 avail_len);
2981 return 1;
2982 }
2983
2984 tlv_type = stream_getc(stream);
2985 tlv_len = stream_getc(stream);
2986
2987 sbuf_push(log, indent + 2,
2988 "Found TLV of type %" PRIu8 " and len %" PRIu8 ".\n",
2989 tlv_type, tlv_len);
2990
2991 if (avail_len < ((size_t)tlv_len) + 2) {
2992 sbuf_push(log, indent + 2,
2993 "Available data %zu too short for claimed TLV len %" PRIu8 ".\n",
2994 avail_len - 2, tlv_len);
2995 return 1;
2996 }
2997
2998 ops = tlv_table[context][tlv_type];
2999 if (ops && ops->unpack) {
3000 return ops->unpack(context, tlv_type, tlv_len, stream, log,
3001 dest, indent + 2);
3002 }
3003
3004 return unpack_tlv_unknown(context, tlv_type, tlv_len, stream, log,
3005 indent + 2);
3006 }
3007
3008 static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len,
3009 struct stream *stream, struct sbuf *log, void *dest,
3010 int indent)
3011 {
3012 int rv;
3013 size_t tlv_start, tlv_pos;
3014
3015 tlv_start = stream_get_getp(stream);
3016 tlv_pos = 0;
3017
3018 sbuf_push(log, indent, "Unpacking %zu bytes of %s...\n", avail_len,
3019 (context == ISIS_CONTEXT_LSP) ? "TLVs" : "sub-TLVs");
3020
3021 while (tlv_pos < avail_len) {
3022 rv = unpack_tlv(context, avail_len - tlv_pos, stream, log, dest,
3023 indent + 2);
3024 if (rv)
3025 return rv;
3026
3027 tlv_pos = stream_get_getp(stream) - tlv_start;
3028 }
3029
3030 return 0;
3031 }
3032
3033 int isis_unpack_tlvs(size_t avail_len, struct stream *stream,
3034 struct isis_tlvs **dest, const char **log)
3035 {
3036 static struct sbuf logbuf;
3037 int indent = 0;
3038 int rv;
3039 struct isis_tlvs *result;
3040
3041 if (!sbuf_buf(&logbuf))
3042 sbuf_init(&logbuf, NULL, 0);
3043
3044 sbuf_reset(&logbuf);
3045 if (avail_len > STREAM_READABLE(stream)) {
3046 sbuf_push(&logbuf, indent,
3047 "Stream doesn't contain sufficient data. "
3048 "Claimed %zu, available %zu\n",
3049 avail_len, STREAM_READABLE(stream));
3050 return 1;
3051 }
3052
3053 result = isis_alloc_tlvs();
3054 rv = unpack_tlvs(ISIS_CONTEXT_LSP, avail_len, stream, &logbuf, result,
3055 indent);
3056
3057 *log = sbuf_buf(&logbuf);
3058 *dest = result;
3059
3060 return rv;
3061 }
3062
3063 #define TLV_OPS(_name_, _desc_) \
3064 static const struct tlv_ops tlv_##_name_##_ops = { \
3065 .name = _desc_, .unpack = unpack_tlv_##_name_, \
3066 }
3067
3068 #define ITEM_TLV_OPS(_name_, _desc_) \
3069 static const struct tlv_ops tlv_##_name_##_ops = { \
3070 .name = _desc_, \
3071 .unpack = unpack_tlv_with_items, \
3072 \
3073 .pack_item = pack_item_##_name_, \
3074 .free_item = free_item_##_name_, \
3075 .unpack_item = unpack_item_##_name_, \
3076 .format_item = format_item_##_name_, \
3077 .copy_item = copy_item_##_name_}
3078
3079 #define SUBTLV_OPS(_name_, _desc_) \
3080 static const struct tlv_ops subtlv_##_name_##_ops = { \
3081 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
3082 }
3083
3084 #define ITEM_SUBTLV_OPS(_name_, _desc_) \
3085 ITEM_TLV_OPS(_name_, _desc_)
3086
3087 ITEM_TLV_OPS(area_address, "TLV 1 Area Addresses");
3088 ITEM_TLV_OPS(oldstyle_reach, "TLV 2 IS Reachability");
3089 ITEM_TLV_OPS(lan_neighbor, "TLV 6 LAN Neighbors");
3090 ITEM_TLV_OPS(lsp_entry, "TLV 9 LSP Entries");
3091 ITEM_TLV_OPS(auth, "TLV 10 IS-IS Auth");
3092 TLV_OPS(purge_originator, "TLV 13 Purge Originator Identification");
3093 ITEM_TLV_OPS(extended_reach, "TLV 22 Extended Reachability");
3094 ITEM_TLV_OPS(oldstyle_ip_reach, "TLV 128/130 IP Reachability");
3095 TLV_OPS(protocols_supported, "TLV 129 Protocols Supported");
3096 ITEM_TLV_OPS(ipv4_address, "TLV 132 IPv4 Interface Address");
3097 TLV_OPS(te_router_id, "TLV 134 TE Router ID");
3098 ITEM_TLV_OPS(extended_ip_reach, "TLV 135 Extended IP Reachability");
3099 TLV_OPS(dynamic_hostname, "TLV 137 Dynamic Hostname");
3100 TLV_OPS(spine_leaf, "TLV 150 Spine Leaf Extensions");
3101 ITEM_TLV_OPS(mt_router_info, "TLV 229 MT Router Information");
3102 TLV_OPS(threeway_adj, "TLV 240 P2P Three-Way Adjacency");
3103 ITEM_TLV_OPS(ipv6_address, "TLV 232 IPv6 Interface Address");
3104 ITEM_TLV_OPS(ipv6_reach, "TLV 236 IPv6 Reachability");
3105
3106 ITEM_SUBTLV_OPS(prefix_sid, "Sub-TLV 3 SR Prefix-SID");
3107 SUBTLV_OPS(ipv6_source_prefix, "Sub-TLV 22 IPv6 Source Prefix");
3108
3109 static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
3110 [ISIS_CONTEXT_LSP] = {
3111 [ISIS_TLV_AREA_ADDRESSES] = &tlv_area_address_ops,
3112 [ISIS_TLV_OLDSTYLE_REACH] = &tlv_oldstyle_reach_ops,
3113 [ISIS_TLV_LAN_NEIGHBORS] = &tlv_lan_neighbor_ops,
3114 [ISIS_TLV_LSP_ENTRY] = &tlv_lsp_entry_ops,
3115 [ISIS_TLV_AUTH] = &tlv_auth_ops,
3116 [ISIS_TLV_PURGE_ORIGINATOR] = &tlv_purge_originator_ops,
3117 [ISIS_TLV_EXTENDED_REACH] = &tlv_extended_reach_ops,
3118 [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops,
3119 [ISIS_TLV_OLDSTYLE_IP_REACH] = &tlv_oldstyle_ip_reach_ops,
3120 [ISIS_TLV_PROTOCOLS_SUPPORTED] = &tlv_protocols_supported_ops,
3121 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT] = &tlv_oldstyle_ip_reach_ops,
3122 [ISIS_TLV_IPV4_ADDRESS] = &tlv_ipv4_address_ops,
3123 [ISIS_TLV_TE_ROUTER_ID] = &tlv_te_router_id_ops,
3124 [ISIS_TLV_EXTENDED_IP_REACH] = &tlv_extended_ip_reach_ops,
3125 [ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops,
3126 [ISIS_TLV_DYNAMIC_HOSTNAME] = &tlv_dynamic_hostname_ops,
3127 [ISIS_TLV_SPINE_LEAF_EXT] = &tlv_spine_leaf_ops,
3128 [ISIS_TLV_MT_ROUTER_INFO] = &tlv_mt_router_info_ops,
3129 [ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops,
3130 [ISIS_TLV_IPV6_ADDRESS] = &tlv_ipv6_address_ops,
3131 [ISIS_TLV_IPV6_REACH] = &tlv_ipv6_reach_ops,
3132 [ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops,
3133 },
3134 [ISIS_CONTEXT_SUBTLV_NE_REACH] = {},
3135 [ISIS_CONTEXT_SUBTLV_IP_REACH] = {
3136 [ISIS_SUBTLV_PREFIX_SID] = &tlv_prefix_sid_ops,
3137 },
3138 [ISIS_CONTEXT_SUBTLV_IPV6_REACH] = {
3139 [ISIS_SUBTLV_PREFIX_SID] = &tlv_prefix_sid_ops,
3140 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX] = &subtlv_ipv6_source_prefix_ops,
3141 }
3142 };
3143
3144 /* Accessor functions */
3145
3146 void isis_tlvs_add_auth(struct isis_tlvs *tlvs, struct isis_passwd *passwd)
3147 {
3148 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth);
3149 init_item_list(&tlvs->isis_auth);
3150
3151 if (passwd->type == ISIS_PASSWD_TYPE_UNUSED)
3152 return;
3153
3154 struct isis_auth *auth = XCALLOC(MTYPE_ISIS_TLV, sizeof(*auth));
3155
3156 auth->type = passwd->type;
3157
3158 auth->plength = passwd->len;
3159 memcpy(auth->passwd, passwd->passwd,
3160 MIN(sizeof(auth->passwd), sizeof(passwd->passwd)));
3161
3162 if (auth->type == ISIS_PASSWD_TYPE_CLEARTXT) {
3163 auth->length = passwd->len;
3164 memcpy(auth->value, passwd->passwd,
3165 MIN(sizeof(auth->value), sizeof(passwd->passwd)));
3166 }
3167
3168 append_item(&tlvs->isis_auth, (struct isis_item *)auth);
3169 }
3170
3171 void isis_tlvs_add_area_addresses(struct isis_tlvs *tlvs,
3172 struct list *addresses)
3173 {
3174 struct listnode *node;
3175 struct area_addr *area_addr;
3176
3177 for (ALL_LIST_ELEMENTS_RO(addresses, node, area_addr)) {
3178 struct isis_area_address *a =
3179 XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
3180
3181 a->len = area_addr->addr_len;
3182 memcpy(a->addr, area_addr->area_addr, 20);
3183 append_item(&tlvs->area_addresses, (struct isis_item *)a);
3184 }
3185 }
3186
3187 void isis_tlvs_add_lan_neighbors(struct isis_tlvs *tlvs, struct list *neighbors)
3188 {
3189 struct listnode *node;
3190 uint8_t *snpa;
3191
3192 for (ALL_LIST_ELEMENTS_RO(neighbors, node, snpa)) {
3193 struct isis_lan_neighbor *n =
3194 XCALLOC(MTYPE_ISIS_TLV, sizeof(*n));
3195
3196 memcpy(n->mac, snpa, 6);
3197 append_item(&tlvs->lan_neighbor, (struct isis_item *)n);
3198 }
3199 }
3200
3201 void isis_tlvs_set_protocols_supported(struct isis_tlvs *tlvs,
3202 struct nlpids *nlpids)
3203 {
3204 tlvs->protocols_supported.count = nlpids->count;
3205 if (tlvs->protocols_supported.protocols)
3206 XFREE(MTYPE_ISIS_TLV, tlvs->protocols_supported.protocols);
3207 if (nlpids->count) {
3208 tlvs->protocols_supported.protocols =
3209 XCALLOC(MTYPE_ISIS_TLV, nlpids->count);
3210 memcpy(tlvs->protocols_supported.protocols, nlpids->nlpids,
3211 nlpids->count);
3212 } else {
3213 tlvs->protocols_supported.protocols = NULL;
3214 }
3215 }
3216
3217 void isis_tlvs_add_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid,
3218 bool overload, bool attached)
3219 {
3220 struct isis_mt_router_info *i = XCALLOC(MTYPE_ISIS_TLV, sizeof(*i));
3221
3222 i->overload = overload;
3223 i->attached = attached;
3224 i->mtid = mtid;
3225 append_item(&tlvs->mt_router_info, (struct isis_item *)i);
3226 }
3227
3228 void isis_tlvs_add_ipv4_address(struct isis_tlvs *tlvs, struct in_addr *addr)
3229 {
3230 struct isis_ipv4_address *a = XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
3231 a->addr = *addr;
3232 append_item(&tlvs->ipv4_address, (struct isis_item *)a);
3233 }
3234
3235
3236 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs *tlvs,
3237 struct list *addresses)
3238 {
3239 struct listnode *node;
3240 struct prefix_ipv4 *ip_addr;
3241 unsigned int addr_count = 0;
3242
3243 for (ALL_LIST_ELEMENTS_RO(addresses, node, ip_addr)) {
3244 isis_tlvs_add_ipv4_address(tlvs, &ip_addr->prefix);
3245 addr_count++;
3246 if (addr_count >= 63)
3247 break;
3248 }
3249 }
3250
3251 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs *tlvs,
3252 struct list *addresses)
3253 {
3254 struct listnode *node;
3255 struct prefix_ipv6 *ip_addr;
3256
3257 for (ALL_LIST_ELEMENTS_RO(addresses, node, ip_addr)) {
3258 struct isis_ipv6_address *a =
3259 XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
3260
3261 a->addr = ip_addr->prefix;
3262 append_item(&tlvs->ipv6_address, (struct isis_item *)a);
3263 }
3264 }
3265
3266 typedef bool (*auth_validator_func)(struct isis_passwd *passwd,
3267 struct stream *stream,
3268 struct isis_auth *auth, bool is_lsp);
3269
3270 static bool auth_validator_cleartxt(struct isis_passwd *passwd,
3271 struct stream *stream,
3272 struct isis_auth *auth, bool is_lsp)
3273 {
3274 return (auth->length == passwd->len
3275 && !memcmp(auth->value, passwd->passwd, passwd->len));
3276 }
3277
3278 static bool auth_validator_hmac_md5(struct isis_passwd *passwd,
3279 struct stream *stream,
3280 struct isis_auth *auth, bool is_lsp)
3281 {
3282 uint8_t digest[16];
3283 uint16_t checksum;
3284 uint16_t rem_lifetime;
3285
3286 if (is_lsp)
3287 safe_auth_md5(stream, &checksum, &rem_lifetime);
3288
3289 memset(STREAM_DATA(stream) + auth->offset, 0, 16);
3290 hmac_md5(STREAM_DATA(stream), stream_get_endp(stream), passwd->passwd,
3291 passwd->len, digest);
3292 memcpy(STREAM_DATA(stream) + auth->offset, auth->value, 16);
3293
3294 bool rv = !memcmp(digest, auth->value, 16);
3295
3296 if (is_lsp)
3297 restore_auth_md5(stream, checksum, rem_lifetime);
3298
3299 return rv;
3300 }
3301
3302 static const auth_validator_func auth_validators[] = {
3303 [ISIS_PASSWD_TYPE_CLEARTXT] = auth_validator_cleartxt,
3304 [ISIS_PASSWD_TYPE_HMAC_MD5] = auth_validator_hmac_md5,
3305 };
3306
3307 int isis_tlvs_auth_is_valid(struct isis_tlvs *tlvs, struct isis_passwd *passwd,
3308 struct stream *stream, bool is_lsp)
3309 {
3310 /* If no auth is set, always pass authentication */
3311 if (!passwd->type)
3312 return ISIS_AUTH_OK;
3313
3314 /* If we don't known how to validate the auth, return invalid */
3315 if (passwd->type >= array_size(auth_validators)
3316 || !auth_validators[passwd->type])
3317 return ISIS_AUTH_NO_VALIDATOR;
3318
3319 struct isis_auth *auth_head = (struct isis_auth *)tlvs->isis_auth.head;
3320 struct isis_auth *auth;
3321 for (auth = auth_head; auth; auth = auth->next) {
3322 if (auth->type == passwd->type)
3323 break;
3324 }
3325
3326 /* If matching auth TLV could not be found, return invalid */
3327 if (!auth)
3328 return ISIS_AUTH_TYPE_FAILURE;
3329
3330
3331 /* Perform validation and return result */
3332 if (auth_validators[passwd->type](passwd, stream, auth, is_lsp))
3333 return ISIS_AUTH_OK;
3334 else
3335 return ISIS_AUTH_FAILURE;
3336 }
3337
3338 bool isis_tlvs_area_addresses_match(struct isis_tlvs *tlvs,
3339 struct list *addresses)
3340 {
3341 struct isis_area_address *addr_head;
3342
3343 addr_head = (struct isis_area_address *)tlvs->area_addresses.head;
3344 for (struct isis_area_address *addr = addr_head; addr;
3345 addr = addr->next) {
3346 struct listnode *node;
3347 struct area_addr *a;
3348
3349 for (ALL_LIST_ELEMENTS_RO(addresses, node, a)) {
3350 if (a->addr_len == addr->len
3351 && !memcmp(a->area_addr, addr->addr, addr->len))
3352 return true;
3353 }
3354 }
3355
3356 return false;
3357 }
3358
3359 static void tlvs_area_addresses_to_adj(struct isis_tlvs *tlvs,
3360 struct isis_adjacency *adj,
3361 bool *changed)
3362 {
3363 if (adj->area_address_count != tlvs->area_addresses.count) {
3364 *changed = true;
3365 adj->area_address_count = tlvs->area_addresses.count;
3366 adj->area_addresses = XREALLOC(
3367 MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses,
3368 adj->area_address_count * sizeof(*adj->area_addresses));
3369 }
3370
3371 struct isis_area_address *addr = NULL;
3372 for (unsigned int i = 0; i < tlvs->area_addresses.count; i++) {
3373 if (!addr)
3374 addr = (struct isis_area_address *)
3375 tlvs->area_addresses.head;
3376 else
3377 addr = addr->next;
3378
3379 if (adj->area_addresses[i].addr_len == addr->len
3380 && !memcmp(adj->area_addresses[i].area_addr, addr->addr,
3381 addr->len)) {
3382 continue;
3383 }
3384
3385 *changed = true;
3386 adj->area_addresses[i].addr_len = addr->len;
3387 memcpy(adj->area_addresses[i].area_addr, addr->addr, addr->len);
3388 }
3389 }
3390
3391 static void tlvs_protocols_supported_to_adj(struct isis_tlvs *tlvs,
3392 struct isis_adjacency *adj,
3393 bool *changed)
3394 {
3395 bool ipv4_supported = false, ipv6_supported = false;
3396
3397 for (uint8_t i = 0; i < tlvs->protocols_supported.count; i++) {
3398 if (tlvs->protocols_supported.protocols[i] == NLPID_IP)
3399 ipv4_supported = true;
3400 if (tlvs->protocols_supported.protocols[i] == NLPID_IPV6)
3401 ipv6_supported = true;
3402 }
3403
3404 struct nlpids reduced = {};
3405
3406 if (ipv4_supported && ipv6_supported) {
3407 reduced.count = 2;
3408 reduced.nlpids[0] = NLPID_IP;
3409 reduced.nlpids[1] = NLPID_IPV6;
3410 } else if (ipv4_supported) {
3411 reduced.count = 1;
3412 reduced.nlpids[0] = NLPID_IP;
3413 } else if (ipv6_supported) {
3414 reduced.count = 1;
3415 reduced.nlpids[0] = NLPID_IPV6;
3416 } else {
3417 reduced.count = 0;
3418 }
3419
3420 if (adj->nlpids.count == reduced.count
3421 && !memcmp(adj->nlpids.nlpids, reduced.nlpids, reduced.count))
3422 return;
3423
3424 *changed = true;
3425 adj->nlpids.count = reduced.count;
3426 memcpy(adj->nlpids.nlpids, reduced.nlpids, reduced.count);
3427 }
3428
3429 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs *tlvs,
3430 struct isis_adjacency *adj,
3431 bool *changed)
3432 {
3433 if (adj->ipv4_address_count != tlvs->ipv4_address.count) {
3434 *changed = true;
3435 adj->ipv4_address_count = tlvs->ipv4_address.count;
3436 adj->ipv4_addresses = XREALLOC(
3437 MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses,
3438 adj->ipv4_address_count * sizeof(*adj->ipv4_addresses));
3439 }
3440
3441 struct isis_ipv4_address *addr = NULL;
3442 for (unsigned int i = 0; i < tlvs->ipv4_address.count; i++) {
3443 if (!addr)
3444 addr = (struct isis_ipv4_address *)
3445 tlvs->ipv4_address.head;
3446 else
3447 addr = addr->next;
3448
3449 if (!memcmp(&adj->ipv4_addresses[i], &addr->addr,
3450 sizeof(addr->addr)))
3451 continue;
3452
3453 *changed = true;
3454 adj->ipv4_addresses[i] = addr->addr;
3455 }
3456 }
3457
3458 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs *tlvs,
3459 struct isis_adjacency *adj,
3460 bool *changed)
3461 {
3462 if (adj->ipv6_address_count != tlvs->ipv6_address.count) {
3463 *changed = true;
3464 adj->ipv6_address_count = tlvs->ipv6_address.count;
3465 adj->ipv6_addresses = XREALLOC(
3466 MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses,
3467 adj->ipv6_address_count * sizeof(*adj->ipv6_addresses));
3468 }
3469
3470 struct isis_ipv6_address *addr = NULL;
3471 for (unsigned int i = 0; i < tlvs->ipv6_address.count; i++) {
3472 if (!addr)
3473 addr = (struct isis_ipv6_address *)
3474 tlvs->ipv6_address.head;
3475 else
3476 addr = addr->next;
3477
3478 if (!memcmp(&adj->ipv6_addresses[i], &addr->addr,
3479 sizeof(addr->addr)))
3480 continue;
3481
3482 *changed = true;
3483 adj->ipv6_addresses[i] = addr->addr;
3484 }
3485 }
3486
3487 void isis_tlvs_to_adj(struct isis_tlvs *tlvs, struct isis_adjacency *adj,
3488 bool *changed)
3489 {
3490 *changed = false;
3491
3492 tlvs_area_addresses_to_adj(tlvs, adj, changed);
3493 tlvs_protocols_supported_to_adj(tlvs, adj, changed);
3494 tlvs_ipv4_addresses_to_adj(tlvs, adj, changed);
3495 tlvs_ipv6_addresses_to_adj(tlvs, adj, changed);
3496 }
3497
3498 bool isis_tlvs_own_snpa_found(struct isis_tlvs *tlvs, uint8_t *snpa)
3499 {
3500 struct isis_lan_neighbor *ne_head;
3501
3502 ne_head = (struct isis_lan_neighbor *)tlvs->lan_neighbor.head;
3503 for (struct isis_lan_neighbor *ne = ne_head; ne; ne = ne->next) {
3504 if (!memcmp(ne->mac, snpa, ETH_ALEN))
3505 return true;
3506 }
3507
3508 return false;
3509 }
3510
3511 void isis_tlvs_add_lsp_entry(struct isis_tlvs *tlvs, struct isis_lsp *lsp)
3512 {
3513 struct isis_lsp_entry *entry = XCALLOC(MTYPE_ISIS_TLV, sizeof(*entry));
3514
3515 entry->rem_lifetime = lsp->hdr.rem_lifetime;
3516 memcpy(entry->id, lsp->hdr.lsp_id, ISIS_SYS_ID_LEN + 2);
3517 entry->checksum = lsp->hdr.checksum;
3518 entry->seqno = lsp->hdr.seqno;
3519 entry->lsp = lsp;
3520
3521 append_item(&tlvs->lsp_entries, (struct isis_item *)entry);
3522 }
3523
3524 void isis_tlvs_add_csnp_entries(struct isis_tlvs *tlvs, uint8_t *start_id,
3525 uint8_t *stop_id, uint16_t num_lsps,
3526 dict_t *lspdb, struct isis_lsp **last_lsp)
3527 {
3528 dnode_t *first = dict_lower_bound(lspdb, start_id);
3529 if (!first)
3530 return;
3531
3532 dnode_t *last = dict_upper_bound(lspdb, stop_id);
3533 dnode_t *curr = first;
3534
3535 isis_tlvs_add_lsp_entry(tlvs, first->dict_data);
3536 *last_lsp = first->dict_data;
3537
3538 while (curr) {
3539 curr = dict_next(lspdb, curr);
3540 if (curr) {
3541 isis_tlvs_add_lsp_entry(tlvs, curr->dict_data);
3542 *last_lsp = curr->dict_data;
3543 }
3544 if (curr == last || tlvs->lsp_entries.count == num_lsps)
3545 break;
3546 }
3547 }
3548
3549 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs,
3550 const char *hostname)
3551 {
3552 XFREE(MTYPE_ISIS_TLV, tlvs->hostname);
3553 if (hostname)
3554 tlvs->hostname = XSTRDUP(MTYPE_ISIS_TLV, hostname);
3555 }
3556
3557 void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs,
3558 const struct in_addr *id)
3559 {
3560 XFREE(MTYPE_ISIS_TLV, tlvs->te_router_id);
3561 if (!id)
3562 return;
3563 tlvs->te_router_id = XCALLOC(MTYPE_ISIS_TLV, sizeof(*id));
3564 memcpy(tlvs->te_router_id, id, sizeof(*id));
3565 }
3566
3567 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs,
3568 struct prefix_ipv4 *dest, uint8_t metric)
3569 {
3570 struct isis_oldstyle_ip_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
3571
3572 r->metric = metric;
3573 memcpy(&r->prefix, dest, sizeof(*dest));
3574 apply_mask_ipv4(&r->prefix);
3575 append_item(&tlvs->oldstyle_ip_reach, (struct isis_item *)r);
3576 }
3577
3578 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs,
3579 struct prefix_ipv4 *dest, uint32_t metric)
3580 {
3581 struct isis_extended_ip_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
3582
3583 r->metric = metric;
3584 memcpy(&r->prefix, dest, sizeof(*dest));
3585 apply_mask_ipv4(&r->prefix);
3586 append_item(&tlvs->extended_ip_reach, (struct isis_item *)r);
3587 }
3588
3589 void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid,
3590 struct prefix_ipv6 *dest, uint32_t metric)
3591 {
3592 struct isis_ipv6_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
3593
3594 r->metric = metric;
3595 memcpy(&r->prefix, dest, sizeof(*dest));
3596 apply_mask_ipv6(&r->prefix);
3597
3598 struct isis_item_list *l;
3599 l = (mtid == ISIS_MT_IPV4_UNICAST)
3600 ? &tlvs->ipv6_reach
3601 : isis_get_mt_items(&tlvs->mt_ipv6_reach, mtid);
3602 append_item(l, (struct isis_item *)r);
3603 }
3604
3605 void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid,
3606 struct prefix_ipv6 *dest,
3607 struct prefix_ipv6 *src,
3608 uint32_t metric)
3609 {
3610 isis_tlvs_add_ipv6_reach(tlvs, mtid, dest, metric);
3611 struct isis_item_list *l = isis_get_mt_items(&tlvs->mt_ipv6_reach,
3612 mtid);
3613
3614 struct isis_ipv6_reach *r = (struct isis_ipv6_reach*)last_item(l);
3615 r->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH);
3616 r->subtlvs->source_prefix = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*src));
3617 memcpy(r->subtlvs->source_prefix, src, sizeof(*src));
3618 }
3619
3620 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id,
3621 uint8_t metric)
3622 {
3623 struct isis_oldstyle_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
3624
3625 r->metric = metric;
3626 memcpy(r->id, id, sizeof(r->id));
3627 append_item(&tlvs->oldstyle_reach, (struct isis_item *)r);
3628 }
3629
3630 void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid,
3631 uint8_t *id, uint32_t metric,
3632 uint8_t *subtlvs, uint8_t subtlv_len)
3633 {
3634 struct isis_extended_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
3635
3636 memcpy(r->id, id, sizeof(r->id));
3637 r->metric = metric;
3638 if (subtlvs && subtlv_len) {
3639 r->subtlvs = XCALLOC(MTYPE_ISIS_TLV, subtlv_len);
3640 memcpy(r->subtlvs, subtlvs, subtlv_len);
3641 r->subtlv_len = subtlv_len;
3642 }
3643
3644 struct isis_item_list *l;
3645 if (mtid == ISIS_MT_IPV4_UNICAST)
3646 l = &tlvs->extended_reach;
3647 else
3648 l = isis_get_mt_items(&tlvs->mt_reach, mtid);
3649 append_item(l, (struct isis_item *)r);
3650 }
3651
3652 void isis_tlvs_add_threeway_adj(struct isis_tlvs *tlvs,
3653 enum isis_threeway_state state,
3654 uint32_t local_circuit_id,
3655 const uint8_t *neighbor_id,
3656 uint32_t neighbor_circuit_id)
3657 {
3658 assert(!tlvs->threeway_adj);
3659
3660 tlvs->threeway_adj = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->threeway_adj));
3661 tlvs->threeway_adj->state = state;
3662 tlvs->threeway_adj->local_circuit_id = local_circuit_id;
3663
3664 if (neighbor_id) {
3665 tlvs->threeway_adj->neighbor_set = true;
3666 memcpy(tlvs->threeway_adj->neighbor_id, neighbor_id, 6);
3667 tlvs->threeway_adj->neighbor_circuit_id = neighbor_circuit_id;
3668 }
3669 }
3670
3671 void isis_tlvs_add_spine_leaf(struct isis_tlvs *tlvs, uint8_t tier,
3672 bool has_tier, bool is_leaf, bool is_spine,
3673 bool is_backup)
3674 {
3675 assert(!tlvs->spine_leaf);
3676
3677 tlvs->spine_leaf = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->spine_leaf));
3678
3679 if (has_tier) {
3680 tlvs->spine_leaf->tier = tier;
3681 }
3682
3683 tlvs->spine_leaf->has_tier = has_tier;
3684 tlvs->spine_leaf->is_leaf = is_leaf;
3685 tlvs->spine_leaf->is_spine = is_spine;
3686 tlvs->spine_leaf->is_backup = is_backup;
3687 }
3688
3689 struct isis_mt_router_info *
3690 isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid)
3691 {
3692 if (tlvs->mt_router_info_empty)
3693 return NULL;
3694
3695 struct isis_mt_router_info *rv;
3696 for (rv = (struct isis_mt_router_info *)tlvs->mt_router_info.head; rv;
3697 rv = rv->next) {
3698 if (rv->mtid == mtid)
3699 return rv;
3700 }
3701
3702 return NULL;
3703 }
3704
3705 void isis_tlvs_set_purge_originator(struct isis_tlvs *tlvs,
3706 const uint8_t *generator,
3707 const uint8_t *sender)
3708 {
3709 assert(!tlvs->purge_originator);
3710
3711 tlvs->purge_originator = XCALLOC(MTYPE_ISIS_TLV,
3712 sizeof(*tlvs->purge_originator));
3713 memcpy(tlvs->purge_originator->generator, generator,
3714 sizeof(tlvs->purge_originator->generator));
3715 if (sender) {
3716 tlvs->purge_originator->sender_set = true;
3717 memcpy(tlvs->purge_originator->sender, sender,
3718 sizeof(tlvs->purge_originator->sender));
3719 }
3720 }