blob: 8d4ea0e35e943e4624af4881f574d3e3ddb4fde6 [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"
45
jardineb5d44e2003-12-23 08:09:43 +000046void
47free_tlv (void *val)
48{
hassof390d2c2004-09-10 20:48:21 +000049 XFREE (MTYPE_ISIS_TLV, val);
50
51 return;
jardineb5d44e2003-12-23 08:09:43 +000052}
53
54/*
55 * Called after parsing of a PDU. There shouldn't be any tlv's left, so this
56 * is only a caution to avoid memory leaks
57 */
hassof390d2c2004-09-10 20:48:21 +000058void
jardineb5d44e2003-12-23 08:09:43 +000059free_tlvs (struct tlvs *tlvs)
60{
hassof390d2c2004-09-10 20:48:21 +000061 if (tlvs->area_addrs)
hassoaac372f2005-09-01 17:52:33 +000062 list_delete (tlvs->area_addrs);
hassof390d2c2004-09-10 20:48:21 +000063 if (tlvs->is_neighs)
hassoaac372f2005-09-01 17:52:33 +000064 list_delete (tlvs->is_neighs);
hassof390d2c2004-09-10 20:48:21 +000065 if (tlvs->te_is_neighs)
hassoaac372f2005-09-01 17:52:33 +000066 list_delete (tlvs->te_is_neighs);
hassof390d2c2004-09-10 20:48:21 +000067 if (tlvs->es_neighs)
hassoaac372f2005-09-01 17:52:33 +000068 list_delete (tlvs->es_neighs);
hassof390d2c2004-09-10 20:48:21 +000069 if (tlvs->lsp_entries)
hassoaac372f2005-09-01 17:52:33 +000070 list_delete (tlvs->lsp_entries);
hassof390d2c2004-09-10 20:48:21 +000071 if (tlvs->prefix_neighs)
hassoaac372f2005-09-01 17:52:33 +000072 list_delete (tlvs->prefix_neighs);
Josh Bailey3f045a02012-03-24 08:35:20 -070073 if (tlvs->lan_neighs)
74 list_delete (tlvs->lan_neighs);
hassof390d2c2004-09-10 20:48:21 +000075 if (tlvs->ipv4_addrs)
hassoaac372f2005-09-01 17:52:33 +000076 list_delete (tlvs->ipv4_addrs);
hassof390d2c2004-09-10 20:48:21 +000077 if (tlvs->ipv4_int_reachs)
hassoaac372f2005-09-01 17:52:33 +000078 list_delete (tlvs->ipv4_int_reachs);
hassof390d2c2004-09-10 20:48:21 +000079 if (tlvs->ipv4_ext_reachs)
hassoaac372f2005-09-01 17:52:33 +000080 list_delete (tlvs->ipv4_ext_reachs);
hassof390d2c2004-09-10 20:48:21 +000081 if (tlvs->te_ipv4_reachs)
hassoaac372f2005-09-01 17:52:33 +000082 list_delete (tlvs->te_ipv4_reachs);
jardineb5d44e2003-12-23 08:09:43 +000083#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +000084 if (tlvs->ipv6_addrs)
hassoaac372f2005-09-01 17:52:33 +000085 list_delete (tlvs->ipv6_addrs);
hassof390d2c2004-09-10 20:48:21 +000086 if (tlvs->ipv6_reachs)
hassoaac372f2005-09-01 17:52:33 +000087 list_delete (tlvs->ipv6_reachs);
jardineb5d44e2003-12-23 08:09:43 +000088#endif /* HAVE_IPV6 */
Josh Bailey3f045a02012-03-24 08:35:20 -070089
90 memset (tlvs, 0, sizeof (struct tlvs));
91
jardineb5d44e2003-12-23 08:09:43 +000092 return;
93}
94
95/*
96 * Parses the tlvs found in the variant length part of the PDU.
97 * Caller tells with flags in "expected" which TLV's it is interested in.
98 */
hassof390d2c2004-09-10 20:48:21 +000099int
100parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
Josh Bailey3f045a02012-03-24 08:35:20 -0700101 u_int32_t * found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset)
jardineb5d44e2003-12-23 08:09:43 +0000102{
hassof390d2c2004-09-10 20:48:21 +0000103 u_char type, length;
104 struct lan_neigh *lan_nei;
105 struct area_addr *area_addr;
106 struct is_neigh *is_nei;
107 struct te_is_neigh *te_is_nei;
108 struct es_neigh *es_nei;
109 struct lsp_entry *lsp_entry;
110 struct in_addr *ipv4_addr;
111 struct ipv4_reachability *ipv4_reach;
112 struct te_ipv4_reachability *te_ipv4_reach;
jardineb5d44e2003-12-23 08:09:43 +0000113#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000114 struct in6_addr *ipv6_addr;
115 struct ipv6_reachability *ipv6_reach;
116 int prefix_octets;
jardineb5d44e2003-12-23 08:09:43 +0000117#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000118 int value_len, retval = ISIS_OK;
David Lamparterf02a0992012-05-08 13:15:45 +0200119 u_char *start = stream, *pnt = stream, *endpnt;
jardineb5d44e2003-12-23 08:09:43 +0000120
121 *found = 0;
122 memset (tlvs, 0, sizeof (struct tlvs));
hassof390d2c2004-09-10 20:48:21 +0000123
124 while (pnt < stream + size - 2)
125 {
126 type = *pnt;
127 length = *(pnt + 1);
128 pnt += 2;
129 value_len = 0;
130 if (pnt + length > stream + size)
131 {
132 zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet "
133 "boundaries", areatag, type, length);
134 retval = ISIS_WARNING;
135 break;
136 }
137 switch (type)
138 {
139 case AREA_ADDRESSES:
140 /* +-------+-------+-------+-------+-------+-------+-------+-------+
141 * | Address Length |
142 * +-------+-------+-------+-------+-------+-------+-------+-------+
143 * | Area Address |
144 * +-------+-------+-------+-------+-------+-------+-------+-------+
145 * : :
146 */
147 *found |= TLVFLAG_AREA_ADDRS;
jardineb5d44e2003-12-23 08:09:43 +0000148#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000149 zlog_debug ("TLV Area Adresses len %d", length);
jardineb5d44e2003-12-23 08:09:43 +0000150#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000151 if (*expected & TLVFLAG_AREA_ADDRS)
152 {
153 while (length > value_len)
154 {
155 area_addr = (struct area_addr *) pnt;
156 value_len += area_addr->addr_len + 1;
157 pnt += area_addr->addr_len + 1;
158 if (!tlvs->area_addrs)
159 tlvs->area_addrs = list_new ();
160 listnode_add (tlvs->area_addrs, area_addr);
161 }
162 }
163 else
164 {
165 pnt += length;
166 }
167 break;
jardineb5d44e2003-12-23 08:09:43 +0000168
hassof390d2c2004-09-10 20:48:21 +0000169 case IS_NEIGHBOURS:
170 *found |= TLVFLAG_IS_NEIGHS;
jardineb5d44e2003-12-23 08:09:43 +0000171#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000172 zlog_debug ("ISIS-TLV (%s): IS Neighbours length %d",
173 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000174#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000175 if (TLVFLAG_IS_NEIGHS & *expected)
176 {
177 /* +-------+-------+-------+-------+-------+-------+-------+-------+
178 * | Virtual Flag |
179 * +-------+-------+-------+-------+-------+-------+-------+-------+
180 */
David Lamparterf50ee932015-03-04 07:13:38 +0100181 /* virtual = *pnt; FIXME: what is the use for this? */
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;
233 value_len += 11;
234 pnt += 11;
235 /* FIXME - subtlvs are handled here, for now we skip */
236 value_len += te_is_nei->sub_tlvs_length;
237 pnt += te_is_nei->sub_tlvs_length;
jardineb5d44e2003-12-23 08:09:43 +0000238
hassof390d2c2004-09-10 20:48:21 +0000239 if (!tlvs->te_is_neighs)
240 tlvs->te_is_neighs = list_new ();
241 listnode_add (tlvs->te_is_neighs, te_is_nei);
242 }
243 }
244 else
245 {
246 pnt += length;
247 }
248 break;
jardineb5d44e2003-12-23 08:09:43 +0000249
hassof390d2c2004-09-10 20:48:21 +0000250 case ES_NEIGHBOURS:
251 /* +-------+-------+-------+-------+-------+-------+-------+-------+
252 * | 0 | I/E | Default Metric |
253 * +-------+-------+-------+-------+-------+-------+-------+-------+
254 * | S | I/E | Delay Metric |
255 * +-------+-------+-------+-------+-------+-------+-------+-------+
256 * | S | I/E | Expense Metric |
257 * +-------+-------+-------+-------+-------+-------+-------+-------+
258 * | S | I/E | Error Metric |
259 * +-------+-------+-------+-------+-------+-------+-------+-------+
260 * | Neighbour ID |
261 * +---------------------------------------------------------------+
262 * | Neighbour ID |
263 * +---------------------------------------------------------------+
264 * : :
265 */
jardineb5d44e2003-12-23 08:09:43 +0000266#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000267 zlog_debug ("ISIS-TLV (%s): ES Neighbours length %d",
hassof390d2c2004-09-10 20:48:21 +0000268 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000269#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000270 *found |= TLVFLAG_ES_NEIGHS;
271 if (*expected & TLVFLAG_ES_NEIGHS)
272 {
273 es_nei = (struct es_neigh *) pnt;
274 value_len += 4;
275 pnt += 4;
276 while (length > value_len)
277 {
278 /* FIXME FIXME FIXME - add to the list */
279 /* sys_id->id = pnt; */
280 value_len += ISIS_SYS_ID_LEN;
281 pnt += ISIS_SYS_ID_LEN;
282 /* if (!es_nei->neigh_ids) es_nei->neigh_ids = sysid; */
283 }
284 if (!tlvs->es_neighs)
285 tlvs->es_neighs = list_new ();
286 listnode_add (tlvs->es_neighs, es_nei);
287 }
288 else
289 {
290 pnt += length;
291 }
292 break;
jardineb5d44e2003-12-23 08:09:43 +0000293
hassof390d2c2004-09-10 20:48:21 +0000294 case LAN_NEIGHBOURS:
295 /* +-------+-------+-------+-------+-------+-------+-------+-------+
296 * | LAN Address |
297 * +-------+-------+-------+-------+-------+-------+-------+-------+
298 * : :
299 */
300 *found |= TLVFLAG_LAN_NEIGHS;
jardineb5d44e2003-12-23 08:09:43 +0000301#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000302 zlog_debug ("ISIS-TLV (%s): LAN Neigbours length %d",
303 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000304#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000305 if (TLVFLAG_LAN_NEIGHS & *expected)
306 {
307 while (length > value_len)
308 {
309 lan_nei = (struct lan_neigh *) pnt;
310 if (!tlvs->lan_neighs)
311 tlvs->lan_neighs = list_new ();
312 listnode_add (tlvs->lan_neighs, lan_nei);
313 value_len += ETH_ALEN;
314 pnt += ETH_ALEN;
315 }
316 }
317 else
318 {
319 pnt += length;
320 }
321 break;
jardineb5d44e2003-12-23 08:09:43 +0000322
hassof390d2c2004-09-10 20:48:21 +0000323 case PADDING:
jardineb5d44e2003-12-23 08:09:43 +0000324#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000325 zlog_debug ("TLV padding %d", length);
jardineb5d44e2003-12-23 08:09:43 +0000326#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000327 pnt += length;
328 break;
jardineb5d44e2003-12-23 08:09:43 +0000329
hassof390d2c2004-09-10 20:48:21 +0000330 case LSP_ENTRIES:
331 /* +-------+-------+-------+-------+-------+-------+-------+-------+
332 * | Remaining Lifetime | 2
333 * +-------+-------+-------+-------+-------+-------+-------+-------+
334 * | LSP ID | id+2
335 * +-------+-------+-------+-------+-------+-------+-------+-------+
336 * | LSP Sequence Number | 4
337 * +-------+-------+-------+-------+-------+-------+-------+-------+
338 * | Checksum | 2
339 * +-------+-------+-------+-------+-------+-------+-------+-------+
340 */
jardineb5d44e2003-12-23 08:09:43 +0000341#ifdef EXTREME_TLV_DEBUG
hasso92365882005-01-18 13:53:33 +0000342 zlog_debug ("ISIS-TLV (%s): LSP Entries length %d", areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000343#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000344 *found |= TLVFLAG_LSP_ENTRIES;
345 if (TLVFLAG_LSP_ENTRIES & *expected)
346 {
347 while (length > value_len)
348 {
349 lsp_entry = (struct lsp_entry *) pnt;
350 value_len += 10 + ISIS_SYS_ID_LEN;
351 pnt += 10 + ISIS_SYS_ID_LEN;
352 if (!tlvs->lsp_entries)
353 tlvs->lsp_entries = list_new ();
354 listnode_add (tlvs->lsp_entries, lsp_entry);
355 }
356 }
357 else
358 {
359 pnt += length;
360 }
361 break;
jardineb5d44e2003-12-23 08:09:43 +0000362
hassof390d2c2004-09-10 20:48:21 +0000363 case CHECKSUM:
364 /* +-------+-------+-------+-------+-------+-------+-------+-------+
365 * | 16 bit fletcher CHECKSUM |
366 * +-------+-------+-------+-------+-------+-------+-------+-------+
367 * : :
368 */
369 *found |= TLVFLAG_CHECKSUM;
jardineb5d44e2003-12-23 08:09:43 +0000370#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000371 zlog_debug ("ISIS-TLV (%s): Checksum length %d", areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000372#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000373 if (*expected & TLVFLAG_CHECKSUM)
374 {
375 tlvs->checksum = (struct checksum *) pnt;
376 }
377 pnt += length;
378 break;
jardineb5d44e2003-12-23 08:09:43 +0000379
hassof390d2c2004-09-10 20:48:21 +0000380 case PROTOCOLS_SUPPORTED:
381 /* +-------+-------+-------+-------+-------+-------+-------+-------+
382 * | NLPID |
383 * +-------+-------+-------+-------+-------+-------+-------+-------+
384 * : :
385 */
386 *found |= TLVFLAG_NLPID;
jardineb5d44e2003-12-23 08:09:43 +0000387#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000388 zlog_debug ("ISIS-TLV (%s): Protocols Supported length %d",
389 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000390#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000391 if (*expected & TLVFLAG_NLPID)
392 {
393 tlvs->nlpids = (struct nlpids *) (pnt - 1);
394 }
395 pnt += length;
396 break;
jardineb5d44e2003-12-23 08:09:43 +0000397
hassof390d2c2004-09-10 20:48:21 +0000398 case IPV4_ADDR:
399 /* +-------+-------+-------+-------+-------+-------+-------+-------+
400 * + IP version 4 address + 4
401 * +-------+-------+-------+-------+-------+-------+-------+-------+
402 * : :
403 */
404 *found |= TLVFLAG_IPV4_ADDR;
jardineb5d44e2003-12-23 08:09:43 +0000405#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000406 zlog_debug ("ISIS-TLV (%s): IPv4 Address length %d",
407 areatag, length);
hassof390d2c2004-09-10 20:48:21 +0000408#endif /* EXTREME_TLV_DEBUG */
409 if (*expected & TLVFLAG_IPV4_ADDR)
410 {
411 while (length > value_len)
412 {
413 ipv4_addr = (struct in_addr *) pnt;
hassof891f442004-09-14 13:54:30 +0000414#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000415 zlog_debug ("ISIS-TLV (%s) : IP ADDR %s, pnt %p", areatag,
416 inet_ntoa (*ipv4_addr), pnt);
hassof891f442004-09-14 13:54:30 +0000417#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000418 if (!tlvs->ipv4_addrs)
419 tlvs->ipv4_addrs = list_new ();
420 listnode_add (tlvs->ipv4_addrs, ipv4_addr);
421 value_len += 4;
422 pnt += 4;
423 }
424 }
425 else
426 {
427 pnt += length;
428 }
429 break;
430
431 case AUTH_INFO:
432 *found |= TLVFLAG_AUTH_INFO;
433#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000434 zlog_debug ("ISIS-TLV (%s): IS-IS Authentication Information",
435 areatag);
jardineb5d44e2003-12-23 08:09:43 +0000436#endif
hassof390d2c2004-09-10 20:48:21 +0000437 if (*expected & TLVFLAG_AUTH_INFO)
438 {
439 tlvs->auth_info.type = *pnt;
Josh Bailey3f045a02012-03-24 08:35:20 -0700440 if (length == 0)
441 {
442 zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) "
443 "incorrect.", areatag, type, length);
444 return ISIS_WARNING;
445 }
446 --length;
447 tlvs->auth_info.len = length;
hassof390d2c2004-09-10 20:48:21 +0000448 pnt++;
Josh Bailey3f045a02012-03-24 08:35:20 -0700449 memcpy (tlvs->auth_info.passwd, pnt, length);
450 /* Return the authentication tlv pos for later computation
451 * of MD5 (RFC 5304, 2)
452 */
453 if (auth_tlv_offset)
454 *auth_tlv_offset += (pnt - start - 3);
455 pnt += length;
hassof390d2c2004-09-10 20:48:21 +0000456 }
457 else
458 {
459 pnt += length;
460 }
461 break;
jardineb5d44e2003-12-23 08:09:43 +0000462
hassof390d2c2004-09-10 20:48:21 +0000463 case DYNAMIC_HOSTNAME:
464 *found |= TLVFLAG_DYN_HOSTNAME;
jardineb5d44e2003-12-23 08:09:43 +0000465#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000466 zlog_debug ("ISIS-TLV (%s): Dynamic Hostname length %d",
467 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000468#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000469 if (*expected & TLVFLAG_DYN_HOSTNAME)
470 {
471 /* the length is also included in the pointed struct */
472 tlvs->hostname = (struct hostname *) (pnt - 1);
473 }
474 pnt += length;
475 break;
jardineb5d44e2003-12-23 08:09:43 +0000476
hassof390d2c2004-09-10 20:48:21 +0000477 case TE_ROUTER_ID:
478 /* +---------------------------------------------------------------+
479 * + Router ID + 4
480 * +---------------------------------------------------------------+
481 */
482 *found |= TLVFLAG_TE_ROUTER_ID;
jardineb5d44e2003-12-23 08:09:43 +0000483#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000484 zlog_debug ("ISIS-TLV (%s): TE Router ID %d", areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000485#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000486 if (*expected & TLVFLAG_TE_ROUTER_ID)
hasso1cd80842004-10-07 20:07:40 +0000487 tlvs->router_id = (struct te_router_id *) (pnt);
hassof390d2c2004-09-10 20:48:21 +0000488 pnt += length;
489 break;
jardineb5d44e2003-12-23 08:09:43 +0000490
hassof390d2c2004-09-10 20:48:21 +0000491 case IPV4_INT_REACHABILITY:
492 /* +-------+-------+-------+-------+-------+-------+-------+-------+
493 * | 0 | I/E | Default Metric | 1
494 * +-------+-------+-------+-------+-------+-------+-------+-------+
495 * | S | I/E | Delay Metric | 1
496 * +-------+-------+-------+-------+-------+-------+-------+-------+
497 * | S | I/E | Expense Metric | 1
498 * +-------+-------+-------+-------+-------+-------+-------+-------+
499 * | S | I/E | Error Metric | 1
500 * +-------+-------+-------+-------+-------+-------+-------+-------+
501 * | ip address | 4
502 * +---------------------------------------------------------------+
503 * | address mask | 4
504 * +---------------------------------------------------------------+
505 * : :
506 */
507 *found |= TLVFLAG_IPV4_INT_REACHABILITY;
jardineb5d44e2003-12-23 08:09:43 +0000508#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000509 zlog_debug ("ISIS-TLV (%s): IPv4 internal Reachability length %d",
510 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000511#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000512 if (*expected & TLVFLAG_IPV4_INT_REACHABILITY)
513 {
514 while (length > value_len)
515 {
516 ipv4_reach = (struct ipv4_reachability *) pnt;
517 if (!tlvs->ipv4_int_reachs)
518 tlvs->ipv4_int_reachs = list_new ();
519 listnode_add (tlvs->ipv4_int_reachs, ipv4_reach);
520 value_len += 12;
521 pnt += 12;
522 }
523 }
524 else
525 {
526 pnt += length;
527 }
528 break;
jardineb5d44e2003-12-23 08:09:43 +0000529
hassof390d2c2004-09-10 20:48:21 +0000530 case IPV4_EXT_REACHABILITY:
531 /* +-------+-------+-------+-------+-------+-------+-------+-------+
532 * | 0 | I/E | Default Metric | 1
533 * +-------+-------+-------+-------+-------+-------+-------+-------+
534 * | S | I/E | Delay Metric | 1
535 * +-------+-------+-------+-------+-------+-------+-------+-------+
536 * | S | I/E | Expense Metric | 1
537 * +-------+-------+-------+-------+-------+-------+-------+-------+
538 * | S | I/E | Error Metric | 1
539 * +-------+-------+-------+-------+-------+-------+-------+-------+
540 * | ip address | 4
541 * +---------------------------------------------------------------+
542 * | address mask | 4
543 * +---------------------------------------------------------------+
544 * : :
545 */
546 *found |= TLVFLAG_IPV4_EXT_REACHABILITY;
jardineb5d44e2003-12-23 08:09:43 +0000547#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000548 zlog_debug ("ISIS-TLV (%s): IPv4 external Reachability length %d",
549 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000550#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000551 if (*expected & TLVFLAG_IPV4_EXT_REACHABILITY)
552 {
553 while (length > value_len)
554 {
555 ipv4_reach = (struct ipv4_reachability *) pnt;
556 if (!tlvs->ipv4_ext_reachs)
557 tlvs->ipv4_ext_reachs = list_new ();
558 listnode_add (tlvs->ipv4_ext_reachs, ipv4_reach);
559 value_len += 12;
560 pnt += 12;
561 }
562 }
563 else
564 {
565 pnt += length;
566 }
567 break;
jardineb5d44e2003-12-23 08:09:43 +0000568
hassof390d2c2004-09-10 20:48:21 +0000569 case TE_IPV4_REACHABILITY:
570 /* +-------+-------+-------+-------+-------+-------+-------+-------+
571 * | TE Metric | 4
572 * +-------+-------+-------+-------+-------+-------+-------+-------+
573 * | U/D | sTLV? | Prefix Mask Len | 1
574 * +-------+-------+-------+-------+-------+-------+-------+-------+
575 * | Prefix | 0-4
576 * +---------------------------------------------------------------+
577 * | sub tlvs |
578 * +---------------------------------------------------------------+
579 * : :
580 */
581 *found |= TLVFLAG_TE_IPV4_REACHABILITY;
jardineb5d44e2003-12-23 08:09:43 +0000582#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000583 zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d",
584 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000585#endif /* EXTREME_TLV_DEBUG */
David Lamparterf02a0992012-05-08 13:15:45 +0200586 endpnt = pnt + length;
hassof390d2c2004-09-10 20:48:21 +0000587 if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
588 {
589 while (length > value_len)
590 {
591 te_ipv4_reach = (struct te_ipv4_reachability *) pnt;
David Lamparterf02a0992012-05-08 13:15:45 +0200592 if ((te_ipv4_reach->control & 0x3F) > IPV4_MAX_BITLEN)
593 {
594 zlog_warn ("ISIS-TLV (%s): invalid IPv4 extended reach"
595 "ability prefix length %d", areatag,
596 te_ipv4_reach->control & 0x3F);
597 retval = ISIS_WARNING;
598 break;
599 }
hassof390d2c2004-09-10 20:48:21 +0000600 if (!tlvs->te_ipv4_reachs)
601 tlvs->te_ipv4_reachs = list_new ();
602 listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach);
603 /* this trickery is permitable since no subtlvs are defined */
604 value_len += 5 + ((te_ipv4_reach->control & 0x3F) ?
605 ((((te_ipv4_reach->control & 0x3F) -
606 1) >> 3) + 1) : 0);
607 pnt += 5 + ((te_ipv4_reach->control & 0x3F) ?
608 ((((te_ipv4_reach->control & 0x3F) - 1) >> 3) + 1) : 0);
609 }
610 }
David Lamparterf02a0992012-05-08 13:15:45 +0200611
612 pnt = endpnt;
hassof390d2c2004-09-10 20:48:21 +0000613 break;
jardineb5d44e2003-12-23 08:09:43 +0000614
615#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000616 case IPV6_ADDR:
617 /* +-------+-------+-------+-------+-------+-------+-------+-------+
618 * + IP version 6 address + 16
619 * +-------+-------+-------+-------+-------+-------+-------+-------+
620 * : :
621 */
622 *found |= TLVFLAG_IPV6_ADDR;
jardineb5d44e2003-12-23 08:09:43 +0000623#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000624 zlog_debug ("ISIS-TLV (%s): IPv6 Address length %d",
625 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000626#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000627 if (*expected & TLVFLAG_IPV6_ADDR)
628 {
629 while (length > value_len)
630 {
631 ipv6_addr = (struct in6_addr *) pnt;
632 if (!tlvs->ipv6_addrs)
633 tlvs->ipv6_addrs = list_new ();
634 listnode_add (tlvs->ipv6_addrs, ipv6_addr);
635 value_len += 16;
636 pnt += 16;
637 }
638 }
639 else
640 {
641 pnt += length;
642 }
643 break;
jardineb5d44e2003-12-23 08:09:43 +0000644
hassof390d2c2004-09-10 20:48:21 +0000645 case IPV6_REACHABILITY:
646 /* +-------+-------+-------+-------+-------+-------+-------+-------+
647 * | Default Metric | 4
648 * +-------+-------+-------+-------+-------+-------+-------+-------+
649 * | Control Informantion |
650 * +---------------------------------------------------------------+
651 * | IPv6 Prefix Length |--+
652 * +---------------------------------------------------------------+ |
653 * | IPv6 Prefix |<-+
654 * +---------------------------------------------------------------+
655 */
656 *found |= TLVFLAG_IPV6_REACHABILITY;
David Lamparterf02a0992012-05-08 13:15:45 +0200657 endpnt = pnt + length;
658
hassof390d2c2004-09-10 20:48:21 +0000659 if (*expected & TLVFLAG_IPV6_REACHABILITY)
660 {
661 while (length > value_len)
662 {
663 ipv6_reach = (struct ipv6_reachability *) pnt;
David Lamparterf02a0992012-05-08 13:15:45 +0200664 if (ipv6_reach->prefix_len > IPV6_MAX_BITLEN)
665 {
666 zlog_warn ("ISIS-TLV (%s): invalid IPv6 extended reach"
667 "ability prefix length %d", areatag,
668 ipv6_reach->prefix_len);
669 retval = ISIS_WARNING;
670 break;
671 }
672
hassof390d2c2004-09-10 20:48:21 +0000673 prefix_octets = ((ipv6_reach->prefix_len + 7) / 8);
674 value_len += prefix_octets + 6;
675 pnt += prefix_octets + 6;
676 /* FIXME: sub-tlvs */
677 if (!tlvs->ipv6_reachs)
678 tlvs->ipv6_reachs = list_new ();
679 listnode_add (tlvs->ipv6_reachs, ipv6_reach);
680 }
681 }
David Lamparterf02a0992012-05-08 13:15:45 +0200682
683 pnt = endpnt;
hassof390d2c2004-09-10 20:48:21 +0000684 break;
jardineb5d44e2003-12-23 08:09:43 +0000685#endif /* HAVE_IPV6 */
686
hassof390d2c2004-09-10 20:48:21 +0000687 case WAY3_HELLO:
688 /* +---------------------------------------------------------------+
689 * | Adjacency state | 1
690 * +---------------------------------------------------------------+
691 * | Extended Local Circuit ID | 4
692 * +---------------------------------------------------------------+
693 * | Neighbor System ID (If known) | 0-8
694 * (probably 6)
695 * +---------------------------------------------------------------+
696 * | Neighbor Local Circuit ID (If known) | 4
697 * +---------------------------------------------------------------+
698 */
699 *found |= TLVFLAG_3WAY_HELLO;
700 if (*expected & TLVFLAG_3WAY_HELLO)
701 {
702 while (length > value_len)
703 {
704 /* FIXME: make this work */
jardineb5d44e2003-12-23 08:09:43 +0000705/* Adjacency State (one octet):
706 0 = Up
707 1 = Initializing
708 2 = Down
709 Extended Local Circuit ID (four octets)
710 Neighbor System ID if known (zero to eight octets)
711 Neighbor Extended Local Circuit ID (four octets, if Neighbor
712 System ID is present) */
hassof390d2c2004-09-10 20:48:21 +0000713 pnt += length;
David Lampartere8aca322012-11-27 01:10:30 +0000714 value_len += length;
hassof390d2c2004-09-10 20:48:21 +0000715 }
716 }
717 else
718 {
719 pnt += length;
720 }
jardineb5d44e2003-12-23 08:09:43 +0000721
hassof390d2c2004-09-10 20:48:21 +0000722 break;
723 case GRACEFUL_RESTART:
724 /* +-------+-------+-------+-------+-------+-------+-------+-------+
725 * | Reserved | SA | RA | RR | 1
726 * +-------+-------+-------+-------+-------+-------+-------+-------+
727 * | Remaining Time | 2
728 * +---------------------------------------------------------------+
729 * | Restarting Neighbor ID (If known) | 0-8
730 * +---------------------------------------------------------------+
731 */
732 *found |= TLVFLAG_GRACEFUL_RESTART;
733 if (*expected & TLVFLAG_GRACEFUL_RESTART)
734 {
735 /* FIXME: make this work */
736 }
737 pnt += length;
738 break;
jardineb5d44e2003-12-23 08:09:43 +0000739
hassof390d2c2004-09-10 20:48:21 +0000740 default:
741 zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
742 areatag, type, length);
jardineb5d44e2003-12-23 08:09:43 +0000743
hassof390d2c2004-09-10 20:48:21 +0000744 pnt += length;
745 break;
746 }
jardineb5d44e2003-12-23 08:09:43 +0000747 }
hassof390d2c2004-09-10 20:48:21 +0000748
jardineb5d44e2003-12-23 08:09:43 +0000749 return retval;
750}
751
752int
hassof390d2c2004-09-10 20:48:21 +0000753add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000754{
Josh Bailey3f045a02012-03-24 08:35:20 -0700755 if ((stream_get_size (stream) - stream_get_endp (stream)) <
756 (((unsigned)len) + 2))
hassof390d2c2004-09-10 20:48:21 +0000757 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700758 zlog_warn ("No room for TLV of type %d "
759 "(total size %d available %d required %d)",
760 tag, (int)stream_get_size (stream),
761 (int)(stream_get_size (stream) - stream_get_endp (stream)),
762 len+2);
hassof390d2c2004-09-10 20:48:21 +0000763 return ISIS_WARNING;
764 }
jardineb5d44e2003-12-23 08:09:43 +0000765
hassof390d2c2004-09-10 20:48:21 +0000766 stream_putc (stream, tag); /* TAG */
767 stream_putc (stream, len); /* LENGTH */
768 stream_put (stream, value, (int) len); /* VALUE */
jardineb5d44e2003-12-23 08:09:43 +0000769
770#ifdef EXTREME_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000771 zlog_debug ("Added TLV %d len %d", tag, len);
jardineb5d44e2003-12-23 08:09:43 +0000772#endif /* EXTREME DEBUG */
773 return ISIS_OK;
774}
775
jardineb5d44e2003-12-23 08:09:43 +0000776int
hassof390d2c2004-09-10 20:48:21 +0000777tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000778{
779 struct listnode *node;
780 struct area_addr *area_addr;
781
hassof390d2c2004-09-10 20:48:21 +0000782 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000783 u_char *pos = value;
hassof390d2c2004-09-10 20:48:21 +0000784
paul1eb8ef22005-04-07 07:30:20 +0000785 for (ALL_LIST_ELEMENTS_RO (area_addrs, node, area_addr))
hassof390d2c2004-09-10 20:48:21 +0000786 {
hassof390d2c2004-09-10 20:48:21 +0000787 if (pos - value + area_addr->addr_len > 255)
788 goto err;
789 *pos = area_addr->addr_len;
790 pos++;
791 memcpy (pos, area_addr->area_addr, (int) area_addr->addr_len);
792 pos += area_addr->addr_len;
793 }
794
jardineb5d44e2003-12-23 08:09:43 +0000795 return add_tlv (AREA_ADDRESSES, pos - value, value, stream);
796
hassof390d2c2004-09-10 20:48:21 +0000797err:
jardineb5d44e2003-12-23 08:09:43 +0000798 zlog_warn ("tlv_add_area_addrs(): TLV longer than 255");
799 return ISIS_WARNING;
800}
801
hassof390d2c2004-09-10 20:48:21 +0000802int
803tlv_add_is_neighs (struct list *is_neighs, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000804{
hasso3fdb2dd2005-09-28 18:45:54 +0000805 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000806 struct is_neigh *is_neigh;
hassof390d2c2004-09-10 20:48:21 +0000807 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000808 u_char *pos = value;
809 int retval;
810
hassof390d2c2004-09-10 20:48:21 +0000811 *pos = 0; /*is_neigh->virtual; */
812 pos++;
jardineb5d44e2003-12-23 08:09:43 +0000813
hasso3fdb2dd2005-09-28 18:45:54 +0000814 for (ALL_LIST_ELEMENTS_RO (is_neighs, node, is_neigh))
hassof390d2c2004-09-10 20:48:21 +0000815 {
hassof390d2c2004-09-10 20:48:21 +0000816 if (pos - value + IS_NEIGHBOURS_LEN > 255)
817 {
818 retval = add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
819 if (retval != ISIS_OK)
820 return retval;
821 pos = value;
822 }
823 *pos = is_neigh->metrics.metric_default;
824 pos++;
825 *pos = is_neigh->metrics.metric_delay;
826 pos++;
827 *pos = is_neigh->metrics.metric_expense;
828 pos++;
829 *pos = is_neigh->metrics.metric_error;
830 pos++;
831 memcpy (pos, is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
832 pos += ISIS_SYS_ID_LEN + 1;
jardineb5d44e2003-12-23 08:09:43 +0000833 }
jardineb5d44e2003-12-23 08:09:43 +0000834
835 return add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
836}
837
jardineb5d44e2003-12-23 08:09:43 +0000838int
hassoea3be4c2005-09-26 17:11:12 +0000839tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
840{
hasso3fdb2dd2005-09-28 18:45:54 +0000841 struct listnode *node;
hassoea3be4c2005-09-26 17:11:12 +0000842 struct te_is_neigh *te_is_neigh;
843 u_char value[255];
844 u_char *pos = value;
845 int retval;
846
hasso3fdb2dd2005-09-28 18:45:54 +0000847 for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh))
hassoea3be4c2005-09-26 17:11:12 +0000848 {
849 /* FIXME: This will be wrong if we are going to add TE sub TLVs. */
850 if (pos - value + IS_NEIGHBOURS_LEN > 255)
851 {
852 retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
853 if (retval != ISIS_OK)
854 return retval;
855 pos = value;
856 }
857
858 memcpy (pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
859 pos += ISIS_SYS_ID_LEN + 1;
860 memcpy (pos, te_is_neigh->te_metric, 3);
861 pos += 3;
862 /* Sub TLVs length. */
863 *pos = 0;
864 pos++;
865 }
866
867 return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
868}
869
870int
jardineb5d44e2003-12-23 08:09:43 +0000871tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream)
872{
hasso3fdb2dd2005-09-28 18:45:54 +0000873 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000874 u_char *snpa;
hassof390d2c2004-09-10 20:48:21 +0000875 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000876 u_char *pos = value;
877 int retval;
878
hasso3fdb2dd2005-09-28 18:45:54 +0000879 for (ALL_LIST_ELEMENTS_RO (lan_neighs, node, snpa))
hassof390d2c2004-09-10 20:48:21 +0000880 {
hassof390d2c2004-09-10 20:48:21 +0000881 if (pos - value + ETH_ALEN > 255)
882 {
883 retval = add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
884 if (retval != ISIS_OK)
885 return retval;
886 pos = value;
887 }
888 memcpy (pos, snpa, ETH_ALEN);
889 pos += ETH_ALEN;
jardineb5d44e2003-12-23 08:09:43 +0000890 }
jardineb5d44e2003-12-23 08:09:43 +0000891
892 return add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
893}
894
jardineb5d44e2003-12-23 08:09:43 +0000895int
896tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream)
897{
hassof390d2c2004-09-10 20:48:21 +0000898 return add_tlv (PROTOCOLS_SUPPORTED, nlpids->count, nlpids->nlpids, stream);
jardineb5d44e2003-12-23 08:09:43 +0000899}
900
hassof390d2c2004-09-10 20:48:21 +0000901int
Josh Bailey3f045a02012-03-24 08:35:20 -0700902tlv_add_authinfo (u_char auth_type, u_char auth_len, u_char *auth_value,
hassof390d2c2004-09-10 20:48:21 +0000903 struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000904{
905 u_char value[255];
906 u_char *pos = value;
Josh Bailey3f045a02012-03-24 08:35:20 -0700907 *pos++ = auth_type;
jardineb5d44e2003-12-23 08:09:43 +0000908 memcpy (pos, auth_value, auth_len);
909
910 return add_tlv (AUTH_INFO, auth_len + 1, value, stream);
911}
912
913int
914tlv_add_checksum (struct checksum *checksum, struct stream *stream)
915{
916 u_char value[255];
hassof390d2c2004-09-10 20:48:21 +0000917 u_char *pos = value;
918 return add_tlv (CHECKSUM, pos - value, value, stream);
jardineb5d44e2003-12-23 08:09:43 +0000919}
920
921int
922tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream)
923{
hasso3fdb2dd2005-09-28 18:45:54 +0000924 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000925 struct prefix_ipv4 *ipv4;
926 u_char value[255];
927 u_char *pos = value;
jardineb5d44e2003-12-23 08:09:43 +0000928
hasso3fdb2dd2005-09-28 18:45:54 +0000929 for (ALL_LIST_ELEMENTS_RO (ip_addrs, node, ipv4))
hassof390d2c2004-09-10 20:48:21 +0000930 {
hassof390d2c2004-09-10 20:48:21 +0000931 if (pos - value + IPV4_MAX_BYTELEN > 255)
932 {
David Lamparter91d799e2012-11-27 01:10:24 +0000933 /* RFC 1195 s4.2: only one tuple of 63 allowed. */
934 zlog_warn ("tlv_add_ip_addrs(): cutting off at 63 IP addresses");
935 break;
hassof390d2c2004-09-10 20:48:21 +0000936 }
937 *(u_int32_t *) pos = ipv4->prefix.s_addr;
938 pos += IPV4_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +0000939 }
hassof390d2c2004-09-10 20:48:21 +0000940
jardineb5d44e2003-12-23 08:09:43 +0000941 return add_tlv (IPV4_ADDR, pos - value, value, stream);
942}
943
hasso81ad8f62005-09-26 17:58:24 +0000944/* Used to add TLV containing just one IPv4 address - either IPv4 address TLV
945 * (in case of LSP) or TE router ID TLV. */
946int
947tlv_add_in_addr (struct in_addr *addr, struct stream *stream, u_char tag)
948{
949 u_char value[255];
950 u_char *pos = value;
951
952 memcpy (pos, addr, IPV4_MAX_BYTELEN);
953 pos += IPV4_MAX_BYTELEN;
954
955 return add_tlv (tag, pos - value, value, stream);
956}
957
jardineb5d44e2003-12-23 08:09:43 +0000958int
959tlv_add_dynamic_hostname (struct hostname *hostname, struct stream *stream)
960{
hassof390d2c2004-09-10 20:48:21 +0000961 return add_tlv (DYNAMIC_HOSTNAME, hostname->namelen, hostname->name,
962 stream);
jardineb5d44e2003-12-23 08:09:43 +0000963}
964
hassof390d2c2004-09-10 20:48:21 +0000965int
jardineb5d44e2003-12-23 08:09:43 +0000966tlv_add_lsp_entries (struct list *lsps, struct stream *stream)
967{
hasso3fdb2dd2005-09-28 18:45:54 +0000968 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000969 struct isis_lsp *lsp;
hassof390d2c2004-09-10 20:48:21 +0000970 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000971 u_char *pos = value;
972 int retval;
973
hasso3fdb2dd2005-09-28 18:45:54 +0000974 for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp))
hassof390d2c2004-09-10 20:48:21 +0000975 {
hassof390d2c2004-09-10 20:48:21 +0000976 if (pos - value + LSP_ENTRIES_LEN > 255)
977 {
978 retval = add_tlv (LSP_ENTRIES, pos - value, value, stream);
979 if (retval != ISIS_OK)
980 return retval;
981 pos = value;
982 }
983 *((u_int16_t *) pos) = lsp->lsp_header->rem_lifetime;
984 pos += 2;
985 memcpy (pos, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
986 pos += ISIS_SYS_ID_LEN + 2;
987 *((u_int32_t *) pos) = lsp->lsp_header->seq_num;
988 pos += 4;
989 *((u_int16_t *) pos) = lsp->lsp_header->checksum;
990 pos += 2;
jardineb5d44e2003-12-23 08:09:43 +0000991 }
hassof390d2c2004-09-10 20:48:21 +0000992
jardineb5d44e2003-12-23 08:09:43 +0000993 return add_tlv (LSP_ENTRIES, pos - value, value, stream);
994}
995
Christian Frankeacf98652015-11-12 14:24:22 +0100996static int
997tlv_add_ipv4_reachs (u_char tag, struct list *ipv4_reachs, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000998{
hasso3fdb2dd2005-09-28 18:45:54 +0000999 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00001000 struct ipv4_reachability *reach;
hassof390d2c2004-09-10 20:48:21 +00001001 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +00001002 u_char *pos = value;
1003 int retval;
1004
hasso3fdb2dd2005-09-28 18:45:54 +00001005 for (ALL_LIST_ELEMENTS_RO (ipv4_reachs, node, reach))
hassof390d2c2004-09-10 20:48:21 +00001006 {
hassof390d2c2004-09-10 20:48:21 +00001007 if (pos - value + IPV4_REACH_LEN > 255)
1008 {
1009 retval =
Christian Frankeacf98652015-11-12 14:24:22 +01001010 add_tlv (tag, pos - value, value, stream);
hassof390d2c2004-09-10 20:48:21 +00001011 if (retval != ISIS_OK)
1012 return retval;
1013 pos = value;
1014 }
1015 *pos = reach->metrics.metric_default;
1016 pos++;
1017 *pos = reach->metrics.metric_delay;
1018 pos++;
1019 *pos = reach->metrics.metric_expense;
1020 pos++;
1021 *pos = reach->metrics.metric_error;
1022 pos++;
1023 *(u_int32_t *) pos = reach->prefix.s_addr;
1024 pos += IPV4_MAX_BYTELEN;
1025 *(u_int32_t *) pos = reach->mask.s_addr;
1026 pos += IPV4_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +00001027 }
hassof390d2c2004-09-10 20:48:21 +00001028
Christian Frankeacf98652015-11-12 14:24:22 +01001029 return add_tlv (tag, pos - value, value, stream);
jardineb5d44e2003-12-23 08:09:43 +00001030}
1031
hassoea3be4c2005-09-26 17:11:12 +00001032int
Christian Frankeacf98652015-11-12 14:24:22 +01001033tlv_add_ipv4_int_reachs (struct list *ipv4_reachs, struct stream *stream)
1034{
1035 return tlv_add_ipv4_reachs(IPV4_INT_REACHABILITY, ipv4_reachs, stream);
1036}
1037
1038int
1039tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream)
1040{
1041 return tlv_add_ipv4_reachs(IPV4_EXT_REACHABILITY, ipv4_reachs, stream);
1042}
1043
1044
1045int
hassoea3be4c2005-09-26 17:11:12 +00001046tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream)
1047{
hasso3fdb2dd2005-09-28 18:45:54 +00001048 struct listnode *node;
hassoea3be4c2005-09-26 17:11:12 +00001049 struct te_ipv4_reachability *te_reach;
1050 u_char value[255];
1051 u_char *pos = value;
1052 u_char prefix_size;
1053 int retval;
1054
hasso3fdb2dd2005-09-28 18:45:54 +00001055 for (ALL_LIST_ELEMENTS_RO (te_ipv4_reachs, node, te_reach))
hassoea3be4c2005-09-26 17:11:12 +00001056 {
1057 prefix_size = ((((te_reach->control & 0x3F) - 1) >> 3) + 1);
1058
1059 if (pos - value + (5 + prefix_size) > 255)
1060 {
1061 retval =
Josh Bailey3f045a02012-03-24 08:35:20 -07001062 add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
hassoea3be4c2005-09-26 17:11:12 +00001063 if (retval != ISIS_OK)
1064 return retval;
1065 pos = value;
1066 }
1067 *(u_int32_t *) pos = te_reach->te_metric;
1068 pos += 4;
1069 *pos = te_reach->control;
1070 pos++;
1071 memcpy (pos, &te_reach->prefix_start, prefix_size);
1072 pos += prefix_size;
1073 }
1074
1075 return add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
1076}
1077
hassof390d2c2004-09-10 20:48:21 +00001078#ifdef HAVE_IPV6
jardineb5d44e2003-12-23 08:09:43 +00001079int
1080tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream)
1081{
hasso3fdb2dd2005-09-28 18:45:54 +00001082 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00001083 struct prefix_ipv6 *ipv6;
1084 u_char value[255];
1085 u_char *pos = value;
1086 int retval;
hassof390d2c2004-09-10 20:48:21 +00001087
hasso3fdb2dd2005-09-28 18:45:54 +00001088 for (ALL_LIST_ELEMENTS_RO (ipv6_addrs, node, ipv6))
hassof390d2c2004-09-10 20:48:21 +00001089 {
hassof390d2c2004-09-10 20:48:21 +00001090 if (pos - value + IPV6_MAX_BYTELEN > 255)
1091 {
1092 retval = add_tlv (IPV6_ADDR, pos - value, value, stream);
1093 if (retval != ISIS_OK)
1094 return retval;
1095 pos = value;
1096 }
1097 memcpy (pos, ipv6->prefix.s6_addr, IPV6_MAX_BYTELEN);
1098 pos += IPV6_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +00001099 }
hassof390d2c2004-09-10 20:48:21 +00001100
jardineb5d44e2003-12-23 08:09:43 +00001101 return add_tlv (IPV6_ADDR, pos - value, value, stream);
1102}
1103
1104int
1105tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream)
1106{
hasso3fdb2dd2005-09-28 18:45:54 +00001107 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00001108 struct ipv6_reachability *ip6reach;
1109 u_char value[255];
1110 u_char *pos = value;
1111 int retval, prefix_octets;
hassof390d2c2004-09-10 20:48:21 +00001112
hasso3fdb2dd2005-09-28 18:45:54 +00001113 for (ALL_LIST_ELEMENTS_RO (ipv6_reachs, node, ip6reach))
hassof390d2c2004-09-10 20:48:21 +00001114 {
hassof390d2c2004-09-10 20:48:21 +00001115 if (pos - value + IPV6_MAX_BYTELEN + 6 > 255)
1116 {
1117 retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
1118 if (retval != ISIS_OK)
1119 return retval;
1120 pos = value;
1121 }
1122 *(uint32_t *) pos = ip6reach->metric;
1123 pos += 4;
1124 *pos = ip6reach->control_info;
1125 pos++;
1126 prefix_octets = ((ip6reach->prefix_len + 7) / 8);
1127 *pos = ip6reach->prefix_len;
1128 pos++;
1129 memcpy (pos, ip6reach->prefix, prefix_octets);
1130 pos += prefix_octets;
jardineb5d44e2003-12-23 08:09:43 +00001131 }
hassof390d2c2004-09-10 20:48:21 +00001132
jardineb5d44e2003-12-23 08:09:43 +00001133 return add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
1134}
1135#endif /* HAVE_IPV6 */
1136
1137int
1138tlv_add_padding (struct stream *stream)
1139{
hassof390d2c2004-09-10 20:48:21 +00001140 int fullpads, i, left;
1141
jardineb5d44e2003-12-23 08:09:43 +00001142 /*
1143 * How many times can we add full padding ?
1144 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001145 fullpads = (stream_get_size (stream) - stream_get_endp (stream)) / 257;
hassof390d2c2004-09-10 20:48:21 +00001146 for (i = 0; i < fullpads; i++)
1147 {
1148 if (!stream_putc (stream, (u_char) PADDING)) /* TAG */
1149 goto err;
1150 if (!stream_putc (stream, (u_char) 255)) /* LENGHT */
1151 goto err;
paul15935e92005-05-03 09:27:23 +00001152 stream_put (stream, NULL, 255); /* zero padding */
hassof390d2c2004-09-10 20:48:21 +00001153 }
1154
Josh Bailey3f045a02012-03-24 08:35:20 -07001155 left = stream_get_size (stream) - stream_get_endp (stream);
hassof390d2c2004-09-10 20:48:21 +00001156
jardineb5d44e2003-12-23 08:09:43 +00001157 if (left < 2)
1158 return ISIS_OK;
hassof390d2c2004-09-10 20:48:21 +00001159
1160 if (left == 2)
1161 {
1162 stream_putc (stream, PADDING);
1163 stream_putc (stream, 0);
1164 return ISIS_OK;
1165 }
1166
jardineb5d44e2003-12-23 08:09:43 +00001167 stream_putc (stream, PADDING);
1168 stream_putc (stream, left - 2);
paul15935e92005-05-03 09:27:23 +00001169 stream_put (stream, NULL, left-2);
jardineb5d44e2003-12-23 08:09:43 +00001170
1171 return ISIS_OK;
1172
hassof390d2c2004-09-10 20:48:21 +00001173err:
jardineb5d44e2003-12-23 08:09:43 +00001174 zlog_warn ("tlv_add_padding(): no room for tlv");
1175 return ISIS_WARNING;
1176}