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