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