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