blob: 3fc717e34845879aa55f047fe5174be04694ab35 [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
Paul Jakma41b36e92006-12-08 01:09:50 +000048/*
49 * Prototypes.
50 */
51int add_tlv (u_char, u_char, u_char *, struct stream *);
52
jardineb5d44e2003-12-23 08:09:43 +000053void
54free_tlv (void *val)
55{
hassof390d2c2004-09-10 20:48:21 +000056 XFREE (MTYPE_ISIS_TLV, val);
57
58 return;
jardineb5d44e2003-12-23 08:09:43 +000059}
60
61/*
62 * Called after parsing of a PDU. There shouldn't be any tlv's left, so this
63 * is only a caution to avoid memory leaks
64 */
hassof390d2c2004-09-10 20:48:21 +000065void
jardineb5d44e2003-12-23 08:09:43 +000066free_tlvs (struct tlvs *tlvs)
67{
hassof390d2c2004-09-10 20:48:21 +000068 if (tlvs->area_addrs)
hassoaac372f2005-09-01 17:52:33 +000069 list_delete (tlvs->area_addrs);
hassof390d2c2004-09-10 20:48:21 +000070 if (tlvs->is_neighs)
hassoaac372f2005-09-01 17:52:33 +000071 list_delete (tlvs->is_neighs);
hassof390d2c2004-09-10 20:48:21 +000072 if (tlvs->te_is_neighs)
hassoaac372f2005-09-01 17:52:33 +000073 list_delete (tlvs->te_is_neighs);
hassof390d2c2004-09-10 20:48:21 +000074 if (tlvs->es_neighs)
hassoaac372f2005-09-01 17:52:33 +000075 list_delete (tlvs->es_neighs);
hassof390d2c2004-09-10 20:48:21 +000076 if (tlvs->lsp_entries)
hassoaac372f2005-09-01 17:52:33 +000077 list_delete (tlvs->lsp_entries);
hassof390d2c2004-09-10 20:48:21 +000078 if (tlvs->lan_neighs)
hassoaac372f2005-09-01 17:52:33 +000079 list_delete (tlvs->lan_neighs);
hassof390d2c2004-09-10 20:48:21 +000080 if (tlvs->prefix_neighs)
hassoaac372f2005-09-01 17:52:33 +000081 list_delete (tlvs->prefix_neighs);
hassof390d2c2004-09-10 20:48:21 +000082 if (tlvs->ipv4_addrs)
hassoaac372f2005-09-01 17:52:33 +000083 list_delete (tlvs->ipv4_addrs);
hassof390d2c2004-09-10 20:48:21 +000084 if (tlvs->ipv4_int_reachs)
hassoaac372f2005-09-01 17:52:33 +000085 list_delete (tlvs->ipv4_int_reachs);
hassof390d2c2004-09-10 20:48:21 +000086 if (tlvs->ipv4_ext_reachs)
hassoaac372f2005-09-01 17:52:33 +000087 list_delete (tlvs->ipv4_ext_reachs);
hassof390d2c2004-09-10 20:48:21 +000088 if (tlvs->te_ipv4_reachs)
hassoaac372f2005-09-01 17:52:33 +000089 list_delete (tlvs->te_ipv4_reachs);
jardineb5d44e2003-12-23 08:09:43 +000090#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +000091 if (tlvs->ipv6_addrs)
hassoaac372f2005-09-01 17:52:33 +000092 list_delete (tlvs->ipv6_addrs);
hassof390d2c2004-09-10 20:48:21 +000093 if (tlvs->ipv6_reachs)
hassoaac372f2005-09-01 17:52:33 +000094 list_delete (tlvs->ipv6_reachs);
jardineb5d44e2003-12-23 08:09:43 +000095#endif /* HAVE_IPV6 */
hassoaac372f2005-09-01 17:52:33 +000096
jardineb5d44e2003-12-23 08:09:43 +000097 return;
98}
99
100/*
101 * Parses the tlvs found in the variant length part of the PDU.
102 * Caller tells with flags in "expected" which TLV's it is interested in.
103 */
hassof390d2c2004-09-10 20:48:21 +0000104int
105parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
106 u_int32_t * found, struct tlvs *tlvs)
jardineb5d44e2003-12-23 08:09:43 +0000107{
hassof390d2c2004-09-10 20:48:21 +0000108 u_char type, length;
109 struct lan_neigh *lan_nei;
110 struct area_addr *area_addr;
111 struct is_neigh *is_nei;
112 struct te_is_neigh *te_is_nei;
113 struct es_neigh *es_nei;
114 struct lsp_entry *lsp_entry;
115 struct in_addr *ipv4_addr;
116 struct ipv4_reachability *ipv4_reach;
117 struct te_ipv4_reachability *te_ipv4_reach;
jardineb5d44e2003-12-23 08:09:43 +0000118#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000119 struct in6_addr *ipv6_addr;
120 struct ipv6_reachability *ipv6_reach;
121 int prefix_octets;
jardineb5d44e2003-12-23 08:09:43 +0000122#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000123 u_char virtual;
124 int value_len, retval = ISIS_OK;
125 u_char *pnt = stream;
jardineb5d44e2003-12-23 08:09:43 +0000126
127 *found = 0;
128 memset (tlvs, 0, sizeof (struct tlvs));
hassof390d2c2004-09-10 20:48:21 +0000129
130 while (pnt < stream + size - 2)
131 {
132 type = *pnt;
133 length = *(pnt + 1);
134 pnt += 2;
135 value_len = 0;
136 if (pnt + length > stream + size)
137 {
138 zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet "
139 "boundaries", areatag, type, length);
140 retval = ISIS_WARNING;
141 break;
142 }
143 switch (type)
144 {
145 case AREA_ADDRESSES:
146 /* +-------+-------+-------+-------+-------+-------+-------+-------+
147 * | Address Length |
148 * +-------+-------+-------+-------+-------+-------+-------+-------+
149 * | Area Address |
150 * +-------+-------+-------+-------+-------+-------+-------+-------+
151 * : :
152 */
153 *found |= TLVFLAG_AREA_ADDRS;
jardineb5d44e2003-12-23 08:09:43 +0000154#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000155 zlog_debug ("TLV Area Adresses len %d", length);
jardineb5d44e2003-12-23 08:09:43 +0000156#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000157 if (*expected & TLVFLAG_AREA_ADDRS)
158 {
159 while (length > value_len)
160 {
161 area_addr = (struct area_addr *) pnt;
162 value_len += area_addr->addr_len + 1;
163 pnt += area_addr->addr_len + 1;
164 if (!tlvs->area_addrs)
165 tlvs->area_addrs = list_new ();
166 listnode_add (tlvs->area_addrs, area_addr);
167 }
168 }
169 else
170 {
171 pnt += length;
172 }
173 break;
jardineb5d44e2003-12-23 08:09:43 +0000174
hassof390d2c2004-09-10 20:48:21 +0000175 case IS_NEIGHBOURS:
176 *found |= TLVFLAG_IS_NEIGHS;
jardineb5d44e2003-12-23 08:09:43 +0000177#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000178 zlog_debug ("ISIS-TLV (%s): IS Neighbours length %d",
179 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000180#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000181 if (TLVFLAG_IS_NEIGHS & *expected)
182 {
183 /* +-------+-------+-------+-------+-------+-------+-------+-------+
184 * | Virtual Flag |
185 * +-------+-------+-------+-------+-------+-------+-------+-------+
186 */
187 virtual = *pnt; /* FIXME: what is the use for this? */
188 pnt++;
189 value_len++;
190 /* +-------+-------+-------+-------+-------+-------+-------+-------+
191 * | 0 | I/E | Default Metric |
192 * +-------+-------+-------+-------+-------+-------+-------+-------+
193 * | S | I/E | Delay Metric |
194 * +-------+-------+-------+-------+-------+-------+-------+-------+
195 * | S | I/E | Expense Metric |
196 * +-------+-------+-------+-------+-------+-------+-------+-------+
197 * | S | I/E | Error Metric |
198 * +-------+-------+-------+-------+-------+-------+-------+-------+
199 * | Neighbour ID |
200 * +---------------------------------------------------------------+
201 * : :
202 */
203 while (length > value_len)
204 {
205 is_nei = (struct is_neigh *) pnt;
206 value_len += 4 + ISIS_SYS_ID_LEN + 1;
207 pnt += 4 + ISIS_SYS_ID_LEN + 1;
208 if (!tlvs->is_neighs)
209 tlvs->is_neighs = list_new ();
210 listnode_add (tlvs->is_neighs, is_nei);
211 }
212 }
213 else
214 {
215 pnt += length;
216 }
217 break;
jardineb5d44e2003-12-23 08:09:43 +0000218
hassof390d2c2004-09-10 20:48:21 +0000219 case TE_IS_NEIGHBOURS:
220 /* +-------+-------+-------+-------+-------+-------+-------+-------+
221 * | Neighbour ID | 7
222 * +---------------------------------------------------------------+
223 * | TE Metric | 3
224 * +---------------------------------------------------------------+
225 * | SubTLVs Length | 1
226 * +---------------------------------------------------------------+
227 * : :
228 */
229 *found |= TLVFLAG_TE_IS_NEIGHS;
jardineb5d44e2003-12-23 08:09:43 +0000230#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000231 zlog_debug ("ISIS-TLV (%s): Extended IS Neighbours length %d",
hassof390d2c2004-09-10 20:48:21 +0000232 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000233#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000234 if (TLVFLAG_TE_IS_NEIGHS & *expected)
235 {
236 while (length > value_len)
237 {
238 te_is_nei = (struct te_is_neigh *) pnt;
239 value_len += 11;
240 pnt += 11;
241 /* FIXME - subtlvs are handled here, for now we skip */
242 value_len += te_is_nei->sub_tlvs_length;
243 pnt += te_is_nei->sub_tlvs_length;
jardineb5d44e2003-12-23 08:09:43 +0000244
hassof390d2c2004-09-10 20:48:21 +0000245 if (!tlvs->te_is_neighs)
246 tlvs->te_is_neighs = list_new ();
247 listnode_add (tlvs->te_is_neighs, te_is_nei);
248 }
249 }
250 else
251 {
252 pnt += length;
253 }
254 break;
jardineb5d44e2003-12-23 08:09:43 +0000255
hassof390d2c2004-09-10 20:48:21 +0000256 case ES_NEIGHBOURS:
257 /* +-------+-------+-------+-------+-------+-------+-------+-------+
258 * | 0 | I/E | Default Metric |
259 * +-------+-------+-------+-------+-------+-------+-------+-------+
260 * | S | I/E | Delay Metric |
261 * +-------+-------+-------+-------+-------+-------+-------+-------+
262 * | S | I/E | Expense Metric |
263 * +-------+-------+-------+-------+-------+-------+-------+-------+
264 * | S | I/E | Error Metric |
265 * +-------+-------+-------+-------+-------+-------+-------+-------+
266 * | Neighbour ID |
267 * +---------------------------------------------------------------+
268 * | Neighbour ID |
269 * +---------------------------------------------------------------+
270 * : :
271 */
jardineb5d44e2003-12-23 08:09:43 +0000272#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000273 zlog_debug ("ISIS-TLV (%s): ES Neighbours length %d",
hassof390d2c2004-09-10 20:48:21 +0000274 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000275#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000276 *found |= TLVFLAG_ES_NEIGHS;
277 if (*expected & TLVFLAG_ES_NEIGHS)
278 {
279 es_nei = (struct es_neigh *) pnt;
280 value_len += 4;
281 pnt += 4;
282 while (length > value_len)
283 {
284 /* FIXME FIXME FIXME - add to the list */
285 /* sys_id->id = pnt; */
286 value_len += ISIS_SYS_ID_LEN;
287 pnt += ISIS_SYS_ID_LEN;
288 /* if (!es_nei->neigh_ids) es_nei->neigh_ids = sysid; */
289 }
290 if (!tlvs->es_neighs)
291 tlvs->es_neighs = list_new ();
292 listnode_add (tlvs->es_neighs, es_nei);
293 }
294 else
295 {
296 pnt += length;
297 }
298 break;
jardineb5d44e2003-12-23 08:09:43 +0000299
hassof390d2c2004-09-10 20:48:21 +0000300 case LAN_NEIGHBOURS:
301 /* +-------+-------+-------+-------+-------+-------+-------+-------+
302 * | LAN Address |
303 * +-------+-------+-------+-------+-------+-------+-------+-------+
304 * : :
305 */
306 *found |= TLVFLAG_LAN_NEIGHS;
jardineb5d44e2003-12-23 08:09:43 +0000307#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000308 zlog_debug ("ISIS-TLV (%s): LAN Neigbours length %d",
309 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000310#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000311 if (TLVFLAG_LAN_NEIGHS & *expected)
312 {
313 while (length > value_len)
314 {
315 lan_nei = (struct lan_neigh *) pnt;
316 if (!tlvs->lan_neighs)
317 tlvs->lan_neighs = list_new ();
318 listnode_add (tlvs->lan_neighs, lan_nei);
319 value_len += ETH_ALEN;
320 pnt += ETH_ALEN;
321 }
322 }
323 else
324 {
325 pnt += length;
326 }
327 break;
jardineb5d44e2003-12-23 08:09:43 +0000328
hassof390d2c2004-09-10 20:48:21 +0000329 case PADDING:
jardineb5d44e2003-12-23 08:09:43 +0000330#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000331 zlog_debug ("TLV padding %d", length);
jardineb5d44e2003-12-23 08:09:43 +0000332#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000333 pnt += length;
334 break;
jardineb5d44e2003-12-23 08:09:43 +0000335
hassof390d2c2004-09-10 20:48:21 +0000336 case LSP_ENTRIES:
337 /* +-------+-------+-------+-------+-------+-------+-------+-------+
338 * | Remaining Lifetime | 2
339 * +-------+-------+-------+-------+-------+-------+-------+-------+
340 * | LSP ID | id+2
341 * +-------+-------+-------+-------+-------+-------+-------+-------+
342 * | LSP Sequence Number | 4
343 * +-------+-------+-------+-------+-------+-------+-------+-------+
344 * | Checksum | 2
345 * +-------+-------+-------+-------+-------+-------+-------+-------+
346 */
jardineb5d44e2003-12-23 08:09:43 +0000347#ifdef EXTREME_TLV_DEBUG
hasso92365882005-01-18 13:53:33 +0000348 zlog_debug ("ISIS-TLV (%s): LSP Entries length %d", areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000349#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000350 *found |= TLVFLAG_LSP_ENTRIES;
351 if (TLVFLAG_LSP_ENTRIES & *expected)
352 {
353 while (length > value_len)
354 {
355 lsp_entry = (struct lsp_entry *) pnt;
356 value_len += 10 + ISIS_SYS_ID_LEN;
357 pnt += 10 + ISIS_SYS_ID_LEN;
358 if (!tlvs->lsp_entries)
359 tlvs->lsp_entries = list_new ();
360 listnode_add (tlvs->lsp_entries, lsp_entry);
361 }
362 }
363 else
364 {
365 pnt += length;
366 }
367 break;
jardineb5d44e2003-12-23 08:09:43 +0000368
hassof390d2c2004-09-10 20:48:21 +0000369 case CHECKSUM:
370 /* +-------+-------+-------+-------+-------+-------+-------+-------+
371 * | 16 bit fletcher CHECKSUM |
372 * +-------+-------+-------+-------+-------+-------+-------+-------+
373 * : :
374 */
375 *found |= TLVFLAG_CHECKSUM;
jardineb5d44e2003-12-23 08:09:43 +0000376#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000377 zlog_debug ("ISIS-TLV (%s): Checksum length %d", areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000378#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000379 if (*expected & TLVFLAG_CHECKSUM)
380 {
381 tlvs->checksum = (struct checksum *) pnt;
382 }
383 pnt += length;
384 break;
jardineb5d44e2003-12-23 08:09:43 +0000385
hassof390d2c2004-09-10 20:48:21 +0000386 case PROTOCOLS_SUPPORTED:
387 /* +-------+-------+-------+-------+-------+-------+-------+-------+
388 * | NLPID |
389 * +-------+-------+-------+-------+-------+-------+-------+-------+
390 * : :
391 */
392 *found |= TLVFLAG_NLPID;
jardineb5d44e2003-12-23 08:09:43 +0000393#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000394 zlog_debug ("ISIS-TLV (%s): Protocols Supported length %d",
395 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000396#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000397 if (*expected & TLVFLAG_NLPID)
398 {
399 tlvs->nlpids = (struct nlpids *) (pnt - 1);
400 }
401 pnt += length;
402 break;
jardineb5d44e2003-12-23 08:09:43 +0000403
hassof390d2c2004-09-10 20:48:21 +0000404 case IPV4_ADDR:
405 /* +-------+-------+-------+-------+-------+-------+-------+-------+
406 * + IP version 4 address + 4
407 * +-------+-------+-------+-------+-------+-------+-------+-------+
408 * : :
409 */
410 *found |= TLVFLAG_IPV4_ADDR;
jardineb5d44e2003-12-23 08:09:43 +0000411#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000412 zlog_debug ("ISIS-TLV (%s): IPv4 Address length %d",
413 areatag, length);
hassof390d2c2004-09-10 20:48:21 +0000414#endif /* EXTREME_TLV_DEBUG */
415 if (*expected & TLVFLAG_IPV4_ADDR)
416 {
417 while (length > value_len)
418 {
419 ipv4_addr = (struct in_addr *) pnt;
hassof891f442004-09-14 13:54:30 +0000420#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000421 zlog_debug ("ISIS-TLV (%s) : IP ADDR %s, pnt %p", areatag,
422 inet_ntoa (*ipv4_addr), pnt);
hassof891f442004-09-14 13:54:30 +0000423#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000424 if (!tlvs->ipv4_addrs)
425 tlvs->ipv4_addrs = list_new ();
426 listnode_add (tlvs->ipv4_addrs, ipv4_addr);
427 value_len += 4;
428 pnt += 4;
429 }
430 }
431 else
432 {
433 pnt += length;
434 }
435 break;
436
437 case AUTH_INFO:
438 *found |= TLVFLAG_AUTH_INFO;
439#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000440 zlog_debug ("ISIS-TLV (%s): IS-IS Authentication Information",
441 areatag);
jardineb5d44e2003-12-23 08:09:43 +0000442#endif
hassof390d2c2004-09-10 20:48:21 +0000443 if (*expected & TLVFLAG_AUTH_INFO)
444 {
445 tlvs->auth_info.type = *pnt;
hasso53c997c2004-09-15 16:21:59 +0000446 tlvs->auth_info.len = length-1;
hassof390d2c2004-09-10 20:48:21 +0000447 pnt++;
448 memcpy (tlvs->auth_info.passwd, pnt, length - 1);
Fritz Reichmanne6b03b72011-10-01 17:49:48 +0400449 /* Fill authentication with 0 for later computation
450 * of MD5 (RFC 5304, 2)
451 */
452 memset (pnt, 0, length - 1);
hassof390d2c2004-09-10 20:48:21 +0000453 pnt += length - 1;
454 }
455 else
456 {
457 pnt += length;
458 }
459 break;
jardineb5d44e2003-12-23 08:09:43 +0000460
hassof390d2c2004-09-10 20:48:21 +0000461 case DYNAMIC_HOSTNAME:
462 *found |= TLVFLAG_DYN_HOSTNAME;
jardineb5d44e2003-12-23 08:09:43 +0000463#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000464 zlog_debug ("ISIS-TLV (%s): Dynamic Hostname length %d",
465 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000466#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000467 if (*expected & TLVFLAG_DYN_HOSTNAME)
468 {
469 /* the length is also included in the pointed struct */
470 tlvs->hostname = (struct hostname *) (pnt - 1);
471 }
472 pnt += length;
473 break;
jardineb5d44e2003-12-23 08:09:43 +0000474
hassof390d2c2004-09-10 20:48:21 +0000475 case TE_ROUTER_ID:
476 /* +---------------------------------------------------------------+
477 * + Router ID + 4
478 * +---------------------------------------------------------------+
479 */
480 *found |= TLVFLAG_TE_ROUTER_ID;
jardineb5d44e2003-12-23 08:09:43 +0000481#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000482 zlog_debug ("ISIS-TLV (%s): TE Router ID %d", areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000483#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000484 if (*expected & TLVFLAG_TE_ROUTER_ID)
hasso1cd80842004-10-07 20:07:40 +0000485 tlvs->router_id = (struct te_router_id *) (pnt);
hassof390d2c2004-09-10 20:48:21 +0000486 pnt += length;
487 break;
jardineb5d44e2003-12-23 08:09:43 +0000488
hassof390d2c2004-09-10 20:48:21 +0000489 case IPV4_INT_REACHABILITY:
490 /* +-------+-------+-------+-------+-------+-------+-------+-------+
491 * | 0 | I/E | Default Metric | 1
492 * +-------+-------+-------+-------+-------+-------+-------+-------+
493 * | S | I/E | Delay Metric | 1
494 * +-------+-------+-------+-------+-------+-------+-------+-------+
495 * | S | I/E | Expense Metric | 1
496 * +-------+-------+-------+-------+-------+-------+-------+-------+
497 * | S | I/E | Error Metric | 1
498 * +-------+-------+-------+-------+-------+-------+-------+-------+
499 * | ip address | 4
500 * +---------------------------------------------------------------+
501 * | address mask | 4
502 * +---------------------------------------------------------------+
503 * : :
504 */
505 *found |= TLVFLAG_IPV4_INT_REACHABILITY;
jardineb5d44e2003-12-23 08:09:43 +0000506#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000507 zlog_debug ("ISIS-TLV (%s): IPv4 internal Reachability length %d",
508 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000509#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000510 if (*expected & TLVFLAG_IPV4_INT_REACHABILITY)
511 {
512 while (length > value_len)
513 {
514 ipv4_reach = (struct ipv4_reachability *) pnt;
515 if (!tlvs->ipv4_int_reachs)
516 tlvs->ipv4_int_reachs = list_new ();
517 listnode_add (tlvs->ipv4_int_reachs, ipv4_reach);
518 value_len += 12;
519 pnt += 12;
520 }
521 }
522 else
523 {
524 pnt += length;
525 }
526 break;
jardineb5d44e2003-12-23 08:09:43 +0000527
hassof390d2c2004-09-10 20:48:21 +0000528 case IPV4_EXT_REACHABILITY:
529 /* +-------+-------+-------+-------+-------+-------+-------+-------+
530 * | 0 | I/E | Default Metric | 1
531 * +-------+-------+-------+-------+-------+-------+-------+-------+
532 * | S | I/E | Delay Metric | 1
533 * +-------+-------+-------+-------+-------+-------+-------+-------+
534 * | S | I/E | Expense Metric | 1
535 * +-------+-------+-------+-------+-------+-------+-------+-------+
536 * | S | I/E | Error Metric | 1
537 * +-------+-------+-------+-------+-------+-------+-------+-------+
538 * | ip address | 4
539 * +---------------------------------------------------------------+
540 * | address mask | 4
541 * +---------------------------------------------------------------+
542 * : :
543 */
544 *found |= TLVFLAG_IPV4_EXT_REACHABILITY;
jardineb5d44e2003-12-23 08:09:43 +0000545#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000546 zlog_debug ("ISIS-TLV (%s): IPv4 external Reachability length %d",
547 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000548#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000549 if (*expected & TLVFLAG_IPV4_EXT_REACHABILITY)
550 {
551 while (length > value_len)
552 {
553 ipv4_reach = (struct ipv4_reachability *) pnt;
554 if (!tlvs->ipv4_ext_reachs)
555 tlvs->ipv4_ext_reachs = list_new ();
556 listnode_add (tlvs->ipv4_ext_reachs, ipv4_reach);
557 value_len += 12;
558 pnt += 12;
559 }
560 }
561 else
562 {
563 pnt += length;
564 }
565 break;
jardineb5d44e2003-12-23 08:09:43 +0000566
hassof390d2c2004-09-10 20:48:21 +0000567 case TE_IPV4_REACHABILITY:
568 /* +-------+-------+-------+-------+-------+-------+-------+-------+
569 * | TE Metric | 4
570 * +-------+-------+-------+-------+-------+-------+-------+-------+
571 * | U/D | sTLV? | Prefix Mask Len | 1
572 * +-------+-------+-------+-------+-------+-------+-------+-------+
573 * | Prefix | 0-4
574 * +---------------------------------------------------------------+
575 * | sub tlvs |
576 * +---------------------------------------------------------------+
577 * : :
578 */
579 *found |= TLVFLAG_TE_IPV4_REACHABILITY;
jardineb5d44e2003-12-23 08:09:43 +0000580#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000581 zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d",
582 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000583#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000584 if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
585 {
586 while (length > value_len)
587 {
588 te_ipv4_reach = (struct te_ipv4_reachability *) pnt;
589 if (!tlvs->te_ipv4_reachs)
590 tlvs->te_ipv4_reachs = list_new ();
591 listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach);
592 /* this trickery is permitable since no subtlvs are defined */
593 value_len += 5 + ((te_ipv4_reach->control & 0x3F) ?
594 ((((te_ipv4_reach->control & 0x3F) -
595 1) >> 3) + 1) : 0);
596 pnt += 5 + ((te_ipv4_reach->control & 0x3F) ?
597 ((((te_ipv4_reach->control & 0x3F) - 1) >> 3) + 1) : 0);
598 }
599 }
600 else
601 {
602 pnt += length;
603 }
604 break;
jardineb5d44e2003-12-23 08:09:43 +0000605
606#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000607 case IPV6_ADDR:
608 /* +-------+-------+-------+-------+-------+-------+-------+-------+
609 * + IP version 6 address + 16
610 * +-------+-------+-------+-------+-------+-------+-------+-------+
611 * : :
612 */
613 *found |= TLVFLAG_IPV6_ADDR;
jardineb5d44e2003-12-23 08:09:43 +0000614#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000615 zlog_debug ("ISIS-TLV (%s): IPv6 Address length %d",
616 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000617#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000618 if (*expected & TLVFLAG_IPV6_ADDR)
619 {
620 while (length > value_len)
621 {
622 ipv6_addr = (struct in6_addr *) pnt;
623 if (!tlvs->ipv6_addrs)
624 tlvs->ipv6_addrs = list_new ();
625 listnode_add (tlvs->ipv6_addrs, ipv6_addr);
626 value_len += 16;
627 pnt += 16;
628 }
629 }
630 else
631 {
632 pnt += length;
633 }
634 break;
jardineb5d44e2003-12-23 08:09:43 +0000635
hassof390d2c2004-09-10 20:48:21 +0000636 case IPV6_REACHABILITY:
637 /* +-------+-------+-------+-------+-------+-------+-------+-------+
638 * | Default Metric | 4
639 * +-------+-------+-------+-------+-------+-------+-------+-------+
640 * | Control Informantion |
641 * +---------------------------------------------------------------+
642 * | IPv6 Prefix Length |--+
643 * +---------------------------------------------------------------+ |
644 * | IPv6 Prefix |<-+
645 * +---------------------------------------------------------------+
646 */
647 *found |= TLVFLAG_IPV6_REACHABILITY;
648 if (*expected & TLVFLAG_IPV6_REACHABILITY)
649 {
650 while (length > value_len)
651 {
652 ipv6_reach = (struct ipv6_reachability *) pnt;
653 prefix_octets = ((ipv6_reach->prefix_len + 7) / 8);
654 value_len += prefix_octets + 6;
655 pnt += prefix_octets + 6;
656 /* FIXME: sub-tlvs */
657 if (!tlvs->ipv6_reachs)
658 tlvs->ipv6_reachs = list_new ();
659 listnode_add (tlvs->ipv6_reachs, ipv6_reach);
660 }
661 }
662 else
663 {
664 pnt += length;
665 }
666 break;
jardineb5d44e2003-12-23 08:09:43 +0000667#endif /* HAVE_IPV6 */
668
hassof390d2c2004-09-10 20:48:21 +0000669 case WAY3_HELLO:
670 /* +---------------------------------------------------------------+
671 * | Adjacency state | 1
672 * +---------------------------------------------------------------+
673 * | Extended Local Circuit ID | 4
674 * +---------------------------------------------------------------+
675 * | Neighbor System ID (If known) | 0-8
676 * (probably 6)
677 * +---------------------------------------------------------------+
678 * | Neighbor Local Circuit ID (If known) | 4
679 * +---------------------------------------------------------------+
680 */
681 *found |= TLVFLAG_3WAY_HELLO;
682 if (*expected & TLVFLAG_3WAY_HELLO)
683 {
684 while (length > value_len)
685 {
686 /* FIXME: make this work */
jardineb5d44e2003-12-23 08:09:43 +0000687/* Adjacency State (one octet):
688 0 = Up
689 1 = Initializing
690 2 = Down
691 Extended Local Circuit ID (four octets)
692 Neighbor System ID if known (zero to eight octets)
693 Neighbor Extended Local Circuit ID (four octets, if Neighbor
694 System ID is present) */
hassof390d2c2004-09-10 20:48:21 +0000695 pnt += length;
696 }
697 }
698 else
699 {
700 pnt += length;
701 }
jardineb5d44e2003-12-23 08:09:43 +0000702
hassof390d2c2004-09-10 20:48:21 +0000703 break;
704 case GRACEFUL_RESTART:
705 /* +-------+-------+-------+-------+-------+-------+-------+-------+
706 * | Reserved | SA | RA | RR | 1
707 * +-------+-------+-------+-------+-------+-------+-------+-------+
708 * | Remaining Time | 2
709 * +---------------------------------------------------------------+
710 * | Restarting Neighbor ID (If known) | 0-8
711 * +---------------------------------------------------------------+
712 */
713 *found |= TLVFLAG_GRACEFUL_RESTART;
714 if (*expected & TLVFLAG_GRACEFUL_RESTART)
715 {
716 /* FIXME: make this work */
717 }
718 pnt += length;
719 break;
jardineb5d44e2003-12-23 08:09:43 +0000720
hassof390d2c2004-09-10 20:48:21 +0000721 default:
722 zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
723 areatag, type, length);
jardineb5d44e2003-12-23 08:09:43 +0000724
hassof390d2c2004-09-10 20:48:21 +0000725 retval = ISIS_WARNING;
726 pnt += length;
727 break;
728 }
jardineb5d44e2003-12-23 08:09:43 +0000729 }
hassof390d2c2004-09-10 20:48:21 +0000730
jardineb5d44e2003-12-23 08:09:43 +0000731 return retval;
732}
733
734int
hassof390d2c2004-09-10 20:48:21 +0000735add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000736{
737
paul9985f832005-02-09 15:51:56 +0000738 if (STREAM_SIZE (stream) - stream_get_endp (stream) < (unsigned) len + 2)
hassof390d2c2004-09-10 20:48:21 +0000739 {
740 zlog_warn ("No room for TLV of type %d", tag);
741 return ISIS_WARNING;
742 }
jardineb5d44e2003-12-23 08:09:43 +0000743
hassof390d2c2004-09-10 20:48:21 +0000744 stream_putc (stream, tag); /* TAG */
745 stream_putc (stream, len); /* LENGTH */
746 stream_put (stream, value, (int) len); /* VALUE */
jardineb5d44e2003-12-23 08:09:43 +0000747
Fritz Reichmannc25eaff2011-10-01 17:43:12 +0400748#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000749 zlog_debug ("Added TLV %d len %d", tag, len);
jardineb5d44e2003-12-23 08:09:43 +0000750#endif /* EXTREME DEBUG */
751 return ISIS_OK;
752}
753
jardineb5d44e2003-12-23 08:09:43 +0000754int
hassof390d2c2004-09-10 20:48:21 +0000755tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000756{
757 struct listnode *node;
758 struct area_addr *area_addr;
759
hassof390d2c2004-09-10 20:48:21 +0000760 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000761 u_char *pos = value;
hassof390d2c2004-09-10 20:48:21 +0000762
paul1eb8ef22005-04-07 07:30:20 +0000763 for (ALL_LIST_ELEMENTS_RO (area_addrs, node, area_addr))
hassof390d2c2004-09-10 20:48:21 +0000764 {
hassof390d2c2004-09-10 20:48:21 +0000765 if (pos - value + area_addr->addr_len > 255)
766 goto err;
767 *pos = area_addr->addr_len;
768 pos++;
769 memcpy (pos, area_addr->area_addr, (int) area_addr->addr_len);
770 pos += area_addr->addr_len;
771 }
772
jardineb5d44e2003-12-23 08:09:43 +0000773 return add_tlv (AREA_ADDRESSES, pos - value, value, stream);
774
hassof390d2c2004-09-10 20:48:21 +0000775err:
jardineb5d44e2003-12-23 08:09:43 +0000776 zlog_warn ("tlv_add_area_addrs(): TLV longer than 255");
777 return ISIS_WARNING;
778}
779
hassof390d2c2004-09-10 20:48:21 +0000780int
781tlv_add_is_neighs (struct list *is_neighs, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000782{
hasso3fdb2dd2005-09-28 18:45:54 +0000783 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000784 struct is_neigh *is_neigh;
hassof390d2c2004-09-10 20:48:21 +0000785 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000786 u_char *pos = value;
787 int retval;
788
hassof390d2c2004-09-10 20:48:21 +0000789 *pos = 0; /*is_neigh->virtual; */
790 pos++;
jardineb5d44e2003-12-23 08:09:43 +0000791
hasso3fdb2dd2005-09-28 18:45:54 +0000792 for (ALL_LIST_ELEMENTS_RO (is_neighs, node, is_neigh))
hassof390d2c2004-09-10 20:48:21 +0000793 {
hassof390d2c2004-09-10 20:48:21 +0000794 if (pos - value + IS_NEIGHBOURS_LEN > 255)
795 {
796 retval = add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
797 if (retval != ISIS_OK)
798 return retval;
799 pos = value;
800 }
801 *pos = is_neigh->metrics.metric_default;
802 pos++;
803 *pos = is_neigh->metrics.metric_delay;
804 pos++;
805 *pos = is_neigh->metrics.metric_expense;
806 pos++;
807 *pos = is_neigh->metrics.metric_error;
808 pos++;
809 memcpy (pos, is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
810 pos += ISIS_SYS_ID_LEN + 1;
jardineb5d44e2003-12-23 08:09:43 +0000811 }
jardineb5d44e2003-12-23 08:09:43 +0000812
813 return add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
814}
815
jardineb5d44e2003-12-23 08:09:43 +0000816int
hassoea3be4c2005-09-26 17:11:12 +0000817tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
818{
hasso3fdb2dd2005-09-28 18:45:54 +0000819 struct listnode *node;
hassoea3be4c2005-09-26 17:11:12 +0000820 struct te_is_neigh *te_is_neigh;
821 u_char value[255];
822 u_char *pos = value;
823 int retval;
824
hasso3fdb2dd2005-09-28 18:45:54 +0000825 for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh))
hassoea3be4c2005-09-26 17:11:12 +0000826 {
827 /* FIXME: This will be wrong if we are going to add TE sub TLVs. */
828 if (pos - value + IS_NEIGHBOURS_LEN > 255)
829 {
830 retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
831 if (retval != ISIS_OK)
832 return retval;
833 pos = value;
834 }
835
836 memcpy (pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
837 pos += ISIS_SYS_ID_LEN + 1;
838 memcpy (pos, te_is_neigh->te_metric, 3);
839 pos += 3;
840 /* Sub TLVs length. */
841 *pos = 0;
842 pos++;
843 }
844
845 return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
846}
847
848int
jardineb5d44e2003-12-23 08:09:43 +0000849tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream)
850{
hasso3fdb2dd2005-09-28 18:45:54 +0000851 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000852 u_char *snpa;
hassof390d2c2004-09-10 20:48:21 +0000853 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000854 u_char *pos = value;
855 int retval;
856
hasso3fdb2dd2005-09-28 18:45:54 +0000857 for (ALL_LIST_ELEMENTS_RO (lan_neighs, node, snpa))
hassof390d2c2004-09-10 20:48:21 +0000858 {
hassof390d2c2004-09-10 20:48:21 +0000859 if (pos - value + ETH_ALEN > 255)
860 {
861 retval = add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
862 if (retval != ISIS_OK)
863 return retval;
864 pos = value;
865 }
866 memcpy (pos, snpa, ETH_ALEN);
867 pos += ETH_ALEN;
jardineb5d44e2003-12-23 08:09:43 +0000868 }
jardineb5d44e2003-12-23 08:09:43 +0000869
870 return add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
871}
872
jardineb5d44e2003-12-23 08:09:43 +0000873int
874tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream)
875{
hassof390d2c2004-09-10 20:48:21 +0000876 return add_tlv (PROTOCOLS_SUPPORTED, nlpids->count, nlpids->nlpids, stream);
jardineb5d44e2003-12-23 08:09:43 +0000877}
878
hassof390d2c2004-09-10 20:48:21 +0000879int
hassof7c43dc2004-09-26 16:24:14 +0000880tlv_add_authinfo (char auth_type, char auth_len, u_char *auth_value,
hassof390d2c2004-09-10 20:48:21 +0000881 struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000882{
883 u_char value[255];
884 u_char *pos = value;
Fritz Reichmanne6b03b72011-10-01 17:49:48 +0400885 *pos++ = auth_type;
jardineb5d44e2003-12-23 08:09:43 +0000886 memcpy (pos, auth_value, auth_len);
887
888 return add_tlv (AUTH_INFO, auth_len + 1, value, stream);
889}
890
891int
892tlv_add_checksum (struct checksum *checksum, struct stream *stream)
893{
894 u_char value[255];
hassof390d2c2004-09-10 20:48:21 +0000895 u_char *pos = value;
896 return add_tlv (CHECKSUM, pos - value, value, stream);
jardineb5d44e2003-12-23 08:09:43 +0000897}
898
899int
900tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream)
901{
hasso3fdb2dd2005-09-28 18:45:54 +0000902 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000903 struct prefix_ipv4 *ipv4;
904 u_char value[255];
905 u_char *pos = value;
906 int retval;
907
hasso3fdb2dd2005-09-28 18:45:54 +0000908 for (ALL_LIST_ELEMENTS_RO (ip_addrs, node, ipv4))
hassof390d2c2004-09-10 20:48:21 +0000909 {
hassof390d2c2004-09-10 20:48:21 +0000910 if (pos - value + IPV4_MAX_BYTELEN > 255)
911 {
912 retval = add_tlv (IPV4_ADDR, pos - value, value, stream);
913 if (retval != ISIS_OK)
914 return retval;
915 pos = value;
916 }
917 *(u_int32_t *) pos = ipv4->prefix.s_addr;
918 pos += IPV4_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +0000919 }
hassof390d2c2004-09-10 20:48:21 +0000920
jardineb5d44e2003-12-23 08:09:43 +0000921 return add_tlv (IPV4_ADDR, pos - value, value, stream);
922}
923
hasso81ad8f62005-09-26 17:58:24 +0000924/* Used to add TLV containing just one IPv4 address - either IPv4 address TLV
925 * (in case of LSP) or TE router ID TLV. */
926int
927tlv_add_in_addr (struct in_addr *addr, struct stream *stream, u_char tag)
928{
929 u_char value[255];
930 u_char *pos = value;
931
932 memcpy (pos, addr, IPV4_MAX_BYTELEN);
933 pos += IPV4_MAX_BYTELEN;
934
935 return add_tlv (tag, pos - value, value, stream);
936}
937
jardineb5d44e2003-12-23 08:09:43 +0000938int
939tlv_add_dynamic_hostname (struct hostname *hostname, struct stream *stream)
940{
hassof390d2c2004-09-10 20:48:21 +0000941 return add_tlv (DYNAMIC_HOSTNAME, hostname->namelen, hostname->name,
942 stream);
jardineb5d44e2003-12-23 08:09:43 +0000943}
944
hassof390d2c2004-09-10 20:48:21 +0000945int
jardineb5d44e2003-12-23 08:09:43 +0000946tlv_add_lsp_entries (struct list *lsps, struct stream *stream)
947{
hasso3fdb2dd2005-09-28 18:45:54 +0000948 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000949 struct isis_lsp *lsp;
hassof390d2c2004-09-10 20:48:21 +0000950 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000951 u_char *pos = value;
952 int retval;
953
hasso3fdb2dd2005-09-28 18:45:54 +0000954 for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp))
hassof390d2c2004-09-10 20:48:21 +0000955 {
hassof390d2c2004-09-10 20:48:21 +0000956 if (pos - value + LSP_ENTRIES_LEN > 255)
957 {
958 retval = add_tlv (LSP_ENTRIES, pos - value, value, stream);
959 if (retval != ISIS_OK)
960 return retval;
961 pos = value;
962 }
963 *((u_int16_t *) pos) = lsp->lsp_header->rem_lifetime;
964 pos += 2;
965 memcpy (pos, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
966 pos += ISIS_SYS_ID_LEN + 2;
967 *((u_int32_t *) pos) = lsp->lsp_header->seq_num;
968 pos += 4;
969 *((u_int16_t *) pos) = lsp->lsp_header->checksum;
970 pos += 2;
jardineb5d44e2003-12-23 08:09:43 +0000971 }
hassof390d2c2004-09-10 20:48:21 +0000972
jardineb5d44e2003-12-23 08:09:43 +0000973 return add_tlv (LSP_ENTRIES, pos - value, value, stream);
974}
975
hassof390d2c2004-09-10 20:48:21 +0000976int
jardineb5d44e2003-12-23 08:09:43 +0000977tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream)
978{
hasso3fdb2dd2005-09-28 18:45:54 +0000979 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000980 struct ipv4_reachability *reach;
hassof390d2c2004-09-10 20:48:21 +0000981 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000982 u_char *pos = value;
983 int retval;
984
hasso3fdb2dd2005-09-28 18:45:54 +0000985 for (ALL_LIST_ELEMENTS_RO (ipv4_reachs, node, reach))
hassof390d2c2004-09-10 20:48:21 +0000986 {
hassof390d2c2004-09-10 20:48:21 +0000987 if (pos - value + IPV4_REACH_LEN > 255)
988 {
989 retval =
990 add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
991 if (retval != ISIS_OK)
992 return retval;
993 pos = value;
994 }
995 *pos = reach->metrics.metric_default;
996 pos++;
997 *pos = reach->metrics.metric_delay;
998 pos++;
999 *pos = reach->metrics.metric_expense;
1000 pos++;
1001 *pos = reach->metrics.metric_error;
1002 pos++;
1003 *(u_int32_t *) pos = reach->prefix.s_addr;
1004 pos += IPV4_MAX_BYTELEN;
1005 *(u_int32_t *) pos = reach->mask.s_addr;
1006 pos += IPV4_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +00001007 }
hassof390d2c2004-09-10 20:48:21 +00001008
1009
jardineb5d44e2003-12-23 08:09:43 +00001010 return add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
1011}
1012
hassoea3be4c2005-09-26 17:11:12 +00001013int
1014tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream)
1015{
hasso3fdb2dd2005-09-28 18:45:54 +00001016 struct listnode *node;
hassoea3be4c2005-09-26 17:11:12 +00001017 struct te_ipv4_reachability *te_reach;
1018 u_char value[255];
1019 u_char *pos = value;
1020 u_char prefix_size;
1021 int retval;
1022
hasso3fdb2dd2005-09-28 18:45:54 +00001023 for (ALL_LIST_ELEMENTS_RO (te_ipv4_reachs, node, te_reach))
hassoea3be4c2005-09-26 17:11:12 +00001024 {
1025 prefix_size = ((((te_reach->control & 0x3F) - 1) >> 3) + 1);
1026
1027 if (pos - value + (5 + prefix_size) > 255)
1028 {
1029 retval =
1030 add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
1031 if (retval != ISIS_OK)
1032 return retval;
1033 pos = value;
1034 }
1035 *(u_int32_t *) pos = te_reach->te_metric;
1036 pos += 4;
1037 *pos = te_reach->control;
1038 pos++;
1039 memcpy (pos, &te_reach->prefix_start, prefix_size);
1040 pos += prefix_size;
1041 }
1042
1043 return add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
1044}
1045
hassof390d2c2004-09-10 20:48:21 +00001046#ifdef HAVE_IPV6
jardineb5d44e2003-12-23 08:09:43 +00001047int
1048tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream)
1049{
hasso3fdb2dd2005-09-28 18:45:54 +00001050 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00001051 struct prefix_ipv6 *ipv6;
1052 u_char value[255];
1053 u_char *pos = value;
1054 int retval;
hassof390d2c2004-09-10 20:48:21 +00001055
hasso3fdb2dd2005-09-28 18:45:54 +00001056 for (ALL_LIST_ELEMENTS_RO (ipv6_addrs, node, ipv6))
hassof390d2c2004-09-10 20:48:21 +00001057 {
hassof390d2c2004-09-10 20:48:21 +00001058 if (pos - value + IPV6_MAX_BYTELEN > 255)
1059 {
1060 retval = add_tlv (IPV6_ADDR, pos - value, value, stream);
1061 if (retval != ISIS_OK)
1062 return retval;
1063 pos = value;
1064 }
1065 memcpy (pos, ipv6->prefix.s6_addr, IPV6_MAX_BYTELEN);
1066 pos += IPV6_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +00001067 }
hassof390d2c2004-09-10 20:48:21 +00001068
jardineb5d44e2003-12-23 08:09:43 +00001069 return add_tlv (IPV6_ADDR, pos - value, value, stream);
1070}
1071
1072int
1073tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream)
1074{
hasso3fdb2dd2005-09-28 18:45:54 +00001075 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00001076 struct ipv6_reachability *ip6reach;
1077 u_char value[255];
1078 u_char *pos = value;
1079 int retval, prefix_octets;
hassof390d2c2004-09-10 20:48:21 +00001080
hasso3fdb2dd2005-09-28 18:45:54 +00001081 for (ALL_LIST_ELEMENTS_RO (ipv6_reachs, node, ip6reach))
hassof390d2c2004-09-10 20:48:21 +00001082 {
hassof390d2c2004-09-10 20:48:21 +00001083 if (pos - value + IPV6_MAX_BYTELEN + 6 > 255)
1084 {
1085 retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
1086 if (retval != ISIS_OK)
1087 return retval;
1088 pos = value;
1089 }
1090 *(uint32_t *) pos = ip6reach->metric;
1091 pos += 4;
1092 *pos = ip6reach->control_info;
1093 pos++;
1094 prefix_octets = ((ip6reach->prefix_len + 7) / 8);
1095 *pos = ip6reach->prefix_len;
1096 pos++;
1097 memcpy (pos, ip6reach->prefix, prefix_octets);
1098 pos += prefix_octets;
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_REACHABILITY, pos - value, value, stream);
1102}
1103#endif /* HAVE_IPV6 */
1104
1105int
1106tlv_add_padding (struct stream *stream)
1107{
hassof390d2c2004-09-10 20:48:21 +00001108 int fullpads, i, left;
1109
jardineb5d44e2003-12-23 08:09:43 +00001110 /*
1111 * How many times can we add full padding ?
1112 */
hassof390d2c2004-09-10 20:48:21 +00001113 fullpads = (STREAM_SIZE (stream) - stream_get_endp (stream)) / 257;
1114 for (i = 0; i < fullpads; i++)
1115 {
1116 if (!stream_putc (stream, (u_char) PADDING)) /* TAG */
1117 goto err;
1118 if (!stream_putc (stream, (u_char) 255)) /* LENGHT */
1119 goto err;
paul15935e92005-05-03 09:27:23 +00001120 stream_put (stream, NULL, 255); /* zero padding */
hassof390d2c2004-09-10 20:48:21 +00001121 }
1122
paul9985f832005-02-09 15:51:56 +00001123 left = STREAM_SIZE (stream) - stream_get_endp (stream);
hassof390d2c2004-09-10 20:48:21 +00001124
jardineb5d44e2003-12-23 08:09:43 +00001125 if (left < 2)
1126 return ISIS_OK;
hassof390d2c2004-09-10 20:48:21 +00001127
1128 if (left == 2)
1129 {
1130 stream_putc (stream, PADDING);
1131 stream_putc (stream, 0);
1132 return ISIS_OK;
1133 }
1134
jardineb5d44e2003-12-23 08:09:43 +00001135 stream_putc (stream, PADDING);
1136 stream_putc (stream, left - 2);
paul15935e92005-05-03 09:27:23 +00001137 stream_put (stream, NULL, left-2);
jardineb5d44e2003-12-23 08:09:43 +00001138
1139 return ISIS_OK;
1140
hassof390d2c2004-09-10 20:48:21 +00001141err:
jardineb5d44e2003-12-23 08:09:43 +00001142 zlog_warn ("tlv_add_padding(): no room for tlv");
1143 return ISIS_WARNING;
1144}