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