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