]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_tlv.c
*: make consistent & update GPLv2 file headers
[mirror_frr.git] / isisd / isis_tlv.c
Content-type: text/html ]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_tlv.c


500 - Internal Server Error

Malformed UTF-8 character (fatal) at (eval 6) line 1, <$fd> line 1299.
CommitLineData
eb5d44eb 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.
896014f4
DL
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
eb5d44eb 22 */
23
24#include <zebra.h>
eb5d44eb 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"
f8c06e2c 45#include "isisd/isis_te.h"
206f4aae 46#include "isisd/isis_mt.h"
eb5d44eb 47
eb5d44eb 48void
49free_tlv (void *val)
50{
f390d2c7 51 XFREE (MTYPE_ISIS_TLV, val);
52
53 return;
eb5d44eb 54}
55
56/*
57 * Called after parsing of a PDU. There shouldn't be any tlv's left, so this
58 * is only a caution to avoid memory leaks
59 */
f390d2c7 60void
eb5d44eb 61free_tlvs (struct tlvs *tlvs)
62{
f390d2c7 63 if (tlvs->area_addrs)
aac372f4 64 list_delete (tlvs->area_addrs);
99894f9a
CF
65 if (tlvs->mt_router_info)
66 list_delete (tlvs->mt_router_info);
f390d2c7 67 if (tlvs->is_neighs)
aac372f4 68 list_delete (tlvs->is_neighs);
f390d2c7 69 if (tlvs->te_is_neighs)
aac372f4 70 list_delete (tlvs->te_is_neighs);
206f4aae
CF
71 if (tlvs->mt_is_neighs)
72 list_delete (tlvs->mt_is_neighs);
f390d2c7 73 if (tlvs->es_neighs)
aac372f4 74 list_delete (tlvs->es_neighs);
f390d2c7 75 if (tlvs->lsp_entries)
aac372f4 76 list_delete (tlvs->lsp_entries);
f390d2c7 77 if (tlvs->prefix_neighs)
aac372f4 78 list_delete (tlvs->prefix_neighs);
3f045a08
JB
79 if (tlvs->lan_neighs)
80 list_delete (tlvs->lan_neighs);
f390d2c7 81 if (tlvs->ipv4_addrs)
aac372f4 82 list_delete (tlvs->ipv4_addrs);
f390d2c7 83 if (tlvs->ipv4_int_reachs)
aac372f4 84 list_delete (tlvs->ipv4_int_reachs);
f390d2c7 85 if (tlvs->ipv4_ext_reachs)
aac372f4 86 list_delete (tlvs->ipv4_ext_reachs);
f390d2c7 87 if (tlvs->te_ipv4_reachs)
aac372f4 88 list_delete (tlvs->te_ipv4_reachs);
c3ae3127
CF
89 if (tlvs->mt_ipv4_reachs)
90 list_delete (tlvs->mt_ipv4_reachs);
f390d2c7 91 if (tlvs->ipv6_addrs)
aac372f4 92 list_delete (tlvs->ipv6_addrs);
f390d2c7 93 if (tlvs->ipv6_reachs)
aac372f4 94 list_delete (tlvs->ipv6_reachs);
c3ae3127
CF
95 if (tlvs->mt_ipv6_reachs)
96 list_delete (tlvs->mt_ipv6_reachs);
3f045a08
JB
97
98 memset (tlvs, 0, sizeof (struct tlvs));
99
eb5d44eb 100 return;
101}
102
206f4aae 103static int
c3ae3127
CF
104parse_mtid(uint16_t *mtid, bool read_mtid,
105 unsigned int *length, u_char **pnt)
206f4aae 106{
c3ae3127 107 if (!read_mtid)
206f4aae 108 {
c3ae3127
CF
109 *mtid = ISIS_MT_IPV4_UNICAST;
110 return ISIS_OK;
111 }
206f4aae 112
c3ae3127 113 uint16_t mtid_buf;
206f4aae 114
c3ae3127 115 if (*length < sizeof(mtid_buf))
206f4aae 116 {
c3ae3127
CF
117 zlog_warn("ISIS-TLV: mt tlv too short to contain MT id");
118 return ISIS_WARNING;
206f4aae
CF
119 }
120
c3ae3127
CF
121 memcpy(&mtid_buf, *pnt, sizeof(mtid_buf));
122 *pnt += sizeof(mtid_buf);
123 *length -= sizeof(mtid_buf);
124
125 *mtid = ntohs(mtid_buf) & ISIS_MT_MASK;
126 return ISIS_OK;
127}
128
129static int
130parse_mt_is_neighs(struct tlvs *tlvs, bool read_mtid,
131 unsigned int length, u_char *pnt)
132{
133 struct list *neigh_list;
134 uint16_t mtid;
135 int rv;
136
137 rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
138 if (rv != ISIS_OK)
139 return rv;
140
206f4aae
CF
141 if (mtid == ISIS_MT_IPV4_UNICAST)
142 {
143 if (!tlvs->te_is_neighs)
144 {
145 tlvs->te_is_neighs = list_new();
146 tlvs->te_is_neighs->del = free_tlv;
147 }
148 neigh_list = tlvs->te_is_neighs;
149 }
150 else
151 {
152 struct tlv_mt_neighbors *neighbors;
153
154 neighbors = tlvs_get_mt_neighbors(tlvs, mtid);
155 neighbors->list->del = free_tlv;
156 neigh_list = neighbors->list;
157 }
158
159 while (length >= IS_NEIGHBOURS_LEN)
160 {
161 struct te_is_neigh *neigh = XCALLOC(MTYPE_ISIS_TLV, sizeof(*neigh));
162
163 memcpy(neigh, pnt, IS_NEIGHBOURS_LEN);
164 pnt += IS_NEIGHBOURS_LEN;
165 length -= IS_NEIGHBOURS_LEN;
166
167 if (neigh->sub_tlvs_length > length)
168 {
169 zlog_warn("ISIS-TLV: neighbor subtlv length exceeds TLV size");
170 XFREE(MTYPE_ISIS_TLV, neigh);
171 return ISIS_WARNING;
172 }
173
174 memcpy(neigh->sub_tlvs, pnt, neigh->sub_tlvs_length);
175 pnt += neigh->sub_tlvs_length;
176 length -= neigh->sub_tlvs_length;
177
178 listnode_add(neigh_list, neigh);
179 }
180
181 if (length)
182 {
183 zlog_warn("ISIS-TLV: TE/MT neighor TLV has trailing data");
184 return ISIS_WARNING;
185 }
186
187 return ISIS_OK;
188}
189
c3ae3127
CF
190static int
191parse_mt_ipv4_reachs(struct tlvs *tlvs, bool read_mtid,
192 unsigned int length, u_char *pnt)
193{
194 struct list *reach_list;
195 uint16_t mtid;
196 int rv;
197
198 rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
199 if (rv != ISIS_OK)
200 return rv;
201
202 if (mtid == ISIS_MT_IPV4_UNICAST)
203 {
204 if (!tlvs->te_ipv4_reachs)
205 {
206 tlvs->te_ipv4_reachs = list_new();
207 tlvs->te_ipv4_reachs->del = free_tlv;
208 }
209 reach_list = tlvs->te_ipv4_reachs;
210 }
211 else
212 {
213 struct tlv_mt_ipv4_reachs *reachs;
214
215 reachs = tlvs_get_mt_ipv4_reachs(tlvs, mtid);
216 reachs->list->del = free_tlv;
217 reach_list = reachs->list;
218 }
219
220 while (length >= 5) /* Metric + Control */
221 {
222 struct te_ipv4_reachability *reach = XCALLOC(MTYPE_ISIS_TLV, TE_IPV4_REACH_LEN);
223
224 memcpy(reach, pnt, 5); /* Metric + Control */
225 pnt += 5;
226 length -= 5;
227
228 unsigned char prefixlen = reach->control & 0x3F;
229
230 if (prefixlen > IPV4_MAX_BITLEN)
231 {
232 zlog_warn("ISIS-TLV: invalid IPv4 extended reachability prefix length %d", prefixlen);
233 XFREE(MTYPE_ISIS_TLV, reach);
234 return ISIS_WARNING;
235 }
236
237 if (length < (unsigned int)PSIZE(prefixlen))
238 {
239 zlog_warn("ISIS-TLV: invalid IPv4 extended reachability prefix too long for tlv");
240 XFREE(MTYPE_ISIS_TLV, reach);
241 return ISIS_WARNING;
242 }
243
244 memcpy(&reach->prefix_start, pnt, PSIZE(prefixlen));
245 pnt += PSIZE(prefixlen);
246 length -= PSIZE(prefixlen);
247
248 if (reach->control & TE_IPV4_HAS_SUBTLV)
249 {
250 if (length < 1)
251 {
252 zlog_warn("ISIS-TLV: invalid IPv4 extended reachability SubTLV missing");
253 XFREE(MTYPE_ISIS_TLV, reach);
254 return ISIS_WARNING;
255 }
256
257 u_char subtlv_len = *pnt;
258 pnt++;
259 length--;
260
261 if (length < subtlv_len)
262 {
263 zlog_warn("ISIS-TLV: invalid IPv4 extended reachability SubTLVs have oversize");
264 XFREE(MTYPE_ISIS_TLV, reach);
265 return ISIS_WARNING;
266 }
267
268 /* Skip Sub-TLVs for now */
269 pnt += subtlv_len;
270 length -= subtlv_len;
271 }
272 listnode_add(reach_list, reach);
273 }
274
275 if (length)
276 {
277 zlog_warn("ISIS-TLV: TE/MT ipv4 reachability TLV has trailing data");
278 return ISIS_WARNING;
279 }
280
281 return ISIS_OK;
282}
283
284static int
285parse_mt_ipv6_reachs(struct tlvs *tlvs, bool read_mtid,
286 unsigned int length, u_char *pnt)
287{
288 struct list *reach_list;
289 uint16_t mtid;
290 int rv;
291
292 rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
293 if (rv != ISIS_OK)
294 return rv;
295
296 if (mtid == ISIS_MT_IPV4_UNICAST)
297 {
298 if (!tlvs->ipv6_reachs)
299 {
300 tlvs->ipv6_reachs = list_new();
301 tlvs->ipv6_reachs->del = free_tlv;
302 }
303 reach_list = tlvs->ipv6_reachs;
304 }
305 else
306 {
307 struct tlv_mt_ipv6_reachs *reachs;
308
309 reachs = tlvs_get_mt_ipv6_reachs(tlvs, mtid);
310 reachs->list->del = free_tlv;
311 reach_list = reachs->list;
312 }
313
314 while (length >= 6) /* Metric + Control + Prefixlen */
315 {
316 struct ipv6_reachability *reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*reach));
317
318 memcpy(reach, pnt, 6); /* Metric + Control + Prefixlen */
319 pnt += 6;
320 length -= 6;
321
322 if (reach->prefix_len > IPV6_MAX_BITLEN)
323 {
324 zlog_warn("ISIS-TLV: invalid IPv6 reachability prefix length %d", reach->prefix_len);
325 XFREE(MTYPE_ISIS_TLV, reach);
326 return ISIS_WARNING;
327 }
328
329 if (length < (unsigned int)PSIZE(reach->prefix_len))
330 {
331 zlog_warn("ISIS-TLV: invalid IPv6 reachability prefix too long for tlv");
332 XFREE(MTYPE_ISIS_TLV, reach);
333 return ISIS_WARNING;
334 }
335
336 memcpy(&reach->prefix, pnt, PSIZE(reach->prefix_len));
337 pnt += PSIZE(reach->prefix_len);
338 length -= PSIZE(reach->prefix_len);
339
340 if (reach->control_info & CTRL_INFO_SUBTLVS)
341 {
342 if (length < 1)
343 {
344 zlog_warn("ISIS-TLV: invalid IPv6 reachability SubTLV missing");
345 XFREE(MTYPE_ISIS_TLV, reach);
346 return ISIS_WARNING;
347 }
348
349 u_char subtlv_len = *pnt;
350 pnt++;
351 length--;
352
353 if (length < subtlv_len)
354 {
355 zlog_warn("ISIS-TLV: invalid IPv6 reachability SubTLVs have oversize");
356 XFREE(MTYPE_ISIS_TLV, reach);
357 return ISIS_WARNING;
358 }
359
360 /* Skip Sub-TLVs for now */
361 pnt += subtlv_len;
362 length -= subtlv_len;
363 }
364 listnode_add(reach_list, reach);
365 }
366
367 if (length)
368 {
369 zlog_warn("ISIS-TLV: (MT) IPv6 reachability TLV has trailing data");
370 return ISIS_WARNING;
371 }
372
373 return ISIS_OK;
374}
375
eb5d44eb 376/*
377 * Parses the tlvs found in the variant length part of the PDU.
378 * Caller tells with flags in "expected" which TLV's it is interested in.
379 */
f390d2c7 380int
381parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
3f045a08 382 u_int32_t * found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset)
eb5d44eb 383{
f390d2c7 384 u_char type, length;
385 struct lan_neigh *lan_nei;
386 struct area_addr *area_addr;
387 struct is_neigh *is_nei;
f390d2c7 388 struct es_neigh *es_nei;
389 struct lsp_entry *lsp_entry;
390 struct in_addr *ipv4_addr;
391 struct ipv4_reachability *ipv4_reach;
f390d2c7 392 struct in6_addr *ipv6_addr;
f390d2c7 393 int value_len, retval = ISIS_OK;
c3ae3127 394 u_char *start = stream, *pnt = stream;
eb5d44eb 395
396 *found = 0;
397 memset (tlvs, 0, sizeof (struct tlvs));
f390d2c7 398
399 while (pnt < stream + size - 2)
400 {
401 type = *pnt;
402 length = *(pnt + 1);
403 pnt += 2;
404 value_len = 0;
405 if (pnt + length > stream + size)
406 {
407 zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet "
408 "boundaries", areatag, type, length);
409 retval = ISIS_WARNING;
410 break;
411 }
412 switch (type)
413 {
414 case AREA_ADDRESSES:
415 /* +-------+-------+-------+-------+-------+-------+-------+-------+
416 * | Address Length |
417 * +-------+-------+-------+-------+-------+-------+-------+-------+
418 * | Area Address |
419 * +-------+-------+-------+-------+-------+-------+-------+-------+
420 * : :
421 */
422 *found |= TLVFLAG_AREA_ADDRS;
eb5d44eb 423#ifdef EXTREME_TLV_DEBUG
529d65b3 424 zlog_debug ("TLV Area Adresses len %d", length);
eb5d44eb 425#endif /* EXTREME_TLV_DEBUG */
f390d2c7 426 if (*expected & TLVFLAG_AREA_ADDRS)
427 {
428 while (length > value_len)
429 {
430 area_addr = (struct area_addr *) pnt;
431 value_len += area_addr->addr_len + 1;
432 pnt += area_addr->addr_len + 1;
433 if (!tlvs->area_addrs)
434 tlvs->area_addrs = list_new ();
435 listnode_add (tlvs->area_addrs, area_addr);
436 }
437 }
438 else
439 {
440 pnt += length;
441 }
442 break;
443
444 case IS_NEIGHBOURS:
445 *found |= TLVFLAG_IS_NEIGHS;
eb5d44eb 446#ifdef EXTREME_TLV_DEBUG
529d65b3 447 zlog_debug ("ISIS-TLV (%s): IS Neighbours length %d",
448 areatag, length);
eb5d44eb 449#endif /* EXTREME_TLV_DEBUG */
f390d2c7 450 if (TLVFLAG_IS_NEIGHS & *expected)
451 {
452 /* +-------+-------+-------+-------+-------+-------+-------+-------+
453 * | Virtual Flag |
454 * +-------+-------+-------+-------+-------+-------+-------+-------+
455 */
f390d2c7 456 pnt++;
457 value_len++;
458 /* +-------+-------+-------+-------+-------+-------+-------+-------+
459 * | 0 | I/E | Default Metric |
460 * +-------+-------+-------+-------+-------+-------+-------+-------+
461 * | S | I/E | Delay Metric |
462 * +-------+-------+-------+-------+-------+-------+-------+-------+
463 * | S | I/E | Expense Metric |
464 * +-------+-------+-------+-------+-------+-------+-------+-------+
465 * | S | I/E | Error Metric |
466 * +-------+-------+-------+-------+-------+-------+-------+-------+
467 * | Neighbour ID |
468 * +---------------------------------------------------------------+
469 * : :
470 */
471 while (length > value_len)
472 {
473 is_nei = (struct is_neigh *) pnt;
474 value_len += 4 + ISIS_SYS_ID_LEN + 1;
475 pnt += 4 + ISIS_SYS_ID_LEN + 1;
476 if (!tlvs->is_neighs)
477 tlvs->is_neighs = list_new ();
478 listnode_add (tlvs->is_neighs, is_nei);
479 }
480 }
481 else
482 {
483 pnt += length;
484 }
485 break;
486
487 case TE_IS_NEIGHBOURS:
f390d2c7 488 *found |= TLVFLAG_TE_IS_NEIGHS;
eb5d44eb 489#ifdef EXTREME_TLV_DEBUG
529d65b3 490 zlog_debug ("ISIS-TLV (%s): Extended IS Neighbours length %d",
f390d2c7 491 areatag, length);
eb5d44eb 492#endif /* EXTREME_TLV_DEBUG */
f390d2c7 493 if (TLVFLAG_TE_IS_NEIGHS & *expected)
206f4aae
CF
494 retval = parse_mt_is_neighs(tlvs, false, length, pnt);
495 pnt += length;
496 break;
497
498 case MT_IS_NEIGHBOURS:
499 *found |= TLVFLAG_TE_IS_NEIGHS;
500#ifdef EXTREME_TLV_DEBUG
501 zlog_debug ("ISIS-TLV (%s): MT IS Neighbours length %d",
502 areatag, length);
503#endif
504 if (TLVFLAG_TE_IS_NEIGHS & *expected)
505 retval = parse_mt_is_neighs(tlvs, true, length, pnt);
506 pnt += length;
f390d2c7 507 break;
508
509 case ES_NEIGHBOURS:
510 /* +-------+-------+-------+-------+-------+-------+-------+-------+
511 * | 0 | I/E | Default Metric |
512 * +-------+-------+-------+-------+-------+-------+-------+-------+
513 * | S | I/E | Delay Metric |
514 * +-------+-------+-------+-------+-------+-------+-------+-------+
515 * | S | I/E | Expense Metric |
516 * +-------+-------+-------+-------+-------+-------+-------+-------+
517 * | S | I/E | Error Metric |
518 * +-------+-------+-------+-------+-------+-------+-------+-------+
519 * | Neighbour ID |
520 * +---------------------------------------------------------------+
521 * | Neighbour ID |
522 * +---------------------------------------------------------------+
523 * : :
524 */
eb5d44eb 525#ifdef EXTREME_TLV_DEBUG
529d65b3 526 zlog_debug ("ISIS-TLV (%s): ES Neighbours length %d",
f390d2c7 527 areatag, length);
eb5d44eb 528#endif /* EXTREME_TLV_DEBUG */
f390d2c7 529 *found |= TLVFLAG_ES_NEIGHS;
530 if (*expected & TLVFLAG_ES_NEIGHS)
531 {
532 es_nei = (struct es_neigh *) pnt;
533 value_len += 4;
534 pnt += 4;
535 while (length > value_len)
536 {
537 /* FIXME FIXME FIXME - add to the list */
538 /* sys_id->id = pnt; */
539 value_len += ISIS_SYS_ID_LEN;
540 pnt += ISIS_SYS_ID_LEN;
541 /* if (!es_nei->neigh_ids) es_nei->neigh_ids = sysid; */
542 }
543 if (!tlvs->es_neighs)
544 tlvs->es_neighs = list_new ();
545 listnode_add (tlvs->es_neighs, es_nei);
546 }
547 else
548 {
549 pnt += length;
550 }
551 break;
552
553 case LAN_NEIGHBOURS:
554 /* +-------+-------+-------+-------+-------+-------+-------+-------+
555 * | LAN Address |
556 * +-------+-------+-------+-------+-------+-------+-------+-------+
557 * : :
558 */
559 *found |= TLVFLAG_LAN_NEIGHS;
eb5d44eb 560#ifdef EXTREME_TLV_DEBUG
529d65b3 561 zlog_debug ("ISIS-TLV (%s): LAN Neigbours length %d",
562 areatag, length);
eb5d44eb 563#endif /* EXTREME_TLV_DEBUG */
f390d2c7 564 if (TLVFLAG_LAN_NEIGHS & *expected)
565 {
566 while (length > value_len)
567 {
568 lan_nei = (struct lan_neigh *) pnt;
569 if (!tlvs->lan_neighs)
570 tlvs->lan_neighs = list_new ();
571 listnode_add (tlvs->lan_neighs, lan_nei);
572 value_len += ETH_ALEN;
573 pnt += ETH_ALEN;
574 }
575 }
576 else
577 {
578 pnt += length;
579 }
580 break;
581
582 case PADDING:
eb5d44eb 583#ifdef EXTREME_TLV_DEBUG
529d65b3 584 zlog_debug ("TLV padding %d", length);
eb5d44eb 585#endif /* EXTREME_TLV_DEBUG */
f390d2c7 586 pnt += length;
587 break;
588
589 case LSP_ENTRIES:
590 /* +-------+-------+-------+-------+-------+-------+-------+-------+
591 * | Remaining Lifetime | 2
592 * +-------+-------+-------+-------+-------+-------+-------+-------+
593 * | LSP ID | id+2
594 * +-------+-------+-------+-------+-------+-------+-------+-------+
595