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