/** * Sends a group specific member report query until the * group times out... */ static void sendGroupSpecificMemberQuery(void *argument) { struct Config *conf = getCommonConfig(); // Cast argument to correct type... GroupVifDesc *gvDesc = (GroupVifDesc*) argument; if(gvDesc->started) { // If aging returns false, we don't do any further action... if(!lastMemberGroupAge(gvDesc->group)) { return; } } else { gvDesc->started = 1; } // Send a group specific membership query... sendIgmp(gvDesc->vifAddr, gvDesc->group, IGMP_MEMBERSHIP_QUERY, conf->lastMemberQueryInterval * IGMP_TIMER_SCALE, gvDesc->group, 0); my_log(LOG_DEBUG, 0, "Sent membership query from %s to %s. Delay: %d", inetFmt(gvDesc->vifAddr,s1), inetFmt(gvDesc->group,s2), conf->lastMemberQueryInterval); // Set timeout for next round... timer_setTimer(conf->lastMemberQueryInterval, sendGroupSpecificMemberQuery, gvDesc); }
/** * Remove a specified route. Returns 1 on success, * and 0 if route was not found. */ int removeRoute(struct RouteTable* croute) { struct Config *conf = getCommonConfig(); int result = 1; // If croute is null, no routes was found. if(croute==NULL) { return 0; } // Log the cleanup in debugmode... my_log(LOG_DEBUG, 0, "Removed route entry for %s from table.", inetFmt(croute->group, s1)); //BIT_ZERO(croute->vifBits); // Uninstall current route from kernel if(!internUpdateKernelRoute(croute, 0)) { my_log(LOG_WARNING, 0, "The removal from Kernel failed."); result = 0; } // Send Leave request upstream if group is joined if(croute->upstrState == ROUTESTATE_JOINED || (croute->upstrState == ROUTESTATE_CHECK_LAST_MEMBER && !conf->fastUpstreamLeave)) { sendJoinLeaveUpstream(croute, 0); } // Update pointers... if(croute->prevroute == NULL) { // Topmost node... if(croute->nextroute != NULL) { croute->nextroute->prevroute = NULL; } routing_table = croute->nextroute; } else { croute->prevroute->nextroute = croute->nextroute; if(croute->nextroute != NULL) { croute->nextroute->prevroute = croute->prevroute; } } // Free the memory, and set the route to NULL... free(croute); croute = NULL; logRouteTable("Remove route"); return result; }
/** * Ages groups in the last member check state. If the * route is not found, or not in this state, 0 is returned. */ int lastMemberGroupAge(struct in6_addr * group, struct in6_addr * src) { struct Config *conf = NULL; struct RouteTable *croute, *nroute; int i; conf = getCommonConfig(); /* printf("\nlastMemberGroupAge called, src = \n"); for (i=0; i <16; i++) printf("%02x ",((char*)group)[i] & 255); printf("\n"); for (i=0; i <16; i++) printf("%02x ",((char*)src)[i] & 255); printf("\n"); */ if( !IN6_ARE_ADDR_EQUAL( src, &allzero_addr ) ) { croute = findRoute(group, src); if(croute!=NULL) { if(croute->upstrState == ROUTESTATE_CHECK_LAST_MEMBER) { internAgeRoute(croute); } } } else { //showRoute(); for( croute = routing_table; croute != NULL; croute = nroute ) { // Keep the next route (since current route may be removed)... nroute = croute->nextroute; // Run the aging round algorithm. if( croute->upstrState = ROUTESTATE_CHECK_LAST_MEMBER && IN6_ARE_ADDR_EQUAL( &croute->group, group ) ) { // Only age routes if Last member probe is not active... internAgeRoute(croute); } } } return 0; }
/** * Should be called when a leave message is recieved, to * mark a route for the last member probe state. */ void setRouteLastMemberMode(struct in6_addr * group, struct in6_addr * src) { struct Config *conf = getCommonConfig(); struct RouteTable *croute, *tmpRoute; croute = findRoute(group, src); if(croute!=NULL) { if( !IN6_ARE_ADDR_EQUAL( src, &allzero_addr) ) { // Check for fast leave mode... /* if(croute->upstrState == ROUTESTATE_JOINED && conf->fastUpstreamLeave) { // Send a leave message right away.. sendJoinLeaveUpstream(croute, 0); } */ // Set the routingstate to Last member check... croute->upstrState = ROUTESTATE_CHECK_LAST_MEMBER; // Set the count value for expiring... (-1 since first aging) croute->ageValue = conf->lastMemberQueryCount; } else { tmpRoute = findNextRoute(group, NULL); while(tmpRoute) { // Check for fast leave mode... /* if(tmpRoute->upstrState == ROUTESTATE_JOINED && conf->fastUpstreamLeave) { // Send a leave message right away.. sendJoinLeaveUpstream(tmpRoute, 0); } */ // Set the routingstate to Last member check... tmpRoute->upstrState = ROUTESTATE_CHECK_LAST_MEMBER; // Set the count value for expiring... (-1 since first aging) tmpRoute->ageValue = conf->lastMemberQueryCount; if (tmpRoute->nextroute) tmpRoute = findNextRoute(group, tmpRoute->nextroute); else break; } } } }
/** * Should be called when a leave message is recieved, to * mark a route for the last member probe state. */ void setRouteLastMemberMode(uint32_t group) { struct Config *conf = getCommonConfig(); struct RouteTable *croute; croute = findRoute(group); if(croute!=NULL) { // Check for fast leave mode... if(croute->upstrState == ROUTESTATE_JOINED && conf->fastUpstreamLeave) { // Send a leave message right away.. sendJoinLeaveUpstream(croute, 0); } // Set the routingstate to Last member check... croute->upstrState = ROUTESTATE_CHECK_LAST_MEMBER; // Set the count value for expiring... (-1 since first aging) croute->ageValue = conf->lastMemberQueryCount; } }
/** * Sends a general membership query on downstream VIFs */ void sendGeneralMembershipQuery() { struct Config *conf = getCommonConfig(); struct IfDesc *Dp; unsigned Ix; #ifdef RALINK_ESW_SUPPORT clear_all_entries_report(); #endif // Loop through all downstream vifs... for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) { if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) { if(Dp->state == IF_STATE_DOWNSTREAM) { // Send the membership query... sendIgmp(Dp->InAdr.s_addr, allhosts_group, IGMP_MEMBERSHIP_QUERY, conf->queryResponseInterval * IGMP_TIMER_SCALE, 0, 0); my_log(LOG_DEBUG, 0, "Sent membership query from %s to %s. Delay: %d", inetFmt(Dp->InAdr.s_addr,s1), inetFmt(allhosts_group,s2), conf->queryResponseInterval); } } } // Install timer for aging active routes. timer_setTimer(conf->queryResponseInterval, ageActiveRoutes, NULL); // Install timer for next general query... if(conf->startupQueryCount>0) { // Use quick timer... timer_setTimer(conf->startupQueryInterval, sendGeneralMembershipQuery, NULL); // Decrease startup counter... conf->startupQueryCount--; } else { // Use slow timer... timer_setTimer(conf->queryInterval, sendGeneralMembershipQuery, NULL); } }
/** * Should be called when a leave message is received, to * mark a route for the last member probe state. */ void setRouteLastMemberMode(uint32_t group) { struct Config *conf = getCommonConfig(); struct RouteTable *croute; croute = findRoute(group); if(croute!=NULL) { // Check for fast leave mode... if(croute->upstrState == ROUTESTATE_JOINED && conf->fastUpstreamLeave) { // Send a leave message right away only when the route has been active on only one interface if (numberOfInterfaces(croute) <= 1) { my_log(LOG_DEBUG, 0, "Leaving group %d now", group); sendJoinLeaveUpstream(croute, 0); } } // Set the routingstate to Last member check... croute->upstrState = ROUTESTATE_CHECK_LAST_MEMBER; // Set the count value for expiring... (-1 since first aging) croute->ageValue = conf->lastMemberQueryCount; } }
/*************************************************** * TODO: Only need run me when detect downstream changed. * For example: /etc/ppp/ip-up & ip-down can touch a file /tmp/ppp_changed * So I can check if the file exist then run me and delete the file. ***************************************************/ void rebuildIfVc () { struct ifreq IfVc[ sizeof( IfDescVc ) / sizeof( IfDescVc[ 0 ] ) ]; struct ifreq *IfEp; struct ifconf IoCtlReq; struct IfDesc *Dp; struct ifreq *IfPt, *IfNext; uint32_t addr, subnet, mask; int Sock, Ix; // Get the config. struct Config *config = getCommonConfig(); if ( (Sock = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 ) my_log( LOG_ERR, errno, "RAW socket open" ); // aimwang: set all downstream IF as lost, for check IF exist or gone. for (Dp = IfDescVc; Dp < IfDescEp; Dp++) { if (Dp->state == IF_STATE_DOWNSTREAM) { Dp->state = IF_STATE_LOST; } } IoCtlReq.ifc_buf = (void *)IfVc; IoCtlReq.ifc_len = sizeof( IfVc ); if ( ioctl( Sock, SIOCGIFCONF, &IoCtlReq ) < 0 ) my_log( LOG_ERR, errno, "ioctl SIOCGIFCONF" ); IfEp = (void *)((char *)IfVc + IoCtlReq.ifc_len); for ( IfPt = IfVc; IfPt < IfEp; IfPt = IfNext ) { struct ifreq IfReq; char FmtBu[ 32 ]; IfNext = (struct ifreq *)((char *)&IfPt->ifr_addr + #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN IfPt->ifr_addr.sa_len #else sizeof(struct sockaddr_in) #endif ); if (IfNext < IfPt + 1) IfNext = IfPt + 1; for (Dp = IfDescVc; Dp < IfDescEp; Dp++) { if (0 == strcmp(Dp->Name, IfPt->ifr_name)) { break; } } if (Dp == IfDescEp) { strncpy( Dp->Name, IfPt->ifr_name, sizeof( IfDescEp->Name ) ); } if ( IfPt->ifr_addr.sa_family != AF_INET ) { if (Dp == IfDescEp) { IfDescEp++; } Dp->InAdr.s_addr = 0; /* mark as non-IP interface */ continue; } // Get the interface adress... Dp->InAdr = ((struct sockaddr_in *)&IfPt->ifr_addr)->sin_addr; addr = Dp->InAdr.s_addr; memcpy( IfReq.ifr_name, Dp->Name, sizeof( IfReq.ifr_name ) ); IfReq.ifr_addr.sa_family = AF_INET; ((struct sockaddr_in *)&IfReq.ifr_addr)->sin_addr.s_addr = addr; // Get the subnet mask... if (ioctl(Sock, SIOCGIFNETMASK, &IfReq ) < 0) my_log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", IfReq.ifr_name); mask = ((struct sockaddr_in *)&IfReq.ifr_addr)->sin_addr.s_addr; subnet = addr & mask; if ( ioctl( Sock, SIOCGIFFLAGS, &IfReq ) < 0 ) my_log( LOG_ERR, errno, "ioctl SIOCGIFFLAGS" ); Dp->Flags = IfReq.ifr_flags; if (0x10d1 == Dp->Flags) { if ( ioctl( Sock, SIOCGIFDSTADDR, &IfReq ) < 0 ) my_log(LOG_ERR, errno, "ioctl SIOCGIFDSTADDR for %s", IfReq.ifr_name); addr = ((struct sockaddr_in *)&IfReq.ifr_dstaddr)->sin_addr.s_addr; subnet = addr & mask; } if (Dp == IfDescEp) { // Insert the verified subnet as an allowed net... Dp->allowednets = (struct SubnetList *)malloc(sizeof(struct SubnetList)); if(IfDescEp->allowednets == NULL) { my_log(LOG_ERR, 0, "Out of memory !"); } Dp->allowednets->next = NULL; Dp->state = IF_STATE_DOWNSTREAM; Dp->robustness = DEFAULT_ROBUSTNESS; Dp->threshold = DEFAULT_THRESHOLD; /* ttl limit */ Dp->ratelimit = DEFAULT_RATELIMIT; } // Set the network address for the IF.. Dp->allowednets->subnet_mask = mask; Dp->allowednets->subnet_addr = subnet; // Set the state for the IF... if (Dp->state == IF_STATE_LOST) { Dp->state = IF_STATE_DOWNSTREAM; } // when IF become enabeld from downstream, addVIF to enable its VIF if (Dp->state == IF_STATE_HIDDEN) { my_log(LOG_NOTICE, 0, "%s [Hidden -> Downstream]", Dp->Name); Dp->state = IF_STATE_DOWNSTREAM; addVIF(Dp); joinMcGroup(getMcGroupSock(), Dp, allrouters_group); } // addVIF when found new IF if (Dp == IfDescEp) { my_log(LOG_NOTICE, 0, "%s [New]", Dp->Name); Dp->state = config->defaultInterfaceState; addVIF(Dp); joinMcGroup(getMcGroupSock(), Dp, allrouters_group); IfDescEp++; } // Debug log the result... my_log( LOG_DEBUG, 0, "rebuildIfVc: Interface %s Addr: %s, Flags: 0x%04x, Network: %s", Dp->Name, fmtInAdr( FmtBu, Dp->InAdr ), Dp->Flags, inetFmts(subnet, mask, s1)); } // aimwang: search not longer exist IF, set as hidden and call delVIF for (Dp = IfDescVc; Dp < IfDescEp; Dp++) { if (IF_STATE_LOST == Dp->state) { my_log(LOG_NOTICE, 0, "%s [Downstream -> Hidden]", Dp->Name); Dp->state = IF_STATE_HIDDEN; leaveMcGroup( getMcGroupSock(), Dp, allrouters_group ); delVIF(Dp); } } close( Sock ); }
/* ** Builds up a vector with the interface of the machine. Calls to the other functions of ** the module will fail if they are called before the vector is build. ** */ void buildIfVc(void) { struct ifreq IfVc[ sizeof( IfDescVc ) / sizeof( IfDescVc[ 0 ] ) ]; struct ifreq *IfEp; struct Config *config = getCommonConfig(); int Sock; if ( (Sock = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 ) my_log( LOG_ERR, errno, "RAW socket open" ); /* get If vector */ { struct ifconf IoCtlReq; IoCtlReq.ifc_buf = (void *)IfVc; IoCtlReq.ifc_len = sizeof( IfVc ); if ( ioctl( Sock, SIOCGIFCONF, &IoCtlReq ) < 0 ) my_log( LOG_ERR, errno, "ioctl SIOCGIFCONF" ); IfEp = (void *)((char *)IfVc + IoCtlReq.ifc_len); } /* loop over interfaces and copy interface info to IfDescVc */ { struct ifreq *IfPt, *IfNext; // Temp keepers of interface params... uint32_t addr, subnet, mask; for ( IfPt = IfVc; IfPt < IfEp; IfPt = IfNext ) { struct ifreq IfReq; char FmtBu[ 32 ]; IfNext = (struct ifreq *)((char *)&IfPt->ifr_addr + #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN IfPt->ifr_addr.sa_len #else sizeof(struct sockaddr_in) #endif ); if (IfNext < IfPt + 1) IfNext = IfPt + 1; strncpy( IfDescEp->Name, IfPt->ifr_name, sizeof( IfDescEp->Name ) ); // Currently don't set any allowed nets... //IfDescEp->allowednets = NULL; // Set the index to -1 by default. IfDescEp->index = -1; /* don't retrieve more info for non-IP interfaces */ if ( IfPt->ifr_addr.sa_family != AF_INET ) { IfDescEp->InAdr.s_addr = 0; /* mark as non-IP interface */ IfDescEp++; continue; } // Get the interface adress... IfDescEp->InAdr = ((struct sockaddr_in *)&IfPt->ifr_addr)->sin_addr; addr = IfDescEp->InAdr.s_addr; memcpy( IfReq.ifr_name, IfDescEp->Name, sizeof( IfReq.ifr_name ) ); IfReq.ifr_addr.sa_family = AF_INET; ((struct sockaddr_in *)&IfReq.ifr_addr)->sin_addr.s_addr = addr; // Get the subnet mask... if (ioctl(Sock, SIOCGIFNETMASK, &IfReq ) < 0) my_log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", IfReq.ifr_name); mask = ((struct sockaddr_in *)&IfReq.ifr_addr)->sin_addr.s_addr; subnet = addr & mask; /* get if flags ** ** typical flags: ** lo 0x0049 -> Running, Loopback, Up ** ethx 0x1043 -> Multicast, Running, Broadcast, Up ** ipppx 0x0091 -> NoArp, PointToPoint, Up ** grex 0x00C1 -> NoArp, Running, Up ** ipipx 0x00C1 -> NoArp, Running, Up */ if ( ioctl( Sock, SIOCGIFFLAGS, &IfReq ) < 0 ) my_log( LOG_ERR, errno, "ioctl SIOCGIFFLAGS" ); IfDescEp->Flags = IfReq.ifr_flags; // aimwang: when pppx get dstaddr for use if (0x10d1 == IfDescEp->Flags) { if ( ioctl( Sock, SIOCGIFDSTADDR, &IfReq ) < 0 ) my_log(LOG_ERR, errno, "ioctl SIOCGIFDSTADDR for %s", IfReq.ifr_name); addr = ((struct sockaddr_in *)&IfReq.ifr_dstaddr)->sin_addr.s_addr; subnet = addr & mask; } // Insert the verified subnet as an allowed net... IfDescEp->allowednets = (struct SubnetList *)malloc(sizeof(struct SubnetList)); if(IfDescEp->allowednets == NULL) my_log(LOG_ERR, 0, "Out of memory !"); // Create the network address for the IF.. IfDescEp->allowednets->next = NULL; IfDescEp->allowednets->subnet_mask = mask; IfDescEp->allowednets->subnet_addr = subnet; // Set the default params for the IF... IfDescEp->state = config->defaultInterfaceState; IfDescEp->robustness = DEFAULT_ROBUSTNESS; IfDescEp->threshold = DEFAULT_THRESHOLD; /* ttl limit */ IfDescEp->ratelimit = DEFAULT_RATELIMIT; // Debug log the result... my_log( LOG_DEBUG, 0, "buildIfVc: Interface %s Addr: %s, Flags: 0x%04x, Network: %s", IfDescEp->Name, fmtInAdr( FmtBu, IfDescEp->InAdr ), IfDescEp->Flags, inetFmts(subnet,mask, s1)); IfDescEp++; } } close( Sock ); }
/** * Ages a specific route */ int internAgeRoute(struct RouteTable* croute) { struct Config *conf = getCommonConfig(); int result = 0; // Drop age by 1. croute->ageValue--; // Check if there has been any activity... if( croute->ageVifBits > 0 && croute->ageActivity == 0 ) { // There was some activity, check if all registered vifs responded. if(croute->vifBits == croute->ageVifBits) { // Everything is in perfect order, so we just update the route age. croute->ageValue = conf->robustnessValue; //croute->ageActivity = 0; } else { // One or more VIF has not gotten any response. croute->ageActivity++; // Update the actual bits for the route... croute->vifBits = croute->ageVifBits; } } // Check if there have been activity in aging process... else if( croute->ageActivity > 0 ) { // If the bits are different in this round, we must if(croute->vifBits != croute->ageVifBits) { // Or the bits together to insure we don't lose any listeners. croute->vifBits |= croute->ageVifBits; // Register changes in this round as well.. croute->ageActivity++; } } // If the aging counter has reached zero, its time for updating... if(croute->ageValue == 0) { // Check for activity in the aging process, if(croute->ageActivity>0) { my_log(LOG_DEBUG, 0, "Updating route after aging : %s", inetFmt(croute->group,s1)); // Just update the routing settings in kernel... internUpdateKernelRoute(croute, 1); // We append the activity counter to the age, and continue... croute->ageValue = croute->ageActivity; croute->ageActivity = 0; } else { my_log(LOG_DEBUG, 0, "Removing group %s. Died of old age.", inetFmt(croute->group,s1)); // No activity was registered within the timelimit, so remove the route. removeRoute(croute); } // Tell that the route was updated... result = 1; } // The aging vif bits must be reset for each round... BIT_ZERO(croute->ageVifBits); return result; }
/** * Adds a specified route to the routingtable. * If the route already exists, the existing route * is updated... */ int insertRoute(uint32_t group, int ifx) { struct Config *conf = getCommonConfig(); struct RouteTable* croute; // Sanitycheck the group adress... if( ! IN_MULTICAST( ntohl(group) )) { my_log(LOG_WARNING, 0, "The group address %s is not a valid Multicast group. Table insert failed.", inetFmt(group, s1)); return 0; } // Santiycheck the VIF index... //if(ifx < 0 || ifx >= MAX_MC_VIFS) { if(ifx >= MAX_MC_VIFS) { my_log(LOG_WARNING, 0, "The VIF Ix %d is out of range (0-%d). Table insert failed.",ifx,MAX_MC_VIFS); return 0; } // Try to find an existing route for this group... croute = findRoute(group); if(croute==NULL) { struct RouteTable* newroute; my_log(LOG_DEBUG, 0, "No existing route for %s. Create new.", inetFmt(group, s1)); // Create and initialize the new route table entry.. newroute = (struct RouteTable*)malloc(sizeof(struct RouteTable)); // Insert the route desc and clear all pointers... newroute->group = group; memset(newroute->originAddrs, 0, MAX_ORIGINS * sizeof(newroute->originAddrs[0])); newroute->nextroute = NULL; newroute->prevroute = NULL; // The group is not joined initially. newroute->upstrState = ROUTESTATE_NOTJOINED; // The route is not active yet, so the age is unimportant. newroute->ageValue = conf->robustnessValue; newroute->ageActivity = 0; BIT_ZERO(newroute->ageVifBits); // Initially we assume no listeners. // Set the listener flag... BIT_ZERO(newroute->vifBits); // Initially no listeners... if(ifx >= 0) { BIT_SET(newroute->vifBits, ifx); } // Check if there is a table already.... if(routing_table == NULL) { // No location set, so insert in on the table top. routing_table = newroute; my_log(LOG_DEBUG, 0, "No routes in table. Insert at beginning."); } else { my_log(LOG_DEBUG, 0, "Found existing routes. Find insert location."); // Check if the route could be inserted at the beginning... if(routing_table->group > group) { my_log(LOG_DEBUG, 0, "Inserting at beginning, before route %s",inetFmt(routing_table->group,s1)); // Insert at beginning... newroute->nextroute = routing_table; newroute->prevroute = NULL; routing_table = newroute; // If the route has a next node, the previous pointer must be updated. if(newroute->nextroute != NULL) { newroute->nextroute->prevroute = newroute; } } else { // Find the location which is closest to the route. for( croute = routing_table; croute->nextroute != NULL; croute = croute->nextroute ) { // Find insert position. if(croute->nextroute->group > group) { break; } } my_log(LOG_DEBUG, 0, "Inserting after route %s",inetFmt(croute->group,s1)); // Insert after current... newroute->nextroute = croute->nextroute; newroute->prevroute = croute; if(croute->nextroute != NULL) { croute->nextroute->prevroute = newroute; } croute->nextroute = newroute; } } // Set the new route as the current... croute = newroute; // Log the cleanup in debugmode... my_log(LOG_INFO, 0, "Inserted route table entry for %s on VIF #%d", inetFmt(croute->group, s1),ifx); } else if(ifx >= 0) { // The route exists already, so just update it. BIT_SET(croute->vifBits, ifx); // Register the VIF activity for the aging routine BIT_SET(croute->ageVifBits, ifx); // Log the cleanup in debugmode... my_log(LOG_INFO, 0, "Updated route entry for %s on VIF #%d", inetFmt(croute->group, s1), ifx); // Update route in kernel... if(!internUpdateKernelRoute(croute, 1)) { my_log(LOG_WARNING, 0, "The insertion into Kernel failed."); return 0; } } // Send join message upstream, if the route has no joined flag... if(croute->upstrState != ROUTESTATE_JOINED) { // Send Join request upstream sendJoinLeaveUpstream(croute, 1); } logRouteTable("Insert Route"); return 1; }
/** * Remove a specified route. Returns 1 on success, * and 0 if route was not found. */ int removeRoute(struct RouteTable* croute) { int result = 1; struct RouteTable* tmpRoute; struct Config *conf = getCommonConfig(); // If croute is null, no routes was found. if(croute==NULL) return 0; //printf("removeRoute called\n"); //BIT_ZERO(croute->vifBits); // Uninstall current route from kernel if(!internUpdateKernelRoute(croute, 0)) { //printf("The removal from Kernel failed.\n"); atlog(LOG_WARNING, 0, "The removal from Kernel failed."); result = 0; } // Send Leave request upstream if group is joined if(croute->upstrState == ROUTESTATE_JOINED || (croute->upstrState == ROUTESTATE_CHECK_LAST_MEMBER && !conf->fastUpstreamLeave)) { tmpRoute = findNextRoute( &(croute->group), NULL); if (tmpRoute && tmpRoute->nextroute) tmpRoute = findNextRoute( &(croute->group), tmpRoute->nextroute); // the group is not used by others if (tmpRoute == NULL) sendJoinLeaveUpstream(croute, 0); } // Update pointers... if(croute->prevroute == NULL) { // Topmost node... if(croute->nextroute != NULL) { croute->nextroute->prevroute = NULL; } routing_table = croute->nextroute; } else { croute->prevroute->nextroute = croute->nextroute; if(croute->nextroute != NULL) { croute->nextroute->prevroute = croute->prevroute; } } // Free the memory, and set the route to NULL... free(croute); croute = NULL; IF_DEBUG atlogRouteTable("Remove route"); return result; }
/** * Adds a specified route to the routingtable. * If the route already exists, the existing route * is updated... */ int insertRoute(struct in6_addr *group, struct in6_addr *src, struct sockaddr_in6 *from) { struct Config *conf = getCommonConfig(); struct RouteTable *croute, *tmpRoute; //int result = 1; /* int i; printf("insertRoute called\n"); for (i = 0; i < 16; i ++) printf("%02x ", ((char*)group)[i] & 255 ); printf("\n"); for (i = 0; i < 16; i ++) printf("%02x ", ((char*)src)[i] & 255 ); printf("\n"); */ // Sanitycheck the group adress... if ( !IN6_IS_ADDR_MULTICAST(group) ) { atlog( LOG_DEBUG, 0, "Not multicast group"); return 0; } // Santiycheck the VIF index... if(from->sin6_scope_id >= MAX_MC_VIFS) { atlog(LOG_WARNING, 0, "The VIF Ix %d is out of range (0-%d). Table insert failed.", from->sin6_scope_id,MAX_MC_VIFS); return 0; } // Try to find an existing route for this group... croute = findRoute(group, src); if(croute==NULL) { struct RouteTable* newroute; /* IF_DEBUG atlog(LOG_DEBUG, 0, "No existing route for %s. Create new.", inetFmt(group, s1)); */ // Create and initialize the new route table entry.. newroute = (struct RouteTable*)malloc(sizeof(struct RouteTable)); // Insert the route desc and clear all pointers... newroute->group = *group; newroute->originAddr = *src; newroute->nextroute = NULL; newroute->prevroute = NULL; // The group is not joined initially. newroute->upstrState = ROUTESTATE_NOTJOINED; // The route is not active yet, so the age is unimportant. newroute->ageValue = conf->robustnessValue; newroute->ageActivity = 0; BIT_ZERO(newroute->ageVifBits); // Initially we assume no listeners. // Set the listener flag... BIT_ZERO(newroute->vifBits); // Initially no listeners... if(from->sin6_scope_id >= 0) { BIT_SET(newroute->vifBits, from->sin6_scope_id); } // Check if there is a table already.... if(routing_table == NULL) { // No location set, so insert in on the table top. routing_table = newroute; IF_DEBUG atlog(LOG_DEBUG, 0, "No routes in table. Insert at beginning."); } else { IF_DEBUG atlog(LOG_DEBUG, 0, "Found existing routes. Find insert location."); // Check if the route could be inserted at the beginning... if( memcmp(&routing_table->group, group, sizeof(struct in6_addr)) > 0 ) { //IF_DEBUG atlog(LOG_DEBUG, 0, "Inserting at beginning, before route %s",inetFmt(routing_table->group,s1)); // Insert at beginning... newroute->nextroute = routing_table; newroute->prevroute = NULL; routing_table = newroute; // If the route has a next node, the previous pointer must be updated. if(newroute->nextroute != NULL) { newroute->nextroute->prevroute = newroute; } } else { // Find the location which is closest to the route. for( croute = routing_table; croute->nextroute != NULL; croute = croute->nextroute ) { // Find insert position. if( memcmp( &(croute->nextroute->group), group, sizeof(struct in6_addr) ) > 0 ) break; } //IF_DEBUG atlog(LOG_DEBUG, 0, "Inserting after route %s",inetFmt(croute->group,s1)); // Insert after current... newroute->nextroute = croute->nextroute; newroute->prevroute = croute; if(croute->nextroute != NULL) { croute->nextroute->prevroute = newroute; } croute->nextroute = newroute; } } // Set the new route as the current... croute = newroute; if( !IN6_ARE_ADDR_EQUAL( &croute->originAddr, &allzero_addr) ) { // Update route in kernel... if( !internUpdateKernelRoute(croute, 1) ) { atlog(LOG_WARNING, 0, "The insertion into Kernel failed."); return 0; } } } else if(from->sin6_scope_id >= 0) { if( !IN6_ARE_ADDR_EQUAL( &croute->originAddr, &allzero_addr) ) { // The route exists already, so just update it. BIT_SET(croute->vifBits, from->sin6_scope_id); // Register the VIF activity for the aging routine BIT_SET(croute->ageVifBits, from->sin6_scope_id); } else { tmpRoute = findNextRoute(group, NULL); while (tmpRoute != NULL) { // The route exists already, so just update it. BIT_SET(tmpRoute->vifBits, from->sin6_scope_id); // Register the VIF activity for the aging routine BIT_SET(tmpRoute->ageVifBits, from->sin6_scope_id); if (tmpRoute->nextroute) tmpRoute = findNextRoute(group, tmpRoute->nextroute); else break; } } } // Send join message upstream, if the route has no joined flag... if(croute->upstrState != ROUTESTATE_JOINED) { // Send Join request upstream sendJoinLeaveUpstream(croute, 1); } IF_DEBUG atlogRouteTable("Insert Route"); return 1; }