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