blob: b51cee91cf84bc0979f1e7f827beb2d5cab48e47 [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 */
514 *found |= TLVFLAG_TE_IPV4_REACHABILITY;
515#ifdef EXTREME_TLV_DEBUG
516 zlog_info ("ISIS-TLV (%s): IPv4 external Reachability length %d",
517 areatag,
518 length);
519#endif /* EXTREME_TLV_DEBUG */
520 if (*expected & TLVFLAG_TE_IPV4_REACHABILITY) {
521 while (length > value_len) {
522 ipv4_reach = (struct ipv4_reachability*)pnt;
523 if (!tlvs->ipv4_ext_reachs) tlvs->ipv4_ext_reachs = list_new();
524 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;
654
655 default:
656 zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
657 areatag,
658 type,
659 length);
660
661 retval = ISIS_WARNING;
662 pnt += length;
663 break;
664 }
665 }
666
667 return retval;
668}
669
670int
671add_tlv (u_char tag, u_char len, u_char *value, struct stream *stream)
672{
673
674 if (STREAM_SIZE (stream) - stream_get_putp (stream) < len + 2) {
675 zlog_warn ("No room for TLV of type %d", tag);
676 return ISIS_WARNING;
677 }
678
679 stream_putc (stream, tag); /* TAG */
680 stream_putc (stream, len); /* LENGTH */
681 stream_put (stream, value, (int)len); /* VALUE */
682
683#ifdef EXTREME_DEBUG
684 zlog_info ("Added TLV %d len %d", tag, len);
685#endif /* EXTREME DEBUG */
686 return ISIS_OK;
687}
688
689
690int
691tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
692{
693 struct listnode *node;
694 struct area_addr *area_addr;
695
696 u_char value [255];
697 u_char *pos = value;
698
699 for (node = listhead (area_addrs); node; nextnode (node)) {
700 area_addr = getdata (node);
701 if (pos - value + area_addr->addr_len > 255)
702 goto err;
703 *pos = area_addr->addr_len;
704 pos ++;
705 memcpy (pos, area_addr->area_addr, (int)area_addr->addr_len);
706 pos += area_addr->addr_len;
707 }
708
709 return add_tlv (AREA_ADDRESSES, pos - value, value, stream);
710
711 err:
712 zlog_warn ("tlv_add_area_addrs(): TLV longer than 255");
713 return ISIS_WARNING;
714}
715
716int tlv_add_is_neighs (struct list *is_neighs, struct stream *stream)
717{
718 struct listnode *node;
719 struct is_neigh *is_neigh;
720 u_char value [255];
721 u_char *pos = value;
722 int retval;
723
724 *pos = 0; /*is_neigh->virtual; */
725 pos ++;
726
727 for (node = listhead (is_neighs); node; nextnode (node)) {
728 is_neigh = getdata (node);
729 if (pos - value + IS_NEIGHBOURS_LEN > 255) {
730 retval = add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
731 if (retval != ISIS_OK)
732 return retval;
733 pos = value;
734 }
735 *pos = is_neigh->metrics.metric_default;
736 pos ++;
737 *pos = is_neigh->metrics.metric_delay;
738 pos ++;
739 *pos = is_neigh->metrics.metric_expense;
740 pos ++;
741 *pos = is_neigh->metrics.metric_error;
742 pos ++;
743 memcpy (pos, is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
744 pos += ISIS_SYS_ID_LEN + 1;
745 }
746
747 return add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
748}
749
750
751int
752tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream)
753{
754 struct listnode *node;
755 u_char *snpa;
756 u_char value [255];
757 u_char *pos = value;
758 int retval;
759
760 for (node = listhead (lan_neighs); node; nextnode (node)) {
761 snpa = getdata (node);
762 if (pos - value + ETH_ALEN > 255) {
763 retval = add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
764 if (retval != ISIS_OK)
765 return retval;
766 pos = value;
767 }
768 memcpy (pos, snpa, ETH_ALEN);
769 pos += ETH_ALEN;
770 }
771
772 return add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
773}
774
775
776/*
777 u_char value[255];
778 u_char *pos = value;
779
780 if (circuit->ip_router) {
781 *pos = (u_char)NLPID_IP;
782 pos ++;
783 }
784 if (circuit->ipv6_router) {
785 *pos = (u_char)NLPID_IPV6;
786 pos ++;
787 }
788*/
789
790int
791tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream)
792{
793
794 return add_tlv (PROTOCOLS_SUPPORTED, nlpids->count,
795 nlpids->nlpids, stream);
796}
797
798int tlv_add_authinfo (char auth_type, char auth_len, char *auth_value,
799 struct stream *stream)
800{
801 u_char value[255];
802 u_char *pos = value;
803 pos++;
804 memcpy (pos, auth_value, auth_len);
805
806 return add_tlv (AUTH_INFO, auth_len + 1, value, stream);
807}
808
809int
810tlv_add_checksum (struct checksum *checksum, struct stream *stream)
811{
812 u_char value[255];
813 u_char *pos = value;
814 return add_tlv (CHECKSUM, pos - value,
815 value, stream);
816}
817
818int
819tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream)
820{
821 struct listnode *node;
822 struct prefix_ipv4 *ipv4;
823 u_char value[255];
824 u_char *pos = value;
825 int retval;
826
827 for (node = listhead (ip_addrs); node; nextnode (node)) {
828 ipv4 = getdata (node);
829 if (pos - value + IPV4_MAX_BYTELEN > 255) {
830 retval = add_tlv (IPV4_ADDR, pos - value, value, stream);
831 if (retval != ISIS_OK)
832 return retval;
833 pos = value;
834 }
835 *(u_int32_t*)pos = ipv4->prefix.s_addr;
836 pos += IPV4_MAX_BYTELEN;
837 }
838
839 return add_tlv (IPV4_ADDR, pos - value, value, stream);
840}
841
842int
843tlv_add_dynamic_hostname (struct hostname *hostname, struct stream *stream)
844{
845 return add_tlv (DYNAMIC_HOSTNAME, hostname->namelen, hostname->name, stream);
846}
847
848int
849tlv_add_lsp_entries (struct list *lsps, struct stream *stream)
850{
851 struct listnode *node;
852 struct isis_lsp *lsp;
853 u_char value [255];
854 u_char *pos = value;
855 int retval;
856
857 for (node = listhead (lsps); node; nextnode (node)) {
858 lsp = getdata (node);
859 if (pos - value + LSP_ENTRIES_LEN > 255) {
860 retval = add_tlv (LSP_ENTRIES, pos - value, value, stream);
861 if (retval != ISIS_OK)
862 return retval;
863 pos = value;
864 }
865 *((u_int16_t*)pos) = lsp->lsp_header->rem_lifetime;
866 pos += 2;
867 memcpy (pos, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
868 pos += ISIS_SYS_ID_LEN + 2;
869 *((u_int32_t*)pos) = lsp->lsp_header->seq_num;
870 pos += 4;
871 *((u_int16_t*)pos) = lsp->lsp_header->checksum;
872 pos += 2;
873 }
874
875 return add_tlv (LSP_ENTRIES, pos - value, value, stream);
876}
877
878int
879tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream)
880{
881 struct listnode *node;
882 struct ipv4_reachability *reach;
883 u_char value [255];
884 u_char *pos = value;
885 int retval;
886
887 for (node = listhead (ipv4_reachs); node; nextnode (node)) {
888 reach = getdata (node);
889 if (pos - value + IPV4_REACH_LEN > 255) {
890 retval = add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
891 if (retval != ISIS_OK)
892 return retval;
893 pos = value;
894 }
895 *pos = reach->metrics.metric_default;
896 pos ++;
897 *pos = reach->metrics.metric_delay;
898 pos ++;
899 *pos = reach->metrics.metric_expense;
900 pos ++;
901 *pos = reach->metrics.metric_error;
902 pos ++;
903 *(u_int32_t*)pos = reach->prefix.s_addr;
904 pos += IPV4_MAX_BYTELEN;
905 *(u_int32_t*)pos = reach->mask.s_addr;
906 pos += IPV4_MAX_BYTELEN;
907 }
908
909
910 return add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
911}
912
913#ifdef HAVE_IPV6
914int
915tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream)
916{
917 struct listnode *node;
918 struct prefix_ipv6 *ipv6;
919 u_char value[255];
920 u_char *pos = value;
921 int retval;
922
923 for (node = listhead (ipv6_addrs); node; nextnode (node)) {
924 ipv6 = getdata (node);
925 if (pos - value + IPV6_MAX_BYTELEN > 255) {
926 retval = add_tlv (IPV6_ADDR, pos - value, value, stream);
927 if (retval != ISIS_OK)
928 return retval;
929 pos = value;
930 }
931 memcpy (pos, ipv6->prefix.s6_addr, IPV6_MAX_BYTELEN);
932 pos += IPV6_MAX_BYTELEN;
933 }
934
935 return add_tlv (IPV6_ADDR, pos - value, value, stream);
936}
937
938int
939tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream)
940{
941 struct listnode *node;
942 struct ipv6_reachability *ip6reach;
943 u_char value[255];
944 u_char *pos = value;
945 int retval, prefix_octets;
946
947 for (node = listhead (ipv6_reachs); node; nextnode (node)) {
948 ip6reach = getdata (node);
949 if (pos - value + IPV6_MAX_BYTELEN + 6 > 255) {
950 retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
951 if (retval != ISIS_OK)
952 return retval;
953 pos = value;
954 }
955 *(uint32_t*)pos = ip6reach->metric;
956 pos += 4;
957 *pos = ip6reach->control_info;
958 pos++;
959 prefix_octets = ((ip6reach->prefix_len + 7) / 8);
960 *pos = ip6reach->prefix_len;
961 pos++;
962 memcpy (pos, ip6reach->prefix, prefix_octets);
963 pos += prefix_octets;
964 }
965
966 return add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
967}
968#endif /* HAVE_IPV6 */
969
970int
971tlv_add_padding (struct stream *stream)
972{
973 unsigned long putp, endp;
974 int fullpads, i, left;
975
976 /*
977 * How many times can we add full padding ?
978 */
979 fullpads = (STREAM_SIZE(stream) - stream_get_endp (stream)) / 257;
980 for (i = 0; i < fullpads; i ++) {
981 if (!stream_putc (stream, (u_char)PADDING)) /* TAG */
982 goto err;
983 if (!stream_putc (stream, (u_char)255)) /* LENGHT */
984 goto err;
985 endp = stream_get_endp (stream);
986 putp = stream_get_putp (stream);
987 if (putp != endp)
988 zlog_warn ("tvl_add_padding endp %ld while putp %ld", endp, putp);
989 stream_set_putp (stream, putp + 255); /* VALUE */
990 stream->endp = stream->putp;
991 }
992
993 left = STREAM_SIZE(stream) - stream_get_putp (stream);
994
995 if (left < 2)
996 return ISIS_OK;
997
998 if (left == 2) {
999 stream_putc (stream, PADDING);
1000 stream_putc (stream, 0);
1001 return ISIS_OK;
1002 }
1003
1004 stream_putc (stream, PADDING);
1005 stream_putc (stream, left - 2);
1006 stream_set_putp (stream, stream_get_putp (stream) + left - 2);
1007 stream->endp = stream->putp;
1008
1009 return ISIS_OK;
1010
1011 err:
1012 zlog_warn ("tlv_add_padding(): no room for tlv");
1013 return ISIS_WARNING;
1014}