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