/** * Updates the Kernel routing table. If activate is 1, the route * is (re-)activated. If activate is false, the route is removed. */ int internUpdateKernelRoute(struct RouteTable *route, int activate) { struct MRouteDesc mrDesc; struct IfDesc *Dp; unsigned Ix; struct IfDesc* upstrIf; // Get the upstream VIF... upstrIf = getIfByIx( upStreamVif ); if(upstrIf == NULL) atlog(LOG_ERR, 0 ,"FATAL: Unable to get Upstream IF."); if( IN6_ARE_ADDR_EQUAL( &(route->group), &allzero_addr ) ) return 1; if( IN6_ARE_ADDR_EQUAL( &(route->originAddr), &allzero_addr ) ) return 1; // Build route descriptor from table entry... // Set the source address and group address... mrDesc.McAdr.sin6_addr = route->group; mrDesc.McAdr.sin6_family = AF_INET6; mrDesc.McAdr.sin6_flowinfo = 0; mrDesc.McAdr.sin6_port = 0; mrDesc.McAdr.sin6_scope_id = upstrIf->index; mrDesc.OriginAdr.sin6_addr = route->originAddr; // clear output interfaces memset( mrDesc.TtlVc, 0, sizeof( mrDesc.TtlVc ) ); IF_DEBUG atlog(LOG_DEBUG, 0, "Vif bits : 0x%08x", route->vifBits); for( Ix = 0 ; Ix < MAXMIFS; Ix++ ) { Dp = getIfDescFromMifByIx(Ix); if (Dp == NULL) break; if ( Dp->state == IF_STATE_UPSTREAM ) mrDesc.InVif = Ix; else if(BIT_TST(route->vifBits, Dp->index)) { mrDesc.TtlVc[ Ix ] = Dp->threshold; } } // Do the actual Kernel route update... if(activate) { // Add route in kernel... addMRoute( &mrDesc ); } else { // Delete the route from Kernel... delMRoute( &mrDesc ); } return 1; }
void sendJoinLeaveUpstream(struct RouteTable* route, int join) { struct IfDesc* upstrIf; // Get the upstream VIF... upstrIf = getIfByIx( upStreamVif ); if(upstrIf == NULL) { atlog(LOG_ERR, 0 ,"FATAL: Unable to get Upstream IF."); } // Send join or leave request... if(join) { // Only join a group if there are listeners downstream... if(route->vifBits > 0) { joinMcGroup( getMcGroupSock(), upstrIf, &route->group ); route->upstrState = ROUTESTATE_JOINED; } } else { // Only leave if group is not left already... if(route->upstrState != ROUTESTATE_NOTJOINED) { leaveMcGroup( getMcGroupSock(), upstrIf, &route->group ); route->upstrState = ROUTESTATE_NOTJOINED; } } }
/** * Internal function to send join or leave requests for * a specified route upstream... */ void sendJoinLeaveUpstream(struct RouteTable* route, int join) { struct IfDesc* upstrIf; // Get the upstream VIF... upstrIf = getIfByIx( upStreamVif ); if(upstrIf == NULL) { my_log(LOG_ERR, 0 ,"FATAL: Unable to get Upstream IF."); } // Check if there is a white list for the upstram VIF if (upstrIf->allowedgroups != NULL) { uint32_t group = route->group; struct SubnetList* sn; // Check if this Request is legit to be forwarded to upstream for(sn = upstrIf->allowedgroups; sn != NULL; sn = sn->next) if((group & sn->subnet_mask) == sn->subnet_addr) // Forward is OK... break; if (sn == NULL) { my_log(LOG_INFO, 0, "The group address %s may not be forwarded upstream. Ignoring.", inetFmt(group, s1)); return; } } // Send join or leave request... if(join) { // Only join a group if there are listeners downstream... if(route->vifBits > 0) { my_log(LOG_DEBUG, 0, "Joining group %s upstream on IF address %s", inetFmt(route->group, s1), inetFmt(upstrIf->InAdr.s_addr, s2)); //k_join(route->group, upstrIf->InAdr.s_addr); joinMcGroup( getMcGroupSock(), upstrIf, route->group ); route->upstrState = ROUTESTATE_JOINED; } else { my_log(LOG_DEBUG, 0, "No downstream listeners for group %s. No join sent.", inetFmt(route->group, s1)); } } else { // Only leave if group is not left already... if(route->upstrState != ROUTESTATE_NOTJOINED) { my_log(LOG_DEBUG, 0, "Leaving group %s upstream on IF address %s", inetFmt(route->group, s1), inetFmt(upstrIf->InAdr.s_addr, s2)); //k_leave(route->group, upstrIf->InAdr.s_addr); leaveMcGroup( getMcGroupSock(), upstrIf, route->group ); route->upstrState = ROUTESTATE_NOTJOINED; } } }
/** * Counts the number of interfaces a given route is active on */ int numberOfInterfaces(struct RouteTable *croute) { int Ix; struct IfDesc *Dp; int result = 0; // Loop through all interfaces for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) { // If the interface is used by the route, increase counter if(BIT_TST(croute->vifBits, Dp->index)) { result++; } } my_log(LOG_DEBUG, 0, "counted %d interfaces", result); return result; }
/** * Updates the Kernel routing table. If activate is 1, the route * is (re-)activated. If activate is false, the route is removed. */ int internUpdateKernelRoute(struct RouteTable *route, int activate) { struct MRouteDesc mrDesc; struct IfDesc *Dp; unsigned Ix; int i; for (int i = 0; i < MAX_ORIGINS; i++) { if (route->originAddrs[i] == 0 || route->upstrVif == -1) { continue; } // Build route descriptor from table entry... // Set the source address and group address... mrDesc.McAdr.s_addr = route->group; mrDesc.OriginAdr.s_addr = route->originAddrs[i]; // clear output interfaces memset( mrDesc.TtlVc, 0, sizeof( mrDesc.TtlVc ) ); my_log(LOG_DEBUG, 0, "Vif bits : 0x%08x", route->vifBits); mrDesc.InVif = route->upstrVif; // Set the TTL's for the route descriptor... for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) { if(Dp->state == IF_STATE_UPSTREAM) { continue; } else if(BIT_TST(route->vifBits, Dp->index)) { my_log(LOG_DEBUG, 0, "Setting TTL for Vif %d to %d", Dp->index, Dp->threshold); mrDesc.TtlVc[ Dp->index ] = Dp->threshold; } } // Do the actual Kernel route update... if(activate) { // Add route in kernel... addMRoute( &mrDesc ); } else { // Delete the route from Kernel... delMRoute( &mrDesc ); } } return 1; }
/** * Appends extra VIF configuration from config file. */ void configureVifs() { unsigned Ix; struct IfDesc *Dp; struct vifconfig *confPtr; // If no config is availible, just return... if(vifconf == NULL) { return; } // Loop through all VIFs... for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) { if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) { // Now try to find a matching config... for( confPtr = vifconf; confPtr; confPtr = confPtr->next) { // I the VIF names match... if(strcmp(Dp->Name, confPtr->name)==0) { struct SubnetList *vifLast; my_log(LOG_DEBUG, 0, "Found config for %s", Dp->Name); // Set the VIF state Dp->state = confPtr->state; Dp->threshold = confPtr->threshold; Dp->ratelimit = confPtr->ratelimit; // Go to last allowed net on VIF... for(vifLast = Dp->allowednets; vifLast->next; vifLast = vifLast->next); // Insert the configured nets... vifLast->next = confPtr->allowednets; Dp->allowedgroups = confPtr->allowedgroups; break; } } } } }
/** * 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); } }
/** * Initializes the routing table. */ void initRouteTable() { unsigned Ix; struct IfDesc *Dp; // Clear routing table... routing_table = NULL; // Join the all routers group on downstream vifs... for ( Ix = 0; (Dp = getIfByIx( Ix )); Ix++ ) { // If this is a downstream vif, we should join the All routers group... if( Dp->state == IF_STATE_DOWNSTREAM ) { /* IF_DEBUG atlog(LOG_DEBUG, 0, "Joining all-routers group %s on vif %s", inetFmt(allrouters_group,s1),inetFmt(Dp->InAdr.s_addr,s2)); */ //joinMcGroup( getMcGroupSock(), Dp, &allrouters_group ); } } }
/** * Initializes the routing table. */ void initRouteTable() { unsigned Ix; struct IfDesc *Dp; // Clear routing table... routing_table = NULL; // Join the all routers group on downstream vifs... for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) { // If this is a downstream vif, we should join the All routers group... if( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) && Dp->state == IF_STATE_DOWNSTREAM) { my_log(LOG_DEBUG, 0, "Joining all-routers group %s on vif %s", inetFmt(allrouters_group,s1),inetFmt(Dp->InAdr.s_addr,s2)); //k_join(allrouters_group, Dp->InAdr.s_addr); joinMcGroup( getMcGroupSock(), Dp, allrouters_group ); my_log(LOG_DEBUG, 0, "Joining all igmpv3 multicast routers group %s on vif %s", inetFmt(alligmp3_group,s1),inetFmt(Dp->InAdr.s_addr,s2)); joinMcGroup( getMcGroupSock(), Dp, alligmp3_group ); } } }
/** * Handles the initial startup of the daemon. */ int igmpProxyInit() { struct sigaction sa; int Err; sa.sa_handler = signalHandler; sa.sa_flags = 0; /* Interrupt system calls */ sigemptyset(&sa.sa_mask); sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); // Loads configuration for Physical interfaces... buildIfVc(); // Configures IF states and settings configureVifs(); switch ( Err = enableMRouter() ) { case 0: break; case EADDRINUSE: my_log( LOG_ERR, EADDRINUSE, "MC-Router API already in use" ); break; default: my_log( LOG_ERR, Err, "MRT_INIT failed" ); } /* create VIFs for all IP, non-loop interfaces */ { unsigned Ix; struct IfDesc *Dp; int vifcount = 0; upStreamVif = -1; for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) { if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) { if(Dp->state == IF_STATE_UPSTREAM) { if(upStreamVif == -1) { upStreamVif = Ix; } else { my_log(LOG_ERR, 0, "Vif #%d was already upstream. Cannot set VIF #%d as upstream as well.", upStreamVif, Ix); } } addVIF( Dp ); vifcount++; } } // If there is only one VIF, or no defined upstream VIF, we send an error. if(vifcount < 2 || upStreamVif < 0) { my_log(LOG_ERR, 0, "There must be at least 2 Vif's where one is upstream."); } } // Initialize IGMP initIgmp(); // Initialize Routing table initRouteTable(); // Initialize timer callout_init(); return 1; }
/** * Process a newly received IGMP packet that is sitting in the input * packet buffer. */ void acceptIgmp(int recvlen) { register uint32_t src, dst, group; struct ip *ip; struct igmp *igmp; struct igmpv3_report *igmpv3; struct igmpv3_grec *grec; int ipdatalen, iphdrlen, ngrec, nsrcs; if (recvlen < sizeof(struct ip)) { my_log(LOG_WARNING, 0, "received packet too short (%u bytes) for IP header", recvlen); return; } ip = (struct ip *)recv_buf; src = ip->ip_src.s_addr; dst = ip->ip_dst.s_addr; /* filter local multicast 239.255.255.250 */ if (dst == htonl(0xEFFFFFFA)) { my_log(LOG_NOTICE, 0, "The IGMP message was local multicast. Ignoring."); return; } /* * this is most likely a message from the kernel indicating that * a new src grp pair message has arrived and so, it would be * necessary to install a route into the kernel for this. */ if (ip->ip_p == 0) { if (src == 0 || dst == 0) { my_log(LOG_WARNING, 0, "kernel request not accurate"); } else { struct IfDesc *checkVIF; // Check if the source address matches a valid address on upstream vif. checkVIF = getIfByIx( upStreamVif ); if(checkVIF == 0) { my_log(LOG_ERR, 0, "Upstream VIF was null."); return; } else if(src == checkVIF->InAdr.s_addr) { my_log(LOG_NOTICE, 0, "Route activation request from %s for %s is from myself. Ignoring.", inetFmt(src, s1), inetFmt(dst, s2)); return; } else if(!isAdressValidForIf(checkVIF, src)) { my_log(LOG_WARNING, 0, "The source address %s for group %s, is not in any valid net for upstream VIF.", inetFmt(src, s1), inetFmt(dst, s2)); return; } // Activate the route. my_log(LOG_DEBUG, 0, "Route activate request from %s to %s", inetFmt(src,s1), inetFmt(dst,s2)); activateRoute(dst, src); } return; } iphdrlen = ip->ip_hl << 2; ipdatalen = ip_data_len(ip); if (iphdrlen + ipdatalen != recvlen) { my_log(LOG_WARNING, 0, "received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)", inetFmt(src, s1), recvlen, iphdrlen, ipdatalen); return; } igmp = (struct igmp *)(recv_buf + iphdrlen); if ((ipdatalen < IGMP_MINLEN) || (igmp->igmp_type == IGMP_V3_MEMBERSHIP_REPORT && ipdatalen <= IGMPV3_MINLEN)) { my_log(LOG_WARNING, 0, "received IP data field too short (%u bytes) for IGMP, from %s", ipdatalen, inetFmt(src, s1)); return; } my_log(LOG_NOTICE, 0, "RECV %s from %-15s to %s", igmpPacketKind(igmp->igmp_type, igmp->igmp_code), inetFmt(src, s1), inetFmt(dst, s2) ); switch (igmp->igmp_type) { case IGMP_V1_MEMBERSHIP_REPORT: case IGMP_V2_MEMBERSHIP_REPORT: group = igmp->igmp_group.s_addr; acceptGroupReport(src, group, igmp->igmp_type); return; case IGMP_V3_MEMBERSHIP_REPORT: igmpv3 = (struct igmpv3_report *)(recv_buf + iphdrlen); grec = &igmpv3->igmp_grec[0]; ngrec = ntohs(igmpv3->igmp_ngrec); while (ngrec--) { if ((uint8_t *)igmpv3 + ipdatalen < (uint8_t *)grec + sizeof(*grec)) break; group = grec->grec_mca.s_addr; nsrcs = ntohs(grec->grec_nsrcs); switch (grec->grec_type) { case IGMPV3_MODE_IS_INCLUDE: case IGMPV3_CHANGE_TO_INCLUDE: if (nsrcs == 0) { acceptLeaveMessage(src, group); break; } /* else fall through */ case IGMPV3_MODE_IS_EXCLUDE: case IGMPV3_CHANGE_TO_EXCLUDE: case IGMPV3_ALLOW_NEW_SOURCES: acceptGroupReport(src, group, IGMP_V2_MEMBERSHIP_REPORT); break; case IGMPV3_BLOCK_OLD_SOURCES: break; default: my_log(LOG_INFO, 0, "ignoring unknown IGMPv3 group record type %x from %s to %s for %s", grec->grec_type, inetFmt(src, s1), inetFmt(dst, s2), inetFmt(group, s3)); break; } grec = (struct igmpv3_grec *) (&grec->grec_src[nsrcs] + grec->grec_auxwords * 4); } return; case IGMP_V2_LEAVE_GROUP: group = igmp->igmp_group.s_addr; acceptLeaveMessage(src, group); return; case IGMP_MEMBERSHIP_QUERY: return; default: my_log(LOG_INFO, 0, "ignoring unknown IGMP message type %x from %s to %s", igmp->igmp_type, inetFmt(src, s1), inetFmt(dst, s2)); return; } }
/** * Process a newly received IGMP packet that is sitting in the input * packet buffer. */ void acceptIgmp(int recvlen) { register uint32_t src, dst, group; struct ip *ip; struct igmp *igmp; int ipdatalen, iphdrlen, igmpdatalen; if (recvlen < sizeof(struct ip)) { my_log(LOG_WARNING, 0, "received packet too short (%u bytes) for IP header", recvlen); return; } ip = (struct ip *)recv_buf; src = ip->ip_src.s_addr; dst = ip->ip_dst.s_addr; /* * this is most likely a message from the kernel indicating that * a new src grp pair message has arrived and so, it would be * necessary to install a route into the kernel for this. */ if (ip->ip_p == 0) { if (src == 0 || dst == 0) { my_log(LOG_WARNING, 0, "kernel request not accurate"); } else { struct IfDesc *checkVIF; // Check if the source address matches a valid address on upstream vif. checkVIF = getIfByIx( upStreamVif ); if(checkVIF == 0) { my_log(LOG_ERR, 0, "Upstream VIF was null."); return; } else if(src == checkVIF->InAdr.s_addr) { my_log(LOG_NOTICE, 0, "Route activation request from %s for %s is from myself. Ignoring.", inetFmt(src, s1), inetFmt(dst, s2)); return; } /* else if(!isAdressValidForIf(checkVIF, src)) { my_log(LOG_WARNING, 0, "The source address %s for group %s, is not in any valid net for upstream VIF.", inetFmt(src, s1), inetFmt(dst, s2)); return; }*/ // Activate the route. my_log(LOG_DEBUG, 0, "Route activate request from %s to %s", inetFmt(src,s1), inetFmt(dst,s2)); activateRoute(dst, src); } return; } iphdrlen = ip->ip_hl << 2; ipdatalen = ip_data_len(ip); if (iphdrlen + ipdatalen != recvlen) { my_log(LOG_WARNING, 0, "received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)", inetFmt(src, s1), recvlen, iphdrlen, ipdatalen); return; } igmp = (struct igmp *)(recv_buf + iphdrlen); group = igmp->igmp_group.s_addr; igmpdatalen = ipdatalen - IGMP_MINLEN; if (igmpdatalen < 0) { my_log(LOG_WARNING, 0, "received IP data field too short (%u bytes) for IGMP, from %s", ipdatalen, inetFmt(src, s1)); return; } my_log(LOG_NOTICE, 0, "RECV %s from %-15s to %s", igmpPacketKind(igmp->igmp_type, igmp->igmp_code), inetFmt(src, s1), inetFmt(dst, s2) ); switch (igmp->igmp_type) { case IGMP_V1_MEMBERSHIP_REPORT: case IGMP_V2_MEMBERSHIP_REPORT: acceptGroupReport(src, group, igmp->igmp_type); return; case IGMP_V2_LEAVE_GROUP: acceptLeaveMessage(src, group); return; case IGMP_MEMBERSHIP_QUERY: return; default: my_log(LOG_INFO, 0, "ignoring unknown IGMP message type %x from %s to %s", igmp->igmp_type, inetFmt(src, s1), inetFmt(dst, s2)); return; } }
/** * Process a newly received IGMP packet that is sitting in the input * packet buffer. */ void acceptIgmp(int recvlen) { register uint32 src, dst, group; struct ip *ip; struct igmp *igmp; int ipdatalen, iphdrlen, igmpdatalen; if (recvlen < sizeof(struct ip)) { log_msg(LOG_WARNING, 0, "received packet too short (%u bytes) for IP header", recvlen); return; } ip = (struct ip *)recv_buf; src = ip->ip_src.s_addr; dst = ip->ip_dst.s_addr; //IF_DEBUG log_msg(LOG_DEBUG, 0, "Got a IGMP request to process..."); /* * this is most likely a message from the kernel indicating that * a new src grp pair message has arrived and so, it would be * necessary to install a route into the kernel for this. */ if (ip->ip_p == 0) { if (src == 0 || dst == 0) { log_msg(LOG_WARNING, 0, "kernel request not accurate"); } else { #if 0 /*remove for cd-router test wan remoteHostIp is different subnet with wan mask*/ struct IfDesc *checkVIF; // Check if the source address matches a valid address on upstream vif. checkVIF = getIfByIx( upStreamVif ); if(checkVIF == 0) { log_msg(LOG_ERR, 0, "Upstream VIF was null."); return; } else if(src == checkVIF->InAdr.s_addr) { log_msg(LOG_NOTICE, 0, "Route activation request from %s for %s is from myself. Ignoring.", inetFmt(src, s1), inetFmt(dst, s2)); return; } else if(!isAdressValidForIf(checkVIF, src)) { log_msg(LOG_WARNING, 0, "The source address %s for group %s, is not in any valid net for upstream VIF.", inetFmt(src, s1), inetFmt(dst, s2)); return; } #else if ((dst & LOCAL_PRIVATE_NETMASK) == LOCAL_PRIVATE_NETMASK){ IF_DEBUG log_msg(LOG_DEBUG, 0, "Got private dst multicast address %s passthrough return ", inetFmt(dst,s2)); return; } #endif // Activate the route. IF_DEBUG log_msg(LOG_DEBUG, 0, "Route activate request from %s to %s", inetFmt(src,s1), inetFmt(dst,s2)); activateRoute(dst, src); } return; } iphdrlen = ip->ip_hl << 2; ipdatalen = ntohs(ip->ip_len) - iphdrlen; if (iphdrlen + ipdatalen != recvlen) { log_msg(LOG_WARNING, 0, "received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)", inetFmt(src, s1), recvlen, iphdrlen, ipdatalen); return; } igmp = (struct igmp *)(recv_buf + iphdrlen); group = igmp->igmp_group.s_addr; igmpdatalen = ipdatalen - IGMP_MINLEN; if (igmpdatalen < 0) { log_msg(LOG_WARNING, 0, "received IP data field too short (%u bytes) for IGMP, from %s", ipdatalen, inetFmt(src, s1)); return; } log_msg(LOG_NOTICE, 0, "RECV %s from %-15s to %s", igmpPacketKind(igmp->igmp_type, igmp->igmp_code), inetFmt(src, s1), inetFmt(dst, s2) ); switch (igmp->igmp_type) { case IGMP_V1_MEMBERSHIP_REPORT: case IGMP_V2_MEMBERSHIP_REPORT: acceptGroupReport(src, group, igmp->igmp_type); return; case IGMP_V2_LEAVE_GROUP: acceptLeaveMessage(src, group); return; /* case IGMP_MEMBERSHIP_QUERY: //accept_membership_query(src, dst, group, igmp->igmp_code); return; */ default: log_msg(LOG_INFO, 0, "ignoring unknown IGMP message type %x from %s to %s", igmp->igmp_type, inetFmt(src, s1), inetFmt(dst, s2)); return; } }
/** * 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; newroute->upstrVif = -1; // 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 struct IfDesc* downstrIf; downstrIf = getIfByIx(ifx); sendJoinLeaveUpstream(croute, 1); } logRouteTable("Insert Route"); return 1; }