/** * Handles incoming membership reports, and * appends them to the routing table. */ void acceptGroupReport(uint32_t src, uint32_t group, uint8_t type) { struct IfDesc *sourceVif; // Sanitycheck the group adress... if(!IN_MULTICAST( ntohl(group) )) { my_log(LOG_WARNING, 0, "The group address %s is not a valid Multicast group.", inetFmt(group, s1)); return; } // Find the interface on which the report was recieved. sourceVif = getIfByAddress( src ); if(sourceVif == NULL) { my_log(LOG_WARNING, 0, "No interfaces found for source %s", inetFmt(src,s1)); return; } if(sourceVif->InAdr.s_addr == src) { my_log(LOG_NOTICE, 0, "The IGMP message was from myself. Ignoring."); return; } // We have a IF so check that it's an downstream IF. if(sourceVif->state == IF_STATE_DOWNSTREAM) { my_log(LOG_DEBUG, 0, "Should insert group %s (from: %s) to route table. Vif Ix : %d", inetFmt(group,s1), inetFmt(src,s2), sourceVif->index); // If we don't have a whitelist we insertRoute and done if(sourceVif->allowedgroups == NULL) { #ifdef RALINK_ESW_SUPPORT insert_multicast_ip(ntohl(group), ntohl(src)); #endif insertRoute(group, sourceVif->index); return; } // Check if this Request is legit on this interface struct SubnetList *sn; for(sn = sourceVif->allowedgroups; sn != NULL; sn = sn->next) if((group & sn->subnet_mask) == sn->subnet_addr) { #ifdef RALINK_ESW_SUPPORT insert_multicast_ip(ntohl(group), ntohl(src)); #endif // The membership report was OK... Insert it into the route table.. insertRoute(group, sourceVif->index); return; } my_log(LOG_INFO, 0, "The group address %s may not be requested from this interface. Ignoring.", inetFmt(group, s1)); } else { // Log the state of the interface the report was recieved on. my_log(LOG_INFO, 0, "Mebership report was recieved on %s. Ignoring.", sourceVif->state==IF_STATE_UPSTREAM?"the upstream interface":"a disabled interface"); } }
/** * Recieves and handles a group leave message. */ void acceptLeaveMessage(uint32_t src, uint32_t group) { struct IfDesc *sourceVif; my_log(LOG_DEBUG, 0, "Got leave message from %s to %s. Starting last member detection.", inetFmt(src, s1), inetFmt(group, s2)); // Sanitycheck the group adress... if(!IN_MULTICAST( ntohl(group) )) { my_log(LOG_WARNING, 0, "The group address %s is not a valid Multicast group.", inetFmt(group, s1)); return; } // Find the interface on which the report was recieved. sourceVif = getIfByAddress( src ); if(sourceVif == NULL) { my_log(LOG_WARNING, 0, "No interfaces found for source %s", inetFmt(src,s1)); return; } // We have a IF so check that it's an downstream IF. if(sourceVif->state == IF_STATE_DOWNSTREAM) { GroupVifDesc *gvDesc; gvDesc = (GroupVifDesc*) malloc(sizeof(GroupVifDesc)); // Tell the route table that we are checking for remaining members... setRouteLastMemberMode(group); // Call the group spesific membership querier... gvDesc->group = group; gvDesc->vifAddr = sourceVif->InAdr.s_addr; gvDesc->started = 0; sendGroupSpecificMemberQuery(gvDesc); #ifdef RALINK_ESW_SUPPORT remove_member(ntohl(group), ntohl(src)); #endif } else { // just ignore the leave request... my_log(LOG_DEBUG, 0, "The found if for %s was not downstream. Ignoring leave request.", inetFmt(src, s1)); } }
/** * Handles incoming membership reports, and * appends them to the routing table. */ void acceptGroupReport(uint32_t src, uint32_t group, uint8_t type) { struct IfDesc *sourceVif; // Sanitycheck the group adress... if(!IN_MULTICAST( ntohl(group) )) { my_log(LOG_WARNING, 0, "The group address %s is not a valid Multicast group.", inetFmt(group, s1)); return; } // Find the interface on which the report was recieved. sourceVif = getIfByAddress( src ); if(sourceVif == NULL) { my_log(LOG_WARNING, 0, "No interfaces found for source %s", inetFmt(src,s1)); return; } if(sourceVif->InAdr.s_addr == src) { my_log(LOG_NOTICE, 0, "The IGMP message was from myself. Ignoring."); return; } // We have a IF so check that it's an downstream IF. if(sourceVif->state == IF_STATE_DOWNSTREAM) { my_log(LOG_DEBUG, 0, "Should insert group %s (from: %s) to route table. Vif Ix : %d", inetFmt(group,s1), inetFmt(src,s2), sourceVif->index); // The membership report was OK... Insert it into the route table.. insertRoute(group, sourceVif->index); } else { // Log the state of the interface the report was recieved on. my_log(LOG_INFO, 0, "Membership report was recieved on %s. Ignoring.", sourceVif->state==IF_STATE_UPSTREAM?"the upstream interface":"a disabled interface"); } }
/** * Accept a V3 Membership Report */ void acceptV3GroupReport(uint32_t src, uint8_t type, struct igmpv3_groupreport* igmpv3rep) { struct IfDesc *sourceVif; // Sanitycheck the group adress... if(!IN_MULTICAST( ntohl(group) )) { my_log(LOG_WARNING, 0, "The group address %s is not a valid Multicast group.", inetFmt(group, s1)); return; } // Find the interface on which the report was recieved. sourceVif = getIfByAddress( src ); if(sourceVif == NULL) { my_log(LOG_WARNING, 0, "No interfaces found for source %s", inetFmt(src,s1)); return; } if(sourceVif->InAdr.s_addr == src) { my_log(LOG_NOTICE, 0, "The IGMP message was from myself. Ignoring."); return; } // We have a IF so check that it's an downstream IF. if(sourceVif->state != IF_STATE_DOWNSTREAM) { // Log the state of the interface the report was recieved on. my_log(LOG_INFO, 0, "Membership report was recieved on %s. Ignoring.", sourceVif->state==IF_STATE_UPSTREAM?"the upstream interface":"a disabled interface"); } else { my_log(LOG_DEBUG, 0, "IGMPv3 Membership Report") // TODO: Can we batch-report here? uint16_t num_entries = ntohl(igmpv3rep->num_entries); uint16_t eix = 0; while ( eix < num_entries ) { struct igmpv3_groupreport_entry* e = (struct igmpv3_groupreport_entry* igmpv3rep->grec) + eix; uint16_t num_sources = ntohl(e->nsrcs); uint16_t six = 0; while ( six < num_sources ) { uint32_t* srcgroup = (uint32_t* e->sources) + six; group = ntohl(*srcgroup); switch ( e->type == 0x0 ) { case IGMPV3_GRE_MODE_INCLUDE: case IGMPV3_GRE_CHMODE_INCLUDE: case IGMPV3_GRE_ALLOW_NEW_SOURCES: my_log(LOG_DEBUG, 0, "IGMPv3 Subscribe to %s.", inetFmt(group, s1)); insertRoute(group, sourceVif->index); break; case IGMPV3_GRE_MODE_EXCLUDE: case IGMPV3_GRE_CHMODE_EXCLUDE: case IGMPV3_GRE_BLOCK_OLD_SOURCES: my_log(LOG_DEBUG, 0, "IGMPv3 Unsubscribe from %s.", inetFmt(group, s1)); deleteRoute(group, sourceVif->index); break; default: my_log(LOG_INFO, 0, "Membership V3 group report received with unknown type %d.", e->type); } }; eix++; }; 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; /* 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_WARNING, 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)) { struct IfDesc *downVIF = getIfByAddress(src); if (downVIF && downVIF->state & IF_STATE_DOWNSTREAM) { my_log(LOG_NOTICE, 0, "The source address %s for group %s is from downstream VIF. Ignoring.", inetFmt(src, s1), inetFmt(dst, s2)); } else { 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; } }