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