]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_igmp.c
1. Remove #ifdef _MSC_EXTENSION_ from all source files
[mirror_edk2.git] / EdkModulePkg / Universal / Network / PxeBc / Dxe / pxe_bc_igmp.c
1 /*++
2
3 Copyright (c) 2006 - 2007, 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
17 #define RAND_MAX 0x10000
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 STATIC UINT8 RouterAlertOption[4] = { 0x80 | 20, 4, 0, 0 };
25 STATIC IPV4_ADDR AllRoutersGroup = { { 224, 0, 0, 2 } };
26
27 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
28 STATIC
29 VOID
30 ClearGroupTimer (
31 PXE_BASECODE_DEVICE *Private,
32 UINTN TimerId
33 )
34 {
35 if (Private == NULL) {
36 return ;
37 }
38
39 if (TimerId >= Private->MCastGroupCount) {
40 return ;
41 }
42
43 if (Private->IgmpGroupEvent[TimerId] == NULL) {
44 return ;
45 }
46
47 gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);
48 Private->IgmpGroupEvent[TimerId] = NULL;
49 }
50
51 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
52 STATIC
53 VOID
54 SetGroupTimer (
55 PXE_BASECODE_DEVICE *Private,
56 UINTN TimerId,
57 UINTN MaxRespTime
58 )
59 /*++
60 Routine description:
61 Set IGMP response timeout value.
62
63 Parameters:
64 Private := Pointer to PxeBc interface
65 TimerId := Timer ID#
66 MaxRespTime := Base response timeout value in tenths of seconds
67
68 Returns:
69 --*/
70 {
71 EFI_STATUS EfiStatus;
72
73 if (Private == NULL) {
74 return ;
75 }
76
77 if (TimerId >= Private->MCastGroupCount) {
78 return ;
79 }
80
81 if (Private->IgmpGroupEvent[TimerId] != NULL) {
82 gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);
83 }
84
85 EfiStatus = gBS->CreateEvent (
86 EFI_EVENT_TIMER,
87 EFI_TPL_CALLBACK,
88 NULL,
89 NULL,
90 &Private->IgmpGroupEvent[TimerId]
91 );
92
93 if (EFI_ERROR (EfiStatus)) {
94 Private->IgmpGroupEvent[TimerId] = NULL;
95 return ;
96 }
97
98 EfiStatus = gBS->SetTimer (
99 Private->IgmpGroupEvent[TimerId],
100 TimerRelative,
101 MaxRespTime * 1000000 + Random (Private) % RAND_MAX
102 );
103
104 if (EFI_ERROR (EfiStatus)) {
105 gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);
106 Private->IgmpGroupEvent[TimerId] = NULL;
107 }
108 }
109
110 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
111 STATIC
112 VOID
113 SendIgmpMessage (
114 PXE_BASECODE_DEVICE *Private,
115 UINT8 Type,
116 INTN GroupId
117 )
118 /*++
119 Routine description:
120 Send an IGMP message
121
122 Parameters:
123 Private := Pointer to PxeBc interface
124 Type := Message type opcode
125 GroupId := Group ID#
126
127 Returns:
128 --*/
129 {
130 Private->IgmpMessage.Type = Type;
131 Private->IgmpMessage.MaxRespTime = 0;
132 Private->IgmpMessage.Checksum = 0;
133 Private->IgmpMessage.GroupAddress = Private->MCastGroup[GroupId];
134 Private->IgmpMessage.Checksum = IpChecksum (
135 (UINT16 *) &Private->IgmpMessage,
136 sizeof Private->IgmpMessage
137 );
138
139 Ipv4SendWOp (
140 Private,
141 0,
142 (UINT8 *) &Private->IgmpMessage,
143 sizeof Private->IgmpMessage,
144 PROT_IGMP,
145 RouterAlertOption,
146 sizeof RouterAlertOption,
147 ((Type == IGMP_TYPE_LEAVE_GROUP) ? AllRoutersGroup.L : Private->IgmpMessage.GroupAddress),
148 EFI_PXE_BASE_CODE_FUNCTION_IGMP
149 );
150 }
151
152 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
153 STATIC
154 VOID
155 ReportIgmp (
156 PXE_BASECODE_DEVICE *Private,
157 INTN GroupId
158 )
159 /*++
160 Routine description:
161 Send an IGMP report message.
162
163 Parameters:
164 Private := Pointer to PxeBc interface
165 GroupId := Group ID#
166
167 Returns:
168 --*/
169 {
170 //
171 // if version 1 querier, send v1 report
172 //
173 UINT8 Type;
174
175 if (Private->Igmpv1TimeoutEvent != NULL) {
176 if (!EFI_ERROR (gBS->CheckEvent (Private->Igmpv1TimeoutEvent))) {
177 gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
178 Private->Igmpv1TimeoutEvent = NULL;
179 Private->UseIgmpv1Reporting = TRUE;
180 }
181 }
182
183 Type = (UINT8) (Private->UseIgmpv1Reporting ? IGMP_TYPE_V1REPORT : IGMP_TYPE_REPORT);
184
185 SendIgmpMessage (Private, Type, GroupId);
186 ClearGroupTimer (Private, GroupId);
187 }
188
189 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
190 VOID
191 IgmpCheckTimers (
192 PXE_BASECODE_DEVICE *Private
193 )
194 /*++
195 Routine description:
196 Check IGMP timers and send reports for all groups that have expired.
197 Parameters:
198 Private := Pointer to PxeBc interface
199
200 Returns:
201 --*/
202 {
203 UINTN GroupId;
204
205 if (Private == NULL) {
206 return ;
207 }
208
209 for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {
210 if (Private->IgmpGroupEvent[GroupId] == NULL) {
211 continue;
212 }
213
214 if (!EFI_ERROR (gBS->CheckEvent (Private->IgmpGroupEvent[GroupId]))) {
215 //
216 // send a report
217 //
218 ReportIgmp (Private, GroupId);
219 }
220 }
221 }
222
223 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
224 STATIC
225 INTN
226 FindMulticastGroup (
227 PXE_BASECODE_DEVICE *Private,
228 UINT32 GroupAddress
229 )
230 /*++
231 Routine description:
232 Fund group ID# (index).
233
234 Parameters:
235 Private := Pointer to PxeBc interface
236 GroupAddress := Group multicast address
237
238 Returns:
239 0 := Group not found
240 other := Group ID#
241 --*/
242 {
243 UINTN GroupId;
244
245 for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {
246 if (Private->MCastGroup[GroupId] == GroupAddress) {
247 return GroupId + 1;
248 }
249 }
250
251 return 0;
252 }
253
254 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
255 VOID
256 IgmpJoinGroup (
257 PXE_BASECODE_DEVICE *Private,
258 EFI_IP_ADDRESS *GroupPtr
259 )
260 /*++
261 Routine description:
262 Join multicast group.
263
264 Parameters:
265 Private := Pointer to PxeBc interface
266 GroupPtr := Pointer to group mutlicast IP address.
267
268 Returns:
269 --*/
270 {
271 UINT32 Grp;
272
273 Grp = *(UINT32 *) GroupPtr;
274
275 //
276 // see if we already have it or if we can't take anymore
277 //
278 if (FindMulticastGroup (Private, Grp) || Private->MCastGroupCount == MAX_MCAST_GROUPS) {
279 return ;
280 }
281 //
282 // add the group
283 //
284 Private->MCastGroup[Private->MCastGroupCount] = Grp;
285
286 ReportIgmp (Private, Private->MCastGroupCount);
287 //
288 // send a report
289 // so it will get sent again per RFC 2236
290 //
291 SetGroupTimer (
292 Private,
293 Private->MCastGroupCount++,
294 UNSOLICITED_REPORT_INTERVAL * 10
295 );
296 }
297
298 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
299 VOID
300 IgmpLeaveGroup (
301 PXE_BASECODE_DEVICE *Private,
302 EFI_IP_ADDRESS *GroupPtr
303 )
304 /*++
305 Routine description:
306 Leave multicast group.
307
308 Parameters:
309 Private := Pointer to PxeBc interface
310 GroupPtr := Mutlicast group IP address.
311
312 Returns:
313 --*/
314 {
315 UINT32 Grp;
316 UINTN GroupId;
317
318 Grp = *(UINT32 *) GroupPtr;
319
320 //
321 // if not in group, ignore
322 //
323 GroupId = FindMulticastGroup (Private, Grp);
324
325 if (GroupId == 0) {
326 return ;
327 }
328 //
329 // if not v1 querrier, send leave group IGMP message
330 //
331 if (Private->Igmpv1TimeoutEvent != NULL) {
332 if (!EFI_ERROR (gBS->CheckEvent (Private->Igmpv1TimeoutEvent))) {
333 gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
334 Private->Igmpv1TimeoutEvent = NULL;
335 Private->UseIgmpv1Reporting = TRUE;
336 } else {
337 SendIgmpMessage (Private, IGMP_TYPE_LEAVE_GROUP, GroupId - 1);
338 }
339 }
340
341 while (GroupId < Private->MCastGroupCount) {
342 Private->MCastGroup[GroupId - 1] = Private->MCastGroup[GroupId];
343 Private->IgmpGroupEvent[GroupId - 1] = Private->IgmpGroupEvent[GroupId];
344 ++GroupId;
345 }
346
347 --Private->MCastGroupCount;
348 }
349
350 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
351 VOID
352 HandleIgmp (
353 PXE_BASECODE_DEVICE *Private,
354 IGMPV2_MESSAGE *IgmpMessagePtr,
355 UINTN IgmpLength
356 )
357 /*++
358 Routine description:
359 Handle received IGMP packet
360
361 Parameters:
362 Private := Pointer to PxeBc interface
363 IgmpMessagePtr := Pointer to IGMP packet
364 IgmpLength := packet length in bytes
365
366 Returns:
367 --*/
368 {
369 EFI_STATUS EfiStatus;
370 UINTN GroupId;
371 INTN MaxRespTime;
372
373 if (Private == NULL) {
374 return ;
375 }
376
377 if (Private->MCastGroupCount == 0) {
378 //
379 // if we don't belong to any multicast groups, ignore
380 //
381 return ;
382 }
383 //
384 // verify checksum
385 //
386 if (IpChecksum ((UINT16 *) IgmpMessagePtr, IgmpLength)) {
387 //
388 // bad checksum - ignore packet
389 //
390 return ;
391 }
392
393 switch (IgmpMessagePtr->Type) {
394 case IGMP_TYPE_QUERY:
395 //
396 // if a version 1 querier, note the fact and set max resp time
397 //
398 MaxRespTime = IgmpMessagePtr->MaxRespTime;
399
400 if (MaxRespTime == 0) {
401 Private->UseIgmpv1Reporting = TRUE;
402
403 if (Private->Igmpv1TimeoutEvent != NULL) {
404 gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
405 }
406
407 EfiStatus = gBS->CreateEvent (
408 EFI_EVENT_TIMER,
409 EFI_TPL_CALLBACK,
410 NULL,
411 NULL,
412 &Private->Igmpv1TimeoutEvent
413 );
414
415 if (EFI_ERROR (EfiStatus)) {
416 Private->Igmpv1TimeoutEvent = NULL;
417 } else {
418 EfiStatus = gBS->SetTimer (
419 Private->Igmpv1TimeoutEvent,
420 TimerRelative,
421 (UINT64) V1ROUTER_PRESENT_TIMEOUT * 10000000
422 );
423 }
424
425 MaxRespTime = IGMP_DEFAULT_MAX_RESPONSE_TIME * 10;
426 }
427 //
428 // if a general query (!GroupAddress), set all our group timers
429 //
430 if (!IgmpMessagePtr->GroupAddress) {
431 for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {
432 SetGroupTimer (Private, GroupId, MaxRespTime);
433 }
434 } else {
435 //
436 // specific query - set only specific group
437 //
438 GroupId = FindMulticastGroup (Private, IgmpMessagePtr->GroupAddress);
439
440 if (GroupId != 0) {
441 SetGroupTimer (Private, GroupId - 1, MaxRespTime);
442 }
443 }
444
445 break;
446
447 //
448 // if we have a timer running for this group, clear it
449 //
450 case IGMP_TYPE_V1REPORT:
451 case IGMP_TYPE_REPORT:
452 GroupId = FindMulticastGroup (Private, IgmpMessagePtr->GroupAddress);
453
454 if (GroupId != 0) {
455 ClearGroupTimer (Private, GroupId - 1);
456 }
457
458 break;
459 }
460 }
461
462 /* EOF - pxe_bc_igmp.c */