blob: 2c2415ae022d3bfc108f3c368be3e426c6bf0fae [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;
David Lamparterf02a0992012-05-08 13:15:45 +0200120 u_char *start = stream, *pnt = stream, *endpnt;
jardineb5d44e2003-12-23 08:09:43 +0000121
122 *found = 0;
123 memset (tlvs, 0, sizeof (struct tlvs));
hassof390d2c2004-09-10 20:48:21 +0000124
125 while (pnt < stream + size - 2)
126 {
127 type = *pnt;
128 length = *(pnt + 1);
129 pnt += 2;
130 value_len = 0;
131 if (pnt + length > stream + size)
132 {
133 zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet "
134 "boundaries", areatag, type, length);
135 retval = ISIS_WARNING;
136 break;
137 }
138 switch (type)
139 {
140 case AREA_ADDRESSES:
141 /* +-------+-------+-------+-------+-------+-------+-------+-------+
142 * | Address Length |
143 * +-------+-------+-------+-------+-------+-------+-------+-------+
144 * | Area Address |
145 * +-------+-------+-------+-------+-------+-------+-------+-------+
146 * : :
147 */
148 *found |= TLVFLAG_AREA_ADDRS;
jardineb5d44e2003-12-23 08:09:43 +0000149#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000150 zlog_debug ("TLV Area Adresses len %d", length);
jardineb5d44e2003-12-23 08:09:43 +0000151#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000152 if (*expected & TLVFLAG_AREA_ADDRS)
153 {
154 while (length > value_len)
155 {
156 area_addr = (struct area_addr *) pnt;
157 value_len += area_addr->addr_len + 1;
158 pnt += area_addr->addr_len + 1;
159 if (!tlvs->area_addrs)
160 tlvs->area_addrs = list_new ();
161 listnode_add (tlvs->area_addrs, area_addr);
162 }
163 }
164 else
165 {
166 pnt += length;
167 }
168 break;
jardineb5d44e2003-12-23 08:09:43 +0000169
hassof390d2c2004-09-10 20:48:21 +0000170 case IS_NEIGHBOURS:
171 *found |= TLVFLAG_IS_NEIGHS;
jardineb5d44e2003-12-23 08:09:43 +0000172#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000173 zlog_debug ("ISIS-TLV (%s): IS Neighbours length %d",
174 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000175#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000176 if (TLVFLAG_IS_NEIGHS & *expected)
177 {
178 /* +-------+-------+-------+-------+-------+-------+-------+-------+
179 * | Virtual Flag |
180 * +-------+-------+-------+-------+-------+-------+-------+-------+
181 */
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 */
David Lamparterf02a0992012-05-08 13:15:45 +0200587 endpnt = pnt + length;
hassof390d2c2004-09-10 20:48:21 +0000588 if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
589 {
590 while (length > value_len)
591 {
592 te_ipv4_reach = (struct te_ipv4_reachability *) pnt;
David Lamparterf02a0992012-05-08 13:15:45 +0200593 if ((te_ipv4_reach->control & 0x3F) > IPV4_MAX_BITLEN)
594 {
595 zlog_warn ("ISIS-TLV (%s): invalid IPv4 extended reach"
596 "ability prefix length %d", areatag,
597 te_ipv4_reach->control & 0x3F);
598 retval = ISIS_WARNING;
599 break;
600 }
hassof390d2c2004-09-10 20:48:21 +0000601 if (!tlvs->te_ipv4_reachs)
602 tlvs->te_ipv4_reachs = list_new ();
603 listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach);
604 /* this trickery is permitable since no subtlvs are defined */
605 value_len += 5 + ((te_ipv4_reach->control & 0x3F) ?
606 ((((te_ipv4_reach->control & 0x3F) -
607 1) >> 3) + 1) : 0);
608 pnt += 5 + ((te_ipv4_reach->control & 0x3F) ?
609 ((((te_ipv4_reach->control & 0x3F) - 1) >> 3) + 1) : 0);
610 }
611 }
David Lamparterf02a0992012-05-08 13:15:45 +0200612
613 pnt = endpnt;
hassof390d2c2004-09-10 20:48:21 +0000614 break;
jardineb5d44e2003-12-23 08:09:43 +0000615
616#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000617 case IPV6_ADDR:
618 /* +-------+-------+-------+-------+-------+-------+-------+-------+
619 * + IP version 6 address + 16
620 * +-------+-------+-------+-------+-------+-------+-------+-------+
621 * : :
622 */
623 *found |= TLVFLAG_IPV6_ADDR;
jardineb5d44e2003-12-23 08:09:43 +0000624#ifdef EXTREME_TLV_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000625 zlog_debug ("ISIS-TLV (%s): IPv6 Address length %d",
626 areatag, length);
jardineb5d44e2003-12-23 08:09:43 +0000627#endif /* EXTREME_TLV_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000628 if (*expected & TLVFLAG_IPV6_ADDR)
629 {
630 while (length > value_len)
631 {
632 ipv6_addr = (struct in6_addr *) pnt;
633 if (!tlvs->ipv6_addrs)
634 tlvs->ipv6_addrs = list_new ();
635 listnode_add (tlvs->ipv6_addrs, ipv6_addr);
636 value_len += 16;
637 pnt += 16;
638 }
639 }
640 else
641 {
642 pnt += length;
643 }
644 break;
jardineb5d44e2003-12-23 08:09:43 +0000645
hassof390d2c2004-09-10 20:48:21 +0000646 case IPV6_REACHABILITY:
647 /* +-------+-------+-------+-------+-------+-------+-------+-------+
648 * | Default Metric | 4
649 * +-------+-------+-------+-------+-------+-------+-------+-------+
650 * | Control Informantion |
651 * +---------------------------------------------------------------+
652 * | IPv6 Prefix Length |--+
653 * +---------------------------------------------------------------+ |
654 * | IPv6 Prefix |<-+
655 * +---------------------------------------------------------------+
656 */
657 *found |= TLVFLAG_IPV6_REACHABILITY;
David Lamparterf02a0992012-05-08 13:15:45 +0200658 endpnt = pnt + length;
659
hassof390d2c2004-09-10 20:48:21 +0000660 if (*expected & TLVFLAG_IPV6_REACHABILITY)
661 {
662 while (length > value_len)
663 {
664 ipv6_reach = (struct ipv6_reachability *) pnt;
David Lamparterf02a0992012-05-08 13:15:45 +0200665 if (ipv6_reach->prefix_len > IPV6_MAX_BITLEN)
666 {
667 zlog_warn ("ISIS-TLV (%s): invalid IPv6 extended reach"
668 "ability prefix length %d", areatag,
669 ipv6_reach->prefix_len);
670 retval = ISIS_WARNING;
671 break;
672 }
673
hassof390d2c2004-09-10 20:48:21 +0000674 prefix_octets = ((ipv6_reach->prefix_len + 7) / 8);
675 value_len += prefix_octets + 6;
676 pnt += prefix_octets + 6;
677 /* FIXME: sub-tlvs */
678 if (!tlvs->ipv6_reachs)
679 tlvs->ipv6_reachs = list_new ();
680 listnode_add (tlvs->ipv6_reachs, ipv6_reach);
681 }
682 }
David Lamparterf02a0992012-05-08 13:15:45 +0200683
684 pnt = endpnt;
hassof390d2c2004-09-10 20:48:21 +0000685 break;
jardineb5d44e2003-12-23 08:09:43 +0000686#endif /* HAVE_IPV6 */
687
hassof390d2c2004-09-10 20:48:21 +0000688 case WAY3_HELLO:
689 /* +---------------------------------------------------------------+
690 * | Adjacency state | 1
691 * +---------------------------------------------------------------+
692 * | Extended Local Circuit ID | 4
693 * +---------------------------------------------------------------+
694 * | Neighbor System ID (If known) | 0-8
695 * (probably 6)
696 * +---------------------------------------------------------------+
697 * | Neighbor Local Circuit ID (If known) | 4
698 * +---------------------------------------------------------------+
699 */
700 *found |= TLVFLAG_3WAY_HELLO;
701 if (*expected & TLVFLAG_3WAY_HELLO)
702 {
703 while (length > value_len)
704 {
705 /* FIXME: make this work */
jardineb5d44e2003-12-23 08:09:43 +0000706/* Adjacency State (one octet):
707 0 = Up
708 1 = Initializing
709 2 = Down
710 Extended Local Circuit ID (four octets)
711 Neighbor System ID if known (zero to eight octets)
712 Neighbor Extended Local Circuit ID (four octets, if Neighbor
713 System ID is present) */
hassof390d2c2004-09-10 20:48:21 +0000714 pnt += length;
David Lampartere8aca322012-11-27 01:10:30 +0000715 value_len += length;
hassof390d2c2004-09-10 20:48:21 +0000716 }
717 }
718 else
719 {
720 pnt += length;
721 }
jardineb5d44e2003-12-23 08:09:43 +0000722
hassof390d2c2004-09-10 20:48:21 +0000723 break;
724 case GRACEFUL_RESTART:
725 /* +-------+-------+-------+-------+-------+-------+-------+-------+
726 * | Reserved | SA | RA | RR | 1
727 * +-------+-------+-------+-------+-------+-------+-------+-------+
728 * | Remaining Time | 2
729 * +---------------------------------------------------------------+
730 * | Restarting Neighbor ID (If known) | 0-8
731 * +---------------------------------------------------------------+
732 */
733 *found |= TLVFLAG_GRACEFUL_RESTART;
734 if (*expected & TLVFLAG_GRACEFUL_RESTART)
735 {
736 /* FIXME: make this work */
737 }
738 pnt += length;
739 break;
jardineb5d44e2003-12-23 08:09:43 +0000740
hassof390d2c2004-09-10 20:48:21 +0000741 default:
742 zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
743 areatag, type, length);
jardineb5d44e2003-12-23 08:09:43 +0000744
hassof390d2c2004-09-10 20:48:21 +0000745 retval = ISIS_WARNING;
746 pnt += length;
747 break;
748 }
jardineb5d44e2003-12-23 08:09:43 +0000749 }
hassof390d2c2004-09-10 20:48:21 +0000750
jardineb5d44e2003-12-23 08:09:43 +0000751 return retval;
752}
753
754int
hassof390d2c2004-09-10 20:48:21 +0000755add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000756{
Josh Bailey3f045a02012-03-24 08:35:20 -0700757 if ((stream_get_size (stream) - stream_get_endp (stream)) <
758 (((unsigned)len) + 2))
hassof390d2c2004-09-10 20:48:21 +0000759 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700760 zlog_warn ("No room for TLV of type %d "
761 "(total size %d available %d required %d)",
762 tag, (int)stream_get_size (stream),
763 (int)(stream_get_size (stream) - stream_get_endp (stream)),
764 len+2);
hassof390d2c2004-09-10 20:48:21 +0000765 return ISIS_WARNING;
766 }
jardineb5d44e2003-12-23 08:09:43 +0000767
hassof390d2c2004-09-10 20:48:21 +0000768 stream_putc (stream, tag); /* TAG */
769 stream_putc (stream, len); /* LENGTH */
770 stream_put (stream, value, (int) len); /* VALUE */
jardineb5d44e2003-12-23 08:09:43 +0000771
772#ifdef EXTREME_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000773 zlog_debug ("Added TLV %d len %d", tag, len);
jardineb5d44e2003-12-23 08:09:43 +0000774#endif /* EXTREME DEBUG */
775 return ISIS_OK;
776}
777
jardineb5d44e2003-12-23 08:09:43 +0000778int
hassof390d2c2004-09-10 20:48:21 +0000779tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000780{
781 struct listnode *node;
782 struct area_addr *area_addr;
783
hassof390d2c2004-09-10 20:48:21 +0000784 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000785 u_char *pos = value;
hassof390d2c2004-09-10 20:48:21 +0000786
paul1eb8ef22005-04-07 07:30:20 +0000787 for (ALL_LIST_ELEMENTS_RO (area_addrs, node, area_addr))
hassof390d2c2004-09-10 20:48:21 +0000788 {
hassof390d2c2004-09-10 20:48:21 +0000789 if (pos - value + area_addr->addr_len > 255)
790 goto err;
791 *pos = area_addr->addr_len;
792 pos++;
793 memcpy (pos, area_addr->area_addr, (int) area_addr->addr_len);
794 pos += area_addr->addr_len;
795 }
796
jardineb5d44e2003-12-23 08:09:43 +0000797 return add_tlv (AREA_ADDRESSES, pos - value, value, stream);
798
hassof390d2c2004-09-10 20:48:21 +0000799err:
jardineb5d44e2003-12-23 08:09:43 +0000800 zlog_warn ("tlv_add_area_addrs(): TLV longer than 255");
801 return ISIS_WARNING;
802}
803
hassof390d2c2004-09-10 20:48:21 +0000804int
805tlv_add_is_neighs (struct list *is_neighs, struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000806{
hasso3fdb2dd2005-09-28 18:45:54 +0000807 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000808 struct is_neigh *is_neigh;
hassof390d2c2004-09-10 20:48:21 +0000809 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000810 u_char *pos = value;
811 int retval;
812
hassof390d2c2004-09-10 20:48:21 +0000813 *pos = 0; /*is_neigh->virtual; */
814 pos++;
jardineb5d44e2003-12-23 08:09:43 +0000815
hasso3fdb2dd2005-09-28 18:45:54 +0000816 for (ALL_LIST_ELEMENTS_RO (is_neighs, node, is_neigh))
hassof390d2c2004-09-10 20:48:21 +0000817 {
hassof390d2c2004-09-10 20:48:21 +0000818 if (pos - value + IS_NEIGHBOURS_LEN > 255)
819 {
820 retval = add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
821 if (retval != ISIS_OK)
822 return retval;
823 pos = value;
824 }
825 *pos = is_neigh->metrics.metric_default;
826 pos++;
827 *pos = is_neigh->metrics.metric_delay;
828 pos++;
829 *pos = is_neigh->metrics.metric_expense;
830 pos++;
831 *pos = is_neigh->metrics.metric_error;
832 pos++;
833 memcpy (pos, is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
834 pos += ISIS_SYS_ID_LEN + 1;
jardineb5d44e2003-12-23 08:09:43 +0000835 }
jardineb5d44e2003-12-23 08:09:43 +0000836
837 return add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
838}
839
jardineb5d44e2003-12-23 08:09:43 +0000840int
hassoea3be4c2005-09-26 17:11:12 +0000841tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
842{
hasso3fdb2dd2005-09-28 18:45:54 +0000843 struct listnode *node;
hassoea3be4c2005-09-26 17:11:12 +0000844 struct te_is_neigh *te_is_neigh;
845 u_char value[255];
846 u_char *pos = value;
847 int retval;
848
hasso3fdb2dd2005-09-28 18:45:54 +0000849 for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh))
hassoea3be4c2005-09-26 17:11:12 +0000850 {
851 /* FIXME: This will be wrong if we are going to add TE sub TLVs. */
852 if (pos - value + IS_NEIGHBOURS_LEN > 255)
853 {
854 retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
855 if (retval != ISIS_OK)
856 return retval;
857 pos = value;
858 }
859
860 memcpy (pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
861 pos += ISIS_SYS_ID_LEN + 1;
862 memcpy (pos, te_is_neigh->te_metric, 3);
863 pos += 3;
864 /* Sub TLVs length. */
865 *pos = 0;
866 pos++;
867 }
868
869 return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
870}
871
872int
jardineb5d44e2003-12-23 08:09:43 +0000873tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream)
874{
hasso3fdb2dd2005-09-28 18:45:54 +0000875 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000876 u_char *snpa;
hassof390d2c2004-09-10 20:48:21 +0000877 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000878 u_char *pos = value;
879 int retval;
880
hasso3fdb2dd2005-09-28 18:45:54 +0000881 for (ALL_LIST_ELEMENTS_RO (lan_neighs, node, snpa))
hassof390d2c2004-09-10 20:48:21 +0000882 {
hassof390d2c2004-09-10 20:48:21 +0000883 if (pos - value + ETH_ALEN > 255)
884 {
885 retval = add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
886 if (retval != ISIS_OK)
887 return retval;
888 pos = value;
889 }
890 memcpy (pos, snpa, ETH_ALEN);
891 pos += ETH_ALEN;
jardineb5d44e2003-12-23 08:09:43 +0000892 }
jardineb5d44e2003-12-23 08:09:43 +0000893
894 return add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
895}
896
jardineb5d44e2003-12-23 08:09:43 +0000897int
898tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream)
899{
hassof390d2c2004-09-10 20:48:21 +0000900 return add_tlv (PROTOCOLS_SUPPORTED, nlpids->count, nlpids->nlpids, stream);
jardineb5d44e2003-12-23 08:09:43 +0000901}
902
hassof390d2c2004-09-10 20:48:21 +0000903int
Josh Bailey3f045a02012-03-24 08:35:20 -0700904tlv_add_authinfo (u_char auth_type, u_char auth_len, u_char *auth_value,
hassof390d2c2004-09-10 20:48:21 +0000905 struct stream *stream)
jardineb5d44e2003-12-23 08:09:43 +0000906{
907 u_char value[255];
908 u_char *pos = value;
Josh Bailey3f045a02012-03-24 08:35:20 -0700909 *pos++ = auth_type;
jardineb5d44e2003-12-23 08:09:43 +0000910 memcpy (pos, auth_value, auth_len);
911
912 return add_tlv (AUTH_INFO, auth_len + 1, value, stream);
913}
914
915int
916tlv_add_checksum (struct checksum *checksum, struct stream *stream)
917{
918 u_char value[255];
hassof390d2c2004-09-10 20:48:21 +0000919 u_char *pos = value;
920 return add_tlv (CHECKSUM, pos - value, value, stream);
jardineb5d44e2003-12-23 08:09:43 +0000921}
922
923int
924tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream)
925{
hasso3fdb2dd2005-09-28 18:45:54 +0000926 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000927 struct prefix_ipv4 *ipv4;
928 u_char value[255];
929 u_char *pos = value;
930 int retval;
931
hasso3fdb2dd2005-09-28 18:45:54 +0000932 for (ALL_LIST_ELEMENTS_RO (ip_addrs, node, ipv4))
hassof390d2c2004-09-10 20:48:21 +0000933 {
hassof390d2c2004-09-10 20:48:21 +0000934 if (pos - value + IPV4_MAX_BYTELEN > 255)
935 {
David Lamparter91d799e2012-11-27 01:10:24 +0000936 /* RFC 1195 s4.2: only one tuple of 63 allowed. */
937 zlog_warn ("tlv_add_ip_addrs(): cutting off at 63 IP addresses");
938 break;
hassof390d2c2004-09-10 20:48:21 +0000939 }
940 *(u_int32_t *) pos = ipv4->prefix.s_addr;
941 pos += IPV4_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +0000942 }
hassof390d2c2004-09-10 20:48:21 +0000943
jardineb5d44e2003-12-23 08:09:43 +0000944 return add_tlv (IPV4_ADDR, pos - value, value, stream);
945}
946
hasso81ad8f62005-09-26 17:58:24 +0000947/* Used to add TLV containing just one IPv4 address - either IPv4 address TLV
948 * (in case of LSP) or TE router ID TLV. */
949int
950tlv_add_in_addr (struct in_addr *addr, struct stream *stream, u_char tag)
951{
952 u_char value[255];
953 u_char *pos = value;
954
955 memcpy (pos, addr, IPV4_MAX_BYTELEN);
956 pos += IPV4_MAX_BYTELEN;
957
958 return add_tlv (tag, pos - value, value, stream);
959}
960
jardineb5d44e2003-12-23 08:09:43 +0000961int
962tlv_add_dynamic_hostname (struct hostname *hostname, struct stream *stream)
963{
hassof390d2c2004-09-10 20:48:21 +0000964 return add_tlv (DYNAMIC_HOSTNAME, hostname->namelen, hostname->name,
965 stream);
jardineb5d44e2003-12-23 08:09:43 +0000966}
967
hassof390d2c2004-09-10 20:48:21 +0000968int
jardineb5d44e2003-12-23 08:09:43 +0000969tlv_add_lsp_entries (struct list *lsps, struct stream *stream)
970{
hasso3fdb2dd2005-09-28 18:45:54 +0000971 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000972 struct isis_lsp *lsp;
hassof390d2c2004-09-10 20:48:21 +0000973 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +0000974 u_char *pos = value;
975 int retval;
976
hasso3fdb2dd2005-09-28 18:45:54 +0000977 for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp))
hassof390d2c2004-09-10 20:48:21 +0000978 {
hassof390d2c2004-09-10 20:48:21 +0000979 if (pos - value + LSP_ENTRIES_LEN > 255)
980 {
981 retval = add_tlv (LSP_ENTRIES, pos - value, value, stream);
982 if (retval != ISIS_OK)
983 return retval;
984 pos = value;
985 }
986 *((u_int16_t *) pos) = lsp->lsp_header->rem_lifetime;
987 pos += 2;
988 memcpy (pos, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
989 pos += ISIS_SYS_ID_LEN + 2;
990 *((u_int32_t *) pos) = lsp->lsp_header->seq_num;
991 pos += 4;
992 *((u_int16_t *) pos) = lsp->lsp_header->checksum;
993 pos += 2;
jardineb5d44e2003-12-23 08:09:43 +0000994 }
hassof390d2c2004-09-10 20:48:21 +0000995
jardineb5d44e2003-12-23 08:09:43 +0000996 return add_tlv (LSP_ENTRIES, pos - value, value, stream);
997}
998
hassof390d2c2004-09-10 20:48:21 +0000999int
jardineb5d44e2003-12-23 08:09:43 +00001000tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream)
1001{
hasso3fdb2dd2005-09-28 18:45:54 +00001002 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00001003 struct ipv4_reachability *reach;
hassof390d2c2004-09-10 20:48:21 +00001004 u_char value[255];
jardineb5d44e2003-12-23 08:09:43 +00001005 u_char *pos = value;
1006 int retval;
1007
hasso3fdb2dd2005-09-28 18:45:54 +00001008 for (ALL_LIST_ELEMENTS_RO (ipv4_reachs, node, reach))
hassof390d2c2004-09-10 20:48:21 +00001009 {
hassof390d2c2004-09-10 20:48:21 +00001010 if (pos - value + IPV4_REACH_LEN > 255)
1011 {
1012 retval =
1013 add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
1014 if (retval != ISIS_OK)
1015 return retval;
1016 pos = value;
1017 }
1018 *pos = reach->metrics.metric_default;
1019 pos++;
1020 *pos = reach->metrics.metric_delay;
1021 pos++;
1022 *pos = reach->metrics.metric_expense;
1023 pos++;
1024 *pos = reach->metrics.metric_error;
1025 pos++;
1026 *(u_int32_t *) pos = reach->prefix.s_addr;
1027 pos += IPV4_MAX_BYTELEN;
1028 *(u_int32_t *) pos = reach->mask.s_addr;
1029 pos += IPV4_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +00001030 }
hassof390d2c2004-09-10 20:48:21 +00001031
jardineb5d44e2003-12-23 08:09:43 +00001032 return add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
1033}
1034
hassoea3be4c2005-09-26 17:11:12 +00001035int
1036tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream)
1037{
hasso3fdb2dd2005-09-28 18:45:54 +00001038 struct listnode *node;
hassoea3be4c2005-09-26 17:11:12 +00001039 struct te_ipv4_reachability *te_reach;
1040 u_char value[255];
1041 u_char *pos = value;
1042 u_char prefix_size;
1043 int retval;
1044
hasso3fdb2dd2005-09-28 18:45:54 +00001045 for (ALL_LIST_ELEMENTS_RO (te_ipv4_reachs, node, te_reach))
hassoea3be4c2005-09-26 17:11:12 +00001046 {
1047 prefix_size = ((((te_reach->control & 0x3F) - 1) >> 3) + 1);
1048
1049 if (pos - value + (5 + prefix_size) > 255)
1050 {
1051 retval =
Josh Bailey3f045a02012-03-24 08:35:20 -07001052 add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
hassoea3be4c2005-09-26 17:11:12 +00001053 if (retval != ISIS_OK)
1054 return retval;
1055 pos = value;
1056 }
1057 *(u_int32_t *) pos = te_reach->te_metric;
1058 pos += 4;
1059 *pos = te_reach->control;
1060 pos++;
1061 memcpy (pos, &te_reach->prefix_start, prefix_size);
1062 pos += prefix_size;
1063 }
1064
1065 return add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
1066}
1067
hassof390d2c2004-09-10 20:48:21 +00001068#ifdef HAVE_IPV6
jardineb5d44e2003-12-23 08:09:43 +00001069int
1070tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream)
1071{
hasso3fdb2dd2005-09-28 18:45:54 +00001072 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00001073 struct prefix_ipv6 *ipv6;
1074 u_char value[255];
1075 u_char *pos = value;
1076 int retval;
hassof390d2c2004-09-10 20:48:21 +00001077
hasso3fdb2dd2005-09-28 18:45:54 +00001078 for (ALL_LIST_ELEMENTS_RO (ipv6_addrs, node, ipv6))
hassof390d2c2004-09-10 20:48:21 +00001079 {
hassof390d2c2004-09-10 20:48:21 +00001080 if (pos - value + IPV6_MAX_BYTELEN > 255)
1081 {
1082 retval = add_tlv (IPV6_ADDR, pos - value, value, stream);
1083 if (retval != ISIS_OK)
1084 return retval;
1085 pos = value;
1086 }
1087 memcpy (pos, ipv6->prefix.s6_addr, IPV6_MAX_BYTELEN);
1088 pos += IPV6_MAX_BYTELEN;
jardineb5d44e2003-12-23 08:09:43 +00001089 }
hassof390d2c2004-09-10 20:48:21 +00001090
jardineb5d44e2003-12-23 08:09:43 +00001091 return add_tlv (IPV6_ADDR, pos - value, value, stream);
1092}
1093
1094int
1095tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream)
1096{
hasso3fdb2dd2005-09-28 18:45:54 +00001097 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00001098 struct ipv6_reachability *ip6reach;
1099 u_char value[255];
1100 u_char *pos = value;
1101 int retval, prefix_octets;
hassof390d2c2004-09-10 20:48:21 +00001102
hasso3fdb2dd2005-09-28 18:45:54 +00001103 for (ALL_LIST_ELEMENTS_RO (ipv6_reachs, node, ip6reach))
hassof390d2c2004-09-10 20:48:21 +00001104 {
hassof390d2c2004-09-10 20:48:21 +00001105 if (pos - value + IPV6_MAX_BYTELEN + 6 > 255)
1106 {
1107 retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
1108 if (retval != ISIS_OK)
1109 return retval;
1110 pos = value;
1111 }
1112 *(uint32_t *) pos = ip6reach->metric;
1113 pos += 4;
1114 *pos = ip6reach->control_info;
1115 pos++;
1116 prefix_octets = ((ip6reach->prefix_len + 7) / 8);
1117 *pos = ip6reach->prefix_len;
1118 pos++;
1119 memcpy (pos, ip6reach->prefix, prefix_octets);
1120 pos += prefix_octets;
jardineb5d44e2003-12-23 08:09:43 +00001121 }
hassof390d2c2004-09-10 20:48:21 +00001122
jardineb5d44e2003-12-23 08:09:43 +00001123 return add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
1124}
1125#endif /* HAVE_IPV6 */
1126
1127int
1128tlv_add_padding (struct stream *stream)
1129{
hassof390d2c2004-09-10 20:48:21 +00001130 int fullpads, i, left;
1131
jardineb5d44e2003-12-23 08:09:43 +00001132 /*
1133 * How many times can we add full padding ?
1134 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001135 fullpads = (stream_get_size (stream) - stream_get_endp (stream)) / 257;
hassof390d2c2004-09-10 20:48:21 +00001136 for (i = 0; i < fullpads; i++)
1137 {
1138 if (!stream_putc (stream, (u_char) PADDING)) /* TAG */
1139 goto err;
1140 if (!stream_putc (stream, (u_char) 255)) /* LENGHT */
1141 goto err;
paul15935e92005-05-03 09:27:23 +00001142 stream_put (stream, NULL, 255); /* zero padding */
hassof390d2c2004-09-10 20:48:21 +00001143 }
1144
Josh Bailey3f045a02012-03-24 08:35:20 -07001145 left = stream_get_size (stream) - stream_get_endp (stream);
hassof390d2c2004-09-10 20:48:21 +00001146
jardineb5d44e2003-12-23 08:09:43 +00001147 if (left < 2)
1148 return ISIS_OK;
hassof390d2c2004-09-10 20:48:21 +00001149
1150 if (left == 2)
1151 {
1152 stream_putc (stream, PADDING);
1153 stream_putc (stream, 0);
1154 return ISIS_OK;
1155 }
1156
jardineb5d44e2003-12-23 08:09:43 +00001157 stream_putc (stream, PADDING);
1158 stream_putc (stream, left - 2);
paul15935e92005-05-03 09:27:23 +00001159 stream_put (stream, NULL, left-2);
jardineb5d44e2003-12-23 08:09:43 +00001160
1161 return ISIS_OK;
1162
hassof390d2c2004-09-10 20:48:21 +00001163err:
jardineb5d44e2003-12-23 08:09:43 +00001164 zlog_warn ("tlv_add_padding(): no room for tlv");
1165 return ISIS_WARNING;
1166}