blob: d7bbb914ca90a3dfd7fdc26e18b7f80ab9c1eae8 [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{
51 XFREE (MTYPE_ISIS_TLV, val);
52
53 return;
54}
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 */
60void
61free_tlvs (struct tlvs *tlvs)
62{
63 if (tlvs->area_addrs) {
64 list_delete (tlvs->area_addrs);
65 }
66 if (tlvs->is_neighs) {
67 list_delete (tlvs->is_neighs);
68 }
69 if (tlvs->te_is_neighs) {
70 list_delete (tlvs->te_is_neighs);
71 }
72 if (tlvs->es_neighs) {
73 list_delete (tlvs->es_neighs);
74 }
75 if (tlvs->lsp_entries) {
76 list_delete (tlvs->lsp_entries);
77 }
78 if (tlvs->lan_neighs) {
79 list_delete (tlvs->lan_neighs);
80 }
81 if (tlvs->prefix_neighs) {
82 list_delete (tlvs->prefix_neighs);
83 }
84 if (tlvs->ipv4_addrs) {
85 list_delete (tlvs->ipv4_addrs);
86 }
87 if (tlvs->ipv4_int_reachs) {
88 list_delete (tlvs->ipv4_int_reachs);
89 }
90 if (tlvs->ipv4_ext_reachs) {
91 list_delete (tlvs->ipv4_ext_reachs);
92 }
93 if (tlvs->te_ipv4_reachs) {
94 list_delete (tlvs->te_ipv4_reachs);
95 }
96#ifdef HAVE_IPV6
97 if (tlvs->ipv6_addrs) {
98 list_delete (tlvs->ipv6_addrs);
99 }
100 if (tlvs->ipv6_reachs) {
101 list_delete (tlvs->ipv6_reachs);
102 }
103#endif /* HAVE_IPV6 */
104 return;
105}
106
107/*
108 * Parses the tlvs found in the variant length part of the PDU.
109 * Caller tells with flags in "expected" which TLV's it is interested in.
110 */
111int
112parse_tlvs (char *areatag, u_char *stream, int size, u_int32_t *expected,
113 u_int32_t *found, struct tlvs *tlvs)
114{
115 u_char type, length;
116 struct lan_neigh *lan_nei;
117 struct area_addr *area_addr;
118 struct is_neigh *is_nei;
119 struct te_is_neigh *te_is_nei;
120 struct es_neigh *es_nei;
121 struct lsp_entry *lsp_entry;
122 struct in_addr *ipv4_addr;
123 struct ipv4_reachability *ipv4_reach;
124 struct te_ipv4_reachability *te_ipv4_reach;
125#ifdef HAVE_IPV6
126 struct in6_addr *ipv6_addr;
127 struct ipv6_reachability *ipv6_reach;
128 int prefix_octets;
129#endif /* HAVE_IPV6 */
130 u_char virtual;
131 int value_len, retval = ISIS_OK;
132 u_char *pnt = stream;
133
134 *found = 0;
135 memset (tlvs, 0, sizeof (struct tlvs));
136
137 while (pnt < stream + size - 2) {
138 type = *pnt;
139 length = *(pnt+1);
140 pnt += 2;
141 value_len = 0;
142 if ( pnt + length > stream + size ) {
143 zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet "
144 "boundaries", areatag, type, length);
145 retval = ISIS_WARNING;
146 break;
147 }
148 switch (type) {
149 case AREA_ADDRESSES:
150 /* +-------+-------+-------+-------+-------+-------+-------+-------+
151 * | Address Length |
152 * +-------+-------+-------+-------+-------+-------+-------+-------+
153 * | Area Address |
154 * +-------+-------+-------+-------+-------+-------+-------+-------+
155 * : :
156 */
157 *found |= TLVFLAG_AREA_ADDRS;
158#ifdef EXTREME_TLV_DEBUG
159 zlog_info ("TLV Area Adresses len %d", length);
160#endif /* EXTREME_TLV_DEBUG */
161 if (*expected & TLVFLAG_AREA_ADDRS) {
162 while (length > value_len) {
163 area_addr = (struct area_addr*)pnt;
164 value_len += area_addr->addr_len + 1;
165 pnt += area_addr->addr_len + 1;
166 if (!tlvs->area_addrs) tlvs->area_addrs = list_new ();
167 listnode_add (tlvs->area_addrs, area_addr);
168 }
169 } else {
170 pnt += length;
171 }
172 break;
173
174 case IS_NEIGHBOURS:
175 *found |= TLVFLAG_IS_NEIGHS;
176#ifdef EXTREME_TLV_DEBUG
177 zlog_info ("ISIS-TLV (%s): IS Neighbours length %d",
178 areatag,
179 length);
180#endif /* EXTREME_TLV_DEBUG */
181 if (TLVFLAG_IS_NEIGHS & *expected) {
182 /* +-------+-------+-------+-------+-------+-------+-------+-------+
183 * | Virtual Flag |
184 * +-------+-------+-------+-------+-------+-------+-------+-------+
185 */
186 virtual = *pnt; /* FIXME: what is the use for this? */
187 pnt++;
188 value_len ++;
189 /* +-------+-------+-------+-------+-------+-------+-------+-------+
190 * | 0 | I/E | Default Metric |
191 * +-------+-------+-------+-------+-------+-------+-------+-------+
192 * | S | I/E | Delay Metric |
193 * +-------+-------+-------+-------+-------+-------+-------+-------+
194 * | S | I/E | Expense Metric |
195 * +-------+-------+-------+-------+-------+-------+-------+-------+
196 * | S | I/E | Error Metric |
197 * +-------+-------+-------+-------+-------+-------+-------+-------+
198 * | Neighbour ID |
199 * +---------------------------------------------------------------+
200 * : :
201 */
202 while (length > value_len) {
203 is_nei = (struct is_neigh*)pnt;
204 value_len += 4 + ISIS_SYS_ID_LEN + 1;
205 pnt += 4 + ISIS_SYS_ID_LEN + 1;
206 if (!tlvs->is_neighs) tlvs->is_neighs = list_new ();
207 listnode_add (tlvs->is_neighs, is_nei);
208 }
209 } else {
210 pnt += length;
211 }
212 break;
213
214 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;
225#ifdef EXTREME_TLV_DEBUG
226 zlog_info ("ISIS-TLV (%s): Extended IS Neighbours length %d",
227 areatag,
228 length);
229#endif /* EXTREME_TLV_DEBUG */
230 if (TLVFLAG_TE_IS_NEIGHS & *expected) {
231 while (length > value_len) {
232 te_is_nei = (struct te_is_neigh*)pnt;
233 value_len += 11;
234 pnt += 11;
235 /* FIXME - subtlvs are handled here, for now we skip */
236 value_len += te_is_nei->sub_tlvs_length;
237 pnt += te_is_nei->sub_tlvs_length;
238
239
240 if (!tlvs->te_is_neighs) tlvs->te_is_neighs = list_new ();
241 listnode_add (tlvs->te_is_neighs, te_is_nei);
242 }
243 } else {
244 pnt += length;
245 }
246 break;
247
248 case ES_NEIGHBOURS:
249 /* +-------+-------+-------+-------+-------+-------+-------+-------+
250 * | 0 | I/E | Default Metric |
251 * +-------+-------+-------+-------+-------+-------+-------+-------+
252 * | S | I/E | Delay Metric |
253 * +-------+-------+-------+-------+-------+-------+-------+-------+
254 * | S | I/E | Expense Metric |
255 * +-------+-------+-------+-------+-------+-------+-------+-------+
256 * | S | I/E | Error Metric |
257 * +-------+-------+-------+-------+-------+-------+-------+-------+
258 * | Neighbour ID |
259 * +---------------------------------------------------------------+
260 * | Neighbour ID |
261 * +---------------------------------------------------------------+
262 * : :
263 */
264#ifdef EXTREME_TLV_DEBUG
265 zlog_info ("ISIS-TLV (%s): ES Neighbours length %d",
266 areatag,
267 length);
268#endif /* EXTREME_TLV_DEBUG */
269 *found |= TLVFLAG_ES_NEIGHS;
270 if (*expected & TLVFLAG_ES_NEIGHS) {
271 es_nei = (struct es_neigh*)pnt;
272 value_len += 4;
273 pnt += 4;
274 while (length > value_len) {
275 /* FIXME FIXME FIXME - add to the list */
276 /* sys_id->id = pnt;*/
277 value_len += ISIS_SYS_ID_LEN;
278 pnt += ISIS_SYS_ID_LEN;
279 /* if (!es_nei->neigh_ids) es_nei->neigh_ids = sysid;*/
280 }
281 if (!tlvs->es_neighs) tlvs->es_neighs = list_new ();
282 listnode_add (tlvs->es_neighs, es_nei);
283 } else {
284 pnt += length;
285 }
286 break;
287
288 case LAN_NEIGHBOURS:
289 /* +-------+-------+-------+-------+-------+-------+-------+-------+
290 * | LAN Address |
291 * +-------+-------+-------+-------+-------+-------+-------+-------+
292 * : :
293 */
294 *found |= TLVFLAG_LAN_NEIGHS;
295 #ifdef EXTREME_TLV_DEBUG
296 zlog_info ("ISIS-TLV (%s): LAN Neigbours length %d",
297 areatag,
298 length);
299 #endif /* EXTREME_TLV_DEBUG */
300 if (TLVFLAG_LAN_NEIGHS & *expected) {
301 while (length > value_len) {
302 lan_nei = (struct lan_neigh*)pnt;
303 if (!tlvs->lan_neighs) tlvs->lan_neighs = list_new ();
304 listnode_add (tlvs->lan_neighs, lan_nei);
305 value_len += ETH_ALEN;
306 pnt += ETH_ALEN;
307 }
308 } else {
309 pnt += length;
310 }
311 break;
312
313 case PADDING:
314#ifdef EXTREME_TLV_DEBUG
315 zlog_info ("TLV padding %d", length);
316#endif /* EXTREME_TLV_DEBUG */
317 pnt += length;
318 break;
319
320 case LSP_ENTRIES:
321 /* +-------+-------+-------+-------+-------+-------+-------+-------+
322 * | Remaining Lifetime | 2
323 * +-------+-------+-------+-------+-------+-------+-------+-------+
324 * | LSP ID | id+2
325 * +-------+-------+-------+-------+-------+-------+-------+-------+
326 * | LSP Sequence Number | 4
327 * +-------+-------+-------+-------+-------+-------+-------+-------+
328 * | Checksum | 2
329 * +-------+-------+-------+-------+-------+-------+-------+-------+
330 */
331#ifdef EXTREME_TLV_DEBUG
332 zlog_info ("LSP Entries length %d",
333 areatag,
334 length);
335#endif /* EXTREME_TLV_DEBUG */
336 *found |= TLVFLAG_LSP_ENTRIES;
337 if (TLVFLAG_LSP_ENTRIES & *expected) {
338 while (length > value_len) {
339 lsp_entry = (struct lsp_entry*)pnt;
340 value_len += 10 + ISIS_SYS_ID_LEN;
341 pnt += 10 + ISIS_SYS_ID_LEN;
342 if (!tlvs->lsp_entries) tlvs->lsp_entries = list_new ();
343 listnode_add (tlvs->lsp_entries, lsp_entry);
344 }
345 } else {
346 pnt += length;
347 }
348 break;
349
350 case CHECKSUM:
351 /* +-------+-------+-------+-------+-------+-------+-------+-------+
352 * | 16 bit fletcher CHECKSUM |
353 * +-------+-------+-------+-------+-------+-------+-------+-------+
354 * : :
355 */
356 *found |= TLVFLAG_CHECKSUM;
357#ifdef EXTREME_TLV_DEBUG
358 zlog_info ("ISIS-TLV (%s): Checksum length %d",
359 areatag,
360 length);
361#endif /* EXTREME_TLV_DEBUG */
362 if (*expected & TLVFLAG_CHECKSUM) {
363 tlvs->checksum = (struct checksum*)pnt;
364 }
365 pnt += length;
366 break;
367
368 case PROTOCOLS_SUPPORTED:
369 /* +-------+-------+-------+-------+-------+-------+-------+-------+
370 * | NLPID |
371 * +-------+-------+-------+-------+-------+-------+-------+-------+
372 * : :
373 */
374 *found |= TLVFLAG_NLPID;
375#ifdef EXTREME_TLV_DEBUG
376 zlog_info ("ISIS-TLV (%s): Protocols Supported length %d",
377 areatag,
378 length);
379#endif /* EXTREME_TLV_DEBUG */
380 if (*expected & TLVFLAG_NLPID) {
381 tlvs->nlpids = (struct nlpids*)(pnt-1);
382 }
383 pnt += length;
384 break;
385
386 case IPV4_ADDR:
387 /* +-------+-------+-------+-------+-------+-------+-------+-------+
388 * + IP version 4 address + 4
389 * +-------+-------+-------+-------+-------+-------+-------+-------+
390 * : :
391 */
392 *found |= TLVFLAG_IPV4_ADDR;
393#ifdef EXTREME_TLV_DEBUG
394 zlog_info ("ISIS-TLV (%s): IPv4 Address length %d",
395 areatag,
396 length);
397#endif /* EXTREME_TLV_DEBUG */
398 if (*expected & TLVFLAG_IPV4_ADDR) {
399 while (length > value_len) {
400 ipv4_addr = (struct in_addr*)pnt;
401 zlog_info ("ISIS-TLV (%s) : IP ADDR %s, pnt %p", areatag,
402 inet_ntoa (*ipv4_addr), pnt);
403 if (!tlvs->ipv4_addrs) tlvs->ipv4_addrs = list_new();
404 listnode_add (tlvs->ipv4_addrs, ipv4_addr);
405 value_len += 4;
406 pnt += 4;
407 }
408 } else {
409 pnt += length;
410 }
411 break;
412
413 case AUTH_INFO:
414 *found |= TLVFLAG_AUTH_INFO;
415#ifdef EXTREME_TLV_DEBUG
416 zlog_info ("ISIS-TLV (%s): IS-IS Authentication Information",
417 areatag);
418#endif
419 if (*expected & TLVFLAG_AUTH_INFO) {
420 tlvs->auth_info.type = *pnt;
421 pnt++;
422 memcpy (tlvs->auth_info.passwd, pnt, length - 1);
423 pnt += length - 1;
424 }
425 else {
426 pnt += length;
427 }
428 break;
429
430 case DYNAMIC_HOSTNAME:
431 *found |= TLVFLAG_DYN_HOSTNAME;
432#ifdef EXTREME_TLV_DEBUG
433 zlog_info ("ISIS-TLV (%s): Dynamic Hostname length %d",
434 areatag,
435 length);
436#endif /* EXTREME_TLV_DEBUG */
437 if (*expected & TLVFLAG_DYN_HOSTNAME) {
438 /* the length is also included in the pointed struct */
439 tlvs->hostname = (struct hostname*)(pnt - 1);
440 }
441 pnt += length;
442 break;
443
444 case TE_ROUTER_ID:
445 /* +---------------------------------------------------------------+
446 * + Router ID + 4
447 * +---------------------------------------------------------------+
448 */
449 *found |= TLVFLAG_TE_ROUTER_ID;
450#ifdef EXTREME_TLV_DEBUG
451 zlog_info ("ISIS-TLV (%s): TE Router ID %d",
452 areatag,
453 length);
454#endif /* EXTREME_TLV_DEBUG */
455 if (*expected & TLVFLAG_TE_ROUTER_ID) {
456 tlvs->router_id = (struct te_router_id*)(pnt);
457 }
458 pnt += length;
459 break;
460
461 case IPV4_INT_REACHABILITY:
462 /* +-------+-------+-------+-------+-------+-------+-------+-------+
463 * | 0 | I/E | Default Metric | 1
464 * +-------+-------+-------+-------+-------+-------+-------+-------+
465 * | S | I/E | Delay Metric | 1
466 * +-------+-------+-------+-------+-------+-------+-------+-------+
467 * | S | I/E | Expense Metric | 1
468 * +-------+-------+-------+-------+-------+-------+-------+-------+
469 * | S | I/E | Error Metric | 1
470 * +-------+-------+-------+-------+-------+-------+-------+-------+
471 * | ip address | 4
472 * +---------------------------------------------------------------+
473 * | address mask | 4
474 * +---------------------------------------------------------------+
475 * : :
476 */
477 *found |= TLVFLAG_IPV4_INT_REACHABILITY;
478#ifdef EXTREME_TLV_DEBUG
479 zlog_info ("ISIS-TLV (%s): IPv4 internal Reachability length %d",
480 areatag,
481 length);
482#endif /* EXTREME_TLV_DEBUG */
483 if (*expected & TLVFLAG_IPV4_INT_REACHABILITY) {
484 while (length > value_len) {
485 ipv4_reach = (struct ipv4_reachability*)pnt;
486 if (!tlvs->ipv4_int_reachs) tlvs->ipv4_int_reachs = list_new();
487 listnode_add (tlvs->ipv4_int_reachs, ipv4_reach);
488 value_len += 12;
489 pnt += 12;
490 }
491 }
492 else {
493 pnt += length;
494 }
495 break;
496
497 case IPV4_EXT_REACHABILITY:
498 /* +-------+-------+-------+-------+-------+-------+-------+-------+
499 * | 0 | I/E | Default Metric | 1
500 * +-------+-------+-------+-------+-------+-------+-------+-------+
501 * | S | I/E | Delay Metric | 1
502 * +-------+-------+-------+-------+-------+-------+-------+-------+
503 * | S | I/E | Expense Metric | 1
504 * +-------+-------+-------+-------+-------+-------+-------+-------+
505 * | S | I/E | Error Metric | 1
506 * +-------+-------+-------+-------+-------+-------+-------+-------+
507 * | ip address | 4
508 * +---------------------------------------------------------------+
509 * | address mask | 4
510 * +---------------------------------------------------------------+
511 * : :
512 */
hasso2097cd82003-12-23 11:51:08 +0000513 *found |= TLVFLAG_IPV4_EXT_REACHABILITY;
jardineb5d44e2003-12-23 08:09:43 +0000514#ifdef EXTREME_TLV_DEBUG
515 zlog_info ("ISIS-TLV (%s): IPv4 external Reachability length %d",
516 areatag,
517 length);
518#endif /* EXTREME_TLV_DEBUG */
hasso2097cd82003-12-23 11:51:08 +0000519 if (*expected & TLVFLAG_IPV4_EXT_REACHABILITY) {
jardineb5d44e2003-12-23 08:09:43 +0000520 while (length > value_len) {
521 ipv4_reach = (struct ipv4_reachability*)pnt;
hasso2097cd82003-12-23 11:51:08 +0000522 if (!tlvs->ipv4_ext_reachs)
523 tlvs->ipv4_ext_reachs = list_new();
jardineb5d44e2003-12-23 08:09:43 +0000524 listnode_add (tlvs->ipv4_ext_reachs, ipv4_reach);
525 value_len += 12;
526 pnt += 12;
527 }
528 }
529 else {
530 pnt += length;
531 }
532 break;
533
534 case TE_IPV4_REACHABILITY:
535 /* +-------+-------+-------+-------+-------+-------+-------+-------+
536 * | TE Metric | 4
537 * +-------+-------+-------+-------+-------+-------+-------+-------+
538 * | U/D | sTLV? | Prefix Mask Len | 1
539 * +-------+-------+-------+-------+-------+-------+-------+-------+
540 * | Prefix | 0-4
541 * +---------------------------------------------------------------+
542 * | sub tlvs |
543 * +---------------------------------------------------------------+
544 * : :
545 */
546 *found |= TLVFLAG_TE_IPV4_REACHABILITY;
547#ifdef EXTREME_TLV_DEBUG
548 zlog_info ("ISIS-TLV (%s): IPv4 extended Reachability length %d",
549 areatag,
550 length);
551#endif /* EXTREME_TLV_DEBUG */
552 if (*expected & TLVFLAG_TE_IPV4_REACHABILITY) {
553 while (length > value_len) {
554 te_ipv4_reach = (struct te_ipv4_reachability*)pnt;
555 if (!tlvs->te_ipv4_reachs) tlvs->te_ipv4_reachs = list_new();
556 listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach);
557 /* this trickery is permitable since no subtlvs are defined */
558 value_len += 5 + ((te_ipv4_reach->control & 0x3F) ?
559 ((((te_ipv4_reach->control & 0x3F)-1)>>3)+1) : 0);
560 pnt += 5 + ((te_ipv4_reach->control & 0x3F) ?
561 ((((te_ipv4_reach->control & 0x3F)-1)>>3)+1) : 0);
562 }
563 }
564 else {
565 pnt += length;
566 }
567 break;
568
569#ifdef HAVE_IPV6
570 case IPV6_ADDR:
571 /* +-------+-------+-------+-------+-------+-------+-------+-------+
572 * + IP version 6 address + 16
573 * +-------+-------+-------+-------+-------+-------+-------+-------+
574 * : :
575 */
576 *found |= TLVFLAG_IPV6_ADDR;
577#ifdef EXTREME_TLV_DEBUG
578 zlog_info ("ISIS-TLV (%s): IPv6 Address length %d",
579 areatag,
580 length);
581#endif /* EXTREME_TLV_DEBUG */
582 if (*expected & TLVFLAG_IPV6_ADDR) {
583 while (length > value_len) {
584 ipv6_addr = (struct in6_addr*)pnt;
585 if (!tlvs->ipv6_addrs) tlvs->ipv6_addrs = list_new();
586 listnode_add (tlvs->ipv6_addrs, ipv6_addr);
587 value_len += 16;
588 pnt += 16;
589 }
590 } else {
591 pnt += length;
592 }
593 break;
594
595 case IPV6_REACHABILITY:
596 /* +-------+-------+-------+-------+-------+-------+-------+-------+
597 * | Default Metric | 4
598 * +-------+-------+-------+-------+-------+-------+-------+-------+
599 * | Control Informantion |
600 * +---------------------------------------------------------------+
601 * | IPv6 Prefix Length |--+
602 * +---------------------------------------------------------------+ |
603 * | IPv6 Prefix |<-+
604 * +---------------------------------------------------------------+
605 */
606 *found |= TLVFLAG_IPV6_REACHABILITY;
607 if (*expected & TLVFLAG_IPV6_REACHABILITY) {
608 while (length > value_len) {
609 ipv6_reach = (struct ipv6_reachability*)pnt;
610 prefix_octets = ((ipv6_reach->prefix_len + 7) / 8);
611 value_len += prefix_octets + 6;
612 pnt += prefix_octets + 6;
613 /* FIXME: sub-tlvs */
614 if (!tlvs->ipv6_reachs) tlvs->ipv6_reachs = list_new();
615 listnode_add (tlvs->ipv6_reachs, ipv6_reach);
616 }
617 } else {
618 pnt += length;
619 }
620 break;
621#endif /* HAVE_IPV6 */
622
623 case WAY3_HELLO:
624 /* +---------------------------------------------------------------+
625 * | Adjacency state | 1
626 * +---------------------------------------------------------------+
627 * | Extended Local Circuit ID | 4
628 * +---------------------------------------------------------------+
629 * | Neighbor System ID (If known) | 0-8
630 * (probably 6)
631 * +---------------------------------------------------------------+
632 * | Neighbor Local Circuit ID (If known) | 4
633 * +---------------------------------------------------------------+
634 */
635 *found |= TLVFLAG_3WAY_HELLO;
636 if (*expected & TLVFLAG_3WAY_HELLO) {
637 while (length > value_len) {
638 /* FIXME: make this work */
639/* Adjacency State (one octet):
640 0 = Up
641 1 = Initializing
642 2 = Down
643 Extended Local Circuit ID (four octets)
644 Neighbor System ID if known (zero to eight octets)
645 Neighbor Extended Local Circuit ID (four octets, if Neighbor
646 System ID is present) */
647 pnt += length;
648 }
649 } else {
650 pnt += length;
651 }
652
653 break;
hasso00995cf2004-05-19 13:43:50 +0000654 case GRACEFUL_RESTART:
655 /* +-------+-------+-------+-------+-------+-------+-------+-------+
656 * | Reserved | SA | RA | RR | 1
657 * +-------+-------+-------+-------+-------+-------+-------+-------+
658 * | Remaining Time | 2
659 * +---------------------------------------------------------------+
660 * | Restarting Neighbor ID (If known) | 0-8
661 * +---------------------------------------------------------------+
662 */
663 *found |= TLVFLAG_GRACEFUL_RESTART;
664 if (*expected & TLVFLAG_GRACEFUL_RESTART) {
665 /* FIXME: make this work */
666 }
667 pnt += length;
668 break;
jardineb5d44e2003-12-23 08:09:43 +0000669
670 default:
671 zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
672 areatag,
673 type,
674 length);
675
676 retval = ISIS_WARNING;
677 pnt += length;
678 break;
679 }
680 }
681
682 return retval;
683}
684
685int
686add_tlv (u_char tag, u_char len, u_char *value, struct stream *stream)
687{
688
689 if (STREAM_SIZE (stream) - stream_get_putp (stream) < len + 2) {
690 zlog_warn ("No room for TLV of type %d", tag);
691 return ISIS_WARNING;
692 }
693
694 stream_putc (stream, tag); /* TAG */
695 stream_putc (stream, len); /* LENGTH */
696 stream_put (stream, value, (int)len); /* VALUE */
697
698#ifdef EXTREME_DEBUG
699 zlog_info ("Added TLV %d len %d", tag, len);
700#endif /* EXTREME DEBUG */
701 return ISIS_OK;
702}
703
704
705int
706tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
707{
708 struct listnode *node;
709 struct area_addr *area_addr;
710
711 u_char value [255];
712 u_char *pos = value;
713
714 for (node = listhead (area_addrs); node; nextnode (node)) {
715 area_addr = getdata (node);
716 if (pos - value + area_addr->addr_len > 255)
717 goto err;
718 *pos = area_addr->addr_len;
719 pos ++;
720 memcpy (pos, area_addr->area_addr, (int)area_addr->addr_len);
721 pos += area_addr->addr_len;
722 }
723
724 return add_tlv (AREA_ADDRESSES, pos - value, value, stream);
725
726 err:
727 zlog_warn ("tlv_add_area_addrs(): TLV longer than 255");
728 return ISIS_WARNING;
729}
730
731int tlv_add_is_neighs (struct list *is_neighs, struct stream *stream)
732{
733 struct listnode *node;
734 struct is_neigh *is_neigh;
735 u_char value [255];
736 u_char *pos = value;
737 int retval;
738
739 *pos = 0; /*is_neigh->virtual; */
740 pos ++;
741
742 for (node = listhead (is_neighs); node; nextnode (node)) {
743 is_neigh = getdata (node);
744 if (pos - value + IS_NEIGHBOURS_LEN > 255) {
745 retval = add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
746 if (retval != ISIS_OK)
747 return retval;
748 pos = value;
749 }
750 *pos = is_neigh->metrics.metric_default;
751 pos ++;
752 *pos = is_neigh->metrics.metric_delay;
753 pos ++;
754 *pos = is_neigh->metrics.metric_expense;
755 pos ++;
756 *pos = is_neigh->metrics.metric_error;
757 pos ++;
758 memcpy (pos, is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
759 pos += ISIS_SYS_ID_LEN + 1;
760 }
761
762 return add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
763}
764
765
766int
767tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream)
768{
769 struct listnode *node;
770 u_char *snpa;
771 u_char value [255];
772 u_char *pos = value;
773 int retval;
774
775 for (node = listhead (lan_neighs); node; nextnode (node)) {
776 snpa = getdata (node);
777 if (pos - value + ETH_ALEN > 255) {
778 retval = add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
779 if (retval != ISIS_OK)
780 return retval;
781 pos = value;
782 }
783 memcpy (pos, snpa, ETH_ALEN);
784 pos += ETH_ALEN;
785 }
786
787 return add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
788}
789
790
791/*
792 u_char value[255];
793 u_char *pos = value;
794
795 if (circuit->ip_router) {
796 *pos = (u_char)NLPID_IP;
797 pos ++;
798 }
799 if (circuit->ipv6_router) {
800 *pos = (u_char)NLPID_IPV6;
801 pos ++;
802 }
803*/
804
805int
806tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream)
807{
808
809 return add_tlv (PROTOCOLS_SUPPORTED, nlpids->count,
810 nlpids->nlpids, stream);
811}
812
813int tlv_add_authinfo (char auth_type, char auth_len, char *auth_value,
814 struct stream *stream)
815{
816 u_char value[255];
817 u_char *pos = value;
818 pos++;
819 memcpy (pos, auth_value, auth_len);
820
821 return add_tlv (AUTH_INFO, auth_len + 1, value, stream);
822}
823
824int
825tlv_add_checksum (struct checksum *checksum, struct stream *stream)
826{
827 u_char value[255];
828 u_char *pos = value;
829 return add_tlv (CHECKSUM, pos - value,
830 value, stream);
831}
832
833int
834tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream)
835{
836 struct listnode *node;
837 struct prefix_ipv4 *ipv4;
838 u_char value[255];
839 u_char *pos = value;
840 int retval;
841
842 for (node = listhead (ip_addrs); node; nextnode (node)) {
843 ipv4 = getdata (node);
844 if (pos - value + IPV4_MAX_BYTELEN > 255) {
845 retval = add_tlv (IPV4_ADDR, pos - value, value, stream);
846 if (retval != ISIS_OK)
847 return retval;
848 pos = value;
849 }
850 *(u_int32_t*)pos = ipv4->prefix.s_addr;
851 pos += IPV4_MAX_BYTELEN;
852 }
853
854 return add_tlv (IPV4_ADDR, pos - value, value, stream);
855}
856
857int
858tlv_add_dynamic_hostname (struct hostname *hostname, struct stream *stream)
859{
860 return add_tlv (DYNAMIC_HOSTNAME, hostname->namelen, hostname->name, stream);
861}
862
863int
864tlv_add_lsp_entries (struct list *lsps, struct stream *stream)
865{
866 struct listnode *node;
867 struct isis_lsp *lsp;
868 u_char value [255];
869 u_char *pos = value;
870 int retval;
871
872 for (node = listhead (lsps); node; nextnode (node)) {
873 lsp = getdata (node);
874 if (pos - value + LSP_ENTRIES_LEN > 255) {
875 retval = add_tlv (LSP_ENTRIES, pos - value, value, stream);
876 if (retval != ISIS_OK)
877 return retval;
878 pos = value;
879 }
880 *((u_int16_t*)pos) = lsp->lsp_header->rem_lifetime;
881 pos += 2;
882 memcpy (pos, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
883 pos += ISIS_SYS_ID_LEN + 2;
884 *((u_int32_t*)pos) = lsp->lsp_header->seq_num;
885 pos += 4;
886 *((u_int16_t*)pos) = lsp->lsp_header->checksum;
887 pos += 2;
888 }
889
890 return add_tlv (LSP_ENTRIES, pos - value, value, stream);
891}
892
893int
894tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream)
895{
896 struct listnode *node;
897 struct ipv4_reachability *reach;
898 u_char value [255];
899 u_char *pos = value;
900 int retval;
901
902 for (node = listhead (ipv4_reachs); node; nextnode (node)) {
903 reach = getdata (node);
904 if (pos - value + IPV4_REACH_LEN > 255) {
905 retval = add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
906 if (retval != ISIS_OK)
907 return retval;
908 pos = value;
909 }
910 *pos = reach->metrics.metric_default;
911 pos ++;
912 *pos = reach->metrics.metric_delay;
913 pos ++;
914 *pos = reach->metrics.metric_expense;
915 pos ++;
916 *pos = reach->metrics.metric_error;
917 pos ++;
918 *(u_int32_t*)pos = reach->prefix.s_addr;
919 pos += IPV4_MAX_BYTELEN;
920 *(u_int32_t*)pos = reach->mask.s_addr;
921 pos += IPV4_MAX_BYTELEN;
922 }
923
924
925 return add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
926}
927
928#ifdef HAVE_IPV6
929int
930tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream)
931{
932 struct listnode *node;
933 struct prefix_ipv6 *ipv6;
934 u_char value[255];
935 u_char *pos = value;
936 int retval;
937
938 for (node = listhead (ipv6_addrs); node; nextnode (node)) {
939 ipv6 = getdata (node);
940 if (pos - value + IPV6_MAX_BYTELEN > 255) {
941 retval = add_tlv (IPV6_ADDR, pos - value, value, stream);
942 if (retval != ISIS_OK)
943 return retval;
944 pos = value;
945 }
946 memcpy (pos, ipv6->prefix.s6_addr, IPV6_MAX_BYTELEN);
947 pos += IPV6_MAX_BYTELEN;
948 }
949
950 return add_tlv (IPV6_ADDR, pos - value, value, stream);
951}
952
953int
954tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream)
955{
956 struct listnode *node;
957 struct ipv6_reachability *ip6reach;
958 u_char value[255];
959 u_char *pos = value;
960 int retval, prefix_octets;
961
962 for (node = listhead (ipv6_reachs); node; nextnode (node)) {
963 ip6reach = getdata (node);
964 if (pos - value + IPV6_MAX_BYTELEN + 6 > 255) {
965 retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
966 if (retval != ISIS_OK)
967 return retval;
968 pos = value;
969 }
970 *(uint32_t*)pos = ip6reach->metric;
971 pos += 4;
972 *pos = ip6reach->control_info;
973 pos++;
974 prefix_octets = ((ip6reach->prefix_len + 7) / 8);
975 *pos = ip6reach->prefix_len;
976 pos++;
977 memcpy (pos, ip6reach->prefix, prefix_octets);
978 pos += prefix_octets;
979 }
980
981 return add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
982}
983#endif /* HAVE_IPV6 */
984
985int
986tlv_add_padding (struct stream *stream)
987{
988 unsigned long putp, endp;
989 int fullpads, i, left;
990
991 /*
992 * How many times can we add full padding ?
993 */
994 fullpads = (STREAM_SIZE(stream) - stream_get_endp (stream)) / 257;
995 for (i = 0; i < fullpads; i ++) {
996 if (!stream_putc (stream, (u_char)PADDING)) /* TAG */
997 goto err;
998 if (!stream_putc (stream, (u_char)255)) /* LENGHT */
999 goto err;
1000 endp = stream_get_endp (stream);
1001 putp = stream_get_putp (stream);
1002 if (putp != endp)
1003 zlog_warn ("tvl_add_padding endp %ld while putp %ld", endp, putp);
1004 stream_set_putp (stream, putp + 255); /* VALUE */
1005 stream->endp = stream->putp;
1006 }
1007
1008 left = STREAM_SIZE(stream) - stream_get_putp (stream);
1009
1010 if (left < 2)
1011 return ISIS_OK;
1012
1013 if (left == 2) {
1014 stream_putc (stream, PADDING);
1015 stream_putc (stream, 0);
1016 return ISIS_OK;
1017 }
1018
1019 stream_putc (stream, PADDING);
1020 stream_putc (stream, left - 2);
1021 stream_set_putp (stream, stream_get_putp (stream) + left - 2);
1022 stream->endp = stream->putp;
1023
1024 return ISIS_OK;
1025
1026 err:
1027 zlog_warn ("tlv_add_padding(): no room for tlv");
1028 return ISIS_WARNING;
1029}