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