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