NetSim Source Code Help v14.4
All 13 Components
 
Loading...
Searching...
No Matches
IGMP_Router.c
1/************************************************************************************
2* Copyright (C) 2023 *
3* TETCOS, Bangalore. India *
4* *
5* Tetcos owns the intellectual property rights in the Product and its content. *
6* The copying, redistribution, reselling or publication of any or all of the *
7* Product or its content without express prior written consent of Tetcos is *
8* prohibited. Ownership and / or any other right relating to the software and all *
9* intellectual property rights therein shall remain at all times with Tetcos. *
10* *
11* Author: Shashi Kant Suman *
12* *
13* ---------------------------------------------------------------------------------*/
14
15#include "main.h"
16#include "List.h"
17#include "IP.h"
18#include "IGMP.h"
19
20ptrIGMP_ROUTER_DB find_or_alloc_multicast_db_router(NETSIM_IPAddress addr,
21 NETSIM_ID d,
22 bool* isAlreadyJoined)
23{
24 ptrIGMP_ROUTER_DB r = GET_IGMP_ROUTER(d)->database;
25
26 while (r)
27 {
28 if (!IP_COMPARE(r->group, addr))
29 {
30 *isAlreadyJoined = true;
31 return r;
32 }
33 r = LIST_NEXT(r);
34 }
35
36 *isAlreadyJoined = false;
37 r = (ptrIGMP_ROUTER_DB)IGMP_ROUTER_DB_ALLOC();
38 r->group = IP_COPY(addr);
39 r->state = RouterState_Querier;
40
41 IGMP_ROUTER_DB_ADD(d, r);
42
43 return r;
44}
45
46static ptrIGMP_ROUTER_DB router_join_multicast_group(NETSIM_ID d, NETSIM_IPAddress group)
47{
48 bool isAlreadyJoined = false;
49 ptrIGMP_ROUTER router = GET_IGMP_ROUTER(d);
50 ptrIGMP_ROUTER_DB db = find_or_alloc_multicast_db_router(group, d, &isAlreadyJoined);
51 if (!isAlreadyJoined)
52 {
53 print_igmp_log("Calling PIM to join group %s", group->str_ip);
54 pim_join_group(d, group);
55 }
56 return db;
57}
58
59ptrIGMP_ROUTER_DB router_get_multicast_db(NETSIM_ID d,
60 NETSIM_IPAddress ip)
61{
62 ptrIGMP_ROUTER_DB db = GET_IGMP_ROUTER(d)->database;
63 while (db)
64 {
65 if (!IP_COMPARE(db->group, ip))
66 return db;
67 db = LIST_NEXT(db);
68 }
69 return NULL;
70}
71
72static void router_delete_multicast_db(NETSIM_ID d,
73 ptrIGMP_ROUTER_DB db)
74{
75 LIST_FREE(&GET_IGMP_ROUTER(d)->database, db);
76}
77
78static bool isBroadcastInterfacePresent(NETSIM_ID d)
79{
80 NETSIM_ID i;
81 for (i = 0; i < DEVICE(d)->nNumOfInterface; i++)
82 {
83 if (isBroadcastInterface(d, i + 1))
84 {
85 return true;
86 }
87 }
88 return false;
89}
90
91static bool isInterfacePresentInDatabase(ptrIGMP_ROUTER_DB db,
92 NETSIM_ID ifid)
93{
94 UINT i;
95 for (i = 0; i < db->count; i++)
96 if (db->ifids[i] == ifid)
97 return true;
98 return false;
99}
100
101static bool isOtherInterfacePresentInDatabase(ptrIGMP_ROUTER_DB db,
102 NETSIM_ID ifid)
103{
104 UINT i;
105 for (i = 0; i < db->count; i++)
106 if (db->ifids[i] != ifid)
107 return true;
108 return false;
109}
110
111static void router_add_ip_route(ptrIGMP_ROUTER_DB db,
112 NETSIM_ID d,
113 NETSIM_ID ifid)
114{
115 if (db->isRouteAlreadyAdded)
116 {
117 UINT c = db->count;
118 db->count++;
119 db->ifids = realloc(db->ifids, db->count * sizeof* db->ifids);
120 db->ifids[c] = ifid;
121
122 NETSIM_IPAddress* ip = calloc(db->count, sizeof* ip);
123 UINT i;
124 for (i = 0; i < db->count; i++)
125 ip[i] = DEVICE_NWADDRESS(d, db->ifids[i]);
126
127 iptable_change(IP_WRAPPER_GET(d),
128 db->group,
129 STR_TO_IP4("255.255.255.255"),
130 0,
131 db->group,
132 db->count,
133 ip,
134 db->ifids,
135 330);
136
137 free(ip);
138 }
139 else
140 {
141 iptable_add(IP_WRAPPER_GET(d),
142 db->group,
143 STR_TO_IP4("255.255.255.255"),
144 0,
145 db->group,
146 1,
147 &DEVICE_NWADDRESS(d, ifid),
148 &ifid,
149 330,
150 "Multicast");
151 db->isRouteAlreadyAdded = true;
152 db->ifids = (NETSIM_ID*)calloc(1, sizeof* db->ifids);
153 db->ifids[0] = ifid;
154 db->count = 1;
155 }
156}
157
158void igmp_router_init(NETSIM_ID d)
159{
160 ptrIGMP_VAR var = GET_IGMP_VAR(d);
161
162 var->StartupQueryInterval = var->QueryInterval / 4;
163
164 var->StartupQueryCount = var->RobustnessVar;
165
166 if (isBroadcastInterfacePresent(d))
167 {
168 NETSIM_IPAddress g = STR_TO_IP4("224.0.0.1");
169
170 print_igmp_log("\nRouter %d, Time 0.0: Joining multicast group %s.",
171 d,
172 g->str_ip);
173 print_igmp_log("Sending query msg after %0.0lf.",(double)IGMP_STARTUP_DELAY);
174
175 router_join_multicast_group(d, g);
176 send_query_msg(d, g, IGMP_STARTUP_DELAY);
177 }
178}
179
180IP_PROTOCOL_ACTION router_is_ip_present_in_db(NETSIM_ID d, NETSIM_IPAddress ip, NetSim_PACKET* packet)
181{
182 ptrIGMP_ROUTER_DB db = GET_IGMP_ROUTER(d)->database;
183 while (db)
184 {
185 if (!IP_COMPARE(db->group, ip))
186 {
187 if (!isInterfacePresentInDatabase(db, pstruEventDetails->nInterfaceId))
188 return ACTION_DROP;
189
190 if (isOtherInterfacePresentInDatabase(db, pstruEventDetails->nInterfaceId))
191 return ACTION_REROUTE;
192 else
193 return ACTION_DROP;
194 }
195 db = LIST_NEXT(db);
196 }
197 return ACTION_DROP;
198}
199
200bool router_process_query(NetSim_PACKET* packet, ptrIGMP_MSG msg, NETSIM_ID d)
201{
202 ptrIGMP_ROUTER r = GET_IGMP_ROUTER(d);
203
204 NETSIM_IPAddress src = packet->pstruNetworkData->szSourceIP;
205
206 if (isIPForSameDevice(src, d))
207 return false; // No processing required
208
209 print_igmp_log("\nRouter %d, Time %0.0lf: Query received for group address %s.",
210 d,
211 pstruEventDetails->dEventTime,
212 msg->GroupAddress->str_ip);
213
214 NETSIM_IPAddress same = get_ip_from_same_subnet(d, src);
215
216 if (same->int_ip[0] > src->int_ip[0])
217 {
218 print_igmp_log("Received from lower ip address %s. Changing state to NonQuerier",
219 src->str_ip);
220
221 ptrIGMP_ROUTER_DB db = router_get_multicast_db(d, msg->GroupAddress);
222 db->state = RouterState_NonQuerier;
223 db->otherQuerierPresentTime = pstruEventDetails->dEventTime;
224
225 if (!db->isOtherquerierTimerStarted)
226 {
227 print_igmp_log("Starting Other querier present timer");
228 db->isOtherquerierTimerStarted = true;
229 igmp_start_timer(d,
230 EVENT_IGMP_OtherQuerierPresentTimer,
231 msg->GroupAddress,
232 pstruEventDetails->dEventTime);
233 }
234 }
235
236 return false;
237}
238
239void igmp_router_processOtherQuerierPresentTime()
240{
241 ptrIGMP_VAR igmp = GET_IGMP_VAR(pstruEventDetails->nDeviceId);
242 ptrIGMP_ROUTER_DB db = router_get_multicast_db(pstruEventDetails->nDeviceId,
243 pstruEventDetails->szOtherDetails);
244
245 if (pstruEventDetails->dEventTime >=
246 db->otherQuerierPresentTime +
247 igmp->QueryPresentInterval*0.1*SECOND)
248 {
249 // Start as querier
250 print_igmp_log("\nRouter %d, Time %0.0lf: Other querier present timer expire for group address %s. Starting as querier.",
251 pstruEventDetails->nDeviceId,
252 pstruEventDetails->dEventTime,
253 db->group->str_ip);
254
255 db->state = RouterState_Querier;
256 send_query_msg(pstruEventDetails->nDeviceId,
257 db->group,
258 pstruEventDetails->dEventTime);
259 }
260 else
261 {
262 //Keep checking
263 print_igmp_log("\nRouter %d, Time %0.0lf: Query is already received for group address %s. Continuing as Non querier.",
264 pstruEventDetails->nDeviceId,
265 pstruEventDetails->dEventTime,
266 db->group->str_ip);
267
268 pstruEventDetails->dEventTime = db->otherQuerierPresentTime +
269 igmp->QueryPresentInterval;
270 fnpAddEvent(pstruEventDetails);
271 }
272}
273
274bool router_process_report(NetSim_PACKET* packet,
275 ptrIGMP_MSG msg,
276 NETSIM_ID d)
277{
278 print_igmp_log("\nRouter %d, Time %0.0lf: Report received for group address %s.",
279 d,
280 pstruEventDetails->dEventTime,
281 msg->GroupAddress->str_ip);
282
283 ptrIGMP_ROUTER_DB r = router_join_multicast_group(d, msg->GroupAddress);
284
285 r->reportRcvTime = pstruEventDetails->dEventTime;
286
287 if (!r->isGroupMembershipTimerStarted)
288 {
289 print_igmp_log("Router %d, Time %0.0lf: Starting group membership timer for group addr %s",
290 d,
291 pstruEventDetails->dEventTime,
292 msg->GroupAddress->str_ip);
293 igmp_start_timer(d,
294 EVENT_IGMP_GroupMembershipTimer,
295 msg->GroupAddress,
296 pstruEventDetails->dEventTime);
297 r->isGroupMembershipTimerStarted = true;
298 print_igmp_log("Starting query msg");
299 send_query_msg(d, msg->GroupAddress, pstruEventDetails->dEventTime);
300 }
301 if(!isInterfacePresentInDatabase(r,pstruEventDetails->nInterfaceId))
302 router_add_ip_route(r, d, pstruEventDetails->nInterfaceId);
303
304 return false;
305}
306
307void igmp_router_ProcessGroupMembershipTimer()
308{
309 NETSIM_ID d = pstruEventDetails->nDeviceId;
310 NETSIM_IPAddress group = pstruEventDetails->szOtherDetails;
311
312 ptrIGMP_VAR igmp = GET_IGMP_VAR(d);
313
314 ptrIGMP_ROUTER_DB db = router_get_multicast_db(d, group);
315
316 if (pstruEventDetails->dEventTime >=
317 db->reportRcvTime +
318 igmp->GroupMembershipInterval*0.1*SECOND)
319 {
320 // No member on this group.
321 print_igmp_log("\nRouter %d, Time %0.0lf: Group membership timer expires for group addr %s. Deleting from database.",
322 d,
323 pstruEventDetails->dEventTime,
324 group->str_ip);
325 router_delete_multicast_db(d, db);
326 }
327 else
328 {
329 //Keep checking
330 print_igmp_log("\nRouter %d, Time %0.0lf: Refreshing Group membership timer for group addr %s.",
331 d,
332 pstruEventDetails->dEventTime,
333 group->str_ip);
334
335 pstruEventDetails->dEventTime = db->reportRcvTime +
336 igmp->GroupMembershipInterval*0.1*SECOND;
337 fnpAddEvent(pstruEventDetails);
338 }
339}
340
341void router_free(NETSIM_ID d)
342{
343 ptrIGMP_ROUTER r = GET_IGMP_ROUTER(d);
344 ptrIGMP_ROUTER_DB db = r->database;
345 while (db)
346 {
347 LIST_FREE(&db, db);
348 }
349 free(r);
350 SET_IGMP_ROUTER(d, NULL);
351}