]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_igmp.c
sync comments, fix function header, rename variable name to follow coding style.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / PxeBcDxe / Pxe_bc_igmp.c
1 /** @file
2
3 Copyright (c) 2004, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12
13 **/
14
15
16 #define RAND_MAX 0x10000
17
18 #include "Bc.h"
19
20 //
21 // Definitions for internet group management protocol version 2 message
22 // structure Per RFC 2236, November 1997
23 //
24 UINT8 RouterAlertOption[4] = { 0x80 | 20, 4, 0, 0 };
25 IPV4_ADDR AllRoutersGroup = { { 224, 0, 0, 2 } };
26
27 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
28 VOID
29 ClearGroupTimer (
30 PXE_BASECODE_DEVICE *Private,
31 UINTN TimerId
32 )
33 {
34 if (Private == NULL) {
35 return ;
36 }
37
38 if (TimerId >= Private->MCastGroupCount) {
39 return ;
40 }
41
42 if (Private->IgmpGroupEvent[TimerId] == NULL) {
43 return ;
44 }
45
46 gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);
47 Private->IgmpGroupEvent[TimerId] = NULL;
48 }
49
50 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
51
52 /**
53
54
55 **/
56 VOID
57 SetGroupTimer (
58 PXE_BASECODE_DEVICE *Private,
59 UINTN TimerId,
60 UINTN MaxRespTime
61 )
62 {
63 EFI_STATUS EfiStatus;
64
65 if (Private == NULL) {
66 return ;
67 }
68
69 if (TimerId >= Private->MCastGroupCount) {
70 return ;
71 }
72
73 if (Private->IgmpGroupEvent[TimerId] != NULL) {
74 gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);
75 }
76
77 EfiStatus = gBS->CreateEvent (
78 EVT_TIMER,
79 TPL_CALLBACK,
80 NULL,
81 NULL,
82 &Private->IgmpGroupEvent[TimerId]
83 );
84
85 if (EFI_ERROR (EfiStatus)) {
86 Private->IgmpGroupEvent[TimerId] = NULL;
87 return ;
88 }
89
90 EfiStatus = gBS->SetTimer (
91 Private->IgmpGroupEvent[TimerId],
92 TimerRelative,
93 MaxRespTime * 1000000 + Random (Private) % RAND_MAX
94 );
95
96 if (EFI_ERROR (EfiStatus)) {
97 gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);
98 Private->IgmpGroupEvent[TimerId] = NULL;
99 }
100 }
101
102 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
103
104 /**
105
106
107 **/
108 VOID
109 SendIgmpMessage (
110 PXE_BASECODE_DEVICE *Private,
111 UINT8 Type,
112 INTN GroupId
113 )
114 {
115 Private->IgmpMessage.Type = Type;
116 Private->IgmpMessage.MaxRespTime = 0;
117 Private->IgmpMessage.Checksum = 0;
118 Private->IgmpMessage.GroupAddress = Private->MCastGroup[GroupId];
119 Private->IgmpMessage.Checksum = IpChecksum (
120 (UINT16 *) &Private->IgmpMessage,
121 sizeof Private->IgmpMessage
122 );
123
124 Ipv4SendWOp (
125 Private,
126 0,
127 (UINT8 *) &Private->IgmpMessage,
128 sizeof Private->IgmpMessage,
129 PROT_IGMP,
130 RouterAlertOption,
131 sizeof RouterAlertOption,
132 ((Type == IGMP_TYPE_LEAVE_GROUP) ? AllRoutersGroup.L : Private->IgmpMessage.GroupAddress),
133 EFI_PXE_BASE_CODE_FUNCTION_IGMP
134 );
135 }
136
137 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
138
139 /**
140
141
142 **/
143 VOID
144 ReportIgmp (
145 PXE_BASECODE_DEVICE *Private,
146 INTN GroupId
147 )
148 {
149 //
150 // if version 1 querier, send v1 report
151 //
152 UINT8 Type;
153
154 if (Private->Igmpv1TimeoutEvent != NULL) {
155 if (!EFI_ERROR (gBS->CheckEvent (Private->Igmpv1TimeoutEvent))) {
156 gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
157 Private->Igmpv1TimeoutEvent = NULL;
158 Private->UseIgmpv1Reporting = TRUE;
159 }
160 }
161
162 Type = (UINT8) (Private->UseIgmpv1Reporting ? IGMP_TYPE_V1REPORT : IGMP_TYPE_REPORT);
163
164 SendIgmpMessage (Private, Type, GroupId);
165 ClearGroupTimer (Private, GroupId);
166 }
167
168 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
169
170 /**
171
172
173 **/
174 VOID
175 IgmpCheckTimers (
176 PXE_BASECODE_DEVICE *Private
177 )
178 {
179 UINTN GroupId;
180
181 if (Private == NULL) {
182 return ;
183 }
184
185 for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {
186 if (Private->IgmpGroupEvent[GroupId] == NULL) {
187 continue;
188 }
189
190 if (!EFI_ERROR (gBS->CheckEvent (Private->IgmpGroupEvent[GroupId]))) {
191 //
192 // send a report
193 //
194 ReportIgmp (Private, GroupId);
195 }
196 }
197 }
198
199 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
200
201 /**
202
203 @return 0 := Group not found
204 @return other := Group ID#
205
206 **/
207 INTN
208 FindMulticastGroup (
209 PXE_BASECODE_DEVICE *Private,
210 UINT32 GroupAddress
211 )
212 {
213 UINTN GroupId;
214
215 for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {
216 if (Private->MCastGroup[GroupId] == GroupAddress) {
217 return GroupId + 1;
218 }
219 }
220
221 return 0;
222 }
223
224 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
225
226 /**
227
228
229 **/
230 VOID
231 IgmpJoinGroup (
232 PXE_BASECODE_DEVICE *Private,
233 EFI_IP_ADDRESS *GroupPtr
234 )
235 {
236 UINT32 Grp;
237
238 Grp = *(UINT32 *) GroupPtr;
239
240 //
241 // see if we already have it or if we can't take anymore
242 //
243 if (FindMulticastGroup (Private, Grp) || Private->MCastGroupCount == MAX_MCAST_GROUPS) {
244 return ;
245 }
246 //
247 // add the group
248 //
249 Private->MCastGroup[Private->MCastGroupCount] = Grp;
250
251 ReportIgmp (Private, Private->MCastGroupCount);
252 //
253 // send a report
254 // so it will get sent again per RFC 2236
255 //
256 SetGroupTimer (
257 Private,
258 Private->MCastGroupCount++,
259 UNSOLICITED_REPORT_INTERVAL * 10
260 );
261 }
262
263 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
264
265 /**
266
267
268 **/
269 VOID
270 IgmpLeaveGroup (
271 PXE_BASECODE_DEVICE *Private,
272 EFI_IP_ADDRESS *GroupPtr
273 )
274 {
275 UINT32 Grp;
276 UINTN GroupId;
277
278 Grp = *(UINT32 *) GroupPtr;
279
280 //
281 // if not in group, ignore
282 //
283 GroupId = FindMulticastGroup (Private, Grp);
284
285 if (GroupId == 0) {
286 return ;
287 }
288 //
289 // if not v1 querrier, send leave group IGMP message
290 //
291 if (Private->Igmpv1TimeoutEvent != NULL) {
292 if (!EFI_ERROR (gBS->CheckEvent (Private->Igmpv1TimeoutEvent))) {
293 gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
294 Private->Igmpv1TimeoutEvent = NULL;
295 Private->UseIgmpv1Reporting = TRUE;
296 } else {
297 SendIgmpMessage (Private, IGMP_TYPE_LEAVE_GROUP, GroupId - 1);
298 }
299 }
300
301 while (GroupId < Private->MCastGroupCount) {
302 Private->MCastGroup[GroupId - 1] = Private->MCastGroup[GroupId];
303 Private->IgmpGroupEvent[GroupId - 1] = Private->IgmpGroupEvent[GroupId];
304 ++GroupId;
305 }
306
307 --Private->MCastGroupCount;
308 }
309
310 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
311
312 /**
313
314
315 **/
316 VOID
317 HandleIgmp (
318 PXE_BASECODE_DEVICE *Private,
319 IGMPV2_MESSAGE *IgmpMessagePtr,
320 UINTN IgmpLength
321 )
322 {
323 EFI_STATUS EfiStatus;
324 UINTN GroupId;
325 INTN MaxRespTime;
326
327 if (Private == NULL) {
328 return ;
329 }
330
331 if (Private->MCastGroupCount == 0) {
332 //
333 // if we don't belong to any multicast groups, ignore
334 //
335 return ;
336 }
337 //
338 // verify checksum
339 //
340 if (IpChecksum ((UINT16 *) IgmpMessagePtr, IgmpLength)) {
341 //
342 // bad checksum - ignore packet
343 //
344 return ;
345 }
346
347 switch (IgmpMessagePtr->Type) {
348 case IGMP_TYPE_QUERY:
349 //
350 // if a version 1 querier, note the fact and set max resp time
351 //
352 MaxRespTime = IgmpMessagePtr->MaxRespTime;
353
354 if (MaxRespTime == 0) {
355 Private->UseIgmpv1Reporting = TRUE;
356
357 if (Private->Igmpv1TimeoutEvent != NULL) {
358 gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
359 }
360
361 EfiStatus = gBS->CreateEvent (
362 EVT_TIMER,
363 TPL_CALLBACK,
364 NULL,
365 NULL,
366 &Private->Igmpv1TimeoutEvent
367 );
368
369 if (EFI_ERROR (EfiStatus)) {
370 Private->Igmpv1TimeoutEvent = NULL;
371 } else {
372 EfiStatus = gBS->SetTimer (
373 Private->Igmpv1TimeoutEvent,
374 TimerRelative,
375 (UINT64) V1ROUTER_PRESENT_TIMEOUT * 10000000
376 );
377 }
378
379 MaxRespTime = IGMP_DEFAULT_MAX_RESPONSE_TIME * 10;
380 }
381 //
382 // if a general query (!GroupAddress), set all our group timers
383 //
384 if (!IgmpMessagePtr->GroupAddress) {
385 for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {
386 SetGroupTimer (Private, GroupId, MaxRespTime);
387 }
388 } else {
389 //
390 // specific query - set only specific group
391 //
392 GroupId = FindMulticastGroup (Private, IgmpMessagePtr->GroupAddress);
393
394 if (GroupId != 0) {
395 SetGroupTimer (Private, GroupId - 1, MaxRespTime);
396 }
397 }
398
399 break;
400
401 //
402 // if we have a timer running for this group, clear it
403 //
404 case IGMP_TYPE_V1REPORT:
405 case IGMP_TYPE_REPORT:
406 GroupId = FindMulticastGroup (Private, IgmpMessagePtr->GroupAddress);
407
408 if (GroupId != 0) {
409 ClearGroupTimer (Private, GroupId - 1);
410 }
411
412 break;
413 }
414 }
415
416 /* EOF - pxe_bc_igmp.c */