|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1994, 1996-2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /*-------------------------------------------------------------------------- ! 23: * Router RTMP protocol functions: ! 24: * ! 25: * This file contains Routing specifics to handle RTMP packets and ! 26: * the maintenance of the routing table through.... ! 27: * ! 28: * The entry point for the rtmp input in ddp is valid only when we're ! 29: * running in router mode. ! 30: * ! 31: * ! 32: * 0.01 03/22/94 Laurent Dumont Creation ! 33: * Modified for MP, 1996 by Tuyen Nguyen ! 34: * Added AURP support, April 8, 1996 by Tuyen Nguyen ! 35: * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX. ! 36: * ! 37: *------------------------------------------------------------------------- ! 38: */ ! 39: ! 40: #include <sys/errno.h> ! 41: #include <sys/types.h> ! 42: #include <sys/param.h> ! 43: #include <machine/spl.h> ! 44: #include <sys/systm.h> ! 45: #include <sys/kernel.h> ! 46: #include <sys/proc.h> ! 47: #include <sys/filedesc.h> ! 48: #include <sys/fcntl.h> ! 49: #include <sys/mbuf.h> ! 50: #include <sys/ioctl.h> ! 51: #include <sys/malloc.h> ! 52: #include <sys/socket.h> ! 53: #include <sys/socketvar.h> ! 54: ! 55: #include <net/if.h> ! 56: ! 57: #include <netat/sysglue.h> ! 58: #include <netat/appletalk.h> ! 59: #include <netat/at_var.h> ! 60: #include <netat/lap.h> ! 61: #include <netat/ddp.h> ! 62: #include <netat/rtmp.h> ! 63: #include <netat/at_pcb.h> ! 64: #include <netat/zip.h> ! 65: #include <netat/routing_tables.h> ! 66: #include <netat/aurp.h> ! 67: #include <netat/debug.h> ! 68: #include <netat/at_config.h> ! 69: ! 70: extern void (*ddp_AURPsendx)(); ! 71: extern at_ifaddr_t *aurp_ifID; ! 72: extern at_ifaddr_t *ifID_table[]; ! 73: extern at_ifaddr_t *ifID_home; ! 74: ! 75: /*DEBUG ONLY */ ! 76: static int dump_counter =0; ! 77: /*DEBUG ONLY */ ! 78: ! 79: static at_kern_err_t ke; ! 80: /* Used to record error discovered in rtmp_update() */ ! 81: gbuf_t *rtmp_prep_new_packet(); ! 82: ! 83: void rtmp_timeout(); ! 84: void rtmp_send_port(); ! 85: void rtmp_dropper(); ! 86: void rtmp_shutdown(); ! 87: static void rtmp_update(); ! 88: static void rtmp_request(); ! 89: extern int elap_online3(); ! 90: ! 91: extern pktsIn, pktsOut, pktsDropped, pktsHome; ! 92: extern short ErrorRTMPoverflow, ErrorZIPoverflow; ! 93: extern atlock_t ddpinp_lock; ! 94: ! 95: /* ! 96: * rtmp_router_input: function called by DDP (in router mode) to handle ! 97: * all incoming RTMP packets. Listen to the RTMP socket ! 98: * for all the connected ports. ! 99: * Switch to the relevant rtmp functions. ! 100: */ ! 101: ! 102: void rtmp_router_input(mp, ifID) ! 103: register gbuf_t *mp; ! 104: register at_ifaddr_t *ifID; ! 105: { ! 106: register at_ddp_t *ddp = (at_ddp_t *)gbuf_rptr(mp); ! 107: /* NOTE: there is an assumption here that the ! 108: * DATA follows the header. */ ! 109: ! 110: register at_net_al OurNet; ! 111: register at_node OurNode; ! 112: register at_net_al DstNet; ! 113: register at_node DstNode; ! 114: short tuples; ! 115: RT_entry *Entry; ! 116: ! 117: if (!ifID || (ifID->ifRoutingState < PORT_ACTIVATING)) { ! 118: gbuf_freem(mp); ! 119: return; ! 120: } ! 121: ! 122: ! 123: OurNet = ifID->ifThisNode.s_net; ! 124: OurNode = ifID->ifThisNode.s_node; ! 125: ! 126: ! 127: if (gbuf_type(mp) != MSG_DATA) { ! 128: ! 129: /* If this is a M_ERROR message, DDP is shutting down, ! 130: * nothing to do here...If it's something else, we don't ! 131: * understand what it is ! 132: */ ! 133: dPrintf(D_M_RTMP, D_L_WARNING, ! 134: ("rtmp_router_input: Not an M_DATA type\n")); ! 135: gbuf_freem(mp); ! 136: return; ! 137: } ! 138: ! 139: DstNet = NET_VALUE(ddp->dst_net); ! 140: DstNode = ddp->dst_node; ! 141: ! 142: /* check the kind of RTMP packet we received */ ! 143: ! 144: switch (ddp->type) { ! 145: ! 146: case DDP_RTMP: ! 147: ! 148: tuples = gbuf_len(mp) - DDP_X_HDR_SIZE - RTMP_IDLENGTH; ! 149: /* ! 150: * we need to make sure that the size of 'tuples' is ! 151: * not less than or equal to 0 due to a bad packet ! 152: */ ! 153: if (tuples <= 0) { ! 154: gbuf_freem(mp); ! 155: break; ! 156: } ! 157: ! 158: if (tuples % 3) {/* not a valid RTMP data packet */ ! 159: gbuf_freem(mp); ! 160: dPrintf(D_M_RTMP, D_L_WARNING, ! 161: ("rtmp_input: bad number of tuple in RTMP packet\n")); ! 162: return; ! 163: } ! 164: ! 165: tuples = tuples / 3; ! 166: ! 167: rtmp_update(ifID, (at_rtmp *)ddp->data, tuples); ! 168: gbuf_freem(mp); ! 169: ! 170: break; ! 171: ! 172: case DDP_RTMP_REQ: ! 173: ! 174: /* we should treat requests a bit differently. ! 175: * - if the request if not for the port, route it and also respond ! 176: * for this port if not locally connected. ! 177: * - if the request for this port, then just respond to it. ! 178: */ ! 179: ! 180: if (!ROUTING_MODE) { ! 181: gbuf_freem(mp); ! 182: return; ! 183: } ! 184: if (DstNode == 255) { ! 185: if (((DstNet >= CableStart) && (DstNet <= CableStop)) || ! 186: DstNet == 0) { ! 187: rtmp_request(ifID, ddp); ! 188: gbuf_freem(mp); ! 189: return; ! 190: } ! 191: else { ! 192: /* check if directly connected port */ ! 193: if ((Entry = rt_blookup(DstNet)) && ! 194: (Entry->NetDist == 0)) { ! 195: dPrintf(D_M_RTMP, D_L_WARNING, ! 196: ("rtmp_router_input: request for %d.%d, port %d\n", ! 197: DstNet, DstNode, Entry->NetPort)); ! 198: rtmp_request(ifID_table[Entry->NetPort], ddp); ! 199: gbuf_freem(mp); ! 200: return; ! 201: } ! 202: else { ! 203: dPrintf(D_M_RTMP, D_L_WARNING, ! 204: ("rtmp_router_input: RTMP packet received for %d.%d, also forward\n", ! 205: NET_VALUE(ddp->dst_net),ddp->dst_node)); ! 206: routing_needed(mp, ifID, TRUE); ! 207: return; ! 208: } ! 209: } ! 210: } ! 211: else { ! 212: ! 213: if ((DstNode == OurNode) && (DstNet == OurNet)) { ! 214: rtmp_request(ifID, ddp); ! 215: gbuf_freem(mp); ! 216: return; ! 217: } ! 218: else { ! 219: dPrintf(D_M_RTMP, D_L_WARNING, ! 220: ("rtmp_router_input: RTMP packet received for %d.%d, forward\n", ! 221: NET_VALUE(ddp->dst_net), ddp->dst_node)); ! 222: routing_needed(mp, ifID, TRUE); ! 223: } ! 224: } ! 225: ! 226: break; ! 227: ! 228: default: ! 229: ! 230: dPrintf(D_M_RTMP, D_L_WARNING, ! 231: ("rtmp_input: RTMP packet type=%d, route it\n", ddp->type)); ! 232: routing_needed(mp, ifID, TRUE); ! 233: break; ! 234: ! 235: } ! 236: } /* rtmp_router_input */ ! 237: ! 238: /* ! 239: * rtmp_update: ! 240: * ! 241: */ ! 242: ! 243: static void rtmp_update(ifID, rtmp, tuple_nb) ! 244: register at_ifaddr_t *ifID; ! 245: register at_rtmp *rtmp; ! 246: register short tuple_nb; ! 247: { ! 248: register int PortFlags = ifID->ifFlags; ! 249: register at_rtmp_tuple *FirstTuple = (at_rtmp_tuple *)&rtmp->at_rtmp_id[1]; ! 250: register at_rtmp_tuple *SecondTuple = (at_rtmp_tuple *)&rtmp->at_rtmp_id[4]; ! 251: RT_entry NewRoute, *CurrentRoute; ! 252: ! 253: register u_char SenderNodeID = rtmp->at_rtmp_id[0]; ! 254: char *TuplePtr; ! 255: short state; ! 256: ! 257: ! 258: /* Make sure this an AppleTalk node sending us the RTMP packet */ ! 259: ! 260: if (rtmp->at_rtmp_id_length != 8) { ! 261: dPrintf(D_M_RTMP, D_L_WARNING, ! 262: ("rtmp_update : RTMP ID not as expected Net=%d L=x%x\n", ! 263: NET_VALUE(rtmp->at_rtmp_this_net), rtmp->at_rtmp_id_length)); ! 264: return; ! 265: } ! 266: ! 267: /* ! 268: * If the port is activating, only take the Network range from the ! 269: * the RTMP packet received. ! 270: * Check if there is a conflict with our seed infos. ! 271: */ ! 272: ! 273: if (ifID->ifRoutingState == PORT_ACTIVATING) { ! 274: if (PortFlags & RTR_XNET_PORT) { ! 275: if ((PortFlags & RTR_SEED_PORT) && ! 276: ((CableStart != TUPLENET(FirstTuple)) || ! 277: (CableStop != TUPLENET(SecondTuple)))) { ! 278: ifID->ifRoutingState = PORT_ERR_SEED; ! 279: ke.error = KE_CONF_SEED_RNG; ! 280: ke.port1 = ifID->ifPort; ! 281: strncpy(ke.name1, ifID->ifName, sizeof(ke.name1)); ! 282: ke.net = NET_VALUE(rtmp->at_rtmp_this_net); ! 283: ke.node = SenderNodeID; ! 284: ke.netr1b = TUPLENET(FirstTuple); ! 285: ke.netr1e = TUPLENET(SecondTuple); ! 286: ke.netr2b = CableStart; ! 287: ke.netr2e = CableStop; ! 288: RouterError(ifID->ifPort, ERTR_SEED_CONFLICT); ! 289: return; ! 290: } ! 291: CableStart = TUPLENET(FirstTuple); ! 292: CableStop = TUPLENET(SecondTuple); ! 293: /* ! 294: dPrintf(D_M_RTMP, D_L_INFO, ! 295: ("rtmp_update: Port #%d activating, set Cable %d-%d\n", ! 296: ifID->ifPort, CableStart, CableStop)); ! 297: */ ! 298: } ! 299: else { /* non extended cable */ ! 300: if ((PortFlags & RTR_SEED_PORT) && ! 301: (ifID->ifThisCableEnd != NET_VALUE(rtmp->at_rtmp_this_net))) { ! 302: ke.error = KE_CONF_SEED1; ! 303: ke.port1 = ifID->ifPort; ! 304: strncpy(ke.name1, ifID->ifName,sizeof(ke.name1)); ! 305: ke.net = NET_VALUE(rtmp->at_rtmp_this_net); ! 306: ke.node = SenderNodeID; ! 307: ke.netr1e = ifID->ifThisCableEnd; ! 308: ifID->ifRoutingState = PORT_ERR_SEED; ! 309: RouterError(ifID->ifPort, ERTR_SEED_CONFLICT); ! 310: return; ! 311: } ! 312: CableStop = NET_VALUE(rtmp->at_rtmp_this_net); ! 313: CableStart = 0; ! 314: dPrintf(D_M_RTMP, D_L_INFO, ! 315: ("rtmp_update: Port #%d NONX activating, set Cable %d-%d\n", ! 316: ifID->ifPort, CableStart, CableStop)); ! 317: } ! 318: } ! 319: ! 320: /* ! 321: * Perform a few sanity checks on the received RTMP data packet ! 322: */ ! 323: ! 324: if ((PortFlags & RTR_XNET_PORT) && (tuple_nb >= 2)) { ! 325: ! 326: /* The first tuple must be extended */ ! 327: ! 328: if (! TUPLERANGE(FirstTuple)) { ! 329: dPrintf(D_M_RTMP, D_L_WARNING, ! 330: ("rtmp_update: bad range value in 1st tuple =%d\n", ! 331: TUPLERANGE(FirstTuple))); ! 332: return; ! 333: } ! 334: ! 335: if (PortFlags & RTR_SEED_PORT) ! 336: if ((TUPLENET(FirstTuple) != CableStart) || ! 337: (TUPLENET(SecondTuple) != CableStop)) { ! 338: dPrintf(D_M_RTMP, D_L_WARNING, ("rtmp_update: conflict on Seed Port\n")); ! 339: ifID->ifRoutingState = PORT_ERR_CABLER; ! 340: ke.error = KE_CONF_SEED_NODE; ! 341: ke.port1 = ifID->ifPort; ! 342: strncpy(ke.name1, ifID->ifName,sizeof(ke.name1)); ! 343: ke.net = NET_VALUE(rtmp->at_rtmp_this_net); ! 344: ke.node = SenderNodeID; ! 345: ke.netr1b = TUPLENET(FirstTuple); ! 346: ke.netr1e = TUPLENET(SecondTuple); ! 347: ke.netr2b = CableStart; ! 348: ke.netr2e = CableStop; ! 349: RouterError(ifID->ifPort, ERTR_CABLE_CONFLICT); ! 350: return; ! 351: } ! 352: ! 353: /* check that the tuple matches the range */ ! 354: ! 355: if ((TUPLENET(SecondTuple) < TUPLENET(FirstTuple)) || ! 356: (TUPLENET(FirstTuple) == 0) || ! 357: (TUPLENET(FirstTuple) >= DDP_STARTUP_LOW) || ! 358: (TUPLENET(SecondTuple) == 0) || ! 359: (TUPLENET(SecondTuple) >= DDP_STARTUP_LOW)) { ! 360: ! 361: /* ! 362: * IS THIS NON-FATAL????? ! 363: */ ! 364: dPrintf(D_M_RTMP, D_L_WARNING, ! 365: ("rtmp_update: STARTUP RANGE!!! 1st %d-%d\n", ! 366: TUPLENET(FirstTuple), TUPLENET(SecondTuple))); ! 367: ifID->ifRoutingState = PORT_ERR_STARTUP; ! 368: ke.error = KE_SEED_STARTUP; ! 369: ke.port1 = ifID->ifPort; ! 370: strncpy(ke.name1, ifID->ifName,sizeof(ke.name1)); ! 371: ke.net = NET_VALUE(rtmp->at_rtmp_this_net); ! 372: ke.node = SenderNodeID; ! 373: RouterError(ifID->ifPort, ERTR_CABLE_STARTUP); ! 374: return; ! 375: } ! 376: ! 377: if (TUPLEDIST(FirstTuple) != 0) { ! 378: dPrintf(D_M_RTMP, D_L_WARNING, ! 379: ("rtmp_update: Invalid distance in 1st tuple\n")); ! 380: return; ! 381: } ! 382: ! 383: if (rtmp->at_rtmp_id[6] != RTMP_VERSION_NUMBER) { ! 384: dPrintf(D_M_RTMP, D_L_WARNING, ! 385: ("rtmp_update: Invalid RTMP version = x%x\n", ! 386: rtmp->at_rtmp_id[6])); ! 387: return; ! 388: } ! 389: ! 390: } ! 391: else { /* non extended interface or problem in tuple*/ ! 392: ! 393: if (PortFlags & RTR_XNET_PORT) { ! 394: dPrintf(D_M_RTMP, D_L_WARNING, ! 395: ("rtmp_update: invalid number of tuple for X-net\n")); ! 396: return; ! 397: } ! 398: ! 399: if (TUPLENET(FirstTuple) == 0) { /* non extended RTMP data */ ! 400: ! 401: if (rtmp->at_rtmp_id[3] > RTMP_VERSION_NUMBER) { ! 402: dPrintf(D_M_RTMP, D_L_WARNING, ! 403: ("rtmp_update: Invalid non extended RTMP version\n")); ! 404: return; ! 405: } ! 406: ! 407: } ! 408: else { ! 409: dPrintf(D_M_RTMP, D_L_WARNING, ! 410: ("rtmp_update: version 1.0 non Xtended net not supported\n")); ! 411: ifID->ifRoutingState = PORT_ERR_BADRTMP; ! 412: ke.error = KE_BAD_VER; ! 413: ke.rtmp_id = rtmp->at_rtmp_id[6]; ! 414: ke.net = NET_VALUE(rtmp->at_rtmp_this_net); ! 415: ke.node = SenderNodeID; ! 416: RouterError(ifID->ifPort, ERTR_RTMP_BAD_VERSION); ! 417: return; ! 418: } ! 419: } ! 420: ! 421: NewRoute.NextIRNet = NET_VALUE(rtmp->at_rtmp_this_net); ! 422: NewRoute.NextIRNode = SenderNodeID; ! 423: NewRoute.NetPort = ifID->ifPort; ! 424: ! 425: /* ! 426: * Process the case where a non-seed port needs to acquire the right ! 427: * information. ! 428: */ ! 429: ! 430: if (!(PortFlags & RTR_SEED_PORT) && (ifID->ifRoutingState == PORT_ACTIVATING)) { ! 431: dPrintf(D_M_RTMP_LOW, D_L_INFO, ! 432: ("rtmp_update: Port# %d, set non seed cable %d-%d\n", ! 433: ifID->ifPort, TUPLENET(FirstTuple), TUPLENET(SecondTuple))); ! 434: ! 435: if (PortFlags & RTR_XNET_PORT) { ! 436: NewRoute.NetStart = TUPLENET(FirstTuple); ! 437: NewRoute.NetStop = TUPLENET(SecondTuple); ! 438: ifID->ifThisCableStart = TUPLENET(FirstTuple); ! 439: ifID->ifThisCableEnd = TUPLENET(SecondTuple); ! 440: ! 441: } ! 442: else { ! 443: ! 444: NewRoute.NetStart = 0; ! 445: NewRoute.NetStop = NET_VALUE(rtmp->at_rtmp_this_net); ! 446: ifID->ifThisCableStart = NET_VALUE(rtmp->at_rtmp_this_net); ! 447: ifID->ifThisCableEnd = NET_VALUE(rtmp->at_rtmp_this_net); ! 448: } ! 449: /* ! 450: * Now, check if we already know this route, or we need to add it ! 451: * (or modify it in the table accordingly) ! 452: */ ! 453: ! 454: if ((CurrentRoute = rt_blookup(NewRoute.NetStop)) && ! 455: (CurrentRoute->NetStop == NewRoute.NetStop) && ! 456: (CurrentRoute->NetStart == NewRoute.NetStart)) { ! 457: /*LD 7/31/95 tempo########*/ ! 458: if (NewRoute.NetPort != CurrentRoute->NetPort) { ! 459: dPrintf(D_M_RTMP, D_L_WARNING, ! 460: ("rtmp_update: port# %d, not the port we waited for %d\n", ! 461: ifID->ifPort, CurrentRoute->NetPort)); ! 462: /* propose to age the entry we know... */ ! 463: ! 464: state = CurrentRoute->EntryState & 0x0F; ! 465: /* if entry has been updated recently, just clear the UPDATED ! 466: bit. if bit not set, then we can age the entry */ ! 467: if (state) ! 468: if (CurrentRoute->EntryState & RTE_STATE_UPDATED) { ! 469: CurrentRoute->EntryState &= ~RTE_STATE_UPDATED; ! 470: } ! 471: else { ! 472: state = state >> 1 ; /* decrement state */ ! 473: } ! 474: ! 475: CurrentRoute->EntryState = (CurrentRoute->EntryState & 0xF0) | state; ! 476: } ! 477: } ! 478: ! 479: else { /* add the new route */ ! 480: ! 481: dPrintf(D_M_RTMP, D_L_INFO, ! 482: ("rtmp_update: P# %d, 1st tuple route not known, add %d-%d\n", ! 483: ifID->ifPort, NewRoute.NetStart, NewRoute.NetStop)); ! 484: ! 485: NewRoute.EntryState = RTE_STATE_GOOD|RTE_STATE_UPDATED; ! 486: NewRoute.NetDist = 0; ! 487: ! 488: if (rt_insert(NewRoute.NetStop, NewRoute.NetStart, 0, ! 489: 0, NewRoute.NetDist, NewRoute.NetPort, ! 490: NewRoute.EntryState) == (RT_entry *)NULL) ! 491: ! 492: ErrorRTMPoverflow = 1; ! 493: } ! 494: ! 495: } ! 496: ! 497: if (ifID->ifRoutingState == PORT_ACTIVATING) { ! 498: dPrintf(D_M_RTMP, D_L_INFO, ! 499: ("rtmp_update: port activating, ignoring remaining tuples\n")); ! 500: return; ! 501: } ! 502: ! 503: /* ! 504: * Process all the tuples against our routing table ! 505: */ ! 506: ! 507: TuplePtr = (char *)FirstTuple; ! 508: ! 509: while (tuple_nb-- > 0) { ! 510: ! 511: if (TUPLEDIST(TuplePtr) == NOTIFY_N_DIST) { ! 512: dPrintf(D_M_RTMP, D_L_INFO, ! 513: ("rtmp_update: Port# %d, Tuple with Notify Neighbour\n", ! 514: ifID->ifPort)); ! 515: NewRoute.NetDist = NOTIFY_N_DIST; ! 516: NewRoute.EntryState = RTE_STATE_BAD; ! 517: } ! 518: else { ! 519: NewRoute.NetDist = TUPLEDIST(TuplePtr) + 1; ! 520: NewRoute.EntryState = RTE_STATE_GOOD; ! 521: NewRoute.EntryState = RTE_STATE_GOOD|RTE_STATE_UPDATED; ! 522: } ! 523: ! 524: ! 525: if (TUPLERANGE(TuplePtr)) { /* Extended Tuple */ ! 526: ! 527: ! 528: NewRoute.NetStart = TUPLENET(TuplePtr); ! 529: TuplePtr += 3; ! 530: NewRoute.NetStop = TUPLENET((TuplePtr)); ! 531: TuplePtr += 3; ! 532: tuple_nb--; ! 533: ! 534: if ((NewRoute.NetDist == 0) || ! 535: (NewRoute.NetStart == 0) || ! 536: (NewRoute.NetStop == 0) || ! 537: (NewRoute.NetStop < NewRoute.NetStart) || ! 538: (NewRoute.NetStart >= DDP_STARTUP_LOW) || ! 539: (NewRoute.NetStop >= DDP_STARTUP_LOW)) { ! 540: ! 541: dPrintf(D_M_RTMP, D_L_WARNING, ! 542: ("rtmp_update: P# %d, non valid xtuple received [%d-%d]\n", ! 543: ifID->ifPort, NewRoute.NetStart, NewRoute.NetStop)); ! 544: ! 545: continue; ! 546: } ! 547: ! 548: } ! 549: else { /* Non Extended Tuple */ ! 550: ! 551: NewRoute.NetStart = 0; ! 552: NewRoute.NetStop = TUPLENET(TuplePtr); ! 553: ! 554: TuplePtr += 3; ! 555: ! 556: if ((NewRoute.NetDist == 0) || ! 557: (NewRoute.NetStop == 0) || ! 558: (NewRoute.NetStop >= DDP_STARTUP_LOW)) { ! 559: ! 560: dPrintf(D_M_RTMP, D_L_WARNING, ! 561: ("rtmp_update: P# %d, non valid tuple received [%d]\n", ! 562: ifID->ifPort, NewRoute.NetStop)); ! 563: ! 564: continue; ! 565: } ! 566: } ! 567: ! 568: if ((CurrentRoute = rt_blookup(NewRoute.NetStop))) { ! 569: /* found something... */ ! 570: ! 571: if (NewRoute.NetDist < 16 || ! 572: NewRoute.NetDist == NOTIFY_N_DIST ) { ! 573: ! 574: /* ! 575: * Check if the definition of the route changed ! 576: */ ! 577: ! 578: if (NewRoute.NetStop != CurrentRoute->NetStop || ! 579: NewRoute.NetStart != CurrentRoute->NetStart) { ! 580: ! 581: if (NewRoute.NetStop == CurrentRoute->NetStop && ! 582: NewRoute.NetStop == CurrentRoute->NetStart && ! 583: NewRoute.NetStart == 0) ! 584: ! 585: NewRoute.NetStart = NewRoute.NetStop; ! 586: ! 587: else if (NewRoute.NetStop == CurrentRoute->NetStop && ! 588: NewRoute.NetStart == NewRoute.NetStop && ! 589: CurrentRoute->NetStart == 0) { ! 590: dPrintf(D_M_RTMP, D_L_WARNING, ! 591: ("rtmp_update: Range %d-%d has changed to %d-%d Dist=%d\n", ! 592: CurrentRoute->NetStart, CurrentRoute->NetStop, ! 593: NewRoute.NetStart, NewRoute.NetStop, NewRoute.NetDist)); ! 594: NewRoute.NetStart = 0; ! 595: } ! 596: ! 597: else { ! 598: dPrintf(D_M_RTMP, D_L_WARNING, ! 599: ("rtmp_update: Net Conflict Cur=%d, New=%d\n", ! 600: CurrentRoute->NetStop, NewRoute.NetStop)); ! 601: CurrentRoute->EntryState = ! 602: (CurrentRoute->EntryState & 0xF0) | RTE_STATE_BAD; ! 603: continue; ! 604: ! 605: } ! 606: } ! 607: ! 608: /* ! 609: * If we don't know the associated zones ! 610: */ ! 611: ! 612: if (!RT_ALL_ZONES_KNOWN(CurrentRoute)) { ! 613: ! 614: dPrintf(D_M_RTMP_LOW, D_L_INFO, ! 615: ("rtmp_update: Zone unknown for %d-%d state=0x%x\n", ! 616: CurrentRoute->NetStart, CurrentRoute->NetStop, ! 617: CurrentRoute->EntryState)); ! 618: ! 619: /* set the flag in the ifID structure telling ! 620: * that a scheduling of Zip Query is needed. ! 621: */ ! 622: ! 623: ifID->ifZipNeedQueries = 1; ! 624: continue; ! 625: } ! 626: ! 627: if (((CurrentRoute->EntryState & 0x0F) <= RTE_STATE_SUSPECT) && ! 628: NewRoute.NetDist != NOTIFY_N_DIST) { ! 629: ! 630: dPrintf(D_M_RTMP, D_L_INFO, ! 631: ("rtmp_update: update suspect entry %d-%d State=%d\n", ! 632: NewRoute.NetStart, NewRoute.NetStop, ! 633: (CurrentRoute->EntryState & 0x0F))); ! 634: ! 635: if (NewRoute.NetDist <= CurrentRoute->NetDist) { ! 636: CurrentRoute->NetDist = NewRoute.NetDist; ! 637: CurrentRoute->NetPort = NewRoute.NetPort; ! 638: CurrentRoute->NextIRNode = NewRoute.NextIRNode; ! 639: CurrentRoute->NextIRNet = NewRoute.NextIRNet; ! 640: CurrentRoute->EntryState = ! 641: (CurrentRoute->EntryState & 0xF0) | ! 642: (RTE_STATE_GOOD|RTE_STATE_UPDATED); ! 643: } ! 644: continue; ! 645: } ! 646: else { ! 647: ! 648: if (NewRoute.NetDist == NOTIFY_N_DIST) { ! 649: ! 650: CurrentRoute->EntryState = ! 651: (CurrentRoute->EntryState & 0xF0) | RTE_STATE_SUSPECT; ! 652: CurrentRoute->NetDist = NOTIFY_N_DIST; ! 653: continue; ! 654: } ! 655: } ! 656: ! 657: } ! 658: ! 659: ! 660: if ((NewRoute.NetDist <= CurrentRoute->NetDist) && (NewRoute.NetDist <16)) { ! 661: ! 662: /* Found a shorter or more recent Route, ! 663: * Replace with the New entryi ! 664: */ ! 665: ! 666: CurrentRoute->NetDist = NewRoute.NetDist; ! 667: CurrentRoute->NetPort = NewRoute.NetPort; ! 668: CurrentRoute->NextIRNode = NewRoute.NextIRNode; ! 669: CurrentRoute->NextIRNet = NewRoute.NextIRNet; ! 670: CurrentRoute->EntryState |= RTE_STATE_UPDATED; ! 671: ! 672: /* Can we consider now that the entry is updated? */ ! 673: dPrintf(D_M_RTMP_LOW, D_L_INFO, ! 674: ("rtmp_update: Shorter route found %d-%d, update\n", ! 675: NewRoute.NetStart, NewRoute.NetStop)); ! 676: ! 677: if (ddp_AURPsendx && (aurp_ifID->ifFlags & AT_IFF_AURP)) ! 678: ddp_AURPsendx(AURPCODE_RTUPDATE, ! 679: (void *)&NewRoute, AURPEV_NetDistChange); ! 680: } ! 681: } ! 682: else { /* no entry found */ ! 683: ! 684: if (NewRoute.NetDist < 16 && NewRoute.NetDist != NOTIFY_N_DIST && ! 685: NewRoute.NextIRNet >= ifID->ifThisCableStart && ! 686: NewRoute.NextIRNet <= ifID->ifThisCableEnd) { ! 687: ! 688: NewRoute.EntryState = (RTE_STATE_GOOD|RTE_STATE_UPDATED); ! 689: ! 690: dPrintf(D_M_RTMP_LOW, D_L_INFO, ! 691: ("rtmp_update: NewRoute %d-%d Tuple #%d\n", ! 692: NewRoute.NetStart, NewRoute.NetStop, tuple_nb)); ! 693: ! 694: ifID->ifZipNeedQueries = 1; ! 695: ! 696: if (rt_insert(NewRoute.NetStop, NewRoute.NetStart, NewRoute.NextIRNet, ! 697: NewRoute.NextIRNode, NewRoute.NetDist, NewRoute.NetPort, ! 698: NewRoute.EntryState) == (RT_entry *)NULL) ! 699: ErrorRTMPoverflow = 1; ! 700: ! 701: else if (ddp_AURPsendx && (aurp_ifID->ifFlags & AT_IFF_AURP)) ! 702: ddp_AURPsendx(AURPCODE_RTUPDATE, ! 703: (void *)&NewRoute, AURPEV_NetAdded); ! 704: } ! 705: } ! 706: ! 707: } /* end of main while */ ! 708: ifID->ifRouterState = ROUTER_UPDATED; ! 709: if (ifID->ifZipNeedQueries) ! 710: zip_send_queries(ifID, 0, 0xFF); ! 711: ! 712: /* ! 713: timeout(rtmp_timeout, (caddr_t) ifID, 20*SYS_HZ); ! 714: */ ! 715: } /* rtmp_update */ ! 716: ! 717: /* The RTMP validity timer expired, we need to update the ! 718: * state of each routing entry in the table ! 719: * because there is only one validity timer and it is always running, ! 720: * we can't just age all the entries automatically, as we might be ! 721: * aging entries that were just updated. So, when an entry is updated, ! 722: * the RTE_STATE_UPDATED bit is set and when the aging routine is called ! 723: * it just resets this bit if it is set, only if it is not set will the ! 724: * route actually be aged. ! 725: * Note there are 4 states for an entry, the state is decremented until ! 726: * it reaches the bad state. At this point, the entry is removed ! 727: * ! 728: * RTE_STATE_GOOD : The entry was valid (will be SUSPECT) ! 729: * RTE_STATE_SUSPECT: The entry was suspect (can still be used for routing) ! 730: * RTE_STATE_BAD : The entry was bad and is now deleted ! 731: * RTE_STATE_UNUSED : Unused or removed entry in the table ! 732: */ ! 733: ! 734: void rtmp_timeout(ifID) ! 735: register at_ifaddr_t *ifID; ! 736: { ! 737: register u_char state; ! 738: register unsigned int s; ! 739: short i; ! 740: RT_entry *en = &RT_table[0]; ! 741: ! 742: if (ifID->ifRoutingState < PORT_ONLINE) ! 743: return; ! 744: ! 745: /* for multihoming mode, we use ifRouterState to tell if there ! 746: is a router out there, so we know when to use cable multicast */ ! 747: if (ifID->ifRouterState > NO_ROUTER) ! 748: ifID->ifRouterState--; ! 749: ! 750: ATDISABLE(s, ddpinp_lock); ! 751: for (i = 0 ; i < RT_maxentry; i++,en++) { ! 752: ! 753: /* we want to age "learned" nets, not directly connected ones */ ! 754: state = en->EntryState & 0x0F; ! 755: ! 756: ! 757: if (state > RTE_STATE_UNUSED && ! 758: !(en->EntryState & RTE_STATE_PERMANENT) && en->NetStop && ! 759: en->NetDist && en->NetPort == ifID->ifPort) { ! 760: ! 761: /* if entry has been updated recently, just clear the UPDATED ! 762: bit. if bit not set, then we can age the entry */ ! 763: if (en->EntryState & RTE_STATE_UPDATED) { ! 764: en->EntryState &= ~RTE_STATE_UPDATED; ! 765: continue; ! 766: } ! 767: else ! 768: state = state >> 1 ; /* decrement state */ ! 769: ! 770: if (state == RTE_STATE_UNUSED) {/* was BAD, needs to delete */ ! 771: dPrintf(D_M_RTMP, D_L_INFO, ! 772: ("rtmp_timeout: Bad State for %d-%d (e#%d): remove\n", ! 773: en->NetStart, en->NetStop, i)); ! 774: ! 775: if (ddp_AURPsendx && (aurp_ifID->ifFlags & AT_IFF_AURP)) ! 776: ddp_AURPsendx(AURPCODE_RTUPDATE, ! 777: (void *)en, AURPEV_NetDeleted); ! 778: ! 779: /* then clear the bit in the table concerning this entry. ! 780: If the zone Count reaches zero, remove the entry */ ! 781: ! 782: zt_remove_zones(en->ZoneBitMap); ! 783: ! 784: RT_DELETE(en->NetStop, en->NetStart); ! 785: } ! 786: else { ! 787: en->EntryState = (en->EntryState & 0xF0) | state; ! 788: dPrintf(D_M_RTMP, D_L_INFO, ("Change State for %d-%d to %d (e#%d)\n", ! 789: en->NetStart, en->NetStop, state, i)); ! 790: } ! 791: } ! 792: } ! 793: ATENABLE(s, ddpinp_lock); ! 794: timeout(rtmp_timeout, (caddr_t) ifID, 20*SYS_HZ); ! 795: ! 796: } ! 797: ! 798: /* ! 799: * rtmp_prep_new_packet: allocate a ddp packet for RTMP use (reply to a RTMP request or ! 800: * Route Data Request, or generation of RTMP data packets. ! 801: * The ddp header is filled with relevant information, as well as ! 802: * the beginning of the rtmp packet with the following info: ! 803: * Router's net number (2bytes) ! 804: * ID Length = 8 (1byte) ! 805: * Router's node ID (1byte) ! 806: * Extended Range Start (2bytes) ! 807: * Range + dist (0x80) (1byte) ! 808: * Extended Range End (2bytes) ! 809: * Rtmp version (0x82) (1byte) ! 810: * ! 811: */ ! 812: ! 813: gbuf_t *rtmp_prep_new_packet (ifID, DstNet, DstNode, socket) ! 814: register at_ifaddr_t *ifID; ! 815: register at_net DstNet; ! 816: register u_char DstNode; ! 817: register char socket; ! 818: ! 819: { ! 820: gbuf_t *m; ! 821: register at_ddp_t *ddp; ! 822: register char * rtmp_data; ! 823: ! 824: if ((m = gbuf_alloc(AT_WR_OFFSET+1024, PRI_HI)) == NULL) { ! 825: dPrintf(D_M_RTMP, D_L_WARNING, ("rtmp_new_packet: Can't allocate mblock\n")); ! 826: return ((gbuf_t *)NULL); ! 827: } ! 828: ! 829: gbuf_rinc(m,AT_WR_OFFSET); ! 830: gbuf_wset(m,DDP_X_HDR_SIZE + 10); ! 831: ddp = (at_ddp_t *)(gbuf_rptr(m)); ! 832: ! 833: /* ! 834: * Prepare the DDP header of the new packet ! 835: */ ! 836: ! 837: ! 838: ddp->unused = ddp->hopcount = 0; ! 839: ! 840: UAS_ASSIGN(ddp->checksum, 0); ! 841: ! 842: NET_NET(ddp->dst_net, DstNet); ! 843: ddp->dst_node = DstNode; ! 844: ddp->dst_socket = socket; ! 845: ! 846: NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net); ! 847: ddp->src_node = ifID->ifThisNode.s_node; ! 848: ddp->src_socket = RTMP_SOCKET; ! 849: ddp->type = DDP_RTMP; ! 850: ! 851: /* ! 852: * Prepare the RTMP header (Router Net, ID, Node and Net Tuple ! 853: * (this works only if we are on an extended net) ! 854: */ ! 855: ! 856: rtmp_data = ddp->data; ! 857: ! 858: *rtmp_data++ = (ifID->ifThisNode.s_net & 0xff00) >> 8; ! 859: *rtmp_data++ = ifID->ifThisNode.s_net & 0x00ff ; ! 860: *rtmp_data++ = 8; ! 861: *rtmp_data++ = (u_char)ifID->ifThisNode.s_node; ! 862: *rtmp_data++ = (CableStart & 0xff00) >> 8; ! 863: *rtmp_data++ = CableStart & 0x00ff ; ! 864: *rtmp_data++ = 0x80; /* first tuple, so distance is always zero */ ! 865: *rtmp_data++ = (CableStop & 0xff00) >> 8; ! 866: *rtmp_data++ = CableStop & 0x00ff ; ! 867: *rtmp_data++ = RTMP_VERSION_NUMBER; ! 868: ! 869: return (m); ! 870: ! 871: ! 872: } ! 873: int rtmp_r_find_bridge(ifID, orig_ddp) ! 874: register at_ifaddr_t *ifID; ! 875: register at_ddp_t *orig_ddp; ! 876: ! 877: { ! 878: gbuf_t *m; ! 879: register int size, status; ! 880: register at_ddp_t *ddp; ! 881: register char * rtmp_data; ! 882: RT_entry *Entry; ! 883: ! 884: ! 885: /* find the bridge for the querried net */ ! 886: ! 887: Entry = rt_blookup(NET_VALUE(orig_ddp->dst_net)); ! 888: ! 889: if (Entry == NULL) { ! 890: dPrintf(D_M_RTMP, D_L_WARNING, ("rtmp_r_find_bridge: no info for net %d\n", ! 891: NET_VALUE(orig_ddp->dst_net))); ! 892: return (1); ! 893: } ! 894: ! 895: ! 896: size = DDP_X_HDR_SIZE + 10 ; ! 897: if ((m = gbuf_alloc(AT_WR_OFFSET+size, PRI_HI)) == NULL) { ! 898: dPrintf(D_M_RTMP, D_L_WARNING, ! 899: ("rtmp_r_find_bridge: Can't allocate mblock\n")); ! 900: return (ENOBUFS); ! 901: } ! 902: ! 903: gbuf_rinc(m,AT_WR_OFFSET); ! 904: gbuf_wset(m,size); ! 905: ddp = (at_ddp_t *)(gbuf_rptr(m)); ! 906: ! 907: /* ! 908: * Prepare the DDP header of the new packet ! 909: */ ! 910: ! 911: ddp->unused = ddp->hopcount = 0; ! 912: ! 913: DDPLEN_ASSIGN(ddp, size); ! 914: UAS_ASSIGN(ddp->checksum, 0); ! 915: ! 916: NET_NET(ddp->dst_net, orig_ddp->src_net); ! 917: ddp->dst_node = orig_ddp->src_node; ! 918: ddp->dst_socket = orig_ddp->src_socket; ! 919: ! 920: NET_ASSIGN(ddp->src_net, Entry->NextIRNet); ! 921: ddp->src_node = Entry->NextIRNode; ! 922: ddp->src_socket = RTMP_SOCKET; ! 923: ddp->type = DDP_RTMP; ! 924: ! 925: /* ! 926: * Prepare the RTMP header (Router Net, ID, Node and Net Tuple ! 927: * (this works only if we are on an extended net) ! 928: */ ! 929: ! 930: rtmp_data = ddp->data; ! 931: ! 932: *rtmp_data++ = (Entry->NextIRNet & 0xff00) >> 8; ! 933: *rtmp_data++ = Entry->NextIRNet & 0x00ff ; ! 934: *rtmp_data++ = 8; ! 935: *rtmp_data++ = (u_char)Entry->NextIRNode; ! 936: *rtmp_data++ = (Entry->NetStart & 0xff00) >> 8; ! 937: *rtmp_data++ = Entry->NetStart & 0x00ff ; ! 938: *rtmp_data++ = 0x80; /* first tuple, so distance is always zero */ ! 939: *rtmp_data++ = (Entry->NetStop & 0xff00) >> 8; ! 940: *rtmp_data++ = Entry->NetStop & 0x00ff ; ! 941: *rtmp_data++ = RTMP_VERSION_NUMBER; ! 942: ! 943: ! 944: dPrintf(D_M_RTMP, D_L_INFO, ("rtmp_r_find_bridge: for net %d send back router %d.%d\n", ! 945: NET_VALUE(orig_ddp->dst_net), Entry->NextIRNet, Entry->NextIRNode)); ! 946: if (status = ddp_router_output(m, ifID, AT_ADDR, NET_VALUE(orig_ddp->src_net), ! 947: orig_ddp->src_node, 0)){ ! 948: dPrintf(D_M_RTMP, D_L_WARNING, ! 949: ("rtmp_r_find_bridge: ddp_router_output failed status=%d\n", status)); ! 950: return (status); ! 951: } ! 952: return (0); ! 953: } ! 954: ! 955: /* ! 956: * rtmp_send_table: ! 957: * Send the routing table entries in RTMP data packets. ! 958: * Use split horizon if specified. The Data packets are sent ! 959: * as full DDP packets, if the last packet is full an empty ! 960: * packet is sent to tell the recipients that this is the end of ! 961: * the table... ! 962: * ! 963: */ ! 964: static int rtmp_send_table(ifID, DestNet, DestNode, split_hz, socket, ! 965: n_neighbors) ! 966: register at_ifaddr_t *ifID; /* interface/port params */ ! 967: register at_net DestNet; /* net where to send the table */ ! 968: register u_char DestNode; /* node where to send to table */ ! 969: short split_hz; /* use split horizon */ ! 970: char socket; /* the destination socket to send to */ ! 971: short n_neighbors; /* used to send packets telling we are going down */ ! 972: { ! 973: ! 974: RT_entry *Entry; ! 975: char *Buff_ptr; ! 976: u_char NewDist; ! 977: gbuf_t *m; ! 978: short size,status ; ! 979: register at_ddp_t *ddp; ! 980: register short EntNb = 0, sent_tuple = 0; ! 981: register unsigned int s; ! 982: ! 983: if (ifID->ifRoutingState < PORT_ONLINE) { ! 984: dPrintf(D_M_RTMP, D_L_INFO, ! 985: ("rtmp_send_table: port %d activating, we don't send anything!\n", ! 986: ifID->ifPort)); ! 987: return (0); ! 988: } ! 989: ! 990: /* prerare tuples and packets for DDP*/ ! 991: /* if split horizon, do not send tuples we can reach on the port we ! 992: * want to send too ! 993: */ ! 994: ! 995: Entry = &RT_table[0]; ! 996: size = 0; ! 997: if (!(m = rtmp_prep_new_packet(ifID, DestNet, DestNode, socket))) { ! 998: dPrintf(D_M_RTMP, D_L_WARNING, ! 999: ("rtmp_send_table: rtmp_prep_new_packet failed\n")); ! 1000: return(ENOBUFS); ! 1001: } ! 1002: ! 1003: ddp = (at_ddp_t *)(gbuf_rptr(m)); ! 1004: Buff_ptr = (char *)((char *)ddp + DDP_X_HDR_SIZE + 10); ! 1005: ! 1006: ATDISABLE(s, ddpinp_lock); ! 1007: while (EntNb < RT_maxentry) { ! 1008: ! 1009: if (Entry->NetStop && ((Entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT)) { ! 1010: if (!(split_hz && ifID->ifPort == Entry->NetPort)) { ! 1011: sent_tuple++; ! 1012: ! 1013: if (((Entry->EntryState & 0x0F) < RTE_STATE_SUSPECT) || n_neighbors) ! 1014: NewDist = NOTIFY_N_DIST; ! 1015: else ! 1016: NewDist = Entry->NetDist & 0x1F; ! 1017: ! 1018: if (Entry->NetStart) { /* Extended */ ! 1019: *Buff_ptr++ = (Entry->NetStart & 0xFF00) >> 8; ! 1020: *Buff_ptr++ = (Entry->NetStart & 0x00FF); ! 1021: *Buff_ptr++ = 0x80 | NewDist; ! 1022: *Buff_ptr++ = (Entry->NetStop & 0xFF00) >> 8; ! 1023: *Buff_ptr++ = (Entry->NetStop & 0x00FF); ! 1024: *Buff_ptr++ = RTMP_VERSION_NUMBER; ! 1025: size += 6; ! 1026: } ! 1027: else { /* non extended tuple */ ! 1028: *Buff_ptr++ = (Entry->NetStop & 0xFF00) >> 8; ! 1029: *Buff_ptr++ = (Entry->NetStop & 0x00FF); ! 1030: *Buff_ptr++ = NewDist; ! 1031: size += 3; ! 1032: } ! 1033: } ! 1034: } ! 1035: ! 1036: if (size > (DDP_MAX_DATA-20)) { ! 1037: DDPLEN_ASSIGN(ddp, size + DDP_X_HDR_SIZE + 10); ! 1038: gbuf_winc(m,size); ! 1039: ATENABLE(s, ddpinp_lock); ! 1040: if (status = ddp_router_output(m, ifID, AT_ADDR, ! 1041: NET_VALUE(DestNet),DestNode, 0)){ ! 1042: dPrintf(D_M_RTMP, D_L_WARNING, ! 1043: ("rtmp_send_table: ddp_router_output failed status=%d\n", ! 1044: status)); ! 1045: return (status); ! 1046: } ! 1047: if ((m = rtmp_prep_new_packet (ifID, DestNet, DestNode, socket)) == NULL){ ! 1048: dPrintf(D_M_RTMP, D_L_WARNING, ! 1049: ("rtmp_send_table: rtmp_prep_new_poacket failed status=%d\n", ! 1050: status)); ! 1051: return (ENOBUFS); ! 1052: } ! 1053: ddp = (at_ddp_t *)(gbuf_rptr(m)); ! 1054: Buff_ptr = (char *)((char *)ddp + DDP_X_HDR_SIZE + 10); ! 1055: ! 1056: dPrintf(D_M_RTMP_LOW, D_L_OUTPUT, ! 1057: ("rtmp_s_tble: Send %d tuples on port %d\n", ! 1058: sent_tuple, ifID->ifPort)); ! 1059: sent_tuple = 0; ! 1060: size = 0; ! 1061: ATDISABLE(s, ddpinp_lock); ! 1062: } ! 1063: ! 1064: Entry++; ! 1065: EntNb++; ! 1066: } ! 1067: ATENABLE(s, ddpinp_lock); ! 1068: ! 1069: /* ! 1070: * If we have some remaining entries to send, send them now. ! 1071: * otherwise, the last packet we sent was full, we need to send an empty one ! 1072: */ ! 1073: ! 1074: DDPLEN_ASSIGN(ddp, size + DDP_X_HDR_SIZE + 10); ! 1075: gbuf_winc(m,size); ! 1076: if ((status = ! 1077: ddp_router_output(m, ifID, AT_ADDR, NET_VALUE(DestNet),DestNode, 0))){ ! 1078: dPrintf(D_M_RTMP, D_L_WARNING, ! 1079: ("rtmp_send_table: ddp_router_output failed status=%d\n", status)); ! 1080: return (status); ! 1081: } ! 1082: dPrintf(D_M_RTMP_LOW, D_L_OUTPUT, ! 1083: ("rtmp_s_tble: LAST Packet split=%d with %d tuples sent on port %d\n", ! 1084: split_hz, sent_tuple, ifID->ifPort)); ! 1085: ! 1086: return (0); ! 1087: } ! 1088: ! 1089: /* ! 1090: * rtmp_request: respond to the 3 types of RTMP requests RTMP may receive ! 1091: * RTMP func =1 : respond with an RTMP Reponse Packet ! 1092: * RTMP func =2 : respond with the routing table RTMP packet with split horizon ! 1093: * RTMP func =3 : respond with the routing table RTMP packet no split horizon ! 1094: * ! 1095: * see Inside AppleTalk around page 5-18 for "details" ! 1096: */ ! 1097: ! 1098: static void rtmp_request(ifID, ddp) ! 1099: register at_ifaddr_t *ifID; ! 1100: register at_ddp_t *ddp; ! 1101: { ! 1102: ! 1103: short split_horizon = FALSE; ! 1104: short code; ! 1105: short error; ! 1106: ! 1107: /* We ignore the request if we're activating on that port */ ! 1108: ! 1109: if (ifID->ifRoutingState < PORT_ONLINE) ! 1110: return; ! 1111: ! 1112: /* check RTMP function code */ ! 1113: ! 1114: code = ddp->data[0]; ! 1115: ! 1116: switch (code) { ! 1117: ! 1118: case RTMP_REQ_FUNC1: /* RTMP Find Bridge */ ! 1119: ! 1120: /* RTMP Request Packet: we send a response with the next IRrange */ ! 1121: dPrintf(D_M_RTMP, D_L_INPUT, ! 1122: ( "rtmp_request: find bridge for net %d port %d node %d.%d\n", ! 1123: NET_VALUE(ddp->dst_net), ifID->ifPort, ! 1124: NET_VALUE(ddp->src_net), ddp->src_node)); ! 1125: ! 1126: if ((error = rtmp_r_find_bridge (ifID, ddp))) { ! 1127: dPrintf(D_M_RTMP, D_L_WARNING, ! 1128: ("rtmp_request: Code 1 ddp_r_output failed error=%d\n", ! 1129: error)); ! 1130: return; ! 1131: } ! 1132: ! 1133: break; ! 1134: ! 1135: case RTMP_REQ_FUNC2: ! 1136: ! 1137: split_horizon = TRUE; ! 1138: ! 1139: case RTMP_REQ_FUNC3: ! 1140: ! 1141: /* RTMP Route Request Packet */ ! 1142: ! 1143: dPrintf(D_M_RTMP, D_L_INPUT, ! 1144: ("rtmp_request: received code=%d from %d.%d for %d.%d\n", ! 1145: code, NET_VALUE(ddp->src_net), ddp->src_node, ! 1146: NET_VALUE(ddp->dst_net), ddp->dst_node)); ! 1147: ! 1148: rtmp_send_table(ifID, ddp->src_net, ddp->src_node, ! 1149: split_horizon, ddp->src_socket, 0); ! 1150: ! 1151: break; ! 1152: ! 1153: default: ! 1154: ! 1155: /* unknown type of request */ ! 1156: dPrintf(D_M_RTMP, D_L_WARNING, ! 1157: ("rtmp_request : invalid type of request =%d\n", ! 1158: code)); ! 1159: break; ! 1160: } ! 1161: ! 1162: } ! 1163: ! 1164: /* ! 1165: * rtmp_send_all_ports : send the routing table on all connected ports ! 1166: * check for the port status and if ok, send the ! 1167: * rtmp tuples to the broadcast address for the port ! 1168: * usually called on timeout every 10 seconds. ! 1169: */ ! 1170: ! 1171: void rtmp_send_port(ifID) ! 1172: register at_ifaddr_t *ifID; ! 1173: { ! 1174: at_net DestNet; ! 1175: ! 1176: NET_ASSIGN(DestNet, 0); ! 1177: ! 1178: if (ifID && ifID->ifRoutingState == PORT_ONLINE) { ! 1179: dPrintf(D_M_RTMP_LOW, D_L_OUTPUT, ! 1180: ("rtmp_send_port: do stuff for port=%d\n", ! 1181: ifID->ifPort)); ! 1182: if (ifID->ifZipNeedQueries) ! 1183: zip_send_queries(ifID, 0, 0xFF); ! 1184: if (!ROUTING_MODE) ! 1185: return; ! 1186: rtmp_send_table(ifID, DestNet, 0xFF, 1, RTMP_SOCKET, 0); ! 1187: } ! 1188: ! 1189: if (ifID == ifID_home) ! 1190: dPrintf(D_M_RTMP_LOW, D_L_VERBOSE, ! 1191: ("I:%5d O:%5d H:%5d dropped:%d\n", ! 1192: pktsIn, pktsOut, pktsHome, pktsDropped)); ! 1193: ! 1194: dPrintf(D_M_RTMP_LOW, D_L_TRACE, ! 1195: ("rtmp_send_port: func=0x%x, ifID=0x%x\n", ! 1196: (u_int) rtmp_send_port, (u_int) ifID)); ! 1197: timeout (rtmp_send_port, (caddr_t)ifID, 10 * SYS_HZ); ! 1198: } ! 1199: ! 1200: /* rtmp_dropper: check the number of packet received every x secondes. ! 1201: * the actual packet dropping is done in ddp_input ! 1202: */ ! 1203: ! 1204: void rtmp_dropper() ! 1205: { ! 1206: pktsIn = pktsOut = pktsHome = pktsDropped = 0; ! 1207: timeout(rtmp_dropper, NULL, 2*SYS_HZ); ! 1208: } ! 1209: ! 1210: /* ! 1211: * rtmp_router_start: perform the sanity checks before declaring the router up ! 1212: * and running. This function looks for discrepency between the net infos ! 1213: * for the different ports and seed problems. ! 1214: * If everything is fine, the state of each port is brought to PORT_ONLINE.\ ! 1215: * ### LD 01/09/95 Changed to correct Zone problem on non seed ports. ! 1216: */ ! 1217: ! 1218: int rtmp_router_start(keP) ! 1219: at_kern_err_t *keP; /* used to report errors (if any) */ ! 1220: { ! 1221: int err = 0; ! 1222: register at_ifaddr_t *ifID, *ifID2; ! 1223: register short Index, router_starting_timer = 0; ! 1224: register RT_entry *Entry; ! 1225: register at_net_al netStart, netStop; ! 1226: ! 1227: /* clear the static structure used to record routing errors */ ! 1228: bzero(&ke, sizeof(ke)); ! 1229: ! 1230: TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) { ! 1231: ! 1232: /* if non seed, need to acquire the right node address */ ! 1233: ! 1234: if ((ifID->ifFlags & RTR_SEED_PORT) == 0) { ! 1235: if ((ifID->ifThisCableStart == 0 && ifID->ifThisCableEnd == 0) || ! 1236: (ifID->ifThisCableStart >= DDP_STARTUP_LOW && ! 1237: ifID->ifThisCableEnd <= DDP_STARTUP_HIGH)) { ! 1238: ! 1239: if (ifID->ifThisCableEnd == 0) { ! 1240: keP->error = KE_NO_SEED; ! 1241: keP->port1 = ifID->ifPort; ! 1242: strncpy(keP->name1, ifID->ifName,sizeof(keP->name1)); ! 1243: } ! 1244: else { ! 1245: keP->error = KE_INVAL_RANGE; ! 1246: keP->port1 = ifID->ifPort; ! 1247: strncpy(keP->name1, ifID->ifName,sizeof(keP->name1)); ! 1248: keP->netr1b = ifID->ifThisCableStart; ! 1249: keP->netr1e = ifID->ifThisCableEnd; ! 1250: } ! 1251: ifID->ifRoutingState = PORT_ERR_STARTUP; ! 1252: RouterError(ifID->ifPort, ERTR_CABLE_STARTUP); ! 1253: ! 1254: goto error; ! 1255: } ! 1256: ! 1257: /* we are non seed, so try to acquire the zones for that guy */ ! 1258: ifID->ifZipNeedQueries = 1; ! 1259: ! 1260: dPrintf(D_M_RTMP, D_L_STARTUP, ! 1261: ("rtmp_router_start: call elap_online for Non Seed port #%d cable =%d-%d\n", ! 1262: ifID->ifPort, CableStart, CableStop)); ! 1263: if ((err = elap_online3(ifID))) ! 1264: goto error; ! 1265: } ! 1266: } ! 1267: ! 1268: /* Check if we have a problem with the routing table size */ ! 1269: ! 1270: if (ErrorRTMPoverflow) { ! 1271: keP->error = KE_RTMP_OVERFLOW; ! 1272: goto error; ! 1273: } ! 1274: ! 1275: ! 1276: /* Now, check that we don't have a conflict in between our interfaces */ ! 1277: TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) { ! 1278: ! 1279: /* check if the RoutingState != PORT_ONERROR */ ! 1280: if (ifID->ifRoutingState < PORT_ACTIVATING) { ! 1281: goto error; ! 1282: } ! 1283: ! 1284: if ((ifID->ifThisCableStart == 0 && ifID->ifThisCableEnd == 0) || ! 1285: (ifID->ifThisCableStart >= DDP_STARTUP_LOW && ! 1286: ifID->ifThisCableEnd <= DDP_STARTUP_HIGH)) { ! 1287: ! 1288: if (ifID->ifThisCableEnd == 0) { ! 1289: keP->error = KE_NO_SEED; ! 1290: keP->port1 = ifID->ifPort; ! 1291: strncpy(keP->name1, ifID->ifName,sizeof(keP->name1)); ! 1292: } ! 1293: else { ! 1294: keP->error = KE_INVAL_RANGE; ! 1295: keP->port1 = ifID->ifPort; ! 1296: strncpy(keP->name1, ifID->ifName,sizeof(keP->name1)); ! 1297: keP->netr1b = ifID->ifThisCableStart; ! 1298: keP->netr1e = ifID->ifThisCableEnd; ! 1299: } ! 1300: ! 1301: ifID->ifRoutingState = PORT_ERR_STARTUP; ! 1302: RouterError(ifID->ifPort, ERTR_CABLE_STARTUP); ! 1303: ! 1304: goto error; ! 1305: } ! 1306: ! 1307: /* check the interface address against all other ifs */ ! 1308: ! 1309: netStart = ifID->ifThisCableStart; ! 1310: netStop = ifID->ifThisCableEnd; ! 1311: ! 1312: for (ifID2 = TAILQ_NEXT(ifID, aa_link); ifID2; ! 1313: ifID2 = TAILQ_NEXT(ifID2, aa_link)) { ! 1314: ! 1315: if (((netStart >= ifID2->ifThisCableStart) && ! 1316: (netStart <= ifID2->ifThisCableEnd)) || ! 1317: ((netStop >= ifID2->ifThisCableStart) && ! 1318: (netStop <= ifID2->ifThisCableEnd)) || ! 1319: ((ifID2->ifThisCableStart >= netStart) && ! 1320: (ifID2->ifThisCableStart <= netStop)) || ! 1321: ((ifID2->ifThisCableEnd >= netStart) && ! 1322: (ifID2->ifThisCableEnd <= netStop)) ) { ! 1323: ! 1324: keP->error = KE_CONF_RANGE; ! 1325: keP->port1 = ifID->ifPort; ! 1326: strncpy(keP->name1, ifID->ifName,sizeof(keP->name1)); ! 1327: keP->port2 = ifID2->ifPort; ! 1328: strncpy(keP->name2, ifID2->ifName,sizeof(keP->name2)); ! 1329: keP->netr1b = ifID->ifThisCableStart; ! 1330: keP->netr1e = ifID->ifThisCableEnd; ! 1331: ifID->ifRoutingState = PORT_ERR_CABLER; ! 1332: RouterError(ifID->ifPort, ERTR_CABLE_CONFLICT); ! 1333: goto error; ! 1334: } ! 1335: ! 1336: } ! 1337: ! 1338: /* ### LD 01/04/94: We need to fill in the next IR info in the routing table */ ! 1339: Entry = rt_blookup(ifID->ifThisCableEnd); ! 1340: ! 1341: if (Entry == NULL) { ! 1342: dPrintf(D_M_RTMP, D_L_ERROR, ! 1343: ("rtmp_router_start: we don't know our cable range port=%d\n", ! 1344: ifID->ifPort)); ! 1345: ! 1346: goto error; ! 1347: } ! 1348: ! 1349: /* ! 1350: * Note: At this point, non seed ports may not be aware of their Default zone ! 1351: */ ! 1352: ! 1353: if (!(ifID->ifFlags & RTR_SEED_PORT)) { ! 1354: ifID->ifDefZone = 0; ! 1355: Entry->EntryState |= (RTE_STATE_GOOD|RTE_STATE_UPDATED); ! 1356: } ! 1357: ! 1358: ifID->ifRoutingState = PORT_ONLINE; ! 1359: ifID->ifState = LAP_ONLINE; ! 1360: ! 1361: /* set the right net and node for each port */ ! 1362: Entry->NextIRNet = ifID->ifThisNode.s_net; ! 1363: Entry->NextIRNode= ifID->ifThisNode.s_node; ! 1364: ! 1365: dPrintf(D_M_RTMP, D_L_STARTUP, ! 1366: ("rtmp_router_start: bring port=%d [%d.%d]... on line\n", ! 1367: ifID->ifPort, ifID->ifThisNode.s_net, ! 1368: ifID->ifThisNode.s_node)); ! 1369: ! 1370: } ! 1371: ! 1372: /* ! 1373: * Everything is fine, we can begin to babble on the net... ! 1374: */ ! 1375: ! 1376: TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) { ! 1377: if (ifID->ifRoutingState == PORT_ONLINE) { ! 1378: rtmp_send_port(ifID); ! 1379: timeout(rtmp_timeout, (caddr_t)ifID, (50+ifID->ifPort) * SYS_HZ); ! 1380: if (ifID->ifRoutingState < PORT_ACTIVATING) { ! 1381: goto error; ! 1382: } ! 1383: } ! 1384: } ! 1385: ! 1386: /* Check if we have a problem with the routing or zip table size */ ! 1387: ! 1388: if (ErrorRTMPoverflow) { ! 1389: keP->error = KE_RTMP_OVERFLOW; ! 1390: goto error; ! 1391: } ! 1392: if (ErrorZIPoverflow) { ! 1393: keP->error = KE_ZIP_OVERFLOW; ! 1394: goto error; ! 1395: } ! 1396: ! 1397: /* sleep for 10 seconds */ ! 1398: if ((err = ! 1399: /* *** eventually this will be the ifID for the interface ! 1400: being brought up in router mode *** */ ! 1401: /* *** router sends rtmp packets every 10 seconds *** */ ! 1402: tsleep(&ifID_home->startup_inprogress, ! 1403: PSOCK | PCATCH, "router_start1", (10+1) * SYS_HZ)) ! 1404: != EWOULDBLOCK) { ! 1405: goto error; ! 1406: } ! 1407: ! 1408: startZoneInfo: ! 1409: err = 0; ! 1410: TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) { ! 1411: ! 1412: if (ifID->ifRoutingState < PORT_ACTIVATING) { ! 1413: goto error; ! 1414: } ! 1415: ! 1416: if ((ifID->ifZipNeedQueries) ! 1417: && (ifID->ifFlags & RTR_SEED_PORT) == 0) { ! 1418: dPrintf(D_M_RTMP, D_L_STARTUP, ! 1419: ("rtmp_router_start: send Zip Queries for Port %d\n", ! 1420: ifID->ifPort)); ! 1421: zip_send_queries(ifID, 0, 0xFF); ! 1422: ! 1423: if (router_starting_timer >= 10) { ! 1424: dPrintf(D_M_RTMP, D_L_WARNING, ! 1425: ("rtmp_router_start: no received response to ZipNeedQueries\n")); ! 1426: keP->error = KE_NO_ZONES_FOUND; ! 1427: keP->port1 = ifID->ifPort; ! 1428: strncpy(keP->name1, ifID->ifName,sizeof(keP->name1)); ! 1429: keP->netr1b = ifID->ifThisCableStart; ! 1430: keP->netr1e = ifID->ifThisCableEnd; ! 1431: ifID->ifRoutingState = PORT_ERR_CABLER; ! 1432: RouterError(ifID->ifPort, ERTR_CABLE_CONFLICT); ! 1433: goto error; ! 1434: } ! 1435: ! 1436: dPrintf(D_M_RTMP, D_L_STARTUP, ! 1437: ("rtmp_router_start: waiting for zone info to complete\n")); ! 1438: /* sleep for 10 seconds */ ! 1439: if ((err = ! 1440: /* *** eventually this will be the ifID for the ! 1441: interface being brought up in router mode *** */ ! 1442: tsleep(&ifID_home->startup_inprogress, ! 1443: PSOCK | PCATCH, "router_start2", 10 * SYS_HZ)) ! 1444: != EWOULDBLOCK) { ! 1445: goto error; ! 1446: } ! 1447: ! 1448: err = 0; ! 1449: router_starting_timer++; ! 1450: goto startZoneInfo; ! 1451: } ! 1452: ! 1453: } ! 1454: ! 1455: /* At This Point, check if we know the default zones for non seed port */ ! 1456: ! 1457: TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) { ! 1458: ! 1459: if (ifID->ifRoutingState < PORT_ACTIVATING) ! 1460: goto error; ! 1461: ! 1462: if (!(ifID->ifFlags & RTR_SEED_PORT)) { ! 1463: Entry = rt_blookup(ifID->ifThisCableEnd); ! 1464: ! 1465: if (Entry == NULL) { ! 1466: dPrintf(D_M_RTMP, D_L_ERROR, ! 1467: ("rtmp_router_start: (2)we don't know our cable range port=%d\n", ! 1468: ifID->ifPort)); ! 1469: goto error; ! 1470: } ! 1471: ! 1472: dPrintf(D_M_RTMP, D_L_STARTUP, ! 1473: ("rtmp_router_start: if %s set to permanent\n", ! 1474: ifID->ifName)); ! 1475: Entry->NetDist = 0; /* added 4-29-96 jjs, prevent direct ! 1476: nets from showing non-zero ! 1477: distance */ ! 1478: /* upgrade the non seed ports. */ ! 1479: Entry->EntryState |= RTE_STATE_PERMANENT; ! 1480: ! 1481: Index = zt_ent_zindex(Entry->ZoneBitMap); ! 1482: if (Index <= 0) { ! 1483: dPrintf(D_M_RTMP, D_L_ERROR, ! 1484: ("rtmp_router_start: still don't know default zone for port %d\n", ! 1485: ifID->ifPort)); ! 1486: } else { ! 1487: ifID->ifDefZone = Index; ! 1488: if ((ifID == ifID_home) || MULTIHOME_MODE) { ! 1489: ifID->ifZoneName = ZT_table[Index-1].Zone; ! 1490: (void)regDefaultZone(ifID); ! 1491: } ! 1492: } ! 1493: } ! 1494: } ! 1495: ! 1496: /* Check if we have a problem with the routing or zip table size */ ! 1497: ! 1498: if (ErrorRTMPoverflow) { ! 1499: keP->error = KE_RTMP_OVERFLOW; ! 1500: goto error; ! 1501: } ! 1502: if (ErrorZIPoverflow) { ! 1503: keP->error = KE_ZIP_OVERFLOW; ! 1504: goto error; ! 1505: } ! 1506: ! 1507: /* ! 1508: * Handle the Home Port specifics ! 1509: */ ! 1510: ! 1511: /* set the router address as being us no matter what*/ ! 1512: ifID_home->ifARouter = ifID_home->ifThisNode; ! 1513: ifID_home->ifRouterState = ROUTER_UPDATED; ! 1514: ! 1515: /* prepare the packet dropper timer */ ! 1516: timeout (rtmp_dropper, NULL, 1*SYS_HZ); ! 1517: ! 1518: return(0); ! 1519: ! 1520: error: ! 1521: dPrintf(D_M_RTMP,D_L_ERROR, ! 1522: ("rtmp_router_start: error type=%d occured on port %d\n", ! 1523: ifID->ifRoutingState, ifID->ifPort)); ! 1524: ! 1525: /* if there's no keP->error, copy the local ke structure, ! 1526: since the error occured asyncronously */ ! 1527: if ((!keP->error) && ke.error) ! 1528: bcopy(&ke, keP, sizeof(ke)); ! 1529: rtmp_shutdown(); ! 1530: ! 1531: /* to return the error in keP, the ioctl has to return 0 */ ! 1532: return((keP->error)? 0: err); ! 1533: } /* rtmp_router_start */ ! 1534: ! 1535: ! 1536: void rtmp_shutdown() ! 1537: { ! 1538: register at_ifaddr_t *ifID; ! 1539: register short i; ! 1540: at_net DestNet; ! 1541: ! 1542: NET_ASSIGN(DestNet, 0); ! 1543: ! 1544: dPrintf(D_M_RTMP, D_L_SHUTDN, ! 1545: ("rtmp_shutdown:stop sending to all ports\n")); ! 1546: ! 1547: untimeout(rtmp_dropper, (caddr_t)0); ! 1548: untimeout(rtmp_router_start, 1); /* added for 2225395 */ ! 1549: untimeout(rtmp_router_start, 3); /* added for 2225395 */ ! 1550: ! 1551: TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) { ! 1552: if (ifID->ifRoutingState > PORT_OFFLINE ) { ! 1553: if (ifID->ifRoutingState == PORT_ONLINE) { ! 1554: untimeout(rtmp_send_port, (caddr_t)ifID); ! 1555: untimeout(rtmp_timeout, (caddr_t) ifID); ! 1556: } ! 1557: /* ! 1558: * it's better to notify the neighbour routers that we are going down ! 1559: */ ! 1560: if (ROUTING_MODE) ! 1561: rtmp_send_table(ifID, DestNet, 0xFF, TRUE, ! 1562: RTMP_SOCKET, TRUE); ! 1563: ! 1564: ifID->ifRoutingState = PORT_OFFLINE; ! 1565: ! 1566: dPrintf(D_M_RTMP, D_L_SHUTDN, ! 1567: ("rtmp_shutdown: routing on port=%d... off line\nStats:\n", ! 1568: ifID->ifPort)); ! 1569: dPrintf(D_M_RTMP, D_L_SHUTDN, ! 1570: ("fwdBytes : %ld\nfwdPackets : %ld\ndroppedBytes : %ld\ndroppedPkts : %ld\n", ! 1571: ifID->ifStatistics.fwdBytes, ifID->ifStatistics.fwdPkts, ! 1572: ifID->ifStatistics.droppedBytes, ifID->ifStatistics.droppedPkts)); ! 1573: ! 1574: } ! 1575: } ! 1576: ! 1577: } ! 1578: ! 1579: /* ! 1580: * Remove all entries associated with the specified port. ! 1581: */ ! 1582: void rtmp_purge(ifID) ! 1583: at_ifaddr_t *ifID; ! 1584: { ! 1585: u_char state; ! 1586: int i, s; ! 1587: RT_entry *en = &RT_table[0]; ! 1588: ! 1589: ATDISABLE(s, ddpinp_lock); ! 1590: for (i=0; i < RT_maxentry; i++) { ! 1591: state = en->EntryState & 0x0F; ! 1592: if ((state > RTE_STATE_UNUSED) && (state != RTE_STATE_PERMANENT) ! 1593: && en->NetStop && en->NetDist && (en->NetPort == ifID->ifPort)) { ! 1594: zt_remove_zones(en->ZoneBitMap); ! 1595: RT_DELETE(en->NetStop, en->NetStart); ! 1596: } ! 1597: en++; ! 1598: } ! 1599: ATENABLE(s, ddpinp_lock); ! 1600: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.