/* * Copyright (c) 1994-2007 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /*---------------------------------------------------------------------------- * * RTMP & ZIP routing tables access routines * * This code implement b-tree search and manipulation of * of the RTMP routing table and ZIP zone table. * * The RTMP routing table is a data block divided in several routing * entries sorted during insertion in a b-tree form. We use a table and * not dynamically allocated entries because it allow us to scan the whole * table when RTMP packets are generated. The routing table entries are sorted * by there NetStop value (because non extended nets have a NetStart value of * zero. From any point in the tree, the left side contains Network ranges * smaller or equal to the current Node, and the right tree points to higher * values network ranges. * * * 0.01 3/16/94 LD Creation * Modified for MP, 1996 by Tuyen Nguyen * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX. * *---------------------------------------------------------------------------- * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include RT_entry *RT_table_freelist; /* start of free entry list */ RT_entry RT_table_start; /* start of the actual entry table */ RT_entry *RT_table; /* the routing table */ ZT_entry *ZT_table; /* the Zone Information Protocol table */ short RT_maxentry; /* Number of entry in RTMP table */ short ZT_maxentry; /* Number of entry in ZIP table */ char errstr[512]; /* used to display meaningfull router errors*/ extern at_ifaddr_t *ifID_table[]; extern at_ifaddr_t *ifID_home; extern snmpStats_t snmpStats; short ErrorRTMPoverflow = 0; /* flag if RTMP table is too small for this net */ short ErrorZIPoverflow = 0; /* flag if ZIP table is too small for this net */ /* * This a temporary function : just to display the router error */ void RouterError(__unused short port, short err_number) { switch (err_number) { case ERTR_SEED_CONFLICT: dPrintf(D_M_RTMP, D_L_ERROR, ("**** RTR Error on port# %d SEED_CONFLICT\n", port)); break; case ERTR_CABLE_CONFLICT: dPrintf(D_M_RTMP, D_L_ERROR, ("**** RTR Error on port# %d CABLE_CONFLICT\n", port)); break; case ERTR_RTMP_BAD_VERSION: dPrintf(D_M_RTMP, D_L_ERROR, ("**** RTR Error on port# %d RTMP_BAD_VERSION\n", port)); break; case ERTR_CABLE_STARTUP: dPrintf(D_M_RTMP, D_L_ERROR, ("**** RTR Error on port# %d RTMP_CABLE_STARTUP\n", port)); break; default: dPrintf(D_M_RTMP, D_L_ERROR, ("**** RTR Error on port# %d WHAT IN THE WORLD IS THIS ONE? code=%d\n", port, err_number)); break; } dPrintf(D_M_RTMP, D_L_ERROR, ("Explanation: %s\n", errstr)); } /* * this function just look for a NetNumber in the routing table, * no check is done for the validity of the entry */ RT_entry *rt_blookup (NetNumber) at_net_al NetNumber; { RT_entry *ptree = &RT_table_start; at_net_al LowEnd; /* dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : Lookup for Net=%d\n", "rt_blookup", NetNumber)); */ while (ptree) { if (NetNumber > ptree->NetStop) { /* dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : Go Right from #%d\n", "rt_blookup", ptree->NextIRNet)); */ ptree = ptree->right; continue; } else { if (ptree->NetStart) LowEnd = ptree->NetStart; else LowEnd = ptree->NetStop; if (NetNumber < LowEnd ) { /* dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : Go Left from #%d\n", "rt_blookup", ptree->NextIRNet)); */ ptree = ptree->left; continue; } /* we're in the range (either extended or not) * return the entry found. */ /* dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : found %04d-%04d Port=%d State=0x%x\n", "rt_blookup", ptree->NetStart, ptree->NetStop, ptree->NetPort, ptree->EntryState)); */ return (ptree); } } dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : %04d : NOT FOUND\n", "rt_blookup", NetNumber)); return ((RT_entry *)NULL); } /* Routing table btree insert routine * Uses a RT_entry parameter as the input, the insert is sorted in * the tree on the NetStop field. Provision is made for non extented * net (ie NetStart = 0). * The function returns the element where the new entry was inserted, or * NULL if the insert didn't work. (In this cas there is a problem with * the tree coherency... * */ RT_entry *rt_binsert (NewEntry) RT_entry *NewEntry; { RT_entry *ptree = &RT_table_start; #if DEBUG register at_net_al NetStart = NewEntry->NetStart; #endif register at_net_al NetStop = NewEntry->NetStop; dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("rt_binsert: for Net %d-%d state=x%x NextIR %d:%d\n", NetStart, NetStop, NewEntry->EntryState,NewEntry->NextIRNet, NewEntry->NextIRNode)); if (ptree == (RT_entry *)NULL) { *ptree = *NewEntry; at_state.flags |= AT_ST_RT_CHANGED; return (NewEntry); } while (ptree) { if (NetStop > ptree->NetStop) { /* walk the right sub-tree */ if (ptree->right) ptree = ptree->right; else { ptree->right = NewEntry; at_state.flags |= AT_ST_RT_CHANGED; return (ptree); } } else { /* walk the left sub-tree */ if (ptree->left) ptree = ptree->left; else { ptree->left = NewEntry; at_state.flags |= AT_ST_RT_CHANGED; return (ptree); } } } dPrintf(D_M_RTMP, D_L_WARNING, ("%s : ERROR NOT INSERTED Net %d-%d\n", "rt_binsert", NetStart, NetStop)); return ((RT_entry *)NULL); } RT_entry *rt_insert(NStop, NStart, NxNet, NxNode, NtDist, NtPort, EntS) at_net_al NStop, NStart, NxNet; at_node NxNode; u_char NtDist, NtPort, EntS; { RT_entry *New; if ((New = RT_table_freelist)) { RT_table_freelist = RT_table_freelist->right; } else return ((RT_entry *)NULL); New->right = NULL; New->NetStop = NStop; New->NetStart = NStart; New->NextIRNet = NxNet; New->NextIRNode = NxNode; New->NetDist = NtDist; New->NetPort = NtPort; New->EntryState = EntS; bzero(New->ZoneBitMap, sizeof(New->ZoneBitMap)); at_state.flags |= AT_ST_RT_CHANGED; return(rt_binsert(New)); } /* dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : %04d : NOT FOUND\n", "rt_blookup", NetNumber)); * Routing table btree deletion routine * */ RT_entry *rt_bdelete (at_net_al NetStop, __unused at_net_al NetStart) { RT_entry *rt_found, *pprevious = NULL, *pnext, *pnextl, *psub; at_net_al LowEnd; rt_found = &RT_table_start; dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("%s : Delete %d-%d\n", "rt_bdelete", NetStart, NetStop)); while (rt_found) { if (NetStop > rt_found->NetStop) { pprevious = rt_found; rt_found = rt_found->right; continue; } else { /* non extended nets cases */ if (rt_found->NetStart) LowEnd = rt_found->NetStart; else LowEnd = rt_found->NetStop; if (NetStop < LowEnd) { pprevious = rt_found; rt_found = rt_found->left; continue; } /* we're in the range (either extended or not) * return the entry found. */ break; } } dPrintf(D_M_RTMP, D_L_ROUTING, ("%s : Delete %d-%d found to delete %d-%d\n", "rt_bdelete", NetStart, NetStop, rt_found->NetStart,rt_found->NetStop)); if (rt_found) { /* we found the entry, now reorg the sub-trees * spanning from our node. */ if ((pnext = rt_found->right)) { /* Tree pruning: take the left branch of the current * node and place it at the lowest left branch * of the current right branch */ psub = pnext; /* walk the Right/Left sub tree from current node */ while ((pnextl = psub->left)) psub = pnextl; /* plug the old left tree to the new ->Right leftmost node */ psub->left = rt_found->left; } else { /* only left sub-tree, simple case */ pnext = rt_found->left; } /* Now, plug the current node sub tree to the good pointer of * our parent node. */ if (pprevious->left == rt_found) pprevious->left = pnext; else pprevious->right = pnext; /* clean-up entry and add to the free-list */ at_state.flags |= AT_ST_RT_CHANGED; return(rt_found); } else { /* Trying to delete something that doesn't exist? */ dPrintf(D_M_RTMP, D_L_WARNING, ("%s : %d NOT Removed\n", "rt_bdelete", NetStop)); return ((RT_entry *)NULL); } } #if DEBUG RT_entry *rt_sortedshow(RT_entry *parent); RT_entry *rt_sortedshow(RT_entry *parent) { RT_entry *me; me = parent; if (parent == NULL) { me = &RT_table_start; while (me) if (me->left) { parent = me; me = me->left; } /* parent = parent->parent; */ } return (parent); } /* * debug only: display the contents of the routing table */ void rt_show(void); void rt_show(void) { RT_entry *ptree; int i=0; ptree = &RT_table[0]; while (ptree && i < 600 ) { if (ptree->NetStop) { dPrintf(D_M_RTMP_LOW, D_L_VERBOSE, ("%4d-%4d IR=%d:%d Dist=%d\n", ptree->NetStop, ptree->NetStart, ptree->NextIRNet, ptree->NextIRNode, (short)ptree->NetDist)); } else { dPrintf(D_M_RTMP_LOW, D_L_VERBOSE, ("%04d : * FREE ENTRY\n", i)); } ptree++; i++; } } #endif /* DEBUG */ /* * prepare the indexing of the free entries in the RTMP table */ int rt_table_init() { short i; if ((RT_table = (RT_entry *)_MALLOC(sizeof(RT_entry)*RT_maxentry, M_RTABLE, M_WAITOK)) == NULL) { dPrintf(D_M_RTMP, D_L_WARNING, ("rtmptable: Can't allocate RT_table\n")); return (ENOMEM); } if ((ZT_table = (ZT_entry *)_MALLOC(sizeof(ZT_entry)*ZT_maxentry, M_RTABLE, M_WAITOK)) == NULL) { dPrintf(D_M_RTMP, D_L_WARNING, ("rtmptable: Can't allocate ZT_table\n")); return (ENOMEM); } dPrintf(D_M_RTMP, D_L_STARTUP, ("rt_table_init called\n")); bzero(&RT_table[0], sizeof(RT_entry)* RT_maxentry); for (i= 1 ; i < RT_maxentry ; i++) { (&RT_table[i-1])->right = &RT_table[i]; } RT_table_freelist = &RT_table[0]; at_state.flags |= AT_ST_RT_CHANGED; at_state.flags |= AT_ST_ZT_CHANGED; bzero(&RT_table_start, sizeof(RT_entry)); /* also clean up the ZIP table */ bzero(&ZT_table[0], sizeof(ZT_entry)* ZT_maxentry); ErrorRTMPoverflow = 0; ErrorZIPoverflow = 0; return(0); } /* * zt_add_zone: add a zone name in the zone table. */ int zt_add_zone(name, length) char *name; short length; { at_nvestr_t zname; bcopy(name, &zname.str, length); zname.len = length; return (zt_add_zonename(&zname)); } /* * zt_add_zonename: add a zone name in the zone table. */ int zt_add_zonename(zname) at_nvestr_t *zname; { register short res,i; if ((res = zt_find_zname(zname))) return(res); for (i = 0; i < ZT_maxentry ; i++) { if (ZT_table[i].ZoneCount == 0 && ZT_table[i].Zone.len == 0) {/* free entry */ ZT_table[i].Zone = *zname; dPrintf(D_M_RTMP, D_L_VERBOSE, ("zt_add_zonename: zone #%d %s len=%d\n", i, ZT_table[i].Zone.str, ZT_table[i].Zone.len)); at_state.flags |= AT_ST_ZT_CHANGED; return(i+1); } } /* table full... */ return (ZT_MAXEDOUT); } /* Adjust zone counts for a removed network entry. * If the ZoneCount of a zone reaches zero, delete the zone from the zone table */ void zt_remove_zones(zmap) u_char *zmap; { register u_short i,j, Index; for (i=0; i< ZT_BYTES ; i++) { if (zmap[i]) { for (j=0; j < 8 ; j++) if ((zmap[i] << j) & 0x80) { Index = i*8 + j; /* get the index in ZT */ /* 1-23-97 this routine caused a crash once, presumably zmap bits beyond ZT_table size got set somehow. prevent that here */ if (Index >= ZT_maxentry) { dPrintf(D_M_RTMP, D_L_ERROR, ("zt_remove_zones: index (%d) GT ZT_maxentry (%d) (zmap:%d)\n", Index,ZT_maxentry,i)); return; } dPrintf(D_M_RTMP, D_L_VERBOSE, ("zt_remove_zones: zone #%d %s was=%d\n", Index, ZT_table[Index].Zone.str, ZT_table[Index].ZoneCount)); if (ZT_table[Index].ZoneCount > 0) ZT_table[Index].ZoneCount--; if (ZT_table[Index].ZoneCount == 0) ZT_table[Index].Zone.len = 0; at_state.flags |= AT_ST_ZT_CHANGED; } } } } /* * zt_compute_hash: compute hash index from the zone name string */ static short zt_compute_hash(at_nvestr_t *); static short zt_compute_hash(zname) at_nvestr_t *zname; { register u_short checksum=0, i; register char c1; /* apply the upper name + DDP checksum algorithm */ for (i= 0 ; i < zname->len; i++) { /* upperize the character */ c1 = zname->str[i]; if (c1 >= 'a' && c1 <= 'z') c1 += 'A' - 'a'; if (c1 & 0x80) c1 = upshift8(c1); /* DDP Checksum */ checksum += c1; checksum = ((checksum & 0x8000) ? (checksum << 1 | 1) : (checksum << 1)); } dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("zt_comphash: value computed for zone=%s h=%d\n", zname->str, checksum)); if (checksum) return (checksum); else return (0xffff); } /* * zt_upper_zname: translate the name string into uppercase */ #if 0 void zt_upper_zname(zname) at_nvestr_t *zname; { register short i; register char c1; for (i= 0 ; i < zname->len; i++) { c1 = zname->str[i]; if (c1 >= 'a' && c1 <= 'z') c1 += 'A' - 'a'; if (c1 & 0x80) c1 = upshift8(c1); zname->str[i] = c1; } } #endif /* * zt_get_zmcast: calcularte the zone multicast address for a * given zone name. * Returns the result in "buffer" */ int zt_get_zmcast(ifID, zname, buffer) at_ifaddr_t *ifID; /* we want to know the media type */ at_nvestr_t *zname; /* source name for multicast address */ char *buffer; /* resulting Zone Multicast address */ { u_short h; h = zt_compute_hash(zname); /* * Find a nice way to decide if it is TokenRing or Ethernet for * the Multicast address computation.... */ if (ifID->aa_ifp->if_type != IFT_ISO88025) { /* token ring */ /* Ethernet case */ buffer[0] = 0x09; buffer[1] = 0x00; buffer[2] = 0x07; /* no router, use cable multicast */ if (MULTIHOME_MODE && ifID->ifRouterState == NO_ROUTER ) { buffer[3] = buffer[4] = buffer[5] = 0xff; } else { buffer[3] = 0x00; buffer[4] = 0x00; buffer[5] = h % 0xFD; } dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("zt_get_multi: computed for h=%d %x %x\n", h, *(u_int *)&buffer[0], *(u_short *)&buffer[4])); return(6); /* returns Multicast address length */ } else { /* assume it is token ring: note for the magic number computation, * first see Inside Mac Page 3-10, there is 20 multicast addresses * for TLAP, and they are from 0xC000 0000 0008 00 to 0xC000 0200 0000 00 */ buffer[0] = 0xC0; buffer[1] = 0x00; *(u_int *)&buffer[2] = 1 << ((h % 19) + 11); dPrintf(D_M_RTMP, D_L_WARNING,("zt_get_multi: BROAD not found forr h=%d \n", h)); return(6); } } /* * zt_ent_zindex: return the first zone index found in the zone map * return the entry number+1 in the Zone Table, or zero if not found */ int zt_ent_zindex(zmap) u_char *zmap; { u_short i,j; for (i = 0 ; i < ZT_BYTES ; i++) if (zmap[i]) for (j = 0 ; j < 8 ; j++) if ((zmap[i] << j) & 0x80) return (8*i + j +1); return (0); } /* * zt_ent_zcount: count the number of actives zone for a routing entry */ int zt_ent_zcount(ent) RT_entry *ent; { register u_char *zmap; register u_short i,j; register int zone_count = 0 ; if (!RT_ALL_ZONES_KNOWN(ent)) return (0); zmap = ent->ZoneBitMap; for (i = 0 ; i < ZT_BYTES ; i++) { if (*zmap) for (j = 0 ; j < 8 ; j++) if ((*zmap << j) & 0x80) zone_count++; zmap++; } return (zone_count); } /* * zt_find_zname: match a zone name in the zone table and return the entry if found */ int zt_find_zname(zname) at_nvestr_t *zname; { register short i, j, found; register char c1, c2; if (!zname->len) return(0); for (i = 0 ; i < ZT_maxentry ; i++) { if (!ZT_table[i].ZoneCount || zname->len != ZT_table[i].Zone.len) continue; found = 1; /* did we get the right one? */ for (j = 0 ; j < zname->len ; j++) { c1 = zname->str[j]; c2 = ZT_table[i].Zone.str[j]; if (c1 >= 'a' && c1 <= 'z') c1 += 'A' - 'a'; if (c2 >= 'a' && c2 <= 'z') c2 += 'A' - 'a'; if (c1 & 0x80) c1 = upshift8(c1); if (c2 & 0x80) c2 = upshift8(c2); if (c1 != c2) { found = 0; break; } } if (found) return (i+1); } return(0); } /* * zt_set_zmap: set a bit for the corresponding zone map in an entry bitmap */ void zt_set_zmap(znum, zmap) u_short znum; unsigned char *zmap; { register u_short num = znum -1; if (!(zmap[num >> 3] & 0x80 >> (num % 8))) { zmap[num >> 3] |= 0x80 >> (num % 8); ZT_table[num].ZoneCount++; } } /* * zt_clr_zmap: clear a bit for the corresponding zone map in an entry bitmap */ #if 0 void zt_clr_zmap(znum, zmap) u_short znum; char *zmap; { register u_short num = znum -1; if (zmap[num >> 3] & 0x80 >> (num % 8)) { zmap[num >> 3] ^= 0x80 >> (num % 8); ZT_table[num].ZoneCount--; } } #endif /* * routing_needed : * This function performs the actual lookup and forward of packets * send to the box for routing. * * The destination network is looked up in our tables, and if we * know the next IR to send the packet to, we forward the packet * on the right port. * * If the destination is unknown, we simply dump the packet. */ void routing_needed(mp, ifID, bypass) gbuf_t *mp; at_ifaddr_t *ifID; char bypass; /* set by special socket handlers */ { register at_ddp_t *ddp; register int msgsize; register RT_entry *Entry; register gbuf_t *tmp_m; /* first check the interface is up and forwarding */ if (!ifID) { dPrintf(D_M_RTMP, D_L_WARNING, ("routing_needed: non valid IFID!\n")); gbuf_freel(mp); return; } if ((ifID->ifRoutingState < PORT_ONLINE)) { dPrintf(D_M_RTMP, D_L_WARNING, ("routing_needed: port %d not online yet\n", ifID->ifPort)); gbuf_freel(mp); return; } ddp = (at_ddp_t *)gbuf_rptr(mp); msgsize = DDPLEN_VALUE(ddp); for (tmp_m = gbuf_next(mp); tmp_m; tmp_m = gbuf_next(tmp_m)) msgsize += DDPLEN_VALUE(((at_ddp_t *)gbuf_rptr(tmp_m))); if (ddp->hopcount++ > 15) { dPrintf(D_M_RTMP, D_L_WARNING, ("routing_needed: drop packet for %d:%d, hopcount too high\n", NET_VALUE(ddp->dst_net), ddp->dst_node)); gbuf_freel(mp); snmpStats.dd_hopCount++; return; /* was return(1); */ } if ((Entry = rt_blookup(NET_VALUE(ddp->dst_net)))) { dPrintf(D_M_RTMP_LOW, D_L_ROUTING, ("routing_needed: FOUND for %d.%d p=%d to %d.%d \n", NET_VALUE(ddp->dst_net), ddp->dst_node, ifID->ifPort, Entry->NextIRNet, Entry->NextIRNode)); /* somehow, come to that point... */ /* if multihomed - need to set source address to the interface * the packet is being sent from. */ if (MULTIHOME_MODE) { NET_ASSIGN(ddp->src_net, ifID_table[Entry->NetPort]->ifThisNode.s_net); ddp->src_node = ifID_table[Entry->NetPort]->ifThisNode.s_node; } ifID->ifStatistics.fwdPkts++; ifID->ifStatistics.fwdBytes += msgsize; if (Entry->NetDist) /* net not directly connected */ ddp_router_output(mp, ifID_table[Entry->NetPort], AT_ADDR, Entry->NextIRNet, Entry->NextIRNode, 0); else {/* we are directly on this net */ /* we want to avoid duplicating broadcast packet on the same net, * but special sockets handlers are ok to do that (mainly for * for loopback purpose). So, if the "bypass" flag is set, we don't * check for that test... [Problem was "movietalk"]. */ if (bypass || ifID_table[Entry->NetPort] != ifID) ddp_router_output(mp, ifID_table[Entry->NetPort], AT_ADDR, NET_VALUE(ddp->dst_net), ddp->dst_node, 0); else { dPrintf(D_M_RTMP, D_L_ROUTING, ("routing_needed: bad loopback for add %d.%d from port %d (%d.%d)\n", NET_VALUE(ddp->dst_net), ddp->dst_node, ifID->ifPort, NET_VALUE(ddp->src_net), ddp->src_node)); ifID->ifStatistics.droppedPkts++; ifID->ifStatistics.droppedBytes += msgsize; gbuf_freel(mp); return; /* was return (2); */ } } } else { dPrintf(D_M_RTMP, D_L_ROUTING, ("routing_needed: NOT FOUND for add %d.%d from port %d our %d.%d\n", NET_VALUE(ddp->dst_net), ddp->dst_node, ifID->ifPort, ifID_home->ifThisNode.s_net, ifID_home->ifThisNode.s_node)); ifID->ifStatistics.droppedPkts++; ifID->ifStatistics.droppedBytes += msgsize; snmpStats.dd_noRoutes++; gbuf_freel(mp); return; /* was return (2); */ } /* return(0); */ } /* routing_needed */ ZT_entryno *zt_getNextZone(first) int first; /* a call made with first = TRUE returns the first valid entry in the ZT_table, if first != TRUE, then then each call returns the next valid entry in the table. The next call after the last valid entry was read returns NULL */ { int i; static int idx=0; static ZT_entryno zte; if (!ZT_table) return NULL; if (first) idx=0; for (i=idx; iEntryState != RTE_STATE_UNUSED) { size = i; return(i); } return(0); } int getZipTableSize(void) { register int i; register ZT_entry *zt; static int size=0; if (!(at_state.flags & AT_ST_ZT_CHANGED)) return(size); for (i=ZT_maxentry,zt = &ZT_table[ZT_maxentry-1]; i; i--,zt--) if (zt->ZoneCount) { size = i; return(i); } return(0); } void getRtmpTable(d,s,c) RT_entry *d; /* destination */ int s; /* starting entry */ int c; /* # entries to copy */ { register int i,n=0; register RT_entry *rt; for(i=s,rt=&RT_table[s]; iEntryState != RTE_STATE_UNUSED) { *d++ = *rt; n++; } } void getZipTable(d,s,c) ZT_entry *d; /* destination */ int s; /* starting entry */ int c; /* # entries to copy */ { bcopy(&ZT_table[s], d, c*sizeof(ZT_entry)); } at_nvestr_t *getRTRLocalZone(ifz) zone_usage_t *ifz; { unsigned char *zmap = NULL; RT_entry *route; int i, j, index; int zcnt=0; /* zone we're pointing to in the list */ char zonesChecked[ZT_BYTES]; at_ifaddr_t *ifID; if (ifz->zone_index < 0) { return((at_nvestr_t*)NULL); } bzero(zonesChecked,sizeof(zonesChecked)); TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) { if (!(route = rt_blookup(ifID->ifThisNode.s_net))) { return((at_nvestr_t*)NULL); } zmap=route->ZoneBitMap; dPrintf(D_M_RTMP_LOW, D_L_USR1, ("getRTRLocal: i/f %s, net:%d\n",ifID->ifName, ifID->ifThisNode.s_net)); for (i = 0 ; i < ZT_BYTES; i++) { if (zmap[i]) { for (j = 0; j < 8 ; j++) if ( (zmap[i] & (0x80 >> j)) && !(zonesChecked[i] & (0x80 >> j)) ) { zonesChecked[i] |= (0x80 >> j); if (ifz->zone_index == zcnt) { index = i * 8 + j; getIfUsage(index, &ifz->zone_iflist); ifz->zone_name = ZT_table[index].Zone; dPrintf(D_M_RTMP_LOW, D_L_USR1, ("getRTRLocal:zmap:%8x zcnt:%d\n", *(int*)zmap, zcnt)); ifz->zone_index = index+1; return(&ZT_table[index].Zone); } zcnt++; } } } } dPrintf(D_M_RTMP_LOW, D_L_USR1, ("getRTRLocal: returning NULL last ent:%d net:%d zmap:%08x\n", (ifID ? ifID->ifPort : 0), (ifID ? ifID->ifThisNode.s_net : 0),*(int*)zmap)); ifz->zone_name.len = 0; return((at_nvestr_t*)NULL); } /* getRTRLocalZone */ void getIfUsage(zone, ifs_in_zone) int zone; at_ifnames_t *ifs_in_zone; /* sets the interface name in each element of the array for each I/F in the requested zone. The array has a 1:1 correspondence with the ifID_table. Zone is assumed to be valid and local, so if we're in single port mode, we'll set the home port and thats it. */ { u_int zmi; /* zone map index for zone */ u_char zmb; /* zone map bit mask for zone */ RT_entry *route; int cnt=0; at_ifaddr_t *ifID; if (!MULTIPORT_MODE) { strlcpy(ifs_in_zone->at_if[cnt], ifID_home->ifName, IFNAMESIZ); return; } bzero(ifs_in_zone, sizeof(at_ifnames_t)); zmi = zone>>3; zmb = 0x80>>(zone % 8); dPrintf(D_M_NBP_LOW, D_L_USR3, ("get_ifs znum:%d zmi%d zmb:%x\n", zone, zmi, zmb)); TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) { if (!(route = rt_blookup(ifID->ifThisNode.s_net))) return; if (route->ZoneBitMap[zmi] & zmb) { dPrintf(D_M_NBP_LOW, D_L_USR3, ("zone in port %d \n", route->NetPort)); strlcpy(ifs_in_zone->at_if[cnt], ifID_table[route->NetPort]->ifName, IFNAMESIZ); cnt++; } } return; } /* getIfUsage */