]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Ip6Dxe/Ip6Driver.c
MdeModulePkg/NetworkPkg: Locate IpSec on IP packet processing only if it's installed.
[mirror_edk2.git] / NetworkPkg / Ip6Dxe / Ip6Driver.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 The driver binding and service binding protocol for IP6 driver.\r
3\r
d551cc64 4 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
c79de074 5 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
a3bcde70
HT
6\r
7 This program and the accompanying materials\r
8 are licensed and made available under the terms and conditions of the BSD License\r
9 which accompanies this distribution. The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php.\r
11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include "Ip6Impl.h"\r
18\r
19EFI_DRIVER_BINDING_PROTOCOL gIp6DriverBinding = {\r
20 Ip6DriverBindingSupported,\r
21 Ip6DriverBindingStart,\r
22 Ip6DriverBindingStop,\r
23 0xa,\r
24 NULL,\r
25 NULL\r
26};\r
27\r
c79de074
SEHM
28BOOLEAN mIpSec2Installed = FALSE;\r
29\r
30/**\r
31 Callback function for IpSec2 Protocol install.\r
32\r
33 @param[in] Event Event whose notification function is being invoked\r
34 @param[in] Context Pointer to the notification function's context\r
35\r
36 @retval EFI_SUCCESS Callback successful.\r
37**/\r
38VOID\r
39EFIAPI\r
40IpSec2InstalledCallback (\r
41 IN EFI_EVENT Event,\r
42 IN VOID *Context\r
43 )\r
44{\r
45 //\r
46 // Close the event so it does not get called again.\r
47 //\r
48 gBS->CloseEvent (Event);\r
49\r
50 mIpSec2Installed = TRUE;\r
51\r
52 return;\r
53}\r
54\r
a3bcde70
HT
55/**\r
56 This is the declaration of an EFI image entry point. This entry point is\r
57 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including\r
58 both device drivers and bus drivers.\r
59\r
60 The entry point for IP6 driver which installs the driver\r
61 binding and component name protocol on its image.\r
62\r
63 @param[in] ImageHandle The firmware allocated handle for the UEFI image.\r
64 @param[in] SystemTable A pointer to the EFI System Table.\r
65\r
66 @retval EFI_SUCCESS The operation completed successfully.\r
67 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
68\r
69**/\r
70EFI_STATUS\r
71EFIAPI\r
72Ip6DriverEntryPoint (\r
73 IN EFI_HANDLE ImageHandle,\r
74 IN EFI_SYSTEM_TABLE *SystemTable\r
75 )\r
76{\r
c79de074
SEHM
77 VOID *Registration;\r
78\r
79 EfiCreateProtocolNotifyEvent (\r
80 &gEfiIpSec2ProtocolGuid,\r
81 TPL_CALLBACK,\r
82 IpSec2InstalledCallback,\r
83 NULL,\r
84 &Registration\r
85 );\r
86\r
a3bcde70
HT
87 return EfiLibInstallDriverBindingComponentName2 (\r
88 ImageHandle,\r
89 SystemTable,\r
90 &gIp6DriverBinding,\r
91 ImageHandle,\r
92 &gIp6ComponentName,\r
93 &gIp6ComponentName2\r
94 );\r
95}\r
96\r
97/**\r
98 Test to see if this driver supports ControllerHandle.\r
99\r
100 @param[in] This Protocol instance pointer.\r
101 @param[in] ControllerHandle Handle of device to test.\r
102 @param[in] RemainingDevicePath Optional parameter use to pick a specific child\r
103 device to start.\r
104\r
105 @retval EFI_SUCCESS This driver supports this device.\r
106 @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
107 @retval other This driver does not support this device.\r
108\r
109**/\r
110EFI_STATUS\r
111EFIAPI\r
112Ip6DriverBindingSupported (\r
113 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
114 IN EFI_HANDLE ControllerHandle,\r
115 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
116 )\r
117{\r
118 //\r
119 // Test for the MNP service binding Protocol\r
120 //\r
121 return gBS->OpenProtocol (\r
122 ControllerHandle,\r
123 &gEfiManagedNetworkServiceBindingProtocolGuid,\r
124 NULL,\r
125 This->DriverBindingHandle,\r
126 ControllerHandle,\r
127 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
128 );\r
129}\r
130\r
131/**\r
132 Clean up an IP6 service binding instance. It releases all\r
133 the resource allocated by the instance. The instance may be\r
134 partly initialized, or partly destroyed. If a resource is\r
75dce340 135 destroyed, it is marked as that in case the destroy failed and\r
a3bcde70
HT
136 being called again later.\r
137\r
138 @param[in] IpSb The IP6 service binding instance to clean up.\r
139\r
140 @retval EFI_SUCCESS The resource used by the instance are cleaned up.\r
141 @retval Others Failed to clean up some of the resources.\r
142\r
143**/\r
144EFI_STATUS\r
145Ip6CleanService (\r
146 IN IP6_SERVICE *IpSb\r
147 )\r
148{\r
149 EFI_STATUS Status;\r
150 EFI_IPv6_ADDRESS AllNodes;\r
151 IP6_NEIGHBOR_ENTRY *NeighborCache;\r
152\r
153 Ip6ConfigCleanInstance (&IpSb->Ip6ConfigInstance);\r
154\r
216f7970 155 if (!IpSb->LinkLocalDadFail) {\r
156 //\r
157 // Leave link-scope all-nodes multicast address (FF02::1)\r
158 //\r
159 Ip6SetToAllNodeMulticast (FALSE, IP6_LINK_LOCAL_SCOPE, &AllNodes);\r
a3bcde70 160\r
216f7970 161 Status = Ip6LeaveGroup (IpSb, &AllNodes);\r
162 if (EFI_ERROR (Status)) {\r
163 return Status;\r
164 } \r
a3bcde70
HT
165 }\r
166\r
167 if (IpSb->DefaultInterface != NULL) {\r
168 Ip6CleanInterface (IpSb->DefaultInterface, NULL);\r
169 IpSb->DefaultInterface = NULL;\r
170 }\r
171\r
172 Ip6CleanDefaultRouterList (IpSb);\r
173\r
174 Ip6CleanPrefixListTable (IpSb, &IpSb->OnlinkPrefix);\r
175 Ip6CleanPrefixListTable (IpSb, &IpSb->AutonomousPrefix);\r
176\r
177 if (IpSb->RouteTable != NULL) {\r
178 Ip6CleanRouteTable (IpSb->RouteTable);\r
179 IpSb->RouteTable = NULL;\r
180 }\r
181\r
182 if (IpSb->InterfaceId != NULL) {\r
183 FreePool (IpSb->InterfaceId);\r
184 }\r
185\r
186 IpSb->InterfaceId = NULL;\r
187\r
188 Ip6CleanAssembleTable (&IpSb->Assemble);\r
189\r
190 if (IpSb->MnpChildHandle != NULL) {\r
191 if (IpSb->Mnp != NULL) {\r
192 IpSb->Mnp->Cancel (IpSb->Mnp, NULL);\r
193 IpSb->Mnp->Configure (IpSb->Mnp, NULL);\r
194 gBS->CloseProtocol (\r
195 IpSb->MnpChildHandle,\r
196 &gEfiManagedNetworkProtocolGuid,\r
197 IpSb->Image,\r
198 IpSb->Controller\r
199 );\r
200\r
201 IpSb->Mnp = NULL;\r
202 }\r
203\r
204 NetLibDestroyServiceChild (\r
205 IpSb->Controller,\r
206 IpSb->Image,\r
207 &gEfiManagedNetworkServiceBindingProtocolGuid,\r
208 IpSb->MnpChildHandle\r
209 );\r
210\r
211 IpSb->MnpChildHandle = NULL;\r
212 }\r
213\r
214 if (IpSb->RecvRequest.MnpToken.Event != NULL) {\r
215 gBS->CloseEvent (IpSb->RecvRequest.MnpToken.Event);\r
216 }\r
217\r
218 if (IpSb->Timer != NULL) {\r
219 gBS->SetTimer (IpSb->Timer, TimerCancel, 0);\r
220 gBS->CloseEvent (IpSb->Timer);\r
221\r
222 IpSb->Timer = NULL;\r
223 }\r
224\r
225 if (IpSb->FasterTimer != NULL) {\r
226 gBS->SetTimer (IpSb->FasterTimer, TimerCancel, 0);\r
227 gBS->CloseEvent (IpSb->FasterTimer);\r
228\r
229 IpSb->FasterTimer = NULL;\r
230 }\r
231 //\r
232 // Free the Neighbor Discovery resources\r
233 //\r
234 while (!IsListEmpty (&IpSb->NeighborTable)) {\r
235 NeighborCache = NET_LIST_HEAD (&IpSb->NeighborTable, IP6_NEIGHBOR_ENTRY, Link);\r
236 Ip6FreeNeighborEntry (IpSb, NeighborCache, FALSE, TRUE, EFI_SUCCESS, NULL, NULL);\r
237 }\r
238\r
239 return EFI_SUCCESS;\r
240}\r
241\r
242/**\r
243 Create a new IP6 driver service binding protocol.\r
244\r
245 @param[in] Controller The controller that has MNP service binding\r
246 installed.\r
247 @param[in] ImageHandle The IP6 driver's image handle.\r
248 @param[out] Service The variable to receive the newly created IP6\r
249 service.\r
250\r
251 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources.\r
252 @retval EFI_SUCCESS A new IP6 service binding private is created.\r
253\r
254**/\r
255EFI_STATUS\r
256Ip6CreateService (\r
257 IN EFI_HANDLE Controller,\r
258 IN EFI_HANDLE ImageHandle,\r
259 OUT IP6_SERVICE **Service\r
260 )\r
261{\r
262 IP6_SERVICE *IpSb;\r
263 EFI_STATUS Status;\r
264 EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;\r
265 EFI_MANAGED_NETWORK_CONFIG_DATA *Config;\r
266 IP6_CONFIG_DATA_ITEM *DataItem;\r
267\r
268 ASSERT (Service != NULL);\r
269\r
270 *Service = NULL;\r
271\r
272 //\r
273 // allocate a service private data then initialize all the filed to\r
274 // empty resources, so if any thing goes wrong when allocating\r
275 // resources, Ip6CleanService can be called to clean it up.\r
276 //\r
277 IpSb = AllocateZeroPool (sizeof (IP6_SERVICE));\r
278\r
279 if (IpSb == NULL) {\r
280 return EFI_OUT_OF_RESOURCES;\r
281 }\r
282\r
283 IpSb->Signature = IP6_SERVICE_SIGNATURE;\r
284 IpSb->ServiceBinding.CreateChild = Ip6ServiceBindingCreateChild;\r
285 IpSb->ServiceBinding.DestroyChild = Ip6ServiceBindingDestroyChild;\r
286 IpSb->State = IP6_SERVICE_UNSTARTED;\r
a3bcde70
HT
287\r
288 IpSb->NumChildren = 0;\r
289 InitializeListHead (&IpSb->Children);\r
290\r
291 InitializeListHead (&IpSb->Interfaces);\r
292 IpSb->DefaultInterface = NULL;\r
293 IpSb->RouteTable = NULL;\r
294\r
295 IpSb->RecvRequest.Signature = IP6_LINK_RX_SIGNATURE;\r
296 IpSb->RecvRequest.CallBack = NULL;\r
297 IpSb->RecvRequest.Context = NULL;\r
298 MnpToken = &IpSb->RecvRequest.MnpToken;\r
299 MnpToken->Event = NULL;\r
300 MnpToken->Status = EFI_NOT_READY;\r
301 MnpToken->Packet.RxData = NULL;\r
302\r
303 Ip6CreateAssembleTable (&IpSb->Assemble);\r
304\r
305 IpSb->MldCtrl.Mldv1QuerySeen = 0;\r
306 InitializeListHead (&IpSb->MldCtrl.Groups);\r
307\r
308 ZeroMem (&IpSb->LinkLocalAddr, sizeof (EFI_IPv6_ADDRESS));\r
309 IpSb->LinkLocalOk = FALSE;\r
310 IpSb->LinkLocalDadFail = FALSE;\r
311 IpSb->Dhcp6NeedStart = FALSE;\r
312 IpSb->Dhcp6NeedInfoRequest = FALSE;\r
313\r
314 IpSb->CurHopLimit = IP6_HOP_LIMIT;\r
315 IpSb->LinkMTU = IP6_MIN_LINK_MTU;\r
316 IpSb->BaseReachableTime = IP6_REACHABLE_TIME;\r
317 Ip6UpdateReachableTime (IpSb);\r
318 //\r
319 // RFC4861 RETRANS_TIMER: 1,000 milliseconds\r
320 //\r
321 IpSb->RetransTimer = IP6_RETRANS_TIMER;\r
322\r
323 IpSb->RoundRobin = 0;\r
324\r
325 InitializeListHead (&IpSb->NeighborTable);\r
326 InitializeListHead (&IpSb->DefaultRouterList);\r
327 InitializeListHead (&IpSb->OnlinkPrefix);\r
328 InitializeListHead (&IpSb->AutonomousPrefix);\r
329\r
330 IpSb->InterfaceIdLen = IP6_IF_ID_LEN;\r
331 IpSb->InterfaceId = NULL;\r
332\r
333 IpSb->RouterAdvertiseReceived = FALSE;\r
334 IpSb->SolicitTimer = IP6_MAX_RTR_SOLICITATIONS;\r
335 IpSb->Ticks = 0;\r
336\r
337 IpSb->Image = ImageHandle;\r
338 IpSb->Controller = Controller;\r
339\r
340 IpSb->MnpChildHandle = NULL;\r
341 IpSb->Mnp = NULL;\r
342\r
343 Config = &IpSb->MnpConfigData;\r
344 Config->ReceivedQueueTimeoutValue = 0;\r
345 Config->TransmitQueueTimeoutValue = 0;\r
346 Config->ProtocolTypeFilter = IP6_ETHER_PROTO;\r
347 Config->EnableUnicastReceive = TRUE;\r
348 Config->EnableMulticastReceive = TRUE;\r
349 Config->EnableBroadcastReceive = TRUE;\r
350 Config->EnablePromiscuousReceive = FALSE;\r
351 Config->FlushQueuesOnReset = TRUE;\r
352 Config->EnableReceiveTimestamps = FALSE;\r
353 Config->DisableBackgroundPolling = FALSE;\r
354\r
355 ZeroMem (&IpSb->SnpMode, sizeof (EFI_SIMPLE_NETWORK_MODE));\r
356\r
357 IpSb->Timer = NULL;\r
358 IpSb->FasterTimer = NULL;\r
359\r
360 ZeroMem (&IpSb->Ip6ConfigInstance, sizeof (IP6_CONFIG_INSTANCE));\r
361\r
362 IpSb->MacString = NULL;\r
363\r
364 //\r
365 // Create various resources. First create the route table, timer\r
366 // event, MNP token event and MNP child.\r
367 //\r
368\r
369 IpSb->RouteTable = Ip6CreateRouteTable ();\r
370 if (IpSb->RouteTable == NULL) {\r
371 Status = EFI_OUT_OF_RESOURCES;\r
372 goto ON_ERROR;\r
373 }\r
374\r
375 Status = gBS->CreateEvent (\r
376 EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
377 TPL_CALLBACK,\r
378 Ip6TimerTicking,\r
379 IpSb,\r
380 &IpSb->Timer\r
381 );\r
382 if (EFI_ERROR (Status)) {\r
383 goto ON_ERROR;\r
384 }\r
385\r
386 Status = gBS->CreateEvent (\r
387 EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
388 TPL_CALLBACK,\r
389 Ip6NdFasterTimerTicking,\r
390 IpSb,\r
391 &IpSb->FasterTimer\r
392 );\r
393 if (EFI_ERROR (Status)) {\r
394 goto ON_ERROR;\r
395 }\r
396\r
397 Status = NetLibCreateServiceChild (\r
398 Controller,\r
399 ImageHandle,\r
400 &gEfiManagedNetworkServiceBindingProtocolGuid,\r
401 &IpSb->MnpChildHandle\r
402 );\r
403 if (EFI_ERROR (Status)) {\r
404 goto ON_ERROR;\r
405 }\r
406\r
407 Status = gBS->OpenProtocol (\r
408 IpSb->MnpChildHandle,\r
409 &gEfiManagedNetworkProtocolGuid,\r
410 (VOID **) (&IpSb->Mnp),\r
411 ImageHandle,\r
412 Controller,\r
413 EFI_OPEN_PROTOCOL_BY_DRIVER\r
414 );\r
415 if (EFI_ERROR (Status)) {\r
416 goto ON_ERROR;\r
417 }\r
418\r
419 Status = Ip6ServiceConfigMnp (IpSb, TRUE);\r
420 if (EFI_ERROR (Status)) {\r
421 goto ON_ERROR;\r
422 }\r
423\r
424 Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &IpSb->SnpMode);\r
425 if (EFI_ERROR (Status)) {\r
426 goto ON_ERROR;\r
427 }\r
428\r
429 IpSb->MaxPacketSize = IP6_MIN_LINK_MTU - sizeof (EFI_IP6_HEADER);\r
430 if (NetLibGetVlanId (IpSb->Controller) != 0) {\r
431 //\r
432 // This is a VLAN device, reduce MTU by VLAN tag length\r
433 //\r
434 IpSb->MaxPacketSize -= NET_VLAN_TAG_LEN;\r
435 }\r
436 IpSb->OldMaxPacketSize = IpSb->MaxPacketSize;\r
437\r
438 //\r
439 // Currently only ETHERNET is supported in IPv6 stack, since\r
440 // link local address requires an IEEE 802 48-bit MACs for\r
441 // EUI-64 format interface identifier mapping.\r
442 //\r
443 if (IpSb->SnpMode.IfType != NET_IFTYPE_ETHERNET) {\r
444 Status = EFI_UNSUPPORTED;\r
445 goto ON_ERROR;\r
446 }\r
447\r
448 Status = Ip6InitMld (IpSb);\r
449 if (EFI_ERROR (Status)) {\r
450 goto ON_ERROR;\r
451 }\r
452\r
8fedfc04 453 Status = NetLibGetMacString (IpSb->Controller, IpSb->Image, &IpSb->MacString);\r
a3bcde70
HT
454 if (EFI_ERROR (Status)) {\r
455 goto ON_ERROR;\r
456 }\r
457\r
8fedfc04 458 Status = Ip6ConfigInitInstance (&IpSb->Ip6ConfigInstance);\r
a3bcde70
HT
459 if (EFI_ERROR (Status)) {\r
460 goto ON_ERROR;\r
461 }\r
462\r
8fedfc04
YT
463 IpSb->DefaultInterface = Ip6CreateInterface (IpSb, TRUE);\r
464 if (IpSb->DefaultInterface == NULL) {\r
465 Status = EFI_DEVICE_ERROR;\r
466 goto ON_ERROR;\r
467 }\r
a3bcde70
HT
468\r
469 Status = gBS->CreateEvent (\r
470 EVT_NOTIFY_SIGNAL,\r
471 TPL_NOTIFY,\r
472 Ip6OnFrameReceived,\r
473 &IpSb->RecvRequest,\r
474 &MnpToken->Event\r
475 );\r
476 if (EFI_ERROR (Status)) {\r
477 goto ON_ERROR;\r
478 }\r
479\r
a3bcde70
HT
480 //\r
481 // If there is any manual address, set it.\r
482 //\r
483 DataItem = &IpSb->Ip6ConfigInstance.DataItem[Ip6ConfigDataTypeManualAddress];\r
484 if (DataItem->Data.Ptr != NULL) {\r
485 DataItem->SetData (\r
486 &IpSb->Ip6ConfigInstance,\r
487 DataItem->DataSize,\r
488 DataItem->Data.Ptr\r
489 );\r
490 }\r
491\r
f269f2af 492 //\r
493 // If there is any gateway address, set it.\r
494 //\r
495 DataItem = &IpSb->Ip6ConfigInstance.DataItem[Ip6ConfigDataTypeGateway];\r
496 if (DataItem->Data.Ptr != NULL) {\r
497 DataItem->SetData (\r
498 &IpSb->Ip6ConfigInstance,\r
499 DataItem->DataSize,\r
500 DataItem->Data.Ptr\r
501 );\r
502 }\r
503\r
a3bcde70
HT
504 InsertHeadList (&IpSb->Interfaces, &IpSb->DefaultInterface->Link);\r
505\r
506 *Service = IpSb;\r
507 return EFI_SUCCESS;\r
508\r
509ON_ERROR:\r
510 Ip6CleanService (IpSb);\r
511 FreePool (IpSb);\r
512 return Status;\r
513}\r
514\r
515\r
516/**\r
517 Start this driver on ControllerHandle.\r
518\r
519 @param[in] This Protocol instance pointer.\r
520 @param[in] ControllerHandle Handle of device to bind driver to.\r
521 @param[in] RemainingDevicePath Optional parameter used to pick a specific child\r
522 device to start.\r
523\r
524 @retval EFI_SUCCES This driver is added to ControllerHandle.\r
525 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.\r
526 @retval other This driver does not support this device.\r
527\r
528**/\r
529EFI_STATUS\r
530EFIAPI\r
531Ip6DriverBindingStart (\r
532 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
533 IN EFI_HANDLE ControllerHandle,\r
534 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
535 )\r
536{\r
537 IP6_SERVICE *IpSb;\r
538 EFI_STATUS Status;\r
539\r
540 //\r
541 // Test for the Ip6 service binding protocol\r
542 //\r
543 Status = gBS->OpenProtocol (\r
544 ControllerHandle,\r
545 &gEfiIp6ServiceBindingProtocolGuid,\r
546 NULL,\r
547 This->DriverBindingHandle,\r
548 ControllerHandle,\r
549 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
550 );\r
551\r
552 if (Status == EFI_SUCCESS) {\r
553 return EFI_ALREADY_STARTED;\r
554 }\r
555\r
556 Status = Ip6CreateService (ControllerHandle, This->DriverBindingHandle, &IpSb);\r
557\r
558 if (EFI_ERROR (Status)) {\r
559 return Status;\r
560 }\r
561\r
562 ASSERT (IpSb != NULL);\r
563\r
564 //\r
565 // Install the Ip6ServiceBinding Protocol onto ControlerHandle\r
566 //\r
567 Status = gBS->InstallMultipleProtocolInterfaces (\r
568 &ControllerHandle,\r
569 &gEfiIp6ServiceBindingProtocolGuid,\r
570 &IpSb->ServiceBinding,\r
571 &gEfiIp6ConfigProtocolGuid,\r
572 &IpSb->Ip6ConfigInstance.Ip6Config,\r
573 NULL\r
574 );\r
575\r
8fedfc04
YT
576 if (!EFI_ERROR (Status)) {\r
577 //\r
578 // ready to go: start the receiving and timer\r
579 //\r
580 Status = Ip6ReceiveFrame (Ip6AcceptFrame, IpSb);\r
581 if (EFI_ERROR (Status)) {\r
582 goto ON_ERROR;\r
583 }\r
584\r
585 //\r
586 // The timer expires every 100 (IP6_TIMER_INTERVAL_IN_MS) milliseconds.\r
587 //\r
588 Status = gBS->SetTimer (\r
589 IpSb->FasterTimer,\r
590 TimerPeriodic,\r
591 TICKS_PER_MS * IP6_TIMER_INTERVAL_IN_MS\r
592 );\r
593 if (EFI_ERROR (Status)) {\r
594 goto ON_ERROR;\r
595 }\r
596\r
597 //\r
598 // The timer expires every 1000 (IP6_ONE_SECOND_IN_MS) milliseconds.\r
599 //\r
600 Status = gBS->SetTimer (\r
601 IpSb->Timer,\r
602 TimerPeriodic,\r
603 TICKS_PER_MS * IP6_ONE_SECOND_IN_MS\r
604 );\r
605 if (EFI_ERROR (Status)) {\r
606 goto ON_ERROR;\r
607 } \r
a3bcde70 608\r
a3bcde70
HT
609 //\r
610 // Initialize the IP6 ID\r
611 //\r
612 mIp6Id = NET_RANDOM (NetRandomInitSeed ());\r
613\r
8fedfc04 614 return EFI_SUCCESS;\r
a3bcde70
HT
615 }\r
616\r
8fedfc04
YT
617ON_ERROR:\r
618 Ip6CleanService (IpSb);\r
619 FreePool (IpSb);\r
a3bcde70
HT
620 return Status;\r
621}\r
622\r
216f7970 623/**\r
624 Callback function which provided by user to remove one node in NetDestroyLinkList process.\r
625 \r
626 @param[in] Entry The entry to be removed.\r
627 @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList.\r
628\r
629 @retval EFI_SUCCESS The entry has been removed successfully.\r
630 @retval Others Fail to remove the entry.\r
631\r
632**/\r
633EFI_STATUS\r
1f7eb561 634EFIAPI\r
216f7970 635Ip6DestroyChildEntryInHandleBuffer (\r
636 IN LIST_ENTRY *Entry,\r
637 IN VOID *Context\r
1f7eb561 638 )\r
216f7970 639{\r
640 IP6_PROTOCOL *IpInstance;\r
641 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;\r
642 UINTN NumberOfChildren;\r
643 EFI_HANDLE *ChildHandleBuffer;\r
644\r
645 if (Entry == NULL || Context == NULL) {\r
646 return EFI_INVALID_PARAMETER;\r
647 }\r
648\r
649 IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP6_PROTOCOL, Link, IP6_PROTOCOL_SIGNATURE);\r
650 ServiceBinding = ((IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;\r
651 NumberOfChildren = ((IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;\r
652 ChildHandleBuffer = ((IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;\r
653\r
654 if (!NetIsInHandleBuffer (IpInstance->Handle, NumberOfChildren, ChildHandleBuffer)) {\r
655 return EFI_SUCCESS;\r
656 }\r
657\r
658 return ServiceBinding->DestroyChild (ServiceBinding, IpInstance->Handle);\r
659}\r
660\r
a3bcde70
HT
661/**\r
662 Stop this driver on ControllerHandle.\r
663\r
664 @param[in] This Protocol instance pointer.\r
665 @param[in] ControllerHandle Handle of device to stop driver on.\r
666 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number\r
667 of children is zero, stop the entire bus driver.\r
668 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
669 if NumberOfChildren is 0.\r
670\r
671 @retval EFI_SUCCESS The device was stopped.\r
672 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
673\r
674**/\r
675EFI_STATUS\r
676EFIAPI\r
677Ip6DriverBindingStop (\r
678 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
679 IN EFI_HANDLE ControllerHandle,\r
680 IN UINTN NumberOfChildren,\r
681 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL\r
682 )\r
683{\r
216f7970 684 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;\r
685 IP6_SERVICE *IpSb;\r
686 EFI_HANDLE NicHandle;\r
687 EFI_STATUS Status;\r
688 LIST_ENTRY *List;\r
689 INTN State;\r
690 BOOLEAN IsDhcp6;\r
691 IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;\r
a3bcde70
HT
692\r
693 IsDhcp6 = FALSE;\r
216f7970 694 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);\r
695 if (NicHandle == NULL) {\r
696 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp6ProtocolGuid);\r
697 if (NicHandle != NULL) {\r
698 IsDhcp6 = TRUE;\r
699 } else {\r
700 return EFI_SUCCESS;\r
a3bcde70
HT
701 }\r
702 }\r
703\r
704 Status = gBS->OpenProtocol (\r
705 NicHandle,\r
706 &gEfiIp6ServiceBindingProtocolGuid,\r
707 (VOID **) &ServiceBinding,\r
708 This->DriverBindingHandle,\r
709 NicHandle,\r
710 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
711 );\r
712 if (EFI_ERROR (Status)) {\r
713 return EFI_DEVICE_ERROR;\r
714 }\r
715\r
716 IpSb = IP6_SERVICE_FROM_PROTOCOL (ServiceBinding);\r
717\r
a3bcde70 718 if (IsDhcp6) {\r
a3bcde70
HT
719 Status = Ip6ConfigDestroyDhcp6 (&IpSb->Ip6ConfigInstance);\r
720 gBS->CloseEvent (IpSb->Ip6ConfigInstance.Dhcp6Event);\r
721 IpSb->Ip6ConfigInstance.Dhcp6Event = NULL;\r
216f7970 722 } else if (NumberOfChildren != 0) {\r
723 //\r
724 // NumberOfChildren is not zero, destroy the IP6 children instances in ChildHandleBuffer.\r
725 //\r
726 List = &IpSb->Children;\r
727 Context.ServiceBinding = ServiceBinding;\r
728 Context.NumberOfChildren = NumberOfChildren;\r
729 Context.ChildHandleBuffer = ChildHandleBuffer;\r
730 Status = NetDestroyLinkList (\r
731 List,\r
732 Ip6DestroyChildEntryInHandleBuffer,\r
733 &Context,\r
734 NULL\r
735 );\r
736 } else if (IsListEmpty (&IpSb->Children)) {\r
a3bcde70
HT
737 State = IpSb->State;\r
738 IpSb->State = IP6_SERVICE_DESTROY;\r
739\r
a3bcde70
HT
740 Status = Ip6CleanService (IpSb);\r
741 if (EFI_ERROR (Status)) {\r
742 IpSb->State = State;\r
743 goto Exit;\r
744 }\r
745\r
746 Status = gBS->UninstallMultipleProtocolInterfaces (\r
747 NicHandle,\r
748 &gEfiIp6ServiceBindingProtocolGuid,\r
749 ServiceBinding,\r
750 &gEfiIp6ConfigProtocolGuid,\r
751 &IpSb->Ip6ConfigInstance.Ip6Config,\r
752 NULL\r
753 );\r
754 ASSERT_EFI_ERROR (Status);\r
755 FreePool (IpSb);\r
216f7970 756 Status = EFI_SUCCESS;\r
a3bcde70 757 }\r
216f7970 758 \r
a3bcde70 759Exit:\r
a3bcde70
HT
760 return Status;\r
761}\r
762\r
763\r
764/**\r
765 Creates a child handle with a set of I/O services.\r
766\r
767 @param[in] This Protocol instance pointer.\r
768 @param[in] ChildHandle Pointer to the handle of the child to create. If\r
769 it is NULL, then a new handle is created. If it\r
770 is not NULL, then the I/O services are added to\r
771 the existing child handle.\r
772\r
773 @retval EFI_SUCCES The child handle was created with the I/O services.\r
774 @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create\r
775 the child.\r
776 @retval other The child handle was not created.\r
777\r
778**/\r
779EFI_STATUS\r
780EFIAPI\r
781Ip6ServiceBindingCreateChild (\r
782 IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
783 IN EFI_HANDLE *ChildHandle\r
784 )\r
785{\r
786 IP6_SERVICE *IpSb;\r
787 IP6_PROTOCOL *IpInstance;\r
788 EFI_TPL OldTpl;\r
789 EFI_STATUS Status;\r
790 VOID *Mnp;\r
791\r
792 if ((This == NULL) || (ChildHandle == NULL)) {\r
793 return EFI_INVALID_PARAMETER;\r
794 }\r
795\r
796 IpSb = IP6_SERVICE_FROM_PROTOCOL (This);\r
797\r
798 if (IpSb->LinkLocalDadFail) {\r
799 return EFI_DEVICE_ERROR;\r
800 }\r
801\r
802 IpInstance = AllocatePool (sizeof (IP6_PROTOCOL));\r
803\r
804 if (IpInstance == NULL) {\r
805 return EFI_OUT_OF_RESOURCES;\r
806 }\r
807\r
808 Ip6InitProtocol (IpSb, IpInstance);\r
809\r
810 //\r
811 // Install Ip6 onto ChildHandle\r
812 //\r
813 Status = gBS->InstallMultipleProtocolInterfaces (\r
814 ChildHandle,\r
815 &gEfiIp6ProtocolGuid,\r
816 &IpInstance->Ip6Proto,\r
817 NULL\r
818 );\r
819 if (EFI_ERROR (Status)) {\r
820 goto ON_ERROR;\r
821 }\r
822\r
823 IpInstance->Handle = *ChildHandle;\r
824\r
825 //\r
826 // Open the Managed Network protocol BY_CHILD.\r
827 //\r
828 Status = gBS->OpenProtocol (\r
829 IpSb->MnpChildHandle,\r
830 &gEfiManagedNetworkProtocolGuid,\r
831 (VOID **) &Mnp,\r
832 gIp6DriverBinding.DriverBindingHandle,\r
833 IpInstance->Handle,\r
834 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
835 );\r
836 if (EFI_ERROR (Status)) {\r
837 gBS->UninstallMultipleProtocolInterfaces (\r
838 ChildHandle,\r
839 &gEfiIp6ProtocolGuid,\r
840 &IpInstance->Ip6Proto,\r
841 NULL\r
842 );\r
843\r
844 goto ON_ERROR;\r
845 }\r
846\r
847 //\r
848 // Insert it into the service binding instance.\r
849 //\r
850 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
851\r
852 InsertTailList (&IpSb->Children, &IpInstance->Link);\r
853 IpSb->NumChildren++;\r
854\r
855 gBS->RestoreTPL (OldTpl);\r
856\r
857ON_ERROR:\r
858\r
859 if (EFI_ERROR (Status)) {\r
860\r
861 Ip6CleanProtocol (IpInstance);\r
862\r
863 FreePool (IpInstance);\r
864 }\r
865\r
866 return Status;\r
867}\r
868\r
869/**\r
870 Destroys a child handle with a set of I/O services.\r
871\r
872 @param[in] This Protocol instance pointer.\r
873 @param[in] ChildHandle Handle of the child to destroy.\r
874\r
875 @retval EFI_SUCCES The I/O services were removed from the child\r
876 handle.\r
877 @retval EFI_UNSUPPORTED The child handle does not support the I/O services\r
878 that are being removed.\r
15ee13fc 879 @retval EFI_INVALID_PARAMETER Child handle is NULL.\r
a3bcde70
HT
880 @retval EFI_ACCESS_DENIED The child handle could not be destroyed because\r
881 its I/O services are being used.\r
882 @retval other The child handle was not destroyed.\r
883\r
884**/\r
885EFI_STATUS\r
886EFIAPI\r
887Ip6ServiceBindingDestroyChild (\r
888 IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
889 IN EFI_HANDLE ChildHandle\r
890 )\r
891{\r
892 EFI_STATUS Status;\r
893 IP6_SERVICE *IpSb;\r
894 IP6_PROTOCOL *IpInstance;\r
895 EFI_IP6_PROTOCOL *Ip6;\r
896 EFI_TPL OldTpl;\r
a3bcde70
HT
897\r
898 if ((This == NULL) || (ChildHandle == NULL)) {\r
899 return EFI_INVALID_PARAMETER;\r
900 }\r
901\r
902 //\r
903 // Retrieve the private context data structures\r
904 //\r
905 IpSb = IP6_SERVICE_FROM_PROTOCOL (This);\r
906\r
907 Status = gBS->OpenProtocol (\r
908 ChildHandle,\r
909 &gEfiIp6ProtocolGuid,\r
910 (VOID **) &Ip6,\r
911 gIp6DriverBinding.DriverBindingHandle,\r
912 ChildHandle,\r
913 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
914 );\r
915\r
916 if (EFI_ERROR (Status)) {\r
917 return EFI_UNSUPPORTED;\r
918 }\r
919\r
920 IpInstance = IP6_INSTANCE_FROM_PROTOCOL (Ip6);\r
921\r
922 if (IpInstance->Service != IpSb) {\r
923 return EFI_INVALID_PARAMETER;\r
924 }\r
925\r
926 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
927\r
928 //\r
929 // A child can be destroyed more than once. For example,\r
75dce340 930 // Ip6DriverBindingStop will destroy all of its children.\r
931 // when UDP driver is being stopped, it will destroy all\r
a3bcde70
HT
932 // the IP child it opens.\r
933 //\r
216f7970 934 if (IpInstance->InDestroy) {\r
a3bcde70
HT
935 gBS->RestoreTPL (OldTpl);\r
936 return EFI_SUCCESS;\r
937 }\r
938\r
216f7970 939 IpInstance->InDestroy = TRUE;\r
a3bcde70
HT
940\r
941 //\r
942 // Close the Managed Network protocol.\r
943 //\r
944 gBS->CloseProtocol (\r
945 IpSb->MnpChildHandle,\r
946 &gEfiManagedNetworkProtocolGuid,\r
947 gIp6DriverBinding.DriverBindingHandle,\r
948 ChildHandle\r
949 );\r
950\r
951 //\r
952 // Uninstall the IP6 protocol first. Many thing happens during\r
953 // this:\r
954 // 1. The consumer of the IP6 protocol will be stopped if it\r
955 // opens the protocol BY_DRIVER. For eaxmple, if MNP driver is\r
956 // stopped, IP driver's stop function will be called, and uninstall\r
957 // EFI_IP6_PROTOCOL will trigger the UDP's stop function. This\r
958 // makes it possible to create the network stack bottom up, and\r
959 // stop it top down.\r
960 // 2. the upper layer will recycle the received packet. The recycle\r
961 // event's TPL is higher than this function. The recycle events\r
962 // will be called back before preceeding. If any packets not recycled,\r
963 // that means there is a resource leak.\r
964 //\r
216f7970 965 gBS->RestoreTPL (OldTpl);\r
a3bcde70
HT
966 Status = gBS->UninstallProtocolInterface (\r
967 ChildHandle,\r
968 &gEfiIp6ProtocolGuid,\r
969 &IpInstance->Ip6Proto\r
970 );\r
216f7970 971 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
a3bcde70
HT
972 if (EFI_ERROR (Status)) {\r
973 goto ON_ERROR;\r
974 }\r
975\r
976 Status = Ip6CleanProtocol (IpInstance);\r
a3bcde70
HT
977 if (EFI_ERROR (Status)) {\r
978 gBS->InstallMultipleProtocolInterfaces (\r
979 &ChildHandle,\r
980 &gEfiIp6ProtocolGuid,\r
981 Ip6,\r
982 NULL\r
983 );\r
984\r
985 goto ON_ERROR;\r
986 }\r
987\r
988 RemoveEntryList (&IpInstance->Link);\r
989 ASSERT (IpSb->NumChildren > 0);\r
990 IpSb->NumChildren--;\r
991\r
992 gBS->RestoreTPL (OldTpl);\r
993\r
994 FreePool (IpInstance);\r
995 return EFI_SUCCESS;\r
996\r
997ON_ERROR:\r
a3bcde70
HT
998 gBS->RestoreTPL (OldTpl);\r
999\r
1000 return Status;\r
1001}\r