1 /*
2 * IS-IS TLV Serializer/Deserializer
3 *
4 * Copyright (C) 2015,2017 Christian Franke
5 *
6 * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR)
7 *
8 * This file is part of FRR.
9 *
10 * FRR is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2, or (at your option) any
13 * later version.
14 *
15 * FRR is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with FRR; see the file COPYING. If not, write to the Free
22 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23 * 02111-1307, USA.
24 */
25 #include <zebra.h>
26
27 #ifdef CRYPTO_INTERNAL
28 #include "md5.h"
29 #endif
30 #include "memory.h"
31 #include "stream.h"
32 #include "sbuf.h"
33 #include "network.h"
34
35 #include "isisd/isisd.h"
36 #include "isisd/isis_memory.h"
37 #include "isisd/isis_tlvs.h"
38 #include "isisd/isis_common.h"
39 #include "isisd/isis_mt.h"
40 #include "isisd/isis_misc.h"
41 #include "isisd/isis_adjacency.h"
42 #include "isisd/isis_circuit.h"
43 #include "isisd/isis_pdu.h"
44 #include "isisd/isis_lsp.h"
45 #include "isisd/isis_te.h"
46 #include "isisd/isis_sr.h"
47
48 DEFINE_MTYPE_STATIC(ISISD, ISIS_TLV, "ISIS TLVs")
49 DEFINE_MTYPE(ISISD, ISIS_SUBTLV, "ISIS Sub-TLVs")
50 DEFINE_MTYPE_STATIC(ISISD, ISIS_MT_ITEM_LIST, "ISIS MT Item Lists")
51
52 typedef int (*unpack_tlv_func)(enum isis_tlv_context context, uint8_t tlv_type,
53 uint8_t tlv_len, struct stream *s,
54 struct sbuf *log, void *dest, int indent);
55 typedef int (*pack_item_func)(struct isis_item *item, struct stream *s);
56 typedef void (*free_item_func)(struct isis_item *i);
57 typedef int (*unpack_item_func)(uint16_t mtid, uint8_t len, struct stream *s,
58 struct sbuf *log, void *dest, int indent);
59 typedef void (*format_item_func)(uint16_t mtid, struct isis_item *i,
60 struct sbuf *buf, int indent);
61 typedef struct isis_item *(*copy_item_func)(struct isis_item *i);
62
63 struct tlv_ops {
64 const char *name;
65 unpack_tlv_func unpack;
66
67 pack_item_func pack_item;
68 free_item_func free_item;
69 unpack_item_func unpack_item;
70 format_item_func format_item;
71 copy_item_func copy_item;
72 };
73
74 enum how_to_pack {
75 ISIS_ITEMS,
76 ISIS_MT_ITEMS,
77 };
78
79 struct pack_order_entry {
80 enum isis_tlv_context context;
81 enum isis_tlv_type type;
82 enum how_to_pack how_to_pack;
83 size_t what_to_pack;
84 };
85 #define PACK_ENTRY(t, h, w) \
86 { \
87 .context = ISIS_CONTEXT_LSP, .type = ISIS_TLV_##t, \
88 .how_to_pack = (h), \
89 .what_to_pack = offsetof(struct isis_tlvs, w), \
90 }
91
92 static const struct pack_order_entry pack_order[] = {
93 PACK_ENTRY(OLDSTYLE_REACH, ISIS_ITEMS, oldstyle_reach),
94 PACK_ENTRY(LAN_NEIGHBORS, ISIS_ITEMS, lan_neighbor),
95 PACK_ENTRY(LSP_ENTRY, ISIS_ITEMS, lsp_entries),
96 PACK_ENTRY(EXTENDED_REACH, ISIS_ITEMS, extended_reach),
97 PACK_ENTRY(MT_REACH, ISIS_MT_ITEMS, mt_reach),
98 PACK_ENTRY(OLDSTYLE_IP_REACH, ISIS_ITEMS, oldstyle_ip_reach),
99 PACK_ENTRY(OLDSTYLE_IP_REACH_EXT, ISIS_ITEMS, oldstyle_ip_reach_ext),
100 PACK_ENTRY(IPV4_ADDRESS, ISIS_ITEMS, ipv4_address),
101 PACK_ENTRY(IPV6_ADDRESS, ISIS_ITEMS, ipv6_address),
102 PACK_ENTRY(EXTENDED_IP_REACH, ISIS_ITEMS, extended_ip_reach),
103 PACK_ENTRY(MT_IP_REACH, ISIS_MT_ITEMS, mt_ip_reach),
104 PACK_ENTRY(IPV6_REACH, ISIS_ITEMS, ipv6_reach),
105 PACK_ENTRY(MT_IPV6_REACH, ISIS_MT_ITEMS, mt_ipv6_reach)
106 };
107
108 /* This is a forward definition. The table is actually initialized
109 * in at the bottom. */
110 static const struct tlv_ops *const tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX];
111
112 /* End of _ops forward definition. */
113
114 /* Prototypes */
115 static void append_item(struct isis_item_list *dest, struct isis_item *item);
116 static void init_item_list(struct isis_item_list *items);
117
118 /* Functions for Extended IS Reachability SubTLVs a.k.a Traffic Engineering */
isis_alloc_ext_subtlvs(void)119 struct isis_ext_subtlvs *isis_alloc_ext_subtlvs(void)
120 {
121 struct isis_ext_subtlvs *ext;
122
123 ext = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_ext_subtlvs));
124 init_item_list(&ext->adj_sid);
125 init_item_list(&ext->lan_sid);
126
127 return ext;
128 }
129
130 /*
131 * mtid parameter is used to determine if Adjacency is related to IPv4 or IPv6.
132 * A negative value could be used to skip copy of Adjacency SID.
133 */
134 static struct isis_ext_subtlvs *
copy_item_ext_subtlvs(struct isis_ext_subtlvs * exts,int16_t mtid)135 copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, int16_t mtid)
136 {
137 struct isis_ext_subtlvs *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
138 struct isis_adj_sid *adj;
139 struct isis_lan_adj_sid *lan;
140
141 memcpy(rv, exts, sizeof(struct isis_ext_subtlvs));
142 init_item_list(&rv->adj_sid);
143 init_item_list(&rv->lan_sid);
144
145 UNSET_SUBTLV(rv, EXT_ADJ_SID);
146 UNSET_SUBTLV(rv, EXT_LAN_ADJ_SID);
147
148 /* Copy Adj SID and LAN Adj SID list for IPv4 if needed */
149 for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj != NULL;
150 adj = adj->next) {
151 if ((mtid != -1)
152 && (((mtid == ISIS_MT_IPV4_UNICAST)
153 && (adj->family != AF_INET))
154 || ((mtid == ISIS_MT_IPV6_UNICAST)
155 && (adj->family != AF_INET6))))
156 continue;
157
158 struct isis_adj_sid *new;
159
160 new = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_adj_sid));
161 new->family = adj->family;
162 new->flags = adj->flags;
163 new->weight = adj->weight;
164 new->sid = adj->sid;
165 append_item(&rv->adj_sid, (struct isis_item *)new);
166 SET_SUBTLV(rv, EXT_ADJ_SID);
167 }
168
169 for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; lan != NULL;
170 lan = lan->next) {
171 if ((mtid != -1)
172 && (((mtid == ISIS_MT_IPV4_UNICAST)
173 && (lan->family != AF_INET))
174 || ((mtid == ISIS_MT_IPV6_UNICAST)
175 && (lan->family != AF_INET6))))
176 continue;
177
178 struct isis_lan_adj_sid *new;
179
180 new = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_lan_adj_sid));
181 new->family = lan->family;
182 new->flags = lan->flags;
183 new->weight = lan->weight;
184 memcpy(new->neighbor_id, lan->neighbor_id, 6);
185 new->sid = lan->sid;
186 append_item(&rv->lan_sid, (struct isis_item *)new);
187 SET_SUBTLV(rv, EXT_LAN_ADJ_SID);
188 }
189
190 return rv;
191 }
192
193 /* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */
format_item_ext_subtlvs(struct isis_ext_subtlvs * exts,struct sbuf * buf,int indent,uint16_t mtid)194 static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
195 struct sbuf *buf, int indent,
196 uint16_t mtid)
197 {
198
199 char ibuf[PREFIX2STR_BUFFER];
200
201 /* Standard metrics */
202 if (IS_SUBTLV(exts, EXT_ADM_GRP))
203 sbuf_push(buf, indent, "Administrative Group: 0x%x\n",
204 exts->adm_group);
205 if (IS_SUBTLV(exts, EXT_LLRI)) {
206 sbuf_push(buf, indent, "Link Local ID: %u\n",
207 exts->local_llri);
208 sbuf_push(buf, indent, "Link Remote ID: %u\n",
209 exts->remote_llri);
210 }
211 if (IS_SUBTLV(exts, EXT_LOCAL_ADDR))
212 sbuf_push(buf, indent, "Local Interface IP Address(es): %s\n",
213 inet_ntoa(exts->local_addr));
214 if (IS_SUBTLV(exts, EXT_NEIGH_ADDR))
215 sbuf_push(buf, indent, "Remote Interface IP Address(es): %s\n",
216 inet_ntoa(exts->neigh_addr));
217 if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6))
218 sbuf_push(buf, indent, "Local Interface IPv6 Address(es): %s\n",
219 inet_ntop(AF_INET6, &exts->local_addr6, ibuf,
220 PREFIX2STR_BUFFER));
221 if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6))
222 sbuf_push(buf, indent, "Remote Interface IPv6 Address(es): %s\n",
223 inet_ntop(AF_INET6, &exts->local_addr6, ibuf,
224 PREFIX2STR_BUFFER));
225 if (IS_SUBTLV(exts, EXT_MAX_BW))
226 sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n",
227 exts->max_bw);
228 if (IS_SUBTLV(exts, EXT_MAX_RSV_BW))
229 sbuf_push(buf, indent,
230 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
231 exts->max_rsv_bw);
232 if (IS_SUBTLV(exts, EXT_UNRSV_BW)) {
233 sbuf_push(buf, indent, "Unreserved Bandwidth:\n");
234 for (int j = 0; j < MAX_CLASS_TYPE; j += 2) {
235 sbuf_push(buf, indent + 2,
236 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
237 j, exts->unrsv_bw[j],
238 j + 1, exts->unrsv_bw[j + 1]);
239 }
240 }
241 if (IS_SUBTLV(exts, EXT_TE_METRIC))
242 sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n",
243 exts->te_metric);
244 if (IS_SUBTLV(exts, EXT_RMT_AS))
245 sbuf_push(buf, indent,
246 "Inter-AS TE Remote AS number: %u\n",
247 exts->remote_as);
248 if (IS_SUBTLV(exts, EXT_RMT_IP))
249 sbuf_push(buf, indent,
250 "Inter-AS TE Remote ASBR IP address: %s\n",
251 inet_ntoa(exts->remote_ip));
252 /* Extended metrics */
253 if (IS_SUBTLV(exts, EXT_DELAY))
254 sbuf_push(buf, indent,
255 "%s Average Link Delay: %u (micro-sec)\n",
256 IS_ANORMAL(exts->delay) ? "Anomalous" : "Normal",
257 exts->delay);
258 if (IS_SUBTLV(exts, EXT_MM_DELAY)) {
259 sbuf_push(buf, indent, "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
260 IS_ANORMAL(exts->min_delay) ? "Anomalous" : "Normal",
261 exts->min_delay & TE_EXT_MASK,
262 exts->max_delay & TE_EXT_MASK);
263 }
264 if (IS_SUBTLV(exts, EXT_DELAY_VAR)) {
265 sbuf_push(buf, indent,
266 "Delay Variation: %u (micro-sec)\n",
267 exts->delay_var & TE_EXT_MASK);
268 }
269 if (IS_SUBTLV(exts, EXT_PKT_LOSS))
270 sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n",
271 IS_ANORMAL(exts->pkt_loss) ? "Anomalous" : "Normal",
272 (float)((exts->pkt_loss & TE_EXT_MASK)
273 * LOSS_PRECISION));
274 if (IS_SUBTLV(exts, EXT_RES_BW))
275 sbuf_push(buf, indent,
276 "Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
277 exts->res_bw);
278 if (IS_SUBTLV(exts, EXT_AVA_BW))
279 sbuf_push(buf, indent,
280 "Unidir. Available Bandwidth: %g (Bytes/sec)\n",
281 exts->ava_bw);
282 if (IS_SUBTLV(exts, EXT_USE_BW))
283 sbuf_push(buf, indent,
284 "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
285 exts->use_bw);
286 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
287 if (IS_SUBTLV(exts, EXT_ADJ_SID)) {
288 struct isis_adj_sid *adj;
289
290 for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj;
291 adj = adj->next) {
292 if (((mtid == ISIS_MT_IPV4_UNICAST)
293 && (adj->family != AF_INET))
294 || ((mtid == ISIS_MT_IPV6_UNICAST)
295 && (adj->family != AF_INET6)))
296 continue;
297 sbuf_push(
298 buf, indent,
299 "Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n",
300 adj->sid, adj->weight,
301 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? '1'
302 : '0',
303 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? '1'
304 : '0',
305 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG ? '1'
306 : '0',
307 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG ? '1'
308 : '0',
309 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG ? '1'
310 : '0',
311 adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
312 ? '1'
313 : '0');
314 }
315 }
316 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
317 if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) {
318 struct isis_lan_adj_sid *lan;
319
320 for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head;
321 lan; lan = lan->next) {
322 if (((mtid == ISIS_MT_IPV4_UNICAST)
323 && (lan->family != AF_INET))
324 || ((mtid == ISIS_MT_IPV6_UNICAST)
325 && (lan->family != AF_INET6)))
326 continue;
327 sbuf_push(buf, indent,
328 "Lan-Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n"
329 " Neighbor-ID: %s\n",
330 lan->sid, lan->weight,
331 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
332 ? '1'
333 : '0',
334 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
335 ? '1'
336 : '0',
337 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
338 ? '1'
339 : '0',
340 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
341 ? '1'
342 : '0',
343 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
344 ? '1'
345 : '0',
346 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
347 ? '1'
348 : '0',
349 isis_format_id(lan->neighbor_id, 6));
350 }
351 }
352 }
353
free_item_ext_subtlvs(struct isis_ext_subtlvs * exts)354 static void free_item_ext_subtlvs(struct isis_ext_subtlvs *exts)
355 {
356 struct isis_item *item, *next_item;
357
358 /* First, free Adj SID and LAN Adj SID list if needed */
359 for (item = exts->adj_sid.head; item; item = next_item) {
360 next_item = item->next;
361 XFREE(MTYPE_ISIS_SUBTLV, item);
362 }
363 for (item = exts->lan_sid.head; item; item = next_item) {
364 next_item = item->next;
365 XFREE(MTYPE_ISIS_SUBTLV, item);
366 }
367 XFREE(MTYPE_ISIS_SUBTLV, exts);
368 }
369
pack_item_ext_subtlvs(struct isis_ext_subtlvs * exts,struct stream * s)370 static int pack_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
371 struct stream *s)
372 {
373 uint8_t size;
374
375 if (STREAM_WRITEABLE(s) < ISIS_SUBTLV_MAX_SIZE)
376 return 1;
377
378 if (IS_SUBTLV(exts, EXT_ADM_GRP)) {
379 stream_putc(s, ISIS_SUBTLV_ADMIN_GRP);
380 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
381 stream_putl(s, exts->adm_group);
382 }
383 if (IS_SUBTLV(exts, EXT_LLRI)) {
384 stream_putc(s, ISIS_SUBTLV_LLRI);
385 stream_putc(s, ISIS_SUBTLV_LLRI_SIZE);
386 stream_putl(s, exts->local_llri);
387 stream_putl(s, exts->remote_llri);
388 }
389 if (IS_SUBTLV(exts, EXT_LOCAL_ADDR)) {
390 stream_putc(s, ISIS_SUBTLV_LOCAL_IPADDR);
391 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
392 stream_put(s, &exts->local_addr.s_addr, 4);
393 }
394 if (IS_SUBTLV(exts, EXT_NEIGH_ADDR)) {
395 stream_putc(s, ISIS_SUBTLV_RMT_IPADDR);
396 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
397 stream_put(s, &exts->neigh_addr.s_addr, 4);
398 }
399 if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6)) {
400 stream_putc(s, ISIS_SUBTLV_LOCAL_IPADDR6);
401 stream_putc(s, ISIS_SUBTLV_IPV6_ADDR_SIZE);
402 stream_put(s, &exts->local_addr6, 16);
403 }
404 if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6)) {
405 stream_putc(s, ISIS_SUBTLV_RMT_IPADDR6);
406 stream_putc(s, ISIS_SUBTLV_IPV6_ADDR_SIZE);
407 stream_put(s, &exts->neigh_addr6, 16);
408 }
409 if (IS_SUBTLV(exts, EXT_MAX_BW)) {
410 stream_putc(s, ISIS_SUBTLV_MAX_BW);
411 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
412 stream_putf(s, exts->max_bw);
413 }
414 if (IS_SUBTLV(exts, EXT_MAX_RSV_BW)) {
415 stream_putc(s, ISIS_SUBTLV_MAX_RSV_BW);
416 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
417 stream_putf(s, exts->max_rsv_bw);
418 }
419 if (IS_SUBTLV(exts, EXT_UNRSV_BW)) {
420 stream_putc(s, ISIS_SUBTLV_UNRSV_BW);
421 stream_putc(s, ISIS_SUBTLV_UNRSV_BW_SIZE);
422 for (int j = 0; j < MAX_CLASS_TYPE; j++)
423 stream_putf(s, exts->unrsv_bw[j]);
424 }
425 if (IS_SUBTLV(exts, EXT_TE_METRIC)) {
426 stream_putc(s, ISIS_SUBTLV_TE_METRIC);
427 stream_putc(s, ISIS_SUBTLV_TE_METRIC_SIZE);
428 stream_put3(s, exts->te_metric);
429 }
430 if (IS_SUBTLV(exts, EXT_RMT_AS)) {
431 stream_putc(s, ISIS_SUBTLV_RAS);
432 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
433 stream_putl(s, exts->remote_as);
434 }
435 if (IS_SUBTLV(exts, EXT_RMT_IP)) {
436 stream_putc(s, ISIS_SUBTLV_RIP);
437 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
438 stream_put(s, &exts->remote_ip.s_addr, 4);
439 }
440 if (IS_SUBTLV(exts, EXT_DELAY)) {
441 stream_putc(s, ISIS_SUBTLV_AV_DELAY);
442 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
443 stream_putl(s, exts->delay);
444 }
445 if (IS_SUBTLV(exts, EXT_MM_DELAY)) {
446 stream_putc(s, ISIS_SUBTLV_MM_DELAY);
447 stream_putc(s, ISIS_SUBTLV_MM_DELAY_SIZE);
448 stream_putl(s, exts->min_delay);
449 stream_putl(s, exts->max_delay);
450 }
451 if (IS_SUBTLV(exts, EXT_DELAY_VAR)) {
452 stream_putc(s, ISIS_SUBTLV_DELAY_VAR);
453 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
454 stream_putl(s, exts->delay_var);
455 }
456 if (IS_SUBTLV(exts, EXT_PKT_LOSS)) {
457 stream_putc(s, ISIS_SUBTLV_PKT_LOSS);
458 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
459 stream_putl(s, exts->pkt_loss);
460 }
461 if (IS_SUBTLV(exts, EXT_RES_BW)) {
462 stream_putc(s, ISIS_SUBTLV_RES_BW);
463 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
464 stream_putf(s, exts->res_bw);
465 }
466 if (IS_SUBTLV(exts, EXT_AVA_BW)) {
467 stream_putc(s, ISIS_SUBTLV_AVA_BW);
468 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
469 stream_putf(s, exts->ava_bw);
470 }
471 if (IS_SUBTLV(exts, EXT_USE_BW)) {
472 stream_putc(s, ISIS_SUBTLV_USE_BW);
473 stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
474 stream_putf(s, exts->use_bw);
475 }
476 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
477 if (IS_SUBTLV(exts, EXT_ADJ_SID)) {
478 struct isis_adj_sid *adj;
479
480 for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj;
481 adj = adj->next) {
482 stream_putc(s, ISIS_SUBTLV_ADJ_SID);
483 size = ISIS_SUBTLV_ADJ_SID_SIZE;
484 if (!(adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG))
485 size++;
486 stream_putc(s, size);
487 stream_putc(s, adj->flags);
488 stream_putc(s, adj->weight);
489 if (adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG)
490 stream_put3(s, adj->sid);
491 else
492 stream_putl(s, adj->sid);
493
494 }
495 }
496 /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
497 if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) {
498 struct isis_lan_adj_sid *lan;
499
500 for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; lan;
501 lan = lan->next) {
502 stream_putc(s, ISIS_SUBTLV_LAN_ADJ_SID);
503 size = ISIS_SUBTLV_LAN_ADJ_SID_SIZE;
504 if (!(lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG))
505 size++;
506 stream_putc(s, size);
507 stream_putc(s, lan->flags);
508 stream_putc(s, lan->weight);
509 stream_put(s, lan->neighbor_id, 6);
510 if (lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG)
511 stream_put3(s, lan->sid);
512 else
513 stream_putl(s, lan->sid);
514 }
515 }
516
517 return 0;
518 }
519
unpack_item_ext_subtlvs(uint16_t mtid,uint8_t len,struct stream * s,struct sbuf * log,void * dest,int indent)520 static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s,
521 struct sbuf *log, void *dest, int indent)
522 {
523 uint8_t sum = 0;
524 uint8_t subtlv_type;
525 uint8_t subtlv_len;
526
527 struct isis_extended_reach *rv = dest;
528 struct isis_ext_subtlvs *exts = isis_alloc_ext_subtlvs();
529
530 rv->subtlvs = exts;
531
532 /*
533 * Parse subTLVs until reach subTLV length
534 * Check that it remains at least 2 bytes: subTLV Type & Length
535 */
536 while (len > sum + 2) {
537 /* Read SubTLV Type and Length */
538 subtlv_type = stream_getc(s);
539 subtlv_len = stream_getc(s);
540 if (subtlv_len > len - sum) {
541 sbuf_push(log, indent, "TLV %hhu: Available data %u is less than TLV size %u !\n",
542 subtlv_type, len - sum, subtlv_len);
543 return 1;
544 }
545
546 switch (subtlv_type) {
547 /* Standard Metric as defined in RFC5305 */
548 case ISIS_SUBTLV_ADMIN_GRP:
549 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
550 sbuf_push(log, indent,
551 "TLV size does not match expected size for Administrative Group!\n");
552 } else {
553 exts->adm_group = stream_getl(s);
554 SET_SUBTLV(exts, EXT_ADM_GRP);
555 }
556 break;
557 case ISIS_SUBTLV_LLRI:
558 if (subtlv_len != ISIS_SUBTLV_LLRI_SIZE) {
559 sbuf_push(log, indent,
560 "TLV size does not match expected size for Link ID!\n");
561 } else {
562 exts->local_llri = stream_getl(s);
563 exts->remote_llri = stream_getl(s);
564 SET_SUBTLV(exts, EXT_LLRI);
565 }
566 break;
567 case ISIS_SUBTLV_LOCAL_IPADDR:
568 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
569 sbuf_push(log, indent,
570 "TLV size does not match expected size for Local IP address!\n");
571 } else {
572 stream_get(&exts->local_addr.s_addr, s, 4);
573 SET_SUBTLV(exts, EXT_LOCAL_ADDR);
574 }
575 break;
576 case ISIS_SUBTLV_RMT_IPADDR:
577 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
578 sbuf_push(log, indent,
579 "TLV size does not match expected size for Remote IP address!\n");
580 } else {
581 stream_get(&exts->neigh_addr.s_addr, s, 4);
582 SET_SUBTLV(exts, EXT_NEIGH_ADDR);
583 }
584 break;
585 case ISIS_SUBTLV_LOCAL_IPADDR6:
586 if (subtlv_len != ISIS_SUBTLV_IPV6_ADDR_SIZE) {
587 sbuf_push(log, indent,
588 "TLV size does not match expected size for Local IPv6 address!\n");
589 } else {
590 stream_get(&exts->local_addr6, s, 16);
591 SET_SUBTLV(exts, EXT_LOCAL_ADDR6);
592 }
593 break;
594 case ISIS_SUBTLV_RMT_IPADDR6:
595 if (subtlv_len != ISIS_SUBTLV_IPV6_ADDR_SIZE) {
596 sbuf_push(log, indent,
597 "TLV size does not match expected size for Remote IPv6 address!\n");
598 } else {
599 stream_get(&exts->neigh_addr6, s, 16);
600 SET_SUBTLV(exts, EXT_NEIGH_ADDR6);
601 }
602 break;
603 case ISIS_SUBTLV_MAX_BW:
604 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
605 sbuf_push(log, indent,
606 "TLV size does not match expected size for Maximum Bandwidth!\n");
607 } else {
608 exts->max_bw = stream_getf(s);
609 SET_SUBTLV(exts, EXT_MAX_BW);
610 }
611 break;
612 case ISIS_SUBTLV_MAX_RSV_BW:
613 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
614 sbuf_push(log, indent,
615 "TLV size does not match expected size for Maximum Reservable Bandwidth!\n");
616 } else {
617 exts->max_rsv_bw = stream_getf(s);
618 SET_SUBTLV(exts, EXT_MAX_RSV_BW);
619 }
620 break;
621 case ISIS_SUBTLV_UNRSV_BW:
622 if (subtlv_len != ISIS_SUBTLV_UNRSV_BW_SIZE) {
623 sbuf_push(log, indent,
624 "TLV size does not match expected size for Unreserved Bandwidth!\n");
625 } else {
626 for (int i = 0; i < MAX_CLASS_TYPE; i++)
627 exts->unrsv_bw[i] = stream_getf(s);
628 SET_SUBTLV(exts, EXT_UNRSV_BW);
629 }
630 break;
631 case ISIS_SUBTLV_TE_METRIC:
632 if (subtlv_len != ISIS_SUBTLV_TE_METRIC_SIZE) {
633 sbuf_push(log, indent,
634 "TLV size does not match expected size for Traffic Engineering Metric!\n");
635 } else {
636 exts->te_metric = stream_get3(s);
637 SET_SUBTLV(exts, EXT_TE_METRIC);
638 }
639 break;
640 case ISIS_SUBTLV_RAS:
641 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
642 sbuf_push(log, indent,
643 "TLV size does not match expected size for Remote AS number!\n");
644 } else {
645 exts->remote_as = stream_getl(s);
646 SET_SUBTLV(exts, EXT_RMT_AS);
647 }
648 break;
649 case ISIS_SUBTLV_RIP:
650 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
651 sbuf_push(log, indent,
652 "TLV size does not match expected size for Remote ASBR IP Address!\n");
653 } else {
654 stream_get(&exts->remote_ip.s_addr, s, 4);
655 SET_SUBTLV(exts, EXT_RMT_IP);
656 }
657 break;
658 /* Extended Metrics as defined in RFC 7810 */
659 case ISIS_SUBTLV_AV_DELAY:
660 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
661 sbuf_push(log, indent,
662 "TLV size does not match expected size for Average Link Delay!\n");
663 } else {
664 exts->delay = stream_getl(s);
665 SET_SUBTLV(exts, EXT_DELAY);
666 }
667 break;
668 case ISIS_SUBTLV_MM_DELAY:
669 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
670 sbuf_push(log, indent,
671 "TLV size does not match expected size for Min/Max Link Delay!\n");
672 } else {
673 exts->min_delay = stream_getl(s);
674 exts->max_delay = stream_getl(s);
675 SET_SUBTLV(exts, EXT_MM_DELAY);
676 }
677 break;
678 case ISIS_SUBTLV_DELAY_VAR:
679 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
680 sbuf_push(log, indent,
681 "TLV size does not match expected size for Delay Variation!\n");
682 } else {
683 exts->delay_var = stream_getl(s);
684 SET_SUBTLV(exts, EXT_DELAY_VAR);
685 }
686 break;
687 case ISIS_SUBTLV_PKT_LOSS:
688 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
689 sbuf_push(log, indent,
690 "TLV size does not match expected size for Link Packet Loss!\n");
691 } else {
692 exts->pkt_loss = stream_getl(s);
693 SET_SUBTLV(exts, EXT_PKT_LOSS);
694 }
695 break;
696 case ISIS_SUBTLV_RES_BW:
697 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
698 sbuf_push(log, indent,
699 "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n");
700 } else {
701 exts->res_bw = stream_getf(s);
702 SET_SUBTLV(exts, EXT_RES_BW);
703 }
704 break;
705 case ISIS_SUBTLV_AVA_BW:
706 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
707 sbuf_push(log, indent,
708 "TLV size does not match expected size for Unidirectional Available Bandwidth!\n");
709 } else {
710 exts->ava_bw = stream_getf(s);
711 SET_SUBTLV(exts, EXT_AVA_BW);
712 }
713 break;
714 case ISIS_SUBTLV_USE_BW:
715 if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
716 sbuf_push(log, indent,
717 "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n");
718 } else {
719 exts->use_bw = stream_getf(s);
720 SET_SUBTLV(exts, EXT_USE_BW);
721 }
722 break;
723 /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
724 case ISIS_SUBTLV_ADJ_SID:
725 if (subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE
726 && subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE + 1) {
727 sbuf_push(log, indent,
728 "TLV size does not match expected size for Adjacency SID!\n");
729 } else {
730 struct isis_adj_sid *adj;
731
732 adj = XCALLOC(MTYPE_ISIS_SUBTLV,
733 sizeof(struct isis_adj_sid));
734 adj->flags = stream_getc(s);
735 adj->weight = stream_getc(s);
736 if (adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) {
737 adj->sid = stream_get3(s);
738 adj->sid &= MPLS_LABEL_VALUE_MASK;
739 } else {
740 adj->sid = stream_getl(s);
741 }
742 if (mtid == ISIS_MT_IPV4_UNICAST)
743 adj->family = AF_INET;
744 if (mtid == ISIS_MT_IPV6_UNICAST)
745 adj->family = AF_INET6;
746 append_item(&exts->adj_sid,
747 (struct isis_item *)adj);
748 SET_SUBTLV(exts, EXT_ADJ_SID);
749 }
750 break;
751 /* Segment Routing LAN-Adjacency as per RFC8667 section 2.2.2 */
752 case ISIS_SUBTLV_LAN_ADJ_SID:
753 if (subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
754 && subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE + 1) {
755 sbuf_push(log, indent,
756 "TLV size does not match expected size for LAN-Adjacency SID!\n");
757 } else {
758 struct isis_lan_adj_sid *lan;
759
760 lan = XCALLOC(MTYPE_ISIS_SUBTLV,
761 sizeof(struct isis_lan_adj_sid));
762 lan->flags = stream_getc(s);
763 lan->weight = stream_getc(s);
764 stream_get(&(lan->neighbor_id), s,
765 ISIS_SYS_ID_LEN);
766 if (lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) {
767 lan->sid = stream_get3(s);
768 lan->sid &= MPLS_LABEL_VALUE_MASK;
769 } else {
770 lan->sid = stream_getl(s);
771 }
772 if (mtid == ISIS_MT_IPV4_UNICAST)
773 lan->family = AF_INET;
774 if (mtid == ISIS_MT_IPV6_UNICAST)
775 lan->family = AF_INET6;
776 append_item(&exts->lan_sid,
777 (struct isis_item *)lan);
778 SET_SUBTLV(exts, EXT_LAN_ADJ_SID);
779 }
780 break;
781 default:
782 /* Skip unknown TLV */
783 stream_forward_getp(s, subtlv_len);
784 break;
785 }
786 sum += subtlv_len + ISIS_SUBTLV_HDR_SIZE;
787 }
788
789 return 0;
790 }
791
792 /* Functions for Sub-TLV 3 SR Prefix-SID as per RFC8667 section 2.1 */
copy_item_prefix_sid(struct isis_item * i)793 static struct isis_item *copy_item_prefix_sid(struct isis_item *i)
794 {
795 struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
796 struct isis_prefix_sid *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
797
798 rv->flags = sid->flags;
799 rv->algorithm = sid->algorithm;
800 rv->value = sid->value;
801 return (struct isis_item *)rv;
802 }
803
format_item_prefix_sid(uint16_t mtid,struct isis_item * i,struct sbuf * buf,int indent)804 static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i,
805 struct sbuf *buf, int indent)
806 {
807 struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
808
809 sbuf_push(buf, indent, "SR Prefix-SID ");
810 if (sid->flags & ISIS_PREFIX_SID_VALUE) {
811 sbuf_push(buf, 0, "Label: %u, ", sid->value);
812 } else {
813 sbuf_push(buf, 0, "Index: %u, ", sid->value);
814 }
815 sbuf_push(buf, 0, "Algorithm: %hhu, ", sid->algorithm);
816 sbuf_push(buf, 0, "Flags:%s%s%s%s%s%s\n",
817 sid->flags & ISIS_PREFIX_SID_READVERTISED ? " READVERTISED"
818 : "",
819 sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "",
820 sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO-PHP" : " PHP",
821 sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL ? " EXPLICIT-NULL"
822 : "",
823 sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "",
824 sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : "");
825 }
826
free_item_prefix_sid(struct isis_item * i)827 static void free_item_prefix_sid(struct isis_item *i)
828 {
829 XFREE(MTYPE_ISIS_SUBTLV, i);
830 }
831
pack_item_prefix_sid(struct isis_item * i,struct stream * s)832 static int pack_item_prefix_sid(struct isis_item *i, struct stream *s)
833 {
834 struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
835
836 uint8_t size = (sid->flags & ISIS_PREFIX_SID_VALUE) ? 5 : 6;
837
838 if (STREAM_WRITEABLE(s) < size)
839 return 1;
840
841 stream_putc(s, sid->flags);
842 stream_putc(s, sid->algorithm);
843
844 if (sid->flags & ISIS_PREFIX_SID_VALUE) {
845 stream_put3(s, sid->value);
846 } else {
847 stream_putl(s, sid->value);
848 }
849
850 return 0;
851 }
852
unpack_item_prefix_sid(uint16_t mtid,uint8_t len,struct stream * s,struct sbuf * log,void * dest,int indent)853 static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s,
854 struct sbuf *log, void *dest, int indent)
855 {
856 struct isis_subtlvs *subtlvs = dest;
857 struct isis_prefix_sid sid = {
858 };
859
860 sbuf_push(log, indent, "Unpacking SR Prefix-SID...\n");
861
862 if (len < 5) {
863 sbuf_push(log, indent,
864 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
865 len);
866 return 1;
867 }
868
869 sid.flags = stream_getc(s);
870 if (!!(sid.flags & ISIS_PREFIX_SID_VALUE)
871 != !!(sid.flags & ISIS_PREFIX_SID_LOCAL)) {
872 sbuf_push(log, indent, "Flags implausible: Local Flag needs to match Value Flag\n");
873 return 1;
874 }
875
876 sid.algorithm = stream_getc(s);
877
878 uint8_t expected_size = (sid.flags & ISIS_PREFIX_SID_VALUE)
879 ? ISIS_SUBTLV_PREFIX_SID_SIZE
880 : ISIS_SUBTLV_PREFIX_SID_SIZE + 1;
881 if (len != expected_size) {
882 sbuf_push(log, indent,
883 "TLV size differs from expected size. (expected %u but got %hhu)\n",
884 expected_size, len);
885 return 1;
886 }
887
888 if (sid.flags & ISIS_PREFIX_SID_VALUE) {
889 sid.value = stream_get3(s);
890 if (!IS_MPLS_UNRESERVED_LABEL(sid.value)) {
891 sbuf_push(log, indent, "Invalid absolute SID %u\n",
892 sid.value);
893 return 1;
894 }
895 } else {
896 sid.value = stream_getl(s);
897 }
898
899 format_item_prefix_sid(mtid, (struct isis_item *)&sid, log, indent + 2);
900 append_item(&subtlvs->prefix_sids, copy_item_prefix_sid((struct isis_item *)&sid));
901 return 0;
902 }
903
904 /* Functions for Sub-TVL ??? IPv6 Source Prefix */
905
copy_subtlv_ipv6_source_prefix(struct prefix_ipv6 * p)906 static struct prefix_ipv6 *copy_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p)
907 {
908 if (!p)
909 return NULL;
910
911 struct prefix_ipv6 *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
912 rv->family = p->family;
913 rv->prefixlen = p->prefixlen;
914 memcpy(&rv->prefix, &p->prefix, sizeof(rv->prefix));
915 return rv;
916 }
917
format_subtlv_ipv6_source_prefix(struct prefix_ipv6 * p,struct sbuf * buf,int indent)918 static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p,
919 struct sbuf *buf, int indent)
920 {
921 if (!p)
922 return;
923
924 char prefixbuf[PREFIX2STR_BUFFER];
925 sbuf_push(buf, indent, "IPv6 Source Prefix: %s\n",
926 prefix2str(p, prefixbuf, sizeof(prefixbuf)));
927 }
928
pack_subtlv_ipv6_source_prefix(struct prefix_ipv6 * p,struct stream * s)929 static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p,
930 struct stream *s)
931 {
932 if (!p)
933 return 0;
934
935 if (STREAM_WRITEABLE(s) < 3 + (unsigned)PSIZE(p->prefixlen))
936 return 1;
937
938 stream_putc(s, ISIS_SUBTLV_IPV6_SOURCE_PREFIX);
939 stream_putc(s, 1 + PSIZE(p->prefixlen));
940 stream_putc(s, p->prefixlen);
941 stream_put(s, &p->prefix, PSIZE(p->prefixlen));
942 return 0;
943 }
944
unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context,uint8_t tlv_type,uint8_t tlv_len,struct stream * s,struct sbuf * log,void * dest,int indent)945 static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context,
946 uint8_t tlv_type, uint8_t tlv_len,
947 struct stream *s, struct sbuf *log,
948 void *dest, int indent)
949 {
950 struct isis_subtlvs *subtlvs = dest;
951 struct prefix_ipv6 p = {
952 .family = AF_INET6,
953 };
954
955 sbuf_push(log, indent, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
956
957 if (tlv_len < 1) {
958 sbuf_push(log, indent,
959 "Not enough data left. (expected 1 or more bytes, got %hhu)\n",
960 tlv_len);
961 return 1;
962 }
963
964 p.prefixlen = stream_getc(s);
965 if (p.prefixlen > 128) {
966 sbuf_push(log, indent, "Prefixlen %u is implausible for IPv6\n",
967 p.prefixlen);
968 return 1;
969 }
970
971 if (tlv_len != 1 + PSIZE(p.prefixlen)) {
972 sbuf_push(
973 log, indent,
974 "TLV size differs from expected size for the prefixlen. (expected %u but got %hhu)\n",
975 1 + PSIZE(p.prefixlen), tlv_len);
976 return 1;
977 }
978
979 stream_get(&p.prefix, s, PSIZE(p.prefixlen));
980
981 if (subtlvs->source_prefix) {
982 sbuf_push(
983 log, indent,
984 "WARNING: source prefix Sub-TLV present multiple times.\n");
985 /* Ignore all but first occurrence of the source prefix Sub-TLV
986 */
987 return 0;
988 }
989
990 subtlvs->source_prefix = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(p));
991 memcpy(subtlvs->source_prefix, &p, sizeof(p));
992 return 0;
993 }
994
995 static struct isis_item *copy_item(enum isis_tlv_context context,
996 enum isis_tlv_type type,
997 struct isis_item *item);
998 static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type,
999 struct isis_item_list *src, struct isis_item_list *dest);
1000 static void format_items_(uint16_t mtid, enum isis_tlv_context context,
1001 enum isis_tlv_type type, struct isis_item_list *items,
1002 struct sbuf *buf, int indent);
1003 #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1004 static void free_items(enum isis_tlv_context context, enum isis_tlv_type type,
1005 struct isis_item_list *items);
1006 static int pack_items_(uint16_t mtid, enum isis_tlv_context context,
1007 enum isis_tlv_type type, struct isis_item_list *items,
1008 struct stream *s, struct isis_tlvs **fragment_tlvs,
1009 const struct pack_order_entry *pe,
1010 struct isis_tlvs *(*new_fragment)(struct list *l),
1011 struct list *new_fragment_arg);
1012 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
1013
1014 /* Functions related to subtlvs */
1015
isis_alloc_subtlvs(enum isis_tlv_context context)1016 static struct isis_subtlvs *isis_alloc_subtlvs(enum isis_tlv_context context)
1017 {
1018 struct isis_subtlvs *result;
1019
1020 result = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*result));
1021 result->context = context;
1022
1023 init_item_list(&result->prefix_sids);
1024
1025 return result;
1026 }
1027
copy_subtlvs(struct isis_subtlvs * subtlvs)1028 static struct isis_subtlvs *copy_subtlvs(struct isis_subtlvs *subtlvs)
1029 {
1030 if (!subtlvs)
1031 return NULL;
1032
1033 struct isis_subtlvs *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
1034
1035 rv->context = subtlvs->context;
1036
1037 copy_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
1038 &subtlvs->prefix_sids, &rv->prefix_sids);
1039
1040 rv->source_prefix =
1041 copy_subtlv_ipv6_source_prefix(subtlvs->source_prefix);
1042 return rv;
1043 }
1044
format_subtlvs(struct isis_subtlvs * subtlvs,struct sbuf * buf,int indent)1045 static void format_subtlvs(struct isis_subtlvs *subtlvs, struct sbuf *buf,
1046 int indent)
1047 {
1048 format_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
1049 &subtlvs->prefix_sids, buf, indent);
1050
1051 format_subtlv_ipv6_source_prefix(subtlvs->source_prefix, buf, indent);
1052 }
1053
isis_free_subtlvs(struct isis_subtlvs * subtlvs)1054 static void isis_free_subtlvs(struct isis_subtlvs *subtlvs)
1055 {
1056 if (!subtlvs)
1057 return;
1058
1059 free_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
1060 &subtlvs->prefix_sids);
1061
1062 XFREE(MTYPE_ISIS_SUBTLV, subtlvs->source_prefix);
1063
1064 XFREE(MTYPE_ISIS_SUBTLV, subtlvs);
1065 }
1066
pack_subtlvs(struct isis_subtlvs * subtlvs,struct stream * s)1067 static int pack_subtlvs(struct isis_subtlvs *subtlvs, struct stream *s)
1068 {
1069 int rv;
1070 size_t subtlv_len_pos = stream_get_endp(s);
1071
1072 if (STREAM_WRITEABLE(s) < 1)
1073 return 1;
1074
1075 stream_putc(s, 0); /* Put 0 as subtlvs length, filled in later */
1076
1077 rv = pack_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
1078 &subtlvs->prefix_sids, s, NULL, NULL, NULL, NULL);
1079 if (rv)
1080 return rv;
1081
1082 rv = pack_subtlv_ipv6_source_prefix(subtlvs->source_prefix, s);
1083 if (rv)
1084 return rv;
1085
1086 size_t subtlv_len = stream_get_endp(s) - subtlv_len_pos - 1;
1087 if (subtlv_len > 255)
1088 return 1;
1089
1090 stream_putc_at(s, subtlv_len_pos, subtlv_len);
1091 return 0;
1092 }
1093
1094 static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len,
1095 struct stream *stream, struct sbuf *log, void *dest,
1096 int indent, bool *unpacked_known_tlvs);
1097
1098 /* Functions related to TLVs 1 Area Addresses */
1099
copy_item_area_address(struct isis_item * i)1100 static struct isis_item *copy_item_area_address(struct isis_item *i)
1101 {
1102 struct isis_area_address *addr = (struct isis_area_address *)i;
1103 struct isis_area_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1104
1105 rv->len = addr->len;
1106 memcpy(rv->addr, addr->addr, addr->len);
1107 return (struct isis_item *)rv;
1108 }
1109
format_item_area_address(uint16_t mtid,struct isis_item * i,struct sbuf * buf,int indent)1110 static void format_item_area_address(uint16_t mtid, struct isis_item *i,
1111 struct sbuf *buf, int indent)
1112 {
1113 struct isis_area_address *addr = (struct isis_area_address *)i;
1114
1115 sbuf_push(buf, indent, "Area Address: %s\n",
1116 isonet_print(addr->addr, addr->len));
1117 }
1118
free_item_area_address(struct isis_item * i)1119 static void free_item_area_address(struct isis_item *i)
1120 {
1121 XFREE(MTYPE_ISIS_TLV, i);
1122 }
1123
pack_item_area_address(struct isis_item * i,struct stream * s)1124 static int pack_item_area_address(struct isis_item *i, struct stream *s)
1125 {
1126 struct isis_area_address *addr = (struct isis_area_address *)i;
1127
1128 if (STREAM_WRITEABLE(s) < (unsigned)1 + addr->len)
1129 return 1;
1130 stream_putc(s, addr->len);
1131 stream_put(s, addr->addr, addr->len);
1132 return 0;
1133 }
1134
unpack_item_area_address(uint16_t mtid,uint8_t len,struct stream * s,struct sbuf * log,void * dest,int indent)1135 static int unpack_item_area_address(uint16_t mtid, uint8_t len,
1136 struct stream *s, struct sbuf *log,
1137 void *dest, int indent)
1138 {
1139 struct isis_tlvs *tlvs = dest;
1140 struct isis_area_address *rv = NULL;
1141
1142 sbuf_push(log, indent, "Unpack area address...\n");
1143 if (len < 1) {
1144 sbuf_push(
1145 log, indent,
1146 "Not enough data left. (Expected 1 byte of address length, got %hhu)\n",
1147 len);
1148 goto out;
1149 }
1150
1151 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1152 rv->len = stream_getc(s);
1153
1154 if (len < 1 + rv->len) {
1155 sbuf_push(log, indent, "Not enough data left. (Expected %hhu bytes of address, got %u)\n",
1156 rv->len, len - 1);
1157 goto out;
1158 }
1159
1160 if (rv->len < 1 || rv->len > 20) {
1161 sbuf_push(log, indent,
1162 "Implausible area address length %hhu\n",
1163 rv->len);
1164 goto out;
1165 }
1166
1167 stream_get(rv->addr, s, rv->len);
1168
1169 format_item_area_address(ISIS_MT_IPV4_UNICAST, (struct isis_item *)rv,
1170 log, indent + 2);
1171 append_item(&tlvs->area_addresses, (struct isis_item *)rv);
1172 return 0;
1173 out:
1174 XFREE(MTYPE_ISIS_TLV, rv);
1175 return 1;
1176 }
1177
1178 /* Functions related to TLV 2 (Old-Style) IS Reach */
copy_item_oldstyle_reach(struct isis_item * i)1179 static struct isis_item *copy_item_oldstyle_reach(struct isis_item *i)
1180 {
1181 struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i;
1182 struct isis_oldstyle_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1183
1184 memcpy(rv->id, r->id, 7);
1185 rv->metric = r->metric;
1186 return (struct isis_item *)rv;
1187 }
1188
format_item_oldstyle_reach(uint16_t mtid,struct isis_item * i,struct sbuf * buf,int indent)1189 static void format_item_oldstyle_reach(uint16_t mtid, struct isis_item *i,
1190 struct sbuf *buf, int indent)
1191 {
1192 struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i;
1193
1194 sbuf_push(buf, indent, "IS Reachability: %s (Metric: %hhu)\n",
1195 isis_format_id(r->id, 7), r->metric);
1196 }
1197
free_item_oldstyle_reach(struct isis_item * i)1198 static void free_item_oldstyle_reach(struct isis_item *i)
1199 {
1200 XFREE(MTYPE_ISIS_TLV, i);
1201 }
1202
pack_item_oldstyle_reach(struct isis_item * i,struct stream * s)1203 static int pack_item_oldstyle_reach(struct isis_item *i, struct stream *s)
1204 {
1205 struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i;
1206
1207 if (STREAM_WRITEABLE(s) < 11)
1208 return 1;
1209
1210 stream_putc(s, r->metric);
1211 stream_putc(s, 0x80); /* delay metric - unsupported */
1212 stream_putc(s, 0x80); /* expense metric - unsupported */
1213 stream_putc(s, 0x80); /* error metric - unsupported */
1214 stream_put(s, r->id, 7);
1215
1216 return 0;
1217 }
1218
unpack_item_oldstyle_reach(uint16_t mtid,uint8_t len,struct stream * s,struct sbuf * log,void * dest,int indent)1219 static int unpack_item_oldstyle_reach(uint16_t mtid, uint8_t len,
1220 struct stream *s, struct sbuf *log,
1221 void *dest, int indent)
1222 {
1223 struct isis_tlvs *tlvs = dest;
1224
1225 sbuf_push(log, indent, "Unpack oldstyle reach...\n");
1226 if (len < 11) {
1227 sbuf_push(
1228 log, indent,
1229 "Not enough data left.(Expected 11 bytes of reach information, got %hhu)\n",
1230 len);
1231 return 1;
1232 }
1233
1234 struct isis_oldstyle_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1235 rv->metric = stream_getc(s);
1236 if ((rv->metric & 0x3f) != rv->metric) {
1237 sbuf_push(log, indent, "Metric has unplausible format\n");
1238 rv->metric &= 0x3f;
1239 }
1240 stream_forward_getp(s, 3); /* Skip other metrics */
1241 stream_get(rv->id, s, 7);
1242
1243 format_item_oldstyle_reach(mtid, (struct isis_item *)rv, log,
1244 indent + 2);
1245 append_item(&tlvs->oldstyle_reach, (struct isis_item *)rv);
1246 return 0;
1247 }
1248
1249 /* Functions related to TLV 6 LAN Neighbors */
copy_item_lan_neighbor(struct isis_item * i)1250 static struct isis_item *copy_item_lan_neighbor(struct isis_item *i)
1251 {
1252 struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i;
1253 struct isis_lan_neighbor *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1254
1255 memcpy(rv->mac, n->mac, 6);
1256 return (struct isis_item *)rv;
1257 }
1258
format_item_lan_neighbor(uint16_t mtid,struct isis_item * i,struct sbuf * buf,int indent)1259 static void format_item_lan_neighbor(uint16_t mtid, struct isis_item *i,
1260 struct sbuf *buf, int indent)
1261 {
1262 struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i;
1263
1264 sbuf_push(buf, indent, "LAN Neighbor: %s\n", isis_format_id(n->mac, 6));
1265 }
1266
free_item_lan_neighbor(struct isis_item * i)1267 static void free_item_lan_neighbor(struct isis_item *i)
1268 {
1269 XFREE(MTYPE_ISIS_TLV, i);
1270 }
1271
pack_item_lan_neighbor(struct isis_item * i,struct stream * s)1272 static int pack_item_lan_neighbor(struct isis_item *i, struct stream *s)
1273 {
1274 struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i;
1275
1276 if (STREAM_WRITEABLE(s) < 6)
1277 return 1;
1278
1279 stream_put(s, n->mac, 6);
1280
1281 return 0;
1282 }
1283
unpack_item_lan_neighbor(uint16_t mtid,uint8_t len,struct stream * s,struct sbuf * log,void * dest,int indent)1284 static int unpack_item_lan_neighbor(uint16_t mtid, uint8_t len,
1285 struct stream *s, struct sbuf *log,
1286 void *dest, int indent)
1287 {
1288 struct isis_tlvs *tlvs = dest;
1289
1290 sbuf_push(log, indent, "Unpack LAN neighbor...\n");
1291 if (len < 6) {
1292 sbuf_push(
1293 log, indent,
1294 "Not enough data left.(Expected 6 bytes of mac, got %hhu)\n",
1295 len);
1296 return 1;
1297 }
1298
1299 struct isis_lan_neighbor *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1300 stream_get(rv->mac, s, 6);
1301
1302 format_item_lan_neighbor(mtid, (struct isis_item *)rv, log, indent + 2);
1303 append_item(&tlvs->lan_neighbor, (struct isis_item *)rv);
1304 return 0;
1305 }
1306
1307 /* Functions related to TLV 9 LSP Entry */
copy_item_lsp_entry(struct isis_item * i)1308 static struct isis_item *copy_item_lsp_entry(struct isis_item *i)
1309 {
1310 struct isis_lsp_entry *e = (struct isis_lsp_entry *)i;
1311 struct isis_lsp_entry *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1312
1313 rv->rem_lifetime = e->rem_lifetime;
1314 memcpy(rv->id, e->id, sizeof(rv->id));
1315 rv->seqno = e->seqno;
1316 rv->checksum = e->checksum;
1317
1318 return (struct isis_item *)rv;
1319 }
1320
format_item_lsp_entry(uint16_t mtid,struct isis_item * i,struct sbuf * buf,int indent)1321 static void format_item_lsp_entry(uint16_t mtid, struct isis_item *i,
1322 struct sbuf *buf, int indent)
1323 {
1324 struct isis_lsp_entry *e = (struct isis_lsp_entry *)i;
1325
1326 sbuf_push(buf, indent,
1327 "LSP Entry: %s, seq 0x%08x, cksum 0x%04hx, lifetime %hus\n",
1328 isis_format_id(e->id, 8), e->seqno, e->checksum,
1329 e->rem_lifetime);
1330 }
1331
free_item_lsp_entry(struct isis_item * i)1332 static void free_item_lsp_entry(struct isis_item *i)
1333 {
1334 XFREE(MTYPE_ISIS_TLV, i);
1335 }
1336
pack_item_lsp_entry(struct isis_item * i,struct stream * s)1337 static int pack_item_lsp_entry(struct isis_item *i, struct stream *s)
1338 {
1339 struct isis_lsp_entry *e = (struct isis_lsp_entry *)i;
1340
1341 if (STREAM_WRITEABLE(s) < 16)
1342 return 1;
1343
1344 stream_putw(s, e->rem_lifetime);
1345 stream_put(s, e->id, 8);
1346 stream_putl(s, e->seqno);
1347 stream_putw(s, e->checksum);
1348
1349 return 0;
1350 }
1351
unpack_item_lsp_entry(uint16_t mtid,uint8_t len,struct stream * s,struct sbuf * log,void * dest,int indent)1352 static int unpack_item_lsp_entry(uint16_t mtid, uint8_t len, struct stream *s,
1353 struct sbuf *log, void *dest, int indent)
1354 {
1355 struct isis_tlvs *tlvs = dest;
1356
1357 sbuf_push(log, indent, "Unpack LSP entry...\n");
1358 if (len < 16) {
1359 sbuf_push(
1360 log, indent,
1361 "Not enough data left. (Expected 16 bytes of LSP info, got %hhu",
1362 len);
1363 return 1;
1364 }
1365
1366 struct isis_lsp_entry *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1367 rv->rem_lifetime = stream_getw(s);
1368 stream_get(rv->id, s, 8);
1369 rv->seqno = stream_getl(s);
1370 rv->checksum = stream_getw(s);
1371
1372 format_item_lsp_entry(mtid, (struct isis_item *)rv, log, indent + 2);
1373 append_item(&tlvs->lsp_entries, (struct isis_item *)rv);
1374 return 0;
1375 }
1376
1377 /* Functions related to TLVs 22/222 Extended Reach/MT Reach */
1378
copy_item_extended_reach(struct isis_item * i)1379 static struct isis_item *copy_item_extended_reach(struct isis_item *i)
1380 {
1381 struct isis_extended_reach *r = (struct isis_extended_reach *)i;
1382 struct isis_extended_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1383
1384 memcpy(rv->id, r->id, 7);
1385 rv->metric = r->metric;
1386
1387 if (r->subtlvs)
1388 rv->subtlvs = copy_item_ext_subtlvs(r->subtlvs, -1);
1389
1390 return (struct isis_item *)rv;
1391 }
1392
format_item_extended_reach(uint16_t mtid,struct isis_item * i,struct sbuf * buf,int indent)1393 static void format_item_extended_reach(uint16_t mtid, struct isis_item *i,
1394 struct sbuf *buf, int indent)
1395 {
1396 struct isis_extended_reach *r = (struct isis_extended_reach *)i;
1397
1398 sbuf_push(buf, indent, "%s Reachability: %s (Metric: %u)",
1399 (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT",
1400 isis_format_id(r->id, 7), r->metric);
1401 if (mtid != ISIS_MT_IPV4_UNICAST)
1402 sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
1403 sbuf_push(buf, 0, "\n");
1404
1405 if (r->subtlvs)
1406 format_item_ext_subtlvs(r->subtlvs, buf, indent + 2, mtid);
1407 }
1408
free_item_extended_reach(struct isis_item * i)1409 static void free_item_extended_reach(struct isis_item *i)
1410 {
1411 struct isis_extended_reach *item = (struct isis_extended_reach *)i;
1412 if (item->subtlvs != NULL)
1413 free_item_ext_subtlvs(item->subtlvs);
1414 XFREE(MTYPE_ISIS_TLV, item);
1415 }
1416
pack_item_extended_reach(struct isis_item * i,struct stream * s)1417 static int pack_item_extended_reach(struct isis_item *i, struct stream *s)
1418 {
1419 struct isis_extended_reach *r = (struct isis_extended_reach *)i;
1420 size_t len;
1421 size_t len_pos;
1422
1423 if (STREAM_WRITEABLE(s) < 11 + ISIS_SUBTLV_MAX_SIZE)
1424 return 1;
1425
1426 stream_put(s, r->id, sizeof(r->id));
1427 stream_put3(s, r->metric);
1428 len_pos = stream_get_endp(s);
1429 /* Real length will be adjust after adding subTLVs */
1430 stream_putc(s, 11);
1431 if (r->subtlvs)
1432 pack_item_ext_subtlvs(r->subtlvs, s);
1433 /* Adjust length */
1434 len = stream_get_endp(s) - len_pos - 1;
1435 stream_putc_at(s, len_pos, len);
1436 return 0;
1437 }
1438
unpack_item_extended_reach(uint16_t mtid,uint8_t len,struct stream * s,struct sbuf * log,void * dest,int indent)1439 static int unpack_item_extended_reach(uint16_t mtid, uint8_t len,
1440 struct stream *s, struct sbuf *log,
1441 void *dest, int indent)
1442 {
1443 struct isis_tlvs *tlvs = dest;
1444 struct isis_extended_reach *rv = NULL;
1445 uint8_t subtlv_len;
1446 struct isis_item_list *items;
1447
1448 if (mtid == ISIS_MT_IPV4_UNICAST) {
1449 items = &tlvs->extended_reach;
1450 } else {
1451 items = isis_get_mt_items(&tlvs->mt_reach, mtid);
1452 }
1453
1454 sbuf_push(log, indent, "Unpacking %s reachability...\n",
1455 (mtid == ISIS_MT_IPV4_UNICAST) ? "extended" : "mt");
1456
1457 if (len < 11) {
1458 sbuf_push(log, indent,
1459 "Not enough data left. (expected 11 or more bytes, got %hhu)\n",
1460 len);
1461 goto out;
1462 }
1463
1464 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1465 stream_get(rv->id, s, 7);
1466 rv->metric = stream_get3(s);
1467 subtlv_len = stream_getc(s);
1468
1469 if ((size_t)len < ((size_t)11) + subtlv_len) {
1470 sbuf_push(log, indent,
1471 "Not enough data left for subtlv size %hhu, there are only %u bytes left.\n",
1472 subtlv_len, len - 11);
1473 goto out;
1474 }
1475
1476 sbuf_push(log, indent, "Storing %hhu bytes of subtlvs\n",
1477 subtlv_len);
1478
1479 if (subtlv_len) {
1480 if (unpack_item_ext_subtlvs(mtid, subtlv_len, s, log, rv,
1481 indent + 4)) {
1482 goto out;
1483 }
1484 }
1485
1486 format_item_extended_reach(mtid, (struct isis_item *)rv, log,
1487 indent + 2);
1488 append_item(items, (struct isis_item *)rv);
1489 return 0;
1490 out:
1491 if (rv)
1492 free_item_extended_reach((struct isis_item *)rv);
1493
1494 return 1;
1495 }
1496
1497 /* Functions related to TLV 128 (Old-Style) IP Reach */
copy_item_oldstyle_ip_reach(struct isis_item * i)1498 static struct isis_item *copy_item_oldstyle_ip_reach(struct isis_item *i)
1499 {
1500 struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i;
1501 struct isis_oldstyle_ip_reach *rv =
1502 XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1503
1504 rv->metric = r->metric;
1505 rv->prefix = r->prefix;
1506 return (struct isis_item *)rv;
1507 }
1508
format_item_oldstyle_ip_reach(uint16_t mtid,struct isis_item * i,struct sbuf * buf,int indent)1509 static void format_item_oldstyle_ip_reach(uint16_t mtid, struct isis_item *i,
1510 struct sbuf *buf, int indent)
1511 {
1512 struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i;
1513 char prefixbuf[PREFIX2STR_BUFFER];
1514
1515 sbuf_push(buf, indent, "IP Reachability: %s (Metric: %hhu)\n",
1516 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)),
1517 r->metric);
1518 }
1519
free_item_oldstyle_ip_reach(struct isis_item * i)1520 static void free_item_oldstyle_ip_reach(struct isis_item *i)
1521 {
1522 XFREE(MTYPE_ISIS_TLV, i);
1523 }
1524
pack_item_oldstyle_ip_reach(struct isis_item * i,struct stream * s)1525 static int pack_item_oldstyle_ip_reach(struct isis_item *i, struct stream *s)
1526 {
1527 struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i;
1528
1529 if (STREAM_WRITEABLE(s) < 12)
1530 return 1;
1531
1532 stream_putc(s, r->metric);
1533 stream_putc(s, 0x80); /* delay metric - unsupported */
1534 stream_putc(s, 0x80); /* expense metric - unsupported */
1535 stream_putc(s, 0x80); /* error metric - unsupported */
1536 stream_put(s, &r->prefix.prefix, 4);
1537
1538 struct in_addr mask;
1539 masklen2ip(r->prefix.prefixlen, &mask);
1540 stream_put(s, &mask, sizeof(mask));
1541
1542 return 0;
1543 }
1544
unpack_item_oldstyle_ip_reach(uint16_t mtid,uint8_t len,struct stream * s,struct sbuf * log,void * dest,int indent)1545 static int unpack_item_oldstyle_ip_reach(uint16_t mtid, uint8_t len,
1546 struct stream *s, struct sbuf *log,
1547 void *dest, int indent)
1548 {
1549 sbuf_push(log, indent, "Unpack oldstyle ip reach...\n");
1550 if (len < 12) {
1551 sbuf_push(
1552 log, indent,
1553 "Not enough data left.(Expected 12 bytes of reach information, got %hhu)\n",
1554 len);
1555 return 1;
1556 }
1557
1558 struct isis_oldstyle_ip_reach *rv =
1559 XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1560 rv->metric = stream_getc(s);
1561 if ((rv->metric & 0x7f) != rv->metric) {
1562 sbuf_push(log, indent, "Metric has unplausible format\n");
1563 rv->metric &= 0x7f;
1564 }
1565 stream_forward_getp(s, 3); /* Skip other metrics */
1566 rv->prefix.family = AF_INET;
1567 stream_get(&rv->prefix.prefix, s, 4);
1568
1569 struct in_addr mask;
1570 stream_get(&mask, s, 4);
1571 rv->prefix.prefixlen = ip_masklen(mask);
1572
1573 format_item_oldstyle_ip_reach(mtid, (struct isis_item *)rv, log,
1574 indent + 2);
1575 append_item(dest, (struct isis_item *)rv);
1576 return 0;
1577 }
1578
1579
1580 /* Functions related to TLV 129 protocols supported */
1581
copy_tlv_protocols_supported(struct isis_protocols_supported * src,struct isis_protocols_supported * dest)1582 static void copy_tlv_protocols_supported(struct isis_protocols_supported *src,
1583 struct isis_protocols_supported *dest)
1584 {
1585 if (!src->protocols || !src->count)
1586 return;
1587 dest->count = src->count;
1588 dest->protocols = XCALLOC(MTYPE_ISIS_TLV, src->count);
1589 memcpy(dest->protocols, src->protocols, src->count);
1590 }
1591
format_tlv_protocols_supported(struct isis_protocols_supported * p,struct sbuf * buf,int indent)1592 static void format_tlv_protocols_supported(struct isis_protocols_supported *p,
1593 struct sbuf *buf, int indent)
1594 {
1595 if (!p || !p->count || !p->protocols)
1596 return;
1597
1598 sbuf_push(buf, indent, "Protocols Supported: ");
1599 for (uint8_t i = 0; i < p->count; i++) {
1600 sbuf_push(buf, 0, "%s%s", nlpid2str(p->protocols[i]),
1601 (i + 1 < p->count) ? ", " : "");
1602 }
1603 sbuf_push(buf, 0, "\n");
1604 }
1605
free_tlv_protocols_supported(struct isis_protocols_supported * p)1606 static void free_tlv_protocols_supported(struct isis_protocols_supported *p)
1607 {
1608 XFREE(MTYPE_ISIS_TLV, p->protocols);
1609 }
1610
pack_tlv_protocols_supported(struct isis_protocols_supported * p,struct stream * s)1611 static int pack_tlv_protocols_supported(struct isis_protocols_supported *p,
1612 struct stream *s)
1613 {
1614 if (!p || !p->count || !p->protocols)
1615 return 0;
1616
1617 if (STREAM_WRITEABLE(s) < (unsigned)(p->count + 2))
1618 return 1;
1619
1620 stream_putc(s, ISIS_TLV_PROTOCOLS_SUPPORTED);
1621 stream_putc(s, p->count);
1622 stream_put(s, p->protocols, p->count);
1623 return 0;
1624 }
1625
unpack_tlv_protocols_supported(enum isis_tlv_context context,uint8_t tlv_type,uint8_t tlv_len,struct stream * s,struct sbuf * log,void * dest,int indent)1626 static int unpack_tlv_protocols_supported(enum isis_tlv_context context,
1627 uint8_t tlv_type, uint8_t tlv_len,
1628 struct stream *s, struct sbuf *log,
1629 void *dest, int indent)
1630 {
1631 struct isis_tlvs *tlvs = dest;
1632
1633 sbuf_push(log, indent, "Unpacking Protocols Supported TLV...\n");
1634 if (!tlv_len) {
1635 sbuf_push(log, indent, "WARNING: No protocols included\n");
1636 return 0;
1637 }
1638 if (tlvs->protocols_supported.protocols) {
1639 sbuf_push(
1640 log, indent,
1641 "WARNING: protocols supported TLV present multiple times.\n");
1642 stream_forward_getp(s, tlv_len);
1643 return 0;
1644 }
1645
1646 tlvs->protocols_supported.count = tlv_len;
1647 tlvs->protocols_supported.protocols = XCALLOC(MTYPE_ISIS_TLV, tlv_len);
1648 stream_get(tlvs->protocols_supported.protocols, s, tlv_len);
1649
1650 format_tlv_protocols_supported(&tlvs->protocols_supported, log,
1651 indent + 2);
1652 return 0;
1653 }
1654
1655 /* Functions related to TLV 132 IPv4 Interface addresses */
copy_item_ipv4_address(struct isis_item * i)1656 static struct isis_item *copy_item_ipv4_address(struct isis_item *i)
1657 {
1658 struct isis_ipv4_address *a = (struct isis_ipv4_address *)i;
1659 struct isis_ipv4_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1660
1661 rv->addr = a->addr;
1662 return (struct isis_item *)rv;
1663 }
1664
format_item_ipv4_address(uint16_t mtid,struct isis_item * i,struct sbuf * buf,int indent)1665 static void format_item_ipv4_address(uint16_t mtid, struct isis_item *i,
1666 struct sbuf *buf, int indent)
1667 {
1668 struct isis_ipv4_address *a = (struct isis_ipv4_address *)i;
1669 char addrbuf[INET_ADDRSTRLEN];
1670
1671 inet_ntop(AF_INET, &a->addr, addrbuf, sizeof(addrbuf));
1672 sbuf_push(buf, indent, "IPv4 Interface Address: %s\n", addrbuf);
1673 }
1674
free_item_ipv4_address(struct isis_item * i)1675 static void free_item_ipv4_address(struct isis_item *i)
1676 {
1677 XFREE(MTYPE_ISIS_TLV, i);
1678 }
1679
pack_item_ipv4_address(struct isis_item * i,struct stream * s)1680 static int pack_item_ipv4_address(struct isis_item *i, struct stream *s)
1681 {
1682 struct isis_ipv4_address *a = (struct isis_ipv4_address *)i;
1683
1684 if (STREAM_WRITEABLE(s) < 4)
1685 return 1;
1686
1687 stream_put(s, &a->addr, 4);
1688
1689 return 0;
1690 }
1691
unpack_item_ipv4_address(uint16_t mtid,uint8_t len,struct stream * s,struct sbuf * log,void * dest,int indent)1692 static int unpack_item_ipv4_address(uint16_t mtid, uint8_t len,
1693 struct stream *s, struct sbuf *log,
1694 void *dest, int indent)
1695 {
1696 struct isis_tlvs *tlvs = dest;
1697
1698 sbuf_push(log, indent, "Unpack IPv4 Interface address...\n");
1699 if (len < 4) {
1700 sbuf_push(
1701 log, indent,
1702 "Not enough data left.(Expected 4 bytes of IPv4 address, got %hhu)\n",
1703 len);
1704 return 1;
1705 }
1706
1707 struct isis_ipv4_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1708 stream_get(&rv->addr, s, 4);
1709
1710 format_item_ipv4_address(mtid, (struct isis_item *)rv, log, indent + 2);
1711 append_item(&tlvs->ipv4_address, (struct isis_item *)rv);
1712 return 0;
1713 }
1714
1715
1716 /* Functions related to TLV 232 IPv6 Interface addresses */
copy_item_ipv6_address(struct isis_item * i)1717 static struct isis_item *copy_item_ipv6_address(struct isis_item *i)
1718 {
1719 struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
1720 struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1721
1722 rv->addr = a->addr;
1723 return (struct isis_item *)rv;
1724 }
1725
format_item_ipv6_address(uint16_t mtid,struct isis_item * i,struct sbuf * buf,int indent)1726 static void format_item_ipv6_address(uint16_t mtid, struct isis_item *i,
1727 struct sbuf *buf, int indent)
1728 {
1729 struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
1730 char addrbuf[INET6_ADDRSTRLEN];
1731
1732 inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf));
1733 sbuf_push(buf, indent, "IPv6 Interface Address: %s\n", addrbuf);
1734 }
1735
free_item_ipv6_address(struct isis_item * i)1736 static void free_item_ipv6_address(struct isis_item *i)
1737 {
1738 XFREE(MTYPE_ISIS_TLV, i);
1739 }
1740
pack_item_ipv6_address(struct isis_item * i,struct stream * s)1741 static int pack_item_ipv6_address(struct isis_item *i, struct stream *s)
1742 {
1743 struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
1744
1745 if (STREAM_WRITEABLE(s) < 16)
1746 return 1;
1747
1748 stream_put(s, &a->addr, 16);
1749
1750 return 0;
1751 }
1752
unpack_item_ipv6_address(uint16_t mtid,uint8_t len,struct stream * s,struct sbuf * log,void * dest,int indent)1753 static int unpack_item_ipv6_address(uint16_t mtid, uint8_t len,
1754 struct stream *s, struct sbuf *log,
1755 void *dest, int indent)
1756 {
1757 struct isis_tlvs *tlvs = dest;
1758
1759 sbuf_push(log, indent, "Unpack IPv6 Interface address...\n");
1760 if (len < 16) {
1761 sbuf_push(
1762 log, indent,
1763 "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
1764 len);
1765 return 1;
1766 }
1767
1768 struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1769 stream_get(&rv->addr, s, 16);
1770
1771 format_item_ipv6_address(mtid, (struct isis_item *)rv, log, indent + 2);
1772 append_item(&tlvs->ipv6_address, (struct isis_item *)rv);
1773 return 0;
1774 }
1775
1776
1777 /* Functions related to TLV 229 MT Router information */
copy_item_mt_router_info(struct isis_item * i)1778 static struct isis_item *copy_item_mt_router_info(struct isis_item *i)
1779 {
1780 struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
1781 struct isis_mt_router_info *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1782
1783 rv->overload = info->overload;
1784 rv->attached = info->attached;
1785 rv->mtid = info->mtid;
1786 return (struct isis_item *)rv;
1787 }
1788
format_item_mt_router_info(uint16_t mtid,struct isis_item * i,struct sbuf * buf,int indent)1789 static void format_item_mt_router_info(uint16_t mtid, struct isis_item *i,
1790 struct sbuf *buf, int indent)
1791 {
1792 struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
1793
1794 sbuf_push(buf, indent, "MT Router Info: %s%s%s\n",
1795 isis_mtid2str(info->mtid),
1796 info->overload ? " Overload" : "",
1797 info->attached ? " Attached" : "");
1798 }
1799
free_item_mt_router_info(struct isis_item * i)1800 static void free_item_mt_router_info(struct isis_item *i)
1801 {
1802 XFREE(MTYPE_ISIS_TLV, i);
1803 }
1804
pack_item_mt_router_info(struct isis_item * i,struct stream * s)1805 static int pack_item_mt_router_info(struct isis_item *i, struct stream *s)
1806 {
1807 struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
1808
1809 if (STREAM_WRITEABLE(s) < 2)
1810 return 1;
1811
1812 uint16_t entry = info->mtid;
1813
1814 if (info->overload)
1815 entry |= ISIS_MT_OL_MASK;
1816 if (info->attached)
1817 entry |= ISIS_MT_AT_MASK;
1818
1819 stream_putw(s, entry);
1820
1821 return 0;
1822 }
1823
unpack_item_mt_router_info(uint16_t mtid,uint8_t len,struct stream * s,struct sbuf * log,void * dest,int indent)1824 static int unpack_item_mt_router_info(uint16_t mtid, uint8_t len,
1825 struct stream *s, struct sbuf *log,
1826 void *dest, int indent)
1827 {
1828 struct isis_tlvs *tlvs = dest;
1829
1830 sbuf_push(log, indent, "Unpack MT Router info...\n");
1831 if (len < 2) {
1832 sbuf_push(
1833 log, indent,
1834 "Not enough data left.(Expected 2 bytes of MT info, got %hhu)\n",
1835 len);
1836 return 1;
1837 }
1838
1839 struct isis_mt_router_info *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1840
1841 uint16_t entry = stream_getw(s);
1842 rv->overload = entry & ISIS_MT_OL_MASK;
1843 rv->attached = entry & ISIS_MT_AT_MASK;
1844 rv->mtid = entry & ISIS_MT_MASK;
1845
1846 format_item_mt_router_info(mtid, (struct isis_item *)rv, log,
1847 indent + 2);
1848 append_item(&tlvs->mt_router_info, (struct isis_item *)rv);
1849 return 0;
1850 }
1851
1852 /* Functions related to TLV 134 TE Router ID */
1853
copy_tlv_te_router_id(const struct in_addr * id)1854 static struct in_addr *copy_tlv_te_router_id(const struct in_addr *id)
1855 {
1856 if (!id)
1857 return NULL;
1858
1859 struct in_addr *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1860 memcpy(rv, id, sizeof(*rv));
1861 return rv;
1862 }
1863
format_tlv_te_router_id(const struct in_addr * id,struct sbuf * buf,int indent)1864 static void format_tlv_te_router_id(const struct in_addr *id, struct sbuf *buf,
1865 int indent)
1866 {
1867 if (!id)
1868 return;
1869
1870 char addrbuf[INET_ADDRSTRLEN];
1871 inet_ntop(AF_INET, id, addrbuf, sizeof(addrbuf));
1872 sbuf_push(buf, indent, "TE Router ID: %s\n", addrbuf);
1873 }
1874
free_tlv_te_router_id(struct in_addr * id)1875 static void free_tlv_te_router_id(struct in_addr *id)
1876 {
1877 XFREE(MTYPE_ISIS_TLV, id);
1878 }
1879
pack_tlv_te_router_id(const struct in_addr * id,struct stream * s)1880 static int pack_tlv_te_router_id(const struct in_addr *id, struct stream *s)
1881 {
1882 if (!id)
1883 return 0;
1884
1885 if (STREAM_WRITEABLE(s) < (unsigned)(2 + sizeof(*id)))
1886 return 1;
1887
1888 stream_putc(s, ISIS_TLV_TE_ROUTER_ID);
1889 stream_putc(s, 4);
1890 stream_put(s, id, 4);
1891 return 0;
1892 }
1893
unpack_tlv_te_router_id(enum isis_tlv_context context,uint8_t tlv_type,uint8_t tlv_len,struct stream * s,struct sbuf * log,void * dest,int indent)1894 static int unpack_tlv_te_router_id(enum isis_tlv_context context,
1895 uint8_t tlv_type, uint8_t tlv_len,
1896 struct stream *s, struct sbuf *log,
1897 void *dest, int indent)
1898 {
1899 struct isis_tlvs *tlvs = dest;
1900
1901 sbuf_push(log, indent, "Unpacking TE Router ID TLV...\n");
1902 if (tlv_len != 4) {
1903 sbuf_push(log, indent, "WARNING: Length invalid\n");
1904 return 1;
1905 }
1906
1907 if (tlvs->te_router_id) {
1908 sbuf_push(log, indent,
1909 "WARNING: TE Router ID present multiple times.\n");
1910 stream_forward_getp(s, tlv_len);
1911 return 0;
1912 }
1913
1914 tlvs->te_router_id = XCALLOC(MTYPE_ISIS_TLV, 4);
1915 stream_get(tlvs->te_router_id, s, 4);
1916 format_tlv_te_router_id(tlvs->te_router_id, log, indent + 2);
1917 return 0;
1918 }
1919
1920
1921 /* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
1922
copy_item_extended_ip_reach(struct isis_item * i)1923 static struct isis_item *copy_item_extended_ip_reach(struct isis_item *i)
1924 {
1925 struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
1926 struct isis_extended_ip_reach *rv =
1927 XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
1928
1929 rv->metric = r->metric;
1930 rv->down = r->down;
1931 rv->prefix = r->prefix;
1932 rv->subtlvs = copy_subtlvs(r->subtlvs);
1933
1934 return (struct isis_item *)rv;
1935 }
1936
format_item_extended_ip_reach(uint16_t mtid,struct isis_item * i,struct sbuf * buf,int indent)1937 static void format_item_extended_ip_reach(uint16_t mtid, struct isis_item *i,
1938 struct sbuf *buf, int indent)
1939 {
1940 struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
1941 char prefixbuf[PREFIX2STR_BUFFER];
1942
1943 sbuf_push(buf, indent, "%s IP Reachability: %s (Metric: %u)%s",
1944 (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT",
1945 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), r->metric,
1946 r->down ? " Down" : "");
1947 if (mtid != ISIS_MT_IPV4_UNICAST)
1948 sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
1949 sbuf_push(buf, 0, "\n");
1950
1951 if (r->subtlvs) {
1952 sbuf_push(buf, indent, " Subtlvs:\n");
1953 format_subtlvs(r->subtlvs, buf, indent + 4);
1954 }
1955 }
1956
free_item_extended_ip_reach(struct isis_item * i)1957 static void free_item_extended_ip_reach(struct isis_item *i)
1958 {
1959 struct isis_extended_ip_reach *item =
1960 (struct isis_extended_ip_reach *)i;
1961 isis_free_subtlvs(item->subtlvs);
1962 XFREE(MTYPE_ISIS_TLV, item);
1963 }
1964
pack_item_extended_ip_reach(struct isis_item * i,struct stream * s)1965 static int pack_item_extended_ip_reach(struct isis_item *i, struct stream *s)
1966 {
1967 struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
1968 uint8_t control;
1969
1970 if (STREAM_WRITEABLE(s) < 5)
1971 return 1;
1972 stream_putl(s, r->metric);
1973
1974 control = r->down ? ISIS_EXTENDED_IP_REACH_DOWN : 0;
1975 control |= r->prefix.prefixlen;
1976 control |= r->subtlvs ? ISIS_EXTENDED_IP_REACH_SUBTLV : 0;
1977
1978 stream_putc(s, control);
1979
1980 if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen))
1981 return 1;
1982 stream_put(s, &r->prefix.prefix.s_addr, PSIZE(r->prefix.prefixlen));
1983
1984 if (r->subtlvs)
1985 return pack_subtlvs(r->subtlvs, s);
1986 return 0;
1987 }
1988
unpack_item_extended_ip_reach(uint16_t mtid,uint8_t len,struct stream * s,struct sbuf * log,void * dest,int indent)1989 static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len,
1990 struct stream *s, struct sbuf *log,
1991 void *dest, int indent)
1992 {
1993 struct isis_tlvs *tlvs = dest;
1994 struct isis_extended_ip_reach *rv = NULL;
1995 size_t consume;
1996 uint8_t control, subtlv_len;
1997 struct isis_item_list *items;
1998
1999 if (mtid == ISIS_MT_IPV4_UNICAST) {
2000 items = &tlvs->extended_ip_reach;
2001 } else {
2002 items = isis_get_mt_items(&tlvs->mt_ip_reach, mtid);
2003 }
2004
2005 sbuf_push(log, indent, "Unpacking %s IPv4 reachability...\n",
2006 (mtid == ISIS_MT_IPV4_UNICAST) ? "extended" : "mt");
2007
2008 consume = 5;
2009 if (len < consume) {
2010 sbuf_push(log, indent,
2011 "Not enough data left. (expected 5 or more bytes, got %hhu)\n",
2012 len);
2013 goto out;
2014 }
2015
2016 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2017
2018 rv->metric = stream_getl(s);
2019 control = stream_getc(s);
2020 rv->down = (control & ISIS_EXTENDED_IP_REACH_DOWN);
2021 rv->prefix.family = AF_INET;
2022 rv->prefix.prefixlen = control & 0x3f;
2023 if (rv->prefix.prefixlen > 32) {
2024 sbuf_push(log, indent, "Prefixlen %u is implausible for IPv4\n",
2025 rv->prefix.prefixlen);
2026 goto out;
2027 }
2028
2029 consume += PSIZE(rv->prefix.prefixlen);
2030 if (len < consume) {
2031 sbuf_push(log, indent,
2032 "Expected %u bytes of prefix, but only %u bytes available.\n",
2033 PSIZE(rv->prefix.prefixlen), len - 5);
2034 goto out;
2035 }
2036 stream_get(&rv->prefix.prefix.s_addr, s, PSIZE(rv->prefix.prefixlen));
2037 in_addr_t orig_prefix = rv->prefix.prefix.s_addr;
2038 apply_mask_ipv4(&rv->prefix);
2039 if (orig_prefix != rv->prefix.prefix.s_addr)
2040 sbuf_push(log, indent + 2,
2041 "WARNING: Prefix had hostbits set.\n");
2042 format_item_extended_ip_reach(mtid, (struct isis_item *)rv, log,
2043 indent + 2);
2044
2045 if (control & ISIS_EXTENDED_IP_REACH_SUBTLV) {
2046 consume += 1;
2047 if (len < consume) {
2048 sbuf_push(log, indent,
2049 "Expected 1 byte of subtlv len, but no more data present.\n");
2050 goto out;
2051 }
2052 subtlv_len = stream_getc(s);
2053
2054 if (!subtlv_len) {
2055 sbuf_push(log, indent + 2,
2056 " WARNING: subtlv bit is set, but there are no subtlvs.\n");
2057 }
2058 consume += subtlv_len;
2059 if (len < consume) {
2060 sbuf_push(log, indent,
2061 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
2062 subtlv_len,
2063 len - 6 - PSIZE(rv->prefix.prefixlen));
2064 goto out;
2065 }
2066
2067 rv->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH);
2068 bool unpacked_known_tlvs = false;
2069
2070 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH, subtlv_len, s,
2071 log, rv->subtlvs, indent + 4, &unpacked_known_tlvs)) {
2072 goto out;
2073 }
2074 if (!unpacked_known_tlvs) {
2075 isis_free_subtlvs(rv->subtlvs);
2076 rv->subtlvs = NULL;
2077 }
2078 }
2079
2080 append_item(items, (struct isis_item *)rv);
2081 return 0;
2082 out:
2083 if (rv)
2084 free_item_extended_ip_reach((struct isis_item *)rv);
2085 return 1;
2086 }
2087
2088 /* Functions related to TLV 137 Dynamic Hostname */
2089
copy_tlv_dynamic_hostname(const char * hostname)2090 static char *copy_tlv_dynamic_hostname(const char *hostname)
2091 {
2092 if (!hostname)
2093 return NULL;
2094
2095 return XSTRDUP(MTYPE_ISIS_TLV, hostname);
2096 }
2097
format_tlv_dynamic_hostname(const char * hostname,struct sbuf * buf,int indent)2098 static void format_tlv_dynamic_hostname(const char *hostname, struct sbuf *buf,
2099 int indent)
2100 {
2101 if (!hostname)
2102 return;
2103
2104 sbuf_push(buf, indent, "Hostname: %s\n", hostname);
2105 }
2106
free_tlv_dynamic_hostname(char * hostname)2107 static void free_tlv_dynamic_hostname(char *hostname)
2108 {
2109 XFREE(MTYPE_ISIS_TLV, hostname);
2110 }
2111
pack_tlv_dynamic_hostname(const char * hostname,struct stream * s)2112 static int pack_tlv_dynamic_hostname(const char *hostname, struct stream *s)
2113 {
2114 if (!hostname)
2115 return 0;
2116
2117 uint8_t name_len = strlen(hostname);
2118
2119 if (STREAM_WRITEABLE(s) < (unsigned)(2 + name_len))
2120 return 1;
2121
2122 stream_putc(s, ISIS_TLV_DYNAMIC_HOSTNAME);
2123 stream_putc(s, name_len);
2124 stream_put(s, hostname, name_len);
2125 return 0;
2126 }
2127
unpack_tlv_dynamic_hostname(enum isis_tlv_context context,uint8_t tlv_type,uint8_t tlv_len,struct stream * s,struct sbuf * log,void * dest,int indent)2128 static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context,
2129 uint8_t tlv_type, uint8_t tlv_len,
2130 struct stream *s, struct sbuf *log,
2131 void *dest, int indent)
2132 {
2133 struct isis_tlvs *tlvs = dest;
2134
2135 sbuf_push(log, indent, "Unpacking Dynamic Hostname TLV...\n");
2136 if (!tlv_len) {
2137 sbuf_push(log, indent, "WARNING: No hostname included\n");
2138 return 0;
2139 }
2140
2141 if (tlvs->hostname) {
2142 sbuf_push(log, indent,
2143 "WARNING: Hostname present multiple times.\n");
2144 stream_forward_getp(s, tlv_len);
2145 return 0;
2146 }
2147
2148 tlvs->hostname = XCALLOC(MTYPE_ISIS_TLV, tlv_len + 1);
2149 stream_get(tlvs->hostname, s, tlv_len);
2150 tlvs->hostname[tlv_len] = '\0';
2151
2152 bool sane = true;
2153 for (uint8_t i = 0; i < tlv_len; i++) {
2154 if ((unsigned char)tlvs->hostname[i] > 127
2155 || !isprint((unsigned char)tlvs->hostname[i])) {
2156 sane = false;
2157 tlvs->hostname[i] = '?';
2158 }
2159 }
2160 if (!sane) {
2161 sbuf_push(
2162 log, indent,
2163 "WARNING: Hostname contained non-printable/non-ascii characters.\n");
2164 }
2165
2166 return 0;
2167 }
2168
2169 /* Functions related to TLV 150 Spine-Leaf-Extension */
2170
copy_tlv_spine_leaf(const struct isis_spine_leaf * spine_leaf)2171 static struct isis_spine_leaf *copy_tlv_spine_leaf(
2172 const struct isis_spine_leaf *spine_leaf)
2173 {
2174 if (!spine_leaf)
2175 return NULL;
2176
2177 struct isis_spine_leaf *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2178 memcpy(rv, spine_leaf, sizeof(*rv));
2179
2180 return rv;
2181 }
2182
format_tlv_spine_leaf(const struct isis_spine_leaf * spine_leaf,struct sbuf * buf,int indent)2183 static void format_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf,
2184 struct sbuf *buf, int indent)
2185 {
2186 if (!spine_leaf)
2187 return;
2188
2189 sbuf_push(buf, indent, "Spine-Leaf-Extension:\n");
2190 if (spine_leaf->has_tier) {
2191 if (spine_leaf->tier == ISIS_TIER_UNDEFINED) {
2192 sbuf_push(buf, indent, " Tier: undefined\n");
2193 } else {
2194 sbuf_push(buf, indent, " Tier: %hhu\n",
2195 spine_leaf->tier);
2196 }
2197 }
2198
2199 sbuf_push(buf, indent, " Flags:%s%s%s\n",
2200 spine_leaf->is_leaf ? " LEAF" : "",
2201 spine_leaf->is_spine ? " SPINE" : "",
2202 spine_leaf->is_backup ? " BACKUP" : "");
2203
2204 }
2205
free_tlv_spine_leaf(struct isis_spine_leaf * spine_leaf)2206 static void free_tlv_spine_leaf(struct isis_spine_leaf *spine_leaf)
2207 {
2208 XFREE(MTYPE_ISIS_TLV, spine_leaf);
2209 }
2210
2211 #define ISIS_SPINE_LEAF_FLAG_TIER 0x08
2212 #define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
2213 #define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
2214 #define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
2215
pack_tlv_spine_leaf(const struct isis_spine_leaf * spine_leaf,struct stream * s)2216 static int pack_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf,
2217 struct stream *s)
2218 {
2219 if (!spine_leaf)
2220 return 0;
2221
2222 uint8_t tlv_len = 2;
2223
2224 if (STREAM_WRITEABLE(s) < (unsigned)(2 + tlv_len))
2225 return 1;
2226
2227 stream_putc(s, ISIS_TLV_SPINE_LEAF_EXT);
2228 stream_putc(s, tlv_len);
2229
2230 uint16_t spine_leaf_flags = 0;
2231
2232 if (spine_leaf->has_tier) {
2233 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_TIER;
2234 spine_leaf_flags |= spine_leaf->tier << 12;
2235 }
2236
2237 if (spine_leaf->is_leaf)
2238 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_LEAF;
2239
2240 if (spine_leaf->is_spine)
2241 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_SPINE;
2242
2243 if (spine_leaf->is_backup)
2244 spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_BACKUP;
2245
2246 stream_putw(s, spine_leaf_flags);
2247
2248 return 0;
2249 }
2250
unpack_tlv_spine_leaf(enum isis_tlv_context context,uint8_t tlv_type,uint8_t tlv_len,struct stream * s,struct sbuf * log,void * dest,int indent)2251 static int unpack_tlv_spine_leaf(enum isis_tlv_context context,
2252 uint8_t tlv_type, uint8_t tlv_len,
2253 struct stream *s, struct sbuf *log,
2254 void *dest, int indent)
2255 {
2256 struct isis_tlvs *tlvs = dest;
2257
2258 sbuf_push(log, indent, "Unpacking Spine Leaf Extension TLV...\n");
2259 if (tlv_len < 2) {
2260 sbuf_push(log, indent, "WARNING: Unexpected TLV size\n");
2261 stream_forward_getp(s, tlv_len);
2262 return 0;
2263 }
2264
2265 if (tlvs->spine_leaf) {
2266 sbuf_push(log, indent,
2267 "WARNING: Spine Leaf Extension TLV present multiple times.\n");
2268 stream_forward_getp(s, tlv_len);
2269 return 0;
2270 }
2271
2272 tlvs->spine_leaf = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->spine_leaf));
2273
2274 uint16_t spine_leaf_flags = stream_getw(s);
2275
2276 if (spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_TIER) {
2277 tlvs->spine_leaf->has_tier = true;
2278 tlvs->spine_leaf->tier = spine_leaf_flags >> 12;
2279 }
2280
2281 tlvs->spine_leaf->is_leaf = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_LEAF;
2282 tlvs->spine_leaf->is_spine = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_SPINE;
2283 tlvs->spine_leaf->is_backup = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_BACKUP;
2284
2285 stream_forward_getp(s, tlv_len - 2);
2286 return 0;
2287 }
2288
2289 /* Functions related to TLV 240 P2P Three-Way Adjacency */
2290
isis_threeway_state_name(enum isis_threeway_state state)2291 const char *isis_threeway_state_name(enum isis_threeway_state state)
2292 {
2293 switch (state) {
2294 case ISIS_THREEWAY_DOWN:
2295 return "Down";
2296 case ISIS_THREEWAY_INITIALIZING:
2297 return "Initializing";
2298 case ISIS_THREEWAY_UP:
2299 return "Up";
2300 default:
2301 return "Invalid!";
2302 }
2303 }
2304
copy_tlv_threeway_adj(const struct isis_threeway_adj * threeway_adj)2305 static struct isis_threeway_adj *copy_tlv_threeway_adj(
2306 const struct isis_threeway_adj *threeway_adj)
2307 {
2308 if (!threeway_adj)
2309 return NULL;
2310
2311 struct isis_threeway_adj *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2312 memcpy(rv, threeway_adj, sizeof(*rv));
2313
2314 return rv;
2315 }
2316
format_tlv_threeway_adj(const struct isis_threeway_adj * threeway_adj,struct sbuf * buf,int indent)2317 static void format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj,
2318 struct sbuf *buf, int indent)
2319 {
2320 if (!threeway_adj)
2321 return;
2322
2323 sbuf_push(buf, indent, "P2P Three-Way Adjacency:\n");
2324 sbuf_push(buf, indent, " State: %s (%d)\n",
2325 isis_threeway_state_name(threeway_adj->state),
2326 threeway_adj->state);
2327 sbuf_push(buf, indent, " Extended Local Circuit ID: %u\n",
2328 threeway_adj->local_circuit_id);
2329 if (!threeway_adj->neighbor_set)
2330 return;
2331
2332 sbuf_push(buf, indent, " Neighbor System ID: %s\n",
2333 isis_format_id(threeway_adj->neighbor_id, 6));
2334 sbuf_push(buf, indent, " Neighbor Extended Circuit ID: %u\n",
2335 threeway_adj->neighbor_circuit_id);
2336 }
2337
free_tlv_threeway_adj(struct isis_threeway_adj * threeway_adj)2338 static void free_tlv_threeway_adj(struct isis_threeway_adj *threeway_adj)
2339 {
2340 XFREE(MTYPE_ISIS_TLV, threeway_adj);
2341 }
2342
pack_tlv_threeway_adj(const struct isis_threeway_adj * threeway_adj,struct stream * s)2343 static int pack_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj,
2344 struct stream *s)
2345 {
2346 if (!threeway_adj)
2347 return 0;
2348
2349 uint8_t tlv_len = (threeway_adj->neighbor_set) ? 15 : 5;
2350
2351 if (STREAM_WRITEABLE(s) < (unsigned)(2 + tlv_len))
2352 return 1;
2353
2354 stream_putc(s, ISIS_TLV_THREE_WAY_ADJ);
2355 stream_putc(s, tlv_len);
2356 stream_putc(s, threeway_adj->state);
2357 stream_putl(s, threeway_adj->local_circuit_id);
2358
2359 if (threeway_adj->neighbor_set) {
2360 stream_put(s, threeway_adj->neighbor_id, 6);
2361 stream_putl(s, threeway_adj->neighbor_circuit_id);
2362 }
2363
2364 return 0;
2365 }
2366
unpack_tlv_threeway_adj(enum isis_tlv_context context,uint8_t tlv_type,uint8_t tlv_len,struct stream * s,struct sbuf * log,void * dest,int indent)2367 static int unpack_tlv_threeway_adj(enum isis_tlv_context context,
2368 uint8_t tlv_type, uint8_t tlv_len,
2369 struct stream *s, struct sbuf *log,
2370 void *dest, int indent)
2371 {
2372 struct isis_tlvs *tlvs = dest;
2373
2374 sbuf_push(log, indent, "Unpacking P2P Three-Way Adjacency TLV...\n");
2375 if (tlv_len != 5 && tlv_len != 15) {
2376 sbuf_push(log, indent, "WARNING: Unexpected TLV size\n");
2377 stream_forward_getp(s, tlv_len);
2378 return 0;
2379 }
2380
2381 if (tlvs->threeway_adj) {
2382 sbuf_push(log, indent,
2383 "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
2384 stream_forward_getp(s, tlv_len);
2385 return 0;
2386 }
2387
2388 tlvs->threeway_adj = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->threeway_adj));
2389
2390 tlvs->threeway_adj->state = stream_getc(s);
2391 tlvs->threeway_adj->local_circuit_id = stream_getl(s);
2392
2393 if (tlv_len == 15) {
2394 tlvs->threeway_adj->neighbor_set = true;
2395 stream_get(tlvs->threeway_adj->neighbor_id, s, 6);
2396 tlvs->threeway_adj->neighbor_circuit_id = stream_getl(s);
2397 }
2398
2399 return 0;
2400 }
2401
2402 /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
copy_item_ipv6_reach(struct isis_item * i)2403 static struct isis_item *copy_item_ipv6_reach(struct isis_item *i)
2404 {
2405 struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
2406 struct isis_ipv6_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2407
2408 rv->metric = r->metric;
2409 rv->down = r->down;
2410 rv->external = r->external;
2411 rv->prefix = r->prefix;
2412 rv->subtlvs = copy_subtlvs(r->subtlvs);
2413
2414 return (struct isis_item *)rv;
2415 }
2416
format_item_ipv6_reach(uint16_t mtid,struct isis_item * i,struct sbuf * buf,int indent)2417 static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i,
2418 struct sbuf *buf, int indent)
2419 {
2420 struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
2421 char prefixbuf[PREFIX2STR_BUFFER];
2422
2423 sbuf_push(buf, indent, "%sIPv6 Reachability: %s (Metric: %u)%s%s",
2424 (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "MT ",
2425 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)),
2426 r->metric,
2427 r->down ? " Down" : "",
2428 r->external ? " External" : "");
2429 if (mtid != ISIS_MT_IPV4_UNICAST)
2430 sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
2431 sbuf_push(buf, 0, "\n");
2432
2433 if (r->subtlvs) {
2434 sbuf_push(buf, indent, " Subtlvs:\n");
2435 format_subtlvs(r->subtlvs, buf, indent + 4);
2436 }
2437 }
2438
free_item_ipv6_reach(struct isis_item * i)2439 static void free_item_ipv6_reach(struct isis_item *i)
2440 {
2441 struct isis_ipv6_reach *item = (struct isis_ipv6_reach *)i;
2442
2443 isis_free_subtlvs(item->subtlvs);
2444 XFREE(MTYPE_ISIS_TLV, item);
2445 }
2446
pack_item_ipv6_reach(struct isis_item * i,struct stream * s)2447 static int pack_item_ipv6_reach(struct isis_item *i, struct stream *s)
2448 {
2449 struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
2450 uint8_t control;
2451
2452 if (STREAM_WRITEABLE(s) < 6)
2453 return 1;
2454 stream_putl(s, r->metric);
2455
2456 control = r->down ? ISIS_IPV6_REACH_DOWN : 0;
2457 control |= r->external ? ISIS_IPV6_REACH_EXTERNAL : 0;
2458 control |= r->subtlvs ? ISIS_IPV6_REACH_SUBTLV : 0;
2459
2460 stream_putc(s, control);
2461 stream_putc(s, r->prefix.prefixlen);
2462
2463 if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen))
2464 return 1;
2465 stream_put(s, &r->prefix.prefix.s6_addr, PSIZE(r->prefix.prefixlen));
2466
2467 if (r->subtlvs)
2468 return pack_subtlvs(r->subtlvs, s);
2469
2470 return 0;
2471 }
2472
unpack_item_ipv6_reach(uint16_t mtid,uint8_t len,struct stream * s,struct sbuf * log,void * dest,int indent)2473 static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s,
2474 struct sbuf *log, void *dest, int indent)
2475 {
2476 struct isis_tlvs *tlvs = dest;
2477 struct isis_ipv6_reach *rv = NULL;
2478 size_t consume;
2479 uint8_t control, subtlv_len;
2480 struct isis_item_list *items;
2481
2482 if (mtid == ISIS_MT_IPV4_UNICAST) {
2483 items = &tlvs->ipv6_reach;
2484 } else {
2485 items = isis_get_mt_items(&tlvs->mt_ipv6_reach, mtid);
2486 }
2487
2488 sbuf_push(log, indent, "Unpacking %sIPv6 reachability...\n",
2489 (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "mt ");
2490 consume = 6;
2491 if (len < consume) {
2492 sbuf_push(log, indent,
2493 "Not enough data left. (expected 6 or more bytes, got %hhu)\n",
2494 len);
2495 goto out;
2496 }
2497
2498 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2499
2500 rv->metric = stream_getl(s);
2501 control = stream_getc(s);
2502 rv->down = (control & ISIS_IPV6_REACH_DOWN);
2503 rv->external = (control & ISIS_IPV6_REACH_EXTERNAL);
2504
2505 rv->prefix.family = AF_INET6;
2506 rv->prefix.prefixlen = stream_getc(s);
2507 if (rv->prefix.prefixlen > 128) {
2508 sbuf_push(log, indent, "Prefixlen %u is implausible for IPv6\n",
2509 rv->prefix.prefixlen);
2510 goto out;
2511 }
2512
2513 consume += PSIZE(rv->prefix.prefixlen);
2514 if (len < consume) {
2515 sbuf_push(log, indent,
2516 "Expected %u bytes of prefix, but only %u bytes available.\n",
2517 PSIZE(rv->prefix.prefixlen), len - 6);
2518 goto out;
2519 }
2520 stream_get(&rv->prefix.prefix.s6_addr, s, PSIZE(rv->prefix.prefixlen));
2521 struct in6_addr orig_prefix = rv->prefix.prefix;
2522
2523 apply_mask_ipv6(&rv->prefix);
2524 if (memcmp(&orig_prefix, &rv->prefix.prefix, sizeof(orig_prefix)))
2525 sbuf_push(log, indent + 2,
2526 "WARNING: Prefix had hostbits set.\n");
2527 format_item_ipv6_reach(mtid, (struct isis_item *)rv, log, indent + 2);
2528
2529 if (control & ISIS_IPV6_REACH_SUBTLV) {
2530 consume += 1;
2531 if (len < consume) {
2532 sbuf_push(log, indent,
2533 "Expected 1 byte of subtlv len, but no more data persent.\n");
2534 goto out;
2535 }
2536 subtlv_len = stream_getc(s);
2537
2538 if (!subtlv_len) {
2539 sbuf_push(log, indent + 2,
2540 " WARNING: subtlv bit set, but there are no subtlvs.\n");
2541 }
2542 consume += subtlv_len;
2543 if (len < consume) {
2544 sbuf_push(log, indent,
2545 "Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
2546 subtlv_len,
2547 len - 6 - PSIZE(rv->prefix.prefixlen));
2548 goto out;
2549 }
2550
2551 rv->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH);
2552 bool unpacked_known_tlvs = false;
2553
2554 if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH, subtlv_len, s,
2555 log, rv->subtlvs, indent + 4, &unpacked_known_tlvs)) {
2556 goto out;
2557 }
2558 if (!unpacked_known_tlvs) {
2559 isis_free_subtlvs(rv->subtlvs);
2560 rv->subtlvs = NULL;
2561 }
2562 }
2563
2564 append_item(items, (struct isis_item *)rv);
2565 return 0;
2566 out:
2567 if (rv)
2568 free_item_ipv6_reach((struct isis_item *)rv);
2569 return 1;
2570 }
2571
2572 /* Functions related to TLV 242 Router Capability as per RFC7981 */
copy_tlv_router_cap(const struct isis_router_cap * router_cap)2573 static struct isis_router_cap *copy_tlv_router_cap(
2574 const struct isis_router_cap *router_cap)
2575 {
2576 struct isis_router_cap *rv;
2577
2578 if (!router_cap)
2579 return NULL;
2580
2581 rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2582
2583 memcpy(rv, router_cap, sizeof(*rv));
2584
2585 return rv;
2586 }
2587
format_tlv_router_cap(const struct isis_router_cap * router_cap,struct sbuf * buf,int indent)2588 static void format_tlv_router_cap(const struct isis_router_cap *router_cap,
2589 struct sbuf *buf, int indent)
2590 {
2591 char addrbuf[INET_ADDRSTRLEN];
2592
2593 if (!router_cap)
2594 return;
2595
2596 /* Router ID and Flags */
2597 inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf));
2598 sbuf_push(buf, indent, "Router Capability:");
2599 sbuf_push(buf, indent, " %s , D:%c, S:%c\n", addrbuf,
2600 router_cap->flags & ISIS_ROUTER_CAP_FLAG_D ? '1' : '0',
2601 router_cap->flags & ISIS_ROUTER_CAP_FLAG_S ? '1' : '0');
2602
2603 /* Segment Routing Global Block as per RFC8667 section #3.1 */
2604 if (router_cap->srgb.range_size != 0)
2605 sbuf_push(
2606 buf, indent,
2607 " Segment Routing: I:%s V:%s, Global Block Base: %u Range: %u\n",
2608 IS_SR_IPV4(router_cap->srgb) ? "1" : "0",
2609 IS_SR_IPV6(router_cap->srgb) ? "1" : "0",
2610 router_cap->srgb.lower_bound,
2611 router_cap->srgb.range_size);
2612
2613 /* Segment Routing Local Block as per RFC8667 section #3.3 */
2614 if (router_cap->srlb.range_size != 0)
2615 sbuf_push(buf, indent, " SR Local Block Base: %u Range: %u\n",
2616 router_cap->srlb.lower_bound,
2617 router_cap->srlb.range_size);
2618
2619 /* Segment Routing Algorithms as per RFC8667 section #3.2 */
2620 if (router_cap->algo[0] != SR_ALGORITHM_UNSET) {
2621 sbuf_push(buf, indent, " SR Algorithm:\n");
2622 for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
2623 if (router_cap->algo[i] != SR_ALGORITHM_UNSET)
2624 sbuf_push(buf, indent, " %u: %s\n", i,
2625 router_cap->algo[i] == 0
2626 ? "SPF"
2627 : "Strict SPF");
2628 }
2629
2630 /* Segment Routing Node MSD as per RFC8491 section #2 */
2631 if (router_cap->msd != 0)
2632 sbuf_push(buf, indent, " Node Maximum SID Depth: %u\n",
2633 router_cap->msd);
2634 }
2635
free_tlv_router_cap(struct isis_router_cap * router_cap)2636 static void free_tlv_router_cap(struct isis_router_cap *router_cap)
2637 {
2638 XFREE(MTYPE_ISIS_TLV, router_cap);
2639 }
2640
pack_tlv_router_cap(const struct isis_router_cap * router_cap,struct stream * s)2641 static int pack_tlv_router_cap(const struct isis_router_cap *router_cap,
2642 struct stream *s)
2643 {
2644 size_t tlv_len = ISIS_ROUTER_CAP_SIZE;
2645 size_t len_pos;
2646 uint8_t nb_algo;
2647
2648 if (!router_cap)
2649 return 0;
2650
2651 /* Compute Maximum TLV size */
2652 tlv_len += ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
2653 + ISIS_SUBTLV_HDR_SIZE
2654 + ISIS_SUBTLV_ALGORITHM_SIZE
2655 + ISIS_SUBTLV_NODE_MSD_SIZE;
2656
2657 if (STREAM_WRITEABLE(s) < (unsigned int)(2 + tlv_len))
2658 return 1;
2659
2660 /* Add Router Capability TLV 242 with Router ID and Flags */
2661 stream_putc(s, ISIS_TLV_ROUTER_CAPABILITY);
2662 /* Real length will be adjusted later */
2663 len_pos = stream_get_endp(s);
2664 stream_putc(s, tlv_len);
2665 stream_put_ipv4(s, router_cap->router_id.s_addr);
2666 stream_putc(s, router_cap->flags);
2667
2668 /* Add SRGB if set as per RFC8667 section #3.1 */
2669 if ((router_cap->srgb.range_size != 0)
2670 && (router_cap->srgb.lower_bound != 0)) {
2671 stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE);
2672 stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE);
2673 stream_putc(s, router_cap->srgb.flags);
2674 stream_put3(s, router_cap->srgb.range_size);
2675 stream_putc(s, ISIS_SUBTLV_SID_LABEL);
2676 stream_putc(s, ISIS_SUBTLV_SID_LABEL_SIZE);
2677 stream_put3(s, router_cap->srgb.lower_bound);
2678
2679 /* Then SR Algorithm if set as per RFC8667 section #3.2 */
2680 for (nb_algo = 0; nb_algo < SR_ALGORITHM_COUNT; nb_algo++)
2681 if (router_cap->algo[nb_algo] == SR_ALGORITHM_UNSET)
2682 break;
2683 if (nb_algo > 0) {
2684 stream_putc(s, ISIS_SUBTLV_ALGORITHM);
2685 stream_putc(s, nb_algo);
2686 for (int i = 0; i < nb_algo; i++)
2687 stream_putc(s, router_cap->algo[i]);
2688 }
2689
2690 /* Local Block if defined as per RFC8667 section #3.3 */
2691 if ((router_cap->srlb.range_size != 0)
2692 && (router_cap->srlb.lower_bound != 0)) {
2693 stream_putc(s, ISIS_SUBTLV_SRLB);
2694 stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE);
2695 /* No Flags are defined for SRLB */
2696 stream_putc(s, 0);
2697 stream_put3(s, router_cap->srlb.range_size);
2698 stream_putc(s, ISIS_SUBTLV_SID_LABEL);
2699 stream_putc(s, ISIS_SUBTLV_SID_LABEL_SIZE);
2700 stream_put3(s, router_cap->srlb.lower_bound);
2701 }
2702
2703 /* And finish with MSD if set as per RFC8491 section #2 */
2704 if (router_cap->msd != 0) {
2705 stream_putc(s, ISIS_SUBTLV_NODE_MSD);
2706 stream_putc(s, ISIS_SUBTLV_NODE_MSD_SIZE);
2707 stream_putc(s, MSD_TYPE_BASE_MPLS_IMPOSITION);
2708 stream_putc(s, router_cap->msd);
2709 }
2710 }
2711
2712 /* Adjust TLV length which depends on subTLVs presence */
2713 tlv_len = stream_get_endp(s) - len_pos - 1;
2714 stream_putc_at(s, len_pos, tlv_len);
2715
2716 return 0;
2717 }
2718
unpack_tlv_router_cap(enum isis_tlv_context context,uint8_t tlv_type,uint8_t tlv_len,struct stream * s,struct sbuf * log,void * dest,int indent)2719 static int unpack_tlv_router_cap(enum isis_tlv_context context,
2720 uint8_t tlv_type, uint8_t tlv_len,
2721 struct stream *s, struct sbuf *log,
2722 void *dest, int indent)
2723 {
2724 struct isis_tlvs *tlvs = dest;
2725 struct isis_router_cap *rcap;
2726 uint8_t type;
2727 uint8_t length;
2728 uint8_t subtlv_len;
2729 uint8_t size;
2730
2731 sbuf_push(log, indent, "Unpacking Router Capability TLV...\n");
2732 if (tlv_len < ISIS_ROUTER_CAP_SIZE) {
2733 sbuf_push(log, indent, "WARNING: Unexpected TLV size\n");
2734 stream_forward_getp(s, tlv_len);
2735 return 0;
2736 }
2737
2738 if (tlvs->router_cap) {
2739 sbuf_push(log, indent,
2740 "WARNING: Router Capability TLV present multiple times.\n");
2741 stream_forward_getp(s, tlv_len);
2742 return 0;
2743 }
2744
2745 /* Allocate router cap structure and initialize SR Algorithms */
2746 rcap = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct isis_router_cap));
2747 for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
2748 rcap->algo[i] = SR_ALGORITHM_UNSET;
2749
2750 /* Get Router ID and Flags */
2751 rcap->router_id.s_addr = stream_get_ipv4(s);
2752 rcap->flags = stream_getc(s);
2753
2754 /* Parse remaining part of the TLV if present */
2755 subtlv_len = tlv_len - ISIS_ROUTER_CAP_SIZE;
2756 while (subtlv_len > 2) {
2757 uint8_t msd_type;
2758
2759 type = stream_getc(s);
2760 length = stream_getc(s);
2761 switch (type) {
2762 case ISIS_SUBTLV_SID_LABEL_RANGE:
2763 /* Check that SRGB is correctly formated */
2764 if (length < SUBTLV_RANGE_LABEL_SIZE
2765 || length > SUBTLV_RANGE_INDEX_SIZE) {
2766 stream_forward_getp(s, length);
2767 continue;
2768 }
2769 /* Only one SRGB is supported. Skip subsequent one */
2770 if (rcap->srgb.range_size != 0) {
2771 stream_forward_getp(s, length);
2772 continue;
2773 }
2774 rcap->srgb.flags = stream_getc(s);
2775 rcap->srgb.range_size = stream_get3(s);
2776 /* Skip Type and get Length of SID Label */
2777 stream_getc(s);
2778 size = stream_getc(s);
2779 if (size == ISIS_SUBTLV_SID_LABEL_SIZE)
2780 rcap->srgb.lower_bound = stream_get3(s);
2781 else
2782 rcap->srgb.lower_bound = stream_getl(s);
2783
2784 /* SRGB sanity checks. */
2785 if (rcap->srgb.range_size == 0
2786 || (rcap->srgb.lower_bound <= MPLS_LABEL_RESERVED_MAX)
2787 || ((rcap->srgb.lower_bound + rcap->srgb.range_size - 1)
2788 > MPLS_LABEL_UNRESERVED_MAX)) {
2789 sbuf_push(log, indent, "Invalid label range. Reset SRGB\n");
2790 rcap->srgb.lower_bound = 0;
2791 rcap->srgb.range_size = 0;
2792 }
2793 /* Only one range is supported. Skip subsequent one */
2794 size = length - (size + SUBTLV_SR_BLOCK_SIZE);
2795 if (size > 0)
2796 stream_forward_getp(s, length);
2797 break;
2798 case ISIS_SUBTLV_ALGORITHM:
2799 /* Only 2 algorithms are supported: SPF & Strict SPF */
2800 stream_get(&rcap->algo, s,
2801 length > SR_ALGORITHM_COUNT
2802 ? SR_ALGORITHM_COUNT
2803 : length);
2804 if (length > SR_ALGORITHM_COUNT)
2805 stream_forward_getp(
2806 s, length - SR_ALGORITHM_COUNT);
2807 break;
2808 case ISIS_SUBTLV_SRLB:
2809 /* Check that SRLB is correctly formated */
2810 if (length < SUBTLV_RANGE_LABEL_SIZE
2811 || length > SUBTLV_RANGE_INDEX_SIZE) {
2812 stream_forward_getp(s, length);
2813 continue;
2814 }
2815 /* RFC 8667 section #3.3: Only one SRLB is authorized */
2816 if (rcap->srlb.range_size != 0) {
2817 stream_forward_getp(s, length);
2818 continue;
2819 }
2820 /* Ignore Flags which are not defined */
2821 stream_getc(s);
2822 rcap->srlb.range_size = stream_get3(s);
2823 /* Skip Type and get Length of SID Label */
2824 stream_getc(s);
2825 size = stream_getc(s);
2826 if (size == ISIS_SUBTLV_SID_LABEL_SIZE)
2827 rcap->srlb.lower_bound = stream_get3(s);
2828 else
2829 rcap->srlb.lower_bound = stream_getl(s);
2830
2831 /* SRLB sanity checks. */
2832 if (rcap->srlb.range_size == 0
2833 || (rcap->srlb.lower_bound <= MPLS_LABEL_RESERVED_MAX)
2834 || ((rcap->srlb.lower_bound + rcap->srlb.range_size - 1)
2835 > MPLS_LABEL_UNRESERVED_MAX)) {
2836 sbuf_push(log, indent, "Invalid label range. Reset SRLB\n");
2837 rcap->srlb.lower_bound = 0;
2838 rcap->srlb.range_size = 0;
2839 }
2840 /* Only one range is supported. Skip subsequent one */
2841 size = length - (size + SUBTLV_SR_BLOCK_SIZE);
2842 if (size > 0)
2843 stream_forward_getp(s, length);
2844 break;
2845 case ISIS_SUBTLV_NODE_MSD:
2846 /* Check that MSD is correctly formated */
2847 if (length < MSD_TLV_SIZE) {
2848 stream_forward_getp(s, length);
2849 continue;
2850 }
2851 msd_type = stream_getc(s);
2852 rcap->msd = stream_getc(s);
2853 /* Only BMI-MSD type has been defined in RFC 8491 */
2854 if (msd_type != MSD_TYPE_BASE_MPLS_IMPOSITION)
2855 rcap->msd = 0;
2856 /* Only one MSD is standardized. Skip others */
2857 if (length > MSD_TLV_SIZE)
2858 stream_forward_getp(s, length - MSD_TLV_SIZE);
2859 break;
2860 default:
2861 stream_forward_getp(s, length);
2862 break;
2863 }
2864 subtlv_len = subtlv_len - length - 2;
2865 }
2866 tlvs->router_cap = rcap;
2867 return 0;
2868 }
2869
2870 /* Functions related to TLV 10 Authentication */
copy_item_auth(struct isis_item * i)2871 static struct isis_item *copy_item_auth(struct isis_item *i)
2872 {
2873 struct isis_auth *auth = (struct isis_auth *)i;
2874 struct isis_auth *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2875
2876 rv->type = auth->type;
2877 rv->length = auth->length;
2878 memcpy(rv->value, auth->value, sizeof(rv->value));
2879 return (struct isis_item *)rv;
2880 }
2881
format_item_auth(uint16_t mtid,struct isis_item * i,struct sbuf * buf,int indent)2882 static void format_item_auth(uint16_t mtid, struct isis_item *i,
2883 struct sbuf *buf, int indent)
2884 {
2885 struct isis_auth *auth = (struct isis_auth *)i;
2886 char obuf[768];
2887
2888 sbuf_push(buf, indent, "Authentication:\n");
2889 switch (auth->type) {
2890 case ISIS_PASSWD_TYPE_CLEARTXT:
2891 zlog_sanitize(obuf, sizeof(obuf), auth->value, auth->length);
2892 sbuf_push(buf, indent, " Password: %s\n", obuf);
2893 break;
2894 case ISIS_PASSWD_TYPE_HMAC_MD5:
2895 for (unsigned int j = 0; j < 16; j++) {
2896 snprintf(obuf + 2 * j, sizeof(obuf) - 2 * j,
2897 "%02hhx", auth->value[j]);
2898 }
2899 sbuf_push(buf, indent, " HMAC-MD5: %s\n", obuf);
2900 break;
2901 default:
2902 sbuf_push(buf, indent, " Unknown (%hhu)\n", auth->type);
2903 break;
2904 }
2905 }
2906
free_item_auth(struct isis_item * i)2907 static void free_item_auth(struct isis_item *i)
2908 {
2909 XFREE(MTYPE_ISIS_TLV, i);
2910 }
2911
pack_item_auth(struct isis_item * i,struct stream * s)2912 static int pack_item_auth(struct isis_item *i, struct stream *s)
2913 {
2914 struct isis_auth *auth = (struct isis_auth *)i;
2915
2916 if (STREAM_WRITEABLE(s) < 1)
2917 return 1;
2918 stream_putc(s, auth->type);
2919
2920 switch (auth->type) {
2921 case ISIS_PASSWD_TYPE_CLEARTXT:
2922 if (STREAM_WRITEABLE(s) < auth->length)
2923 return 1;
2924 stream_put(s, auth->passwd, auth->length);
2925 break;
2926 case ISIS_PASSWD_TYPE_HMAC_MD5:
2927 if (STREAM_WRITEABLE(s) < 16)
2928 return 1;
2929 auth->offset = stream_get_endp(s);
2930 stream_put(s, NULL, 16);
2931 break;
2932 default:
2933 return 1;
2934 }
2935
2936 return 0;
2937 }
2938
unpack_item_auth(uint16_t mtid,uint8_t len,struct stream * s,struct sbuf * log,void * dest,int indent)2939 static int unpack_item_auth(uint16_t mtid, uint8_t len, struct stream *s,
2940 struct sbuf *log, void *dest, int indent)
2941 {
2942 struct isis_tlvs *tlvs = dest;
2943
2944 sbuf_push(log, indent, "Unpack Auth TLV...\n");
2945 if (len < 1) {
2946 sbuf_push(
2947 log, indent,
2948 "Not enough data left.(Expected 1 bytes of auth type, got %hhu)\n",
2949 len);
2950 return 1;
2951 }
2952
2953 struct isis_auth *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2954
2955 rv->type = stream_getc(s);
2956 rv->length = len - 1;
2957
2958 if (rv->type == ISIS_PASSWD_TYPE_HMAC_MD5 && rv->length != 16) {
2959 sbuf_push(
2960 log, indent,
2961 "Unexpected auth length for HMAC-MD5 (expected 16, got %hhu)\n",
2962 rv->length);
2963 XFREE(MTYPE_ISIS_TLV, rv);
2964 return 1;
2965 }
2966
2967 rv->offset = stream_get_getp(s);
2968 stream_get(rv->value, s, rv->length);
2969 format_item_auth(mtid, (struct isis_item *)rv, log, indent + 2);
2970 append_item(&tlvs->isis_auth, (struct isis_item *)rv);
2971 return 0;
2972 }
2973
2974 /* Functions related to TLV 13 Purge Originator */
2975
copy_tlv_purge_originator(struct isis_purge_originator * poi)2976 static struct isis_purge_originator *copy_tlv_purge_originator(
2977 struct isis_purge_originator *poi)
2978 {
2979 if (!poi)
2980 return NULL;
2981
2982 struct isis_purge_originator *rv;
2983
2984 rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
2985 rv->sender_set = poi->sender_set;
2986 memcpy(rv->generator, poi->generator, sizeof(rv->generator));
2987 if (poi->sender_set)
2988 memcpy(rv->sender, poi->sender, sizeof(rv->sender));
2989 return rv;
2990 }
2991
format_tlv_purge_originator(struct isis_purge_originator * poi,struct sbuf * buf,int indent)2992 static void format_tlv_purge_originator(struct isis_purge_originator *poi,
2993 struct sbuf *buf, int indent)
2994 {
2995 if (!poi)
2996 return;
2997
2998 sbuf_push(buf, indent, "Purge Originator Identification:\n");
2999 sbuf_push(buf, indent, " Generator: %s\n",
3000 isis_format_id(poi->generator, sizeof(poi->generator)));
3001 if (poi->sender_set) {
3002 sbuf_push(buf, indent, " Received-From: %s\n",
3003 isis_format_id(poi->sender, sizeof(poi->sender)));
3004 }
3005 }
3006
free_tlv_purge_originator(struct isis_purge_originator * poi)3007 static void free_tlv_purge_originator(struct isis_purge_originator *poi)
3008 {
3009 XFREE(MTYPE_ISIS_TLV, poi);
3010 }
3011
pack_tlv_purge_originator(struct isis_purge_originator * poi,struct stream * s)3012 static int pack_tlv_purge_originator(struct isis_purge_originator *poi,
3013 struct stream *s)
3014 {
3015 if (!poi)
3016 return 0;
3017
3018 uint8_t data_len = 1 + sizeof(poi->generator);
3019
3020 if (poi->sender_set)
3021 data_len += sizeof(poi->sender);
3022
3023 if (STREAM_WRITEABLE(s) < (unsigned)(2 + data_len))
3024 return 1;
3025
3026 stream_putc(s, ISIS_TLV_PURGE_ORIGINATOR);
3027 stream_putc(s, data_len);
3028 stream_putc(s, poi->sender_set ? 2 : 1);
3029 stream_put(s, poi->generator, sizeof(poi->generator));
3030 if (poi->sender_set)
3031 stream_put(s, poi->sender, sizeof(poi->sender));
3032 return 0;
3033 }
3034
unpack_tlv_purge_originator(enum isis_tlv_context context,uint8_t tlv_type,uint8_t tlv_len,struct stream * s,struct sbuf * log,void * dest,int indent)3035 static int unpack_tlv_purge_originator(enum isis_tlv_context context,
3036 uint8_t tlv_type, uint8_t tlv_len,
3037 struct stream *s, struct sbuf *log,
3038 void *dest, int indent)
3039 {
3040 struct isis_tlvs *tlvs = dest;
3041 struct isis_purge_originator poi = {};
3042
3043 sbuf_push(log, indent, "Unpacking Purge Originator Identification TLV...\n");
3044 if (tlv_len < 7) {
3045 sbuf_push(log, indent, "Not enough data left. (Expected at least 7 bytes, got %hhu)\n", tlv_len);
3046 return 1;
3047 }
3048
3049 uint8_t number_of_ids = stream_getc(s);
3050
3051 if (number_of_ids == 1) {
3052 poi.sender_set = false;
3053 } else if (number_of_ids == 2) {
3054 poi.sender_set = true;
3055 } else {
3056 sbuf_push(log, indent, "Got invalid value for number of system IDs: %hhu)\n", number_of_ids);
3057 return 1;
3058 }
3059
3060 if (tlv_len != 1 + 6 * number_of_ids) {
3061 sbuf_push(log, indent, "Incorrect tlv len for number of IDs.\n");
3062 return 1;
3063 }
3064
3065 stream_get(poi.generator, s, sizeof(poi.generator));
3066 if (poi.sender_set)
3067 stream_get(poi.sender, s, sizeof(poi.sender));
3068
3069 if (tlvs->purge_originator) {
3070 sbuf_push(log, indent,
3071 "WARNING: Purge originator present multiple times, ignoring.\n");
3072 return 0;
3073 }
3074
3075 tlvs->purge_originator = copy_tlv_purge_originator(&poi);
3076 return 0;
3077 }
3078
3079
3080 /* Functions relating to item TLVs */
3081
init_item_list(struct isis_item_list * items)3082 static void init_item_list(struct isis_item_list *items)
3083 {
3084 items->head = NULL;
3085 items->tail = &items->head;
3086 items->count = 0;
3087 }
3088
copy_item(enum isis_tlv_context context,enum isis_tlv_type type,struct isis_item * item)3089 static struct isis_item *copy_item(enum isis_tlv_context context,
3090 enum isis_tlv_type type,
3091 struct isis_item *item)
3092 {
3093 const struct tlv_ops *ops = tlv_table[context][type];
3094
3095 if (ops && ops->copy_item)
3096 return ops->copy_item(item);
3097
3098 assert(!"Unknown item tlv type!");
3099 return NULL;
3100 }
3101
copy_items(enum isis_tlv_context context,enum isis_tlv_type type,struct isis_item_list * src,struct isis_item_list * dest)3102 static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type,
3103 struct isis_item_list *src, struct isis_item_list *dest)
3104 {
3105 struct isis_item *item;
3106
3107 init_item_list(dest);
3108
3109 for (item = src->head; item; item = item->next) {
3110 append_item(dest, copy_item(context, type, item));
3111 }
3112 }
3113
format_item(uint16_t mtid,enum isis_tlv_context context,enum isis_tlv_type type,struct isis_item * i,struct sbuf * buf,int indent)3114 static void format_item(uint16_t mtid, enum isis_tlv_context context,
3115 enum isis_tlv_type type, struct isis_item *i,
3116 struct sbuf *buf, int indent)
3117 {
3118 const struct tlv_ops *ops = tlv_table[context][type];
3119
3120 if (ops && ops->format_item) {
3121 ops->format_item(mtid, i, buf, indent);
3122 return;
3123 }
3124
3125 assert(!"Unknown item tlv type!");
3126 }
3127
format_items_(uint16_t mtid,enum isis_tlv_context context,enum isis_tlv_type type,struct isis_item_list * items,struct sbuf * buf,int indent)3128 static void format_items_(uint16_t mtid, enum isis_tlv_context context,
3129 enum isis_tlv_type type, struct isis_item_list *items,
3130 struct sbuf *buf, int indent)
3131 {
3132 struct isis_item *i;
3133
3134 for (i = items->head; i; i = i->next)
3135 format_item(mtid, context, type, i, buf, indent);
3136 }
3137
free_item(enum isis_tlv_context tlv_context,enum isis_tlv_type tlv_type,struct isis_item * item)3138 static void free_item(enum isis_tlv_context tlv_context,
3139 enum isis_tlv_type tlv_type, struct isis_item *item)
3140 {
3141 const struct tlv_ops *ops = tlv_table[tlv_context][tlv_type];
3142
3143 if (ops && ops->free_item) {
3144 ops->free_item(item);
3145 return;
3146 }
3147
3148 assert(!"Unknown item tlv type!");
3149 }
3150
free_items(enum isis_tlv_context context,enum isis_tlv_type type,struct isis_item_list * items)3151 static void free_items(enum isis_tlv_context context, enum isis_tlv_type type,
3152 struct isis_item_list *items)
3153 {
3154 struct isis_item *item, *next_item;
3155
3156 for (item = items->head; item; item = next_item) {
3157 next_item = item->next;
3158 free_item(context, type, item);
3159 }
3160 }
3161
pack_item(enum isis_tlv_context context,enum isis_tlv_type type,struct isis_item * i,struct stream * s,struct isis_tlvs ** fragment_tlvs,const struct pack_order_entry * pe,uint16_t mtid)3162 static int pack_item(enum isis_tlv_context context, enum isis_tlv_type type,
3163 struct isis_item *i, struct stream *s,
3164 struct isis_tlvs **fragment_tlvs,
3165 const struct pack_order_entry *pe, uint16_t mtid)
3166 {
3167 const struct tlv_ops *ops = tlv_table[context][type];
3168
3169 if (ops && ops->pack_item) {
3170 return ops->pack_item(i, s);
3171 }
3172
3173 assert(!"Unknown item tlv type!");
3174 return 1;
3175 }
3176
add_item_to_fragment(struct isis_item * i,const struct pack_order_entry * pe,struct isis_tlvs * fragment_tlvs,uint16_t mtid)3177 static void add_item_to_fragment(struct isis_item *i,
3178 const struct pack_order_entry *pe,
3179 struct isis_tlvs *fragment_tlvs, uint16_t mtid)
3180 {
3181 struct isis_item_list *l;
3182
3183 if (pe->how_to_pack == ISIS_ITEMS) {
3184 l = (struct isis_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack);
3185 } else {
3186 struct isis_mt_item_list *m;
3187 m = (struct isis_mt_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack);
3188 l = isis_get_mt_items(m, mtid);
3189 }
3190
3191 append_item(l, copy_item(pe->context, pe->type, i));
3192 }
3193
pack_items_(uint16_t mtid,enum isis_tlv_context context,enum isis_tlv_type type,struct isis_item_list * items,struct stream * s,struct isis_tlvs ** fragment_tlvs,const struct pack_order_entry * pe,struct isis_tlvs * (* new_fragment)(struct list * l),struct list * new_fragment_arg)3194 static int pack_items_(uint16_t mtid, enum isis_tlv_context context,
3195 enum isis_tlv_type type, struct isis_item_list *items,
3196 struct stream *s, struct isis_tlvs **fragment_tlvs,
3197 const struct pack_order_entry *pe,
3198 struct isis_tlvs *(*new_fragment)(struct list *l),
3199 struct list *new_fragment_arg)
3200 {
3201 size_t len_pos, last_len, len;
3202 struct isis_item *item = NULL;
3203 int rv;
3204
3205 if (!items->head)
3206 return 0;
3207
3208 top:
3209 if (STREAM_WRITEABLE(s) < 2)
3210 goto too_long;
3211
3212 stream_putc(s, type);
3213 len_pos = stream_get_endp(s);
3214 stream_putc(s, 0); /* Put 0 as length for now */
3215
3216 if (context == ISIS_CONTEXT_LSP && IS_COMPAT_MT_TLV(type)
3217 && mtid != ISIS_MT_IPV4_UNICAST) {
3218 if (STREAM_WRITEABLE(s) < 2)
3219 goto too_long;
3220 stream_putw(s, mtid);
3221 }
3222
3223 if (context == ISIS_CONTEXT_LSP && type == ISIS_TLV_OLDSTYLE_REACH) {
3224 if (STREAM_WRITEABLE(s) < 1)
3225 goto too_long;
3226 stream_putc(s, 0); /* Virtual flag is set to 0 */
3227 }
3228
3229 last_len = len = 0;
3230 for (item = item ? item : items->head; item; item = item->next) {
3231 rv = pack_item(context, type, item, s, fragment_tlvs, pe, mtid);
3232 if (rv)
3233 goto too_long;
3234
3235 len = stream_get_endp(s) - len_pos - 1;
3236
3237 /* Multiple auths don't go into one TLV, so always break */
3238 if (context == ISIS_CONTEXT_LSP && type == ISIS_TLV_AUTH) {
3239 item = item->next;
3240 break;
3241 }
3242
3243 /* Multiple prefix-sids don't go into one TLV, so always break */
3244 if (type == ISIS_SUBTLV_PREFIX_SID
3245 && (context == ISIS_CONTEXT_SUBTLV_IP_REACH
3246 || context == ISIS_CONTEXT_SUBTLV_IPV6_REACH)) {
3247 item = item->next;
3248 break;
3249 }
3250
3251 if (len > 255) {
3252 if (!last_len) /* strange, not a single item fit */
3253 return 1;
3254 /* drop last tlv, otherwise, its too long */
3255 stream_set_endp(s, len_pos + 1 + last_len);
3256 len = last_len;
3257 break;
3258 }
3259
3260 if (fragment_tlvs)
3261 add_item_to_fragment(item, pe, *fragment_tlvs, mtid);
3262
3263 last_len = len;
3264 }
3265
3266 stream_putc_at(s, len_pos, len);
3267 if (item)
3268 goto top;
3269
3270 return 0;
3271 too_long:
3272 if (!fragment_tlvs)
3273 return 1;
3274 stream_reset(s);
3275 *fragment_tlvs = new_fragment(new_fragment_arg);
3276 goto top;
3277 }
3278 #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
3279
append_item(struct isis_item_list * dest,struct isis_item * item)3280 static void append_item(struct isis_item_list *dest, struct isis_item *item)
3281 {
3282 *dest->tail = item;
3283 dest->tail = &(*dest->tail)->next;
3284 dest->count++;
3285 }
3286
delete_item(struct isis_item_list * dest,struct isis_item * del)3287 static void delete_item(struct isis_item_list *dest, struct isis_item *del)
3288 {
3289 struct isis_item *item, *prev = NULL, *next;
3290
3291 /* Sanity Check */
3292 if ((dest == NULL) || (del == NULL))
3293 return;
3294
3295 /*
3296 * TODO: delete is tricky because "dest" is a singly linked list.
3297 * We need to switch a doubly linked list.
3298 */
3299 for (item = dest->head; item; item = next) {
3300 if (item->next == del) {
3301 prev = item;
3302 break;
3303 }
3304 next = item->next;
3305 }
3306 if (prev)
3307 prev->next = del->next;
3308 if (dest->head == del)
3309 dest->head = del->next;
3310 if ((struct isis_item *)dest->tail == del) {
3311 *dest->tail = prev;
3312 if (prev)
3313 dest->tail = &(*dest->tail)->next;
3314 else
3315 dest->tail = &dest->head;
3316 }
3317 dest->count--;
3318 }
3319
last_item(struct isis_item_list * list)3320 static struct isis_item *last_item(struct isis_item_list *list)
3321 {
3322 return container_of(list->tail, struct isis_item, next);
3323 }
3324
unpack_item(uint16_t mtid,enum isis_tlv_context context,uint8_t tlv_type,uint8_t len,struct stream * s,struct sbuf * log,void * dest,int indent)3325 static int unpack_item(uint16_t mtid, enum isis_tlv_context context,
3326 uint8_t tlv_type, uint8_t len, struct stream *s,
3327 struct sbuf *log, void *dest, int indent)
3328 {
3329 const struct tlv_ops *ops = tlv_table[context][tlv_type];
3330
3331 if (ops && ops->unpack_item)
3332 return ops->unpack_item(mtid, len, s, log, dest, indent);
3333
3334 assert(!"Unknown item tlv type!");
3335 sbuf_push(log, indent, "Unknown item tlv type!\n");
3336 return 1;
3337 }
3338
unpack_tlv_with_items(enum isis_tlv_context context,uint8_t tlv_type,uint8_t tlv_len,struct stream * s,struct sbuf * log,void * dest,int indent)3339 static int unpack_tlv_with_items(enum isis_tlv_context context,
3340 uint8_t tlv_type, uint8_t tlv_len,
3341 struct stream *s, struct sbuf *log, void *dest,
3342 int indent)
3343 {
3344 size_t tlv_start;
3345 size_t tlv_pos;
3346 int rv;
3347 uint16_t mtid;
3348
3349 tlv_start = stream_get_getp(s);
3350 tlv_pos = 0;
3351
3352 if (context == ISIS_CONTEXT_LSP && IS_COMPAT_MT_TLV(tlv_type)) {
3353 if (tlv_len < 2) {
3354 sbuf_push(log, indent,
3355 "TLV is too short to contain MTID\n");
3356 return 1;
3357 }
3358 mtid = stream_getw(s) & ISIS_MT_MASK;
3359 tlv_pos += 2;
3360 sbuf_push(log, indent, "Unpacking as MT %s item TLV...\n",
3361 isis_mtid2str(mtid));
3362 } else {
3363 sbuf_push(log, indent, "Unpacking as item TLV...\n");
3364 mtid = ISIS_MT_IPV4_UNICAST;
3365 }
3366
3367 if (context == ISIS_CONTEXT_LSP
3368 && tlv_type == ISIS_TLV_OLDSTYLE_REACH) {
3369 if (tlv_len - tlv_pos < 1) {
3370 sbuf_push(log, indent,
3371 "TLV is too short for old style reach\n");
3372 return 1;
3373 }
3374 stream_forward_getp(s, 1);
3375 tlv_pos += 1;
3376 }
3377
3378 if (context == ISIS_CONTEXT_LSP
3379 && tlv_type == ISIS_TLV_OLDSTYLE_IP_REACH) {
3380 struct isis_tlvs *tlvs = dest;
3381 dest = &tlvs->oldstyle_ip_reach;
3382 } else if (context == ISIS_CONTEXT_LSP
3383 && tlv_type == ISIS_TLV_OLDSTYLE_IP_REACH_EXT) {
3384 struct isis_tlvs *tlvs = dest;
3385 dest = &tlvs->oldstyle_ip_reach_ext;
3386 }
3387
3388 if (context == ISIS_CONTEXT_LSP
3389 && tlv_type == ISIS_TLV_MT_ROUTER_INFO) {
3390 struct isis_tlvs *tlvs = dest;
3391 tlvs->mt_router_info_empty = (tlv_pos >= (size_t)tlv_len);
3392 }
3393
3394 while (tlv_pos < (size_t)tlv_len) {
3395 rv = unpack_item(mtid, context, tlv_type, tlv_len - tlv_pos, s,
3396 log, dest, indent + 2);
3397 if (rv)
3398 return rv;
3399
3400 tlv_pos = stream_get_getp(s) - tlv_start;
3401 }
3402
3403 return 0;
3404 }
3405
3406 /* Functions to manipulate mt_item_lists */
3407
isis_mt_item_list_cmp(const struct isis_item_list * a,const struct isis_item_list * b)3408 static int isis_mt_item_list_cmp(const struct isis_item_list *a,
3409 const struct isis_item_list *b)
3410 {
3411 if (a->mtid < b->mtid)
3412 return -1;
3413 if (a->mtid > b->mtid)
3414 return 1;
3415 return 0;
3416 }
3417
3418 RB_PROTOTYPE(isis_mt_item_list, isis_item_list, mt_tree, isis_mt_item_list_cmp);
3419 RB_GENERATE(isis_mt_item_list, isis_item_list, mt_tree, isis_mt_item_list_cmp);
3420
isis_get_mt_items(struct isis_mt_item_list * m,uint16_t mtid)3421 struct isis_item_list *isis_get_mt_items(struct isis_mt_item_list *m,
3422 uint16_t mtid)
3423 {
3424 struct isis_item_list *rv;
3425
3426 rv = isis_lookup_mt_items(m, mtid);
3427 if (!rv) {
3428 rv = XCALLOC(MTYPE_ISIS_MT_ITEM_LIST, sizeof(*rv));
3429 init_item_list(rv);
3430 rv->mtid = mtid;
3431 RB_INSERT(isis_mt_item_list, m, rv);
3432 }
3433
3434 return rv;
3435 }
3436
isis_lookup_mt_items(struct isis_mt_item_list * m,uint16_t mtid)3437 struct isis_item_list *isis_lookup_mt_items(struct isis_mt_item_list *m,
3438 uint16_t mtid)
3439 {
3440 struct isis_item_list key = {.mtid = mtid};
3441
3442 return RB_FIND(isis_mt_item_list, m, &key);
3443 }
3444
free_mt_items(enum isis_tlv_context context,enum isis_tlv_type type,struct isis_mt_item_list * m)3445 static void free_mt_items(enum isis_tlv_context context,
3446 enum isis_tlv_type type, struct isis_mt_item_list *m)
3447 {
3448 struct isis_item_list *n, *nnext;
3449
3450 RB_FOREACH_SAFE (n, isis_mt_item_list, m, nnext) {
3451 free_items(context, type, n);
3452 RB_REMOVE(isis_mt_item_list, m, n);
3453 XFREE(MTYPE_ISIS_MT_ITEM_LIST, n);
3454 }
3455 }
3456
format_mt_items(enum isis_tlv_context context,enum isis_tlv_type type,struct isis_mt_item_list * m,struct sbuf * buf,int indent)3457 static void format_mt_items(enum isis_tlv_context context,
3458 enum isis_tlv_type type,
3459 struct isis_mt_item_list *m, struct sbuf *buf,
3460 int indent)
3461 {
3462 struct isis_item_list *n;
3463
3464 RB_FOREACH (n, isis_mt_item_list, m) {
3465 format_items_(n->mtid, context, type, n, buf, indent);
3466 }
3467 }
3468
pack_mt_items(enum isis_tlv_context context,enum isis_tlv_type type,struct isis_mt_item_list * m,struct stream * s,struct isis_tlvs ** fragment_tlvs,const struct pack_order_entry * pe,struct isis_tlvs * (* new_fragment)(struct list * l),struct list * new_fragment_arg)3469 static int pack_mt_items(enum isis_tlv_context context, enum isis_tlv_type type,
3470 struct isis_mt_item_list *m, struct stream *s,
3471 struct isis_tlvs **fragment_tlvs,
3472 const struct pack_order_entry *pe,
3473 struct isis_tlvs *(*new_fragment)(struct list *l),
3474 struct list *new_fragment_arg)
3475 {
3476 struct isis_item_list *n;
3477
3478 RB_FOREACH (n, isis_mt_item_list, m) {
3479 int rv;
3480
3481 rv = pack_items_(n->mtid, context, type, n, s, fragment_tlvs,
3482 pe, new_fragment, new_fragment_arg);
3483 if (rv)
3484 return rv;
3485 }
3486
3487 return 0;
3488 }
3489
copy_mt_items(enum isis_tlv_context context,enum isis_tlv_type type,struct isis_mt_item_list * src,struct isis_mt_item_list * dest)3490 static void copy_mt_items(enum isis_tlv_context context,
3491 enum isis_tlv_type type,
3492 struct isis_mt_item_list *src,
3493 struct isis_mt_item_list *dest)
3494 {
3495 struct isis_item_list *n;
3496
3497 RB_INIT(isis_mt_item_list, dest);
3498
3499 RB_FOREACH (n, isis_mt_item_list, src) {
3500 copy_items(context, type, n, isis_get_mt_items(dest, n->mtid));
3501 }
3502 }
3503
3504 /* Functions related to tlvs in general */
3505
isis_alloc_tlvs(void)3506 struct isis_tlvs *isis_alloc_tlvs(void)
3507 {
3508 struct isis_tlvs *result;
3509
3510 result = XCALLOC(MTYPE_ISIS_TLV, sizeof(*result));
3511
3512 init_item_list(&result->isis_auth);
3513 init_item_list(&result->area_addresses);
3514 init_item_list(&result->mt_router_info);
3515 init_item_list(&result->oldstyle_reach);
3516 init_item_list(&result->lan_neighbor);
3517 init_item_list(&result->lsp_entries);
3518 init_item_list(&result->extended_reach);
3519 RB_INIT(isis_mt_item_list, &result->mt_reach);
3520 init_item_list(&result->oldstyle_ip_reach);
3521 init_item_list(&result->oldstyle_ip_reach_ext);
3522 init_item_list(&result->ipv4_address);
3523 init_item_list(&result->ipv6_address);
3524 init_item_list(&result->extended_ip_reach);
3525 RB_INIT(isis_mt_item_list, &result->mt_ip_reach);
3526 init_item_list(&result->ipv6_reach);
3527 RB_INIT(isis_mt_item_list, &result->mt_ipv6_reach);
3528
3529 return result;
3530 }
3531
isis_copy_tlvs(struct isis_tlvs * tlvs)3532 struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs)
3533 {
3534 struct isis_tlvs *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
3535
3536 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth,
3537 &rv->isis_auth);
3538
3539 rv->purge_originator =
3540 copy_tlv_purge_originator(tlvs->purge_originator);
3541
3542 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
3543 &tlvs->area_addresses, &rv->area_addresses);
3544
3545 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
3546 &tlvs->mt_router_info, &rv->mt_router_info);
3547
3548 rv->mt_router_info_empty = tlvs->mt_router_info_empty;
3549
3550 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
3551 &tlvs->oldstyle_reach, &rv->oldstyle_reach);
3552
3553 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
3554 &tlvs->lan_neighbor, &rv->lan_neighbor);
3555
3556 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries,
3557 &rv->lsp_entries);
3558
3559 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
3560 &tlvs->extended_reach, &rv->extended_reach);
3561
3562 copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach,
3563 &rv->mt_reach);
3564
3565 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
3566 &tlvs->oldstyle_ip_reach, &rv->oldstyle_ip_reach);
3567
3568 copy_tlv_protocols_supported(&tlvs->protocols_supported,
3569 &rv->protocols_supported);
3570
3571 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
3572 &tlvs->oldstyle_ip_reach_ext, &rv->oldstyle_ip_reach_ext);
3573
3574 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS, &tlvs->ipv4_address,
3575 &rv->ipv4_address);
3576
3577 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS, &tlvs->ipv6_address,
3578 &rv->ipv6_address);
3579
3580 rv->te_router_id = copy_tlv_te_router_id(tlvs->te_router_id);
3581
3582 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
3583 &tlvs->extended_ip_reach, &rv->extended_ip_reach);
3584
3585 copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
3586 &tlvs->mt_ip_reach, &rv->mt_ip_reach);
3587
3588 rv->hostname = copy_tlv_dynamic_hostname(tlvs->hostname);
3589
3590 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach,
3591 &rv->ipv6_reach);
3592
3593 copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
3594 &tlvs->mt_ipv6_reach, &rv->mt_ipv6_reach);
3595
3596 rv->threeway_adj = copy_tlv_threeway_adj(tlvs->threeway_adj);
3597
3598 rv->router_cap = copy_tlv_router_cap(tlvs->router_cap);
3599
3600 rv->spine_leaf = copy_tlv_spine_leaf(tlvs->spine_leaf);
3601
3602 return rv;
3603 }
3604
format_tlvs(struct isis_tlvs * tlvs,struct sbuf * buf,int indent)3605 static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent)
3606 {
3607 format_tlv_protocols_supported(&tlvs->protocols_supported, buf, indent);
3608
3609 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth, buf,
3610 indent);
3611
3612 format_tlv_purge_originator(tlvs->purge_originator, buf, indent);
3613
3614 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
3615 &tlvs->area_addresses, buf, indent);
3616
3617 if (tlvs->mt_router_info_empty) {
3618 sbuf_push(buf, indent, "MT Router Info: None\n");
3619 } else {
3620 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
3621 &tlvs->mt_router_info, buf, indent);
3622 }
3623
3624 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
3625 &tlvs->oldstyle_reach, buf, indent);
3626
3627 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
3628 &tlvs->lan_neighbor, buf, indent);
3629
3630 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries,
3631 buf, indent);
3632
3633 format_tlv_dynamic_hostname(tlvs->hostname, buf, indent);
3634 format_tlv_te_router_id(tlvs->te_router_id, buf, indent);
3635 format_tlv_router_cap(tlvs->router_cap, buf, indent);
3636
3637 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
3638 &tlvs->extended_reach, buf, indent);
3639
3640 format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach,
3641 buf, indent);
3642
3643 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
3644 &tlvs->oldstyle_ip_reach, buf, indent);
3645
3646 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
3647 &tlvs->oldstyle_ip_reach_ext, buf, indent);
3648
3649 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS,
3650 &tlvs->ipv4_address, buf, indent);
3651
3652 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS,
3653 &tlvs->ipv6_address, buf, indent);
3654
3655 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
3656 &tlvs->extended_ip_reach, buf, indent);
3657
3658 format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
3659 &tlvs->mt_ip_reach, buf, indent);
3660
3661 format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach,
3662 buf, indent);
3663
3664 format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
3665 &tlvs->mt_ipv6_reach, buf, indent);
3666
3667 format_tlv_threeway_adj(tlvs->threeway_adj, buf, indent);
3668
3669 format_tlv_spine_leaf(tlvs->spine_leaf, buf, indent);
3670 }
3671
isis_format_tlvs(struct isis_tlvs * tlvs)3672 const char *isis_format_tlvs(struct isis_tlvs *tlvs)
3673 {
3674 static struct sbuf buf;
3675
3676 if (!sbuf_buf(&buf))
3677 sbuf_init(&buf, NULL, 0);
3678
3679 sbuf_reset(&buf);
3680 format_tlvs(tlvs, &buf, 0);
3681 return sbuf_buf(&buf);
3682 }
3683
isis_free_tlvs(struct isis_tlvs * tlvs)3684 void isis_free_tlvs(struct isis_tlvs *tlvs)
3685 {
3686 if (!tlvs)
3687 return;
3688
3689 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth);
3690 free_tlv_purge_originator(tlvs->purge_originator);
3691 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
3692 &tlvs->area_addresses);
3693 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
3694 &tlvs->mt_router_info);
3695 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
3696 &tlvs->oldstyle_reach);
3697 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
3698 &tlvs->lan_neighbor);
3699 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries);
3700 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
3701 &tlvs->extended_reach);
3702 free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach);
3703 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
3704 &tlvs->oldstyle_ip_reach);
3705 free_tlv_protocols_supported(&tlvs->protocols_supported);
3706 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
3707 &tlvs->oldstyle_ip_reach_ext);
3708 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS,
3709 &tlvs->ipv4_address);
3710 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS,
3711 &tlvs->ipv6_address);
3712 free_tlv_te_router_id(tlvs->te_router_id);
3713 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
3714 &tlvs->extended_ip_reach);
3715 free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
3716 &tlvs->mt_ip_reach);
3717 free_tlv_dynamic_hostname(tlvs->hostname);
3718 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach);
3719 free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
3720 &tlvs->mt_ipv6_reach);
3721 free_tlv_threeway_adj(tlvs->threeway_adj);
3722 free_tlv_router_cap(tlvs->router_cap);
3723 free_tlv_spine_leaf(tlvs->spine_leaf);
3724
3725 XFREE(MTYPE_ISIS_TLV, tlvs);
3726 }
3727
add_padding(struct stream * s)3728 static void add_padding(struct stream *s)
3729 {
3730 while (STREAM_WRITEABLE(s)) {
3731 if (STREAM_WRITEABLE(s) == 1)
3732 break;
3733 uint32_t padding_len = STREAM_WRITEABLE(s) - 2;
3734
3735 if (padding_len > 255) {
3736 if (padding_len == 256)
3737 padding_len = 254;
3738 else
3739 padding_len = 255;
3740 }
3741
3742 stream_putc(s, ISIS_TLV_PADDING);
3743 stream_putc(s, padding_len);
3744 stream_put(s, NULL, padding_len);
3745 }
3746 }
3747
3748 #define LSP_REM_LIFETIME_OFF 10
3749 #define LSP_CHECKSUM_OFF 24
safe_auth_md5(struct stream * s,uint16_t * checksum,uint16_t * rem_lifetime)3750 static void safe_auth_md5(struct stream *s, uint16_t *checksum,
3751 uint16_t *rem_lifetime)
3752 {
3753 memcpy(rem_lifetime, STREAM_DATA(s) + LSP_REM_LIFETIME_OFF,
3754 sizeof(*rem_lifetime));
3755 memset(STREAM_DATA(s) + LSP_REM_LIFETIME_OFF, 0, sizeof(*rem_lifetime));
3756 memcpy(checksum, STREAM_DATA(s) + LSP_CHECKSUM_OFF, sizeof(*checksum));
3757 memset(STREAM_DATA(s) + LSP_CHECKSUM_OFF, 0, sizeof(*checksum));
3758 }
3759
restore_auth_md5(struct stream * s,uint16_t checksum,uint16_t rem_lifetime)3760 static void restore_auth_md5(struct stream *s, uint16_t checksum,
3761 uint16_t rem_lifetime)
3762 {
3763 memcpy(STREAM_DATA(s) + LSP_REM_LIFETIME_OFF, &rem_lifetime,
3764 sizeof(rem_lifetime));
3765 memcpy(STREAM_DATA(s) + LSP_CHECKSUM_OFF, &checksum, sizeof(checksum));
3766 }
3767
update_auth_hmac_md5(struct isis_auth * auth,struct stream * s,bool is_lsp)3768 static void update_auth_hmac_md5(struct isis_auth *auth, struct stream *s,
3769 bool is_lsp)
3770 {
3771 uint8_t digest[16];
3772 uint16_t checksum, rem_lifetime;
3773
3774 if (is_lsp)
3775 safe_auth_md5(s, &checksum, &rem_lifetime);
3776
3777 memset(STREAM_DATA(s) + auth->offset, 0, 16);
3778 #ifdef CRYPTO_OPENSSL
3779 uint8_t *result = (uint8_t *)HMAC(EVP_md5(), auth->passwd,
3780 auth->plength, STREAM_DATA(s),
3781 stream_get_endp(s), NULL, NULL);
3782
3783 memcpy(digest, result, 16);
3784 #elif CRYPTO_INTERNAL
3785 hmac_md5(STREAM_DATA(s), stream_get_endp(s), auth->passwd,
3786 auth->plength, digest);
3787 #endif
3788 memcpy(auth->value, digest, 16);
3789 memcpy(STREAM_DATA(s) + auth->offset, digest, 16);
3790
3791 if (is_lsp)
3792 restore_auth_md5(s, checksum, rem_lifetime);
3793 }
3794
update_auth(struct isis_tlvs * tlvs,struct stream * s,bool is_lsp)3795 static void update_auth(struct isis_tlvs *tlvs, struct stream *s, bool is_lsp)
3796 {
3797 struct isis_auth *auth_head = (struct isis_auth *)tlvs->isis_auth.head;
3798
3799 for (struct isis_auth *auth = auth_head; auth; auth = auth->next) {
3800 if (auth->type == ISIS_PASSWD_TYPE_HMAC_MD5)
3801 update_auth_hmac_md5(auth, s, is_lsp);
3802 }
3803 }
3804
handle_pack_entry(const struct pack_order_entry * pe,struct isis_tlvs * tlvs,struct stream * stream,struct isis_tlvs ** fragment_tlvs,struct isis_tlvs * (* new_fragment)(struct list * l),struct list * new_fragment_arg)3805 static int handle_pack_entry(const struct pack_order_entry *pe,
3806 struct isis_tlvs *tlvs, struct stream *stream,
3807 struct isis_tlvs **fragment_tlvs,
3808 struct isis_tlvs *(*new_fragment)(struct list *l),
3809 struct list *new_fragment_arg)
3810 {
3811 int rv;
3812
3813 if (pe->how_to_pack == ISIS_ITEMS) {
3814 struct isis_item_list *l;
3815 l = (struct isis_item_list *)(((char *)tlvs)
3816 + pe->what_to_pack);
3817 rv = pack_items(pe->context, pe->type, l, stream, fragment_tlvs,
3818 pe, new_fragment, new_fragment_arg);
3819 } else {
3820 struct isis_mt_item_list *l;
3821 l = (struct isis_mt_item_list *)(((char *)tlvs)
3822 + pe->what_to_pack);
3823 rv = pack_mt_items(pe->context, pe->type, l, stream,
3824 fragment_tlvs, pe, new_fragment,
3825 new_fragment_arg);
3826 }
3827
3828 return rv;
3829 }
3830
pack_tlvs(struct isis_tlvs * tlvs,struct stream * stream,struct isis_tlvs * fragment_tlvs,struct isis_tlvs * (* new_fragment)(struct list * l),struct list * new_fragment_arg)3831 static int pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
3832 struct isis_tlvs *fragment_tlvs,
3833 struct isis_tlvs *(*new_fragment)(struct list *l),
3834 struct list *new_fragment_arg)
3835 {
3836 int rv;
3837
3838 /* When fragmenting, don't add auth as it's already accounted for in the
3839 * size we are given. */
3840 if (!fragment_tlvs) {
3841 rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH,
3842 &tlvs->isis_auth, stream, NULL, NULL, NULL,
3843 NULL);
3844 if (rv)
3845 return rv;
3846 }
3847
3848 rv = pack_tlv_purge_originator(tlvs->purge_originator, stream);
3849 if (rv)
3850 return rv;
3851 if (fragment_tlvs) {
3852 fragment_tlvs->purge_originator =
3853 copy_tlv_purge_originator(tlvs->purge_originator);
3854 }
3855
3856 rv = pack_tlv_protocols_supported(&tlvs->protocols_supported, stream);
3857 if (rv)
3858 return rv;
3859 if (fragment_tlvs) {
3860 copy_tlv_protocols_supported(
3861 &tlvs->protocols_supported,
3862 &fragment_tlvs->protocols_supported);
3863 }
3864
3865 rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
3866 &tlvs->area_addresses, stream, NULL, NULL, NULL, NULL);
3867 if (rv)
3868 return rv;
3869 if (fragment_tlvs) {
3870 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
3871 &tlvs->area_addresses,
3872 &fragment_tlvs->area_addresses);
3873 }
3874
3875
3876 if (tlvs->mt_router_info_empty) {
3877 if (STREAM_WRITEABLE(stream) < 2)
3878 return 1;
3879 stream_putc(stream, ISIS_TLV_MT_ROUTER_INFO);
3880 stream_putc(stream, 0);
3881 if (fragment_tlvs)
3882 fragment_tlvs->mt_router_info_empty = true;
3883 } else {
3884 rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
3885 &tlvs->mt_router_info, stream, NULL, NULL, NULL,
3886 NULL);
3887 if (rv)
3888 return rv;
3889 if (fragment_tlvs) {
3890 copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
3891 &tlvs->mt_router_info,
3892 &fragment_tlvs->mt_router_info);
3893 }
3894 }
3895
3896 rv = pack_tlv_dynamic_hostname(tlvs->hostname, stream);
3897 if (rv)
3898 return rv;
3899 if (fragment_tlvs)
3900 fragment_tlvs->hostname =
3901 copy_tlv_dynamic_hostname(tlvs->hostname);
3902
3903 rv = pack_tlv_router_cap(tlvs->router_cap, stream);
3904 if (rv)
3905 return rv;
3906 if (fragment_tlvs) {
3907 fragment_tlvs->router_cap =
3908 copy_tlv_router_cap(tlvs->router_cap);
3909 }
3910
3911 rv = pack_tlv_te_router_id(tlvs->te_router_id, stream);
3912 if (rv)
3913 return rv;
3914 if (fragment_tlvs) {
3915 fragment_tlvs->te_router_id =
3916 copy_tlv_te_router_id(tlvs->te_router_id);
3917 }
3918
3919 rv = pack_tlv_threeway_adj(tlvs->threeway_adj, stream);
3920 if (rv)
3921 return rv;
3922 if (fragment_tlvs) {
3923 fragment_tlvs->threeway_adj =
3924 copy_tlv_threeway_adj(tlvs->threeway_adj);
3925 }
3926
3927 rv = pack_tlv_spine_leaf(tlvs->spine_leaf, stream);
3928 if (rv)
3929 return rv;
3930 if (fragment_tlvs) {
3931 fragment_tlvs->spine_leaf =
3932 copy_tlv_spine_leaf(tlvs->spine_leaf);
3933 }
3934
3935 for (size_t pack_idx = 0; pack_idx < array_size(pack_order);
3936 pack_idx++) {
3937 rv = handle_pack_entry(&pack_order[pack_idx], tlvs, stream,
3938 fragment_tlvs ? &fragment_tlvs : NULL,
3939 new_fragment, new_fragment_arg);
3940
3941 if (rv)
3942 return rv;
3943 }
3944
3945 return 0;
3946 }
3947
isis_pack_tlvs(struct isis_tlvs * tlvs,struct stream * stream,size_t len_pointer,bool pad,bool is_lsp)3948 int isis_pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
3949 size_t len_pointer, bool pad, bool is_lsp)
3950 {
3951 int rv;
3952
3953 rv = pack_tlvs(tlvs, stream, NULL, NULL, NULL);
3954 if (rv)
3955 return rv;
3956
3957 if (pad)
3958 add_padding(stream);
3959
3960 if (len_pointer != (size_t)-1) {
3961 stream_putw_at(stream, len_pointer, stream_get_endp(stream));
3962 }
3963
3964 update_auth(tlvs, stream, is_lsp);
3965
3966 return 0;
3967 }
3968
new_fragment(struct list * l)3969 static struct isis_tlvs *new_fragment(struct list *l)
3970 {
3971 struct isis_tlvs *rv = isis_alloc_tlvs();
3972
3973 listnode_add(l, rv);
3974 return rv;
3975 }
3976
isis_fragment_tlvs(struct isis_tlvs * tlvs,size_t size)3977 struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size)
3978 {
3979 struct stream *dummy_stream = stream_new(size);
3980 struct list *rv = list_new();
3981 struct isis_tlvs *fragment_tlvs = new_fragment(rv);
3982
3983 if (pack_tlvs(tlvs, dummy_stream, fragment_tlvs, new_fragment, rv)) {
3984 struct listnode *node;
3985 for (ALL_LIST_ELEMENTS_RO(rv, node, fragment_tlvs))
3986 isis_free_tlvs(fragment_tlvs);
3987 list_delete(&rv);
3988 }
3989
3990 stream_free(dummy_stream);
3991 return rv;
3992 }
3993
unpack_tlv_unknown(enum isis_tlv_context context,uint8_t tlv_type,uint8_t tlv_len,struct stream * s,struct sbuf * log,int indent)3994 static int unpack_tlv_unknown(enum isis_tlv_context context, uint8_t tlv_type,
3995 uint8_t tlv_len, struct stream *s,
3996 struct sbuf *log, int indent)
3997 {
3998 stream_forward_getp(s, tlv_len);
3999 sbuf_push(log, indent,
4000 "Skipping unknown TLV %hhu (%hhu bytes)\n",
4001 tlv_type, tlv_len);
4002 return 0;
4003 }
4004
unpack_tlv(enum isis_tlv_context context,size_t avail_len,struct stream * stream,struct sbuf * log,void * dest,int indent,bool * unpacked_known_tlvs)4005 static int unpack_tlv(enum isis_tlv_context context, size_t avail_len,
4006 struct stream *stream, struct sbuf *log, void *dest,
4007 int indent, bool *unpacked_known_tlvs)
4008 {
4009 uint8_t tlv_type, tlv_len;
4010 const struct tlv_ops *ops;
4011
4012 sbuf_push(log, indent, "Unpacking TLV...\n");
4013
4014 if (avail_len < 2) {
4015 sbuf_push(
4016 log, indent + 2,
4017 "Available data %zu too short to contain a TLV header.\n",
4018 avail_len);
4019 return 1;
4020 }
4021
4022 tlv_type = stream_getc(stream);
4023 tlv_len = stream_getc(stream);
4024
4025 sbuf_push(log, indent + 2,
4026 "Found TLV of type %hhu and len %hhu.\n",
4027 tlv_type, tlv_len);
4028
4029 if (avail_len < ((size_t)tlv_len) + 2) {
4030 sbuf_push(log, indent + 2,
4031 "Available data %zu too short for claimed TLV len %hhu.\n",
4032 avail_len - 2, tlv_len);
4033 return 1;
4034 }
4035
4036 ops = tlv_table[context][tlv_type];
4037 if (ops && ops->unpack) {
4038 if (unpacked_known_tlvs)
4039 *unpacked_known_tlvs = true;
4040 return ops->unpack(context, tlv_type, tlv_len, stream, log,
4041 dest, indent + 2);
4042 }
4043
4044 return unpack_tlv_unknown(context, tlv_type, tlv_len, stream, log,
4045 indent + 2);
4046 }
4047
unpack_tlvs(enum isis_tlv_context context,size_t avail_len,struct stream * stream,struct sbuf * log,void * dest,int indent,bool * unpacked_known_tlvs)4048 static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len,
4049 struct stream *stream, struct sbuf *log, void *dest,
4050 int indent, bool *unpacked_known_tlvs)
4051 {
4052 int rv;
4053 size_t tlv_start, tlv_pos;
4054
4055 tlv_start = stream_get_getp(stream);
4056 tlv_pos = 0;
4057
4058 sbuf_push(log, indent, "Unpacking %zu bytes of %s...\n", avail_len,
4059 (context == ISIS_CONTEXT_LSP) ? "TLVs" : "sub-TLVs");
4060
4061 while (tlv_pos < avail_len) {
4062 rv = unpack_tlv(context, avail_len - tlv_pos, stream, log, dest,
4063 indent + 2, unpacked_known_tlvs);
4064 if (rv)
4065 return rv;
4066
4067 tlv_pos = stream_get_getp(stream) - tlv_start;
4068 }
4069
4070 return 0;
4071 }
4072
isis_unpack_tlvs(size_t avail_len,struct stream * stream,struct isis_tlvs ** dest,const char ** log)4073 int isis_unpack_tlvs(size_t avail_len, struct stream *stream,
4074 struct isis_tlvs **dest, const char **log)
4075 {
4076 static struct sbuf logbuf;
4077 int indent = 0;
4078 int rv;
4079 struct isis_tlvs *result;
4080
4081 if (!sbuf_buf(&logbuf))
4082 sbuf_init(&logbuf, NULL, 0);
4083
4084 sbuf_reset(&logbuf);
4085 if (avail_len > STREAM_READABLE(stream)) {
4086 sbuf_push(&logbuf, indent,
4087 "Stream doesn't contain sufficient data. Claimed %zu, available %zu\n",
4088 avail_len, STREAM_READABLE(stream));
4089 return 1;
4090 }
4091
4092 result = isis_alloc_tlvs();
4093 rv = unpack_tlvs(ISIS_CONTEXT_LSP, avail_len, stream, &logbuf, result,
4094 indent, NULL);
4095
4096 *log = sbuf_buf(&logbuf);
4097 *dest = result;
4098
4099 return rv;
4100 }
4101
4102 #define TLV_OPS(_name_, _desc_) \
4103 static const struct tlv_ops tlv_##_name_##_ops = { \
4104 .name = _desc_, .unpack = unpack_tlv_##_name_, \
4105 }
4106
4107 #define ITEM_TLV_OPS(_name_, _desc_) \
4108 static const struct tlv_ops tlv_##_name_##_ops = { \
4109 .name = _desc_, \
4110 .unpack = unpack_tlv_with_items, \
4111 \
4112 .pack_item = pack_item_##_name_, \
4113 .free_item = free_item_##_name_, \
4114 .unpack_item = unpack_item_##_name_, \
4115 .format_item = format_item_##_name_, \
4116 .copy_item = copy_item_##_name_}
4117
4118 #define SUBTLV_OPS(_name_, _desc_) \
4119 static const struct tlv_ops subtlv_##_name_##_ops = { \
4120 .name = _desc_, .unpack = unpack_subtlv_##_name_, \
4121 }
4122
4123 #define ITEM_SUBTLV_OPS(_name_, _desc_) \
4124 ITEM_TLV_OPS(_name_, _desc_)
4125
4126 ITEM_TLV_OPS(area_address, "TLV 1 Area Addresses");
4127 ITEM_TLV_OPS(oldstyle_reach, "TLV 2 IS Reachability");
4128 ITEM_TLV_OPS(lan_neighbor, "TLV 6 LAN Neighbors");
4129 ITEM_TLV_OPS(lsp_entry, "TLV 9 LSP Entries");
4130 ITEM_TLV_OPS(auth, "TLV 10 IS-IS Auth");
4131 TLV_OPS(purge_originator, "TLV 13 Purge Originator Identification");
4132 ITEM_TLV_OPS(extended_reach, "TLV 22 Extended Reachability");
4133 ITEM_TLV_OPS(oldstyle_ip_reach, "TLV 128/130 IP Reachability");
4134 TLV_OPS(protocols_supported, "TLV 129 Protocols Supported");
4135 ITEM_TLV_OPS(ipv4_address, "TLV 132 IPv4 Interface Address");
4136 TLV_OPS(te_router_id, "TLV 134 TE Router ID");
4137 ITEM_TLV_OPS(extended_ip_reach, "TLV 135 Extended IP Reachability");
4138 TLV_OPS(dynamic_hostname, "TLV 137 Dynamic Hostname");
4139 TLV_OPS(spine_leaf, "TLV 150 Spine Leaf Extensions");
4140 ITEM_TLV_OPS(mt_router_info, "TLV 229 MT Router Information");
4141 TLV_OPS(threeway_adj, "TLV 240 P2P Three-Way Adjacency");
4142 ITEM_TLV_OPS(ipv6_address, "TLV 232 IPv6 Interface Address");
4143 ITEM_TLV_OPS(ipv6_reach, "TLV 236 IPv6 Reachability");
4144 TLV_OPS(router_cap, "TLV 242 Router Capability");
4145
4146 ITEM_SUBTLV_OPS(prefix_sid, "Sub-TLV 3 SR Prefix-SID");
4147 SUBTLV_OPS(ipv6_source_prefix, "Sub-TLV 22 IPv6 Source Prefix");
4148
4149 static const struct tlv_ops *const tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
4150 [ISIS_CONTEXT_LSP] = {
4151 [ISIS_TLV_AREA_ADDRESSES] = &tlv_area_address_ops,
4152 [ISIS_TLV_OLDSTYLE_REACH] = &tlv_oldstyle_reach_ops,
4153 [ISIS_TLV_LAN_NEIGHBORS] = &tlv_lan_neighbor_ops,
4154 [ISIS_TLV_LSP_ENTRY] = &tlv_lsp_entry_ops,
4155 [ISIS_TLV_AUTH] = &tlv_auth_ops,
4156 [ISIS_TLV_PURGE_ORIGINATOR] = &tlv_purge_originator_ops,
4157 [ISIS_TLV_EXTENDED_REACH] = &tlv_extended_reach_ops,
4158 [ISIS_TLV_OLDSTYLE_IP_REACH] = &tlv_oldstyle_ip_reach_ops,
4159 [ISIS_TLV_PROTOCOLS_SUPPORTED] = &tlv_protocols_supported_ops,
4160 [ISIS_TLV_OLDSTYLE_IP_REACH_EXT] = &tlv_oldstyle_ip_reach_ops,
4161 [ISIS_TLV_IPV4_ADDRESS] = &tlv_ipv4_address_ops,
4162 [ISIS_TLV_TE_ROUTER_ID] = &tlv_te_router_id_ops,
4163 [ISIS_TLV_EXTENDED_IP_REACH] = &tlv_extended_ip_reach_ops,
4164 [ISIS_TLV_DYNAMIC_HOSTNAME] = &tlv_dynamic_hostname_ops,
4165 [ISIS_TLV_SPINE_LEAF_EXT] = &tlv_spine_leaf_ops,
4166 [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops,
4167 [ISIS_TLV_MT_ROUTER_INFO] = &tlv_mt_router_info_ops,
4168 [ISIS_TLV_IPV6_ADDRESS] = &tlv_ipv6_address_ops,
4169 [ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops,
4170 [ISIS_TLV_IPV6_REACH] = &tlv_ipv6_reach_ops,
4171 [ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops,
4172 [ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops,
4173 [ISIS_TLV_ROUTER_CAPABILITY] = &tlv_router_cap_ops,
4174 },
4175 [ISIS_CONTEXT_SUBTLV_NE_REACH] = {},
4176 [ISIS_CONTEXT_SUBTLV_IP_REACH] = {
4177 [ISIS_SUBTLV_PREFIX_SID] = &tlv_prefix_sid_ops,
4178 },
4179 [ISIS_CONTEXT_SUBTLV_IPV6_REACH] = {
4180 [ISIS_SUBTLV_PREFIX_SID] = &tlv_prefix_sid_ops,
4181 [ISIS_SUBTLV_IPV6_SOURCE_PREFIX] = &subtlv_ipv6_source_prefix_ops,
4182 }
4183 };
4184
4185 /* Accessor functions */
4186
isis_tlvs_add_auth(struct isis_tlvs * tlvs,struct isis_passwd * passwd)4187 void isis_tlvs_add_auth(struct isis_tlvs *tlvs, struct isis_passwd *passwd)
4188 {
4189 free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth);
4190 init_item_list(&tlvs->isis_auth);
4191
4192 if (passwd->type == ISIS_PASSWD_TYPE_UNUSED)
4193 return;
4194
4195 struct isis_auth *auth = XCALLOC(MTYPE_ISIS_TLV, sizeof(*auth));
4196
4197 auth->type = passwd->type;
4198
4199 auth->plength = passwd->len;
4200 memcpy(auth->passwd, passwd->passwd,
4201 MIN(sizeof(auth->passwd), sizeof(passwd->passwd)));
4202
4203 if (auth->type == ISIS_PASSWD_TYPE_CLEARTXT) {
4204 auth->length = passwd->len;
4205 memcpy(auth->value, passwd->passwd,
4206 MIN(sizeof(auth->value), sizeof(passwd->passwd)));
4207 }
4208
4209 append_item(&tlvs->isis_auth, (struct isis_item *)auth);
4210 }
4211
isis_tlvs_add_area_addresses(struct isis_tlvs * tlvs,struct list * addresses)4212 void isis_tlvs_add_area_addresses(struct isis_tlvs *tlvs,
4213 struct list *addresses)
4214 {
4215 struct listnode *node;
4216 struct area_addr *area_addr;
4217
4218 for (ALL_LIST_ELEMENTS_RO(addresses, node, area_addr)) {
4219 struct isis_area_address *a =
4220 XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
4221
4222 a->len = area_addr->addr_len;
4223 memcpy(a->addr, area_addr->area_addr, 20);
4224 append_item(&tlvs->area_addresses, (struct isis_item *)a);
4225 }
4226 }
4227
isis_tlvs_add_lan_neighbors(struct isis_tlvs * tlvs,struct list * neighbors)4228 void isis_tlvs_add_lan_neighbors(struct isis_tlvs *tlvs, struct list *neighbors)
4229 {
4230 struct listnode *node;
4231 uint8_t *snpa;
4232
4233 for (ALL_LIST_ELEMENTS_RO(neighbors, node, snpa)) {
4234 struct isis_lan_neighbor *n =
4235 XCALLOC(MTYPE_ISIS_TLV, sizeof(*n));
4236
4237 memcpy(n->mac, snpa, 6);
4238 append_item(&tlvs->lan_neighbor, (struct isis_item *)n);
4239 }
4240 }
4241
isis_tlvs_set_protocols_supported(struct isis_tlvs * tlvs,struct nlpids * nlpids)4242 void isis_tlvs_set_protocols_supported(struct isis_tlvs *tlvs,
4243 struct nlpids *nlpids)
4244 {
4245 tlvs->protocols_supported.count = nlpids->count;
4246 XFREE(MTYPE_ISIS_TLV, tlvs->protocols_supported.protocols);
4247 if (nlpids->count) {
4248 tlvs->protocols_supported.protocols =
4249 XCALLOC(MTYPE_ISIS_TLV, nlpids->count);
4250 memcpy(tlvs->protocols_supported.protocols, nlpids->nlpids,
4251 nlpids->count);
4252 } else {
4253 tlvs->protocols_supported.protocols = NULL;
4254 }
4255 }
4256
isis_tlvs_add_mt_router_info(struct isis_tlvs * tlvs,uint16_t mtid,bool overload,bool attached)4257 void isis_tlvs_add_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid,
4258 bool overload, bool attached)
4259 {
4260 struct isis_mt_router_info *i = XCALLOC(MTYPE_ISIS_TLV, sizeof(*i));
4261
4262 i->overload = overload;
4263 i->attached = attached;
4264 i->mtid = mtid;
4265 append_item(&tlvs->mt_router_info, (struct isis_item *)i);
4266 }
4267
isis_tlvs_add_ipv4_address(struct isis_tlvs * tlvs,struct in_addr * addr)4268 void isis_tlvs_add_ipv4_address(struct isis_tlvs *tlvs, struct in_addr *addr)
4269 {
4270 struct isis_ipv4_address *a = XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
4271 a->addr = *addr;
4272 append_item(&tlvs->ipv4_address, (struct isis_item *)a);
4273 }
4274
4275
isis_tlvs_add_ipv4_addresses(struct isis_tlvs * tlvs,struct list * addresses)4276 void isis_tlvs_add_ipv4_addresses(struct isis_tlvs *tlvs,
4277 struct list *addresses)
4278 {
4279 struct listnode *node;
4280 struct prefix_ipv4 *ip_addr;
4281 unsigned int addr_count = 0;
4282
4283 for (ALL_LIST_ELEMENTS_RO(addresses, node, ip_addr)) {
4284 isis_tlvs_add_ipv4_address(tlvs, &ip_addr->prefix);
4285 addr_count++;
4286 if (addr_count >= 63)
4287 break;
4288 }
4289 }
4290
isis_tlvs_add_ipv6_addresses(struct isis_tlvs * tlvs,struct list * addresses)4291 void isis_tlvs_add_ipv6_addresses(struct isis_tlvs *tlvs,
4292 struct list *addresses)
4293 {
4294 struct listnode *node;
4295 struct prefix_ipv6 *ip_addr;
4296 unsigned int addr_count = 0;
4297
4298 for (ALL_LIST_ELEMENTS_RO(addresses, node, ip_addr)) {
4299 if (addr_count >= 15)
4300 break;
4301
4302 struct isis_ipv6_address *a =
4303 XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
4304
4305 a->addr = ip_addr->prefix;
4306 append_item(&tlvs->ipv6_address, (struct isis_item *)a);
4307 addr_count++;
4308 }
4309 }
4310
4311 typedef bool (*auth_validator_func)(struct isis_passwd *passwd,
4312 struct stream *stream,
4313 struct isis_auth *auth, bool is_lsp);
4314
auth_validator_cleartxt(struct isis_passwd * passwd,struct stream * stream,struct isis_auth * auth,bool is_lsp)4315 static bool auth_validator_cleartxt(struct isis_passwd *passwd,
4316 struct stream *stream,
4317 struct isis_auth *auth, bool is_lsp)
4318 {
4319 return (auth->length == passwd->len
4320 && !memcmp(auth->value, passwd->passwd, passwd->len));
4321 }
4322
auth_validator_hmac_md5(struct isis_passwd * passwd,struct stream * stream,struct isis_auth * auth,bool is_lsp)4323 static bool auth_validator_hmac_md5(struct isis_passwd *passwd,
4324 struct stream *stream,
4325 struct isis_auth *auth, bool is_lsp)
4326 {
4327 uint8_t digest[16];
4328 uint16_t checksum;
4329 uint16_t rem_lifetime;
4330
4331 if (is_lsp)
4332 safe_auth_md5(stream, &checksum, &rem_lifetime);
4333
4334 memset(STREAM_DATA(stream) + auth->offset, 0, 16);
4335 #ifdef CRYPTO_OPENSSL
4336 uint8_t *result = (uint8_t *)HMAC(EVP_md5(), passwd->passwd,
4337 passwd->len, STREAM_DATA(stream),
4338 stream_get_endp(stream), NULL, NULL);
4339
4340 memcpy(digest, result, 16);
4341 #elif CRYPTO_INTERNAL
4342 hmac_md5(STREAM_DATA(stream), stream_get_endp(stream), passwd->passwd,
4343 passwd->len, digest);
4344 #endif
4345 memcpy(STREAM_DATA(stream) + auth->offset, auth->value, 16);
4346
4347 bool rv = !memcmp(digest, auth->value, 16);
4348
4349 if (is_lsp)
4350 restore_auth_md5(stream, checksum, rem_lifetime);
4351
4352 return rv;
4353 }
4354
4355 static const auth_validator_func auth_validators[] = {
4356 [ISIS_PASSWD_TYPE_CLEARTXT] = auth_validator_cleartxt,
4357 [ISIS_PASSWD_TYPE_HMAC_MD5] = auth_validator_hmac_md5,
4358 };
4359
isis_tlvs_auth_is_valid(struct isis_tlvs * tlvs,struct isis_passwd * passwd,struct stream * stream,bool is_lsp)4360 int isis_tlvs_auth_is_valid(struct isis_tlvs *tlvs, struct isis_passwd *passwd,
4361 struct stream *stream, bool is_lsp)
4362 {
4363 /* If no auth is set, always pass authentication */
4364 if (!passwd->type)
4365 return ISIS_AUTH_OK;
4366
4367 /* If we don't known how to validate the auth, return invalid */
4368 if (passwd->type >= array_size(auth_validators)
4369 || !auth_validators[passwd->type])
4370 return ISIS_AUTH_NO_VALIDATOR;
4371
4372 struct isis_auth *auth_head = (struct isis_auth *)tlvs->isis_auth.head;
4373 struct isis_auth *auth;
4374 for (auth = auth_head; auth; auth = auth->next) {
4375 if (auth->type == passwd->type)
4376 break;
4377 }
4378
4379 /* If matching auth TLV could not be found, return invalid */
4380 if (!auth)
4381 return ISIS_AUTH_TYPE_FAILURE;
4382
4383
4384 /* Perform validation and return result */
4385 if (auth_validators[passwd->type](passwd, stream, auth, is_lsp))
4386 return ISIS_AUTH_OK;
4387 else
4388 return ISIS_AUTH_FAILURE;
4389 }
4390
isis_tlvs_area_addresses_match(struct isis_tlvs * tlvs,struct list * addresses)4391 bool isis_tlvs_area_addresses_match(struct isis_tlvs *tlvs,
4392 struct list *addresses)
4393 {
4394 struct isis_area_address *addr_head;
4395
4396 addr_head = (struct isis_area_address *)tlvs->area_addresses.head;
4397 for (struct isis_area_address *addr = addr_head; addr;
4398 addr = addr->next) {
4399 struct listnode *node;
4400 struct area_addr *a;
4401
4402 for (ALL_LIST_ELEMENTS_RO(addresses, node, a)) {
4403 if (a->addr_len == addr->len
4404 && !memcmp(a->area_addr, addr->addr, addr->len))
4405 return true;
4406 }
4407 }
4408
4409 return false;
4410 }
4411
tlvs_area_addresses_to_adj(struct isis_tlvs * tlvs,struct isis_adjacency * adj,bool * changed)4412 static void tlvs_area_addresses_to_adj(struct isis_tlvs *tlvs,
4413 struct isis_adjacency *adj,
4414 bool *changed)
4415 {
4416 if (adj->area_address_count != tlvs->area_addresses.count) {
4417 uint32_t oc = adj->area_address_count;
4418
4419 *changed = true;
4420 adj->area_address_count = tlvs->area_addresses.count;
4421 adj->area_addresses = XREALLOC(
4422 MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses,
4423 adj->area_address_count * sizeof(*adj->area_addresses));
4424
4425 for (; oc < adj->area_address_count; oc++) {
4426 adj->area_addresses[oc].addr_len = 0;
4427 memset(&adj->area_addresses[oc].area_addr, 0,
4428 sizeof(adj->area_addresses[oc].area_addr));
4429 }
4430 }
4431
4432 struct isis_area_address *addr = NULL;
4433 for (unsigned int i = 0; i < tlvs->area_addresses.count; i++) {
4434 if (!addr)
4435 addr = (struct isis_area_address *)
4436 tlvs->area_addresses.head;
4437 else
4438 addr = addr->next;
4439
4440 if (adj->area_addresses[i].addr_len == addr->len
4441 && !memcmp(adj->area_addresses[i].area_addr, addr->addr,
4442 addr->len)) {
4443 continue;
4444 }
4445
4446 *changed = true;
4447 adj->area_addresses[i].addr_len = addr->len;
4448 memcpy(adj->area_addresses[i].area_addr, addr->addr, addr->len);
4449 }
4450 }
4451
tlvs_protocols_supported_to_adj(struct isis_tlvs * tlvs,struct isis_adjacency * adj,bool * changed)4452 static void tlvs_protocols_supported_to_adj(struct isis_tlvs *tlvs,
4453 struct isis_adjacency *adj,
4454 bool *changed)
4455 {
4456 bool ipv4_supported = false, ipv6_supported = false;
4457
4458 for (uint8_t i = 0; i < tlvs->protocols_supported.count; i++) {
4459 if (tlvs->protocols_supported.protocols[i] == NLPID_IP)
4460 ipv4_supported = true;
4461 if (tlvs->protocols_supported.protocols[i] == NLPID_IPV6)
4462 ipv6_supported = true;
4463 }
4464
4465 struct nlpids reduced = {};
4466
4467 if (ipv4_supported && ipv6_supported) {
4468 reduced.count = 2;
4469 reduced.nlpids[0] = NLPID_IP;
4470 reduced.nlpids[1] = NLPID_IPV6;
4471 } else if (ipv4_supported) {
4472 reduced.count = 1;
4473 reduced.nlpids[0] = NLPID_IP;
4474 } else if (ipv6_supported) {
4475 reduced.count = 1;
4476 reduced.nlpids[0] = NLPID_IPV6;
4477 } else {
4478 reduced.count = 0;
4479 }
4480
4481 if (adj->nlpids.count == reduced.count
4482 && !memcmp(adj->nlpids.nlpids, reduced.nlpids, reduced.count))
4483 return;
4484
4485 *changed = true;
4486 adj->nlpids.count = reduced.count;
4487 memcpy(adj->nlpids.nlpids, reduced.nlpids, reduced.count);
4488 }
4489
4490 DEFINE_HOOK(isis_adj_ip_enabled_hook, (struct isis_adjacency *adj, int family),
4491 (adj, family))
4492 DEFINE_HOOK(isis_adj_ip_disabled_hook,
4493 (struct isis_adjacency *adj, int family), (adj, family))
4494
tlvs_ipv4_addresses_to_adj(struct isis_tlvs * tlvs,struct isis_adjacency * adj,bool * changed)4495 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs *tlvs,
4496 struct isis_adjacency *adj,
4497 bool *changed)
4498 {
4499 bool ipv4_enabled = false;
4500
4501 if (adj->ipv4_address_count == 0 && tlvs->ipv4_address.count > 0)
4502 ipv4_enabled = true;
4503 else if (adj->ipv4_address_count > 0 && tlvs->ipv4_address.count == 0)
4504 hook_call(isis_adj_ip_disabled_hook, adj, AF_INET);
4505
4506 if (adj->ipv4_address_count != tlvs->ipv4_address.count) {
4507 uint32_t oc = adj->ipv4_address_count;
4508
4509 *changed = true;
4510 adj->ipv4_address_count = tlvs->ipv4_address.count;
4511 adj->ipv4_addresses = XREALLOC(
4512 MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses,
4513 adj->ipv4_address_count * sizeof(*adj->ipv4_addresses));
4514
4515 for (; oc < adj->ipv4_address_count; oc++) {
4516 memset(&adj->ipv4_addresses[oc], 0,
4517 sizeof(adj->ipv4_addresses[oc]));
4518 }
4519 }
4520
4521 struct isis_ipv4_address *addr = NULL;
4522 for (unsigned int i = 0; i < tlvs->ipv4_address.count; i++) {
4523 if (!addr)
4524 addr = (struct isis_ipv4_address *)
4525 tlvs->ipv4_address.head;
4526 else
4527 addr = addr->next;
4528
4529 if (!memcmp(&adj->ipv4_addresses[i], &addr->addr,
4530 sizeof(addr->addr)))
4531 continue;
4532
4533 *changed = true;
4534 adj->ipv4_addresses[i] = addr->addr;
4535 }
4536
4537 if (ipv4_enabled)
4538 hook_call(isis_adj_ip_enabled_hook, adj, AF_INET);
4539 }
4540
tlvs_ipv6_addresses_to_adj(struct isis_tlvs * tlvs,struct isis_adjacency * adj,bool * changed)4541 static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs *tlvs,
4542 struct isis_adjacency *adj,
4543 bool *changed)
4544 {
4545 bool ipv6_enabled = false;
4546
4547 if (adj->ipv6_address_count == 0 && tlvs->ipv6_address.count > 0)
4548 ipv6_enabled = true;
4549 else if (adj->ipv6_address_count > 0 && tlvs->ipv6_address.count == 0)
4550 hook_call(isis_adj_ip_disabled_hook, adj, AF_INET6);
4551
4552 if (adj->ipv6_address_count != tlvs->ipv6_address.count) {
4553 uint32_t oc = adj->ipv6_address_count;
4554
4555 *changed = true;
4556 adj->ipv6_address_count = tlvs->ipv6_address.count;
4557 adj->ipv6_addresses = XREALLOC(
4558 MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses,
4559 adj->ipv6_address_count * sizeof(*adj->ipv6_addresses));
4560
4561 for (; oc < adj->ipv6_address_count; oc++) {
4562 memset(&adj->ipv6_addresses[oc], 0,
4563 sizeof(adj->ipv6_addresses[oc]));
4564 }
4565 }
4566
4567 struct isis_ipv6_address *addr = NULL;
4568 for (unsigned int i = 0; i < tlvs->ipv6_address.count; i++) {
4569 if (!addr)
4570 addr = (struct isis_ipv6_address *)
4571 tlvs->ipv6_address.head;
4572 else
4573 addr = addr->next;
4574
4575 if (!memcmp(&adj->ipv6_addresses[i], &addr->addr,
4576 sizeof(addr->addr)))
4577 continue;
4578
4579 *changed = true;
4580 adj->ipv6_addresses[i] = addr->addr;
4581 }
4582
4583 if (ipv6_enabled)
4584 hook_call(isis_adj_ip_enabled_hook, adj, AF_INET6);
4585 }
4586
isis_tlvs_to_adj(struct isis_tlvs * tlvs,struct isis_adjacency * adj,bool * changed)4587 void isis_tlvs_to_adj(struct isis_tlvs *tlvs, struct isis_adjacency *adj,
4588 bool *changed)
4589 {
4590 *changed = false;
4591
4592 tlvs_area_addresses_to_adj(tlvs, adj, changed);
4593 tlvs_protocols_supported_to_adj(tlvs, adj, changed);
4594 tlvs_ipv4_addresses_to_adj(tlvs, adj, changed);
4595 tlvs_ipv6_addresses_to_adj(tlvs, adj, changed);
4596 }
4597
isis_tlvs_own_snpa_found(struct isis_tlvs * tlvs,uint8_t * snpa)4598 bool isis_tlvs_own_snpa_found(struct isis_tlvs *tlvs, uint8_t *snpa)
4599 {
4600 struct isis_lan_neighbor *ne_head;
4601
4602 ne_head = (struct isis_lan_neighbor *)tlvs->lan_neighbor.head;
4603 for (struct isis_lan_neighbor *ne = ne_head; ne; ne = ne->next) {
4604 if (!memcmp(ne->mac, snpa, ETH_ALEN))
4605 return true;
4606 }
4607
4608 return false;
4609 }
4610
isis_tlvs_add_lsp_entry(struct isis_tlvs * tlvs,struct isis_lsp * lsp)4611 void isis_tlvs_add_lsp_entry(struct isis_tlvs *tlvs, struct isis_lsp *lsp)
4612 {
4613 struct isis_lsp_entry *entry = XCALLOC(MTYPE_ISIS_TLV, sizeof(*entry));
4614
4615 entry->rem_lifetime = lsp->hdr.rem_lifetime;
4616 memcpy(entry->id, lsp->hdr.lsp_id, ISIS_SYS_ID_LEN + 2);
4617 entry->checksum = lsp->hdr.checksum;
4618 entry->seqno = lsp->hdr.seqno;
4619 entry->lsp = lsp;
4620
4621 append_item(&tlvs->lsp_entries, (struct isis_item *)entry);
4622 }
4623
isis_tlvs_add_csnp_entries(struct isis_tlvs * tlvs,uint8_t * start_id,uint8_t * stop_id,uint16_t num_lsps,struct lspdb_head * head,struct isis_lsp ** last_lsp)4624 void isis_tlvs_add_csnp_entries(struct isis_tlvs *tlvs, uint8_t *start_id,
4625 uint8_t *stop_id, uint16_t num_lsps,
4626 struct lspdb_head *head,
4627 struct isis_lsp **last_lsp)
4628 {
4629 struct isis_lsp searchfor;
4630 struct isis_lsp *first, *lsp;
4631
4632 memcpy(&searchfor.hdr.lsp_id, start_id, sizeof(searchfor.hdr.lsp_id));
4633 first = lspdb_find_gteq(head, &searchfor);
4634 if (!first)
4635 return;
4636
4637 frr_each_from (lspdb, head, lsp, first) {
4638 if (memcmp(lsp->hdr.lsp_id, stop_id, sizeof(lsp->hdr.lsp_id))
4639 > 0 || tlvs->lsp_entries.count == num_lsps)
4640 break;
4641
4642 isis_tlvs_add_lsp_entry(tlvs, lsp);
4643 *last_lsp = lsp;
4644 }
4645 }
4646
isis_tlvs_set_dynamic_hostname(struct isis_tlvs * tlvs,const char * hostname)4647 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs,
4648 const char *hostname)
4649 {
4650 XFREE(MTYPE_ISIS_TLV, tlvs->hostname);
4651 if (hostname)
4652 tlvs->hostname = XSTRDUP(MTYPE_ISIS_TLV, hostname);
4653 }
4654
4655 /* Set Router Capability TLV parameters */
isis_tlvs_set_router_capability(struct isis_tlvs * tlvs,const struct isis_router_cap * cap)4656 void isis_tlvs_set_router_capability(struct isis_tlvs *tlvs,
4657 const struct isis_router_cap *cap)
4658 {
4659 XFREE(MTYPE_ISIS_TLV, tlvs->router_cap);
4660 if (!cap)
4661 return;
4662
4663 tlvs->router_cap = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->router_cap));
4664 *tlvs->router_cap = *cap;
4665 }
4666
isis_tlvs_set_te_router_id(struct isis_tlvs * tlvs,const struct in_addr * id)4667 void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs,
4668 const struct in_addr *id)
4669 {
4670 XFREE(MTYPE_ISIS_TLV, tlvs->te_router_id);
4671 if (!id)
4672 return;
4673 tlvs->te_router_id = XCALLOC(MTYPE_ISIS_TLV, sizeof(*id));
4674 memcpy(tlvs->te_router_id, id, sizeof(*id));
4675 }
4676
isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs * tlvs,struct prefix_ipv4 * dest,uint8_t metric)4677 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs,
4678 struct prefix_ipv4 *dest, uint8_t metric)
4679 {
4680 struct isis_oldstyle_ip_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
4681
4682 r->metric = metric;
4683 memcpy(&r->prefix, dest, sizeof(*dest));
4684 apply_mask_ipv4(&r->prefix);
4685 append_item(&tlvs->oldstyle_ip_reach, (struct isis_item *)r);
4686 }
4687
4688 /* Add IS-IS SR Adjacency-SID subTLVs */
isis_tlvs_add_adj_sid(struct isis_ext_subtlvs * exts,struct isis_adj_sid * adj)4689 void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs *exts,
4690 struct isis_adj_sid *adj)
4691 {
4692 append_item(&exts->adj_sid, (struct isis_item *)adj);
4693 SET_SUBTLV(exts, EXT_ADJ_SID);
4694 }
4695
4696 /* Delete IS-IS SR Adjacency-SID subTLVs */
isis_tlvs_del_adj_sid(struct isis_ext_subtlvs * exts,struct isis_adj_sid * adj)4697 void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs *exts,
4698 struct isis_adj_sid *adj)
4699 {
4700 delete_item(&exts->adj_sid, (struct isis_item *)adj);
4701 XFREE(MTYPE_ISIS_SUBTLV, adj);
4702 if (exts->adj_sid.count == 0)
4703 UNSET_SUBTLV(exts, EXT_ADJ_SID);
4704 }
4705
4706 /* Add IS-IS SR LAN-Adjacency-SID subTLVs */
isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs * exts,struct isis_lan_adj_sid * lan)4707 void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs *exts,
4708 struct isis_lan_adj_sid *lan)
4709 {
4710 append_item(&exts->lan_sid, (struct isis_item *)lan);
4711 SET_SUBTLV(exts, EXT_LAN_ADJ_SID);
4712 }
4713
4714 /* Delete IS-IS SR LAN-Adjacency-SID subTLVs */
isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs * exts,struct isis_lan_adj_sid * lan)4715 void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs *exts,
4716 struct isis_lan_adj_sid *lan)
4717 {
4718 delete_item(&exts->lan_sid, (struct isis_item *)lan);
4719 XFREE(MTYPE_ISIS_SUBTLV, lan);
4720 if (exts->lan_sid.count == 0)
4721 UNSET_SUBTLV(exts, EXT_LAN_ADJ_SID);
4722 }
4723
isis_tlvs_add_extended_ip_reach(struct isis_tlvs * tlvs,struct prefix_ipv4 * dest,uint32_t metric,bool external,struct sr_prefix_cfg * pcfg)4724 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs,
4725 struct prefix_ipv4 *dest, uint32_t metric,
4726 bool external, struct sr_prefix_cfg *pcfg)
4727 {
4728 struct isis_extended_ip_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
4729
4730 r->metric = metric;
4731 memcpy(&r->prefix, dest, sizeof(*dest));
4732 apply_mask_ipv4(&r->prefix);
4733 if (pcfg) {
4734 struct isis_prefix_sid *psid =
4735 XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*psid));
4736
4737 isis_sr_prefix_cfg2subtlv(pcfg, external, psid);
4738 r->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH);
4739 append_item(&r->subtlvs->prefix_sids, (struct isis_item *)psid);
4740 }
4741 append_item(&tlvs->extended_ip_reach, (struct isis_item *)r);
4742 }
4743
isis_tlvs_add_ipv6_reach(struct isis_tlvs * tlvs,uint16_t mtid,struct prefix_ipv6 * dest,uint32_t metric,bool external,struct sr_prefix_cfg * pcfg)4744 void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid,
4745 struct prefix_ipv6 *dest, uint32_t metric,
4746 bool external, struct sr_prefix_cfg *pcfg)
4747 {
4748 struct isis_ipv6_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
4749
4750 r->metric = metric;
4751 memcpy(&r->prefix, dest, sizeof(*dest));
4752 apply_mask_ipv6(&r->prefix);
4753 if (pcfg) {
4754 struct isis_prefix_sid *psid =
4755 XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*psid));
4756
4757 isis_sr_prefix_cfg2subtlv(pcfg, external, psid);
4758 r->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH);
4759 append_item(&r->subtlvs->prefix_sids, (struct isis_item *)psid);
4760 }
4761
4762 struct isis_item_list *l;
4763 l = (mtid == ISIS_MT_IPV4_UNICAST)
4764 ? &tlvs->ipv6_reach
4765 : isis_get_mt_items(&tlvs->mt_ipv6_reach, mtid);
4766 append_item(l, (struct isis_item *)r);
4767 }
4768
isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs * tlvs,uint16_t mtid,struct prefix_ipv6 * dest,struct prefix_ipv6 * src,uint32_t metric)4769 void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid,
4770 struct prefix_ipv6 *dest,
4771 struct prefix_ipv6 *src,
4772 uint32_t metric)
4773 {
4774 isis_tlvs_add_ipv6_reach(tlvs, mtid, dest, metric, false, NULL);
4775 struct isis_item_list *l = isis_get_mt_items(&tlvs->mt_ipv6_reach,
4776 mtid);
4777
4778 struct isis_ipv6_reach *r = (struct isis_ipv6_reach*)last_item(l);
4779 r->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH);
4780 r->subtlvs->source_prefix = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*src));
4781 memcpy(r->subtlvs->source_prefix, src, sizeof(*src));
4782 }
4783
isis_tlvs_add_oldstyle_reach(struct isis_tlvs * tlvs,uint8_t * id,uint8_t metric)4784 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id,
4785 uint8_t metric)
4786 {
4787 struct isis_oldstyle_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
4788
4789 r->metric = metric;
4790 memcpy(r->id, id, sizeof(r->id));
4791 append_item(&tlvs->oldstyle_reach, (struct isis_item *)r);
4792 }
4793
isis_tlvs_add_extended_reach(struct isis_tlvs * tlvs,uint16_t mtid,uint8_t * id,uint32_t metric,struct isis_ext_subtlvs * exts)4794 void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid,
4795 uint8_t *id, uint32_t metric,
4796 struct isis_ext_subtlvs *exts)
4797 {
4798 struct isis_extended_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
4799
4800 memcpy(r->id, id, sizeof(r->id));
4801 r->metric = metric;
4802 if (exts)
4803 r->subtlvs = copy_item_ext_subtlvs(exts, mtid);
4804
4805 struct isis_item_list *l;
4806 if (mtid == ISIS_MT_IPV4_UNICAST)
4807 l = &tlvs->extended_reach;
4808 else
4809 l = isis_get_mt_items(&tlvs->mt_reach, mtid);
4810 append_item(l, (struct isis_item *)r);
4811 }
4812
isis_tlvs_add_threeway_adj(struct isis_tlvs * tlvs,enum isis_threeway_state state,uint32_t local_circuit_id,const uint8_t * neighbor_id,uint32_t neighbor_circuit_id)4813 void isis_tlvs_add_threeway_adj(struct isis_tlvs *tlvs,
4814 enum isis_threeway_state state,
4815 uint32_t local_circuit_id,
4816 const uint8_t *neighbor_id,
4817 uint32_t neighbor_circuit_id)
4818 {
4819 assert(!tlvs->threeway_adj);
4820
4821 tlvs->threeway_adj = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->threeway_adj));
4822 tlvs->threeway_adj->state = state;
4823 tlvs->threeway_adj->local_circuit_id = local_circuit_id;
4824
4825 if (neighbor_id) {
4826 tlvs->threeway_adj->neighbor_set = true;
4827 memcpy(tlvs->threeway_adj->neighbor_id, neighbor_id, 6);
4828 tlvs->threeway_adj->neighbor_circuit_id = neighbor_circuit_id;
4829 }
4830 }
4831
isis_tlvs_add_spine_leaf(struct isis_tlvs * tlvs,uint8_t tier,bool has_tier,bool is_leaf,bool is_spine,bool is_backup)4832 void isis_tlvs_add_spine_leaf(struct isis_tlvs *tlvs, uint8_t tier,
4833 bool has_tier, bool is_leaf, bool is_spine,
4834 bool is_backup)
4835 {
4836 assert(!tlvs->spine_leaf);
4837
4838 tlvs->spine_leaf = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->spine_leaf));
4839
4840 if (has_tier) {
4841 tlvs->spine_leaf->tier = tier;
4842 }
4843
4844 tlvs->spine_leaf->has_tier = has_tier;
4845 tlvs->spine_leaf->is_leaf = is_leaf;
4846 tlvs->spine_leaf->is_spine = is_spine;
4847 tlvs->spine_leaf->is_backup = is_backup;
4848 }
4849
4850 struct isis_mt_router_info *
isis_tlvs_lookup_mt_router_info(struct isis_tlvs * tlvs,uint16_t mtid)4851 isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid)
4852 {
4853 if (!tlvs || tlvs->mt_router_info_empty)
4854 return NULL;
4855
4856 struct isis_mt_router_info *rv;
4857 for (rv = (struct isis_mt_router_info *)tlvs->mt_router_info.head; rv;
4858 rv = rv->next) {
4859 if (rv->mtid == mtid)
4860 return rv;
4861 }
4862
4863 return NULL;
4864 }
4865
isis_tlvs_set_purge_originator(struct isis_tlvs * tlvs,const uint8_t * generator,const uint8_t * sender)4866 void isis_tlvs_set_purge_originator(struct isis_tlvs *tlvs,
4867 const uint8_t *generator,
4868 const uint8_t *sender)
4869 {
4870 assert(!tlvs->purge_originator);
4871
4872 tlvs->purge_originator = XCALLOC(MTYPE_ISIS_TLV,
4873 sizeof(*tlvs->purge_originator));
4874 memcpy(tlvs->purge_originator->generator, generator,
4875 sizeof(tlvs->purge_originator->generator));
4876 if (sender) {
4877 tlvs->purge_originator->sender_set = true;
4878 memcpy(tlvs->purge_originator->sender, sender,
4879 sizeof(tlvs->purge_originator->sender));
4880 }
4881 }
4882