blob: 1d29d78287b23ffca0f991c6c2a674ae22d97be7 [file] [log] [blame]
jardineb5d44e2003-12-23 08:09:43 +00001/*
2 * IS-IS Rout(e)ing protocol - isis_tlv.c
3 * IS-IS TLV related routines
4 *
5 * Copyright (C) 2001,2002 Sampo Saaristo
6 * Tampere University of Technology
7 * Institute of Communications Engineering
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public Licenseas published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
12 * any later version.
13 *
14 * This program is distributed in the hope that it will be useful,but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24#include <zebra.h>
jardineb5d44e2003-12-23 08:09:43 +000025
26#include "log.h"
27#include "linklist.h"
28#include "stream.h"
29#include "memory.h"
30#include "prefix.h"
31#include "vty.h"
32#include "if.h"
33
34#include "isisd/dict.h"
35#include "isisd/isis_constants.h"
36#include "isisd/isis_common.h"
37#include "isisd/isis_flags.h"
38#include "isisd/isis_circuit.h"
39#include "isisd/isis_tlv.h"
40#include "isisd/isisd.h"
41#include "isisd/isis_dynhn.h"
42#include "isisd/isis_misc.h"
43#include "isisd/isis_pdu.h"
44#include "isisd/isis_lsp.h"
Olivier Dugeon4f593572016-04-19 19:03:05 +020045#include "isisd/isis_te.h"
jardineb5d44e2003-12-23 08:09:43 +000046
jardineb5d44e2003-12-23 08:09:43 +000047void
48free_tlv (void *val)
49{
hassof390d2c2004-09-10 20:48:21 +000050 XFREE (MTYPE_ISIS_TLV, val);
51
52 return;
jardineb5d44e2003-12-23 08:09:43 +000053}
54
55/*
56 * Called after parsing of a PDU. There shouldn't be any tlv's left, so this
57 * is only a caution to avoid memory leaks
58 */
hassof390d2c2004-09-10 20:48:21 +000059void
jardineb5d44e2003-12-23 08:09:43 +000060free_tlvs (struct tlvs *tlvs)
61{
hassof390d2c2004-09-10 20:48:21 +000062 if (tlvs->area_addrs)
hassoaac372f2005-09-01 17:52:33 +000063 list_delete (tlvs->area_addrs);
hassof390d2c2004-09-10 20:48:21 +000064 if (tlvs->is_neighs)
hassoaac372f2005-09-01 17:52:33 +000065 list_delete (tlvs->is_neighs);
hassof390d2c2004-09-10 20:48:21 +000066 if (tlvs->te_is_neighs)
hassoaac372f2005-09-01 17:52:33 +000067 list_delete (tlvs->te_is_neighs);
hassof390d2c2004-09-10 20:48:21 +000068 if (tlvs->es_neighs)
hassoaac372f2005-09-01 17:52:33 +000069 list_delete (tlvs->es_neighs);
hassof390d2c2004-09-10 20:48:21 +000070 if (tlvs->lsp_entries)
hassoaac372f2005-09-01 17:52:33 +000071 list_delete (tlvs->lsp_entries);
hassof390d2c2004-09-10 20:48:21 +000072 if (tlvs->prefix_neighs)
hassoaac372f2005-09-01 17:52:33 +000073 list_delete (tlvs->prefix_neighs);
Josh Bailey3f045a02012-03-24 08:35:20 -070074 if (tlvs->lan_neighs)
75 list_delete (tlvs->lan_neighs);
hassof390d2c2004-09-10 20:48:21 +000076 if (tlvs->ipv4_addrs)
hassoaac372f2005-09-01 17:52:33 +000077 list_delete (tlvs->ipv4_addrs);
hassof390d2c2004-09-10 20:48:21 +000078 if (tlvs->ipv4_int_reachs)
hassoaac372f2005-09-01 17:52:33 +000079 list_delete (tlvs->ipv4_int_reachs);
hassof390d2c2004-09-10 20:48:21 +000080 if (tlvs->ipv4_ext_reachs)
hassoaac372f2005-09-01 17:52:33 +000081 list_delete (tlvs->ipv4_ext_reachs);
hassof390d2c2004-09-10 20:48:21 +000082 if (tlvs->te_ipv4_reachs)
hassoaac372f2005-09-01 17:52:33 +000083 list_delete (tlvs->te_ipv4_reachs);
jardineb5d44e2003-12-23 08:09:43 +000084#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +000085 if (tlvs->ipv6_addrs)
hassoaac372f2005-09-01 17:52:33 +000086 list_delete (tlvs->ipv6_addrs);
hassof390d2c2004-09-10 20:48:21 +000087 if (tlvs->ipv6_reachs)
hassoaac372f2005-09-01 17:52:33 +000088 list_delete (tlvs->ipv6_reachs);
jardineb5d44e2003-12-23 08:09:43 +000089#endif /* HAVE_IPV6 */
Josh Bailey3f045a02012-03-24 08:35:20 -070090
91 memset (tlvs, 0, sizeof (struct tlvs));
92
jardineb5d44e2003-12-23 08:09:43 +000093 return;
94}
95
96/*
97 * Parses the tlvs found in the variant length part of the PDU.
98 * Caller tells with flags in "expected" which TLV's it is interested in.
99 */
hassof390d2c2004-09-10 20:48:21 +0000100int
101parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
Josh Bailey3f045a02012-03-24 08:35:20 -0700102 u_int32_t * found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset)
jardineb5d44e2003-12-23 08:09:43 +0000103{
hassof390d2c2004-09-10 20:48:21 +0000104 u_char type, length;
105 struct lan_neigh *lan_nei;
106 struct area_addr *area_addr;
107 struct is_neigh *is_nei;
108 struct te_is_neigh *te_is_nei;
109 struct es_neigh *es_nei;
110 struct lsp_entry *lsp_entry;
111 struct in_addr *ipv4_addr;
112 struct ipv4_reachability *ipv4_reach;
113 struct te_ipv4_reachability *te_ipv4_reach;
jardineb5d44e2003-12-23 08:09:43 +0000114#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000115 struct in6_addr *ipv6_addr;
116 struct ipv6_reachability *ipv6_reach;
117 int prefix_octets;
jardineb5d44e2003-12-23 08:09:43 +0000118#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000119 int value_len, retval = ISIS_OK;
David Lamparterf02a0992012-05-08 13:15:45 +0200120 u_char *start = stream, *pnt = stream, *endpnt;
jardineb5d44e2003-12-23 08:09:43 +0000121
122 *found = 0;
123 memset (tlvs, 0, sizeof (struct tlvs));
hassof390d2c2004-09-10 20:48:21 +0000124
125 while (pnt < stream + size - 2)
126 {
127 type = *pnt;
128 length = *(pnt + 1);
129 pnt += 2;
130 value_len = 0;
131 if (pnt + length > stream + size)
132 {
133 zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet "
134 "boundaries", areatag, type, length);
135 retval = ISIS_WARNING;
136 break;
137 }
138 switch (type)
139 {
140 case AREA_ADDRESSES:
141 /* +-------+-------+-------+-------+-------+-------+-------+-------+
142 * | Address Length |
143 * +-------+-------+-------+-------+-------+-------+-------+-------+
144 * | Area Address |
145 * +-------+-------+-------+-------+-------+-------+-------+-------+
146 * : :
147 */
148 *found |= TLVFLAG_AREA_ADDRS;
jardineb5d44e2003-12-23 08:09:43 +0000149#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000150 zlog_debug ("TLV Area Adresses len %d", length);
jardineb5d44e2003-12-23 08:09:43 +0000151#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000152 if (*expected & TLVFLAG_AREA_ADDRS)
153 {
154 while (length > value_len)
155 {
156 area_addr = (struct area_addr *) pnt;
157 value_len += area_addr->addr_len + 1;
158 pnt += area_addr->addr_len + 1;
159 if (!tlvs->area_addrs)
160 tlvs->area_addrs = list_new ();
161 listnode_add (tlvs->area_addrs, area_addr);
162 }
163 }
164 else
165 {
166 pnt += length;
167 }
168 break;
jardineb5d44e2003-12-23 08:09:43 +0000169
hassof390d2c2004-09-10 20:48:21 +0000170 case IS_NEIGHBOURS:
171 *found |= TLVFLAG_IS_NEIGHS;
jardineb5d44e2003-12-23 08:09:43 +0000172#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000173 zlog_debug ("ISIS-TLV (%s): IS Neighbours length %d",
174 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000175#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000176 if (TLVFLAG_IS_NEIGHS & *expected)
177 {
178 /* +-------+-------+-------+-------+-------+-------+-------+-------+
179 * | Virtual Flag |
180 * +-------+-------+-------+-------+-------+-------+-------+-------+
181 */
hassof390d2c2004-09-10 20:48:21 +0000182 pnt++;
183 value_len++;
184 /* +-------+-------+-------+-------+-------+-------+-------+-------+
185 * | 0 | I/E | Default Metric |
186 * +-------+-------+-------+-------+-------+-------+-------+-------+
187 * | S | I/E | Delay Metric |
188 * +-------+-------+-------+-------+-------+-------+-------+-------+
189 * | S | I/E | Expense Metric |
190 * +-------+-------+-------+-------+-------+-------+-------+-------+
191 * | S | I/E | Error Metric |
192 * +-------+-------+-------+-------+-------+-------+-------+-------+
193 * | Neighbour ID |
194 * +---------------------------------------------------------------+
195 * : :
196 */
197 while (length > value_len)
198 {
199 is_nei = (struct is_neigh *) pnt;
200 value_len += 4 + ISIS_SYS_ID_LEN + 1;
201 pnt += 4 + ISIS_SYS_ID_LEN + 1;
202 if (!tlvs->is_neighs)
203 tlvs->is_neighs = list_new ();
204 listnode_add (tlvs->is_neighs, is_nei);
205 }
206 }
207 else
208 {
209 pnt += length;
210 }
211 break;
jardineb5d44e2003-12-23 08:09:43 +0000212
hassof390d2c2004-09-10 20:48:21 +0000213 case TE_IS_NEIGHBOURS:
214 /* +-------+-------+-------+-------+-------+-------+-------+-------+
215 * | Neighbour ID | 7
216 * +---------------------------------------------------------------+
217 * | TE Metric | 3
218 * +---------------------------------------------------------------+
219 * | SubTLVs Length | 1
220 * +---------------------------------------------------------------+
221 * : :
222 */
223 *found |= TLVFLAG_TE_IS_NEIGHS;
jardineb5d44e2003-12-23 08:09:43 +0000224#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000225 zlog_debug ("ISIS-TLV (%s): Extended IS Neighbours length %d",
hassof390d2c2004-09-10 20:48:21 +0000226 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000227#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000228 if (TLVFLAG_TE_IS_NEIGHS & *expected)
229 {
230 while (length > value_len)
231 {
232 te_is_nei = (struct te_is_neigh *) pnt;
Olivier Dugeon4f593572016-04-19 19:03:05 +0200233 value_len += IS_NEIGHBOURS_LEN;
234 pnt += IS_NEIGHBOURS_LEN;
235 /* FIXME - subtlvs are handled here, for now we skip */
236 /* FIXME: All TE SubTLVs are not necessary present in LSP PDU. */
237 /* So, it must be copied in a new te_is_neigh structure */
238 /* rather than just initialize pointer to the original LSP PDU */
239 /* to avoid consider the rest of lspdu as subTLVs or buffer overflow */
240 if (IS_MPLS_TE(isisMplsTE))
241 {
242 struct te_is_neigh *new = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct te_is_neigh));
243 memcpy(new->neigh_id, te_is_nei->neigh_id, ISIS_SYS_ID_LEN + 1);
244 memcpy(new->te_metric, te_is_nei->te_metric, 3);
245 new->sub_tlvs_length = te_is_nei->sub_tlvs_length;
246 memcpy(new->sub_tlvs, pnt, te_is_nei->sub_tlvs_length);
247 te_is_nei = new;
248 }
249 /* Skip SUB TLVs payload */
hassof390d2c2004-09-10 20:48:21 +0000250 value_len += te_is_nei->sub_tlvs_length;
251 pnt += te_is_nei->sub_tlvs_length;
jardineb5d44e2003-12-23 08:09:43 +0000252
hassof390d2c2004-09-10 20:48:21 +0000253 if (!tlvs->te_is_neighs)
254 tlvs->te_is_neighs = list_new ();
255 listnode_add (tlvs->te_is_neighs, te_is_nei);
256 }
257 }
258 else
259 {
260 pnt += length;
261 }
262 break;
jardineb5d44e2003-12-23 08:09:43 +0000263
hassof390d2c2004-09-10 20:48:21 +0000264 case ES_NEIGHBOURS:
265 /* +-------+-------+-------+-------+-------+-------+-------+-------+
266 * | 0 | I/E | Default Metric |
267 * +-------+-------+-------+-------+-------+-------+-------+-------+
268 * | S | I/E | Delay Metric |
269 * +-------+-------+-------+-------+-------+-------+-------+-------+
270 * | S | I/E | Expense Metric |
271 * +-------+-------+-------+-------+-------+-------+-------+-------+
272 * | S | I/E | Error Metric |
273 * +-------+-------+-------+-------+-------+-------+-------+-------+
274 * | Neighbour ID |
275 * +---------------------------------------------------------------+
276 * | Neighbour ID |
277 * +---------------------------------------------------------------+
278 * : :
279 */
jardineb5d44e2003-12-23 08:09:43 +0000280#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000281 zlog_debug ("ISIS-TLV (%s): ES Neighbours length %d",
hassof390d2c2004-09-10 20:48:21 +0000282 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000283#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000284 *found |= TLVFLAG_ES_NEIGHS;
285 if (*expected & TLVFLAG_ES_NEIGHS)
286 {
287 es_nei = (struct es_neigh *) pnt;
288 value_len += 4;
289 pnt += 4;
290 while (length > value_len)
291 {
292 /* FIXME FIXME FIXME - add to the list */
293 /* sys_id->id = pnt; */
294 value_len += ISIS_SYS_ID_LEN;
295 pnt += ISIS_SYS_ID_LEN;
296 /* if (!es_nei->neigh_ids) es_nei->neigh_ids = sysid; */
297 }
298 if (!tlvs->es_neighs)
299 tlvs->es_neighs = list_new ();
300 listnode_add (tlvs->es_neighs, es_nei);
301 }
302 else
303 {
304 pnt += length;
305 }
306 break;
jardineb5d44e2003-12-23 08:09:43 +0000307
hassof390d2c2004-09-10 20:48:21 +0000308 case LAN_NEIGHBOURS:
309 /* +-------+-------+-------+-------+-------+-------+-------+-------+
310 * | LAN Address |
311 * +-------+-------+-------+-------+-------+-------+-------+-------+
312 * : :
313 */
314 *found |= TLVFLAG_LAN_NEIGHS;
jardineb5d44e2003-12-23 08:09:43 +0000315#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000316 zlog_debug ("ISIS-TLV (%s): LAN Neigbours length %d",
317 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000318#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000319 if (TLVFLAG_LAN_NEIGHS & *expected)
320 {
321 while (length > value_len)
322 {
323 lan_nei = (struct lan_neigh *) pnt;
324 if (!tlvs->lan_neighs)
325 tlvs->lan_neighs = list_new ();
326 listnode_add (tlvs->lan_neighs, lan_nei);
327 value_len += ETH_ALEN;
328 pnt += ETH_ALEN;
329 }
330 }
331 else
332 {
333 pnt += length;
334 }
335 break;
jardineb5d44e2003-12-23 08:09:43 +0000336
hassof390d2c2004-09-10 20:48:21 +0000337 case PADDING:
jardineb5d44e2003-12-23 08:09:43 +0000338#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000339 zlog_debug ("TLV padding %d", length);
jardineb5d44e2003-12-23 08:09:43 +0000340#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000341 pnt += length;
342 break;
jardineb5d44e2003-12-23 08:09:43 +0000343
hassof390d2c2004-09-10 20:48:21 +0000344 case LSP_ENTRIES:
345 /* +-------+-------+-------+-------+-------+-------+-------+-------+
346 * | Remaining Lifetime | 2
347 * +-------+-------+-------+-------+-------+-------+-------+-------+
348 * | LSP ID | id+2
349 * +-------+-------+-------+-------+-------+-------+-------+-------+
350 * | LSP Sequence Number | 4
351 * +-------+-------+-------+-------+-------+-------+-------+-------+
352 * | Checksum | 2
353 * +-------+-------+-------+-------+-------+-------+-------+-------+
354 */
jardineb5d44e2003-12-23 08:09:43 +0000355#ifdef EXTREME_TLV_DEBUG
hasso92365882005-01-18 13:53:33 +0000356 zlog_debug ("ISIS-TLV (%s): LSP Entries length %d", areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000357#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000358 *found |= TLVFLAG_LSP_ENTRIES;
359 if (TLVFLAG_LSP_ENTRIES & *expected)
360 {
361 while (length > value_len)
362 {
363 lsp_entry = (struct lsp_entry *) pnt;
364 value_len += 10 + ISIS_SYS_ID_LEN;
365 pnt += 10 + ISIS_SYS_ID_LEN;
366 if (!tlvs->lsp_entries)
367 tlvs->lsp_entries = list_new ();
368 listnode_add (tlvs->lsp_entries, lsp_entry);
369 }
370 }
371 else
372 {
373 pnt += length;
374 }
375 break;
jardineb5d44e2003-12-23 08:09:43 +0000376
hassof390d2c2004-09-10 20:48:21 +0000377 case CHECKSUM:
378 /* +-------+-------+-------+-------+-------+-------+-------+-------+
379 * | 16 bit fletcher CHECKSUM |
380 * +-------+-------+-------+-------+-------+-------+-------+-------+
381 * : :
382 */
383 *found |= TLVFLAG_CHECKSUM;
jardineb5d44e2003-12-23 08:09:43 +0000384#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000385 zlog_debug ("ISIS-TLV (%s): Checksum length %d", areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000386#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000387 if (*expected & TLVFLAG_CHECKSUM)
388 {
389 tlvs->checksum = (struct checksum *) pnt;
390 }
391 pnt += length;
392 break;
jardineb5d44e2003-12-23 08:09:43 +0000393
hassof390d2c2004-09-10 20:48:21 +0000394 case PROTOCOLS_SUPPORTED:
395 /* +-------+-------+-------+-------+-------+-------+-------+-------+
396 * | NLPID |
397 * +-------+-------+-------+-------+-------+-------+-------+-------+
398 * : :
399 */
400 *found |= TLVFLAG_NLPID;
jardineb5d44e2003-12-23 08:09:43 +0000401#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000402 zlog_debug ("ISIS-TLV (%s): Protocols Supported length %d",
403 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000404#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000405 if (*expected & TLVFLAG_NLPID)
406 {
407 tlvs->nlpids = (struct nlpids *) (pnt - 1);
408 }
409 pnt += length;
410 break;
jardineb5d44e2003-12-23 08:09:43 +0000411
hassof390d2c2004-09-10 20:48:21 +0000412 case IPV4_ADDR:
413 /* +-------+-------+-------+-------+-------+-------+-------+-------+
414 * + IP version 4 address + 4
415 * +-------+-------+-------+-------+-------+-------+-------+-------+
416 * : :
417 */
418 *found |= TLVFLAG_IPV4_ADDR;
jardineb5d44e2003-12-23 08:09:43 +0000419#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000420 zlog_debug ("ISIS-TLV (%s): IPv4 Address length %d",
421 areatag, length);
hassof390d2c2004-09-10 20:48:21 +0000422#endif /* EXTREME_TLV_DEBUG */
423 if (*expected & TLVFLAG_IPV4_ADDR)
424 {
425 while (length > value_len)
426 {
427 ipv4_addr = (struct in_addr *) pnt;
hassof891f442004-09-14 13:54:30 +0000428#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000429 zlog_debug ("ISIS-TLV (%s) : IP ADDR %s, pnt %p", areatag,
430 inet_ntoa (*ipv4_addr), pnt);
hassof891f442004-09-14 13:54:30 +0000431#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000432 if (!tlvs->ipv4_addrs)
433 tlvs->ipv4_addrs = list_new ();
434 listnode_add (tlvs->ipv4_addrs, ipv4_addr);
435 value_len += 4;
436 pnt += 4;
437 }
438 }
439 else
440 {
441 pnt += length;
442 }
443 break;
444
445 case AUTH_INFO:
446 *found |= TLVFLAG_AUTH_INFO;
447#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000448 zlog_debug ("ISIS-TLV (%s): IS-IS Authentication Information",
449 areatag);
jardineb5d44e2003-12-23 08:09:43 +0000450#endif
hassof390d2c2004-09-10 20:48:21 +0000451 if (*expected & TLVFLAG_AUTH_INFO)
452 {
453 tlvs->auth_info.type = *pnt;
Josh Bailey3f045a02012-03-24 08:35:20 -0700454 if (length == 0)
455 {
456 zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) "
457 "incorrect.", areatag, type, length);
458 return ISIS_WARNING;
459 }
460 --length;
461 tlvs->auth_info.len = length;
hassof390d2c2004-09-10 20:48:21 +0000462 pnt++;
Josh Bailey3f045a02012-03-24 08:35:20 -0700463 memcpy (tlvs->auth_info.passwd, pnt, length);
464 /* Return the authentication tlv pos for later computation
465 * of MD5 (RFC 5304, 2)
466 */
467 if (auth_tlv_offset)
468 *auth_tlv_offset += (pnt - start - 3);
469 pnt += length;
hassof390d2c2004-09-10 20:48:21 +0000470 }
471 else
472 {
473 pnt += length;
474 }
475 break;
jardineb5d44e2003-12-23 08:09:43 +0000476
hassof390d2c2004-09-10 20:48:21 +0000477 case DYNAMIC_HOSTNAME:
478 *found |= TLVFLAG_DYN_HOSTNAME;
jardineb5d44e2003-12-23 08:09:43 +0000479#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000480 zlog_debug ("ISIS-TLV (%s): Dynamic Hostname length %d",
481 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000482#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000483 if (*expected & TLVFLAG_DYN_HOSTNAME)
484 {
485 /* the length is also included in the pointed struct */
486 tlvs->hostname = (struct hostname *) (pnt - 1);
487 }
488 pnt += length;
489 break;
jardineb5d44e2003-12-23 08:09:43 +0000490
hassof390d2c2004-09-10 20:48:21 +0000491 case TE_ROUTER_ID:
492 /* +---------------------------------------------------------------+
493 * + Router ID + 4
494 * +---------------------------------------------------------------+
495 */
496 *found |= TLVFLAG_TE_ROUTER_ID;
jardineb5d44e2003-12-23 08:09:43 +0000497#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000498 zlog_debug ("ISIS-TLV (%s): TE Router ID %d", areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000499#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000500 if (*expected & TLVFLAG_TE_ROUTER_ID)
hasso1cd80842004-10-07 20:07:40 +0000501 tlvs->router_id = (struct te_router_id *) (pnt);
hassof390d2c2004-09-10 20:48:21 +0000502 pnt += length;
503 break;
jardineb5d44e2003-12-23 08:09:43 +0000504
hassof390d2c2004-09-10 20:48:21 +0000505 case IPV4_INT_REACHABILITY:
506 /* +-------+-------+-------+-------+-------+-------+-------+-------+
507 * | 0 | I/E | Default Metric | 1
508 * +-------+-------+-------+-------+-------+-------+-------+-------+
509 * | S | I/E | Delay Metric | 1
510 * +-------+-------+-------+-------+-------+-------+-------+-------+
511 * | S | I/E | Expense Metric | 1
512 * +-------+-------+-------+-------+-------+-------+-------+-------+
513 * | S | I/E | Error Metric | 1
514 * +-------+-------+-------+-------+-------+-------+-------+-------+
515 * | ip address | 4
516 * +---------------------------------------------------------------+
517 * | address mask | 4
518 * +---------------------------------------------------------------+
519 * : :
520 */
521 *found |= TLVFLAG_IPV4_INT_REACHABILITY;
jardineb5d44e2003-12-23 08:09:43 +0000522#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000523 zlog_debug ("ISIS-TLV (%s): IPv4 internal Reachability length %d",
524 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000525#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000526 if (*expected & TLVFLAG_IPV4_INT_REACHABILITY)
527 {
528 while (length > value_len)
529 {
530 ipv4_reach = (struct ipv4_reachability *) pnt;
531 if (!tlvs->ipv4_int_reachs)
532 tlvs->ipv4_int_reachs = list_new ();
533 listnode_add (tlvs->ipv4_int_reachs, ipv4_reach);
534 value_len += 12;
535 pnt += 12;
536 }
537 }
538 else
539 {
540 pnt += length;
541 }
542 break;
jardineb5d44e2003-12-23 08:09:43 +0000543
hassof390d2c2004-09-10 20:48:21 +0000544 case IPV4_EXT_REACHABILITY:
545 /* +-------+-------+-------+-------+-------+-------+-------+-------+
546 * | 0 | I/E | Default Metric | 1
547 * +-------+-------+-------+-------+-------+-------+-------+-------+
548 * | S | I/E | Delay Metric | 1
549 * +-------+-------+-------+-------+-------+-------+-------+-------+
550 * | S | I/E | Expense Metric | 1
551 * +-------+-------+-------+-------+-------+-------+-------+-------+
552 * | S | I/E | Error Metric | 1
553 * +-------+-------+-------+-------+-------+-------+-------+-------+
554 * | ip address | 4
555 * +---------------------------------------------------------------+
556 * | address mask | 4
557 * +---------------------------------------------------------------+
558 * : :
559 */
560 *found |= TLVFLAG_IPV4_EXT_REACHABILITY;
jardineb5d44e2003-12-23 08:09:43 +0000561#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000562 zlog_debug ("ISIS-TLV (%s): IPv4 external Reachability length %d",
563 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000564#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000565 if (*expected & TLVFLAG_IPV4_EXT_REACHABILITY)
566 {
567 while (length > value_len)
568 {
569 ipv4_reach = (struct ipv4_reachability *) pnt;
570 if (!tlvs->ipv4_ext_reachs)
571 tlvs->ipv4_ext_reachs = list_new ();
572 listnode_add (tlvs->ipv4_ext_reachs, ipv4_reach);
573 value_len += 12;
574 pnt += 12;
575 }
576 }
577 else
578 {
579 pnt += length;
580 }
581 break;
jardineb5d44e2003-12-23 08:09:43 +0000582
hassof390d2c2004-09-10 20:48:21 +0000583 case TE_IPV4_REACHABILITY:
584 /* +-------+-------+-------+-------+-------+-------+-------+-------+
585 * | TE Metric | 4
586 * +-------+-------+-------+-------+-------+-------+-------+-------+
587 * | U/D | sTLV? | Prefix Mask Len | 1
588 * +-------+-------+-------+-------+-------+-------+-------+-------+
589 * | Prefix | 0-4
590 * +---------------------------------------------------------------+
591 * | sub tlvs |
592 * +---------------------------------------------------------------+
593 * : :
594 */
595 *found |= TLVFLAG_TE_IPV4_REACHABILITY;
jardineb5d44e2003-12-23 08:09:43 +0000596#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000597 zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d",
598 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000599#endif /* EXTREME_TLV_DEBUG */
David Lamparterf02a0992012-05-08 13:15:45 +0200600 endpnt = pnt + length;
hassof390d2c2004-09-10 20:48:21 +0000601 if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
602 {
603 while (length > value_len)
604 {
605 te_ipv4_reach = (struct te_ipv4_reachability *) pnt;
David Lamparterf02a0992012-05-08 13:15:45 +0200606 if ((te_ipv4_reach->control & 0x3F) > IPV4_MAX_BITLEN)
607 {
608 zlog_warn ("ISIS-TLV (%s): invalid IPv4 extended reach"
609 "ability prefix length %d", areatag,
610 te_ipv4_reach->control & 0x3F);
611 retval = ISIS_WARNING;
612 break;
613 }
hassof390d2c2004-09-10 20:48:21 +0000614 if (!tlvs->te_ipv4_reachs)
615 tlvs->te_ipv4_reachs = list_new ();
616 listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach);
617 /* this trickery is permitable since no subtlvs are defined */
618 value_len += 5 + ((te_ipv4_reach->control & 0x3F) ?
619 ((((te_ipv4_reach->control & 0x3F) -
620 1) >> 3) + 1) : 0);
621 pnt += 5 + ((te_ipv4_reach->control & 0x3F) ?
622 ((((te_ipv4_reach->control & 0x3F) - 1) >> 3) + 1) : 0);
623 }
624 }
David Lamparterf02a0992012-05-08 13:15:45 +0200625
626 pnt = endpnt;
hassof390d2c2004-09-10 20:48:21 +0000627 break;
jardineb5d44e2003-12-23 08:09:43 +0000628
629#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000630 case IPV6_ADDR:
631 /* +-------+-------+-------+-------+-------+-------+-------+-------+
632 * + IP version 6 address + 16
633 * +-------+-------+-------+-------+-------+-------+-------+-------+
634 * : :
635 */
636 *found |= TLVFLAG_IPV6_ADDR;
jardineb5d44e2003-12-23 08:09:43 +0000637#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000638 zlog_debug ("ISIS-TLV (%s): IPv6 Address length %d",
639 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000640#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000641 if (*expected & TLVFLAG_IPV6_ADDR)
642 {
643 while (length > value_len)
644 {
645 ipv6_addr = (struct in6_addr *) pnt;
646 if (!tlvs->ipv6_addrs)
647 tlvs->ipv6_addrs = list_new ();
648 listnode_add (tlvs->ipv6_addrs, ipv6_addr);
649 value_len += 16;
650 pnt += 16;
651 }
652 }
653 else
654 {
655 pnt += length;
656 }
657 break;
jardineb5d44e2003-12-23 08:09:43 +0000658
hassof390d2c2004-09-10 20:48:21 +0000659 case IPV6_REACHABILITY:
660 /* +-------+-------+-------+-------+-------+-------+-------+-------+
661 * | Default Metric | 4
662 * +-------+-------+-------+-------+-------+-------+-------+-------+
663 * | Control Informantion |
664 * +---------------------------------------------------------------+
665 * | IPv6 Prefix Length |--+
666 * +---------------------------------------------------------------+ |
667 * | IPv6 Prefix |<-+
668 * +---------------------------------------------------------------+
669 */
670 *found |= TLVFLAG_IPV6_REACHABILITY;
David Lamparterf02a0992012-05-08 13:15:45 +0200671 endpnt = pnt + length;
672
hassof390d2c2004-09-10 20:48:21 +0000673 if (*expected & TLVFLAG_IPV6_REACHABILITY)
674 {
675 while (length > value_len)
676 {
677 ipv6_reach = (struct ipv6_reachability *) pnt;
David Lamparterf02a0992012-05-08 13:15:45 +0200678 if (ipv6_reach->prefix_len > IPV6_MAX_BITLEN)
679 {
680 zlog_warn ("ISIS-TLV (%s): invalid IPv6 extended reach"
681 "ability prefix length %d", areatag,
682 ipv6_reach->prefix_len);
683 retval = ISIS_WARNING;
684 break;
685 }
686
hassof390d2c2004-09-10 20:48:21 +0000687 prefix_octets = ((ipv6_reach->prefix_len + 7) / 8);
688 value_len += prefix_octets + 6;
689 pnt += prefix_octets + 6;
690 /* FIXME: sub-tlvs */
691 if (!tlvs->ipv6_reachs)
692 tlvs->ipv6_reachs = list_new ();
693 listnode_add (tlvs->ipv6_reachs, ipv6_reach);
694 }
695 }
David Lamparterf02a0992012-05-08 13:15:45 +0200696
697 pnt = endpnt;
hassof390d2c2004-09-10 20:48:21 +0000698 break;
jardineb5d44e2003-12-23 08:09:43 +0000699#endif /* HAVE_IPV6 */
700
hassof390d2c2004-09-10 20:48:21 +0000701 case WAY3_HELLO:
702 /* +---------------------------------------------------------------+
703 * | Adjacency state | 1
704 * +---------------------------------------------------------------+
705 * | Extended Local Circuit ID | 4
706 * +---------------------------------------------------------------+
707 * | Neighbor System ID (If known) | 0-8
708 * (probably 6)
709 * +---------------------------------------------------------------+
710 * | Neighbor Local Circuit ID (If known) | 4
711 * +---------------------------------------------------------------+
712 */
713 *found |= TLVFLAG_3WAY_HELLO;
714 if (*expected & TLVFLAG_3WAY_HELLO)
715 {
716 while (length > value_len)
717 {
718 /* FIXME: make this work */
jardineb5d44e2003-12-23 08:09:43 +0000719/* Adjacency State (one octet):
720 0 = Up
721 1 = Initializing
722 2 = Down
723 Extended Local Circuit ID (four octets)
724 Neighbor System ID if known (zero to eight octets)
725 Neighbor Extended Local Circuit ID (four octets, if Neighbor
726 System ID is present) */
hassof390d2c2004-09-10 20:48:21 +0000727 pnt += length;
David Lampartere8aca322012-11-27 01:10:30 +0000728 value_len += length;
hassof390d2c2004-09-10 20:48:21 +0000729 }
730 }
731 else
732 {
733 pnt += length;
734 }
jardineb5d44e2003-12-23 08:09:43 +0000735
hassof390d2c2004-09-10 20:48:21 +0000736 break;
737 case GRACEFUL_RESTART:
738 /* +-------+-------+-------+-------+-------+-------+-------+-------+
739 * | Reserved | SA | RA | RR | 1
740 * +-------+-------+-------+-------+-------+-------+-------+-------+
741 * | Remaining Time | 2
742 * +---------------------------------------------------------------+
743 * | Restarting Neighbor ID (If known) | 0-8
744 * +---------------------------------------------------------------+
745 */
746 *found |= TLVFLAG_GRACEFUL_RESTART;
747 if (*expected & TLVFLAG_GRACEFUL_RESTART)
748 {
749 /* FIXME: make this work */
750 }
751 pnt += length;
752 break;
jardineb5d44e2003-12-23 08:09:43 +0000753
hassof390d2c2004-09-10 20:48:21 +0000754 default:
755 zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
756 areatag, type, length);
jardineb5d44e2003-12-23 08:09:43 +0000757
hassof390d2c2004-09-10 20:48:21 +0000758 pnt += length;
759 break;
760 }
jardineb5d44e2003-12-23 08:09:43 +0000761 }
hassof390d2c2004-09-10 20:48:21 +0000762
jardineb5d44e2003-12-23 08:09:43 +0000763 return retval;
764}
765
766int
hassof390d2c2004-09-10 20:48:21 +0000767add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000768{
Josh Bailey3f045a02012-03-24 08:35:20 -0700769 if ((stream_get_size (stream) - stream_get_endp (stream)) <
770 (((unsigned)len) + 2))
hassof390d2c2004-09-10 20:48:21 +0000771 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700772 zlog_warn ("No room for TLV of type %d "
773 "(total size %d available %d required %d)",
774 tag, (int)stream_get_size (stream),
775 (int)(stream_get_size (stream) - stream_get_endp (stream)),
776 len+2);
hassof390d2c2004-09-10 20:48:21 +0000777 return ISIS_WARNING;
778 }
jardineb5d44e2003-12-23 08:09:43 +0000779
hassof390d2c2004-09-10 20:48:21 +0000780 stream_putc (stream, tag); /* TAG */
781 stream_putc (stream, len); /* LENGTH */
782 stream_put (stream, value, (int) len); /* VALUE */
jardineb5d44e2003-12-23 08:09:43 +0000783
784#ifdef EXTREME_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000785 zlog_debug ("Added TLV %d len %d", tag, len);
jardineb5d44e2003-12-23 08:09:43 +0000786#endif /* EXTREME DEBUG */
787 return ISIS_OK;
788}
789
jardineb5d44e2003-12-23 08:09:43 +0000790int
hassof390d2c2004-09-10 20:48:21 +0000791tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000792{
793 struct listnode *node;
794 struct area_addr *area_addr;
795
hassof390d2c2004-09-10 20:48:21 +0000796 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000797 u_char *pos = value;
hassof390d2c2004-09-10 20:48:21 +0000798
paul1eb8ef22005-04-07 07:30:20 +0000799 for (ALL_LIST_ELEMENTS_RO (area_addrs, node, area_addr))
hassof390d2c2004-09-10 20:48:21 +0000800 {
hassof390d2c2004-09-10 20:48:21 +0000801 if (pos - value + area_addr->addr_len > 255)
802 goto err;
803 *pos = area_addr->addr_len;
804 pos++;
805 memcpy (pos, area_addr->area_addr, (int) area_addr->addr_len);
806 pos += area_addr->addr_len;
807 }
808
jardineb5d44e2003-12-23 08:09:43 +0000809 return add_tlv (AREA_ADDRESSES, pos - value, value, stream);
810
hassof390d2c2004-09-10 20:48:21 +0000811err:
jardineb5d44e2003-12-23 08:09:43 +0000812 zlog_warn ("tlv_add_area_addrs(): TLV longer than 255");
813 return ISIS_WARNING;
814}
815
hassof390d2c2004-09-10 20:48:21 +0000816int
817tlv_add_is_neighs (struct list *is_neighs, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000818{
hasso3fdb2dd2005-09-28 18:45:54 +0000819 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000820 struct is_neigh *is_neigh;
hassof390d2c2004-09-10 20:48:21 +0000821 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000822 u_char *pos = value;
823 int retval;
824
hassof390d2c2004-09-10 20:48:21 +0000825 *pos = 0; /*is_neigh->virtual; */
826 pos++;
jardineb5d44e2003-12-23 08:09:43 +0000827
hasso3fdb2dd2005-09-28 18:45:54 +0000828 for (ALL_LIST_ELEMENTS_RO (is_neighs, node, is_neigh))
hassof390d2c2004-09-10 20:48:21 +0000829 {
hassof390d2c2004-09-10 20:48:21 +0000830 if (pos - value + IS_NEIGHBOURS_LEN > 255)
831 {
832 retval = add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
833 if (retval != ISIS_OK)
834 return retval;
835 pos = value;
836 }
837 *pos = is_neigh->metrics.metric_default;
838 pos++;
839 *pos = is_neigh->metrics.metric_delay;
840 pos++;
841 *pos = is_neigh->metrics.metric_expense;
842 pos++;
843 *pos = is_neigh->metrics.metric_error;
844 pos++;
845 memcpy (pos, is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
846 pos += ISIS_SYS_ID_LEN + 1;
jardineb5d44e2003-12-23 08:09:43 +0000847 }
jardineb5d44e2003-12-23 08:09:43 +0000848
849 return add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
850}
851
jardineb5d44e2003-12-23 08:09:43 +0000852int
hassoea3be4c2005-09-26 17:11:12 +0000853tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
854{
hasso3fdb2dd2005-09-28 18:45:54 +0000855 struct listnode *node;
hassoea3be4c2005-09-26 17:11:12 +0000856 struct te_is_neigh *te_is_neigh;
857 u_char value[255];
858 u_char *pos = value;
859 int retval;
860
hasso3fdb2dd2005-09-28 18:45:54 +0000861 for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh))
hassoea3be4c2005-09-26 17:11:12 +0000862 {
Olivier Dugeon4f593572016-04-19 19:03:05 +0200863 /* FIXME: Check if Total SubTLVs size doesn't exceed 255 */
864 if (pos - value + IS_NEIGHBOURS_LEN + te_is_neigh->sub_tlvs_length > 255)
hassoea3be4c2005-09-26 17:11:12 +0000865 {
866 retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
867 if (retval != ISIS_OK)
868 return retval;
869 pos = value;
870 }
871
872 memcpy (pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
873 pos += ISIS_SYS_ID_LEN + 1;
874 memcpy (pos, te_is_neigh->te_metric, 3);
875 pos += 3;
Olivier Dugeon4f593572016-04-19 19:03:05 +0200876 /* Set the total size of Sub TLVs */
877 *pos = te_is_neigh->sub_tlvs_length;
hassoea3be4c2005-09-26 17:11:12 +0000878 pos++;
Olivier Dugeon4f593572016-04-19 19:03:05 +0200879 /* Copy Sub TLVs if any */
880 if (te_is_neigh->sub_tlvs_length > 0)
881 {
882 memcpy (pos, te_is_neigh->sub_tlvs, te_is_neigh->sub_tlvs_length);
883 pos += te_is_neigh->sub_tlvs_length;
884 }
hassoea3be4c2005-09-26 17:11:12 +0000885 }
886
887 return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
888}
889
890int
jardineb5d44e2003-12-23 08:09:43 +0000891tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream)
892{
hasso3fdb2dd2005-09-28 18:45:54 +0000893 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000894 u_char *snpa;
hassof390d2c2004-09-10 20:48:21 +0000895 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000896 u_char *pos = value;
897 int retval;
898
hasso3fdb2dd2005-09-28 18:45:54 +0000899 for (ALL_LIST_ELEMENTS_RO (lan_neighs, node, snpa))
hassof390d2c2004-09-10 20:48:21 +0000900 {
hassof390d2c2004-09-10 20:48:21 +0000901 if (pos - value + ETH_ALEN > 255)
902 {
903 retval = add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
904 if (retval != ISIS_OK)
905 return retval;
906 pos = value;
907 }
908 memcpy (pos, snpa, ETH_ALEN);
909 pos += ETH_ALEN;
jardineb5d44e2003-12-23 08:09:43 +0000910 }
jardineb5d44e2003-12-23 08:09:43 +0000911
912 return add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
913}
914
jardineb5d44e2003-12-23 08:09:43 +0000915int
916tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream)
917{
hassof390d2c2004-09-10 20:48:21 +0000918 return add_tlv (PROTOCOLS_SUPPORTED, nlpids->count, nlpids->nlpids, stream);
jardineb5d44e2003-12-23 08:09:43 +0000919}
920
hassof390d2c2004-09-10 20:48:21 +0000921int
Josh Bailey3f045a02012-03-24 08:35:20 -0700922tlv_add_authinfo (u_char auth_type, u_char auth_len, u_char *auth_value,
hassof390d2c2004-09-10 20:48:21 +0000923 struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000924{
925 u_char value[255];
926 u_char *pos = value;
Josh Bailey3f045a02012-03-24 08:35:20 -0700927 *pos++ = auth_type;
jardineb5d44e2003-12-23 08:09:43 +0000928 memcpy (pos, auth_value, auth_len);
929
930 return add_tlv (AUTH_INFO, auth_len + 1, value, stream);
931}
932
933int
934tlv_add_checksum (struct checksum *checksum, struct stream *stream)
935{
936 u_char value[255];
hassof390d2c2004-09-10 20:48:21 +0000937 u_char *pos = value;
938 return add_tlv (CHECKSUM, pos - value, value, stream);
jardineb5d44e2003-12-23 08:09:43 +0000939}
940
941int
942tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream)
943{
hasso3fdb2dd2005-09-28 18:45:54 +0000944 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000945 struct prefix_ipv4 *ipv4;
946 u_char value[255];
947 u_char *pos = value;
jardineb5d44e2003-12-23 08:09:43 +0000948
hasso3fdb2dd2005-09-28 18:45:54 +0000949 for (ALL_LIST_ELEMENTS_RO (ip_addrs, node, ipv4))
hassof390d2c2004-09-10 20:48:21 +0000950 {
hassof390d2c2004-09-10 20:48:21 +0000951 if (pos - value + IPV4_MAX_BYTELEN > 255)
952 {
David Lamparter91d799e2012-11-27 01:10:24 +0000953 /* RFC 1195 s4.2: only one tuple of 63 allowed. */
954 zlog_warn ("tlv_add_ip_addrs(): cutting off at 63 IP addresses");
955 break;
hassof390d2c2004-09-10 20:48:21 +0000956 }
957 *(u_int32_t *) pos = ipv4->prefix.s_addr;
958 pos += IPV4_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +0000959 }
hassof390d2c2004-09-10 20:48:21 +0000960
jardineb5d44e2003-12-23 08:09:43 +0000961 return add_tlv (IPV4_ADDR, pos - value, value, stream);
962}
963
hasso81ad8f62005-09-26 17:58:24 +0000964/* Used to add TLV containing just one IPv4 address - either IPv4 address TLV
965 * (in case of LSP) or TE router ID TLV. */
966int
967tlv_add_in_addr (struct in_addr *addr, struct stream *stream, u_char tag)
968{
969 u_char value[255];
970 u_char *pos = value;
971
972 memcpy (pos, addr, IPV4_MAX_BYTELEN);
973 pos += IPV4_MAX_BYTELEN;
974
975 return add_tlv (tag, pos - value, value, stream);
976}
977
jardineb5d44e2003-12-23 08:09:43 +0000978int
979tlv_add_dynamic_hostname (struct hostname *hostname, struct stream *stream)
980{
hassof390d2c2004-09-10 20:48:21 +0000981 return add_tlv (DYNAMIC_HOSTNAME, hostname->namelen, hostname->name,
982 stream);
jardineb5d44e2003-12-23 08:09:43 +0000983}
984
hassof390d2c2004-09-10 20:48:21 +0000985int
jardineb5d44e2003-12-23 08:09:43 +0000986tlv_add_lsp_entries (struct list *lsps, struct stream *stream)
987{
hasso3fdb2dd2005-09-28 18:45:54 +0000988 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000989 struct isis_lsp *lsp;
hassof390d2c2004-09-10 20:48:21 +0000990 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000991 u_char *pos = value;
992 int retval;
993
hasso3fdb2dd2005-09-28 18:45:54 +0000994 for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp))
hassof390d2c2004-09-10 20:48:21 +0000995 {
hassof390d2c2004-09-10 20:48:21 +0000996 if (pos - value + LSP_ENTRIES_LEN > 255)
997 {
998 retval = add_tlv (LSP_ENTRIES, pos - value, value, stream);
999 if (retval != ISIS_OK)
1000 return retval;
1001 pos = value;
1002 }
1003 *((u_int16_t *) pos) = lsp->lsp_header->rem_lifetime;
1004 pos += 2;
1005 memcpy (pos, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
1006 pos += ISIS_SYS_ID_LEN + 2;
1007 *((u_int32_t *) pos) = lsp->lsp_header->seq_num;
1008 pos += 4;
1009 *((u_int16_t *) pos) = lsp->lsp_header->checksum;
1010 pos += 2;
jardineb5d44e2003-12-23 08:09:43 +00001011 }
hassof390d2c2004-09-10 20:48:21 +00001012
jardineb5d44e2003-12-23 08:09:43 +00001013 return add_tlv (LSP_ENTRIES, pos - value, value, stream);
1014}
1015
Christian Frankeacf98652015-11-12 14:24:22 +01001016static int
1017tlv_add_ipv4_reachs (u_char tag, struct list *ipv4_reachs, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +00001018{
hasso3fdb2dd2005-09-28 18:45:54 +00001019 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00001020 struct ipv4_reachability *reach;
hassof390d2c2004-09-10 20:48:21 +00001021 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +00001022 u_char *pos = value;
1023 int retval;
1024
hasso3fdb2dd2005-09-28 18:45:54 +00001025 for (ALL_LIST_ELEMENTS_RO (ipv4_reachs, node, reach))
hassof390d2c2004-09-10 20:48:21 +00001026 {
hassof390d2c2004-09-10 20:48:21 +00001027 if (pos - value + IPV4_REACH_LEN > 255)
1028 {
1029 retval =
Christian Frankeacf98652015-11-12 14:24:22 +01001030 add_tlv (tag, pos - value, value, stream);
hassof390d2c2004-09-10 20:48:21 +00001031 if (retval != ISIS_OK)
1032 return retval;
1033 pos = value;
1034 }
1035 *pos = reach->metrics.metric_default;
1036 pos++;
1037 *pos = reach->metrics.metric_delay;
1038 pos++;
1039 *pos = reach->metrics.metric_expense;
1040 pos++;
1041 *pos = reach->metrics.metric_error;
1042 pos++;
1043 *(u_int32_t *) pos = reach->prefix.s_addr;
1044 pos += IPV4_MAX_BYTELEN;
1045 *(u_int32_t *) pos = reach->mask.s_addr;
1046 pos += IPV4_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +00001047 }
hassof390d2c2004-09-10 20:48:21 +00001048
Christian Frankeacf98652015-11-12 14:24:22 +01001049 return add_tlv (tag, pos - value, value, stream);
jardineb5d44e2003-12-23 08:09:43 +00001050}
1051
hassoea3be4c2005-09-26 17:11:12 +00001052int
Christian Frankeacf98652015-11-12 14:24:22 +01001053tlv_add_ipv4_int_reachs (struct list *ipv4_reachs, struct stream *stream)
1054{
1055 return tlv_add_ipv4_reachs(IPV4_INT_REACHABILITY, ipv4_reachs, stream);
1056}
1057
1058int
1059tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream)
1060{
1061 return tlv_add_ipv4_reachs(IPV4_EXT_REACHABILITY, ipv4_reachs, stream);
1062}
1063
1064
1065int
hassoea3be4c2005-09-26 17:11:12 +00001066tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream)
1067{
hasso3fdb2dd2005-09-28 18:45:54 +00001068 struct listnode *node;
hassoea3be4c2005-09-26 17:11:12 +00001069 struct te_ipv4_reachability *te_reach;
1070 u_char value[255];
1071 u_char *pos = value;
1072 u_char prefix_size;
1073 int retval;
1074
hasso3fdb2dd2005-09-28 18:45:54 +00001075 for (ALL_LIST_ELEMENTS_RO (te_ipv4_reachs, node, te_reach))
hassoea3be4c2005-09-26 17:11:12 +00001076 {
1077 prefix_size = ((((te_reach->control & 0x3F) - 1) >> 3) + 1);
1078
1079 if (pos - value + (5 + prefix_size) > 255)
1080 {
1081 retval =
Josh Bailey3f045a02012-03-24 08:35:20 -07001082 add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
hassoea3be4c2005-09-26 17:11:12 +00001083 if (retval != ISIS_OK)
1084 return retval;
1085 pos = value;
1086 }
1087 *(u_int32_t *) pos = te_reach->te_metric;
1088 pos += 4;
1089 *pos = te_reach->control;
1090 pos++;
1091 memcpy (pos, &te_reach->prefix_start, prefix_size);
1092 pos += prefix_size;
1093 }
1094
1095 return add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
1096}
1097
hassof390d2c2004-09-10 20:48:21 +00001098#ifdef HAVE_IPV6
jardineb5d44e2003-12-23 08:09:43 +00001099int
1100tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream)
1101{
hasso3fdb2dd2005-09-28 18:45:54 +00001102 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00001103 struct prefix_ipv6 *ipv6;
1104 u_char value[255];
1105 u_char *pos = value;
1106 int retval;
hassof390d2c2004-09-10 20:48:21 +00001107
hasso3fdb2dd2005-09-28 18:45:54 +00001108 for (ALL_LIST_ELEMENTS_RO (ipv6_addrs, node, ipv6))
hassof390d2c2004-09-10 20:48:21 +00001109 {
hassof390d2c2004-09-10 20:48:21 +00001110 if (pos - value + IPV6_MAX_BYTELEN > 255)
1111 {
1112 retval = add_tlv (IPV6_ADDR, pos - value, value, stream);
1113 if (retval != ISIS_OK)
1114 return retval;
1115 pos = value;
1116 }
1117 memcpy (pos, ipv6->prefix.s6_addr, IPV6_MAX_BYTELEN);
1118 pos += IPV6_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +00001119 }
hassof390d2c2004-09-10 20:48:21 +00001120
jardineb5d44e2003-12-23 08:09:43 +00001121 return add_tlv (IPV6_ADDR, pos - value, value, stream);
1122}
1123
1124int
1125tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream)
1126{
hasso3fdb2dd2005-09-28 18:45:54 +00001127 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00001128 struct ipv6_reachability *ip6reach;
1129 u_char value[255];
1130 u_char *pos = value;
1131 int retval, prefix_octets;
hassof390d2c2004-09-10 20:48:21 +00001132
hasso3fdb2dd2005-09-28 18:45:54 +00001133 for (ALL_LIST_ELEMENTS_RO (ipv6_reachs, node, ip6reach))
hassof390d2c2004-09-10 20:48:21 +00001134 {
hassof390d2c2004-09-10 20:48:21 +00001135 if (pos - value + IPV6_MAX_BYTELEN + 6 > 255)
1136 {
1137 retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
1138 if (retval != ISIS_OK)
1139 return retval;
1140 pos = value;
1141 }
1142 *(uint32_t *) pos = ip6reach->metric;
1143 pos += 4;
1144 *pos = ip6reach->control_info;
1145 pos++;
1146 prefix_octets = ((ip6reach->prefix_len + 7) / 8);
1147 *pos = ip6reach->prefix_len;
1148 pos++;
1149 memcpy (pos, ip6reach->prefix, prefix_octets);
1150 pos += prefix_octets;
jardineb5d44e2003-12-23 08:09:43 +00001151 }
hassof390d2c2004-09-10 20:48:21 +00001152
jardineb5d44e2003-12-23 08:09:43 +00001153 return add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
1154}
1155#endif /* HAVE_IPV6 */
1156
1157int
1158tlv_add_padding (struct stream *stream)
1159{
hassof390d2c2004-09-10 20:48:21 +00001160 int fullpads, i, left;
1161
jardineb5d44e2003-12-23 08:09:43 +00001162 /*
1163 * How many times can we add full padding ?
1164 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001165 fullpads = (stream_get_size (stream) - stream_get_endp (stream)) / 257;
hassof390d2c2004-09-10 20:48:21 +00001166 for (i = 0; i < fullpads; i++)
1167 {
1168 if (!stream_putc (stream, (u_char) PADDING)) /* TAG */
1169 goto err;
1170 if (!stream_putc (stream, (u_char) 255)) /* LENGHT */
1171 goto err;
paul15935e92005-05-03 09:27:23 +00001172 stream_put (stream, NULL, 255); /* zero padding */
hassof390d2c2004-09-10 20:48:21 +00001173 }
1174
Josh Bailey3f045a02012-03-24 08:35:20 -07001175 left = stream_get_size (stream) - stream_get_endp (stream);
hassof390d2c2004-09-10 20:48:21 +00001176
jardineb5d44e2003-12-23 08:09:43 +00001177 if (left < 2)
1178 return ISIS_OK;
hassof390d2c2004-09-10 20:48:21 +00001179
1180 if (left == 2)
1181 {
1182 stream_putc (stream, PADDING);
1183 stream_putc (stream, 0);
1184 return ISIS_OK;
1185 }
1186
jardineb5d44e2003-12-23 08:09:43 +00001187 stream_putc (stream, PADDING);
1188 stream_putc (stream, left - 2);
paul15935e92005-05-03 09:27:23 +00001189 stream_put (stream, NULL, left-2);
jardineb5d44e2003-12-23 08:09:43 +00001190
1191 return ISIS_OK;
1192
hassof390d2c2004-09-10 20:48:21 +00001193err:
jardineb5d44e2003-12-23 08:09:43 +00001194 zlog_warn ("tlv_add_padding(): no room for tlv");
1195 return ISIS_WARNING;
1196}