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