]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_tlv.c
Switch to using syslog for logging as the default
[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; see the file COPYING; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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 #include "isisd/isis_mt.h"
47
48 void 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 free_tlvs(struct tlvs *tlvs)
60 {
61 if (tlvs->area_addrs)
62 list_delete(tlvs->area_addrs);
63 if (tlvs->mt_router_info)
64 list_delete(tlvs->mt_router_info);
65 if (tlvs->is_neighs)
66 list_delete(tlvs->is_neighs);
67 if (tlvs->te_is_neighs)
68 list_delete(tlvs->te_is_neighs);
69 if (tlvs->mt_is_neighs)
70 list_delete(tlvs->mt_is_neighs);
71 if (tlvs->es_neighs)
72 list_delete(tlvs->es_neighs);
73 if (tlvs->lsp_entries)
74 list_delete(tlvs->lsp_entries);
75 if (tlvs->prefix_neighs)
76 list_delete(tlvs->prefix_neighs);
77 if (tlvs->lan_neighs)
78 list_delete(tlvs->lan_neighs);
79 if (tlvs->ipv4_addrs)
80 list_delete(tlvs->ipv4_addrs);
81 if (tlvs->ipv4_int_reachs)
82 list_delete(tlvs->ipv4_int_reachs);
83 if (tlvs->ipv4_ext_reachs)
84 list_delete(tlvs->ipv4_ext_reachs);
85 if (tlvs->te_ipv4_reachs)
86 list_delete(tlvs->te_ipv4_reachs);
87 if (tlvs->mt_ipv4_reachs)
88 list_delete(tlvs->mt_ipv4_reachs);
89 if (tlvs->ipv6_addrs)
90 list_delete(tlvs->ipv6_addrs);
91 if (tlvs->ipv6_reachs)
92 list_delete(tlvs->ipv6_reachs);
93 if (tlvs->mt_ipv6_reachs)
94 list_delete(tlvs->mt_ipv6_reachs);
95
96 memset(tlvs, 0, sizeof(struct tlvs));
97
98 return;
99 }
100
101 static int parse_mtid(uint16_t *mtid, bool read_mtid, unsigned int *length,
102 u_char **pnt)
103 {
104 if (!read_mtid) {
105 *mtid = ISIS_MT_IPV4_UNICAST;
106 return ISIS_OK;
107 }
108
109 uint16_t mtid_buf;
110
111 if (*length < sizeof(mtid_buf)) {
112 zlog_warn("ISIS-TLV: mt tlv too short to contain MT id");
113 return ISIS_WARNING;
114 }
115
116 memcpy(&mtid_buf, *pnt, sizeof(mtid_buf));
117 *pnt += sizeof(mtid_buf);
118 *length -= sizeof(mtid_buf);
119
120 *mtid = ntohs(mtid_buf) & ISIS_MT_MASK;
121 return ISIS_OK;
122 }
123
124 static int parse_mt_is_neighs(struct tlvs *tlvs, bool read_mtid,
125 unsigned int length, u_char *pnt)
126 {
127 struct list *neigh_list;
128 uint16_t mtid;
129 int rv;
130
131 rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
132 if (rv != ISIS_OK)
133 return rv;
134
135 if (mtid == ISIS_MT_IPV4_UNICAST) {
136 if (!tlvs->te_is_neighs) {
137 tlvs->te_is_neighs = list_new();
138 tlvs->te_is_neighs->del = free_tlv;
139 }
140 neigh_list = tlvs->te_is_neighs;
141 } else {
142 struct tlv_mt_neighbors *neighbors;
143
144 neighbors = tlvs_get_mt_neighbors(tlvs, mtid);
145 neighbors->list->del = free_tlv;
146 neigh_list = neighbors->list;
147 }
148
149 while (length >= IS_NEIGHBOURS_LEN) {
150 struct te_is_neigh *neigh =
151 XCALLOC(MTYPE_ISIS_TLV, sizeof(*neigh));
152
153 memcpy(neigh, pnt, IS_NEIGHBOURS_LEN);
154 pnt += IS_NEIGHBOURS_LEN;
155 length -= IS_NEIGHBOURS_LEN;
156
157 if (neigh->sub_tlvs_length > length) {
158 zlog_warn(
159 "ISIS-TLV: neighbor subtlv length exceeds TLV size");
160 XFREE(MTYPE_ISIS_TLV, neigh);
161 return ISIS_WARNING;
162 }
163
164 memcpy(neigh->sub_tlvs, pnt, neigh->sub_tlvs_length);
165 pnt += neigh->sub_tlvs_length;
166 length -= neigh->sub_tlvs_length;
167
168 listnode_add(neigh_list, neigh);
169 }
170
171 if (length) {
172 zlog_warn("ISIS-TLV: TE/MT neighor TLV has trailing data");
173 return ISIS_WARNING;
174 }
175
176 return ISIS_OK;
177 }
178
179 static int parse_mt_ipv4_reachs(struct tlvs *tlvs, bool read_mtid,
180 unsigned int length, u_char *pnt)
181 {
182 struct list *reach_list;
183 uint16_t mtid;
184 int rv;
185
186 rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
187 if (rv != ISIS_OK)
188 return rv;
189
190 if (mtid == ISIS_MT_IPV4_UNICAST) {
191 if (!tlvs->te_ipv4_reachs) {
192 tlvs->te_ipv4_reachs = list_new();
193 tlvs->te_ipv4_reachs->del = free_tlv;
194 }
195 reach_list = tlvs->te_ipv4_reachs;
196 } else {
197 struct tlv_mt_ipv4_reachs *reachs;
198
199 reachs = tlvs_get_mt_ipv4_reachs(tlvs, mtid);
200 reachs->list->del = free_tlv;
201 reach_list = reachs->list;
202 }
203
204 while (length >= 5) /* Metric + Control */
205 {
206 struct te_ipv4_reachability *reach =
207 XCALLOC(MTYPE_ISIS_TLV, TE_IPV4_REACH_LEN);
208
209 memcpy(reach, pnt, 5); /* Metric + Control */
210 pnt += 5;
211 length -= 5;
212
213 unsigned char prefixlen = reach->control & 0x3F;
214
215 if (prefixlen > IPV4_MAX_BITLEN) {
216 zlog_warn(
217 "ISIS-TLV: invalid IPv4 extended reachability prefix length %d",
218 prefixlen);
219 XFREE(MTYPE_ISIS_TLV, reach);
220 return ISIS_WARNING;
221 }
222
223 if (length < (unsigned int)PSIZE(prefixlen)) {
224 zlog_warn(
225 "ISIS-TLV: invalid IPv4 extended reachability prefix too long for tlv");
226 XFREE(MTYPE_ISIS_TLV, reach);
227 return ISIS_WARNING;
228 }
229
230 memcpy(&reach->prefix_start, pnt, PSIZE(prefixlen));
231 pnt += PSIZE(prefixlen);
232 length -= PSIZE(prefixlen);
233
234 if (reach->control & TE_IPV4_HAS_SUBTLV) {
235 if (length < 1) {
236 zlog_warn(
237 "ISIS-TLV: invalid IPv4 extended reachability SubTLV missing");
238 XFREE(MTYPE_ISIS_TLV, reach);
239 return ISIS_WARNING;
240 }
241
242 u_char subtlv_len = *pnt;
243 pnt++;
244 length--;
245
246 if (length < subtlv_len) {
247 zlog_warn(
248 "ISIS-TLV: invalid IPv4 extended reachability SubTLVs have oversize");
249 XFREE(MTYPE_ISIS_TLV, reach);
250 return ISIS_WARNING;
251 }
252
253 /* Skip Sub-TLVs for now */
254 pnt += subtlv_len;
255 length -= subtlv_len;
256 }
257 listnode_add(reach_list, reach);
258 }
259
260 if (length) {
261 zlog_warn(
262 "ISIS-TLV: TE/MT ipv4 reachability TLV has trailing data");
263 return ISIS_WARNING;
264 }
265
266 return ISIS_OK;
267 }
268
269 static int parse_mt_ipv6_reachs(struct tlvs *tlvs, bool read_mtid,
270 unsigned int length, u_char *pnt)
271 {
272 struct list *reach_list;
273 uint16_t mtid;
274 int rv;
275
276 rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
277 if (rv != ISIS_OK)
278 return rv;
279
280 if (mtid == ISIS_MT_IPV4_UNICAST) {
281 if (!tlvs->ipv6_reachs) {
282 tlvs->ipv6_reachs = list_new();
283 tlvs->ipv6_reachs->del = free_tlv;
284 }
285 reach_list = tlvs->ipv6_reachs;
286 } else {
287 struct tlv_mt_ipv6_reachs *reachs;
288
289 reachs = tlvs_get_mt_ipv6_reachs(tlvs, mtid);
290 reachs->list->del = free_tlv;
291 reach_list = reachs->list;
292 }
293
294 while (length >= 6) /* Metric + Control + Prefixlen */
295 {
296 struct ipv6_reachability *reach =
297 XCALLOC(MTYPE_ISIS_TLV, sizeof(*reach));
298
299 memcpy(reach, pnt, 6); /* Metric + Control + Prefixlen */
300 pnt += 6;
301 length -= 6;
302
303 if (reach->prefix_len > IPV6_MAX_BITLEN) {
304 zlog_warn(
305 "ISIS-TLV: invalid IPv6 reachability prefix length %d",
306 reach->prefix_len);
307 XFREE(MTYPE_ISIS_TLV, reach);
308 return ISIS_WARNING;
309 }
310
311 if (length < (unsigned int)PSIZE(reach->prefix_len)) {
312 zlog_warn(
313 "ISIS-TLV: invalid IPv6 reachability prefix too long for tlv");
314 XFREE(MTYPE_ISIS_TLV, reach);
315 return ISIS_WARNING;
316 }
317
318 memcpy(&reach->prefix, pnt, PSIZE(reach->prefix_len));
319 pnt += PSIZE(reach->prefix_len);
320 length -= PSIZE(reach->prefix_len);
321
322 if (reach->control_info & CTRL_INFO_SUBTLVS) {
323 if (length < 1) {
324 zlog_warn(
325 "ISIS-TLV: invalid IPv6 reachability SubTLV missing");
326 XFREE(MTYPE_ISIS_TLV, reach);
327 return ISIS_WARNING;
328 }
329
330 u_char subtlv_len = *pnt;
331 pnt++;
332 length--;
333
334 if (length < subtlv_len) {
335 zlog_warn(
336 "ISIS-TLV: invalid IPv6 reachability SubTLVs have oversize");
337 XFREE(MTYPE_ISIS_TLV, reach);
338 return ISIS_WARNING;
339 }
340
341 /* Skip Sub-TLVs for now */
342 pnt += subtlv_len;
343 length -= subtlv_len;
344 }
345 listnode_add(reach_list, reach);
346 }
347
348 if (length) {
349 zlog_warn(
350 "ISIS-TLV: (MT) IPv6 reachability TLV has trailing data");
351 return ISIS_WARNING;
352 }
353
354 return ISIS_OK;
355 }
356
357 /*
358 * Parses the tlvs found in the variant length part of the PDU.
359 * Caller tells with flags in "expected" which TLV's it is interested in.
360 */
361 int parse_tlvs(char *areatag, u_char *stream, int size, u_int32_t *expected,
362 u_int32_t *found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset)
363 {
364 u_char type, length;
365 struct lan_neigh *lan_nei;
366 struct area_addr *area_addr;
367 struct is_neigh *is_nei;
368 struct es_neigh *es_nei;
369 struct lsp_entry *lsp_entry;
370 struct in_addr *ipv4_addr;
371 struct ipv4_reachability *ipv4_reach;
372 struct in6_addr *ipv6_addr;
373 int value_len, retval = ISIS_OK;
374 u_char *start = stream, *pnt = stream;
375
376 *found = 0;
377 memset(tlvs, 0, sizeof(struct tlvs));
378
379 while (pnt < stream + size - 2) {
380 type = *pnt;
381 length = *(pnt + 1);
382 pnt += 2;
383 value_len = 0;
384 if (pnt + length > stream + size) {
385 zlog_warn(
386 "ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet "
387 "boundaries",
388 areatag, type, length);
389 retval = ISIS_WARNING;
390 break;
391 }
392 switch (type) {
393 case AREA_ADDRESSES:
394 /* +-------+-------+-------+-------+-------+-------+-------+-------+
395 * | Address Length |
396 * +-------+-------+-------+-------+-------+-------+-------+-------+
397 * | Area Address |
398 * +-------+-------+-------+-------+-------+-------+-------+-------+
399 * : :
400 */
401 *found |= TLVFLAG_AREA_ADDRS;
402 #ifdef EXTREME_TLV_DEBUG
403 zlog_debug("TLV Area Adresses len %d", length);
404 #endif /* EXTREME_TLV_DEBUG */
405 if (*expected & TLVFLAG_AREA_ADDRS) {
406 while (length > value_len) {
407 area_addr = (struct area_addr *)pnt;
408 value_len += area_addr->addr_len + 1;
409 pnt += area_addr->addr_len + 1;
410 if (!tlvs->area_addrs)
411 tlvs->area_addrs = list_new();
412 listnode_add(tlvs->area_addrs,
413 area_addr);
414 }
415 } else {
416 pnt += length;
417 }
418 break;
419
420 case IS_NEIGHBOURS:
421 *found |= TLVFLAG_IS_NEIGHS;
422 #ifdef EXTREME_TLV_DEBUG
423 zlog_debug("ISIS-TLV (%s): IS Neighbours length %d",
424 areatag, length);
425 #endif /* EXTREME_TLV_DEBUG */
426 if (TLVFLAG_IS_NEIGHS & *expected) {
427 /* +-------+-------+-------+-------+-------+-------+-------+-------+
428 * | Virtual Flag |
429 * +-------+-------+-------+-------+-------+-------+-------+-------+
430 */
431 pnt++;
432 value_len++;
433 /* +-------+-------+-------+-------+-------+-------+-------+-------+
434 * | 0 | I/E | Default
435 * Metric |
436 * +-------+-------+-------+-------+-------+-------+-------+-------+
437 * | S | I/E | Delay Metric
438 * |
439 * +-------+-------+-------+-------+-------+-------+-------+-------+
440 * | S | I/E | Expense
441 * Metric |
442 * +-------+-------+-------+-------+-------+-------+-------+-------+
443 * | S | I/E | Error Metric
444 * |
445 * +-------+-------+-------+-------+-------+-------+-------+-------+
446 * | Neighbour ID |
447 * +---------------------------------------------------------------+
448 * : :
449 */
450 while (length > value_len) {
451 is_nei = (struct is_neigh *)pnt;
452 value_len += 4 + ISIS_SYS_ID_LEN + 1;
453 pnt += 4 + ISIS_SYS_ID_LEN + 1;
454 if (!tlvs->is_neighs)
455 tlvs->is_neighs = list_new();
456 listnode_add(tlvs->is_neighs, is_nei);
457 }
458 } else {
459 pnt += length;
460 }
461 break;
462
463 case TE_IS_NEIGHBOURS:
464 *found |= TLVFLAG_TE_IS_NEIGHS;
465 #ifdef EXTREME_TLV_DEBUG
466 zlog_debug(
467 "ISIS-TLV (%s): Extended IS Neighbours length %d",
468 areatag, length);
469 #endif /* EXTREME_TLV_DEBUG */
470 if (TLVFLAG_TE_IS_NEIGHS & *expected)
471 retval = parse_mt_is_neighs(tlvs, false, length,
472 pnt);
473 pnt += length;
474 break;
475
476 case MT_IS_NEIGHBOURS:
477 *found |= TLVFLAG_TE_IS_NEIGHS;
478 #ifdef EXTREME_TLV_DEBUG
479 zlog_debug("ISIS-TLV (%s): MT IS Neighbours length %d",
480 areatag, length);
481 #endif
482 if (TLVFLAG_TE_IS_NEIGHS & *expected)
483 retval = parse_mt_is_neighs(tlvs, true, length,
484 pnt);
485 pnt += length;
486 break;
487
488 case ES_NEIGHBOURS:
489 /* +-------+-------+-------+-------+-------+-------+-------+-------+
490 * | 0 | I/E | Default Metric |
491 * +-------+-------+-------+-------+-------+-------+-------+-------+
492 * | S | I/E | Delay Metric |
493 * +-------+-------+-------+-------+-------+-------+-------+-------+
494 * | S | I/E | Expense Metric |
495 * +-------+-------+-------+-------+-------+-------+-------+-------+
496 * | S | I/E | Error Metric |
497 * +-------+-------+-------+-------+-------+-------+-------+-------+
498 * | Neighbour ID |
499 * +---------------------------------------------------------------+
500 * | Neighbour ID |
501 * +---------------------------------------------------------------+
502 * : :
503 */
504 #ifdef EXTREME_TLV_DEBUG
505 zlog_debug("ISIS-TLV (%s): ES Neighbours length %d",
506 areatag, length);
507 #endif /* EXTREME_TLV_DEBUG */
508 *found |= TLVFLAG_ES_NEIGHS;
509 if (*expected & TLVFLAG_ES_NEIGHS) {
510 es_nei = (struct es_neigh *)pnt;
511 value_len += 4;
512 pnt += 4;
513 while (length > value_len) {
514 /* FIXME FIXME FIXME - add to the list
515 */
516 /* sys_id->id = pnt; */
517 value_len += ISIS_SYS_ID_LEN;
518 pnt += ISIS_SYS_ID_LEN;
519 /* if (!es_nei->neigh_ids)
520 * es_nei->neigh_ids = sysid; */
521 }
522 if (!tlvs->es_neighs)
523 tlvs->es_neighs = list_new();
524 listnode_add(tlvs->es_neighs, es_nei);
525 } else {
526 pnt += length;
527 }
528 break;
529
530 case LAN_NEIGHBOURS:
531 /* +-------+-------+-------+-------+-------+-------+-------+-------+
532 * | LAN Address |
533 * +-------+-------+-------+-------+-------+-------+-------+-------+
534 * : :
535 */
536 *found |= TLVFLAG_LAN_NEIGHS;
537 #ifdef EXTREME_TLV_DEBUG
538 zlog_debug("ISIS-TLV (%s): LAN Neigbours length %d",
539 areatag, length);
540 #endif /* EXTREME_TLV_DEBUG */
541 if (TLVFLAG_LAN_NEIGHS & *expected) {
542 while (length > value_len) {
543 lan_nei = (struct lan_neigh *)pnt;
544 if (!tlvs->lan_neighs)
545 tlvs->lan_neighs = list_new();
546 listnode_add(tlvs->lan_neighs, lan_nei);
547 value_len += ETH_ALEN;
548 pnt += ETH_ALEN;
549 }
550 } else {
551 pnt += length;
552 }
553 break;
554
555 case PADDING:
556 #ifdef EXTREME_TLV_DEBUG
557 zlog_debug("TLV padding %d", length);
558 #endif /* EXTREME_TLV_DEBUG */
559 pnt += length;
560 break;
561
562 case LSP_ENTRIES:
563 /* +-------+-------+-------+-------+-------+-------+-------+-------+
564 * | Remaining Lifetime | 2
565 * +-------+-------+-------+-------+-------+-------+-------+-------+
566 * | LSP ID | id+2
567 * +-------+-------+-------+-------+-------+-------+-------+-------+
568 * | LSP Sequence Number | 4
569 * +-------+-------+-------+-------+-------+-------+-------+-------+
570 * | Checksum | 2
571 * +-------+-------+-------+-------+-------+-------+-------+-------+
572 */
573 #ifdef EXTREME_TLV_DEBUG
574 zlog_debug("ISIS-TLV (%s): LSP Entries length %d",
575 areatag, length);
576 #endif /* EXTREME_TLV_DEBUG */
577 *found |= TLVFLAG_LSP_ENTRIES;
578 if (TLVFLAG_LSP_ENTRIES & *expected) {
579 while (length > value_len) {
580 lsp_entry = (struct lsp_entry *)pnt;
581 value_len += 10 + ISIS_SYS_ID_LEN;
582 pnt += 10 + ISIS_SYS_ID_LEN;
583 if (!tlvs->lsp_entries)
584 tlvs->lsp_entries = list_new();
585 listnode_add(tlvs->lsp_entries,
586 lsp_entry);
587 }
588 } else {
589 pnt += length;
590 }
591 break;
592
593 case CHECKSUM:
594 /* +-------+-------+-------+-------+-------+-------+-------+-------+
595 * | 16 bit fletcher CHECKSUM |
596 * +-------+-------+-------+-------+-------+-------+-------+-------+
597 * : :
598 */
599 *found |= TLVFLAG_CHECKSUM;
600 #ifdef EXTREME_TLV_DEBUG
601 zlog_debug("ISIS-TLV (%s): Checksum length %d", areatag,
602 length);
603 #endif /* EXTREME_TLV_DEBUG */
604 if (*expected & TLVFLAG_CHECKSUM) {
605 tlvs->checksum = (struct checksum *)pnt;
606 }
607 pnt += length;
608 break;
609
610 case PROTOCOLS_SUPPORTED:
611 /* +-------+-------+-------+-------+-------+-------+-------+-------+
612 * | NLPID |
613 * +-------+-------+-------+-------+-------+-------+-------+-------+
614 * : :
615 */
616 *found |= TLVFLAG_NLPID;
617 #ifdef EXTREME_TLV_DEBUG
618 zlog_debug(
619 "ISIS-TLV (%s): Protocols Supported length %d",
620 areatag, length);
621 #endif /* EXTREME_TLV_DEBUG */
622 if (*expected & TLVFLAG_NLPID) {
623 tlvs->nlpids = (struct nlpids *)(pnt - 1);
624 }
625 pnt += length;
626 break;
627
628 case IPV4_ADDR:
629 /* +-------+-------+-------+-------+-------+-------+-------+-------+
630 * + IP version 4 address + 4
631 * +-------+-------+-------+-------+-------+-------+-------+-------+
632 * : :
633 */
634 *found |= TLVFLAG_IPV4_ADDR;
635 #ifdef EXTREME_TLV_DEBUG
636 zlog_debug("ISIS-TLV (%s): IPv4 Address length %d",
637 areatag, length);
638 #endif /* EXTREME_TLV_DEBUG */
639 if (*expected & TLVFLAG_IPV4_ADDR) {
640 while (length > value_len) {
641 ipv4_addr = (struct in_addr *)pnt;
642 #ifdef EXTREME_TLV_DEBUG
643 zlog_debug(
644 "ISIS-TLV (%s) : IP ADDR %s, pnt %p",
645 areatag, inet_ntoa(*ipv4_addr),
646 pnt);
647 #endif /* EXTREME_TLV_DEBUG */
648 if (!tlvs->ipv4_addrs)
649 tlvs->ipv4_addrs = list_new();
650 listnode_add(tlvs->ipv4_addrs,
651 ipv4_addr);
652 value_len += 4;
653 pnt += 4;
654 }
655 } else {
656 pnt += length;
657 }
658 break;
659
660 case AUTH_INFO:
661 *found |= TLVFLAG_AUTH_INFO;
662 #ifdef EXTREME_TLV_DEBUG
663 zlog_debug(
664 "ISIS-TLV (%s): IS-IS Authentication Information",
665 areatag);
666 #endif
667 if (*expected & TLVFLAG_AUTH_INFO) {
668 tlvs->auth_info.type = *pnt;
669 if (length == 0) {
670 zlog_warn(
671 "ISIS-TLV (%s): TLV (type %d, length %d) "
672 "incorrect.",
673 areatag, type, length);
674 return ISIS_WARNING;
675 }
676 --length;
677 tlvs->auth_info.len = length;
678 pnt++;
679 memcpy(tlvs->auth_info.passwd, pnt, length);
680 /* Return the authentication tlv pos for later
681 * computation
682 * of MD5 (RFC 5304, 2)
683 */
684 if (auth_tlv_offset)
685 *auth_tlv_offset += (pnt - start - 3);
686 pnt += length;
687 } else {
688 pnt += length;
689 }
690 break;
691
692 case DYNAMIC_HOSTNAME:
693 *found |= TLVFLAG_DYN_HOSTNAME;
694 #ifdef EXTREME_TLV_DEBUG
695 zlog_debug("ISIS-TLV (%s): Dynamic Hostname length %d",
696 areatag, length);
697 #endif /* EXTREME_TLV_DEBUG */
698 if (*expected & TLVFLAG_DYN_HOSTNAME) {
699 /* the length is also included in the pointed
700 * struct */
701 tlvs->hostname = (struct hostname *)(pnt - 1);
702 }
703 pnt += length;
704 break;
705
706 case TE_ROUTER_ID:
707 /* +---------------------------------------------------------------+
708 * + Router ID + 4
709 * +---------------------------------------------------------------+
710 */
711 *found |= TLVFLAG_TE_ROUTER_ID;
712 #ifdef EXTREME_TLV_DEBUG
713 zlog_debug("ISIS-TLV (%s): TE Router ID %d", areatag,
714 length);
715 #endif /* EXTREME_TLV_DEBUG */
716 if (*expected & TLVFLAG_TE_ROUTER_ID)
717 tlvs->router_id = (struct te_router_id *)(pnt);
718 pnt += length;
719 break;
720
721 case IPV4_INT_REACHABILITY:
722 /* +-------+-------+-------+-------+-------+-------+-------+-------+
723 * | 0 | I/E | Default Metric | 1
724 * +-------+-------+-------+-------+-------+-------+-------+-------+
725 * | S | I/E | Delay Metric | 1
726 * +-------+-------+-------+-------+-------+-------+-------+-------+
727 * | S | I/E | Expense Metric | 1
728 * +-------+-------+-------+-------+-------+-------+-------+-------+
729 * | S | I/E | Error Metric | 1
730 * +-------+-------+-------+-------+-------+-------+-------+-------+
731 * | ip address | 4
732 * +---------------------------------------------------------------+
733 * | address mask | 4
734 * +---------------------------------------------------------------+
735 * : :
736 */
737 *found |= TLVFLAG_IPV4_INT_REACHABILITY;
738 #ifdef EXTREME_TLV_DEBUG
739 zlog_debug(
740 "ISIS-TLV (%s): IPv4 internal Reachability length %d",
741 areatag, length);
742 #endif /* EXTREME_TLV_DEBUG */
743 if (*expected & TLVFLAG_IPV4_INT_REACHABILITY) {
744 while (length > value_len) {
745 ipv4_reach =
746 (struct ipv4_reachability *)pnt;
747 if (!tlvs->ipv4_int_reachs)
748 tlvs->ipv4_int_reachs =
749 list_new();
750 listnode_add(tlvs->ipv4_int_reachs,
751 ipv4_reach);
752 value_len += 12;
753 pnt += 12;
754 }
755 } else {
756 pnt += length;
757 }
758 break;
759
760 case IPV4_EXT_REACHABILITY:
761 /* +-------+-------+-------+-------+-------+-------+-------+-------+
762 * | 0 | I/E | Default Metric | 1
763 * +-------+-------+-------+-------+-------+-------+-------+-------+
764 * | S | I/E | Delay Metric | 1
765 * +-------+-------+-------+-------+-------+-------+-------+-------+
766 * | S | I/E | Expense Metric | 1
767 * +-------+-------+-------+-------+-------+-------+-------+-------+
768 * | S | I/E | Error Metric | 1
769 * +-------+-------+-------+-------+-------+-------+-------+-------+
770 * | ip address | 4
771 * +---------------------------------------------------------------+
772 * | address mask | 4
773 * +---------------------------------------------------------------+
774 * : :
775 */
776 *found |= TLVFLAG_IPV4_EXT_REACHABILITY;
777 #ifdef EXTREME_TLV_DEBUG
778 zlog_debug(
779 "ISIS-TLV (%s): IPv4 external Reachability length %d",
780 areatag, length);
781 #endif /* EXTREME_TLV_DEBUG */
782 if (*expected & TLVFLAG_IPV4_EXT_REACHABILITY) {
783 while (length > value_len) {
784 ipv4_reach =
785 (struct ipv4_reachability *)pnt;
786 if (!tlvs->ipv4_ext_reachs)
787 tlvs->ipv4_ext_reachs =
788 list_new();
789 listnode_add(tlvs->ipv4_ext_reachs,
790 ipv4_reach);
791 value_len += 12;
792 pnt += 12;
793 }
794 } else {
795 pnt += length;
796 }
797 break;
798
799 case TE_IPV4_REACHABILITY:
800 *found |= TLVFLAG_TE_IPV4_REACHABILITY;
801 #ifdef EXTREME_TLV_DEBUG
802 zlog_debug(
803 "ISIS-TLV (%s): IPv4 extended Reachability length %d",
804 areatag, length);
805 #endif /* EXTREME_TLV_DEBUG */
806 if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
807 retval = parse_mt_ipv4_reachs(tlvs, false,
808 length, pnt);
809 pnt += length;
810 break;
811 case MT_IPV4_REACHABILITY:
812 *found |= TLVFLAG_TE_IPV4_REACHABILITY;
813 #ifdef EXTREME_TLV_DEBUG
814 zlog_debug(
815 "ISIS-TLV (%s): IPv4 MT Reachability length %d",
816 areatag, length);
817 #endif /* EXTREME_TLV_DEBUG */
818 if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
819 retval = parse_mt_ipv4_reachs(tlvs, true,
820 length, pnt);
821 pnt += length;
822 break;
823 case IPV6_ADDR:
824 /* +-------+-------+-------+-------+-------+-------+-------+-------+
825 * + IP version 6 address + 16
826 * +-------+-------+-------+-------+-------+-------+-------+-------+
827 * : :
828 */
829 *found |= TLVFLAG_IPV6_ADDR;
830 #ifdef EXTREME_TLV_DEBUG
831 zlog_debug("ISIS-TLV (%s): IPv6 Address length %d",
832 areatag, length);
833 #endif /* EXTREME_TLV_DEBUG */
834 if (*expected & TLVFLAG_IPV6_ADDR) {
835 while (length > value_len) {
836 ipv6_addr = (struct in6_addr *)pnt;
837 if (!tlvs->ipv6_addrs)
838 tlvs->ipv6_addrs = list_new();
839 listnode_add(tlvs->ipv6_addrs,
840 ipv6_addr);
841 value_len += 16;
842 pnt += 16;
843 }
844 } else {
845 pnt += length;
846 }
847 break;
848
849 case IPV6_REACHABILITY:
850 *found |= TLVFLAG_IPV6_REACHABILITY;
851 #ifdef EXTREME_TLV_DEBUG
852 zlog_debug("ISIS-TLV (%s): IPv6 Reachability length %d",
853 areatag, length);
854 #endif /* EXTREME_TLV_DEBUG */
855 if (*expected & TLVFLAG_IPV6_REACHABILITY)
856 retval = parse_mt_ipv6_reachs(tlvs, false,
857 length, pnt);
858 pnt += length;
859 break;
860 case MT_IPV6_REACHABILITY:
861 *found |= TLVFLAG_IPV6_REACHABILITY;
862 #ifdef EXTREME_TLV_DEBUG
863 zlog_debug("ISIS-TLV (%s): IPv6 Reachability length %d",
864 areatag, length);
865 #endif /* EXTREME_TLV_DEBUG */
866 if (*expected & TLVFLAG_IPV6_REACHABILITY)
867 retval = parse_mt_ipv6_reachs(tlvs, true,
868 length, pnt);
869 pnt += length;
870 break;
871 case WAY3_HELLO:
872 /* +---------------------------------------------------------------+
873 * | Adjacency state | 1
874 * +---------------------------------------------------------------+
875 * | Extended Local Circuit ID | 4
876 * +---------------------------------------------------------------+
877 * | Neighbor System ID (If known)
878 * | 0-8
879 * (probably 6)
880 * +---------------------------------------------------------------+
881 * | Neighbor Local Circuit ID (If
882 * known) | 4
883 * +---------------------------------------------------------------+
884 */
885 *found |= TLVFLAG_3WAY_HELLO;
886 if (*expected & TLVFLAG_3WAY_HELLO) {
887 while (length > value_len) {
888 /* FIXME: make this work */
889 /* Adjacency State (one
890 octet):
891 0 = Up
892 1 = Initializing
893 2 = Down
894 Extended Local Circuit ID
895 (four octets)
896 Neighbor System ID if known
897 (zero to eight octets)
898 Neighbor Extended Local
899 Circuit ID (four octets, if Neighbor
900 System ID is present) */
901 pnt += length;
902 value_len += length;
903 }
904 } else {
905 pnt += length;
906 }
907
908 break;
909 case GRACEFUL_RESTART:
910 /* +-------+-------+-------+-------+-------+-------+-------+-------+
911 * | Reserved | SA | RA
912 * | RR | 1
913 * +-------+-------+-------+-------+-------+-------+-------+-------+
914 * | Remaining Time | 2
915 * +---------------------------------------------------------------+
916 * | Restarting Neighbor ID (If known)
917 * | 0-8
918 * +---------------------------------------------------------------+
919 */
920 *found |= TLVFLAG_GRACEFUL_RESTART;
921 if (*expected & TLVFLAG_GRACEFUL_RESTART) {
922 /* FIXME: make this work */
923 }
924 pnt += length;
925 break;
926
927 case MT_ROUTER_INFORMATION:
928 *found |= TLVFLAG_MT_ROUTER_INFORMATION;
929 if (*expected & TLVFLAG_MT_ROUTER_INFORMATION) {
930 if (!tlvs->mt_router_info) {
931 tlvs->mt_router_info = list_new();
932 tlvs->mt_router_info->del = free_tlv;
933 }
934 while (length > value_len) {
935 uint16_t mt_info;
936 struct mt_router_info *info;
937
938 if (value_len + sizeof(mt_info)
939 > length) {
940 zlog_warn(
941 "ISIS-TLV (%s): TLV 229 is truncated.",
942 areatag);
943 pnt += length - value_len;
944 break;
945 }
946
947 memcpy(&mt_info, pnt, sizeof(mt_info));
948 pnt += sizeof(mt_info);
949 value_len += sizeof(mt_info);
950
951 mt_info = ntohs(mt_info);
952 info = XCALLOC(MTYPE_ISIS_TLV,
953 sizeof(*info));
954 info->mtid = mt_info & ISIS_MT_MASK;
955 info->overload =
956 mt_info & ISIS_MT_OL_MASK;
957 listnode_add(tlvs->mt_router_info,
958 info);
959 }
960 } else {
961 pnt += length;
962 }
963 break;
964 default:
965 zlog_warn(
966 "ISIS-TLV (%s): unsupported TLV type %d, length %d",
967 areatag, type, length);
968
969 pnt += length;
970 break;
971 }
972 /* Abort Parsing if error occured */
973 if (retval != ISIS_OK)
974 return retval;
975 }
976
977 return retval;
978 }
979
980 int add_tlv(u_char tag, u_char len, u_char *value, struct stream *stream)
981 {
982 if ((stream_get_size(stream) - stream_get_endp(stream))
983 < (((unsigned)len) + 2)) {
984 zlog_warn(
985 "No room for TLV of type %d "
986 "(total size %d available %d required %d)",
987 tag, (int)stream_get_size(stream),
988 (int)(stream_get_size(stream)
989 - stream_get_endp(stream)),
990 len + 2);
991 return ISIS_WARNING;
992 }
993
994 stream_putc(stream, tag); /* TAG */
995 stream_putc(stream, len); /* LENGTH */
996 stream_put(stream, value, (int)len); /* VALUE */
997
998 #ifdef EXTREME_DEBUG
999 zlog_debug("Added TLV %d len %d", tag, len);
1000 #endif /* EXTREME DEBUG */
1001 return ISIS_OK;
1002 }
1003
1004 int tlv_add_mt_router_info(struct list *mt_router_info, struct stream *stream)
1005 {
1006 struct listnode *node;
1007 struct mt_router_info *info;
1008
1009 uint16_t value[127];
1010 uint16_t *pos = value;
1011
1012 for (ALL_LIST_ELEMENTS_RO(mt_router_info, node, info)) {
1013 uint16_t mt_info;
1014
1015 mt_info = info->mtid;
1016 if (info->overload)
1017 mt_info |= ISIS_MT_OL_MASK;
1018
1019 *pos = htons(mt_info);
1020 pos++;
1021 }
1022
1023 return add_tlv(MT_ROUTER_INFORMATION, (pos - value) * sizeof(*pos),
1024 (u_char *)value, stream);
1025 }
1026
1027 int tlv_add_area_addrs(struct list *area_addrs, struct stream *stream)
1028 {
1029 struct listnode *node;
1030 struct area_addr *area_addr;
1031
1032 u_char value[255];
1033 u_char *pos = value;
1034
1035 for (ALL_LIST_ELEMENTS_RO(area_addrs, node, area_addr)) {
1036 if (pos - value + area_addr->addr_len > 255)
1037 goto err;
1038 *pos = area_addr->addr_len;
1039 pos++;
1040 memcpy(pos, area_addr->area_addr, (int)area_addr->addr_len);
1041 pos += area_addr->addr_len;
1042 }
1043
1044 return add_tlv(AREA_ADDRESSES, pos - value, value, stream);
1045
1046 err:
1047 zlog_warn("tlv_add_area_addrs(): TLV longer than 255");
1048 return ISIS_WARNING;
1049 }
1050
1051 int tlv_add_is_neighs(struct list *is_neighs, struct stream *stream)
1052 {
1053 struct listnode *node;
1054 struct is_neigh *is_neigh;
1055 u_char value[255];
1056 u_char *pos = value;
1057 int retval;
1058
1059 *pos = 0; /*is_neigh->virtual; */
1060 pos++;
1061
1062 for (ALL_LIST_ELEMENTS_RO(is_neighs, node, is_neigh)) {
1063 if (pos - value + IS_NEIGHBOURS_LEN > 255) {
1064 retval = add_tlv(IS_NEIGHBOURS, pos - value, value,
1065 stream);
1066 if (retval != ISIS_OK)
1067 return retval;
1068 pos = value;
1069 }
1070 *pos = is_neigh->metrics.metric_default;
1071 pos++;
1072 *pos = is_neigh->metrics.metric_delay;
1073 pos++;
1074 *pos = is_neigh->metrics.metric_expense;
1075 pos++;
1076 *pos = is_neigh->metrics.metric_error;
1077 pos++;
1078 memcpy(pos, is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
1079 pos += ISIS_SYS_ID_LEN + 1;
1080 }
1081
1082 return add_tlv(IS_NEIGHBOURS, pos - value, value, stream);
1083 }
1084
1085 static size_t max_tlv_size(struct stream *stream)
1086 {
1087 size_t avail = stream_get_size(stream) - stream_get_endp(stream);
1088
1089 if (avail < 2)
1090 return 0;
1091
1092 if (avail < 257)
1093 return avail - 2;
1094
1095 return 255;
1096 }
1097
1098 unsigned int tlv_add_te_is_neighs(struct list *te_is_neighs,
1099 struct stream *stream, void *arg)
1100 {
1101 struct listnode *node;
1102 struct te_is_neigh *te_is_neigh;
1103 u_char value[255];
1104 u_char *pos = value;
1105 uint16_t mtid = arg ? *(uint16_t *)arg : ISIS_MT_IPV4_UNICAST;
1106 unsigned int consumed = 0;
1107 size_t max_size = max_tlv_size(stream);
1108
1109 if (mtid != ISIS_MT_IPV4_UNICAST) {
1110 uint16_t mtid_conversion = ntohs(mtid);
1111 memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
1112 pos += sizeof(mtid_conversion);
1113 }
1114
1115 for (ALL_LIST_ELEMENTS_RO(te_is_neighs, node, te_is_neigh)) {
1116 /* FIXME: Check if Total SubTLVs size doesn't exceed 255 */
1117 if ((size_t)(pos - value) + IS_NEIGHBOURS_LEN
1118 + te_is_neigh->sub_tlvs_length
1119 > max_size)
1120 break;
1121
1122 memcpy(pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
1123 pos += ISIS_SYS_ID_LEN + 1;
1124 memcpy(pos, te_is_neigh->te_metric, 3);
1125 pos += 3;
1126 /* Set the total size of Sub TLVs */
1127 *pos = te_is_neigh->sub_tlvs_length;
1128 pos++;
1129 /* Copy Sub TLVs if any */
1130 if (te_is_neigh->sub_tlvs_length > 0) {
1131 memcpy(pos, te_is_neigh->sub_tlvs,
1132 te_is_neigh->sub_tlvs_length);
1133 pos += te_is_neigh->sub_tlvs_length;
1134 }
1135 consumed++;
1136 }
1137
1138 if (consumed) {
1139 int rv = add_tlv((mtid != ISIS_MT_IPV4_UNICAST)
1140 ? MT_IS_NEIGHBOURS
1141 : TE_IS_NEIGHBOURS,
1142 pos - value, value, stream);
1143 assert(rv == ISIS_OK);
1144 }
1145 return consumed;
1146 }
1147
1148 int tlv_add_lan_neighs(struct list *lan_neighs, struct stream *stream)
1149 {
1150 struct listnode *node;
1151 u_char *snpa;
1152 u_char value[255];
1153 u_char *pos = value;
1154 int retval;
1155
1156 for (ALL_LIST_ELEMENTS_RO(lan_neighs, node, snpa)) {
1157 if (pos - value + ETH_ALEN > 255) {
1158 retval = add_tlv(LAN_NEIGHBOURS, pos - value, value,
1159 stream);
1160 if (retval != ISIS_OK)
1161 return retval;
1162 pos = value;
1163 }
1164 memcpy(pos, snpa, ETH_ALEN);
1165 pos += ETH_ALEN;
1166 }
1167
1168 return add_tlv(LAN_NEIGHBOURS, pos - value, value, stream);
1169 }
1170
1171 int tlv_add_nlpid(struct nlpids *nlpids, struct stream *stream)
1172 {
1173 return add_tlv(PROTOCOLS_SUPPORTED, nlpids->count, nlpids->nlpids,
1174 stream);
1175 }
1176
1177 int tlv_add_authinfo(u_char auth_type, u_char auth_len, u_char *auth_value,
1178 struct stream *stream)
1179 {
1180 u_char value[255];
1181 u_char *pos = value;
1182 *pos++ = auth_type;
1183 memcpy(pos, auth_value, auth_len);
1184
1185 return add_tlv(AUTH_INFO, auth_len + 1, value, stream);
1186 }
1187
1188 int tlv_add_checksum(struct checksum *checksum, struct stream *stream)
1189 {
1190 u_char value[255];
1191 u_char *pos = value;
1192 return add_tlv(CHECKSUM, pos - value, value, stream);
1193 }
1194
1195 int tlv_add_ip_addrs(struct list *ip_addrs, struct stream *stream)
1196 {
1197 struct listnode *node;
1198 struct prefix_ipv4 *ipv4;
1199 u_char value[255];
1200 u_char *pos = value;
1201
1202 for (ALL_LIST_ELEMENTS_RO(ip_addrs, node, ipv4)) {
1203 if (pos - value + IPV4_MAX_BYTELEN > 255) {
1204 /* RFC 1195 s4.2: only one tuple of 63 allowed. */
1205 zlog_warn(
1206 "tlv_add_ip_addrs(): cutting off at 63 IP addresses");
1207 break;
1208 }
1209 *(u_int32_t *)pos = ipv4->prefix.s_addr;
1210 pos += IPV4_MAX_BYTELEN;
1211 }
1212
1213 return add_tlv(IPV4_ADDR, pos - value, value, stream);
1214 }
1215
1216 /* Used to add TLV containing just one IPv4 address - either IPv4 address TLV
1217 * (in case of LSP) or TE router ID TLV. */
1218 int tlv_add_in_addr(struct in_addr *addr, struct stream *stream, u_char tag)
1219 {
1220 u_char value[255];
1221 u_char *pos = value;
1222
1223 memcpy(pos, addr, IPV4_MAX_BYTELEN);
1224 pos += IPV4_MAX_BYTELEN;
1225
1226 return add_tlv(tag, pos - value, value, stream);
1227 }
1228
1229 int tlv_add_dynamic_hostname(struct hostname *hostname, struct stream *stream)
1230 {
1231 return add_tlv(DYNAMIC_HOSTNAME, hostname->namelen, hostname->name,
1232 stream);
1233 }
1234
1235 int tlv_add_lsp_entries(struct list *lsps, struct stream *stream)
1236 {
1237 struct listnode *node;
1238 struct isis_lsp *lsp;
1239 u_char value[255];
1240 u_char *pos = value;
1241 int retval;
1242
1243 for (ALL_LIST_ELEMENTS_RO(lsps, node, lsp)) {
1244 if (pos - value + LSP_ENTRIES_LEN > 255) {
1245 retval = add_tlv(LSP_ENTRIES, pos - value, value,
1246 stream);
1247 if (retval != ISIS_OK)
1248 return retval;
1249 pos = value;
1250 }
1251 *((u_int16_t *)pos) = lsp->lsp_header->rem_lifetime;
1252 pos += 2;
1253 memcpy(pos, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
1254 pos += ISIS_SYS_ID_LEN + 2;
1255 *((u_int32_t *)pos) = lsp->lsp_header->seq_num;
1256 pos += 4;
1257 *((u_int16_t *)pos) = lsp->lsp_header->checksum;
1258 pos += 2;
1259 }
1260
1261 return add_tlv(LSP_ENTRIES, pos - value, value, stream);
1262 }
1263
1264 static int tlv_add_ipv4_reachs(u_char tag, struct list *ipv4_reachs,
1265 struct stream *stream)
1266 {
1267 struct listnode *node;
1268 struct ipv4_reachability *reach;
1269 u_char value[255];
1270 u_char *pos = value;
1271 int retval;
1272
1273 for (ALL_LIST_ELEMENTS_RO(ipv4_reachs, node, reach)) {
1274 if (pos - value + IPV4_REACH_LEN > 255) {
1275 retval = add_tlv(tag, pos - value, value, stream);
1276 if (retval != ISIS_OK)
1277 return retval;
1278 pos = value;
1279 }
1280 *pos = reach->metrics.metric_default;
1281 pos++;
1282 *pos = reach->metrics.metric_delay;
1283 pos++;
1284 *pos = reach->metrics.metric_expense;
1285 pos++;
1286 *pos = reach->metrics.metric_error;
1287 pos++;
1288 *(u_int32_t *)pos = reach->prefix.s_addr;
1289 pos += IPV4_MAX_BYTELEN;
1290 *(u_int32_t *)pos = reach->mask.s_addr;
1291 pos += IPV4_MAX_BYTELEN;
1292 }
1293
1294 return add_tlv(tag, pos - value, value, stream);
1295 }
1296
1297 int tlv_add_ipv4_int_reachs(struct list *ipv4_reachs, struct stream *stream)
1298 {
1299 return tlv_add_ipv4_reachs(IPV4_INT_REACHABILITY, ipv4_reachs, stream);
1300 }
1301
1302 int tlv_add_ipv4_ext_reachs(struct list *ipv4_reachs, struct stream *stream)
1303 {
1304 return tlv_add_ipv4_reachs(IPV4_EXT_REACHABILITY, ipv4_reachs, stream);
1305 }
1306
1307
1308 unsigned int tlv_add_te_ipv4_reachs(struct list *te_ipv4_reachs,
1309 struct stream *stream, void *arg)
1310 {
1311 struct listnode *node;
1312 struct te_ipv4_reachability *te_reach;
1313 u_char value[255];
1314 u_char *pos = value;
1315 uint16_t mtid = arg ? *(uint16_t *)arg : ISIS_MT_IPV4_UNICAST;
1316 unsigned int consumed = 0;
1317 size_t max_size = max_tlv_size(stream);
1318
1319 if (mtid != ISIS_MT_IPV4_UNICAST) {
1320 uint16_t mtid_conversion = ntohs(mtid);
1321 memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
1322 pos += sizeof(mtid_conversion);
1323 }
1324
1325 for (ALL_LIST_ELEMENTS_RO(te_ipv4_reachs, node, te_reach)) {
1326 unsigned char prefixlen = te_reach->control & 0x3F;
1327
1328 if ((size_t)(pos - value) + 5 + PSIZE(prefixlen) > max_size)
1329 break;
1330
1331 *(u_int32_t *)pos = te_reach->te_metric;
1332 pos += 4;
1333 *pos = te_reach->control;
1334 pos++;
1335 memcpy(pos, &te_reach->prefix_start, PSIZE(prefixlen));
1336 pos += PSIZE(prefixlen);
1337 consumed++;
1338 }
1339
1340 if (consumed) {
1341 int rv = add_tlv((mtid != ISIS_MT_IPV4_UNICAST)
1342 ? MT_IPV4_REACHABILITY
1343 : TE_IPV4_REACHABILITY,
1344 pos - value, value, stream);
1345 assert(rv == ISIS_OK);
1346 }
1347
1348 return consumed;
1349 }
1350
1351 int tlv_add_ipv6_addrs(struct list *ipv6_addrs, struct stream *stream)
1352 {
1353 struct listnode *node;
1354 struct prefix_ipv6 *ipv6;
1355 u_char value[255];
1356 u_char *pos = value;
1357 int retval;
1358
1359 for (ALL_LIST_ELEMENTS_RO(ipv6_addrs, node, ipv6)) {
1360 if (pos - value + IPV6_MAX_BYTELEN > 255) {
1361 retval = add_tlv(IPV6_ADDR, pos - value, value, stream);
1362 if (retval != ISIS_OK)
1363 return retval;
1364 pos = value;
1365 }
1366 memcpy(pos, ipv6->prefix.s6_addr, IPV6_MAX_BYTELEN);
1367 pos += IPV6_MAX_BYTELEN;
1368 }
1369
1370 return add_tlv(IPV6_ADDR, pos - value, value, stream);
1371 }
1372
1373 unsigned int tlv_add_ipv6_reachs(struct list *ipv6_reachs,
1374 struct stream *stream, void *arg)
1375 {
1376 struct listnode *node;
1377 struct ipv6_reachability *ip6reach;
1378 u_char value[255];
1379 u_char *pos = value;
1380 uint16_t mtid = arg ? *(uint16_t *)arg : ISIS_MT_IPV4_UNICAST;
1381 unsigned int consumed = 0;
1382 size_t max_size = max_tlv_size(stream);
1383
1384 if (mtid != ISIS_MT_IPV4_UNICAST) {
1385 uint16_t mtid_conversion = ntohs(mtid);
1386 memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
1387 pos += sizeof(mtid_conversion);
1388 }
1389
1390 for (ALL_LIST_ELEMENTS_RO(ipv6_reachs, node, ip6reach)) {
1391 if ((size_t)(pos - value) + 6 + PSIZE(ip6reach->prefix_len)
1392 > max_size)
1393 break;
1394
1395 *(uint32_t *)pos = ip6reach->metric;
1396 pos += 4;
1397 *pos = ip6reach->control_info;
1398 pos++;
1399 *pos = ip6reach->prefix_len;
1400 pos++;
1401 memcpy(pos, ip6reach->prefix, PSIZE(ip6reach->prefix_len));
1402 pos += PSIZE(ip6reach->prefix_len);
1403 consumed++;
1404 }
1405
1406 if (consumed) {
1407 int rv = add_tlv((mtid != ISIS_MT_IPV4_UNICAST)
1408 ? MT_IPV6_REACHABILITY
1409 : IPV6_REACHABILITY,
1410 pos - value, value, stream);
1411 assert(rv == ISIS_OK);
1412 }
1413
1414 return consumed;
1415 }
1416
1417 int tlv_add_padding(struct stream *stream)
1418 {
1419 int fullpads, i, left;
1420
1421 /*
1422 * How many times can we add full padding ?
1423 */
1424 fullpads = (stream_get_size(stream) - stream_get_endp(stream)) / 257;
1425 for (i = 0; i < fullpads; i++) {
1426 if (!stream_putc(stream, (u_char)PADDING)) /* TAG */
1427 goto err;
1428 if (!stream_putc(stream, (u_char)255)) /* LENGHT */
1429 goto err;
1430 stream_put(stream, NULL, 255); /* zero padding */
1431 }
1432
1433 left = stream_get_size(stream) - stream_get_endp(stream);
1434
1435 if (left < 2)
1436 return ISIS_OK;
1437
1438 if (left == 2) {
1439 stream_putc(stream, PADDING);
1440 stream_putc(stream, 0);
1441 return ISIS_OK;
1442 }
1443
1444 stream_putc(stream, PADDING);
1445 stream_putc(stream, left - 2);
1446 stream_put(stream, NULL, left - 2);
1447
1448 return ISIS_OK;
1449
1450 err:
1451 zlog_warn("tlv_add_padding(): no room for tlv");
1452 return ISIS_WARNING;
1453 }