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