blob: 7b99ab5d109beafeae2c15bbf9a1673ed566d9d1 [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
46extern struct isis *isis;
47
48void
49free_tlv (void *val)
50{
hassof390d2c2004-09-10 20:48:21 +000051 XFREE (MTYPE_ISIS_TLV, val);
52
53 return;
jardineb5d44e2003-12-23 08:09:43 +000054}
55
56/*
57 * Called after parsing of a PDU. There shouldn't be any tlv's left, so this
58 * is only a caution to avoid memory leaks
59 */
hassof390d2c2004-09-10 20:48:21 +000060void
jardineb5d44e2003-12-23 08:09:43 +000061free_tlvs (struct tlvs *tlvs)
62{
hassof390d2c2004-09-10 20:48:21 +000063 if (tlvs->area_addrs)
hassoaac372f2005-09-01 17:52:33 +000064 list_delete (tlvs->area_addrs);
hassof390d2c2004-09-10 20:48:21 +000065 if (tlvs->is_neighs)
hassoaac372f2005-09-01 17:52:33 +000066 list_delete (tlvs->is_neighs);
hassof390d2c2004-09-10 20:48:21 +000067 if (tlvs->te_is_neighs)
hassoaac372f2005-09-01 17:52:33 +000068 list_delete (tlvs->te_is_neighs);
hassof390d2c2004-09-10 20:48:21 +000069 if (tlvs->es_neighs)
hassoaac372f2005-09-01 17:52:33 +000070 list_delete (tlvs->es_neighs);
hassof390d2c2004-09-10 20:48:21 +000071 if (tlvs->lsp_entries)
hassoaac372f2005-09-01 17:52:33 +000072 list_delete (tlvs->lsp_entries);
hassof390d2c2004-09-10 20:48:21 +000073 if (tlvs->lan_neighs)
hassoaac372f2005-09-01 17:52:33 +000074 list_delete (tlvs->lan_neighs);
hassof390d2c2004-09-10 20:48:21 +000075 if (tlvs->prefix_neighs)
hassoaac372f2005-09-01 17:52:33 +000076 list_delete (tlvs->prefix_neighs);
hassof390d2c2004-09-10 20:48:21 +000077 if (tlvs->ipv4_addrs)
hassoaac372f2005-09-01 17:52:33 +000078 list_delete (tlvs->ipv4_addrs);
hassof390d2c2004-09-10 20:48:21 +000079 if (tlvs->ipv4_int_reachs)
hassoaac372f2005-09-01 17:52:33 +000080 list_delete (tlvs->ipv4_int_reachs);
hassof390d2c2004-09-10 20:48:21 +000081 if (tlvs->ipv4_ext_reachs)
hassoaac372f2005-09-01 17:52:33 +000082 list_delete (tlvs->ipv4_ext_reachs);
hassof390d2c2004-09-10 20:48:21 +000083 if (tlvs->te_ipv4_reachs)
hassoaac372f2005-09-01 17:52:33 +000084 list_delete (tlvs->te_ipv4_reachs);
jardineb5d44e2003-12-23 08:09:43 +000085#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +000086 if (tlvs->ipv6_addrs)
hassoaac372f2005-09-01 17:52:33 +000087 list_delete (tlvs->ipv6_addrs);
hassof390d2c2004-09-10 20:48:21 +000088 if (tlvs->ipv6_reachs)
hassoaac372f2005-09-01 17:52:33 +000089 list_delete (tlvs->ipv6_reachs);
jardineb5d44e2003-12-23 08:09:43 +000090#endif /* HAVE_IPV6 */
hassoaac372f2005-09-01 17:52:33 +000091
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,
101 u_int32_t * found, struct tlvs *tlvs)
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;
120 u_char *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;
hasso53c997c2004-09-15 16:21:59 +0000441 tlvs->auth_info.len = length-1;
hassof390d2c2004-09-10 20:48:21 +0000442 pnt++;
443 memcpy (tlvs->auth_info.passwd, pnt, length - 1);
444 pnt += length - 1;
445 }
446 else
447 {
448 pnt += length;
449 }
450 break;
jardineb5d44e2003-12-23 08:09:43 +0000451
hassof390d2c2004-09-10 20:48:21 +0000452 case DYNAMIC_HOSTNAME:
453 *found |= TLVFLAG_DYN_HOSTNAME;
jardineb5d44e2003-12-23 08:09:43 +0000454#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000455 zlog_debug ("ISIS-TLV (%s): Dynamic Hostname length %d",
456 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000457#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000458 if (*expected & TLVFLAG_DYN_HOSTNAME)
459 {
460 /* the length is also included in the pointed struct */
461 tlvs->hostname = (struct hostname *) (pnt - 1);
462 }
463 pnt += length;
464 break;
jardineb5d44e2003-12-23 08:09:43 +0000465
hassof390d2c2004-09-10 20:48:21 +0000466 case TE_ROUTER_ID:
467 /* +---------------------------------------------------------------+
468 * + Router ID + 4
469 * +---------------------------------------------------------------+
470 */
471 *found |= TLVFLAG_TE_ROUTER_ID;
jardineb5d44e2003-12-23 08:09:43 +0000472#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000473 zlog_debug ("ISIS-TLV (%s): TE Router ID %d", areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000474#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000475 if (*expected & TLVFLAG_TE_ROUTER_ID)
hasso1cd80842004-10-07 20:07:40 +0000476 tlvs->router_id = (struct te_router_id *) (pnt);
hassof390d2c2004-09-10 20:48:21 +0000477 pnt += length;
478 break;
jardineb5d44e2003-12-23 08:09:43 +0000479
hassof390d2c2004-09-10 20:48:21 +0000480 case IPV4_INT_REACHABILITY:
481 /* +-------+-------+-------+-------+-------+-------+-------+-------+
482 * | 0 | I/E | Default Metric | 1
483 * +-------+-------+-------+-------+-------+-------+-------+-------+
484 * | S | I/E | Delay Metric | 1
485 * +-------+-------+-------+-------+-------+-------+-------+-------+
486 * | S | I/E | Expense Metric | 1
487 * +-------+-------+-------+-------+-------+-------+-------+-------+
488 * | S | I/E | Error Metric | 1
489 * +-------+-------+-------+-------+-------+-------+-------+-------+
490 * | ip address | 4
491 * +---------------------------------------------------------------+
492 * | address mask | 4
493 * +---------------------------------------------------------------+
494 * : :
495 */
496 *found |= TLVFLAG_IPV4_INT_REACHABILITY;
jardineb5d44e2003-12-23 08:09:43 +0000497#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000498 zlog_debug ("ISIS-TLV (%s): IPv4 internal Reachability length %d",
499 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000500#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000501 if (*expected & TLVFLAG_IPV4_INT_REACHABILITY)
502 {
503 while (length > value_len)
504 {
505 ipv4_reach = (struct ipv4_reachability *) pnt;
506 if (!tlvs->ipv4_int_reachs)
507 tlvs->ipv4_int_reachs = list_new ();
508 listnode_add (tlvs->ipv4_int_reachs, ipv4_reach);
509 value_len += 12;
510 pnt += 12;
511 }
512 }
513 else
514 {
515 pnt += length;
516 }
517 break;
jardineb5d44e2003-12-23 08:09:43 +0000518
hassof390d2c2004-09-10 20:48:21 +0000519 case IPV4_EXT_REACHABILITY:
520 /* +-------+-------+-------+-------+-------+-------+-------+-------+
521 * | 0 | I/E | Default Metric | 1
522 * +-------+-------+-------+-------+-------+-------+-------+-------+
523 * | S | I/E | Delay Metric | 1
524 * +-------+-------+-------+-------+-------+-------+-------+-------+
525 * | S | I/E | Expense Metric | 1
526 * +-------+-------+-------+-------+-------+-------+-------+-------+
527 * | S | I/E | Error Metric | 1
528 * +-------+-------+-------+-------+-------+-------+-------+-------+
529 * | ip address | 4
530 * +---------------------------------------------------------------+
531 * | address mask | 4
532 * +---------------------------------------------------------------+
533 * : :
534 */
535 *found |= TLVFLAG_IPV4_EXT_REACHABILITY;
jardineb5d44e2003-12-23 08:09:43 +0000536#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000537 zlog_debug ("ISIS-TLV (%s): IPv4 external Reachability length %d",
538 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000539#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000540 if (*expected & TLVFLAG_IPV4_EXT_REACHABILITY)
541 {
542 while (length > value_len)
543 {
544 ipv4_reach = (struct ipv4_reachability *) pnt;
545 if (!tlvs->ipv4_ext_reachs)
546 tlvs->ipv4_ext_reachs = list_new ();
547 listnode_add (tlvs->ipv4_ext_reachs, ipv4_reach);
548 value_len += 12;
549 pnt += 12;
550 }
551 }
552 else
553 {
554 pnt += length;
555 }
556 break;
jardineb5d44e2003-12-23 08:09:43 +0000557
hassof390d2c2004-09-10 20:48:21 +0000558 case TE_IPV4_REACHABILITY:
559 /* +-------+-------+-------+-------+-------+-------+-------+-------+
560 * | TE Metric | 4
561 * +-------+-------+-------+-------+-------+-------+-------+-------+
562 * | U/D | sTLV? | Prefix Mask Len | 1
563 * +-------+-------+-------+-------+-------+-------+-------+-------+
564 * | Prefix | 0-4
565 * +---------------------------------------------------------------+
566 * | sub tlvs |
567 * +---------------------------------------------------------------+
568 * : :
569 */
570 *found |= TLVFLAG_TE_IPV4_REACHABILITY;
jardineb5d44e2003-12-23 08:09:43 +0000571#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000572 zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d",
573 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000574#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000575 if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
576 {
577 while (length > value_len)
578 {
579 te_ipv4_reach = (struct te_ipv4_reachability *) pnt;
580 if (!tlvs->te_ipv4_reachs)
581 tlvs->te_ipv4_reachs = list_new ();
582 listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach);
583 /* this trickery is permitable since no subtlvs are defined */
584 value_len += 5 + ((te_ipv4_reach->control & 0x3F) ?
585 ((((te_ipv4_reach->control & 0x3F) -
586 1) >> 3) + 1) : 0);
587 pnt += 5 + ((te_ipv4_reach->control & 0x3F) ?
588 ((((te_ipv4_reach->control & 0x3F) - 1) >> 3) + 1) : 0);
589 }
590 }
591 else
592 {
593 pnt += length;
594 }
595 break;
jardineb5d44e2003-12-23 08:09:43 +0000596
597#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000598 case IPV6_ADDR:
599 /* +-------+-------+-------+-------+-------+-------+-------+-------+
600 * + IP version 6 address + 16
601 * +-------+-------+-------+-------+-------+-------+-------+-------+
602 * : :
603 */
604 *found |= TLVFLAG_IPV6_ADDR;
jardineb5d44e2003-12-23 08:09:43 +0000605#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000606 zlog_debug ("ISIS-TLV (%s): IPv6 Address length %d",
607 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000608#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000609 if (*expected & TLVFLAG_IPV6_ADDR)
610 {
611 while (length > value_len)
612 {
613 ipv6_addr = (struct in6_addr *) pnt;
614 if (!tlvs->ipv6_addrs)
615 tlvs->ipv6_addrs = list_new ();
616 listnode_add (tlvs->ipv6_addrs, ipv6_addr);
617 value_len += 16;
618 pnt += 16;
619 }
620 }
621 else
622 {
623 pnt += length;
624 }
625 break;
jardineb5d44e2003-12-23 08:09:43 +0000626
hassof390d2c2004-09-10 20:48:21 +0000627 case IPV6_REACHABILITY:
628 /* +-------+-------+-------+-------+-------+-------+-------+-------+
629 * | Default Metric | 4
630 * +-------+-------+-------+-------+-------+-------+-------+-------+
631 * | Control Informantion |
632 * +---------------------------------------------------------------+
633 * | IPv6 Prefix Length |--+
634 * +---------------------------------------------------------------+ |
635 * | IPv6 Prefix |<-+
636 * +---------------------------------------------------------------+
637 */
638 *found |= TLVFLAG_IPV6_REACHABILITY;
639 if (*expected & TLVFLAG_IPV6_REACHABILITY)
640 {
641 while (length > value_len)
642 {
643 ipv6_reach = (struct ipv6_reachability *) pnt;
644 prefix_octets = ((ipv6_reach->prefix_len + 7) / 8);
645 value_len += prefix_octets + 6;
646 pnt += prefix_octets + 6;
647 /* FIXME: sub-tlvs */
648 if (!tlvs->ipv6_reachs)
649 tlvs->ipv6_reachs = list_new ();
650 listnode_add (tlvs->ipv6_reachs, ipv6_reach);
651 }
652 }
653 else
654 {
655 pnt += length;
656 }
657 break;
jardineb5d44e2003-12-23 08:09:43 +0000658#endif /* HAVE_IPV6 */
659
hassof390d2c2004-09-10 20:48:21 +0000660 case WAY3_HELLO:
661 /* +---------------------------------------------------------------+
662 * | Adjacency state | 1
663 * +---------------------------------------------------------------+
664 * | Extended Local Circuit ID | 4
665 * +---------------------------------------------------------------+
666 * | Neighbor System ID (If known) | 0-8
667 * (probably 6)
668 * +---------------------------------------------------------------+
669 * | Neighbor Local Circuit ID (If known) | 4
670 * +---------------------------------------------------------------+
671 */
672 *found |= TLVFLAG_3WAY_HELLO;
673 if (*expected & TLVFLAG_3WAY_HELLO)
674 {
675 while (length > value_len)
676 {
677 /* FIXME: make this work */
jardineb5d44e2003-12-23 08:09:43 +0000678/* Adjacency State (one octet):
679 0 = Up
680 1 = Initializing
681 2 = Down
682 Extended Local Circuit ID (four octets)
683 Neighbor System ID if known (zero to eight octets)
684 Neighbor Extended Local Circuit ID (four octets, if Neighbor
685 System ID is present) */
hassof390d2c2004-09-10 20:48:21 +0000686 pnt += length;
687 }
688 }
689 else
690 {
691 pnt += length;
692 }
jardineb5d44e2003-12-23 08:09:43 +0000693
hassof390d2c2004-09-10 20:48:21 +0000694 break;
695 case GRACEFUL_RESTART:
696 /* +-------+-------+-------+-------+-------+-------+-------+-------+
697 * | Reserved | SA | RA | RR | 1
698 * +-------+-------+-------+-------+-------+-------+-------+-------+
699 * | Remaining Time | 2
700 * +---------------------------------------------------------------+
701 * | Restarting Neighbor ID (If known) | 0-8
702 * +---------------------------------------------------------------+
703 */
704 *found |= TLVFLAG_GRACEFUL_RESTART;
705 if (*expected & TLVFLAG_GRACEFUL_RESTART)
706 {
707 /* FIXME: make this work */
708 }
709 pnt += length;
710 break;
jardineb5d44e2003-12-23 08:09:43 +0000711
hassof390d2c2004-09-10 20:48:21 +0000712 default:
713 zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
714 areatag, type, length);
jardineb5d44e2003-12-23 08:09:43 +0000715
hassof390d2c2004-09-10 20:48:21 +0000716 retval = ISIS_WARNING;
717 pnt += length;
718 break;
719 }
jardineb5d44e2003-12-23 08:09:43 +0000720 }
hassof390d2c2004-09-10 20:48:21 +0000721
jardineb5d44e2003-12-23 08:09:43 +0000722 return retval;
723}
724
725int
hassof390d2c2004-09-10 20:48:21 +0000726add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000727{
728
paul9985f832005-02-09 15:51:56 +0000729 if (STREAM_SIZE (stream) - stream_get_endp (stream) < (unsigned) len + 2)
hassof390d2c2004-09-10 20:48:21 +0000730 {
731 zlog_warn ("No room for TLV of type %d", tag);
732 return ISIS_WARNING;
733 }
jardineb5d44e2003-12-23 08:09:43 +0000734
hassof390d2c2004-09-10 20:48:21 +0000735 stream_putc (stream, tag); /* TAG */
736 stream_putc (stream, len); /* LENGTH */
737 stream_put (stream, value, (int) len); /* VALUE */
jardineb5d44e2003-12-23 08:09:43 +0000738
739#ifdef EXTREME_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000740 zlog_debug ("Added TLV %d len %d", tag, len);
jardineb5d44e2003-12-23 08:09:43 +0000741#endif /* EXTREME DEBUG */
742 return ISIS_OK;
743}
744
jardineb5d44e2003-12-23 08:09:43 +0000745int
hassof390d2c2004-09-10 20:48:21 +0000746tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000747{
748 struct listnode *node;
749 struct area_addr *area_addr;
750
hassof390d2c2004-09-10 20:48:21 +0000751 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000752 u_char *pos = value;
hassof390d2c2004-09-10 20:48:21 +0000753
paul1eb8ef22005-04-07 07:30:20 +0000754 for (ALL_LIST_ELEMENTS_RO (area_addrs, node, area_addr))
hassof390d2c2004-09-10 20:48:21 +0000755 {
hassof390d2c2004-09-10 20:48:21 +0000756 if (pos - value + area_addr->addr_len > 255)
757 goto err;
758 *pos = area_addr->addr_len;
759 pos++;
760 memcpy (pos, area_addr->area_addr, (int) area_addr->addr_len);
761 pos += area_addr->addr_len;
762 }
763
jardineb5d44e2003-12-23 08:09:43 +0000764 return add_tlv (AREA_ADDRESSES, pos - value, value, stream);
765
hassof390d2c2004-09-10 20:48:21 +0000766err:
jardineb5d44e2003-12-23 08:09:43 +0000767 zlog_warn ("tlv_add_area_addrs(): TLV longer than 255");
768 return ISIS_WARNING;
769}
770
hassof390d2c2004-09-10 20:48:21 +0000771int
772tlv_add_is_neighs (struct list *is_neighs, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000773{
hasso3fdb2dd2005-09-28 18:45:54 +0000774 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000775 struct is_neigh *is_neigh;
hassof390d2c2004-09-10 20:48:21 +0000776 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000777 u_char *pos = value;
778 int retval;
779
hassof390d2c2004-09-10 20:48:21 +0000780 *pos = 0; /*is_neigh->virtual; */
781 pos++;
jardineb5d44e2003-12-23 08:09:43 +0000782
hasso3fdb2dd2005-09-28 18:45:54 +0000783 for (ALL_LIST_ELEMENTS_RO (is_neighs, node, is_neigh))
hassof390d2c2004-09-10 20:48:21 +0000784 {
hassof390d2c2004-09-10 20:48:21 +0000785 if (pos - value + IS_NEIGHBOURS_LEN > 255)
786 {
787 retval = add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
788 if (retval != ISIS_OK)
789 return retval;
790 pos = value;
791 }
792 *pos = is_neigh->metrics.metric_default;
793 pos++;
794 *pos = is_neigh->metrics.metric_delay;
795 pos++;
796 *pos = is_neigh->metrics.metric_expense;
797 pos++;
798 *pos = is_neigh->metrics.metric_error;
799 pos++;
800 memcpy (pos, is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
801 pos += ISIS_SYS_ID_LEN + 1;
jardineb5d44e2003-12-23 08:09:43 +0000802 }
jardineb5d44e2003-12-23 08:09:43 +0000803
804 return add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
805}
806
jardineb5d44e2003-12-23 08:09:43 +0000807int
hassoea3be4c2005-09-26 17:11:12 +0000808tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
809{
hasso3fdb2dd2005-09-28 18:45:54 +0000810 struct listnode *node;
hassoea3be4c2005-09-26 17:11:12 +0000811 struct te_is_neigh *te_is_neigh;
812 u_char value[255];
813 u_char *pos = value;
814 int retval;
815
hasso3fdb2dd2005-09-28 18:45:54 +0000816 for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh))
hassoea3be4c2005-09-26 17:11:12 +0000817 {
818 /* FIXME: This will be wrong if we are going to add TE sub TLVs. */
819 if (pos - value + IS_NEIGHBOURS_LEN > 255)
820 {
821 retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
822 if (retval != ISIS_OK)
823 return retval;
824 pos = value;
825 }
826
827 memcpy (pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
828 pos += ISIS_SYS_ID_LEN + 1;
829 memcpy (pos, te_is_neigh->te_metric, 3);
830 pos += 3;
831 /* Sub TLVs length. */
832 *pos = 0;
833 pos++;
834 }
835
836 return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
837}
838
839int
jardineb5d44e2003-12-23 08:09:43 +0000840tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream)
841{
hasso3fdb2dd2005-09-28 18:45:54 +0000842 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000843 u_char *snpa;
hassof390d2c2004-09-10 20:48:21 +0000844 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000845 u_char *pos = value;
846 int retval;
847
hasso3fdb2dd2005-09-28 18:45:54 +0000848 for (ALL_LIST_ELEMENTS_RO (lan_neighs, node, snpa))
hassof390d2c2004-09-10 20:48:21 +0000849 {
hassof390d2c2004-09-10 20:48:21 +0000850 if (pos - value + ETH_ALEN > 255)
851 {
852 retval = add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
853 if (retval != ISIS_OK)
854 return retval;
855 pos = value;
856 }
857 memcpy (pos, snpa, ETH_ALEN);
858 pos += ETH_ALEN;
jardineb5d44e2003-12-23 08:09:43 +0000859 }
jardineb5d44e2003-12-23 08:09:43 +0000860
861 return add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
862}
863
jardineb5d44e2003-12-23 08:09:43 +0000864int
865tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream)
866{
hassof390d2c2004-09-10 20:48:21 +0000867 return add_tlv (PROTOCOLS_SUPPORTED, nlpids->count, nlpids->nlpids, stream);
jardineb5d44e2003-12-23 08:09:43 +0000868}
869
hassof390d2c2004-09-10 20:48:21 +0000870int
hassof7c43dc2004-09-26 16:24:14 +0000871tlv_add_authinfo (char auth_type, char auth_len, u_char *auth_value,
hassof390d2c2004-09-10 20:48:21 +0000872 struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000873{
874 u_char value[255];
875 u_char *pos = value;
hasso53c997c2004-09-15 16:21:59 +0000876 *pos++ = ISIS_PASSWD_TYPE_CLEARTXT;
jardineb5d44e2003-12-23 08:09:43 +0000877 memcpy (pos, auth_value, auth_len);
878
879 return add_tlv (AUTH_INFO, auth_len + 1, value, stream);
880}
881
882int
883tlv_add_checksum (struct checksum *checksum, struct stream *stream)
884{
885 u_char value[255];
hassof390d2c2004-09-10 20:48:21 +0000886 u_char *pos = value;
887 return add_tlv (CHECKSUM, pos - value, value, stream);
jardineb5d44e2003-12-23 08:09:43 +0000888}
889
890int
891tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream)
892{
hasso3fdb2dd2005-09-28 18:45:54 +0000893 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000894 struct prefix_ipv4 *ipv4;
895 u_char value[255];
896 u_char *pos = value;
897 int retval;
898
hasso3fdb2dd2005-09-28 18:45:54 +0000899 for (ALL_LIST_ELEMENTS_RO (ip_addrs, node, ipv4))
hassof390d2c2004-09-10 20:48:21 +0000900 {
hassof390d2c2004-09-10 20:48:21 +0000901 if (pos - value + IPV4_MAX_BYTELEN > 255)
902 {
903 retval = add_tlv (IPV4_ADDR, pos - value, value, stream);
904 if (retval != ISIS_OK)
905 return retval;
906 pos = value;
907 }
908 *(u_int32_t *) pos = ipv4->prefix.s_addr;
909 pos += IPV4_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +0000910 }
hassof390d2c2004-09-10 20:48:21 +0000911
jardineb5d44e2003-12-23 08:09:43 +0000912 return add_tlv (IPV4_ADDR, pos - value, value, stream);
913}
914
hasso81ad8f62005-09-26 17:58:24 +0000915/* Used to add TLV containing just one IPv4 address - either IPv4 address TLV
916 * (in case of LSP) or TE router ID TLV. */
917int
918tlv_add_in_addr (struct in_addr *addr, struct stream *stream, u_char tag)
919{
920 u_char value[255];
921 u_char *pos = value;
922
923 memcpy (pos, addr, IPV4_MAX_BYTELEN);
924 pos += IPV4_MAX_BYTELEN;
925
926 return add_tlv (tag, pos - value, value, stream);
927}
928
jardineb5d44e2003-12-23 08:09:43 +0000929int
930tlv_add_dynamic_hostname (struct hostname *hostname, struct stream *stream)
931{
hassof390d2c2004-09-10 20:48:21 +0000932 return add_tlv (DYNAMIC_HOSTNAME, hostname->namelen, hostname->name,
933 stream);
jardineb5d44e2003-12-23 08:09:43 +0000934}
935
hassof390d2c2004-09-10 20:48:21 +0000936int
jardineb5d44e2003-12-23 08:09:43 +0000937tlv_add_lsp_entries (struct list *lsps, struct stream *stream)
938{
hasso3fdb2dd2005-09-28 18:45:54 +0000939 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000940 struct isis_lsp *lsp;
hassof390d2c2004-09-10 20:48:21 +0000941 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000942 u_char *pos = value;
943 int retval;
944
hasso3fdb2dd2005-09-28 18:45:54 +0000945 for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp))
hassof390d2c2004-09-10 20:48:21 +0000946 {
hassof390d2c2004-09-10 20:48:21 +0000947 if (pos - value + LSP_ENTRIES_LEN > 255)
948 {
949 retval = add_tlv (LSP_ENTRIES, pos - value, value, stream);
950 if (retval != ISIS_OK)
951 return retval;
952 pos = value;
953 }
954 *((u_int16_t *) pos) = lsp->lsp_header->rem_lifetime;
955 pos += 2;
956 memcpy (pos, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
957 pos += ISIS_SYS_ID_LEN + 2;
958 *((u_int32_t *) pos) = lsp->lsp_header->seq_num;
959 pos += 4;
960 *((u_int16_t *) pos) = lsp->lsp_header->checksum;
961 pos += 2;
jardineb5d44e2003-12-23 08:09:43 +0000962 }
hassof390d2c2004-09-10 20:48:21 +0000963
jardineb5d44e2003-12-23 08:09:43 +0000964 return add_tlv (LSP_ENTRIES, pos - value, value, stream);
965}
966
hassof390d2c2004-09-10 20:48:21 +0000967int
jardineb5d44e2003-12-23 08:09:43 +0000968tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream)
969{
hasso3fdb2dd2005-09-28 18:45:54 +0000970 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000971 struct ipv4_reachability *reach;
hassof390d2c2004-09-10 20:48:21 +0000972 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000973 u_char *pos = value;
974 int retval;
975
hasso3fdb2dd2005-09-28 18:45:54 +0000976 for (ALL_LIST_ELEMENTS_RO (ipv4_reachs, node, reach))
hassof390d2c2004-09-10 20:48:21 +0000977 {
hassof390d2c2004-09-10 20:48:21 +0000978 if (pos - value + IPV4_REACH_LEN > 255)
979 {
980 retval =
981 add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
982 if (retval != ISIS_OK)
983 return retval;
984 pos = value;
985 }
986 *pos = reach->metrics.metric_default;
987 pos++;
988 *pos = reach->metrics.metric_delay;
989 pos++;
990 *pos = reach->metrics.metric_expense;
991 pos++;
992 *pos = reach->metrics.metric_error;
993 pos++;
994 *(u_int32_t *) pos = reach->prefix.s_addr;
995 pos += IPV4_MAX_BYTELEN;
996 *(u_int32_t *) pos = reach->mask.s_addr;
997 pos += IPV4_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +0000998 }
hassof390d2c2004-09-10 20:48:21 +0000999
1000
jardineb5d44e2003-12-23 08:09:43 +00001001 return add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
1002}
1003
hassoea3be4c2005-09-26 17:11:12 +00001004int
1005tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream)
1006{
hasso3fdb2dd2005-09-28 18:45:54 +00001007 struct listnode *node;
hassoea3be4c2005-09-26 17:11:12 +00001008 struct te_ipv4_reachability *te_reach;
1009 u_char value[255];
1010 u_char *pos = value;
1011 u_char prefix_size;
1012 int retval;
1013
hasso3fdb2dd2005-09-28 18:45:54 +00001014 for (ALL_LIST_ELEMENTS_RO (te_ipv4_reachs, node, te_reach))
hassoea3be4c2005-09-26 17:11:12 +00001015 {
1016 prefix_size = ((((te_reach->control & 0x3F) - 1) >> 3) + 1);
1017
1018 if (pos - value + (5 + prefix_size) > 255)
1019 {
1020 retval =
1021 add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
1022 if (retval != ISIS_OK)
1023 return retval;
1024 pos = value;
1025 }
1026 *(u_int32_t *) pos = te_reach->te_metric;
1027 pos += 4;
1028 *pos = te_reach->control;
1029 pos++;
1030 memcpy (pos, &te_reach->prefix_start, prefix_size);
1031 pos += prefix_size;
1032 }
1033
1034 return add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
1035}
1036
hassof390d2c2004-09-10 20:48:21 +00001037#ifdef HAVE_IPV6
jardineb5d44e2003-12-23 08:09:43 +00001038int
1039tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream)
1040{
hasso3fdb2dd2005-09-28 18:45:54 +00001041 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00001042 struct prefix_ipv6 *ipv6;
1043 u_char value[255];
1044 u_char *pos = value;
1045 int retval;
hassof390d2c2004-09-10 20:48:21 +00001046
hasso3fdb2dd2005-09-28 18:45:54 +00001047 for (ALL_LIST_ELEMENTS_RO (ipv6_addrs, node, ipv6))
hassof390d2c2004-09-10 20:48:21 +00001048 {
hassof390d2c2004-09-10 20:48:21 +00001049 if (pos - value + IPV6_MAX_BYTELEN > 255)
1050 {
1051 retval = add_tlv (IPV6_ADDR, pos - value, value, stream);
1052 if (retval != ISIS_OK)
1053 return retval;
1054 pos = value;
1055 }
1056 memcpy (pos, ipv6->prefix.s6_addr, IPV6_MAX_BYTELEN);
1057 pos += IPV6_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +00001058 }
hassof390d2c2004-09-10 20:48:21 +00001059
jardineb5d44e2003-12-23 08:09:43 +00001060 return add_tlv (IPV6_ADDR, pos - value, value, stream);
1061}
1062
1063int
1064tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream)
1065{
hasso3fdb2dd2005-09-28 18:45:54 +00001066 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00001067 struct ipv6_reachability *ip6reach;
1068 u_char value[255];
1069 u_char *pos = value;
1070 int retval, prefix_octets;
hassof390d2c2004-09-10 20:48:21 +00001071
hasso3fdb2dd2005-09-28 18:45:54 +00001072 for (ALL_LIST_ELEMENTS_RO (ipv6_reachs, node, ip6reach))
hassof390d2c2004-09-10 20:48:21 +00001073 {
hassof390d2c2004-09-10 20:48:21 +00001074 if (pos - value + IPV6_MAX_BYTELEN + 6 > 255)
1075 {
1076 retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
1077 if (retval != ISIS_OK)
1078 return retval;
1079 pos = value;
1080 }
1081 *(uint32_t *) pos = ip6reach->metric;
1082 pos += 4;
1083 *pos = ip6reach->control_info;
1084 pos++;
1085 prefix_octets = ((ip6reach->prefix_len + 7) / 8);
1086 *pos = ip6reach->prefix_len;
1087 pos++;
1088 memcpy (pos, ip6reach->prefix, prefix_octets);
1089 pos += prefix_octets;
jardineb5d44e2003-12-23 08:09:43 +00001090 }
hassof390d2c2004-09-10 20:48:21 +00001091
jardineb5d44e2003-12-23 08:09:43 +00001092 return add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
1093}
1094#endif /* HAVE_IPV6 */
1095
1096int
1097tlv_add_padding (struct stream *stream)
1098{
hassof390d2c2004-09-10 20:48:21 +00001099 int fullpads, i, left;
1100
jardineb5d44e2003-12-23 08:09:43 +00001101 /*
1102 * How many times can we add full padding ?
1103 */
hassof390d2c2004-09-10 20:48:21 +00001104 fullpads = (STREAM_SIZE (stream) - stream_get_endp (stream)) / 257;
1105 for (i = 0; i < fullpads; i++)
1106 {
1107 if (!stream_putc (stream, (u_char) PADDING)) /* TAG */
1108 goto err;
1109 if (!stream_putc (stream, (u_char) 255)) /* LENGHT */
1110 goto err;
paul15935e92005-05-03 09:27:23 +00001111 stream_put (stream, NULL, 255); /* zero padding */
hassof390d2c2004-09-10 20:48:21 +00001112 }
1113
paul9985f832005-02-09 15:51:56 +00001114 left = STREAM_SIZE (stream) - stream_get_endp (stream);
hassof390d2c2004-09-10 20:48:21 +00001115
jardineb5d44e2003-12-23 08:09:43 +00001116 if (left < 2)
1117 return ISIS_OK;
hassof390d2c2004-09-10 20:48:21 +00001118
1119 if (left == 2)
1120 {
1121 stream_putc (stream, PADDING);
1122 stream_putc (stream, 0);
1123 return ISIS_OK;
1124 }
1125
jardineb5d44e2003-12-23 08:09:43 +00001126 stream_putc (stream, PADDING);
1127 stream_putc (stream, left - 2);
paul15935e92005-05-03 09:27:23 +00001128 stream_put (stream, NULL, left-2);
jardineb5d44e2003-12-23 08:09:43 +00001129
1130 return ISIS_OK;
1131
hassof390d2c2004-09-10 20:48:21 +00001132err:
jardineb5d44e2003-12-23 08:09:43 +00001133 zlog_warn ("tlv_add_padding(): no room for tlv");
1134 return ISIS_WARNING;
1135}