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