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