Changes to update Tomato RAF.
[tomato.git] / release / src / router / igmpproxy / src / request.c
blob22b9c30bb9aecf95cd6124c56436a5ca5aa9b234
1 /*
2 ** igmpproxy - IGMP proxy based multicast router
3 ** Copyright (C) 2005 Johnny Egeland <johnny@rlo.org>
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 **----------------------------------------------------------------------------
21 ** This software is derived work from the following software. The original
22 ** source code has been modified from it's original state by the author
23 ** of igmpproxy.
25 ** smcroute 0.92 - Copyright (C) 2001 Carsten Schill <carsten@cschill.de>
26 ** - Licensed under the GNU General Public License, version 2
27 **
28 ** mrouted 3.9-beta3 - COPYRIGHT 1989 by The Board of Trustees of
29 ** Leland Stanford Junior University.
30 ** - Original license can be found in the Stanford.txt file.
33 /**
34 * request.c
36 * Functions for recieveing and processing IGMP requests.
40 #include "igmpproxy.h"
42 // Prototypes...
43 void sendGroupSpecificMemberQuery(void *argument);
45 typedef struct {
46 uint32_t group;
47 uint32_t vifAddr;
48 short started;
49 } GroupVifDesc;
52 /**
53 * Handles incoming membership reports, and
54 * appends them to the routing table.
56 void acceptGroupReport(uint32_t src, uint32_t group, uint8_t type) {
57 struct IfDesc *sourceVif;
59 // Sanitycheck the group adress...
60 if(!IN_MULTICAST( ntohl(group) )) {
61 my_log(LOG_WARNING, 0, "The group address %s is not a valid Multicast group.",
62 inetFmt(group, s1));
63 return;
66 // Find the interface on which the report was recieved.
67 sourceVif = getIfByAddress( src );
68 if(sourceVif == NULL) {
69 my_log(LOG_WARNING, 0, "No interfaces found for source %s",
70 inetFmt(src,s1));
71 return;
74 if(sourceVif->InAdr.s_addr == src) {
75 my_log(LOG_NOTICE, 0, "The IGMP message was from myself. Ignoring.");
76 return;
79 // We have a IF so check that it's an downstream IF.
80 if(sourceVif->state == IF_STATE_DOWNSTREAM) {
82 my_log(LOG_DEBUG, 0, "Should insert group %s (from: %s) to route table. Vif Ix : %d",
83 inetFmt(group,s1), inetFmt(src,s2), sourceVif->index);
85 // If we don't have a whitelist we insertRoute and done
86 if(sourceVif->allowedgroups == NULL)
88 insertRoute(group, sourceVif->index);
89 return;
91 // Check if this Request is legit on this interface
92 struct SubnetList *sn;
93 for(sn = sourceVif->allowedgroups; sn != NULL; sn = sn->next)
94 if((group & sn->subnet_mask) == sn->subnet_addr)
96 // The membership report was OK... Insert it into the route table..
97 insertRoute(group, sourceVif->index);
98 return;
100 my_log(LOG_INFO, 0, "The group address %s may not be requested from this interface. Ignoring.", inetFmt(group, s1));
101 } else {
102 // Log the state of the interface the report was recieved on.
103 my_log(LOG_INFO, 0, "Membership report was recieved on %s. Ignoring.",
104 sourceVif->state==IF_STATE_UPSTREAM?"the upstream interface":"a disabled interface");
110 * Recieves and handles a group leave message.
112 void acceptLeaveMessage(uint32_t src, uint32_t group) {
113 struct IfDesc *sourceVif;
115 my_log(LOG_DEBUG, 0,
116 "Got leave message from %s to %s. Starting last member detection.",
117 inetFmt(src, s1), inetFmt(group, s2));
119 // Sanitycheck the group adress...
120 if(!IN_MULTICAST( ntohl(group) )) {
121 my_log(LOG_WARNING, 0, "The group address %s is not a valid Multicast group.",
122 inetFmt(group, s1));
123 return;
126 // Find the interface on which the report was recieved.
127 sourceVif = getIfByAddress( src );
128 if(sourceVif == NULL) {
129 my_log(LOG_WARNING, 0, "No interfaces found for source %s",
130 inetFmt(src,s1));
131 return;
134 // We have a IF so check that it's an downstream IF.
135 if(sourceVif->state == IF_STATE_DOWNSTREAM) {
137 GroupVifDesc *gvDesc;
138 gvDesc = (GroupVifDesc*) malloc(sizeof(GroupVifDesc));
140 // Tell the route table that we are checking for remaining members...
141 setRouteLastMemberMode(group);
143 // Call the group spesific membership querier...
144 gvDesc->group = group;
145 gvDesc->vifAddr = sourceVif->InAdr.s_addr;
146 gvDesc->started = 0;
148 sendGroupSpecificMemberQuery(gvDesc);
150 } else {
151 // just ignore the leave request...
152 my_log(LOG_DEBUG, 0, "The found if for %s was not downstream. Ignoring leave request.", inetFmt(src, s1));
157 * Sends a group specific member report query until the
158 * group times out...
160 void sendGroupSpecificMemberQuery(void *argument) {
161 struct Config *conf = getCommonConfig();
163 // Cast argument to correct type...
164 GroupVifDesc *gvDesc = (GroupVifDesc*) argument;
166 if(gvDesc->started) {
167 // If aging returns false, we don't do any further action...
168 if(!lastMemberGroupAge(gvDesc->group)) {
169 return;
171 } else {
172 gvDesc->started = 1;
175 // Send a group specific membership query...
176 sendIgmp(gvDesc->vifAddr, gvDesc->group,
177 IGMP_MEMBERSHIP_QUERY,
178 conf->lastMemberQueryInterval * IGMP_TIMER_SCALE,
179 gvDesc->group, 0);
181 my_log(LOG_DEBUG, 0, "Sent membership query from %s to %s. Delay: %d",
182 inetFmt(gvDesc->vifAddr,s1), inetFmt(gvDesc->group,s2),
183 conf->lastMemberQueryInterval);
185 // Set timeout for next round...
186 timer_setTimer(conf->lastMemberQueryInterval, sendGroupSpecificMemberQuery, gvDesc);
192 * Sends a general membership query on downstream VIFs
194 void sendGeneralMembershipQuery() {
195 struct Config *conf = getCommonConfig();
196 struct IfDesc *Dp;
197 int Ix;
199 // Loop through all downstream vifs...
200 for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) {
201 if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) {
202 if(Dp->state == IF_STATE_DOWNSTREAM) {
203 // Send the membership query...
204 sendIgmp(Dp->InAdr.s_addr, allhosts_group,
205 IGMP_MEMBERSHIP_QUERY,
206 conf->queryResponseInterval * IGMP_TIMER_SCALE, 0, 0);
208 my_log(LOG_DEBUG, 0,
209 "Sent membership query from %s to %s. Delay: %d",
210 inetFmt(Dp->InAdr.s_addr,s1),
211 inetFmt(allhosts_group,s2),
212 conf->queryResponseInterval);
217 // Install timer for aging active routes.
218 timer_setTimer(conf->queryResponseInterval, ageActiveRoutes, NULL);
220 // Install timer for next general query...
221 if(conf->startupQueryCount>0) {
222 // Use quick timer...
223 timer_setTimer(conf->startupQueryInterval, sendGeneralMembershipQuery, NULL);
224 // Decrease startup counter...
225 conf->startupQueryCount--;
227 else {
228 // Use slow timer...
229 timer_setTimer(conf->queryInterval, sendGeneralMembershipQuery, NULL);