Annotation of embedaddon/quagga/isisd/isis_pdu.c, revision 1.1
1.1 ! misho 1: /*
! 2: * IS-IS Rout(e)ing protocol - isis_pdu.c
! 3: * PDU processing
! 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 "memory.h"
! 27: #include "thread.h"
! 28: #include "linklist.h"
! 29: #include "log.h"
! 30: #include "stream.h"
! 31: #include "vty.h"
! 32: #include "hash.h"
! 33: #include "prefix.h"
! 34: #include "if.h"
! 35: #include "checksum.h"
! 36:
! 37: #include "isisd/dict.h"
! 38: #include "isisd/include-netbsd/iso.h"
! 39: #include "isisd/isis_constants.h"
! 40: #include "isisd/isis_common.h"
! 41: #include "isisd/isis_adjacency.h"
! 42: #include "isisd/isis_circuit.h"
! 43: #include "isisd/isis_network.h"
! 44: #include "isisd/isis_misc.h"
! 45: #include "isisd/isis_dr.h"
! 46: #include "isisd/isis_flags.h"
! 47: #include "isisd/isis_tlv.h"
! 48: #include "isisd/isisd.h"
! 49: #include "isisd/isis_dynhn.h"
! 50: #include "isisd/isis_lsp.h"
! 51: #include "isisd/isis_pdu.h"
! 52: #include "isisd/iso_checksum.h"
! 53: #include "isisd/isis_csm.h"
! 54: #include "isisd/isis_events.h"
! 55:
! 56: extern struct thread_master *master;
! 57: extern struct isis *isis;
! 58:
! 59: #define ISIS_MINIMUM_FIXED_HDR_LEN 15
! 60: #define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */
! 61:
! 62: #ifndef PNBBY
! 63: #define PNBBY 8
! 64: #endif /* PNBBY */
! 65:
! 66: /* Utility mask array. */
! 67: static const u_char maskbit[] = {
! 68: 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
! 69: };
! 70:
! 71: /*
! 72: * HELPER FUNCS
! 73: */
! 74:
! 75: /*
! 76: * Compares two sets of area addresses
! 77: */
! 78: static int
! 79: area_match (struct list *left, struct list *right)
! 80: {
! 81: struct area_addr *addr1, *addr2;
! 82: struct listnode *node1, *node2;
! 83:
! 84: for (ALL_LIST_ELEMENTS_RO (left, node1, addr1))
! 85: {
! 86: for (ALL_LIST_ELEMENTS_RO (right, node2, addr2))
! 87: {
! 88: if (addr1->addr_len == addr2->addr_len &&
! 89: !memcmp (addr1->area_addr, addr2->area_addr, (int) addr1->addr_len))
! 90: return 1; /* match */
! 91: }
! 92: }
! 93:
! 94: return 0; /* mismatch */
! 95: }
! 96:
! 97: /*
! 98: * Check if ip2 is in the ip1's network (function like Prefix.h:prefix_match() )
! 99: * param ip1 the IS interface ip address structure
! 100: * param ip2 the IIH's ip address
! 101: * return 0 the IIH's IP is not in the IS's subnetwork
! 102: * 1 the IIH's IP is in the IS's subnetwork
! 103: */
! 104: static int
! 105: ip_same_subnet (struct prefix_ipv4 *ip1, struct in_addr *ip2)
! 106: {
! 107: u_char *addr1, *addr2;
! 108: int shift, offset, offsetloop;
! 109: int len;
! 110:
! 111: addr1 = (u_char *) & ip1->prefix.s_addr;
! 112: addr2 = (u_char *) & ip2->s_addr;
! 113: len = ip1->prefixlen;
! 114:
! 115: shift = len % PNBBY;
! 116: offsetloop = offset = len / PNBBY;
! 117:
! 118: while (offsetloop--)
! 119: if (addr1[offsetloop] != addr2[offsetloop])
! 120: return 0;
! 121:
! 122: if (shift)
! 123: if (maskbit[shift] & (addr1[offset] ^ addr2[offset]))
! 124: return 0;
! 125:
! 126: return 1; /* match */
! 127: }
! 128:
! 129: /*
! 130: * Compares two set of ip addresses
! 131: * param left the local interface's ip addresses
! 132: * param right the iih interface's ip address
! 133: * return 0 no match;
! 134: * 1 match;
! 135: */
! 136: static int
! 137: ip_match (struct list *left, struct list *right)
! 138: {
! 139: struct prefix_ipv4 *ip1;
! 140: struct in_addr *ip2;
! 141: struct listnode *node1, *node2;
! 142:
! 143: if ((left == NULL) || (right == NULL))
! 144: return 0;
! 145:
! 146: for (ALL_LIST_ELEMENTS_RO (left, node1, ip1))
! 147: {
! 148: for (ALL_LIST_ELEMENTS_RO (right, node2, ip2))
! 149: {
! 150: if (ip_same_subnet (ip1, ip2))
! 151: {
! 152: return 1; /* match */
! 153: }
! 154: }
! 155:
! 156: }
! 157: return 0;
! 158: }
! 159:
! 160: /*
! 161: * Checks whether we should accept a PDU of given level
! 162: */
! 163: static int
! 164: accept_level (int level, int circuit_t)
! 165: {
! 166: int retval = ((circuit_t & level) == level); /* simple approach */
! 167:
! 168: return retval;
! 169: }
! 170:
! 171: int
! 172: authentication_check (struct isis_passwd *one, struct isis_passwd *theother)
! 173: {
! 174: if (one->type != theother->type)
! 175: {
! 176: zlog_warn ("Unsupported authentication type %d", theother->type);
! 177: return 1; /* Auth fail (different authentication types) */
! 178: }
! 179: switch (one->type)
! 180: {
! 181: case ISIS_PASSWD_TYPE_CLEARTXT:
! 182: if (one->len != theother->len)
! 183: return 1; /* Auth fail () - passwd len mismatch */
! 184: return memcmp (one->passwd, theother->passwd, one->len);
! 185: break;
! 186: default:
! 187: zlog_warn ("Unsupported authentication type");
! 188: break;
! 189: }
! 190: return 0; /* Auth pass */
! 191: }
! 192:
! 193: /*
! 194: * Processing helper functions
! 195: */
! 196: static void
! 197: tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj)
! 198: {
! 199: int i;
! 200: struct nlpids *tlv_nlpids;
! 201:
! 202: if (tlvs->nlpids)
! 203: {
! 204:
! 205: tlv_nlpids = tlvs->nlpids;
! 206:
! 207: adj->nlpids.count = tlv_nlpids->count;
! 208:
! 209: for (i = 0; i < tlv_nlpids->count; i++)
! 210: {
! 211: adj->nlpids.nlpids[i] = tlv_nlpids->nlpids[i];
! 212: }
! 213: }
! 214: }
! 215:
! 216: static void
! 217: del_ip_addr (void *val)
! 218: {
! 219: XFREE (MTYPE_ISIS_TMP, val);
! 220: }
! 221:
! 222: static void
! 223: tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
! 224: {
! 225: struct listnode *node;
! 226: struct in_addr *ipv4_addr, *malloced;
! 227:
! 228: if (adj->ipv4_addrs)
! 229: {
! 230: adj->ipv4_addrs->del = del_ip_addr;
! 231: list_delete (adj->ipv4_addrs);
! 232: }
! 233: adj->ipv4_addrs = list_new ();
! 234: if (tlvs->ipv4_addrs)
! 235: {
! 236: for (ALL_LIST_ELEMENTS_RO (tlvs->ipv4_addrs, node, ipv4_addr))
! 237: {
! 238: malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in_addr));
! 239: memcpy (malloced, ipv4_addr, sizeof (struct in_addr));
! 240: listnode_add (adj->ipv4_addrs, malloced);
! 241: }
! 242: }
! 243: }
! 244:
! 245: #ifdef HAVE_IPV6
! 246: static void
! 247: tlvs_to_adj_ipv6_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
! 248: {
! 249: struct listnode *node;
! 250: struct in6_addr *ipv6_addr, *malloced;
! 251:
! 252: if (adj->ipv6_addrs)
! 253: {
! 254: adj->ipv6_addrs->del = del_ip_addr;
! 255: list_delete (adj->ipv6_addrs);
! 256: }
! 257: adj->ipv6_addrs = list_new ();
! 258: if (tlvs->ipv6_addrs)
! 259: {
! 260: for (ALL_LIST_ELEMENTS_RO (tlvs->ipv6_addrs, node, ipv6_addr))
! 261: {
! 262: malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in6_addr));
! 263: memcpy (malloced, ipv6_addr, sizeof (struct in6_addr));
! 264: listnode_add (adj->ipv6_addrs, malloced);
! 265: }
! 266: }
! 267:
! 268: }
! 269: #endif /* HAVE_IPV6 */
! 270:
! 271: /*
! 272: * RECEIVE SIDE
! 273: */
! 274:
! 275: /*
! 276: * Process P2P IIH
! 277: * ISO - 10589
! 278: * Section 8.2.5 - Receiving point-to-point IIH PDUs
! 279: *
! 280: */
! 281: static int
! 282: process_p2p_hello (struct isis_circuit *circuit)
! 283: {
! 284: int retval = ISIS_OK;
! 285: struct isis_p2p_hello_hdr *hdr;
! 286: struct isis_adjacency *adj;
! 287: u_int32_t expected = 0, found;
! 288: struct tlvs tlvs;
! 289:
! 290: if ((stream_get_endp (circuit->rcv_stream) -
! 291: stream_get_getp (circuit->rcv_stream)) < ISIS_P2PHELLO_HDRLEN)
! 292: {
! 293: zlog_warn ("Packet too short");
! 294: return ISIS_WARNING;
! 295: }
! 296:
! 297: /* 8.2.5.1 PDU acceptance tests */
! 298:
! 299: /* 8.2.5.1 a) external domain untrue */
! 300: /* FIXME: not useful at all? */
! 301:
! 302: /* 8.2.5.1 b) ID Length mismatch */
! 303: /* checked at the handle_pdu */
! 304:
! 305: /* 8.2.5.2 IIH PDU Processing */
! 306:
! 307: /* 8.2.5.2 a) 1) Maximum Area Addresses */
! 308: /* Already checked, and can also be ommited */
! 309:
! 310: /*
! 311: * Get the header
! 312: */
! 313: hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream);
! 314: circuit->rcv_stream->getp += ISIS_P2PHELLO_HDRLEN;
! 315:
! 316: /* hdr.circuit_t = stream_getc (stream);
! 317: stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN);
! 318: hdr.hold_time = stream_getw (stream);
! 319: hdr.pdu_len = stream_getw (stream);
! 320: hdr.local_id = stream_getc (stream); */
! 321:
! 322: /*
! 323: * My interpertation of the ISO, if no adj exists we will create one for
! 324: * the circuit
! 325: */
! 326:
! 327: if (isis->debugs & DEBUG_ADJ_PACKETS)
! 328: {
! 329: zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
! 330: " cir id %02d, length %d",
! 331: circuit->area->area_tag, circuit->interface->name,
! 332: circuit_t2string (circuit->circuit_is_type),
! 333: circuit->circuit_id, ntohs (hdr->pdu_len));
! 334: }
! 335:
! 336: adj = circuit->u.p2p.neighbor;
! 337: if (!adj)
! 338: {
! 339: adj = isis_new_adj (hdr->source_id, NULL, 0, circuit);
! 340: if (adj == NULL)
! 341: return ISIS_ERROR;
! 342: circuit->u.p2p.neighbor = adj;
! 343: isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
! 344: adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
! 345: }
! 346:
! 347: /* 8.2.6 Monitoring point-to-point adjacencies */
! 348: adj->hold_time = ntohs (hdr->hold_time);
! 349: adj->last_upd = time (NULL);
! 350:
! 351: /*
! 352: * Lets get the TLVS now
! 353: */
! 354: expected |= TLVFLAG_AREA_ADDRS;
! 355: expected |= TLVFLAG_AUTH_INFO;
! 356: expected |= TLVFLAG_NLPID;
! 357: expected |= TLVFLAG_IPV4_ADDR;
! 358: expected |= TLVFLAG_IPV6_ADDR;
! 359:
! 360: retval = parse_tlvs (circuit->area->area_tag,
! 361: STREAM_PNT (circuit->rcv_stream),
! 362: ntohs (hdr->pdu_len) - ISIS_P2PHELLO_HDRLEN
! 363: - ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs);
! 364:
! 365: if (retval > ISIS_WARNING)
! 366: {
! 367: free_tlvs (&tlvs);
! 368: return retval;
! 369: };
! 370:
! 371: /* 8.2.5.1 c) Authentication */
! 372: if (circuit->passwd.type)
! 373: {
! 374: if (!(found & TLVFLAG_AUTH_INFO) ||
! 375: authentication_check (&circuit->passwd, &tlvs.auth_info))
! 376: {
! 377: isis_event_auth_failure (circuit->area->area_tag,
! 378: "P2P hello authentication failure",
! 379: hdr->source_id);
! 380: return ISIS_OK;
! 381: }
! 382: }
! 383:
! 384: /* we do this now because the adj may not survive till the end... */
! 385:
! 386: /* we need to copy addresses to the adj */
! 387: tlvs_to_adj_ipv4_addrs (&tlvs, adj);
! 388:
! 389: #ifdef HAVE_IPV6
! 390: tlvs_to_adj_ipv6_addrs (&tlvs, adj);
! 391: #endif /* HAVE_IPV6 */
! 392:
! 393: /* lets take care of the expiry */
! 394: THREAD_TIMER_OFF (adj->t_expire);
! 395: THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
! 396: (long) adj->hold_time);
! 397:
! 398: /* 8.2.5.2 a) a match was detected */
! 399: if (area_match (circuit->area->area_addrs, tlvs.area_addrs))
! 400: {
! 401: /* 8.2.5.2 a) 2) If the system is L1 - table 5 */
! 402: if (circuit->area->is_type == IS_LEVEL_1)
! 403: {
! 404: switch (hdr->circuit_t)
! 405: {
! 406: case IS_LEVEL_1:
! 407: case IS_LEVEL_1_AND_2:
! 408: if (adj->adj_state != ISIS_ADJ_UP)
! 409: {
! 410: /* (4) adj state up */
! 411: isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
! 412: /* (5) adj usage level 1 */
! 413: adj->adj_usage = ISIS_ADJ_LEVEL1;
! 414: }
! 415: else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
! 416: {
! 417: ; /* accept */
! 418: }
! 419: break;
! 420: case IS_LEVEL_2:
! 421: if (adj->adj_state != ISIS_ADJ_UP)
! 422: {
! 423: /* (7) reject - wrong system type event */
! 424: zlog_warn ("wrongSystemType");
! 425: return ISIS_WARNING; /* Reject */
! 426: }
! 427: else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
! 428: {
! 429: /* (6) down - wrong system */
! 430: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
! 431: }
! 432: break;
! 433: }
! 434: }
! 435:
! 436: /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */
! 437: if (circuit->area->is_type == IS_LEVEL_1_AND_2)
! 438: {
! 439: switch (hdr->circuit_t)
! 440: {
! 441: case IS_LEVEL_1:
! 442: if (adj->adj_state != ISIS_ADJ_UP)
! 443: {
! 444: /* (6) adj state up */
! 445: isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
! 446: /* (7) adj usage level 1 */
! 447: adj->adj_usage = ISIS_ADJ_LEVEL1;
! 448: }
! 449: else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
! 450: {
! 451: ; /* accept */
! 452: }
! 453: else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
! 454: (adj->adj_usage == ISIS_ADJ_LEVEL2))
! 455: {
! 456: /* (8) down - wrong system */
! 457: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
! 458: }
! 459: break;
! 460: case IS_LEVEL_2:
! 461: if (adj->adj_state != ISIS_ADJ_UP)
! 462: {
! 463: /* (6) adj state up */
! 464: isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
! 465: /* (9) adj usage level 2 */
! 466: adj->adj_usage = ISIS_ADJ_LEVEL2;
! 467: }
! 468: else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) ||
! 469: (adj->adj_usage == ISIS_ADJ_LEVEL1AND2))
! 470: {
! 471: /* (8) down - wrong system */
! 472: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
! 473: }
! 474: else if (adj->adj_usage == ISIS_ADJ_LEVEL2)
! 475: {
! 476: ; /* Accept */
! 477: }
! 478: break;
! 479: case IS_LEVEL_1_AND_2:
! 480: if (adj->adj_state != ISIS_ADJ_UP)
! 481: {
! 482: /* (6) adj state up */
! 483: isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
! 484: /* (10) adj usage level 1 */
! 485: adj->adj_usage = ISIS_ADJ_LEVEL1AND2;
! 486: }
! 487: else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) ||
! 488: (adj->adj_usage == ISIS_ADJ_LEVEL2))
! 489: {
! 490: /* (8) down - wrong system */
! 491: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
! 492: }
! 493: else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
! 494: {
! 495: ; /* Accept */
! 496: }
! 497: break;
! 498: }
! 499: }
! 500:
! 501: /* 8.2.5.2 a) 4) If the system is L2 - table 7 */
! 502: if (circuit->area->is_type == IS_LEVEL_2)
! 503: {
! 504: switch (hdr->circuit_t)
! 505: {
! 506: case IS_LEVEL_1:
! 507: if (adj->adj_state != ISIS_ADJ_UP)
! 508: {
! 509: /* (5) reject - wrong system type event */
! 510: zlog_warn ("wrongSystemType");
! 511: return ISIS_WARNING; /* Reject */
! 512: }
! 513: else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
! 514: (adj->adj_usage == ISIS_ADJ_LEVEL2))
! 515: {
! 516: /* (6) down - wrong system */
! 517: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
! 518: }
! 519: break;
! 520: case IS_LEVEL_1_AND_2:
! 521: case IS_LEVEL_2:
! 522: if (adj->adj_state != ISIS_ADJ_UP)
! 523: {
! 524: /* (7) adj state up */
! 525: isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
! 526: /* (8) adj usage level 2 */
! 527: adj->adj_usage = ISIS_ADJ_LEVEL2;
! 528: }
! 529: else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
! 530: {
! 531: /* (6) down - wrong system */
! 532: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
! 533: }
! 534: else if (adj->adj_usage == ISIS_ADJ_LEVEL2)
! 535: {
! 536: ; /* Accept */
! 537: }
! 538: break;
! 539: }
! 540: }
! 541: }
! 542: /* 8.2.5.2 b) if no match was detected */
! 543: else
! 544: {
! 545: if (circuit->area->is_type == IS_LEVEL_1)
! 546: {
! 547: /* 8.2.5.2 b) 1) is_type L1 and adj is not up */
! 548: if (adj->adj_state != ISIS_ADJ_UP)
! 549: {
! 550: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
! 551: /* 8.2.5.2 b) 2)is_type L1 and adj is up */
! 552: }
! 553: else
! 554: {
! 555: isis_adj_state_change (adj, ISIS_ADJ_DOWN,
! 556: "Down - Area Mismatch");
! 557: }
! 558: }
! 559: /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */
! 560: else
! 561: {
! 562: switch (hdr->circuit_t)
! 563: {
! 564: case IS_LEVEL_1:
! 565: if (adj->adj_state != ISIS_ADJ_UP)
! 566: {
! 567: /* (6) reject - Area Mismatch event */
! 568: zlog_warn ("AreaMismatch");
! 569: return ISIS_WARNING; /* Reject */
! 570: }
! 571: else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
! 572: {
! 573: /* (7) down - area mismatch */
! 574: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
! 575:
! 576: }
! 577: else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
! 578: (adj->adj_usage == ISIS_ADJ_LEVEL2))
! 579: {
! 580: /* (7) down - wrong system */
! 581: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
! 582: }
! 583: break;
! 584: case IS_LEVEL_1_AND_2:
! 585: case IS_LEVEL_2:
! 586: if (adj->adj_state != ISIS_ADJ_UP)
! 587: {
! 588: /* (8) adj state up */
! 589: isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
! 590: /* (9) adj usage level 2 */
! 591: adj->adj_usage = ISIS_ADJ_LEVEL2;
! 592: }
! 593: else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
! 594: {
! 595: /* (7) down - wrong system */
! 596: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
! 597: }
! 598: else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
! 599: {
! 600: if (hdr->circuit_t == IS_LEVEL_2)
! 601: {
! 602: /* (7) down - wrong system */
! 603: isis_adj_state_change (adj, ISIS_ADJ_DOWN,
! 604: "Wrong System");
! 605: }
! 606: else
! 607: {
! 608: /* (7) down - area mismatch */
! 609: isis_adj_state_change (adj, ISIS_ADJ_DOWN,
! 610: "Area Mismatch");
! 611: }
! 612: }
! 613: else if (adj->adj_usage == ISIS_ADJ_LEVEL2)
! 614: {
! 615: ; /* Accept */
! 616: }
! 617: break;
! 618: }
! 619: }
! 620: }
! 621: /* 8.2.5.2 c) if the action was up - comparing circuit IDs */
! 622: /* FIXME - Missing parts */
! 623:
! 624: /* some of my own understanding of the ISO, why the heck does
! 625: * it not say what should I change the system_type to...
! 626: */
! 627: switch (adj->adj_usage)
! 628: {
! 629: case ISIS_ADJ_LEVEL1:
! 630: adj->sys_type = ISIS_SYSTYPE_L1_IS;
! 631: break;
! 632: case ISIS_ADJ_LEVEL2:
! 633: adj->sys_type = ISIS_SYSTYPE_L2_IS;
! 634: break;
! 635: case ISIS_ADJ_LEVEL1AND2:
! 636: adj->sys_type = ISIS_SYSTYPE_L2_IS;
! 637: break;
! 638: case ISIS_ADJ_NONE:
! 639: adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
! 640: break;
! 641: }
! 642:
! 643: adj->circuit_t = hdr->circuit_t;
! 644: adj->level = hdr->circuit_t;
! 645:
! 646: free_tlvs (&tlvs);
! 647:
! 648: return retval;
! 649: }
! 650:
! 651: /*
! 652: * Process IS-IS LAN Level 1/2 Hello PDU
! 653: */
! 654: static int
! 655: process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
! 656: {
! 657: int retval = ISIS_OK;
! 658: struct isis_lan_hello_hdr hdr;
! 659: struct isis_adjacency *adj;
! 660: u_int32_t expected = 0, found;
! 661: struct tlvs tlvs;
! 662: u_char *snpa;
! 663: struct listnode *node;
! 664:
! 665: if ((stream_get_endp (circuit->rcv_stream) -
! 666: stream_get_getp (circuit->rcv_stream)) < ISIS_LANHELLO_HDRLEN)
! 667: {
! 668: zlog_warn ("Packet too short");
! 669: return ISIS_WARNING;
! 670: }
! 671:
! 672: if (circuit->ext_domain)
! 673: {
! 674: zlog_debug ("level %d LAN Hello received over circuit with "
! 675: "externalDomain = true", level);
! 676: return ISIS_WARNING;
! 677: }
! 678:
! 679: if (!accept_level (level, circuit->circuit_is_type))
! 680: {
! 681: if (isis->debugs & DEBUG_ADJ_PACKETS)
! 682: {
! 683: zlog_debug ("ISIS-Adj (%s): Interface level mismatch, %s",
! 684: circuit->area->area_tag, circuit->interface->name);
! 685: }
! 686: return ISIS_WARNING;
! 687: }
! 688:
! 689: #if 0
! 690: /* Cisco's debug message compatability */
! 691: if (!accept_level (level, circuit->area->is_type))
! 692: {
! 693: if (isis->debugs & DEBUG_ADJ_PACKETS)
! 694: {
! 695: zlog_debug ("ISIS-Adj (%s): is type mismatch",
! 696: circuit->area->area_tag);
! 697: }
! 698: return ISIS_WARNING;
! 699: }
! 700: #endif
! 701: /*
! 702: * Fill the header
! 703: */
! 704: hdr.circuit_t = stream_getc (circuit->rcv_stream);
! 705: stream_get (hdr.source_id, circuit->rcv_stream, ISIS_SYS_ID_LEN);
! 706: hdr.hold_time = stream_getw (circuit->rcv_stream);
! 707: hdr.pdu_len = stream_getw (circuit->rcv_stream);
! 708: hdr.prio = stream_getc (circuit->rcv_stream);
! 709: stream_get (hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1);
! 710:
! 711: if (hdr.circuit_t != IS_LEVEL_1 && hdr.circuit_t != IS_LEVEL_2 &&
! 712: hdr.circuit_t != IS_LEVEL_1_AND_2)
! 713: {
! 714: zlog_warn ("Level %d LAN Hello with Circuit Type %d", level,
! 715: hdr.circuit_t);
! 716: return ISIS_ERROR;
! 717: }
! 718: /*
! 719: * Then get the tlvs
! 720: */
! 721: expected |= TLVFLAG_AUTH_INFO;
! 722: expected |= TLVFLAG_AREA_ADDRS;
! 723: expected |= TLVFLAG_LAN_NEIGHS;
! 724: expected |= TLVFLAG_NLPID;
! 725: expected |= TLVFLAG_IPV4_ADDR;
! 726: expected |= TLVFLAG_IPV6_ADDR;
! 727:
! 728: retval = parse_tlvs (circuit->area->area_tag,
! 729: STREAM_PNT (circuit->rcv_stream),
! 730: hdr.pdu_len - ISIS_LANHELLO_HDRLEN -
! 731: ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs);
! 732:
! 733: if (retval > ISIS_WARNING)
! 734: {
! 735: zlog_warn ("parse_tlvs() failed");
! 736: goto out;
! 737: }
! 738:
! 739: if (!(found & TLVFLAG_AREA_ADDRS))
! 740: {
! 741: zlog_warn ("No Area addresses TLV in Level %d LAN IS to IS hello",
! 742: level);
! 743: retval = ISIS_WARNING;
! 744: goto out;
! 745: }
! 746:
! 747: if (circuit->passwd.type)
! 748: {
! 749: if (!(found & TLVFLAG_AUTH_INFO) ||
! 750: authentication_check (&circuit->passwd, &tlvs.auth_info))
! 751: {
! 752: isis_event_auth_failure (circuit->area->area_tag,
! 753: "LAN hello authentication failure",
! 754: hdr.source_id);
! 755: retval = ISIS_WARNING;
! 756: goto out;
! 757: }
! 758: }
! 759:
! 760: /*
! 761: * Accept the level 1 adjacency only if a match between local and
! 762: * remote area addresses is found
! 763: */
! 764: if (level == 1 && !area_match (circuit->area->area_addrs, tlvs.area_addrs))
! 765: {
! 766: if (isis->debugs & DEBUG_ADJ_PACKETS)
! 767: {
! 768: zlog_debug ("ISIS-Adj (%s): Area mismatch, level %d IIH on %s",
! 769: circuit->area->area_tag, level,
! 770: circuit->interface->name);
! 771: }
! 772: retval = ISIS_OK;
! 773: goto out;
! 774: }
! 775:
! 776: /*
! 777: * it's own IIH PDU - discard silently
! 778: */
! 779: if (!memcmp (circuit->u.bc.snpa, ssnpa, ETH_ALEN))
! 780: {
! 781: zlog_debug ("ISIS-Adj (%s): it's own IIH PDU - discarded",
! 782: circuit->area->area_tag);
! 783:
! 784: retval = ISIS_OK;
! 785: goto out;
! 786: }
! 787:
! 788: /*
! 789: * check if it's own interface ip match iih ip addrs
! 790: */
! 791: if (!(found & TLVFLAG_IPV4_ADDR)
! 792: || !ip_match (circuit->ip_addrs, tlvs.ipv4_addrs))
! 793: {
! 794: zlog_debug
! 795: ("ISIS-Adj: No usable IP interface addresses in LAN IIH from %s\n",
! 796: circuit->interface->name);
! 797: retval = ISIS_WARNING;
! 798: goto out;
! 799: }
! 800:
! 801: adj = isis_adj_lookup (hdr.source_id, circuit->u.bc.adjdb[level - 1]);
! 802: if (!adj)
! 803: {
! 804: /*
! 805: * Do as in 8.4.2.5
! 806: */
! 807: adj = isis_new_adj (hdr.source_id, ssnpa, level, circuit);
! 808: if (adj == NULL)
! 809: {
! 810: retval = ISIS_ERROR;
! 811: goto out;
! 812: }
! 813:
! 814: adj->level = level;
! 815: isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
! 816:
! 817: if (level == 1)
! 818: {
! 819: adj->sys_type = ISIS_SYSTYPE_L1_IS;
! 820: }
! 821: else
! 822: {
! 823: adj->sys_type = ISIS_SYSTYPE_L2_IS;
! 824: }
! 825: list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
! 826: isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
! 827: circuit->u.bc.lan_neighs[level - 1]);
! 828: }
! 829:
! 830: if(adj->dis_record[level-1].dis==ISIS_IS_DIS)
! 831: switch (level)
! 832: {
! 833: case 1:
! 834: if (memcmp (circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1))
! 835: {
! 836: thread_add_event (master, isis_event_dis_status_change, circuit, 0);
! 837: memcpy (&circuit->u.bc.l1_desig_is, hdr.lan_id,
! 838: ISIS_SYS_ID_LEN + 1);
! 839: }
! 840: break;
! 841: case 2:
! 842: if (memcmp (circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1))
! 843: {
! 844: thread_add_event (master, isis_event_dis_status_change, circuit, 0);
! 845: memcpy (&circuit->u.bc.l2_desig_is, hdr.lan_id,
! 846: ISIS_SYS_ID_LEN + 1);
! 847: }
! 848: break;
! 849: }
! 850:
! 851: adj->hold_time = hdr.hold_time;
! 852: adj->last_upd = time (NULL);
! 853: adj->prio[level - 1] = hdr.prio;
! 854:
! 855: memcpy (adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
! 856:
! 857: /* which protocol are spoken ??? */
! 858: if (found & TLVFLAG_NLPID)
! 859: tlvs_to_adj_nlpids (&tlvs, adj);
! 860:
! 861: /* we need to copy addresses to the adj */
! 862: if (found & TLVFLAG_IPV4_ADDR)
! 863: tlvs_to_adj_ipv4_addrs (&tlvs, adj);
! 864:
! 865: #ifdef HAVE_IPV6
! 866: if (found & TLVFLAG_IPV6_ADDR)
! 867: tlvs_to_adj_ipv6_addrs (&tlvs, adj);
! 868: #endif /* HAVE_IPV6 */
! 869:
! 870: adj->circuit_t = hdr.circuit_t;
! 871:
! 872: /* lets take care of the expiry */
! 873: THREAD_TIMER_OFF (adj->t_expire);
! 874: THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
! 875: (long) adj->hold_time);
! 876:
! 877: /*
! 878: * If the snpa for this circuit is found from LAN Neighbours TLV
! 879: * we have two-way communication -> adjacency can be put to state "up"
! 880: */
! 881:
! 882: if (found & TLVFLAG_LAN_NEIGHS)
! 883: {
! 884: if (adj->adj_state != ISIS_ADJ_UP)
! 885: {
! 886: for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa))
! 887: if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))
! 888: {
! 889: isis_adj_state_change (adj, ISIS_ADJ_UP,
! 890: "own SNPA found in LAN Neighbours TLV");
! 891: }
! 892: }
! 893: }
! 894:
! 895: out:
! 896: /* DEBUG_ADJ_PACKETS */
! 897: if (isis->debugs & DEBUG_ADJ_PACKETS)
! 898: {
! 899: /* FIXME: is this place right? fix missing info */
! 900: zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "
! 901: "cirID %u, length %ld",
! 902: circuit->area->area_tag,
! 903: level, snpa_print (ssnpa), circuit->interface->name,
! 904: circuit_t2string (circuit->circuit_is_type),
! 905: circuit->circuit_id,
! 906: /* FIXME: use %z when we stop supporting old compilers. */
! 907: (unsigned long) stream_get_endp (circuit->rcv_stream));
! 908: }
! 909:
! 910: free_tlvs (&tlvs);
! 911:
! 912: return retval;
! 913: }
! 914:
! 915: /*
! 916: * Process Level 1/2 Link State
! 917: * ISO - 10589
! 918: * Section 7.3.15.1 - Action on receipt of a link state PDU
! 919: */
! 920: static int
! 921: process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)
! 922: {
! 923: struct isis_link_state_hdr *hdr;
! 924: struct isis_adjacency *adj = NULL;
! 925: struct isis_lsp *lsp, *lsp0 = NULL;
! 926: int retval = ISIS_OK, comp = 0;
! 927: u_char lspid[ISIS_SYS_ID_LEN + 2];
! 928: struct isis_passwd *passwd;
! 929:
! 930: /* Sanity check - FIXME: move to correct place */
! 931: if ((stream_get_endp (circuit->rcv_stream) -
! 932: stream_get_getp (circuit->rcv_stream)) < ISIS_LSP_HDR_LEN)
! 933: {
! 934: zlog_warn ("Packet too short");
! 935: return ISIS_WARNING;
! 936: }
! 937:
! 938: /* Reference the header */
! 939: hdr = (struct isis_link_state_hdr *) STREAM_PNT (circuit->rcv_stream);
! 940:
! 941: if (isis->debugs & DEBUG_UPDATE_PACKETS)
! 942: {
! 943: zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "
! 944: "lifetime %us, len %lu, on %s",
! 945: circuit->area->area_tag,
! 946: level,
! 947: rawlspid_print (hdr->lsp_id),
! 948: ntohl (hdr->seq_num),
! 949: ntohs (hdr->checksum),
! 950: ntohs (hdr->rem_lifetime),
! 951: /* FIXME: use %z when we stop supporting old compilers. */
! 952: (unsigned long) stream_get_endp (circuit->rcv_stream),
! 953: circuit->interface->name);
! 954: }
! 955:
! 956: assert (ntohs (hdr->pdu_len) > ISIS_LSP_HDR_LEN);
! 957:
! 958: /* Checksum sanity check - FIXME: move to correct place */
! 959: /* 12 = sysid+pdu+remtime */
! 960: if (iso_csum_verify (STREAM_PNT (circuit->rcv_stream) + 4,
! 961: ntohs (hdr->pdu_len) - 12, &hdr->checksum))
! 962: {
! 963: zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
! 964: circuit->area->area_tag,
! 965: rawlspid_print (hdr->lsp_id), ntohs (hdr->checksum));
! 966:
! 967: return ISIS_WARNING;
! 968: }
! 969:
! 970: /* 7.3.15.1 a) 1 - external domain circuit will discard lsps */
! 971: if (circuit->ext_domain)
! 972: {
! 973: zlog_debug
! 974: ("ISIS-Upd (%s): LSP %s received at level %d over circuit with "
! 975: "externalDomain = true", circuit->area->area_tag,
! 976: rawlspid_print (hdr->lsp_id), level);
! 977:
! 978: return ISIS_WARNING;
! 979: }
! 980:
! 981: /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
! 982: if (!accept_level (level, circuit->circuit_is_type))
! 983: {
! 984: zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of"
! 985: " type %s",
! 986: circuit->area->area_tag,
! 987: rawlspid_print (hdr->lsp_id),
! 988: level, circuit_t2string (circuit->circuit_is_type));
! 989:
! 990: return ISIS_WARNING;
! 991: }
! 992:
! 993: /* 7.3.15.1 a) 4 - need to make sure IDLength matches */
! 994:
! 995: /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */
! 996:
! 997: /* 7.3.15.1 a) 7 - password check */
! 998: (level == ISIS_LEVEL1) ? (passwd = &circuit->area->area_passwd) :
! 999: (passwd = &circuit->area->domain_passwd);
! 1000: if (passwd->type)
! 1001: {
! 1002: if (isis_lsp_authinfo_check (circuit->rcv_stream, circuit->area,
! 1003: ntohs (hdr->pdu_len), passwd))
! 1004: {
! 1005: isis_event_auth_failure (circuit->area->area_tag,
! 1006: "LSP authentication failure", hdr->lsp_id);
! 1007: return ISIS_WARNING;
! 1008: }
! 1009: }
! 1010: /* Find the LSP in our database and compare it to this Link State header */
! 1011: lsp = lsp_search (hdr->lsp_id, circuit->area->lspdb[level - 1]);
! 1012: if (lsp)
! 1013: comp = lsp_compare (circuit->area->area_tag, lsp, hdr->seq_num,
! 1014: hdr->checksum, hdr->rem_lifetime);
! 1015: if (lsp && (lsp->own_lsp
! 1016: #ifdef TOPOLOGY_GENERATE
! 1017: || lsp->from_topology
! 1018: #endif /* TOPOLOGY_GENERATE */
! 1019: ))
! 1020: goto dontcheckadj;
! 1021:
! 1022: /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level */
! 1023: /* for broadcast circuits, snpa should be compared */
! 1024: /* FIXME : Point To Point */
! 1025:
! 1026: if (circuit->circ_type == CIRCUIT_T_BROADCAST)
! 1027: {
! 1028: adj = isis_adj_lookup_snpa (ssnpa, circuit->u.bc.adjdb[level - 1]);
! 1029: if (!adj)
! 1030: {
! 1031: zlog_debug ("(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, "
! 1032: "lifetime %us on %s",
! 1033: circuit->area->area_tag,
! 1034: rawlspid_print (hdr->lsp_id),
! 1035: ntohl (hdr->seq_num),
! 1036: ntohs (hdr->checksum),
! 1037: ntohs (hdr->rem_lifetime), circuit->interface->name);
! 1038: return ISIS_WARNING; /* Silently discard */
! 1039: }
! 1040: }
! 1041:
! 1042: /* for non broadcast, we just need to find same level adj */
! 1043: else
! 1044: {
! 1045: /* If no adj, or no sharing of level */
! 1046: if (!circuit->u.p2p.neighbor)
! 1047: {
! 1048: return ISIS_OK; /* Silently discard */
! 1049: }
! 1050: else
! 1051: {
! 1052: if (((level == 1) &&
! 1053: (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL2)) ||
! 1054: ((level == 2) &&
! 1055: (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL1)))
! 1056: return ISIS_WARNING; /* Silently discard */
! 1057: }
! 1058: }
! 1059: dontcheckadj:
! 1060: /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */
! 1061:
! 1062: /* 7.3.15.1 a) 8 - Passwords for level 2 - not implemented */
! 1063:
! 1064: /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented FIXME: do it */
! 1065:
! 1066: /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */
! 1067: if (hdr->rem_lifetime == 0)
! 1068: {
! 1069: if (!lsp)
! 1070: {
! 1071: /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't save */
! 1072: /* only needed on explicit update, eg - p2p */
! 1073: if (circuit->circ_type == CIRCUIT_T_P2P)
! 1074: ack_lsp (hdr, circuit, level);
! 1075: return retval; /* FIXME: do we need a purge? */
! 1076: }
! 1077: else
! 1078: {
! 1079: if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN))
! 1080: {
! 1081: /* LSP by some other system -> do 7.3.16.4 b) */
! 1082: /* 7.3.16.4 b) 1) */
! 1083: if (comp == LSP_NEWER)
! 1084: {
! 1085: lsp_update (lsp, hdr, circuit->rcv_stream, circuit->area,
! 1086: level);
! 1087: /* ii */
! 1088: ISIS_FLAGS_SET_ALL (lsp->SRMflags);
! 1089: /* iii */
! 1090: ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
! 1091: /* v */
! 1092: ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags); /* FIXME: OTHER than c */
! 1093: /* iv */
! 1094: if (circuit->circ_type != CIRCUIT_T_BROADCAST)
! 1095: ISIS_SET_FLAG (lsp->SSNflags, circuit);
! 1096:
! 1097: } /* 7.3.16.4 b) 2) */
! 1098: else if (comp == LSP_EQUAL)
! 1099: {
! 1100: /* i */
! 1101: ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
! 1102: /* ii */
! 1103: if (circuit->circ_type != CIRCUIT_T_BROADCAST)
! 1104: ISIS_SET_FLAG (lsp->SSNflags, circuit);
! 1105: } /* 7.3.16.4 b) 3) */
! 1106: else
! 1107: {
! 1108: ISIS_SET_FLAG (lsp->SRMflags, circuit);
! 1109: ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
! 1110: }
! 1111: }
! 1112: else
! 1113: {
! 1114: /* our own LSP -> 7.3.16.4 c) */
! 1115: if (LSP_PSEUDO_ID (lsp->lsp_header->lsp_id) !=
! 1116: circuit->circuit_id
! 1117: || (LSP_PSEUDO_ID (lsp->lsp_header->lsp_id) ==
! 1118: circuit->circuit_id
! 1119: && circuit->u.bc.is_dr[level - 1] == 1))
! 1120: {
! 1121: lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1);
! 1122: if (isis->debugs & DEBUG_UPDATE_PACKETS)
! 1123: zlog_debug ("LSP LEN: %d",
! 1124: ntohs (lsp->lsp_header->pdu_len));
! 1125: fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
! 1126: ntohs (lsp->lsp_header->pdu_len) - 12, 12);
! 1127: ISIS_FLAGS_SET_ALL (lsp->SRMflags);
! 1128: if (isis->debugs & DEBUG_UPDATE_PACKETS)
! 1129: zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new "
! 1130: "seq 0x%08x", circuit->area->area_tag,
! 1131: rawlspid_print (hdr->lsp_id),
! 1132: ntohl (lsp->lsp_header->seq_num));
! 1133: lsp->lsp_header->rem_lifetime =
! 1134: htons (isis_jitter
! 1135: (circuit->area->max_lsp_lifetime[level - 1],
! 1136: MAX_AGE_JITTER));
! 1137: }
! 1138: else
! 1139: {
! 1140: /* Got purge for own pseudo-lsp, and we are not DR */
! 1141: lsp_purge_dr (lsp->lsp_header->lsp_id, circuit, level);
! 1142: }
! 1143: }
! 1144: }
! 1145: return retval;
! 1146: }
! 1147: /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a
! 1148: * purge */
! 1149: if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN) == 0)
! 1150: {
! 1151: if (!lsp)
! 1152: {
! 1153: /* 7.3.16.4: initiate a purge */
! 1154: lsp_purge_non_exist (hdr, circuit->area);
! 1155: return ISIS_OK;
! 1156: }
! 1157: /* 7.3.15.1 d) - If this is our own lsp and we have it */
! 1158:
! 1159: /* In 7.3.16.1, If an Intermediate system R somewhere in the domain
! 1160: * has information that the current sequence number for source S is
! 1161: * "greater" than that held by S, ... */
! 1162:
! 1163: else if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num))
! 1164: {
! 1165: /* 7.3.16.1 */
! 1166: lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1);
! 1167:
! 1168: fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
! 1169: ntohs (lsp->lsp_header->pdu_len) - 12, 12);
! 1170:
! 1171: ISIS_FLAGS_SET_ALL (lsp->SRMflags);
! 1172: if (isis->debugs & DEBUG_UPDATE_PACKETS)
! 1173: zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq "
! 1174: "0x%08x", circuit->area->area_tag,
! 1175: rawlspid_print (hdr->lsp_id),
! 1176: ntohl (lsp->lsp_header->seq_num));
! 1177: lsp->lsp_header->rem_lifetime =
! 1178: htons (isis_jitter
! 1179: (circuit->area->max_lsp_lifetime[level - 1],
! 1180: MAX_AGE_JITTER));
! 1181: }
! 1182: }
! 1183: else
! 1184: {
! 1185: /* 7.3.15.1 e) - This lsp originated on another system */
! 1186:
! 1187: /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */
! 1188: if ((!lsp || comp == LSP_NEWER))
! 1189: {
! 1190: /* i */
! 1191: if (lsp)
! 1192: {
! 1193: #ifdef EXTREME_DEBUG
! 1194: zlog_debug ("level %d number is - %ld", level,
! 1195: circuit->area->lspdb[level - 1]->dict_nodecount);
! 1196: #endif /* EXTREME DEBUG */
! 1197: lsp_search_and_destroy (hdr->lsp_id,
! 1198: circuit->area->lspdb[level - 1]);
! 1199: /* exists, so we overwrite */
! 1200: #ifdef EXTREME_DEBUG
! 1201: zlog_debug ("level %d number is - %ld", level,
! 1202: circuit->area->lspdb[level - 1]->dict_nodecount);
! 1203: #endif /* EXTREME DEBUG */
! 1204: }
! 1205: /*
! 1206: * If this lsp is a frag, need to see if we have zero lsp present
! 1207: */
! 1208: if (LSP_FRAGMENT (hdr->lsp_id) != 0)
! 1209: {
! 1210: memcpy (lspid, hdr->lsp_id, ISIS_SYS_ID_LEN + 1);
! 1211: LSP_FRAGMENT (lspid) = 0;
! 1212: lsp0 = lsp_search (lspid, circuit->area->lspdb[level - 1]);
! 1213: if (!lsp0)
! 1214: {
! 1215: zlog_debug ("Got lsp frag, while zero lsp not database");
! 1216: return ISIS_OK;
! 1217: }
! 1218: }
! 1219: lsp =
! 1220: lsp_new_from_stream_ptr (circuit->rcv_stream,
! 1221: ntohs (hdr->pdu_len), lsp0,
! 1222: circuit->area);
! 1223: lsp->level = level;
! 1224: lsp->adj = adj;
! 1225: lsp_insert (lsp, circuit->area->lspdb[level - 1]);
! 1226: /* ii */
! 1227: ISIS_FLAGS_SET_ALL (lsp->SRMflags);
! 1228: /* iii */
! 1229: ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
! 1230:
! 1231: /* iv */
! 1232: if (circuit->circ_type != CIRCUIT_T_BROADCAST)
! 1233: ISIS_SET_FLAG (lsp->SSNflags, circuit);
! 1234: /* FIXME: v) */
! 1235: }
! 1236: /* 7.3.15.1 e) 2) LSP equal to the one in db */
! 1237: else if (comp == LSP_EQUAL)
! 1238: {
! 1239: ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
! 1240: lsp_update (lsp, hdr, circuit->rcv_stream, circuit->area, level);
! 1241: if (circuit->circ_type != CIRCUIT_T_BROADCAST)
! 1242: {
! 1243: ISIS_SET_FLAG (lsp->SSNflags, circuit);
! 1244: }
! 1245: }
! 1246: /* 7.3.15.1 e) 3) LSP older than the one in db */
! 1247: else
! 1248: {
! 1249: ISIS_SET_FLAG (lsp->SRMflags, circuit);
! 1250: ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
! 1251: }
! 1252: }
! 1253: if (lsp)
! 1254: lsp->adj = adj;
! 1255: return retval;
! 1256: }
! 1257:
! 1258: /*
! 1259: * Process Sequence Numbers
! 1260: * ISO - 10589
! 1261: * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU
! 1262: */
! 1263:
! 1264: static int
! 1265: process_snp (int snp_type, int level, struct isis_circuit *circuit,
! 1266: u_char * ssnpa)
! 1267: {
! 1268: int retval = ISIS_OK;
! 1269: int cmp, own_lsp;
! 1270: char typechar = ' ';
! 1271: int len;
! 1272: struct isis_adjacency *adj;
! 1273: struct isis_complete_seqnum_hdr *chdr = NULL;
! 1274: struct isis_partial_seqnum_hdr *phdr = NULL;
! 1275: uint32_t found = 0, expected = 0;
! 1276: struct isis_lsp *lsp;
! 1277: struct lsp_entry *entry;
! 1278: struct listnode *node, *nnode;
! 1279: struct listnode *node2, *nnode2;
! 1280: struct tlvs tlvs;
! 1281: struct list *lsp_list = NULL;
! 1282: struct isis_passwd *passwd;
! 1283:
! 1284: if (snp_type == ISIS_SNP_CSNP_FLAG)
! 1285: {
! 1286: /* getting the header info */
! 1287: typechar = 'C';
! 1288: chdr =
! 1289: (struct isis_complete_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream);
! 1290: circuit->rcv_stream->getp += ISIS_CSNP_HDRLEN;
! 1291: len = ntohs (chdr->pdu_len);
! 1292: if (len < ISIS_CSNP_HDRLEN)
! 1293: {
! 1294: zlog_warn ("Received a CSNP with bogus length!");
! 1295: return ISIS_OK;
! 1296: }
! 1297: }
! 1298: else
! 1299: {
! 1300: typechar = 'P';
! 1301: phdr =
! 1302: (struct isis_partial_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream);
! 1303: circuit->rcv_stream->getp += ISIS_PSNP_HDRLEN;
! 1304: len = ntohs (phdr->pdu_len);
! 1305: if (len < ISIS_PSNP_HDRLEN)
! 1306: {
! 1307: zlog_warn ("Received a CSNP with bogus length!");
! 1308: return ISIS_OK;
! 1309: }
! 1310: }
! 1311:
! 1312: /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */
! 1313: if (circuit->ext_domain)
! 1314: {
! 1315:
! 1316: zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
! 1317: "skipping: circuit externalDomain = true",
! 1318: circuit->area->area_tag,
! 1319: level, typechar, circuit->interface->name);
! 1320:
! 1321: return ISIS_OK;
! 1322: }
! 1323:
! 1324: /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
! 1325: if (!accept_level (level, circuit->circuit_is_type))
! 1326: {
! 1327:
! 1328: zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
! 1329: "skipping: circuit type %s does not match level %d",
! 1330: circuit->area->area_tag,
! 1331: level,
! 1332: typechar,
! 1333: circuit->interface->name,
! 1334: circuit_t2string (circuit->circuit_is_type), level);
! 1335:
! 1336: return ISIS_OK;
! 1337: }
! 1338:
! 1339: /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */
! 1340: if ((snp_type == ISIS_SNP_PSNP_FLAG) &&
! 1341: (circuit->circ_type == CIRCUIT_T_BROADCAST))
! 1342: {
! 1343: if (!circuit->u.bc.is_dr[level - 1])
! 1344: {
! 1345:
! 1346: zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
! 1347: "skipping: we are not the DIS",
! 1348: circuit->area->area_tag,
! 1349: level,
! 1350: typechar, snpa_print (ssnpa), circuit->interface->name);
! 1351:
! 1352: return ISIS_OK;
! 1353: }
! 1354: }
! 1355:
! 1356: /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */
! 1357:
! 1358: /* 7.3.15.2 a) 6 - maximum area match, can be ommited since we only use 3
! 1359: * - already checked */
! 1360:
! 1361: /* 7.3.15.2 a) 7 - Must check that we have an adjacency of the same level */
! 1362: /* for broadcast circuits, snpa should be compared */
! 1363: /* FIXME : Do we need to check SNPA? */
! 1364: if (circuit->circ_type == CIRCUIT_T_BROADCAST)
! 1365: {
! 1366: if (snp_type == ISIS_SNP_CSNP_FLAG)
! 1367: {
! 1368: adj =
! 1369: isis_adj_lookup (chdr->source_id, circuit->u.bc.adjdb[level - 1]);
! 1370: }
! 1371: else
! 1372: {
! 1373: /* a psnp on a broadcast, how lovely of Juniper :) */
! 1374: adj =
! 1375: isis_adj_lookup (phdr->source_id, circuit->u.bc.adjdb[level - 1]);
! 1376: }
! 1377: if (!adj)
! 1378: return ISIS_OK; /* Silently discard */
! 1379: }
! 1380: else
! 1381: {
! 1382: if (!circuit->u.p2p.neighbor)
! 1383: return ISIS_OK; /* Silently discard */
! 1384: }
! 1385:
! 1386: /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */
! 1387:
! 1388: /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */
! 1389:
! 1390: memset (&tlvs, 0, sizeof (struct tlvs));
! 1391:
! 1392: /* parse the SNP */
! 1393: expected |= TLVFLAG_LSP_ENTRIES;
! 1394: expected |= TLVFLAG_AUTH_INFO;
! 1395: retval = parse_tlvs (circuit->area->area_tag,
! 1396: STREAM_PNT (circuit->rcv_stream),
! 1397: len - circuit->rcv_stream->getp,
! 1398: &expected, &found, &tlvs);
! 1399:
! 1400: if (retval > ISIS_WARNING)
! 1401: {
! 1402: zlog_warn ("something went very wrong processing SNP");
! 1403: free_tlvs (&tlvs);
! 1404: return retval;
! 1405: }
! 1406:
! 1407: if (level == 1)
! 1408: passwd = &circuit->area->area_passwd;
! 1409: else
! 1410: passwd = &circuit->area->domain_passwd;
! 1411:
! 1412: if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV))
! 1413: {
! 1414: if (passwd->type)
! 1415: {
! 1416: if (!(found & TLVFLAG_AUTH_INFO) ||
! 1417: authentication_check (passwd, &tlvs.auth_info))
! 1418: {
! 1419: isis_event_auth_failure (circuit->area->area_tag,
! 1420: "SNP authentication" " failure",
! 1421: phdr ? phdr->source_id : chdr->source_id);
! 1422: return ISIS_OK;
! 1423: }
! 1424: }
! 1425: }
! 1426:
! 1427: /* debug isis snp-packets */
! 1428: if (isis->debugs & DEBUG_SNP_PACKETS)
! 1429: {
! 1430: zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s",
! 1431: circuit->area->area_tag,
! 1432: level,
! 1433: typechar, snpa_print (ssnpa), circuit->interface->name);
! 1434: if (tlvs.lsp_entries)
! 1435: {
! 1436: for (ALL_LIST_ELEMENTS_RO (tlvs.lsp_entries, node, entry))
! 1437: {
! 1438: zlog_debug ("ISIS-Snp (%s): %cSNP entry %s, seq 0x%08x,"
! 1439: " cksum 0x%04x, lifetime %us",
! 1440: circuit->area->area_tag,
! 1441: typechar,
! 1442: rawlspid_print (entry->lsp_id),
! 1443: ntohl (entry->seq_num),
! 1444: ntohs (entry->checksum), ntohs (entry->rem_lifetime));
! 1445: }
! 1446: }
! 1447: }
! 1448:
! 1449: /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */
! 1450: if (tlvs.lsp_entries)
! 1451: {
! 1452: for (ALL_LIST_ELEMENTS_RO (tlvs.lsp_entries, node, entry))
! 1453: {
! 1454: lsp = lsp_search (entry->lsp_id, circuit->area->lspdb[level - 1]);
! 1455: own_lsp = !memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
! 1456: if (lsp)
! 1457: {
! 1458: /* 7.3.15.2 b) 1) is this LSP newer */
! 1459: cmp = lsp_compare (circuit->area->area_tag, lsp, entry->seq_num,
! 1460: entry->checksum, entry->rem_lifetime);
! 1461: /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */
! 1462: if (cmp == LSP_EQUAL)
! 1463: {
! 1464: if (circuit->circ_type != CIRCUIT_T_BROADCAST)
! 1465: ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
! 1466: /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
! 1467: }
! 1468: else if (cmp == LSP_OLDER)
! 1469: {
! 1470: ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
! 1471: ISIS_SET_FLAG (lsp->SRMflags, circuit);
! 1472: }
! 1473: else
! 1474: {
! 1475: /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM
! 1476: * on p2p */
! 1477: if (own_lsp)
! 1478: {
! 1479: lsp_inc_seqnum (lsp, ntohl (entry->seq_num));
! 1480: ISIS_SET_FLAG (lsp->SRMflags, circuit);
! 1481: }
! 1482: else
! 1483: {
! 1484: ISIS_SET_FLAG (lsp->SSNflags, circuit);
! 1485: if (circuit->circ_type != CIRCUIT_T_BROADCAST)
! 1486: ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
! 1487: }
! 1488: }
! 1489: }
! 1490: else
! 1491: {
! 1492: /* 7.3.15.2 b) 5) if it was not found, and all of those are not 0,
! 1493: * insert it and set SSN on it */
! 1494: if (entry->rem_lifetime && entry->checksum && entry->seq_num &&
! 1495: memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN))
! 1496: {
! 1497: lsp = lsp_new (entry->lsp_id, ntohs (entry->rem_lifetime),
! 1498: 0, 0, entry->checksum, level);
! 1499: lsp_insert (lsp, circuit->area->lspdb[level - 1]);
! 1500: ISIS_SET_FLAG (lsp->SSNflags, circuit);
! 1501: }
! 1502: }
! 1503: }
! 1504: }
! 1505:
! 1506: /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported */
! 1507: if (snp_type == ISIS_SNP_CSNP_FLAG)
! 1508: {
! 1509: /*
! 1510: * Build a list from our own LSP db bounded with start_ and stop_lsp_id
! 1511: */
! 1512: lsp_list = list_new ();
! 1513: lsp_build_list_nonzero_ht (chdr->start_lsp_id, chdr->stop_lsp_id,
! 1514: lsp_list, circuit->area->lspdb[level - 1]);
! 1515:
! 1516: /* Fixme: Find a better solution */
! 1517: if (tlvs.lsp_entries)
! 1518: {
! 1519: for (ALL_LIST_ELEMENTS (tlvs.lsp_entries, node, nnode, entry))
! 1520: {
! 1521: for (ALL_LIST_ELEMENTS (lsp_list, node2, nnode2, lsp))
! 1522: {
! 1523: if (lsp_id_cmp (lsp->lsp_header->lsp_id, entry->lsp_id) == 0)
! 1524: {
! 1525: list_delete_node (lsp_list, node2);
! 1526: break;
! 1527: }
! 1528: }
! 1529: }
! 1530: }
! 1531: /* on remaining LSPs we set SRM (neighbor knew not of) */
! 1532: for (ALL_LIST_ELEMENTS_RO (lsp_list, node, lsp))
! 1533: {
! 1534: ISIS_SET_FLAG (lsp->SRMflags, circuit);
! 1535: }
! 1536: /* lets free it */
! 1537: list_free (lsp_list);
! 1538: }
! 1539:
! 1540: free_tlvs (&tlvs);
! 1541: return retval;
! 1542: }
! 1543:
! 1544: static int
! 1545: process_csnp (int level, struct isis_circuit *circuit, u_char * ssnpa)
! 1546: {
! 1547: /* Sanity check - FIXME: move to correct place */
! 1548: if ((stream_get_endp (circuit->rcv_stream) -
! 1549: stream_get_getp (circuit->rcv_stream)) < ISIS_CSNP_HDRLEN)
! 1550: {
! 1551: zlog_warn ("Packet too short ( < %d)", ISIS_CSNP_HDRLEN);
! 1552: return ISIS_WARNING;
! 1553: }
! 1554:
! 1555: return process_snp (ISIS_SNP_CSNP_FLAG, level, circuit, ssnpa);
! 1556: }
! 1557:
! 1558: static int
! 1559: process_psnp (int level, struct isis_circuit *circuit, u_char * ssnpa)
! 1560: {
! 1561: if ((stream_get_endp (circuit->rcv_stream) -
! 1562: stream_get_getp (circuit->rcv_stream)) < ISIS_PSNP_HDRLEN)
! 1563: {
! 1564: zlog_warn ("Packet too short");
! 1565: return ISIS_WARNING;
! 1566: }
! 1567:
! 1568: return process_snp (ISIS_SNP_PSNP_FLAG, level, circuit, ssnpa);
! 1569: }
! 1570:
! 1571: /*
! 1572: * Process ISH
! 1573: * ISO - 10589
! 1574: * Section 8.2.2 - Receiving ISH PDUs by an intermediate system
! 1575: * FIXME: sample packet dump, need to figure 0x81 - looks like NLPid
! 1576: * 0x82 0x15 0x01 0x00 0x04 0x01 0x2c 0x59
! 1577: * 0x38 0x08 0x47 0x00 0x01 0x00 0x02 0x00
! 1578: * 0x03 0x00 0x81 0x01 0xcc
! 1579: */
! 1580: static int
! 1581: process_is_hello (struct isis_circuit *circuit)
! 1582: {
! 1583: struct isis_adjacency *adj;
! 1584: int retval = ISIS_OK;
! 1585: u_char neigh_len;
! 1586: u_char *sysid;
! 1587:
! 1588: /* In this point in time we are not yet able to handle is_hellos
! 1589: * on lan - Sorry juniper...
! 1590: */
! 1591: if (circuit->circ_type == CIRCUIT_T_BROADCAST)
! 1592: return retval;
! 1593:
! 1594: neigh_len = stream_getc (circuit->rcv_stream);
! 1595: sysid = STREAM_PNT (circuit->rcv_stream) + neigh_len - 1 - ISIS_SYS_ID_LEN;
! 1596: adj = circuit->u.p2p.neighbor;
! 1597: if (!adj)
! 1598: {
! 1599: /* 8.2.2 */
! 1600: adj = isis_new_adj (sysid, NULL, 0, circuit);
! 1601: if (adj == NULL)
! 1602: return ISIS_ERROR;
! 1603:
! 1604: isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
! 1605: adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
! 1606: circuit->u.p2p.neighbor = adj;
! 1607: }
! 1608: /* 8.2.2 a) */
! 1609: if ((adj->adj_state == ISIS_ADJ_UP) && memcmp (adj->sysid, sysid,
! 1610: ISIS_SYS_ID_LEN))
! 1611: {
! 1612: /* 8.2.2 a) 1) FIXME: adjStateChange(down) event */
! 1613: /* 8.2.2 a) 2) delete the adj */
! 1614: XFREE (MTYPE_ISIS_ADJACENCY, adj);
! 1615: /* 8.2.2 a) 3) create a new adj */
! 1616: adj = isis_new_adj (sysid, NULL, 0, circuit);
! 1617: if (adj == NULL)
! 1618: return ISIS_ERROR;
! 1619:
! 1620: /* 8.2.2 a) 3) i */
! 1621: isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
! 1622: /* 8.2.2 a) 3) ii */
! 1623: adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
! 1624: /* 8.2.2 a) 4) quite meaningless */
! 1625: }
! 1626: /* 8.2.2 b) ignore on condition */
! 1627: if ((adj->adj_state == ISIS_ADJ_INITIALIZING) &&
! 1628: (adj->sys_type == ISIS_SYSTYPE_IS))
! 1629: {
! 1630: /* do nothing */
! 1631: }
! 1632: else
! 1633: {
! 1634: /* 8.2.2 c) respond with a p2p IIH */
! 1635: send_hello (circuit, 1);
! 1636: }
! 1637: /* 8.2.2 d) type is IS */
! 1638: adj->sys_type = ISIS_SYSTYPE_IS;
! 1639: /* 8.2.2 e) FIXME: Circuit type of? */
! 1640:
! 1641: return retval;
! 1642: }
! 1643:
! 1644: /*
! 1645: * PDU Dispatcher
! 1646: */
! 1647:
! 1648: static int
! 1649: isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa)
! 1650: {
! 1651: struct isis_fixed_hdr *hdr;
! 1652: struct esis_fixed_hdr *esis_hdr;
! 1653:
! 1654: int retval = ISIS_OK;
! 1655:
! 1656: /*
! 1657: * Let's first read data from stream to the header
! 1658: */
! 1659: hdr = (struct isis_fixed_hdr *) STREAM_DATA (circuit->rcv_stream);
! 1660:
! 1661: if ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS))
! 1662: {
! 1663: zlog_warn ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp);
! 1664: return ISIS_ERROR;
! 1665: }
! 1666:
! 1667: /* now we need to know if this is an ISO 9542 packet and
! 1668: * take real good care of it, waaa!
! 1669: */
! 1670: if (hdr->idrp == ISO9542_ESIS)
! 1671: {
! 1672: esis_hdr = (struct esis_fixed_hdr *) STREAM_DATA (circuit->rcv_stream);
! 1673: stream_set_getp (circuit->rcv_stream, ESIS_FIXED_HDR_LEN);
! 1674: /* FIXME: Need to do some acceptence tests */
! 1675: /* example length... */
! 1676: switch (esis_hdr->pdu_type)
! 1677: {
! 1678: case ESH_PDU:
! 1679: /* FIXME */
! 1680: break;
! 1681: case ISH_PDU:
! 1682: zlog_debug ("AN ISH PDU!!");
! 1683: retval = process_is_hello (circuit);
! 1684: break;
! 1685: default:
! 1686: return ISIS_ERROR;
! 1687: }
! 1688: return retval;
! 1689: }
! 1690: else
! 1691: {
! 1692: stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN);
! 1693: }
! 1694: /*
! 1695: * and then process it
! 1696: */
! 1697:
! 1698: if (hdr->length < ISIS_MINIMUM_FIXED_HDR_LEN)
! 1699: {
! 1700: zlog_err ("Fixed header length = %d", hdr->length);
! 1701: return ISIS_ERROR;
! 1702: }
! 1703:
! 1704: if (hdr->version1 != 1)
! 1705: {
! 1706: zlog_warn ("Unsupported ISIS version %u", hdr->version1);
! 1707: return ISIS_WARNING;
! 1708: }
! 1709: /* either 6 or 0 */
! 1710: if ((hdr->id_len != 0) && (hdr->id_len != ISIS_SYS_ID_LEN))
! 1711: {
! 1712: zlog_err
! 1713: ("IDFieldLengthMismatch: ID Length field in a received PDU %u, "
! 1714: "while the parameter for this IS is %u", hdr->id_len,
! 1715: ISIS_SYS_ID_LEN);
! 1716: return ISIS_ERROR;
! 1717: }
! 1718:
! 1719: if (hdr->version2 != 1)
! 1720: {
! 1721: zlog_warn ("Unsupported ISIS version %u", hdr->version2);
! 1722: return ISIS_WARNING;
! 1723: }
! 1724: /* either 3 or 0 */
! 1725: if ((hdr->max_area_addrs != 0)
! 1726: && (hdr->max_area_addrs != isis->max_area_addrs))
! 1727: {
! 1728: zlog_err ("maximumAreaAddressesMismatch: maximumAreaAdresses in a "
! 1729: "received PDU %u while the parameter for this IS is %u",
! 1730: hdr->max_area_addrs, isis->max_area_addrs);
! 1731: return ISIS_ERROR;
! 1732: }
! 1733:
! 1734: switch (hdr->pdu_type)
! 1735: {
! 1736: case L1_LAN_HELLO:
! 1737: retval = process_lan_hello (ISIS_LEVEL1, circuit, ssnpa);
! 1738: break;
! 1739: case L2_LAN_HELLO:
! 1740: retval = process_lan_hello (ISIS_LEVEL2, circuit, ssnpa);
! 1741: break;
! 1742: case P2P_HELLO:
! 1743: retval = process_p2p_hello (circuit);
! 1744: break;
! 1745: case L1_LINK_STATE:
! 1746: retval = process_lsp (ISIS_LEVEL1, circuit, ssnpa);
! 1747: break;
! 1748: case L2_LINK_STATE:
! 1749: retval = process_lsp (ISIS_LEVEL2, circuit, ssnpa);
! 1750: break;
! 1751: case L1_COMPLETE_SEQ_NUM:
! 1752: retval = process_csnp (ISIS_LEVEL1, circuit, ssnpa);
! 1753: break;
! 1754: case L2_COMPLETE_SEQ_NUM:
! 1755: retval = process_csnp (ISIS_LEVEL2, circuit, ssnpa);
! 1756: break;
! 1757: case L1_PARTIAL_SEQ_NUM:
! 1758: retval = process_psnp (ISIS_LEVEL1, circuit, ssnpa);
! 1759: break;
! 1760: case L2_PARTIAL_SEQ_NUM:
! 1761: retval = process_psnp (ISIS_LEVEL2, circuit, ssnpa);
! 1762: break;
! 1763: default:
! 1764: return ISIS_ERROR;
! 1765: }
! 1766:
! 1767: return retval;
! 1768: }
! 1769:
! 1770: #ifdef GNU_LINUX
! 1771: int
! 1772: isis_receive (struct thread *thread)
! 1773: {
! 1774: struct isis_circuit *circuit;
! 1775: u_char ssnpa[ETH_ALEN];
! 1776: int retval;
! 1777:
! 1778: /*
! 1779: * Get the circuit
! 1780: */
! 1781: circuit = THREAD_ARG (thread);
! 1782: assert (circuit);
! 1783:
! 1784: if (!circuit->area)
! 1785: return ISIS_OK;
! 1786:
! 1787: if (circuit->rcv_stream == NULL)
! 1788: circuit->rcv_stream = stream_new (ISO_MTU (circuit));
! 1789: else
! 1790: stream_reset (circuit->rcv_stream);
! 1791:
! 1792: retval = circuit->rx (circuit, ssnpa);
! 1793: circuit->t_read = NULL;
! 1794:
! 1795: if (retval == ISIS_OK)
! 1796: retval = isis_handle_pdu (circuit, ssnpa);
! 1797:
! 1798: /*
! 1799: * prepare for next packet.
! 1800: */
! 1801: THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit,
! 1802: circuit->fd);
! 1803:
! 1804: return retval;
! 1805: }
! 1806:
! 1807: #else
! 1808: int
! 1809: isis_receive (struct thread *thread)
! 1810: {
! 1811: struct isis_circuit *circuit;
! 1812: u_char ssnpa[ETH_ALEN];
! 1813: int retval;
! 1814:
! 1815: /*
! 1816: * Get the circuit
! 1817: */
! 1818: circuit = THREAD_ARG (thread);
! 1819: assert (circuit);
! 1820:
! 1821: circuit->t_read = NULL;
! 1822:
! 1823: if (circuit->rcv_stream == NULL)
! 1824: circuit->rcv_stream = stream_new (ISO_MTU (circuit));
! 1825: else
! 1826: stream_reset (circuit->rcv_stream);
! 1827:
! 1828: retval = circuit->rx (circuit, ssnpa);
! 1829:
! 1830: if (retval == ISIS_OK)
! 1831: retval = isis_handle_pdu (circuit, ssnpa);
! 1832:
! 1833: /*
! 1834: * prepare for next packet.
! 1835: */
! 1836: circuit->t_read = thread_add_timer_msec (master, isis_receive, circuit,
! 1837: listcount
! 1838: (circuit->area->circuit_list) *
! 1839: 100);
! 1840:
! 1841: return retval;
! 1842: }
! 1843:
! 1844: #endif
! 1845:
! 1846: /* filling of the fixed isis header */
! 1847: void
! 1848: fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type)
! 1849: {
! 1850: memset (hdr, 0, sizeof (struct isis_fixed_hdr));
! 1851:
! 1852: hdr->idrp = ISO10589_ISIS;
! 1853:
! 1854: switch (pdu_type)
! 1855: {
! 1856: case L1_LAN_HELLO:
! 1857: case L2_LAN_HELLO:
! 1858: hdr->length = ISIS_LANHELLO_HDRLEN;
! 1859: break;
! 1860: case P2P_HELLO:
! 1861: hdr->length = ISIS_P2PHELLO_HDRLEN;
! 1862: break;
! 1863: case L1_LINK_STATE:
! 1864: case L2_LINK_STATE:
! 1865: hdr->length = ISIS_LSP_HDR_LEN;
! 1866: break;
! 1867: case L1_COMPLETE_SEQ_NUM:
! 1868: case L2_COMPLETE_SEQ_NUM:
! 1869: hdr->length = ISIS_CSNP_HDRLEN;
! 1870: break;
! 1871: case L1_PARTIAL_SEQ_NUM:
! 1872: case L2_PARTIAL_SEQ_NUM:
! 1873: hdr->length = ISIS_PSNP_HDRLEN;
! 1874: break;
! 1875: default:
! 1876: zlog_warn ("fill_fixed_hdr(): unknown pdu type %d", pdu_type);
! 1877: return;
! 1878: }
! 1879: hdr->length += ISIS_FIXED_HDR_LEN;
! 1880: hdr->pdu_type = pdu_type;
! 1881: hdr->version1 = 1;
! 1882: hdr->id_len = 0; /* ISIS_SYS_ID_LEN - 0==6 */
! 1883: hdr->version2 = 1;
! 1884: hdr->max_area_addrs = 0; /* isis->max_area_addrs - 0==3 */
! 1885: }
! 1886:
! 1887: /*
! 1888: * SEND SIDE
! 1889: */
! 1890: static void
! 1891: fill_fixed_hdr_andstream (struct isis_fixed_hdr *hdr, u_char pdu_type,
! 1892: struct stream *stream)
! 1893: {
! 1894: fill_fixed_hdr (hdr, pdu_type);
! 1895:
! 1896: stream_putc (stream, hdr->idrp);
! 1897: stream_putc (stream, hdr->length);
! 1898: stream_putc (stream, hdr->version1);
! 1899: stream_putc (stream, hdr->id_len);
! 1900: stream_putc (stream, hdr->pdu_type);
! 1901: stream_putc (stream, hdr->version2);
! 1902: stream_putc (stream, hdr->reserved);
! 1903: stream_putc (stream, hdr->max_area_addrs);
! 1904:
! 1905: return;
! 1906: }
! 1907:
! 1908: int
! 1909: send_hello (struct isis_circuit *circuit, int level)
! 1910: {
! 1911: struct isis_fixed_hdr fixed_hdr;
! 1912: struct isis_lan_hello_hdr hello_hdr;
! 1913: struct isis_p2p_hello_hdr p2p_hello_hdr;
! 1914:
! 1915: u_int32_t interval;
! 1916: unsigned long len_pointer, length;
! 1917: int retval;
! 1918:
! 1919: if (circuit->interface->mtu == 0)
! 1920: {
! 1921: zlog_warn ("circuit has zero MTU");
! 1922: return ISIS_WARNING;
! 1923: }
! 1924:
! 1925: if (!circuit->snd_stream)
! 1926: circuit->snd_stream = stream_new (ISO_MTU (circuit));
! 1927: else
! 1928: stream_reset (circuit->snd_stream);
! 1929:
! 1930: if (circuit->circ_type == CIRCUIT_T_BROADCAST)
! 1931: if (level == 1)
! 1932: fill_fixed_hdr_andstream (&fixed_hdr, L1_LAN_HELLO,
! 1933: circuit->snd_stream);
! 1934: else
! 1935: fill_fixed_hdr_andstream (&fixed_hdr, L2_LAN_HELLO,
! 1936: circuit->snd_stream);
! 1937: else
! 1938: fill_fixed_hdr_andstream (&fixed_hdr, P2P_HELLO, circuit->snd_stream);
! 1939:
! 1940: /*
! 1941: * Fill LAN Level 1 or 2 Hello PDU header
! 1942: */
! 1943: memset (&hello_hdr, 0, sizeof (struct isis_lan_hello_hdr));
! 1944: interval = circuit->hello_multiplier[level - 1] *
! 1945: circuit->hello_interval[level - 1];
! 1946: /* If we are the DIS then hello interval is divided by three, as is the hold-timer */
! 1947: if (circuit->u.bc.is_dr[level - 1])
! 1948: interval=interval/3;
! 1949: if (interval > USHRT_MAX)
! 1950: interval = USHRT_MAX;
! 1951: hello_hdr.circuit_t = circuit->circuit_is_type;
! 1952: memcpy (hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN);
! 1953: hello_hdr.hold_time = htons ((u_int16_t) interval);
! 1954:
! 1955: hello_hdr.pdu_len = 0; /* Update the PDU Length later */
! 1956: len_pointer = stream_get_endp (circuit->snd_stream) + 3 + ISIS_SYS_ID_LEN;
! 1957:
! 1958: /* copy the shared part of the hello to the p2p hello if needed */
! 1959: if (circuit->circ_type == CIRCUIT_T_P2P)
! 1960: {
! 1961: memcpy (&p2p_hello_hdr, &hello_hdr, 5 + ISIS_SYS_ID_LEN);
! 1962: p2p_hello_hdr.local_id = circuit->circuit_id;
! 1963: /* FIXME: need better understanding */
! 1964: stream_put (circuit->snd_stream, &p2p_hello_hdr, ISIS_P2PHELLO_HDRLEN);
! 1965: }
! 1966: else
! 1967: {
! 1968: hello_hdr.prio = circuit->u.bc.priority[level - 1];
! 1969: if (level == 1 && circuit->u.bc.l1_desig_is)
! 1970: {
! 1971: memcpy (hello_hdr.lan_id, circuit->u.bc.l1_desig_is,
! 1972: ISIS_SYS_ID_LEN + 1);
! 1973: }
! 1974: else if (level == 2 && circuit->u.bc.l2_desig_is)
! 1975: {
! 1976: memcpy (hello_hdr.lan_id, circuit->u.bc.l2_desig_is,
! 1977: ISIS_SYS_ID_LEN + 1);
! 1978: }
! 1979: stream_put (circuit->snd_stream, &hello_hdr, ISIS_LANHELLO_HDRLEN);
! 1980: }
! 1981:
! 1982: /*
! 1983: * Then the variable length part
! 1984: */
! 1985: /* add circuit password */
! 1986: if (circuit->passwd.type)
! 1987: if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len,
! 1988: circuit->passwd.passwd, circuit->snd_stream))
! 1989: return ISIS_WARNING;
! 1990: /* Area Addresses TLV */
! 1991: assert (circuit->area);
! 1992: if (circuit->area->area_addrs && circuit->area->area_addrs->count > 0)
! 1993: if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream))
! 1994: return ISIS_WARNING;
! 1995:
! 1996: /* LAN Neighbors TLV */
! 1997: if (circuit->circ_type == CIRCUIT_T_BROADCAST)
! 1998: {
! 1999: if (level == 1 && circuit->u.bc.lan_neighs[0]->count > 0)
! 2000: if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0],
! 2001: circuit->snd_stream))
! 2002: return ISIS_WARNING;
! 2003: if (level == 2 && circuit->u.bc.lan_neighs[1]->count > 0)
! 2004: if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1],
! 2005: circuit->snd_stream))
! 2006: return ISIS_WARNING;
! 2007: }
! 2008:
! 2009: /* Protocols Supported TLV */
! 2010: if (circuit->nlpids.count > 0)
! 2011: if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream))
! 2012: return ISIS_WARNING;
! 2013: /* IP interface Address TLV */
! 2014: if (circuit->ip_router && circuit->ip_addrs && circuit->ip_addrs->count > 0)
! 2015: if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream))
! 2016: return ISIS_WARNING;
! 2017:
! 2018: #ifdef HAVE_IPV6
! 2019: /* IPv6 Interface Address TLV */
! 2020: if (circuit->ipv6_router && circuit->ipv6_link &&
! 2021: circuit->ipv6_link->count > 0)
! 2022: if (tlv_add_ipv6_addrs (circuit->ipv6_link, circuit->snd_stream))
! 2023: return ISIS_WARNING;
! 2024: #endif /* HAVE_IPV6 */
! 2025:
! 2026: if (circuit->u.bc.pad_hellos)
! 2027: if (tlv_add_padding (circuit->snd_stream))
! 2028: return ISIS_WARNING;
! 2029:
! 2030: length = stream_get_endp (circuit->snd_stream);
! 2031: /* Update PDU length */
! 2032: stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t) length);
! 2033:
! 2034: retval = circuit->tx (circuit, level);
! 2035: if (retval)
! 2036: zlog_warn ("sending of LAN Level %d Hello failed", level);
! 2037:
! 2038: /* DEBUG_ADJ_PACKETS */
! 2039: if (isis->debugs & DEBUG_ADJ_PACKETS)
! 2040: {
! 2041: if (circuit->circ_type == CIRCUIT_T_BROADCAST)
! 2042: {
! 2043: zlog_debug ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %ld",
! 2044: circuit->area->area_tag, level, circuit->interface->name,
! 2045: /* FIXME: use %z when we stop supporting old compilers. */
! 2046: (unsigned long) STREAM_SIZE (circuit->snd_stream));
! 2047: }
! 2048: else
! 2049: {
! 2050: zlog_debug ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld",
! 2051: circuit->area->area_tag, circuit->interface->name,
! 2052: /* FIXME: use %z when we stop supporting old compilers. */
! 2053: (unsigned long) STREAM_SIZE (circuit->snd_stream));
! 2054: }
! 2055: }
! 2056:
! 2057: return retval;
! 2058: }
! 2059:
! 2060: static int
! 2061: send_lan_hello (struct isis_circuit *circuit, int level)
! 2062: {
! 2063: return send_hello (circuit, level);
! 2064: }
! 2065:
! 2066: int
! 2067: send_lan_l1_hello (struct thread *thread)
! 2068: {
! 2069: struct isis_circuit *circuit;
! 2070: int retval;
! 2071: unsigned long next_hello;
! 2072:
! 2073: circuit = THREAD_ARG (thread);
! 2074: assert (circuit);
! 2075:
! 2076: if (!circuit->area) {
! 2077: return ISIS_OK;
! 2078: }
! 2079:
! 2080: /* Pseudonode sends hellos three times more than the other nodes */
! 2081: if (circuit->u.bc.is_dr[0])
! 2082: next_hello=circuit->hello_interval[0]/3+1;
! 2083: else
! 2084: next_hello=circuit->hello_interval[0];
! 2085:
! 2086: circuit->u.bc.t_send_lan_hello[0] = NULL;
! 2087:
! 2088: if (circuit->u.bc.run_dr_elect[0])
! 2089: retval = isis_dr_elect (circuit, 1);
! 2090:
! 2091: retval = send_lan_hello (circuit, 1);
! 2092:
! 2093: /* set next timer thread */
! 2094: THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0],
! 2095: send_lan_l1_hello, circuit,
! 2096: isis_jitter (next_hello, IIH_JITTER));
! 2097:
! 2098: return retval;
! 2099: }
! 2100:
! 2101: int
! 2102: send_lan_l2_hello (struct thread *thread)
! 2103: {
! 2104: struct isis_circuit *circuit;
! 2105: int retval;
! 2106: unsigned long next_hello;
! 2107:
! 2108: circuit = THREAD_ARG (thread);
! 2109: assert (circuit);
! 2110:
! 2111: if (!circuit->area) {
! 2112: return ISIS_OK;
! 2113: }
! 2114:
! 2115: /* Pseudonode sends hellos three times more than the other nodes */
! 2116: if (circuit->u.bc.is_dr[1])
! 2117: next_hello=circuit->hello_interval[1]/3+1;
! 2118: else
! 2119: next_hello=circuit->hello_interval[1];
! 2120:
! 2121: circuit->u.bc.t_send_lan_hello[1] = NULL;
! 2122:
! 2123: if (circuit->u.bc.run_dr_elect[1])
! 2124: retval = isis_dr_elect (circuit, 2);
! 2125:
! 2126: retval = send_lan_hello (circuit, 2);
! 2127:
! 2128: /* set next timer thread */
! 2129: THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[1],
! 2130: send_lan_l2_hello, circuit,
! 2131: isis_jitter (next_hello, IIH_JITTER));
! 2132:
! 2133: return retval;
! 2134: }
! 2135:
! 2136: int
! 2137: send_p2p_hello (struct thread *thread)
! 2138: {
! 2139: struct isis_circuit *circuit;
! 2140:
! 2141: circuit = THREAD_ARG (thread);
! 2142: assert (circuit);
! 2143: circuit->u.p2p.t_send_p2p_hello = NULL;
! 2144:
! 2145: send_hello (circuit, 1);
! 2146:
! 2147: /* set next timer thread */
! 2148: THREAD_TIMER_ON (master, circuit->u.p2p.t_send_p2p_hello, send_p2p_hello,
! 2149: circuit, isis_jitter (circuit->hello_interval[1],
! 2150: IIH_JITTER));
! 2151:
! 2152: return ISIS_OK;
! 2153: }
! 2154:
! 2155: static int
! 2156: build_csnp (int level, u_char * start, u_char * stop, struct list *lsps,
! 2157: struct isis_circuit *circuit)
! 2158: {
! 2159: struct isis_fixed_hdr fixed_hdr;
! 2160: struct isis_passwd *passwd;
! 2161: int retval = ISIS_OK;
! 2162: unsigned long lenp;
! 2163: u_int16_t length;
! 2164:
! 2165: if (level == 1)
! 2166: fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM,
! 2167: circuit->snd_stream);
! 2168: else
! 2169: fill_fixed_hdr_andstream (&fixed_hdr, L2_COMPLETE_SEQ_NUM,
! 2170: circuit->snd_stream);
! 2171:
! 2172: /*
! 2173: * Fill Level 1 or 2 Complete Sequence Numbers header
! 2174: */
! 2175:
! 2176: lenp = stream_get_endp (circuit->snd_stream);
! 2177: stream_putw (circuit->snd_stream, 0); /* PDU length - when we know it */
! 2178: /* no need to send the source here, it is always us if we csnp */
! 2179: stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
! 2180: /* with zero circuit id - ref 9.10, 9.11 */
! 2181: stream_putc (circuit->snd_stream, 0x00);
! 2182:
! 2183: stream_put (circuit->snd_stream, start, ISIS_SYS_ID_LEN + 2);
! 2184: stream_put (circuit->snd_stream, stop, ISIS_SYS_ID_LEN + 2);
! 2185:
! 2186: /*
! 2187: * And TLVs
! 2188: */
! 2189: if (level == 1)
! 2190: passwd = &circuit->area->area_passwd;
! 2191: else
! 2192: passwd = &circuit->area->domain_passwd;
! 2193:
! 2194: if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
! 2195: if (passwd->type)
! 2196: retval = tlv_add_authinfo (passwd->type, passwd->len,
! 2197: passwd->passwd, circuit->snd_stream);
! 2198:
! 2199: if (!retval && lsps)
! 2200: {
! 2201: retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
! 2202: }
! 2203: length = (u_int16_t) stream_get_endp (circuit->snd_stream);
! 2204: assert (length >= ISIS_CSNP_HDRLEN);
! 2205: /* Update PU length */
! 2206: stream_putw_at (circuit->snd_stream, lenp, length);
! 2207:
! 2208: return retval;
! 2209: }
! 2210:
! 2211: /*
! 2212: * FIXME: support multiple CSNPs
! 2213: */
! 2214:
! 2215: int
! 2216: send_csnp (struct isis_circuit *circuit, int level)
! 2217: {
! 2218: int retval = ISIS_OK;
! 2219: u_char start[ISIS_SYS_ID_LEN + 2];
! 2220: u_char stop[ISIS_SYS_ID_LEN + 2];
! 2221: struct list *list = NULL;
! 2222: struct listnode *node;
! 2223: struct isis_lsp *lsp;
! 2224:
! 2225: memset (start, 0x00, ISIS_SYS_ID_LEN + 2);
! 2226: memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
! 2227:
! 2228: if (circuit->area->lspdb[level - 1] &&
! 2229: dict_count (circuit->area->lspdb[level - 1]) > 0)
! 2230: {
! 2231: list = list_new ();
! 2232: lsp_build_list (start, stop, list, circuit->area->lspdb[level - 1]);
! 2233:
! 2234: if (circuit->snd_stream == NULL)
! 2235: circuit->snd_stream = stream_new (ISO_MTU (circuit));
! 2236: else
! 2237: stream_reset (circuit->snd_stream);
! 2238:
! 2239: retval = build_csnp (level, start, stop, list, circuit);
! 2240:
! 2241: if (isis->debugs & DEBUG_SNP_PACKETS)
! 2242: {
! 2243: zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld",
! 2244: circuit->area->area_tag, level, circuit->interface->name,
! 2245: /* FIXME: use %z when we stop supporting old compilers. */
! 2246: (unsigned long) STREAM_SIZE (circuit->snd_stream));
! 2247: for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
! 2248: {
! 2249: zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x,"
! 2250: " cksum 0x%04x, lifetime %us",
! 2251: circuit->area->area_tag,
! 2252: rawlspid_print (lsp->lsp_header->lsp_id),
! 2253: ntohl (lsp->lsp_header->seq_num),
! 2254: ntohs (lsp->lsp_header->checksum),
! 2255: ntohs (lsp->lsp_header->rem_lifetime));
! 2256: }
! 2257: }
! 2258:
! 2259: list_delete (list);
! 2260:
! 2261: if (retval == ISIS_OK)
! 2262: retval = circuit->tx (circuit, level);
! 2263: }
! 2264: return retval;
! 2265: }
! 2266:
! 2267: int
! 2268: send_l1_csnp (struct thread *thread)
! 2269: {
! 2270: struct isis_circuit *circuit;
! 2271: int retval = ISIS_OK;
! 2272:
! 2273: circuit = THREAD_ARG (thread);
! 2274: assert (circuit);
! 2275:
! 2276: circuit->t_send_csnp[0] = NULL;
! 2277:
! 2278: if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[0])
! 2279: {
! 2280: send_csnp (circuit, 1);
! 2281: }
! 2282: /* set next timer thread */
! 2283: THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit,
! 2284: isis_jitter (circuit->csnp_interval[0], CSNP_JITTER));
! 2285:
! 2286: return retval;
! 2287: }
! 2288:
! 2289: int
! 2290: send_l2_csnp (struct thread *thread)
! 2291: {
! 2292: struct isis_circuit *circuit;
! 2293: int retval = ISIS_OK;
! 2294:
! 2295: circuit = THREAD_ARG (thread);
! 2296: assert (circuit);
! 2297:
! 2298: circuit->t_send_csnp[1] = NULL;
! 2299:
! 2300: if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[1])
! 2301: {
! 2302: send_csnp (circuit, 2);
! 2303: }
! 2304: /* set next timer thread */
! 2305: THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit,
! 2306: isis_jitter (circuit->csnp_interval[1], CSNP_JITTER));
! 2307:
! 2308: return retval;
! 2309: }
! 2310:
! 2311: static int
! 2312: build_psnp (int level, struct isis_circuit *circuit, struct list *lsps)
! 2313: {
! 2314: struct isis_fixed_hdr fixed_hdr;
! 2315: unsigned long lenp;
! 2316: u_int16_t length;
! 2317: int retval = 0;
! 2318: struct isis_lsp *lsp;
! 2319: struct isis_passwd *passwd;
! 2320: struct listnode *node;
! 2321:
! 2322: if (level == 1)
! 2323: fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
! 2324: circuit->snd_stream);
! 2325: else
! 2326: fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM,
! 2327: circuit->snd_stream);
! 2328:
! 2329: /*
! 2330: * Fill Level 1 or 2 Partial Sequence Numbers header
! 2331: */
! 2332: lenp = stream_get_endp (circuit->snd_stream);
! 2333: stream_putw (circuit->snd_stream, 0); /* PDU length - when we know it */
! 2334: stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
! 2335: stream_putc (circuit->snd_stream, circuit->idx);
! 2336:
! 2337: /*
! 2338: * And TLVs
! 2339: */
! 2340:
! 2341: if (level == 1)
! 2342: passwd = &circuit->area->area_passwd;
! 2343: else
! 2344: passwd = &circuit->area->domain_passwd;
! 2345:
! 2346: if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
! 2347: if (passwd->type)
! 2348: retval = tlv_add_authinfo (passwd->type, passwd->len,
! 2349: passwd->passwd, circuit->snd_stream);
! 2350:
! 2351: if (!retval && lsps)
! 2352: {
! 2353: retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
! 2354: }
! 2355:
! 2356: if (isis->debugs & DEBUG_SNP_PACKETS)
! 2357: {
! 2358: for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp))
! 2359: {
! 2360: zlog_debug ("ISIS-Snp (%s): PSNP entry %s, seq 0x%08x,"
! 2361: " cksum 0x%04x, lifetime %us",
! 2362: circuit->area->area_tag,
! 2363: rawlspid_print (lsp->lsp_header->lsp_id),
! 2364: ntohl (lsp->lsp_header->seq_num),
! 2365: ntohs (lsp->lsp_header->checksum),
! 2366: ntohs (lsp->lsp_header->rem_lifetime));
! 2367: }
! 2368: }
! 2369:
! 2370: length = (u_int16_t) stream_get_endp (circuit->snd_stream);
! 2371: assert (length >= ISIS_PSNP_HDRLEN);
! 2372: /* Update PDU length */
! 2373: stream_putw_at (circuit->snd_stream, lenp, length);
! 2374:
! 2375: return ISIS_OK;
! 2376: }
! 2377:
! 2378: /*
! 2379: * 7.3.15.4 action on expiration of partial SNP interval
! 2380: * level 1
! 2381: */
! 2382: static int
! 2383: send_psnp (int level, struct isis_circuit *circuit)
! 2384: {
! 2385: int retval = ISIS_OK;
! 2386: struct isis_lsp *lsp;
! 2387: struct list *list = NULL;
! 2388: struct listnode *node;
! 2389:
! 2390: if ((circuit->circ_type == CIRCUIT_T_BROADCAST &&
! 2391: !circuit->u.bc.is_dr[level - 1]) ||
! 2392: circuit->circ_type != CIRCUIT_T_BROADCAST)
! 2393: {
! 2394:
! 2395: if (circuit->area->lspdb[level - 1] &&
! 2396: dict_count (circuit->area->lspdb[level - 1]) > 0)
! 2397: {
! 2398: list = list_new ();
! 2399: lsp_build_list_ssn (circuit, list, circuit->area->lspdb[level - 1]);
! 2400:
! 2401: if (listcount (list) > 0)
! 2402: {
! 2403: if (circuit->snd_stream == NULL)
! 2404: circuit->snd_stream = stream_new (ISO_MTU (circuit));
! 2405: else
! 2406: stream_reset (circuit->snd_stream);
! 2407:
! 2408:
! 2409: if (isis->debugs & DEBUG_SNP_PACKETS)
! 2410: zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld",
! 2411: circuit->area->area_tag, level,
! 2412: circuit->interface->name,
! 2413: /* FIXME: use %z when we stop supporting old
! 2414: * compilers. */
! 2415: (unsigned long) STREAM_SIZE (circuit->snd_stream));
! 2416:
! 2417: retval = build_psnp (level, circuit, list);
! 2418: if (retval == ISIS_OK)
! 2419: retval = circuit->tx (circuit, level);
! 2420:
! 2421: if (retval == ISIS_OK)
! 2422: {
! 2423: /*
! 2424: * sending succeeded, we can clear SSN flags of this circuit
! 2425: * for the LSPs in list
! 2426: */
! 2427: for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
! 2428: ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
! 2429: }
! 2430: }
! 2431: list_delete (list);
! 2432: }
! 2433: }
! 2434:
! 2435: return retval;
! 2436: }
! 2437:
! 2438: int
! 2439: send_l1_psnp (struct thread *thread)
! 2440: {
! 2441:
! 2442: struct isis_circuit *circuit;
! 2443: int retval = ISIS_OK;
! 2444:
! 2445: circuit = THREAD_ARG (thread);
! 2446: assert (circuit);
! 2447:
! 2448: circuit->t_send_psnp[0] = NULL;
! 2449:
! 2450: send_psnp (1, circuit);
! 2451: /* set next timer thread */
! 2452: THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
! 2453: isis_jitter (circuit->psnp_interval[0], PSNP_JITTER));
! 2454:
! 2455: return retval;
! 2456: }
! 2457:
! 2458: /*
! 2459: * 7.3.15.4 action on expiration of partial SNP interval
! 2460: * level 2
! 2461: */
! 2462: int
! 2463: send_l2_psnp (struct thread *thread)
! 2464: {
! 2465: struct isis_circuit *circuit;
! 2466: int retval = ISIS_OK;
! 2467:
! 2468: circuit = THREAD_ARG (thread);
! 2469: assert (circuit);
! 2470:
! 2471: circuit->t_send_psnp[1] = NULL;
! 2472:
! 2473: send_psnp (2, circuit);
! 2474:
! 2475: /* set next timer thread */
! 2476: THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
! 2477: isis_jitter (circuit->psnp_interval[1], PSNP_JITTER));
! 2478:
! 2479: return retval;
! 2480: }
! 2481:
! 2482: /*
! 2483: * ISO 10589 - 7.3.14.3
! 2484: */
! 2485: int
! 2486: send_lsp (struct thread *thread)
! 2487: {
! 2488: struct isis_circuit *circuit;
! 2489: struct isis_lsp *lsp;
! 2490: struct listnode *node;
! 2491: int retval = 0;
! 2492:
! 2493: circuit = THREAD_ARG (thread);
! 2494: assert (circuit);
! 2495:
! 2496: if (circuit->state == C_STATE_UP)
! 2497: {
! 2498: lsp = listgetdata ((node = listhead (circuit->lsp_queue)));
! 2499:
! 2500: /*
! 2501: * Do not send if levels do not match
! 2502: */
! 2503: if (!(lsp->level & circuit->circuit_is_type))
! 2504: goto dontsend;
! 2505:
! 2506: /*
! 2507: * Do not send if we do not have adjacencies in state up on the circuit
! 2508: */
! 2509: if (circuit->upadjcount[lsp->level - 1] == 0)
! 2510: goto dontsend;
! 2511: /* only send if it needs sending */
! 2512: if ((time (NULL) - lsp->last_sent) >=
! 2513: circuit->area->lsp_gen_interval[lsp->level - 1])
! 2514: {
! 2515:
! 2516: if (isis->debugs & DEBUG_UPDATE_PACKETS)
! 2517: {
! 2518: zlog_debug
! 2519: ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
! 2520: " lifetime %us on %s", circuit->area->area_tag, lsp->level,
! 2521: rawlspid_print (lsp->lsp_header->lsp_id),
! 2522: ntohl (lsp->lsp_header->seq_num),
! 2523: ntohs (lsp->lsp_header->checksum),
! 2524: ntohs (lsp->lsp_header->rem_lifetime),
! 2525: circuit->interface->name);
! 2526: }
! 2527: /* copy our lsp to the send buffer */
! 2528: stream_copy (circuit->snd_stream, lsp->pdu);
! 2529:
! 2530: retval = circuit->tx (circuit, lsp->level);
! 2531:
! 2532: /*
! 2533: * If the sending succeeded, we can del the lsp from circuits
! 2534: * lsp_queue
! 2535: */
! 2536: if (retval == ISIS_OK)
! 2537: {
! 2538: list_delete_node (circuit->lsp_queue, node);
! 2539:
! 2540: /*
! 2541: * On broadcast circuits also the SRMflag can be cleared
! 2542: */
! 2543: if (circuit->circ_type == CIRCUIT_T_BROADCAST)
! 2544: ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
! 2545:
! 2546: if (flags_any_set (lsp->SRMflags) == 0)
! 2547: {
! 2548: /*
! 2549: * need to remember when we were last sent
! 2550: */
! 2551: lsp->last_sent = time (NULL);
! 2552: }
! 2553: }
! 2554: else
! 2555: {
! 2556: zlog_debug ("sending of level %d link state failed", lsp->level);
! 2557: }
! 2558: }
! 2559: else
! 2560: {
! 2561: /* my belief is that if it wasn't his time, the lsp can be removed
! 2562: * from the queue
! 2563: */
! 2564: dontsend:
! 2565: list_delete_node (circuit->lsp_queue, node);
! 2566: }
! 2567: #if 0
! 2568: /*
! 2569: * If there are still LSPs send next one after lsp-interval (33 msecs)
! 2570: */
! 2571: if (listcount (circuit->lsp_queue) > 0)
! 2572: thread_add_timer (master, send_lsp, circuit, 1);
! 2573: #endif
! 2574: }
! 2575:
! 2576: return retval;
! 2577: }
! 2578:
! 2579: int
! 2580: ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit,
! 2581: int level)
! 2582: {
! 2583: unsigned long lenp;
! 2584: int retval;
! 2585: u_int16_t length;
! 2586: struct isis_fixed_hdr fixed_hdr;
! 2587:
! 2588: if (!circuit->snd_stream)
! 2589: circuit->snd_stream = stream_new (ISO_MTU (circuit));
! 2590: else
! 2591: stream_reset (circuit->snd_stream);
! 2592:
! 2593: // fill_llc_hdr (stream);
! 2594: if (level == 1)
! 2595: fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
! 2596: circuit->snd_stream);
! 2597: else
! 2598: fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM,
! 2599: circuit->snd_stream);
! 2600:
! 2601:
! 2602: lenp = stream_get_endp (circuit->snd_stream);
! 2603: stream_putw (circuit->snd_stream, 0); /* PDU length */
! 2604: stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
! 2605: stream_putc (circuit->snd_stream, circuit->idx);
! 2606: stream_putc (circuit->snd_stream, 9); /* code */
! 2607: stream_putc (circuit->snd_stream, 16); /* len */
! 2608:
! 2609: stream_putw (circuit->snd_stream, ntohs (hdr->rem_lifetime));
! 2610: stream_put (circuit->snd_stream, hdr->lsp_id, ISIS_SYS_ID_LEN + 2);
! 2611: stream_putl (circuit->snd_stream, ntohl (hdr->seq_num));
! 2612: stream_putw (circuit->snd_stream, ntohs (hdr->checksum));
! 2613:
! 2614: length = (u_int16_t) stream_get_endp (circuit->snd_stream);
! 2615: /* Update PDU length */
! 2616: stream_putw_at (circuit->snd_stream, lenp, length);
! 2617:
! 2618: retval = circuit->tx (circuit, level);
! 2619:
! 2620: return retval;
! 2621: }
! 2622:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>