blob: bb57bd6be4d2f140d7e0d9e94e25443a8920ea6c [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 u_char virtual;
119 int value_len, retval = ISIS_OK;
Josh Bailey3f045a02012-03-24 08:35:20 -0700120 u_char *start = stream, *pnt = stream;
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 */
182 virtual = *pnt; /* FIXME: what is the use for this? */
183 pnt++;
184 value_len++;
185 /* +-------+-------+-------+-------+-------+-------+-------+-------+
186 * | 0 | I/E | Default Metric |
187 * +-------+-------+-------+-------+-------+-------+-------+-------+
188 * | S | I/E | Delay Metric |
189 * +-------+-------+-------+-------+-------+-------+-------+-------+
190 * | S | I/E | Expense Metric |
191 * +-------+-------+-------+-------+-------+-------+-------+-------+
192 * | S | I/E | Error Metric |
193 * +-------+-------+-------+-------+-------+-------+-------+-------+
194 * | Neighbour ID |
195 * +---------------------------------------------------------------+
196 * : :
197 */
198 while (length > value_len)
199 {
200 is_nei = (struct is_neigh *) pnt;
201 value_len += 4 + ISIS_SYS_ID_LEN + 1;
202 pnt += 4 + ISIS_SYS_ID_LEN + 1;
203 if (!tlvs->is_neighs)
204 tlvs->is_neighs = list_new ();
205 listnode_add (tlvs->is_neighs, is_nei);
206 }
207 }
208 else
209 {
210 pnt += length;
211 }
212 break;
jardineb5d44e2003-12-23 08:09:43 +0000213
hassof390d2c2004-09-10 20:48:21 +0000214 case TE_IS_NEIGHBOURS:
215 /* +-------+-------+-------+-------+-------+-------+-------+-------+
216 * | Neighbour ID | 7
217 * +---------------------------------------------------------------+
218 * | TE Metric | 3
219 * +---------------------------------------------------------------+
220 * | SubTLVs Length | 1
221 * +---------------------------------------------------------------+
222 * : :
223 */
224 *found |= TLVFLAG_TE_IS_NEIGHS;
jardineb5d44e2003-12-23 08:09:43 +0000225#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000226 zlog_debug ("ISIS-TLV (%s): Extended IS Neighbours length %d",
hassof390d2c2004-09-10 20:48:21 +0000227 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000228#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000229 if (TLVFLAG_TE_IS_NEIGHS & *expected)
230 {
231 while (length > value_len)
232 {
233 te_is_nei = (struct te_is_neigh *) pnt;
234 value_len += 11;
235 pnt += 11;
236 /* FIXME - subtlvs are handled here, for now we skip */
237 value_len += te_is_nei->sub_tlvs_length;
238 pnt += te_is_nei->sub_tlvs_length;
jardineb5d44e2003-12-23 08:09:43 +0000239
hassof390d2c2004-09-10 20:48:21 +0000240 if (!tlvs->te_is_neighs)
241 tlvs->te_is_neighs = list_new ();
242 listnode_add (tlvs->te_is_neighs, te_is_nei);
243 }
244 }
245 else
246 {
247 pnt += length;
248 }
249 break;
jardineb5d44e2003-12-23 08:09:43 +0000250
hassof390d2c2004-09-10 20:48:21 +0000251 case ES_NEIGHBOURS:
252 /* +-------+-------+-------+-------+-------+-------+-------+-------+
253 * | 0 | I/E | Default Metric |
254 * +-------+-------+-------+-------+-------+-------+-------+-------+
255 * | S | I/E | Delay Metric |
256 * +-------+-------+-------+-------+-------+-------+-------+-------+
257 * | S | I/E | Expense Metric |
258 * +-------+-------+-------+-------+-------+-------+-------+-------+
259 * | S | I/E | Error Metric |
260 * +-------+-------+-------+-------+-------+-------+-------+-------+
261 * | Neighbour ID |
262 * +---------------------------------------------------------------+
263 * | Neighbour ID |
264 * +---------------------------------------------------------------+
265 * : :
266 */
jardineb5d44e2003-12-23 08:09:43 +0000267#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000268 zlog_debug ("ISIS-TLV (%s): ES Neighbours length %d",
hassof390d2c2004-09-10 20:48:21 +0000269 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000270#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000271 *found |= TLVFLAG_ES_NEIGHS;
272 if (*expected & TLVFLAG_ES_NEIGHS)
273 {
274 es_nei = (struct es_neigh *) pnt;
275 value_len += 4;
276 pnt += 4;
277 while (length > value_len)
278 {
279 /* FIXME FIXME FIXME - add to the list */
280 /* sys_id->id = pnt; */
281 value_len += ISIS_SYS_ID_LEN;
282 pnt += ISIS_SYS_ID_LEN;
283 /* if (!es_nei->neigh_ids) es_nei->neigh_ids = sysid; */
284 }
285 if (!tlvs->es_neighs)
286 tlvs->es_neighs = list_new ();
287 listnode_add (tlvs->es_neighs, es_nei);
288 }
289 else
290 {
291 pnt += length;
292 }
293 break;
jardineb5d44e2003-12-23 08:09:43 +0000294
hassof390d2c2004-09-10 20:48:21 +0000295 case LAN_NEIGHBOURS:
296 /* +-------+-------+-------+-------+-------+-------+-------+-------+
297 * | LAN Address |
298 * +-------+-------+-------+-------+-------+-------+-------+-------+
299 * : :
300 */
301 *found |= TLVFLAG_LAN_NEIGHS;
jardineb5d44e2003-12-23 08:09:43 +0000302#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000303 zlog_debug ("ISIS-TLV (%s): LAN Neigbours length %d",
304 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000305#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000306 if (TLVFLAG_LAN_NEIGHS & *expected)
307 {
308 while (length > value_len)
309 {
310 lan_nei = (struct lan_neigh *) pnt;
311 if (!tlvs->lan_neighs)
312 tlvs->lan_neighs = list_new ();
313 listnode_add (tlvs->lan_neighs, lan_nei);
314 value_len += ETH_ALEN;
315 pnt += ETH_ALEN;
316 }
317 }
318 else
319 {
320 pnt += length;
321 }
322 break;
jardineb5d44e2003-12-23 08:09:43 +0000323
hassof390d2c2004-09-10 20:48:21 +0000324 case PADDING:
jardineb5d44e2003-12-23 08:09:43 +0000325#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000326 zlog_debug ("TLV padding %d", length);
jardineb5d44e2003-12-23 08:09:43 +0000327#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000328 pnt += length;
329 break;
jardineb5d44e2003-12-23 08:09:43 +0000330
hassof390d2c2004-09-10 20:48:21 +0000331 case LSP_ENTRIES:
332 /* +-------+-------+-------+-------+-------+-------+-------+-------+
333 * | Remaining Lifetime | 2
334 * +-------+-------+-------+-------+-------+-------+-------+-------+
335 * | LSP ID | id+2
336 * +-------+-------+-------+-------+-------+-------+-------+-------+
337 * | LSP Sequence Number | 4
338 * +-------+-------+-------+-------+-------+-------+-------+-------+
339 * | Checksum | 2
340 * +-------+-------+-------+-------+-------+-------+-------+-------+
341 */
jardineb5d44e2003-12-23 08:09:43 +0000342#ifdef EXTREME_TLV_DEBUG
hasso92365882005-01-18 13:53:33 +0000343 zlog_debug ("ISIS-TLV (%s): LSP Entries length %d", areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000344#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000345 *found |= TLVFLAG_LSP_ENTRIES;
346 if (TLVFLAG_LSP_ENTRIES & *expected)
347 {
348 while (length > value_len)
349 {
350 lsp_entry = (struct lsp_entry *) pnt;
351 value_len += 10 + ISIS_SYS_ID_LEN;
352 pnt += 10 + ISIS_SYS_ID_LEN;
353 if (!tlvs->lsp_entries)
354 tlvs->lsp_entries = list_new ();
355 listnode_add (tlvs->lsp_entries, lsp_entry);
356 }
357 }
358 else
359 {
360 pnt += length;
361 }
362 break;
jardineb5d44e2003-12-23 08:09:43 +0000363
hassof390d2c2004-09-10 20:48:21 +0000364 case CHECKSUM:
365 /* +-------+-------+-------+-------+-------+-------+-------+-------+
366 * | 16 bit fletcher CHECKSUM |
367 * +-------+-------+-------+-------+-------+-------+-------+-------+
368 * : :
369 */
370 *found |= TLVFLAG_CHECKSUM;
jardineb5d44e2003-12-23 08:09:43 +0000371#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000372 zlog_debug ("ISIS-TLV (%s): Checksum length %d", areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000373#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000374 if (*expected & TLVFLAG_CHECKSUM)
375 {
376 tlvs->checksum = (struct checksum *) pnt;
377 }
378 pnt += length;
379 break;
jardineb5d44e2003-12-23 08:09:43 +0000380
hassof390d2c2004-09-10 20:48:21 +0000381 case PROTOCOLS_SUPPORTED:
382 /* +-------+-------+-------+-------+-------+-------+-------+-------+
383 * | NLPID |
384 * +-------+-------+-------+-------+-------+-------+-------+-------+
385 * : :
386 */
387 *found |= TLVFLAG_NLPID;
jardineb5d44e2003-12-23 08:09:43 +0000388#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000389 zlog_debug ("ISIS-TLV (%s): Protocols Supported length %d",
390 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000391#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000392 if (*expected & TLVFLAG_NLPID)
393 {
394 tlvs->nlpids = (struct nlpids *) (pnt - 1);
395 }
396 pnt += length;
397 break;
jardineb5d44e2003-12-23 08:09:43 +0000398
hassof390d2c2004-09-10 20:48:21 +0000399 case IPV4_ADDR:
400 /* +-------+-------+-------+-------+-------+-------+-------+-------+
401 * + IP version 4 address + 4
402 * +-------+-------+-------+-------+-------+-------+-------+-------+
403 * : :
404 */
405 *found |= TLVFLAG_IPV4_ADDR;
jardineb5d44e2003-12-23 08:09:43 +0000406#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000407 zlog_debug ("ISIS-TLV (%s): IPv4 Address length %d",
408 areatag, length);
hassof390d2c2004-09-10 20:48:21 +0000409#endif /* EXTREME_TLV_DEBUG */
410 if (*expected & TLVFLAG_IPV4_ADDR)
411 {
412 while (length > value_len)
413 {
414 ipv4_addr = (struct in_addr *) pnt;
hassof891f442004-09-14 13:54:30 +0000415#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000416 zlog_debug ("ISIS-TLV (%s) : IP ADDR %s, pnt %p", areatag,
417 inet_ntoa (*ipv4_addr), pnt);
hassof891f442004-09-14 13:54:30 +0000418#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000419 if (!tlvs->ipv4_addrs)
420 tlvs->ipv4_addrs = list_new ();
421 listnode_add (tlvs->ipv4_addrs, ipv4_addr);
422 value_len += 4;
423 pnt += 4;
424 }
425 }
426 else
427 {
428 pnt += length;
429 }
430 break;
431
432 case AUTH_INFO:
433 *found |= TLVFLAG_AUTH_INFO;
434#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000435 zlog_debug ("ISIS-TLV (%s): IS-IS Authentication Information",
436 areatag);
jardineb5d44e2003-12-23 08:09:43 +0000437#endif
hassof390d2c2004-09-10 20:48:21 +0000438 if (*expected & TLVFLAG_AUTH_INFO)
439 {
440 tlvs->auth_info.type = *pnt;
Josh Bailey3f045a02012-03-24 08:35:20 -0700441 if (length == 0)
442 {
443 zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) "
444 "incorrect.", areatag, type, length);
445 return ISIS_WARNING;
446 }
447 --length;
448 tlvs->auth_info.len = length;
hassof390d2c2004-09-10 20:48:21 +0000449 pnt++;
Josh Bailey3f045a02012-03-24 08:35:20 -0700450 memcpy (tlvs->auth_info.passwd, pnt, length);
451 /* Return the authentication tlv pos for later computation
452 * of MD5 (RFC 5304, 2)
453 */
454 if (auth_tlv_offset)
455 *auth_tlv_offset += (pnt - start - 3);
456 pnt += length;
hassof390d2c2004-09-10 20:48:21 +0000457 }
458 else
459 {
460 pnt += length;
461 }
462 break;
jardineb5d44e2003-12-23 08:09:43 +0000463
hassof390d2c2004-09-10 20:48:21 +0000464 case DYNAMIC_HOSTNAME:
465 *found |= TLVFLAG_DYN_HOSTNAME;
jardineb5d44e2003-12-23 08:09:43 +0000466#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000467 zlog_debug ("ISIS-TLV (%s): Dynamic Hostname length %d",
468 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000469#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000470 if (*expected & TLVFLAG_DYN_HOSTNAME)
471 {
472 /* the length is also included in the pointed struct */
473 tlvs->hostname = (struct hostname *) (pnt - 1);
474 }
475 pnt += length;
476 break;
jardineb5d44e2003-12-23 08:09:43 +0000477
hassof390d2c2004-09-10 20:48:21 +0000478 case TE_ROUTER_ID:
479 /* +---------------------------------------------------------------+
480 * + Router ID + 4
481 * +---------------------------------------------------------------+
482 */
483 *found |= TLVFLAG_TE_ROUTER_ID;
jardineb5d44e2003-12-23 08:09:43 +0000484#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000485 zlog_debug ("ISIS-TLV (%s): TE Router ID %d", areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000486#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000487 if (*expected & TLVFLAG_TE_ROUTER_ID)
hasso1cd80842004-10-07 20:07:40 +0000488 tlvs->router_id = (struct te_router_id *) (pnt);
hassof390d2c2004-09-10 20:48:21 +0000489 pnt += length;
490 break;
jardineb5d44e2003-12-23 08:09:43 +0000491
hassof390d2c2004-09-10 20:48:21 +0000492 case IPV4_INT_REACHABILITY:
493 /* +-------+-------+-------+-------+-------+-------+-------+-------+
494 * | 0 | I/E | Default Metric | 1
495 * +-------+-------+-------+-------+-------+-------+-------+-------+
496 * | S | I/E | Delay Metric | 1
497 * +-------+-------+-------+-------+-------+-------+-------+-------+
498 * | S | I/E | Expense Metric | 1
499 * +-------+-------+-------+-------+-------+-------+-------+-------+
500 * | S | I/E | Error Metric | 1
501 * +-------+-------+-------+-------+-------+-------+-------+-------+
502 * | ip address | 4
503 * +---------------------------------------------------------------+
504 * | address mask | 4
505 * +---------------------------------------------------------------+
506 * : :
507 */
508 *found |= TLVFLAG_IPV4_INT_REACHABILITY;
jardineb5d44e2003-12-23 08:09:43 +0000509#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000510 zlog_debug ("ISIS-TLV (%s): IPv4 internal Reachability length %d",
511 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000512#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000513 if (*expected & TLVFLAG_IPV4_INT_REACHABILITY)
514 {
515 while (length > value_len)
516 {
517 ipv4_reach = (struct ipv4_reachability *) pnt;
518 if (!tlvs->ipv4_int_reachs)
519 tlvs->ipv4_int_reachs = list_new ();
520 listnode_add (tlvs->ipv4_int_reachs, ipv4_reach);
521 value_len += 12;
522 pnt += 12;
523 }
524 }
525 else
526 {
527 pnt += length;
528 }
529 break;
jardineb5d44e2003-12-23 08:09:43 +0000530
hassof390d2c2004-09-10 20:48:21 +0000531 case IPV4_EXT_REACHABILITY:
532 /* +-------+-------+-------+-------+-------+-------+-------+-------+
533 * | 0 | I/E | Default Metric | 1
534 * +-------+-------+-------+-------+-------+-------+-------+-------+
535 * | S | I/E | Delay Metric | 1
536 * +-------+-------+-------+-------+-------+-------+-------+-------+
537 * | S | I/E | Expense Metric | 1
538 * +-------+-------+-------+-------+-------+-------+-------+-------+
539 * | S | I/E | Error Metric | 1
540 * +-------+-------+-------+-------+-------+-------+-------+-------+
541 * | ip address | 4
542 * +---------------------------------------------------------------+
543 * | address mask | 4
544 * +---------------------------------------------------------------+
545 * : :
546 */
547 *found |= TLVFLAG_IPV4_EXT_REACHABILITY;
jardineb5d44e2003-12-23 08:09:43 +0000548#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000549 zlog_debug ("ISIS-TLV (%s): IPv4 external Reachability length %d",
550 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000551#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000552 if (*expected & TLVFLAG_IPV4_EXT_REACHABILITY)
553 {
554 while (length > value_len)
555 {
556 ipv4_reach = (struct ipv4_reachability *) pnt;
557 if (!tlvs->ipv4_ext_reachs)
558 tlvs->ipv4_ext_reachs = list_new ();
559 listnode_add (tlvs->ipv4_ext_reachs, ipv4_reach);
560 value_len += 12;
561 pnt += 12;
562 }
563 }
564 else
565 {
566 pnt += length;
567 }
568 break;
jardineb5d44e2003-12-23 08:09:43 +0000569
hassof390d2c2004-09-10 20:48:21 +0000570 case TE_IPV4_REACHABILITY:
571 /* +-------+-------+-------+-------+-------+-------+-------+-------+
572 * | TE Metric | 4
573 * +-------+-------+-------+-------+-------+-------+-------+-------+
574 * | U/D | sTLV? | Prefix Mask Len | 1
575 * +-------+-------+-------+-------+-------+-------+-------+-------+
576 * | Prefix | 0-4
577 * +---------------------------------------------------------------+
578 * | sub tlvs |
579 * +---------------------------------------------------------------+
580 * : :
581 */
582 *found |= TLVFLAG_TE_IPV4_REACHABILITY;
jardineb5d44e2003-12-23 08:09:43 +0000583#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000584 zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d",
585 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000586#endif /* EXTREME_TLV_DEBUG */
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;
592 if (!tlvs->te_ipv4_reachs)
593 tlvs->te_ipv4_reachs = list_new ();
594 listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach);
595 /* this trickery is permitable since no subtlvs are defined */
596 value_len += 5 + ((te_ipv4_reach->control & 0x3F) ?
597 ((((te_ipv4_reach->control & 0x3F) -
598 1) >> 3) + 1) : 0);
599 pnt += 5 + ((te_ipv4_reach->control & 0x3F) ?
600 ((((te_ipv4_reach->control & 0x3F) - 1) >> 3) + 1) : 0);
601 }
602 }
603 else
604 {
605 pnt += length;
606 }
607 break;
jardineb5d44e2003-12-23 08:09:43 +0000608
609#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000610 case IPV6_ADDR:
611 /* +-------+-------+-------+-------+-------+-------+-------+-------+
612 * + IP version 6 address + 16
613 * +-------+-------+-------+-------+-------+-------+-------+-------+
614 * : :
615 */
616 *found |= TLVFLAG_IPV6_ADDR;
jardineb5d44e2003-12-23 08:09:43 +0000617#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000618 zlog_debug ("ISIS-TLV (%s): IPv6 Address length %d",
619 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000620#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000621 if (*expected & TLVFLAG_IPV6_ADDR)
622 {
623 while (length > value_len)
624 {
625 ipv6_addr = (struct in6_addr *) pnt;
626 if (!tlvs->ipv6_addrs)
627 tlvs->ipv6_addrs = list_new ();
628 listnode_add (tlvs->ipv6_addrs, ipv6_addr);
629 value_len += 16;
630 pnt += 16;
631 }
632 }
633 else
634 {
635 pnt += length;
636 }
637 break;
jardineb5d44e2003-12-23 08:09:43 +0000638
hassof390d2c2004-09-10 20:48:21 +0000639 case IPV6_REACHABILITY:
640 /* +-------+-------+-------+-------+-------+-------+-------+-------+
641 * | Default Metric | 4
642 * +-------+-------+-------+-------+-------+-------+-------+-------+
643 * | Control Informantion |
644 * +---------------------------------------------------------------+
645 * | IPv6 Prefix Length |--+
646 * +---------------------------------------------------------------+ |
647 * | IPv6 Prefix |<-+
648 * +---------------------------------------------------------------+
649 */
650 *found |= TLVFLAG_IPV6_REACHABILITY;
651 if (*expected & TLVFLAG_IPV6_REACHABILITY)
652 {
653 while (length > value_len)
654 {
655 ipv6_reach = (struct ipv6_reachability *) pnt;
656 prefix_octets = ((ipv6_reach->prefix_len + 7) / 8);
657 value_len += prefix_octets + 6;
658 pnt += prefix_octets + 6;
659 /* FIXME: sub-tlvs */
660 if (!tlvs->ipv6_reachs)
661 tlvs->ipv6_reachs = list_new ();
662 listnode_add (tlvs->ipv6_reachs, ipv6_reach);
663 }
664 }
665 else
666 {
667 pnt += length;
668 }
669 break;
jardineb5d44e2003-12-23 08:09:43 +0000670#endif /* HAVE_IPV6 */
671
hassof390d2c2004-09-10 20:48:21 +0000672 case WAY3_HELLO:
673 /* +---------------------------------------------------------------+
674 * | Adjacency state | 1
675 * +---------------------------------------------------------------+
676 * | Extended Local Circuit ID | 4
677 * +---------------------------------------------------------------+
678 * | Neighbor System ID (If known) | 0-8
679 * (probably 6)
680 * +---------------------------------------------------------------+
681 * | Neighbor Local Circuit ID (If known) | 4
682 * +---------------------------------------------------------------+
683 */
684 *found |= TLVFLAG_3WAY_HELLO;
685 if (*expected & TLVFLAG_3WAY_HELLO)
686 {
687 while (length > value_len)
688 {
689 /* FIXME: make this work */
jardineb5d44e2003-12-23 08:09:43 +0000690/* Adjacency State (one octet):
691 0 = Up
692 1 = Initializing
693 2 = Down
694 Extended Local Circuit ID (four octets)
695 Neighbor System ID if known (zero to eight octets)
696 Neighbor Extended Local Circuit ID (four octets, if Neighbor
697 System ID is present) */
hassof390d2c2004-09-10 20:48:21 +0000698 pnt += length;
699 }
700 }
701 else
702 {
703 pnt += length;
704 }
jardineb5d44e2003-12-23 08:09:43 +0000705
hassof390d2c2004-09-10 20:48:21 +0000706 break;
707 case GRACEFUL_RESTART:
708 /* +-------+-------+-------+-------+-------+-------+-------+-------+
709 * | Reserved | SA | RA | RR | 1
710 * +-------+-------+-------+-------+-------+-------+-------+-------+
711 * | Remaining Time | 2
712 * +---------------------------------------------------------------+
713 * | Restarting Neighbor ID (If known) | 0-8
714 * +---------------------------------------------------------------+
715 */
716 *found |= TLVFLAG_GRACEFUL_RESTART;
717 if (*expected & TLVFLAG_GRACEFUL_RESTART)
718 {
719 /* FIXME: make this work */
720 }
721 pnt += length;
722 break;
jardineb5d44e2003-12-23 08:09:43 +0000723
hassof390d2c2004-09-10 20:48:21 +0000724 default:
725 zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
726 areatag, type, length);
jardineb5d44e2003-12-23 08:09:43 +0000727
hassof390d2c2004-09-10 20:48:21 +0000728 retval = ISIS_WARNING;
729 pnt += length;
730 break;
731 }
jardineb5d44e2003-12-23 08:09:43 +0000732 }
hassof390d2c2004-09-10 20:48:21 +0000733
jardineb5d44e2003-12-23 08:09:43 +0000734 return retval;
735}
736
737int
hassof390d2c2004-09-10 20:48:21 +0000738add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000739{
Josh Bailey3f045a02012-03-24 08:35:20 -0700740 if ((stream_get_size (stream) - stream_get_endp (stream)) <
741 (((unsigned)len) + 2))
hassof390d2c2004-09-10 20:48:21 +0000742 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700743 zlog_warn ("No room for TLV of type %d "
744 "(total size %d available %d required %d)",
745 tag, (int)stream_get_size (stream),
746 (int)(stream_get_size (stream) - stream_get_endp (stream)),
747 len+2);
hassof390d2c2004-09-10 20:48:21 +0000748 return ISIS_WARNING;
749 }
jardineb5d44e2003-12-23 08:09:43 +0000750
hassof390d2c2004-09-10 20:48:21 +0000751 stream_putc (stream, tag); /* TAG */
752 stream_putc (stream, len); /* LENGTH */
753 stream_put (stream, value, (int) len); /* VALUE */
jardineb5d44e2003-12-23 08:09:43 +0000754
755#ifdef EXTREME_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000756 zlog_debug ("Added TLV %d len %d", tag, len);
jardineb5d44e2003-12-23 08:09:43 +0000757#endif /* EXTREME DEBUG */
758 return ISIS_OK;
759}
760
jardineb5d44e2003-12-23 08:09:43 +0000761int
hassof390d2c2004-09-10 20:48:21 +0000762tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000763{
764 struct listnode *node;
765 struct area_addr *area_addr;
766
hassof390d2c2004-09-10 20:48:21 +0000767 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000768 u_char *pos = value;
hassof390d2c2004-09-10 20:48:21 +0000769
paul1eb8ef22005-04-07 07:30:20 +0000770 for (ALL_LIST_ELEMENTS_RO (area_addrs, node, area_addr))
hassof390d2c2004-09-10 20:48:21 +0000771 {
hassof390d2c2004-09-10 20:48:21 +0000772 if (pos - value + area_addr->addr_len > 255)
773 goto err;
774 *pos = area_addr->addr_len;
775 pos++;
776 memcpy (pos, area_addr->area_addr, (int) area_addr->addr_len);
777 pos += area_addr->addr_len;
778 }
779
jardineb5d44e2003-12-23 08:09:43 +0000780 return add_tlv (AREA_ADDRESSES, pos - value, value, stream);
781
hassof390d2c2004-09-10 20:48:21 +0000782err:
jardineb5d44e2003-12-23 08:09:43 +0000783 zlog_warn ("tlv_add_area_addrs(): TLV longer than 255");
784 return ISIS_WARNING;
785}
786
hassof390d2c2004-09-10 20:48:21 +0000787int
788tlv_add_is_neighs (struct list *is_neighs, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000789{
hasso3fdb2dd2005-09-28 18:45:54 +0000790 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000791 struct is_neigh *is_neigh;
hassof390d2c2004-09-10 20:48:21 +0000792 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000793 u_char *pos = value;
794 int retval;
795
hassof390d2c2004-09-10 20:48:21 +0000796 *pos = 0; /*is_neigh->virtual; */
797 pos++;
jardineb5d44e2003-12-23 08:09:43 +0000798
hasso3fdb2dd2005-09-28 18:45:54 +0000799 for (ALL_LIST_ELEMENTS_RO (is_neighs, node, is_neigh))
hassof390d2c2004-09-10 20:48:21 +0000800 {
hassof390d2c2004-09-10 20:48:21 +0000801 if (pos - value + IS_NEIGHBOURS_LEN > 255)
802 {
803 retval = add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
804 if (retval != ISIS_OK)
805 return retval;
806 pos = value;
807 }
808 *pos = is_neigh->metrics.metric_default;
809 pos++;
810 *pos = is_neigh->metrics.metric_delay;
811 pos++;
812 *pos = is_neigh->metrics.metric_expense;
813 pos++;
814 *pos = is_neigh->metrics.metric_error;
815 pos++;
816 memcpy (pos, is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
817 pos += ISIS_SYS_ID_LEN + 1;
jardineb5d44e2003-12-23 08:09:43 +0000818 }
jardineb5d44e2003-12-23 08:09:43 +0000819
820 return add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
821}
822
jardineb5d44e2003-12-23 08:09:43 +0000823int
hassoea3be4c2005-09-26 17:11:12 +0000824tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
825{
hasso3fdb2dd2005-09-28 18:45:54 +0000826 struct listnode *node;
hassoea3be4c2005-09-26 17:11:12 +0000827 struct te_is_neigh *te_is_neigh;
828 u_char value[255];
829 u_char *pos = value;
830 int retval;
831
hasso3fdb2dd2005-09-28 18:45:54 +0000832 for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh))
hassoea3be4c2005-09-26 17:11:12 +0000833 {
834 /* FIXME: This will be wrong if we are going to add TE sub TLVs. */
835 if (pos - value + IS_NEIGHBOURS_LEN > 255)
836 {
837 retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
838 if (retval != ISIS_OK)
839 return retval;
840 pos = value;
841 }
842
843 memcpy (pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
844 pos += ISIS_SYS_ID_LEN + 1;
845 memcpy (pos, te_is_neigh->te_metric, 3);
846 pos += 3;
847 /* Sub TLVs length. */
848 *pos = 0;
849 pos++;
850 }
851
852 return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
853}
854
855int
jardineb5d44e2003-12-23 08:09:43 +0000856tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream)
857{
hasso3fdb2dd2005-09-28 18:45:54 +0000858 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000859 u_char *snpa;
hassof390d2c2004-09-10 20:48:21 +0000860 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000861 u_char *pos = value;
862 int retval;
863
hasso3fdb2dd2005-09-28 18:45:54 +0000864 for (ALL_LIST_ELEMENTS_RO (lan_neighs, node, snpa))
hassof390d2c2004-09-10 20:48:21 +0000865 {
hassof390d2c2004-09-10 20:48:21 +0000866 if (pos - value + ETH_ALEN > 255)
867 {
868 retval = add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
869 if (retval != ISIS_OK)
870 return retval;
871 pos = value;
872 }
873 memcpy (pos, snpa, ETH_ALEN);
874 pos += ETH_ALEN;
jardineb5d44e2003-12-23 08:09:43 +0000875 }
jardineb5d44e2003-12-23 08:09:43 +0000876
877 return add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
878}
879
jardineb5d44e2003-12-23 08:09:43 +0000880int
881tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream)
882{
hassof390d2c2004-09-10 20:48:21 +0000883 return add_tlv (PROTOCOLS_SUPPORTED, nlpids->count, nlpids->nlpids, stream);
jardineb5d44e2003-12-23 08:09:43 +0000884}
885
hassof390d2c2004-09-10 20:48:21 +0000886int
Josh Bailey3f045a02012-03-24 08:35:20 -0700887tlv_add_authinfo (u_char auth_type, u_char auth_len, u_char *auth_value,
hassof390d2c2004-09-10 20:48:21 +0000888 struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000889{
890 u_char value[255];
891 u_char *pos = value;
Josh Bailey3f045a02012-03-24 08:35:20 -0700892 *pos++ = auth_type;
jardineb5d44e2003-12-23 08:09:43 +0000893 memcpy (pos, auth_value, auth_len);
894
895 return add_tlv (AUTH_INFO, auth_len + 1, value, stream);
896}
897
898int
899tlv_add_checksum (struct checksum *checksum, struct stream *stream)
900{
901 u_char value[255];
hassof390d2c2004-09-10 20:48:21 +0000902 u_char *pos = value;
903 return add_tlv (CHECKSUM, pos - value, value, stream);
jardineb5d44e2003-12-23 08:09:43 +0000904}
905
906int
907tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream)
908{
hasso3fdb2dd2005-09-28 18:45:54 +0000909 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000910 struct prefix_ipv4 *ipv4;
911 u_char value[255];
912 u_char *pos = value;
913 int retval;
914
hasso3fdb2dd2005-09-28 18:45:54 +0000915 for (ALL_LIST_ELEMENTS_RO (ip_addrs, node, ipv4))
hassof390d2c2004-09-10 20:48:21 +0000916 {
hassof390d2c2004-09-10 20:48:21 +0000917 if (pos - value + IPV4_MAX_BYTELEN > 255)
918 {
919 retval = add_tlv (IPV4_ADDR, pos - value, value, stream);
920 if (retval != ISIS_OK)
921 return retval;
922 pos = value;
923 }
924 *(u_int32_t *) pos = ipv4->prefix.s_addr;
925 pos += IPV4_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +0000926 }
hassof390d2c2004-09-10 20:48:21 +0000927
jardineb5d44e2003-12-23 08:09:43 +0000928 return add_tlv (IPV4_ADDR, pos - value, value, stream);
929}
930
hasso81ad8f62005-09-26 17:58:24 +0000931/* Used to add TLV containing just one IPv4 address - either IPv4 address TLV
932 * (in case of LSP) or TE router ID TLV. */
933int
934tlv_add_in_addr (struct in_addr *addr, struct stream *stream, u_char tag)
935{
936 u_char value[255];
937 u_char *pos = value;
938
939 memcpy (pos, addr, IPV4_MAX_BYTELEN);
940 pos += IPV4_MAX_BYTELEN;
941
942 return add_tlv (tag, pos - value, value, stream);
943}
944
jardineb5d44e2003-12-23 08:09:43 +0000945int
946tlv_add_dynamic_hostname (struct hostname *hostname, struct stream *stream)
947{
hassof390d2c2004-09-10 20:48:21 +0000948 return add_tlv (DYNAMIC_HOSTNAME, hostname->namelen, hostname->name,
949 stream);
jardineb5d44e2003-12-23 08:09:43 +0000950}
951
hassof390d2c2004-09-10 20:48:21 +0000952int
jardineb5d44e2003-12-23 08:09:43 +0000953tlv_add_lsp_entries (struct list *lsps, struct stream *stream)
954{
hasso3fdb2dd2005-09-28 18:45:54 +0000955 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000956 struct isis_lsp *lsp;
hassof390d2c2004-09-10 20:48:21 +0000957 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000958 u_char *pos = value;
959 int retval;
960
hasso3fdb2dd2005-09-28 18:45:54 +0000961 for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp))
hassof390d2c2004-09-10 20:48:21 +0000962 {
hassof390d2c2004-09-10 20:48:21 +0000963 if (pos - value + LSP_ENTRIES_LEN > 255)
964 {
965 retval = add_tlv (LSP_ENTRIES, pos - value, value, stream);
966 if (retval != ISIS_OK)
967 return retval;
968 pos = value;
969 }
970 *((u_int16_t *) pos) = lsp->lsp_header->rem_lifetime;
971 pos += 2;
972 memcpy (pos, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
973 pos += ISIS_SYS_ID_LEN + 2;
974 *((u_int32_t *) pos) = lsp->lsp_header->seq_num;
975 pos += 4;
976 *((u_int16_t *) pos) = lsp->lsp_header->checksum;
977 pos += 2;
jardineb5d44e2003-12-23 08:09:43 +0000978 }
hassof390d2c2004-09-10 20:48:21 +0000979
jardineb5d44e2003-12-23 08:09:43 +0000980 return add_tlv (LSP_ENTRIES, pos - value, value, stream);
981}
982
hassof390d2c2004-09-10 20:48:21 +0000983int
jardineb5d44e2003-12-23 08:09:43 +0000984tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream)
985{
hasso3fdb2dd2005-09-28 18:45:54 +0000986 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000987 struct ipv4_reachability *reach;
hassof390d2c2004-09-10 20:48:21 +0000988 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000989 u_char *pos = value;
990 int retval;
991
hasso3fdb2dd2005-09-28 18:45:54 +0000992 for (ALL_LIST_ELEMENTS_RO (ipv4_reachs, node, reach))
hassof390d2c2004-09-10 20:48:21 +0000993 {
hassof390d2c2004-09-10 20:48:21 +0000994 if (pos - value + IPV4_REACH_LEN > 255)
995 {
996 retval =
997 add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
998 if (retval != ISIS_OK)
999 return retval;
1000 pos = value;
1001 }
1002 *pos = reach->metrics.metric_default;
1003 pos++;
1004 *pos = reach->metrics.metric_delay;
1005 pos++;
1006 *pos = reach->metrics.metric_expense;
1007 pos++;
1008 *pos = reach->metrics.metric_error;
1009 pos++;
1010 *(u_int32_t *) pos = reach->prefix.s_addr;
1011 pos += IPV4_MAX_BYTELEN;
1012 *(u_int32_t *) pos = reach->mask.s_addr;
1013 pos += IPV4_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +00001014 }
hassof390d2c2004-09-10 20:48:21 +00001015
jardineb5d44e2003-12-23 08:09:43 +00001016 return add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
1017}
1018
hassoea3be4c2005-09-26 17:11:12 +00001019int
1020tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream)
1021{
hasso3fdb2dd2005-09-28 18:45:54 +00001022 struct listnode *node;
hassoea3be4c2005-09-26 17:11:12 +00001023 struct te_ipv4_reachability *te_reach;
1024 u_char value[255];
1025 u_char *pos = value;
1026 u_char prefix_size;
1027 int retval;
1028
hasso3fdb2dd2005-09-28 18:45:54 +00001029 for (ALL_LIST_ELEMENTS_RO (te_ipv4_reachs, node, te_reach))
hassoea3be4c2005-09-26 17:11:12 +00001030 {
1031 prefix_size = ((((te_reach->control & 0x3F) - 1) >> 3) + 1);
1032
1033 if (pos - value + (5 + prefix_size) > 255)
1034 {
1035 retval =
Josh Bailey3f045a02012-03-24 08:35:20 -07001036 add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
hassoea3be4c2005-09-26 17:11:12 +00001037 if (retval != ISIS_OK)
1038 return retval;
1039 pos = value;
1040 }
1041 *(u_int32_t *) pos = te_reach->te_metric;
1042 pos += 4;
1043 *pos = te_reach->control;
1044 pos++;
1045 memcpy (pos, &te_reach->prefix_start, prefix_size);
1046 pos += prefix_size;
1047 }
1048
1049 return add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
1050}
1051
hassof390d2c2004-09-10 20:48:21 +00001052#ifdef HAVE_IPV6
jardineb5d44e2003-12-23 08:09:43 +00001053int
1054tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream)
1055{
hasso3fdb2dd2005-09-28 18:45:54 +00001056 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00001057 struct prefix_ipv6 *ipv6;
1058 u_char value[255];
1059 u_char *pos = value;
1060 int retval;
hassof390d2c2004-09-10 20:48:21 +00001061
hasso3fdb2dd2005-09-28 18:45:54 +00001062 for (ALL_LIST_ELEMENTS_RO (ipv6_addrs, node, ipv6))
hassof390d2c2004-09-10 20:48:21 +00001063 {
hassof390d2c2004-09-10 20:48:21 +00001064 if (pos - value + IPV6_MAX_BYTELEN > 255)
1065 {
1066 retval = add_tlv (IPV6_ADDR, pos - value, value, stream);
1067 if (retval != ISIS_OK)
1068 return retval;
1069 pos = value;
1070 }
1071 memcpy (pos, ipv6->prefix.s6_addr, IPV6_MAX_BYTELEN);
1072 pos += IPV6_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +00001073 }
hassof390d2c2004-09-10 20:48:21 +00001074
jardineb5d44e2003-12-23 08:09:43 +00001075 return add_tlv (IPV6_ADDR, pos - value, value, stream);
1076}
1077
1078int
1079tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream)
1080{
hasso3fdb2dd2005-09-28 18:45:54 +00001081 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00001082 struct ipv6_reachability *ip6reach;
1083 u_char value[255];
1084 u_char *pos = value;
1085 int retval, prefix_octets;
hassof390d2c2004-09-10 20:48:21 +00001086
hasso3fdb2dd2005-09-28 18:45:54 +00001087 for (ALL_LIST_ELEMENTS_RO (ipv6_reachs, node, ip6reach))
hassof390d2c2004-09-10 20:48:21 +00001088 {
hassof390d2c2004-09-10 20:48:21 +00001089 if (pos - value + IPV6_MAX_BYTELEN + 6 > 255)
1090 {
1091 retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
1092 if (retval != ISIS_OK)
1093 return retval;
1094 pos = value;
1095 }
1096 *(uint32_t *) pos = ip6reach->metric;
1097 pos += 4;
1098 *pos = ip6reach->control_info;
1099 pos++;
1100 prefix_octets = ((ip6reach->prefix_len + 7) / 8);
1101 *pos = ip6reach->prefix_len;
1102 pos++;
1103 memcpy (pos, ip6reach->prefix, prefix_octets);
1104 pos += prefix_octets;
jardineb5d44e2003-12-23 08:09:43 +00001105 }
hassof390d2c2004-09-10 20:48:21 +00001106
jardineb5d44e2003-12-23 08:09:43 +00001107 return add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
1108}
1109#endif /* HAVE_IPV6 */
1110
1111int
1112tlv_add_padding (struct stream *stream)
1113{
hassof390d2c2004-09-10 20:48:21 +00001114 int fullpads, i, left;
1115
jardineb5d44e2003-12-23 08:09:43 +00001116 /*
1117 * How many times can we add full padding ?
1118 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001119 fullpads = (stream_get_size (stream) - stream_get_endp (stream)) / 257;
hassof390d2c2004-09-10 20:48:21 +00001120 for (i = 0; i < fullpads; i++)
1121 {
1122 if (!stream_putc (stream, (u_char) PADDING)) /* TAG */
1123 goto err;
1124 if (!stream_putc (stream, (u_char) 255)) /* LENGHT */
1125 goto err;
paul15935e92005-05-03 09:27:23 +00001126 stream_put (stream, NULL, 255); /* zero padding */
hassof390d2c2004-09-10 20:48:21 +00001127 }
1128
Josh Bailey3f045a02012-03-24 08:35:20 -07001129 left = stream_get_size (stream) - stream_get_endp (stream);
hassof390d2c2004-09-10 20:48:21 +00001130
jardineb5d44e2003-12-23 08:09:43 +00001131 if (left < 2)
1132 return ISIS_OK;
hassof390d2c2004-09-10 20:48:21 +00001133
1134 if (left == 2)
1135 {
1136 stream_putc (stream, PADDING);
1137 stream_putc (stream, 0);
1138 return ISIS_OK;
1139 }
1140
jardineb5d44e2003-12-23 08:09:43 +00001141 stream_putc (stream, PADDING);
1142 stream_putc (stream, left - 2);
paul15935e92005-05-03 09:27:23 +00001143 stream_put (stream, NULL, left-2);
jardineb5d44e2003-12-23 08:09:43 +00001144
1145 return ISIS_OK;
1146
hassof390d2c2004-09-10 20:48:21 +00001147err:
jardineb5d44e2003-12-23 08:09:43 +00001148 zlog_warn ("tlv_add_padding(): no room for tlv");
1149 return ISIS_WARNING;
1150}