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