|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 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: * ! 24: * RTMP & ZIP routing tables access routines ! 25: * ! 26: * This code implement b-tree search and manipulation of ! 27: * of the RTMP routing table and ZIP zone table. ! 28: * ! 29: * The RTMP routing table is a data block divided in several routing ! 30: * entries sorted during insertion in a b-tree form. We use a table and ! 31: * not dynamically allocated entries because it allow us to scan the whole ! 32: * table when RTMP packets are generated. The routing table entries are sorted ! 33: * by there NetStop value (because non extended nets have a NetStart value of ! 34: * zero. From any point in the tree, the left side contains Network ranges ! 35: * smaller or equal to the current Node, and the right tree points to higher ! 36: * values network ranges. ! 37: * ! 38: * ! 39: * 0.01 3/16/94 LD Creation ! 40: * Modified for MP, 1996 by Tuyen Nguyen ! 41: * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX. ! 42: * ! 43: *---------------------------------------------------------------------------- ! 44: * ! 45: * Copyright (c) 1994, 1996, 1997, 1998 Apple Computer, Inc. ! 46: */ ! 47: ! 48: #include <sys/errno.h> ! 49: #include <sys/types.h> ! 50: #include <sys/param.h> ! 51: #include <machine/spl.h> ! 52: #include <sys/systm.h> ! 53: #include <sys/kernel.h> ! 54: #include <sys/proc.h> ! 55: #include <sys/filedesc.h> ! 56: #include <sys/fcntl.h> ! 57: #include <sys/mbuf.h> ! 58: #include <sys/ioctl.h> ! 59: #include <sys/malloc.h> ! 60: #include <sys/socket.h> ! 61: #include <sys/socketvar.h> ! 62: ! 63: #include <net/if.h> ! 64: #include <net/if_types.h> ! 65: ! 66: #include <netat/sysglue.h> ! 67: #include <netat/appletalk.h> ! 68: #include <netat/at_var.h> ! 69: #include <netat/lap.h> ! 70: #include <netat/ddp.h> ! 71: #include <netat/rtmp.h> ! 72: #include <netat/at_pcb.h> ! 73: #include <netat/zip.h> ! 74: #include <netat/routing_tables.h> ! 75: #include <netat/at_snmp.h> ! 76: #include <netat/debug.h> ! 77: #include <netat/at_config.h> ! 78: ! 79: RT_entry *RT_table_freelist; /* start of free entry list */ ! 80: RT_entry RT_table_start; /* start of the actual entry table */ ! 81: RT_entry *RT_table; /* the routing table */ ! 82: ZT_entry *ZT_table; /* the Zone Information Protocol table */ ! 83: short RT_maxentry; /* Number of entry in RTMP table */ ! 84: short ZT_maxentry; /* Number of entry in ZIP table */ ! 85: ! 86: char errstr[512]; /* used to display meaningfull router errors*/ ! 87: ! 88: extern at_ifaddr_t *ifID_table[]; ! 89: extern at_ifaddr_t *ifID_home; ! 90: extern snmpStats_t snmpStats; ! 91: extern atlock_t ddpinp_lock; ! 92: ! 93: short ErrorRTMPoverflow = 0; /* flag if RTMP table is too small for this net */ ! 94: short ErrorZIPoverflow = 0; /* flag if ZIP table is too small for this net */ ! 95: ! 96: /* prototypes */ ! 97: void getIfUsage( int, char*); ! 98: ! 99: /* ! 100: * This a temporary function : just to display the router error ! 101: */ ! 102: ! 103: void RouterError(port, err_number) ! 104: short port, err_number; ! 105: ! 106: { ! 107: switch (err_number) { ! 108: ! 109: case ERTR_SEED_CONFLICT: ! 110: dPrintf(D_M_RTMP, D_L_ERROR, ! 111: ("**** RTR Error on port# %d SEED_CONFLICT\n", port)); ! 112: break; ! 113: ! 114: case ERTR_CABLE_CONFLICT: ! 115: dPrintf(D_M_RTMP, D_L_ERROR, ! 116: ("**** RTR Error on port# %d CABLE_CONFLICT\n", port)); ! 117: break; ! 118: ! 119: case ERTR_RTMP_BAD_VERSION: ! 120: dPrintf(D_M_RTMP, D_L_ERROR, ! 121: ("**** RTR Error on port# %d RTMP_BAD_VERSION\n", port)); ! 122: break; ! 123: ! 124: case ERTR_CABLE_STARTUP: ! 125: dPrintf(D_M_RTMP, D_L_ERROR, ! 126: ("**** RTR Error on port# %d RTMP_CABLE_STARTUP\n", ! 127: port)); ! 128: break; ! 129: ! 130: default: ! 131: dPrintf(D_M_RTMP, D_L_ERROR, ! 132: ("**** RTR Error on port# %d WHAT IN THE WORLD IS THIS ONE? code=%d\n", ! 133: port, err_number)); ! 134: break; ! 135: } ! 136: dPrintf(D_M_RTMP, D_L_ERROR, ("Explanation: %s\n", errstr)); ! 137: } ! 138: ! 139: ! 140: /* ! 141: * this function just look for a NetNumber in the routing table, ! 142: * no check is done for the validity of the entry ! 143: */ ! 144: ! 145: RT_entry *rt_blookup (NetNumber) ! 146: at_net_al NetNumber; ! 147: { ! 148: ! 149: RT_entry *ptree = &RT_table_start; ! 150: at_net_al LowEnd; ! 151: register unsigned int s; ! 152: /* ! 153: dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : Lookup for Net=%d\n", ! 154: "rt_blookup", NetNumber)); ! 155: */ ! 156: ATDISABLE(s, ddpinp_lock); ! 157: while (ptree) { ! 158: ! 159: if (NetNumber > ptree->NetStop) { ! 160: /* ! 161: dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : Go Right from #%d\n", ! 162: "rt_blookup", ptree->NextIRNet)); ! 163: */ ! 164: ptree = ptree->right; ! 165: continue; ! 166: } ! 167: else { ! 168: if (ptree->NetStart) ! 169: LowEnd = ptree->NetStart; ! 170: else ! 171: LowEnd = ptree->NetStop; ! 172: ! 173: if (NetNumber < LowEnd ) { ! 174: /* ! 175: dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : Go Left from #%d\n", ! 176: "rt_blookup", ptree->NextIRNet)); ! 177: */ ! 178: ptree = ptree->left; ! 179: continue; ! 180: } ! 181: ATENABLE(s, ddpinp_lock); ! 182: ! 183: /* we're in the range (either extended or not) ! 184: * return the entry found. ! 185: */ ! 186: ! 187: /* dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : found %04d-%04d Port=%d State=0x%x\n", ! 188: "rt_blookup", ptree->NetStart, ptree->NetStop, ptree->NetPort, ! 189: ptree->EntryState)); ! 190: */ ! 191: ! 192: return (ptree); ! 193: } ! 194: } ! 195: ATENABLE(s, ddpinp_lock); ! 196: ! 197: dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : %04d : NOT FOUND\n", ! 198: "rt_blookup", NetNumber)); ! 199: return ((RT_entry *)NULL); ! 200: } ! 201: ! 202: ! 203: /* Routing table btree insert routine ! 204: * Uses a RT_entry parameter as the input, the insert is sorted in ! 205: * the tree on the NetStop field. Provision is made for non extented ! 206: * net (ie NetStart = 0). ! 207: * The function returns the element where the new entry was inserted, or ! 208: * NULL if the insert didn't work. (In this cas there is a problem with ! 209: * the tree coherency... ! 210: * ! 211: */ ! 212: ! 213: ! 214: RT_entry *rt_binsert (NewEntry) ! 215: RT_entry *NewEntry; ! 216: { ! 217: RT_entry *ptree = &RT_table_start; ! 218: ! 219: register at_net_al NetStart = NewEntry->NetStart; ! 220: register at_net_al NetStop = NewEntry->NetStop; ! 221: ! 222: dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("rt_binsert: for Net %d-%d state=x%x NextIR %d:%d\n", ! 223: NetStart, NetStop, NewEntry->EntryState,NewEntry->NextIRNet, NewEntry->NextIRNode)); ! 224: ! 225: if (ptree == (RT_entry *)NULL) { ! 226: *ptree = *NewEntry; ! 227: at_state.flags |= AT_ST_RT_CHANGED; ! 228: return (NewEntry); ! 229: } ! 230: ! 231: ! 232: while (ptree) { ! 233: ! 234: if (NetStop > ptree->NetStop) { /* walk the right sub-tree */ ! 235: if (ptree->right) ! 236: ptree = ptree->right; ! 237: else { ! 238: ptree->right = NewEntry; ! 239: at_state.flags |= AT_ST_RT_CHANGED; ! 240: return (ptree); ! 241: } ! 242: } ! 243: else { /* walk the left sub-tree */ ! 244: if (ptree->left) ! 245: ptree = ptree->left; ! 246: else { ! 247: ptree->left = NewEntry; ! 248: at_state.flags |= AT_ST_RT_CHANGED; ! 249: return (ptree); ! 250: } ! 251: } ! 252: ! 253: } ! 254: ! 255: dPrintf(D_M_RTMP, D_L_WARNING, ("%s : ERROR NOT INSERTED Net %d-%d\n", ! 256: "rt_binsert", NetStart, NetStop)); ! 257: return ((RT_entry *)NULL); ! 258: } ! 259: ! 260: RT_entry *rt_insert(NStop, NStart, NxNet, NxNode, NtDist, NtPort, EntS) ! 261: at_net_al NStop, NStart, NxNet; ! 262: at_node NxNode; ! 263: u_char NtDist, NtPort, EntS; ! 264: { ! 265: RT_entry *New; ! 266: if ((New = RT_table_freelist)) { ! 267: RT_table_freelist = RT_table_freelist->right; ! 268: } else ! 269: return ((RT_entry *)NULL); ! 270: New->right = NULL; ! 271: New->NetStop = NStop; ! 272: New->NetStart = NStart; ! 273: New->NextIRNet = NxNet; ! 274: New->NextIRNode = NxNode; ! 275: New->NetDist = NtDist; ! 276: New->NetPort = NtPort; ! 277: New->EntryState = EntS; ! 278: bzero(New->ZoneBitMap, sizeof(New->ZoneBitMap)); ! 279: at_state.flags |= AT_ST_RT_CHANGED; ! 280: return(rt_binsert(New)); ! 281: } ! 282: ! 283: /* ! 284: dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : %04d : NOT FOUND\n", ! 285: "rt_blookup", NetNumber)); ! 286: * Routing table btree deletion routine ! 287: * ! 288: */ ! 289: ! 290: RT_entry *rt_bdelete (NetStop, NetStart) ! 291: at_net_al NetStop, NetStart; ! 292: { ! 293: ! 294: RT_entry *rt_found, *pprevious, *pnext, *pnextl, *psub; ! 295: at_net_al LowEnd; ! 296: ! 297: rt_found = &RT_table_start; ! 298: ! 299: dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : Delete %d-%d\n", ! 300: "rt_bdelete", NetStart, NetStop)); ! 301: ! 302: while (rt_found) { ! 303: ! 304: if (NetStop > rt_found->NetStop) { ! 305: pprevious = rt_found; ! 306: rt_found = rt_found->right; ! 307: continue; ! 308: } ! 309: else { ! 310: ! 311: /* non extended nets cases */ ! 312: ! 313: if (rt_found->NetStart) ! 314: LowEnd = rt_found->NetStart; ! 315: else ! 316: LowEnd = rt_found->NetStop; ! 317: ! 318: if (NetStop < LowEnd) { ! 319: pprevious = rt_found; ! 320: rt_found = rt_found->left; ! 321: continue; ! 322: } ! 323: ! 324: /* we're in the range (either extended or not) ! 325: * return the entry found. ! 326: */ ! 327: ! 328: break; ! 329: } ! 330: } ! 331: ! 332: dPrintf(D_M_RTMP, D_L_ROUTING, ("%s : Delete %d-%d found to delete %d-%d\n", ! 333: "rt_bdelete", NetStart, NetStop, rt_found->NetStart,rt_found->NetStop)); ! 334: ! 335: if (rt_found) { ! 336: ! 337: ! 338: ! 339: /* we found the entry, now reorg the sub-trees ! 340: * spanning from our node. ! 341: */ ! 342: ! 343: if ((pnext = rt_found->right)) { ! 344: ! 345: /* Tree pruning: take the left branch of the current ! 346: * node and place it at the lowest left branch ! 347: * of the current right branch ! 348: */ ! 349: ! 350: psub = pnext; ! 351: ! 352: /* walk the Right/Left sub tree from current node */ ! 353: ! 354: while ((pnextl = psub->left)) ! 355: psub = pnextl; ! 356: ! 357: /* plug the old left tree to the new ->Right leftmost node */ ! 358: ! 359: psub->left = rt_found->left; ! 360: ! 361: ! 362: } else { /* only left sub-tree, simple case */ ! 363: ! 364: pnext = rt_found->left; ! 365: } ! 366: ! 367: /* Now, plug the current node sub tree to the good pointer of ! 368: * our parent node. ! 369: */ ! 370: ! 371: ! 372: if (pprevious->left == rt_found) ! 373: pprevious->left = pnext; ! 374: else ! 375: pprevious->right = pnext; ! 376: ! 377: /* clean-up entry and add to the free-list */ ! 378: ! 379: at_state.flags |= AT_ST_RT_CHANGED; ! 380: return(rt_found); ! 381: } ! 382: ! 383: else { /* Trying to delete something that doesn't exist? */ ! 384: ! 385: dPrintf(D_M_RTMP, D_L_WARNING, ("%s : %d NOT Removed\n", ! 386: "rt_bdelete", NetStop)); ! 387: ! 388: return ((RT_entry *)NULL); ! 389: } ! 390: ! 391: ! 392: } ! 393: ! 394: ! 395: RT_entry *rt_sortedshow(parent) ! 396: RT_entry *parent; ! 397: { ! 398: RT_entry *me; ! 399: ! 400: me = parent; ! 401: ! 402: if (parent == NULL) { ! 403: me = &RT_table_start; ! 404: while (me) ! 405: if (me->left) { ! 406: parent = me; ! 407: me = me->left; ! 408: } ! 409: /* parent = parent->parent; */ ! 410: } ! 411: return (parent); ! 412: } ! 413: ! 414: /* ! 415: * debug only: display the contents of the routing table ! 416: */ ! 417: ! 418: void rt_show () ! 419: { ! 420: RT_entry *ptree; ! 421: int i=0; ! 422: ! 423: ptree = &RT_table[0]; ! 424: ! 425: while (ptree && i < 600 ) { ! 426: if (ptree->NetStop) { ! 427: dPrintf(D_M_RTMP_LOW, D_L_VERBOSE, ! 428: ("%4d-%4d IR=%d:%d Dist=%d\n", ! 429: ptree->NetStop, ptree->NetStart, ptree->NextIRNet, ! 430: ptree->NextIRNode, (short)ptree->NetDist)); ! 431: } else { ! 432: dPrintf(D_M_RTMP_LOW, D_L_VERBOSE, ! 433: ("%04d : * FREE ENTRY\n", i)); ! 434: } ! 435: ptree++; ! 436: i++; ! 437: } ! 438: } ! 439: ! 440: /* ! 441: * prepare the indexing of the free entries in the RTMP table ! 442: */ ! 443: ! 444: rt_table_init() ! 445: { ! 446: short i; ! 447: ! 448: if ((RT_table = (RT_entry *)_MALLOC(sizeof(RT_entry)*RT_maxentry, ! 449: M_RTABLE, M_NOWAIT)) == NULL) { ! 450: dPrintf(D_M_RTMP, D_L_WARNING, ! 451: ("rtmptable: Can't allocate RT_table\n")); ! 452: return (ENOMEM); ! 453: } ! 454: if ((ZT_table = (ZT_entry *)_MALLOC(sizeof(ZT_entry)*ZT_maxentry, ! 455: M_RTABLE, M_NOWAIT)) == NULL) { ! 456: dPrintf(D_M_RTMP, D_L_WARNING, ! 457: ("rtmptable: Can't allocate ZT_table\n")); ! 458: return (ENOMEM); ! 459: } ! 460: dPrintf(D_M_RTMP, D_L_STARTUP, ("rt_table_init called\n")); ! 461: bzero(&RT_table[0], sizeof(RT_entry)* RT_maxentry); ! 462: for (i= 1 ; i < RT_maxentry ; i++) { ! 463: (&RT_table[i-1])->right = &RT_table[i]; ! 464: } ! 465: RT_table_freelist = &RT_table[0]; ! 466: ! 467: at_state.flags |= AT_ST_RT_CHANGED; ! 468: at_state.flags |= AT_ST_ZT_CHANGED; ! 469: bzero(&RT_table_start, sizeof(RT_entry)); ! 470: ! 471: /* also clean up the ZIP table */ ! 472: ! 473: bzero(&ZT_table[0], sizeof(ZT_entry)* ZT_maxentry); ! 474: ErrorRTMPoverflow = 0; ! 475: ErrorZIPoverflow = 0; ! 476: return(0); ! 477: } ! 478: ! 479: /* ! 480: * zt_add_zone: add a zone name in the zone table. ! 481: */ ! 482: ! 483: zt_add_zone(name, length) ! 484: char *name; ! 485: short length; ! 486: { ! 487: at_nvestr_t zname; ! 488: bcopy(name, &zname.str, length); ! 489: zname.len = length; ! 490: return (zt_add_zonename(&zname)); ! 491: } ! 492: ! 493: /* ! 494: * zt_add_zonename: add a zone name in the zone table. ! 495: */ ! 496: ! 497: int zt_add_zonename(zname) ! 498: at_nvestr_t *zname; ! 499: { ! 500: register short res,i; ! 501: register unsigned int s; ! 502: ! 503: if (res = zt_find_zname(zname)) ! 504: return(res); ! 505: ! 506: ATDISABLE(s, ddpinp_lock); ! 507: for (i = 0; i < ZT_maxentry ; i++) { ! 508: if (ZT_table[i].ZoneCount == 0 && ZT_table[i].Zone.len == 0) {/* free entry */ ! 509: ZT_table[i].Zone = *zname; ! 510: dPrintf(D_M_RTMP, D_L_VERBOSE, ("zt_add_zonename: zone #%d %s len=%d\n", ! 511: i, ZT_table[i].Zone.str, ZT_table[i].Zone.len)); ! 512: at_state.flags |= AT_ST_ZT_CHANGED; ! 513: ATENABLE(s, ddpinp_lock); ! 514: return(i+1); ! 515: } ! 516: } ! 517: ATENABLE(s, ddpinp_lock); ! 518: /* table full... */ ! 519: return (ZT_MAXEDOUT); ! 520: } ! 521: ! 522: /* Adjust zone counts for a removed network entry. ! 523: * If the ZoneCount of a zone reaches zero, delete the zone from the zone table ! 524: */ ! 525: void zt_remove_zones(zmap) ! 526: u_char *zmap; ! 527: { ! 528: ! 529: register u_short i,j, Index; ! 530: ! 531: for (i=0; i< ZT_BYTES ; i++) { ! 532: ! 533: if (zmap[i]) { ! 534: for (j=0; j < 8 ; j++) ! 535: if ((zmap[i] << j) & 0x80) { ! 536: Index = i*8 + j; /* get the index in ZT */ ! 537: /* 1-23-97 this routine caused a crash once, presumably ! 538: zmap bits beyond ZT_table size got set somehow. ! 539: prevent that here ! 540: */ ! 541: if (Index >= ZT_maxentry) { ! 542: dPrintf(D_M_RTMP, D_L_ERROR, ! 543: ("zt_remove_zones: index (%d) GT ZT_maxentry (%d) (zmap:%d)\n", ! 544: Index,ZT_maxentry,i)); ! 545: return; ! 546: } ! 547: dPrintf(D_M_RTMP, D_L_VERBOSE, ! 548: ("zt_remove_zones: zone #%d %s was=%d\n", Index, ! 549: ZT_table[Index].Zone.str, ZT_table[Index].ZoneCount)); ! 550: if (ZT_table[Index].ZoneCount > 0) ! 551: ZT_table[Index].ZoneCount--; ! 552: if (ZT_table[Index].ZoneCount == 0) ! 553: ZT_table[Index].Zone.len = 0; ! 554: at_state.flags |= AT_ST_ZT_CHANGED; ! 555: } ! 556: } ! 557: } ! 558: } ! 559: ! 560: ! 561: ! 562: /* ! 563: * zt_compute_hash: compute hash index from the zone name string ! 564: */ ! 565: ! 566: short zt_compute_hash(zname) ! 567: at_nvestr_t *zname; ! 568: { ! 569: register u_short checksum=0, i; ! 570: register char c1; ! 571: ! 572: /* apply the upper name + DDP checksum algorithm */ ! 573: ! 574: for (i= 0 ; i < zname->len; i++) { ! 575: ! 576: /* upperize the character */ ! 577: ! 578: c1 = zname->str[i]; ! 579: if (c1 >= 'a' && c1 <= 'z') ! 580: c1 += 'A' - 'a'; ! 581: if (c1 & 0x80) ! 582: c1 = upshift8(c1); ! 583: ! 584: /* DDP Checksum */ ! 585: ! 586: checksum += c1; ! 587: checksum = ((checksum & 0x8000) ? ! 588: (checksum << 1 | 1) : (checksum << 1)); ! 589: } ! 590: ! 591: dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("zt_comphash: value computed for zone=%s h=%d\n", ! 592: zname->str, checksum)); ! 593: ! 594: if (checksum) ! 595: return (checksum); ! 596: else ! 597: return (0xffff); ! 598: ! 599: } ! 600: ! 601: /* ! 602: * zt_upper_zname: translate the name string into uppercase ! 603: */ ! 604: ! 605: void zt_upper_zname(zname) ! 606: at_nvestr_t *zname; ! 607: { ! 608: register short i; ! 609: register char c1; ! 610: ! 611: for (i= 0 ; i < zname->len; i++) { ! 612: ! 613: c1 = zname->str[i]; ! 614: if (c1 >= 'a' && c1 <= 'z') ! 615: c1 += 'A' - 'a'; ! 616: if (c1 & 0x80) ! 617: c1 = upshift8(c1); ! 618: ! 619: zname->str[i] = c1; ! 620: } ! 621: } ! 622: ! 623: /* ! 624: * zt_get_zmcast: calcularte the zone multicast address for a ! 625: * given zone name. ! 626: * Returns the result in "buffer" ! 627: */ ! 628: ! 629: zt_get_zmcast(ifID, zname, buffer) ! 630: at_ifaddr_t *ifID; /* we want to know the media type */ ! 631: at_nvestr_t *zname; /* source name for multicast address */ ! 632: char *buffer; /* resulting Zone Multicast address */ ! 633: { ! 634: u_short h; ! 635: ! 636: h = zt_compute_hash(zname); ! 637: ! 638: /* ! 639: * Find a nice way to decide if it is TokenRing or Ethernet for ! 640: * the Multicast address computation.... ! 641: */ ! 642: ! 643: if (ifID->aa_ifp->if_type != IFT_ISO88025) { /* token ring */ ! 644: ! 645: /* Ethernet case */ ! 646: ! 647: buffer[0] = 0x09; ! 648: buffer[1] = 0x00; ! 649: buffer[2] = 0x07; ! 650: /* no router, use cable multicast */ ! 651: if (MULTIHOME_MODE && ifID->ifRouterState == NO_ROUTER ) { ! 652: buffer[3] = buffer[4] = buffer[5] = 0xff; ! 653: } ! 654: else { ! 655: buffer[3] = 0x00; ! 656: buffer[4] = 0x00; ! 657: buffer[5] = h % 0xFD; ! 658: } ! 659: dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("zt_get_multi: computed for h=%d %x %x\n", ! 660: h, *(u_int *)&buffer[0], *(u_short *)&buffer[4])); ! 661: ! 662: return(6); /* returns Multicast address length */ ! 663: ! 664: } ! 665: else { ! 666: /* assume it is token ring: note for the magic number computation, ! 667: * first see Inside Mac Page 3-10, there is 20 multicast addresses ! 668: * for TLAP, and they are from 0xC000 0000 0008 00 to 0xC000 0200 0000 00 ! 669: */ ! 670: buffer[0] = 0xC0; ! 671: buffer[1] = 0x00; ! 672: *(u_int *)&buffer[2] = 1 << ((h % 19) + 11); ! 673: dPrintf(D_M_RTMP, D_L_WARNING,("zt_get_multi: BROAD not found forr h=%d \n", ! 674: h)); ! 675: return(6); ! 676: } ! 677: ! 678: ! 679: ! 680: } ! 681: ! 682: /* ! 683: * zt_ent_zindex: return the first zone index found in the zone map ! 684: * return the entry number+1 in the Zone Table, or zero if not found ! 685: */ ! 686: ! 687: int zt_ent_zindex(zmap) ! 688: u_char *zmap; ! 689: { ! 690: u_short i,j; ! 691: ! 692: ! 693: for (i = 0 ; i < ZT_BYTES ; i++) ! 694: ! 695: if (zmap[i]) ! 696: for (j = 0 ; j < 8 ; j++) ! 697: if ((zmap[i] << j) & 0x80) ! 698: return (8*i + j +1); ! 699: ! 700: return (0); ! 701: } ! 702: /* ! 703: * zt_ent_zcount: count the number of actives zone for a routing entry ! 704: */ ! 705: ! 706: zt_ent_zcount(ent) ! 707: RT_entry *ent; ! 708: { ! 709: register u_char *zmap; ! 710: register u_short i,j; ! 711: register int zone_count = 0 ; ! 712: register unsigned int s; ! 713: ! 714: ATDISABLE(s, ddpinp_lock); ! 715: ! 716: if (!RT_ALL_ZONES_KNOWN(ent)) { ! 717: ATENABLE(s, ddpinp_lock); ! 718: return (0); ! 719: } ! 720: zmap = ent->ZoneBitMap; ! 721: ! 722: for (i = 0 ; i < ZT_BYTES ; i++) { ! 723: ! 724: if (*zmap) ! 725: ! 726: for (j = 0 ; j < 8 ; j++) ! 727: if ((*zmap << j) & 0x80) ! 728: zone_count++; ! 729: zmap++; ! 730: } ! 731: ! 732: ATENABLE(s, ddpinp_lock); ! 733: return (zone_count); ! 734: } ! 735: ! 736: /* ! 737: * zt_find_zname: match a zone name in the zone table and return the entry if found ! 738: */ ! 739: zt_find_zname(zname) ! 740: at_nvestr_t *zname; ! 741: { ! 742: register short i, j, found; ! 743: register char c1, c2; ! 744: register unsigned int s; ! 745: ! 746: ! 747: if (!zname->len) ! 748: return(0); ! 749: ! 750: ATDISABLE(s, ddpinp_lock); ! 751: for (i = 0 ; i < ZT_maxentry ; i++) { ! 752: if (!ZT_table[i].ZoneCount || zname->len != ZT_table[i].Zone.len) ! 753: continue; ! 754: ! 755: found = 1; /* did we get the right one? */ ! 756: ! 757: for (j = 0 ; j < zname->len ; j++) { ! 758: c1 = zname->str[j]; ! 759: c2 = ZT_table[i].Zone.str[j]; ! 760: if (c1 >= 'a' && c1 <= 'z') ! 761: c1 += 'A' - 'a'; ! 762: if (c2 >= 'a' && c2 <= 'z') ! 763: c2 += 'A' - 'a'; ! 764: if (c1 & 0x80) ! 765: c1 = upshift8(c1); ! 766: if (c2 & 0x80) ! 767: c2 = upshift8(c2); ! 768: if (c1 != c2) { ! 769: found = 0; ! 770: break; ! 771: } ! 772: } ! 773: ! 774: if (found) { ! 775: ATENABLE(s, ddpinp_lock); ! 776: return (i+1); ! 777: } ! 778: } ! 779: ! 780: ATENABLE(s, ddpinp_lock); ! 781: return(0); ! 782: } ! 783: ! 784: ! 785: /* ! 786: * zt_set_zmap: set a bit for the corresponding zone map in an entry bitmap ! 787: */ ! 788: void zt_set_zmap(znum, zmap) ! 789: u_short znum; ! 790: char *zmap; ! 791: { ! 792: register u_short num = znum -1; ! 793: register unsigned int s; ! 794: ! 795: ATDISABLE(s, ddpinp_lock); ! 796: if (!(zmap[num >> 3] & 0x80 >> (num % 8))) { ! 797: zmap[num >> 3] |= 0x80 >> (num % 8); ! 798: ZT_table[num].ZoneCount++; ! 799: } ! 800: ATENABLE(s, ddpinp_lock); ! 801: } ! 802: ! 803: ! 804: /* ! 805: * zt_clr_zmap: clear a bit for the corresponding zone map in an entry bitmap ! 806: */ ! 807: void zt_clr_zmap(znum, zmap) ! 808: u_short znum; ! 809: char *zmap; ! 810: { ! 811: register u_short num = znum -1; ! 812: register unsigned int s; ! 813: ! 814: ATDISABLE(s, ddpinp_lock); ! 815: if (zmap[num >> 3] & 0x80 >> (num % 8)) { ! 816: zmap[num >> 3] ^= 0x80 >> (num % 8); ! 817: ZT_table[num].ZoneCount--; ! 818: } ! 819: ATENABLE(s, ddpinp_lock); ! 820: } ! 821: ! 822: ! 823: /* ! 824: * routing_needed : ! 825: * This function performs the actual lookup and forward of packets ! 826: * send to the box for routing. ! 827: * ! 828: * The destination network is looked up in our tables, and if we ! 829: * know the next IR to send the packet to, we forward the packet ! 830: * on the right port. ! 831: * ! 832: * If the destination is unknown, we simply dump the packet. ! 833: */ ! 834: ! 835: void routing_needed(mp, ifID, bypass) ! 836: gbuf_t *mp; ! 837: at_ifaddr_t *ifID; ! 838: char bypass; /* set by special socket handlers */ ! 839: { ! 840: ! 841: register at_ddp_t *ddp; ! 842: register int msgsize; ! 843: register RT_entry *Entry; ! 844: register gbuf_t *tmp_m; ! 845: ! 846: /* first check the interface is up and forwarding */ ! 847: ! 848: if (!ifID) { ! 849: dPrintf(D_M_RTMP, D_L_WARNING, ! 850: ("routing_needed: non valid IFID!\n")); ! 851: gbuf_freel(mp); ! 852: return; ! 853: } ! 854: if ((ifID->ifRoutingState < PORT_ONLINE)) { ! 855: dPrintf(D_M_RTMP, D_L_WARNING, ! 856: ("routing_needed: port %d not online yet\n", ! 857: ifID->ifPort)); ! 858: gbuf_freel(mp); ! 859: return; ! 860: } ! 861: ! 862: ddp = (at_ddp_t *)gbuf_rptr(mp); ! 863: msgsize = DDPLEN_VALUE(ddp); ! 864: for (tmp_m = gbuf_next(mp); tmp_m; tmp_m = gbuf_next(tmp_m)) ! 865: msgsize += DDPLEN_VALUE(((at_ddp_t *)gbuf_rptr(tmp_m))); ! 866: ! 867: if (ddp->hopcount++ > 15) { ! 868: dPrintf(D_M_RTMP, D_L_WARNING, ! 869: ("routing_needed: drop packet for %d:%d, hopcount too high\n", ! 870: NET_VALUE(ddp->dst_net), ddp->dst_node)); ! 871: gbuf_freel(mp); ! 872: snmpStats.dd_hopCount++; ! 873: return; /* was return(1); */ ! 874: } ! 875: ! 876: if ((Entry = rt_blookup(NET_VALUE(ddp->dst_net)))) { ! 877: ! 878: dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ! 879: ("routing_needed: FOUND for %d.%d p=%d to %d.%d \n", ! 880: NET_VALUE(ddp->dst_net), ddp->dst_node, ifID->ifPort, ! 881: Entry->NextIRNet, Entry->NextIRNode)); ! 882: ! 883: /* somehow, come to that point... */ ! 884: ! 885: ifID->ifStatistics.fwdPkts++; ! 886: ifID->ifStatistics.fwdBytes += msgsize; ! 887: ! 888: if (Entry->NetDist) /* net not directly connected */ ! 889: ddp_router_output(mp, ifID_table[Entry->NetPort], AT_ADDR, ! 890: Entry->NextIRNet, Entry->NextIRNode, 0); ! 891: else {/* we are directly on this net */ ! 892: ! 893: /* we want to avoid duplicating broadcast packet on the same net, ! 894: * but special sockets handlers are ok to do that (mainly for ! 895: * for loopback purpose). So, if the "bypass" flag is set, we don't ! 896: * check for that test... [Problem was "movietalk"]. ! 897: */ ! 898: ! 899: if (bypass || ifID_table[Entry->NetPort] != ifID) ! 900: ddp_router_output(mp, ifID_table[Entry->NetPort], AT_ADDR, ! 901: NET_VALUE(ddp->dst_net), ddp->dst_node, 0); ! 902: else { ! 903: dPrintf(D_M_RTMP, D_L_ROUTING, ! 904: ("routing_needed: bad loopback for add %d.%d from port %d (%d.%d)\n", ! 905: NET_VALUE(ddp->dst_net), ddp->dst_node, ifID->ifPort, ! 906: NET_VALUE(ddp->src_net), ddp->src_node)); ! 907: ifID->ifStatistics.droppedPkts++; ! 908: ifID->ifStatistics.droppedBytes += msgsize; ! 909: ! 910: gbuf_freel(mp); ! 911: return; /* was return (2); */ ! 912: } ! 913: ! 914: ! 915: } ! 916: } ! 917: else { ! 918: dPrintf(D_M_RTMP, D_L_ROUTING, ! 919: ("routing_needed: NOT FOUND for add %d.%d from port %d our %d.%d\n", ! 920: NET_VALUE(ddp->dst_net), ddp->dst_node, ifID->ifPort, ! 921: ifID_home->ifThisNode.s_net, ! 922: ifID_home->ifThisNode.s_node)); ! 923: ! 924: ifID->ifStatistics.droppedPkts++; ! 925: ifID->ifStatistics.droppedBytes += msgsize; ! 926: snmpStats.dd_noRoutes++; ! 927: ! 928: gbuf_freel(mp); ! 929: return; /* was return (2); */ ! 930: ! 931: } ! 932: /* return(0); */ ! 933: } /* routing_needed */ ! 934: ! 935: ZT_entryno *zt_getNextZone(first) ! 936: int first; ! 937: /* a call made with first = TRUE returns the first valid entry in ! 938: the ZT_table, if first != TRUE, then then each call returns the ! 939: next valid entry in the table. The next call after the last ! 940: valid entry was read returns NULL ! 941: */ ! 942: { ! 943: int i; ! 944: static int idx=0; ! 945: static ZT_entryno zte; ! 946: ! 947: if (!ZT_table) ! 948: return NULL; ! 949: ! 950: if (first) ! 951: idx=0; ! 952: ! 953: for (i=idx; i<ZT_maxentry; i++) { ! 954: if (ZT_table[i].ZoneCount) ! 955: break; ! 956: } ! 957: if (i<ZT_maxentry) { ! 958: idx = i+1; ! 959: zte.zt = ZT_table[i]; ! 960: zte.entryno = i; ! 961: return(&zte); ! 962: } ! 963: else ! 964: return(NULL); ! 965: } ! 966: ! 967: RT_entry *rt_getNextRoute(first) ! 968: int first; ! 969: ! 970: /* a call made with first = TRUE returns the first valid entry in ! 971: the RT_table, if first != TRUE, then then each call returns the ! 972: next valid entry in the table. The next call after the last ! 973: valid entry was read returns NULL ! 974: */ ! 975: ! 976: { ! 977: int i; ! 978: static int idx=0; ! 979: ! 980: if (!RT_table) ! 981: return(NULL); ! 982: ! 983: if (first) ! 984: idx=0; ! 985: ! 986: for (i=idx; i<RT_maxentry; i++) { ! 987: if (RT_table[i].EntryState != RTE_STATE_UNUSED) ! 988: break; ! 989: } ! 990: if (i<RT_maxentry) { ! 991: idx = i+1; ! 992: return(&RT_table[i]); ! 993: } ! 994: else ! 995: return(NULL); ! 996: } ! 997: ! 998: ! 999: getRtmpTableSize() ! 1000: { ! 1001: register int i; ! 1002: register RT_entry *rt; ! 1003: static int size=0; ! 1004: ! 1005: if(!(at_state.flags &AT_ST_RT_CHANGED)) ! 1006: return(size); ! 1007: ! 1008: for (i=RT_maxentry,rt = &RT_table[RT_maxentry-1]; i; i--,rt--) ! 1009: if (rt->EntryState != RTE_STATE_UNUSED) { ! 1010: size = i; ! 1011: return(i); ! 1012: } ! 1013: return(0); ! 1014: } ! 1015: ! 1016: getZipTableSize() ! 1017: { ! 1018: register int i; ! 1019: register ZT_entry *zt; ! 1020: static int size=0; ! 1021: ! 1022: if (!(at_state.flags & AT_ST_ZT_CHANGED)) ! 1023: return(size); ! 1024: ! 1025: for (i=ZT_maxentry,zt = &ZT_table[ZT_maxentry-1]; i; i--,zt--) ! 1026: if (zt->ZoneCount) { ! 1027: size = i; ! 1028: return(i); ! 1029: } ! 1030: return(0); ! 1031: } ! 1032: ! 1033: getRtmpTable(d,s,c) ! 1034: RT_entry *d; /* destination */ ! 1035: int s; /* starting entry */ ! 1036: int c; /* # entries to copy */ ! 1037: { ! 1038: register int i,n=0; ! 1039: register RT_entry *rt; ! 1040: ! 1041: for(i=s,rt=&RT_table[s]; i<RT_maxentry && n<c; rt++,i++) ! 1042: if (rt->EntryState != RTE_STATE_UNUSED) { ! 1043: *d++ = *rt; ! 1044: n++; ! 1045: } ! 1046: } ! 1047: ! 1048: getZipTable(d,s,c) ! 1049: ZT_entry *d; /* destination */ ! 1050: int s; /* starting entry */ ! 1051: int c; /* # entries to copy */ ! 1052: { ! 1053: ! 1054: bcopy(&ZT_table[s], d, c*sizeof(ZT_entry)); ! 1055: } ! 1056: ! 1057: at_nvestr_t *getRTRLocalZone(ifz) ! 1058: if_zone_t *ifz; ! 1059: { ! 1060: char *zmap; ! 1061: RT_entry *route; ! 1062: int i, j, index; ! 1063: int zcnt=0; /* zone we're pointing to in the list */ ! 1064: char zonesChecked[ZT_BYTES]; ! 1065: at_ifaddr_t *ifID; ! 1066: ! 1067: if (ifz->ifzn.zone < 0) { ! 1068: return((at_nvestr_t*)NULL); ! 1069: } ! 1070: bzero(zonesChecked,sizeof(zonesChecked)); ! 1071: TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) { ! 1072: if (!(route = rt_blookup(ifID->ifThisNode.s_net))) { ! 1073: return((at_nvestr_t*)NULL); ! 1074: } ! 1075: zmap=route->ZoneBitMap; ! 1076: dPrintf(D_M_RTMP_LOW, D_L_USR1, ! 1077: ("getRTRLocal: i/f %s, net:%d\n",ifID->ifName, ! 1078: ifID->ifThisNode.s_net)); ! 1079: for (i = 0 ; i < ZT_BYTES; i++) { ! 1080: if (zmap[i]) { ! 1081: for (j = 0; j < 8 ; j++) ! 1082: if ( (zmap[i] & (0x80 >> j)) && ! 1083: !(zonesChecked[i] & (0x80 >> j)) ! 1084: ) { ! 1085: zonesChecked[i] |= (0x80 >> j); ! 1086: if (ifz->ifzn.zone == zcnt) { ! 1087: index = i * 8 + j; ! 1088: getIfUsage(index,ifz->usage); ! 1089: ifz->ifzn.ifnve = ZT_table[index].Zone; ! 1090: dPrintf(D_M_RTMP_LOW, D_L_USR1, ! 1091: ("getRTRLocal:zmap:%8x zcnt:%d usage:%8x\n", ! 1092: *(int*)zmap,zcnt,*(int*)ifz->usage)); ! 1093: ifz->index = index+1; ! 1094: return(&ZT_table[index].Zone); ! 1095: } ! 1096: zcnt++; ! 1097: } ! 1098: } ! 1099: } ! 1100: } ! 1101: dPrintf(D_M_RTMP_LOW, D_L_USR1, ! 1102: ("getRTRLocal: returning NULL last ent:%d net:%d zmap:%08x\n", ! 1103: (ifID ? ifID->ifPort : 0), ! 1104: (ifID ? ifID->ifThisNode.s_net : 0),*(int*)zmap)); ! 1105: ifz->ifzn.ifnve.len = 0; ! 1106: return((at_nvestr_t*)NULL); ! 1107: } /* getRTRLocalZone */ ! 1108: ! 1109: void getIfUsage(zone, ifs_in_zone) ! 1110: int zone; ! 1111: char *ifs_in_zone; ! 1112: ! 1113: /* sets a "1" in each element of the char array for each I/F in the ! 1114: requested zone. The char array has a 1:1 correspondence with the ! 1115: ifID_table. Zone is assumed to be valid and local, so if we're in ! 1116: single port mode, we'll set the home port and thats it. ! 1117: */ ! 1118: { ! 1119: u_int zmi; /* zone map index for zone */ ! 1120: u_char zmb; /* zone map bit mask for zone */ ! 1121: RT_entry *route; ! 1122: int cnt=0; ! 1123: at_ifaddr_t *ifID; ! 1124: ! 1125: if (!MULTIPORT_MODE) { ! 1126: ifs_in_zone[0] = 1; ! 1127: return; ! 1128: } ! 1129: bzero(ifs_in_zone,IF_TOTAL_MAX); ! 1130: zmi = zone>>3; ! 1131: zmb = 0x80>>(zone % 8); ! 1132: dPrintf(D_M_NBP_LOW, D_L_USR3, ("get_ifs znum:%d zmi%d zmb:%x\n", ! 1133: zone, zmi, zmb)); ! 1134: TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) { ! 1135: if (!(route = rt_blookup(ifID->ifThisNode.s_net))) ! 1136: return; ! 1137: if (route->ZoneBitMap[zmi] & zmb) { ! 1138: dPrintf(D_M_NBP_LOW, D_L_USR3, ("zone in port %d \n", ! 1139: route->NetPort)); ! 1140: ifs_in_zone[route->NetPort] = 1; ! 1141: cnt++; ! 1142: } ! 1143: } ! 1144: return; ! 1145: } /* getIfUsage */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.