]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / NetworkPkg / Ip6Dxe / Ip6ConfigImpl.c
... / ...
CommitLineData
1/** @file\r
2 The implementation of EFI IPv6 Configuration Protocol.\r
3\r
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
5 Copyright (c) Microsoft Corporation.<BR>\r
6\r
7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
8\r
9**/\r
10\r
11#include "Ip6Impl.h"\r
12\r
13LIST_ENTRY mIp6ConfigInstanceList = {&mIp6ConfigInstanceList, &mIp6ConfigInstanceList};\r
14\r
15/**\r
16 The event process routine when the DHCPv6 service binding protocol is installed\r
17 in the system.\r
18\r
19 @param[in] Event Not used.\r
20 @param[in] Context Pointer to the IP6 config instance data.\r
21\r
22**/\r
23VOID\r
24EFIAPI\r
25Ip6ConfigOnDhcp6SbInstalled (\r
26 IN EFI_EVENT Event,\r
27 IN VOID *Context\r
28 );\r
29\r
30/**\r
31 Update the current policy to NewPolicy. During the transition\r
32 period, the default router list, on-link prefix list, autonomous prefix list\r
33 and address list in all interfaces will be released.\r
34\r
35 @param[in] IpSb The IP6 service binding instance.\r
36 @param[in] NewPolicy The new policy to be updated to.\r
37\r
38**/\r
39VOID\r
40Ip6ConfigOnPolicyChanged (\r
41 IN IP6_SERVICE *IpSb,\r
42 IN EFI_IP6_CONFIG_POLICY NewPolicy\r
43 )\r
44{\r
45 LIST_ENTRY *Entry;\r
46 LIST_ENTRY *Entry2;\r
47 LIST_ENTRY *Next;\r
48 IP6_INTERFACE *IpIf;\r
49 IP6_DAD_ENTRY *DadEntry;\r
50 IP6_DELAY_JOIN_LIST *DelayNode;\r
51 IP6_ADDRESS_INFO *AddrInfo;\r
52 IP6_PROTOCOL *Instance;\r
53 BOOLEAN Recovery;\r
54\r
55 Recovery = FALSE;\r
56\r
57 //\r
58 // Currently there are only two policies: Manual and Automatic. Regardless of\r
59 // what transition is going on, i.e., Manual -> Automatic and Automatic ->\r
60 // Manual, we have to free default router list, on-link prefix list, autonomous\r
61 // prefix list, address list in all the interfaces and destroy any IPv6 child\r
62 // instance whose local IP is neither 0 nor the link-local address.\r
63 //\r
64 Ip6CleanDefaultRouterList (IpSb);\r
65 Ip6CleanPrefixListTable (IpSb, &IpSb->OnlinkPrefix);\r
66 Ip6CleanPrefixListTable (IpSb, &IpSb->AutonomousPrefix);\r
67\r
68 //\r
69 // It's tricky... If the LinkLocal address is O.K., add back the link-local\r
70 // prefix to the on-link prefix table.\r
71 //\r
72 if (IpSb->LinkLocalOk) {\r
73 Ip6CreatePrefixListEntry (\r
74 IpSb,\r
75 TRUE,\r
76 (UINT32) IP6_INFINIT_LIFETIME,\r
77 (UINT32) IP6_INFINIT_LIFETIME,\r
78 IP6_LINK_LOCAL_PREFIX_LENGTH,\r
79 &IpSb->LinkLocalAddr\r
80 );\r
81 }\r
82\r
83 if (!IsListEmpty (&IpSb->DefaultInterface->AddressList) && IpSb->DefaultInterface->AddressCount > 0) {\r
84 //\r
85 // If any IPv6 children (Instance) in configured state and use global unicast address, it will be\r
86 // destroyed in Ip6RemoveAddr() function later. Then, the upper layer driver's Stop() function will be\r
87 // called, which may break the upper layer network stacks. So, the driver should take the responsibility\r
88 // for the recovery by using ConnectController() after Ip6RemoveAddr().\r
89 // Here, just check whether need to recover the upper layer network stacks later.\r
90 //\r
91 NET_LIST_FOR_EACH (Entry, &IpSb->DefaultInterface->AddressList) {\r
92 AddrInfo = NET_LIST_USER_STRUCT_S (Entry, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);\r
93 if (!IsListEmpty (&IpSb->Children)) {\r
94 NET_LIST_FOR_EACH (Entry2, &IpSb->Children) {\r
95 Instance = NET_LIST_USER_STRUCT_S (Entry2, IP6_PROTOCOL, Link, IP6_PROTOCOL_SIGNATURE);\r
96 if ((Instance->State == IP6_STATE_CONFIGED) && EFI_IP6_EQUAL (&Instance->ConfigData.StationAddress, &AddrInfo->Address)) {\r
97 Recovery = TRUE;\r
98 break;\r
99 }\r
100 }\r
101 }\r
102 }\r
103\r
104 //\r
105 // All IPv6 children that use global unicast address as its source address\r
106 // should be destroyed now. The survivers are those use the link-local address\r
107 // or the unspecified address as the source address.\r
108 // TODO: Conduct a check here.\r
109 Ip6RemoveAddr (\r
110 IpSb,\r
111 &IpSb->DefaultInterface->AddressList,\r
112 &IpSb->DefaultInterface->AddressCount,\r
113 NULL,\r
114 0\r
115 );\r
116\r
117 if (IpSb->Controller != NULL && Recovery) {\r
118 //\r
119 // ConnectController() to recover the upper layer network stacks.\r
120 //\r
121 gBS->ConnectController (IpSb->Controller, NULL, NULL, TRUE);\r
122 }\r
123 }\r
124\r
125\r
126 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
127 //\r
128 // remove all pending delay node and DAD entries for the global addresses.\r
129 //\r
130 IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);\r
131\r
132 NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DelayJoinList) {\r
133 DelayNode = NET_LIST_USER_STRUCT (Entry2, IP6_DELAY_JOIN_LIST, Link);\r
134 if (!NetIp6IsLinkLocalAddr (&DelayNode->AddressInfo->Address)) {\r
135 RemoveEntryList (&DelayNode->Link);\r
136 FreePool (DelayNode);\r
137 }\r
138 }\r
139\r
140 NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DupAddrDetectList) {\r
141 DadEntry = NET_LIST_USER_STRUCT_S (Entry2, IP6_DAD_ENTRY, Link, IP6_DAD_ENTRY_SIGNATURE);\r
142\r
143 if (!NetIp6IsLinkLocalAddr (&DadEntry->AddressInfo->Address)) {\r
144 //\r
145 // Fail this DAD entry if the address is not link-local.\r
146 //\r
147 Ip6OnDADFinished (FALSE, IpIf, DadEntry);\r
148 }\r
149 }\r
150 }\r
151\r
152 if (NewPolicy == Ip6ConfigPolicyAutomatic) {\r
153 //\r
154 // Set parameters to trigger router solicitation sending in timer handler.\r
155 //\r
156 IpSb->RouterAdvertiseReceived = FALSE;\r
157 IpSb->SolicitTimer = IP6_MAX_RTR_SOLICITATIONS;\r
158 //\r
159 // delay 1 second\r
160 //\r
161 IpSb->Ticks = (UINT32) IP6_GET_TICKS (IP6_ONE_SECOND_IN_MS);\r
162 }\r
163}\r
164\r
165/**\r
166 The work function to trigger the DHCPv6 process to perform a stateful autoconfiguration.\r
167\r
168 @param[in] Instance Pointer to the IP6 config instance data.\r
169 @param[in] OtherInfoOnly If FALSE, get stateful address and other information\r
170 via DHCPv6. Otherwise, only get the other information.\r
171\r
172 @retval EFI_SUCCESS The operation finished successfully.\r
173 @retval EFI_UNSUPPORTED The DHCP6 driver is not available.\r
174\r
175**/\r
176EFI_STATUS\r
177Ip6ConfigStartStatefulAutoConfig (\r
178 IN IP6_CONFIG_INSTANCE *Instance,\r
179 IN BOOLEAN OtherInfoOnly\r
180 )\r
181{\r
182 EFI_STATUS Status;\r
183 IP6_SERVICE *IpSb;\r
184 EFI_DHCP6_CONFIG_DATA Dhcp6CfgData;\r
185 EFI_DHCP6_PROTOCOL *Dhcp6;\r
186 EFI_DHCP6_PACKET_OPTION *OptList[1];\r
187 UINT16 OptBuf[4];\r
188 EFI_DHCP6_PACKET_OPTION *Oro;\r
189 EFI_DHCP6_RETRANSMISSION InfoReqReXmit;\r
190\r
191 //\r
192 // A host must not invoke stateful address configuration if it is already\r
193 // participating in the statuful protocol as a result of an earlier advertisement.\r
194 //\r
195 if (Instance->Dhcp6Handle != NULL) {\r
196 return EFI_SUCCESS;\r
197 }\r
198\r
199 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
200\r
201 Instance->OtherInfoOnly = OtherInfoOnly;\r
202\r
203 Status = NetLibCreateServiceChild (\r
204 IpSb->Controller,\r
205 IpSb->Image,\r
206 &gEfiDhcp6ServiceBindingProtocolGuid,\r
207 &Instance->Dhcp6Handle\r
208 );\r
209\r
210 if (Status == EFI_UNSUPPORTED) {\r
211 //\r
212 // No DHCPv6 Service Binding protocol, register a notify.\r
213 //\r
214 if (Instance->Dhcp6SbNotifyEvent == NULL) {\r
215 Instance->Dhcp6SbNotifyEvent = EfiCreateProtocolNotifyEvent (\r
216 &gEfiDhcp6ServiceBindingProtocolGuid,\r
217 TPL_CALLBACK,\r
218 Ip6ConfigOnDhcp6SbInstalled,\r
219 (VOID *) Instance,\r
220 &Instance->Registration\r
221 );\r
222 }\r
223 }\r
224\r
225 if (EFI_ERROR (Status)) {\r
226 return Status;\r
227 }\r
228\r
229 if (Instance->Dhcp6SbNotifyEvent != NULL) {\r
230 gBS->CloseEvent (Instance->Dhcp6SbNotifyEvent);\r
231 }\r
232\r
233 Status = gBS->OpenProtocol (\r
234 Instance->Dhcp6Handle,\r
235 &gEfiDhcp6ProtocolGuid,\r
236 (VOID **) &Instance->Dhcp6,\r
237 IpSb->Image,\r
238 IpSb->Controller,\r
239 EFI_OPEN_PROTOCOL_BY_DRIVER\r
240 );\r
241 ASSERT_EFI_ERROR (Status);\r
242\r
243 Dhcp6 = Instance->Dhcp6;\r
244 Dhcp6->Configure (Dhcp6, NULL);\r
245\r
246 //\r
247 // Set the exta options to send. Here we only want the option request option\r
248 // with DNS SERVERS.\r
249 //\r
250 Oro = (EFI_DHCP6_PACKET_OPTION *) OptBuf;\r
251 Oro->OpCode = HTONS (DHCP6_OPT_ORO);\r
252 Oro->OpLen = HTONS (2);\r
253 *((UINT16 *) &Oro->Data[0]) = HTONS (DHCP6_OPT_DNS_SERVERS);\r
254 OptList[0] = Oro;\r
255\r
256 Status = EFI_SUCCESS;\r
257\r
258 if (!OtherInfoOnly) {\r
259 //\r
260 // Get stateful address and other information via DHCPv6.\r
261 //\r
262 Dhcp6CfgData.Dhcp6Callback = NULL;\r
263 Dhcp6CfgData.CallbackContext = NULL;\r
264 Dhcp6CfgData.OptionCount = 1;\r
265 Dhcp6CfgData.OptionList = &OptList[0];\r
266 Dhcp6CfgData.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA;\r
267 Dhcp6CfgData.IaDescriptor.IaId = Instance->IaId;\r
268 Dhcp6CfgData.IaInfoEvent = Instance->Dhcp6Event;\r
269 Dhcp6CfgData.ReconfigureAccept = FALSE;\r
270 Dhcp6CfgData.RapidCommit = FALSE;\r
271 Dhcp6CfgData.SolicitRetransmission = NULL;\r
272\r
273 Status = Dhcp6->Configure (Dhcp6, &Dhcp6CfgData);\r
274\r
275 if (!EFI_ERROR (Status)) {\r
276\r
277 if (IpSb->LinkLocalOk) {\r
278 Status = Dhcp6->Start (Dhcp6);\r
279 } else {\r
280 IpSb->Dhcp6NeedStart = TRUE;\r
281 }\r
282\r
283 }\r
284 } else {\r
285 //\r
286 // Only get other information via DHCPv6, this doesn't require a config\r
287 // action.\r
288 //\r
289 InfoReqReXmit.Irt = 4;\r
290 InfoReqReXmit.Mrc = 64;\r
291 InfoReqReXmit.Mrt = 60;\r
292 InfoReqReXmit.Mrd = 0;\r
293\r
294 if (IpSb->LinkLocalOk) {\r
295 Status = Dhcp6->InfoRequest (\r
296 Dhcp6,\r
297 TRUE,\r
298 Oro,\r
299 0,\r
300 NULL,\r
301 &InfoReqReXmit,\r
302 Instance->Dhcp6Event,\r
303 Ip6ConfigOnDhcp6Reply,\r
304 Instance\r
305 );\r
306 } else {\r
307 IpSb->Dhcp6NeedInfoRequest = TRUE;\r
308 }\r
309\r
310 }\r
311\r
312 return Status;\r
313}\r
314\r
315/**\r
316 Signal the registered event. It is the callback routine for NetMapIterate.\r
317\r
318 @param[in] Map Points to the list of registered event.\r
319 @param[in] Item The registered event.\r
320 @param[in] Arg Not used.\r
321\r
322**/\r
323EFI_STATUS\r
324EFIAPI\r
325Ip6ConfigSignalEvent (\r
326 IN NET_MAP *Map,\r
327 IN NET_MAP_ITEM *Item,\r
328 IN VOID *Arg\r
329 )\r
330{\r
331 gBS->SignalEvent ((EFI_EVENT) Item->Key);\r
332\r
333 return EFI_SUCCESS;\r
334}\r
335\r
336/**\r
337 Read the configuration data from variable storage according to the VarName and\r
338 gEfiIp6ConfigProtocolGuid. It checks the integrity of variable data. If the\r
339 data is corrupted, it clears the variable data to ZERO. Otherwise, it outputs the\r
340 configuration data to IP6_CONFIG_INSTANCE.\r
341\r
342 @param[in] VarName The pointer to the variable name\r
343 @param[in, out] Instance The pointer to the IP6 config instance data.\r
344\r
345 @retval EFI_NOT_FOUND The variable can not be found or already corrupted.\r
346 @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete the operation.\r
347 @retval EFI_SUCCESS The configuration data was retrieved successfully.\r
348\r
349**/\r
350EFI_STATUS\r
351Ip6ConfigReadConfigData (\r
352 IN CHAR16 *VarName,\r
353 IN OUT IP6_CONFIG_INSTANCE *Instance\r
354 )\r
355{\r
356 EFI_STATUS Status;\r
357 UINTN VarSize;\r
358 IP6_CONFIG_VARIABLE *Variable;\r
359 IP6_CONFIG_DATA_ITEM *DataItem;\r
360 UINTN Index;\r
361 IP6_CONFIG_DATA_RECORD DataRecord;\r
362 CHAR8 *Data;\r
363\r
364 //\r
365 // Try to read the configuration variable.\r
366 //\r
367 VarSize = 0;\r
368 Status = gRT->GetVariable (\r
369 VarName,\r
370 &gEfiIp6ConfigProtocolGuid,\r
371 NULL,\r
372 &VarSize,\r
373 NULL\r
374 );\r
375\r
376 if (Status == EFI_BUFFER_TOO_SMALL) {\r
377 //\r
378 // Allocate buffer and read the config variable.\r
379 //\r
380 Variable = AllocatePool (VarSize);\r
381 if (Variable == NULL) {\r
382 return EFI_OUT_OF_RESOURCES;\r
383 }\r
384\r
385 Status = gRT->GetVariable (\r
386 VarName,\r
387 &gEfiIp6ConfigProtocolGuid,\r
388 NULL,\r
389 &VarSize,\r
390 Variable\r
391 );\r
392 if (EFI_ERROR (Status) || (UINT16) (~NetblockChecksum ((UINT8 *) Variable, (UINT32) VarSize)) != 0) {\r
393 //\r
394 // GetVariable error or the variable is corrupted.\r
395 //\r
396 goto Error;\r
397 }\r
398\r
399 //\r
400 // Get the IAID we use.\r
401 //\r
402 Instance->IaId = Variable->IaId;\r
403\r
404 for (Index = 0; Index < Variable->DataRecordCount; Index++) {\r
405\r
406 CopyMem (&DataRecord, &Variable->DataRecord[Index], sizeof (DataRecord));\r
407\r
408 DataItem = &Instance->DataItem[DataRecord.DataType];\r
409 if (DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED) &&\r
410 (DataItem->DataSize != DataRecord.DataSize)\r
411 ) {\r
412 //\r
413 // Perhaps a corrupted data record...\r
414 //\r
415 continue;\r
416 }\r
417\r
418 if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED)) {\r
419 //\r
420 // This data item has variable length data.\r
421 // Check that the length is contained within the variable before allocating.\r
422 //\r
423 if (DataRecord.DataSize > VarSize - DataRecord.Offset) {\r
424 goto Error;\r
425 }\r
426\r
427 DataItem->Data.Ptr = AllocatePool (DataRecord.DataSize);\r
428 if (DataItem->Data.Ptr == NULL) {\r
429 //\r
430 // no memory resource\r
431 //\r
432 continue;\r
433 }\r
434 }\r
435\r
436 Data = (CHAR8 *) Variable + DataRecord.Offset;\r
437 CopyMem (DataItem->Data.Ptr, Data, DataRecord.DataSize);\r
438\r
439 DataItem->DataSize = DataRecord.DataSize;\r
440 DataItem->Status = EFI_SUCCESS;\r
441 }\r
442\r
443 FreePool (Variable);\r
444 return EFI_SUCCESS;\r
445 }\r
446\r
447 return Status;\r
448\r
449Error:\r
450 //\r
451 // Fall back to the default value.\r
452 //\r
453 if (Variable != NULL) {\r
454 FreePool (Variable);\r
455 }\r
456\r
457 //\r
458 // Remove the problematic variable and return EFI_NOT_FOUND, a new\r
459 // variable will be set again.\r
460 //\r
461 gRT->SetVariable (\r
462 VarName,\r
463 &gEfiIp6ConfigProtocolGuid,\r
464 IP6_CONFIG_VARIABLE_ATTRIBUTE,\r
465 0,\r
466 NULL\r
467 );\r
468\r
469 return EFI_NOT_FOUND;\r
470}\r
471\r
472/**\r
473 Write the configuration data from IP6_CONFIG_INSTANCE to variable storage.\r
474\r
475 @param[in] VarName The pointer to the variable name.\r
476 @param[in] Instance The pointer to the IP6 configuration instance data.\r
477\r
478 @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete the operation.\r
479 @retval EFI_SUCCESS The configuration data is written successfully.\r
480\r
481**/\r
482EFI_STATUS\r
483Ip6ConfigWriteConfigData (\r
484 IN CHAR16 *VarName,\r
485 IN IP6_CONFIG_INSTANCE *Instance\r
486 )\r
487{\r
488 UINTN Index;\r
489 UINTN VarSize;\r
490 IP6_CONFIG_DATA_ITEM *DataItem;\r
491 IP6_CONFIG_VARIABLE *Variable;\r
492 IP6_CONFIG_DATA_RECORD *DataRecord;\r
493 CHAR8 *Heap;\r
494 EFI_STATUS Status;\r
495\r
496 VarSize = sizeof (IP6_CONFIG_VARIABLE) - sizeof (IP6_CONFIG_DATA_RECORD);\r
497\r
498 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {\r
499\r
500 DataItem = &Instance->DataItem[Index];\r
501 if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_VOLATILE) && !EFI_ERROR (DataItem->Status)) {\r
502\r
503 VarSize += sizeof (IP6_CONFIG_DATA_RECORD) + DataItem->DataSize;\r
504 }\r
505 }\r
506\r
507 Variable = AllocatePool (VarSize);\r
508 if (Variable == NULL) {\r
509 return EFI_OUT_OF_RESOURCES;\r
510 }\r
511\r
512 Variable->IaId = Instance->IaId;\r
513 Heap = (CHAR8 *) Variable + VarSize;\r
514 Variable->DataRecordCount = 0;\r
515\r
516 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {\r
517\r
518 DataItem = &Instance->DataItem[Index];\r
519 if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_VOLATILE) && !EFI_ERROR (DataItem->Status)) {\r
520\r
521 Heap -= DataItem->DataSize;\r
522 CopyMem (Heap, DataItem->Data.Ptr, DataItem->DataSize);\r
523\r
524 DataRecord = &Variable->DataRecord[Variable->DataRecordCount];\r
525 DataRecord->DataType = (EFI_IP6_CONFIG_DATA_TYPE) Index;\r
526 DataRecord->DataSize = (UINT32) DataItem->DataSize;\r
527 DataRecord->Offset = (UINT16) (Heap - (CHAR8 *) Variable);\r
528\r
529 Variable->DataRecordCount++;\r
530 }\r
531 }\r
532\r
533 Variable->Checksum = 0;\r
534 Variable->Checksum = (UINT16) ~NetblockChecksum ((UINT8 *) Variable, (UINT32) VarSize);\r
535\r
536 Status = gRT->SetVariable (\r
537 VarName,\r
538 &gEfiIp6ConfigProtocolGuid,\r
539 IP6_CONFIG_VARIABLE_ATTRIBUTE,\r
540 VarSize,\r
541 Variable\r
542 );\r
543\r
544 FreePool (Variable);\r
545\r
546 return Status;\r
547}\r
548\r
549/**\r
550 The work function for EfiIp6ConfigGetData() to get the interface information\r
551 of the communication device this IP6Config instance manages.\r
552\r
553 @param[in] Instance Pointer to the IP6 config instance data.\r
554 @param[in, out] DataSize On input, in bytes, the size of Data. On output, in\r
555 bytes, the size of buffer required to store the specified\r
556 configuration data.\r
557 @param[in] Data The data buffer in which the configuration data is returned.\r
558 Ignored if DataSize is ZERO.\r
559\r
560 @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified\r
561 configuration data, and the required size is\r
562 returned in DataSize.\r
563 @retval EFI_SUCCESS The specified configuration data was obtained.\r
564\r
565**/\r
566EFI_STATUS\r
567Ip6ConfigGetIfInfo (\r
568 IN IP6_CONFIG_INSTANCE *Instance,\r
569 IN OUT UINTN *DataSize,\r
570 IN VOID *Data OPTIONAL\r
571 )\r
572{\r
573 IP6_SERVICE *IpSb;\r
574 UINTN Length;\r
575 IP6_CONFIG_DATA_ITEM *Item;\r
576 EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo;\r
577 UINT32 AddressCount;\r
578 UINT32 RouteCount;\r
579\r
580 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
581 Length = sizeof (EFI_IP6_CONFIG_INTERFACE_INFO);\r
582\r
583 //\r
584 // Calculate the required length, add the buffer size for AddressInfo and\r
585 // RouteTable\r
586 //\r
587 Ip6BuildEfiAddressList (IpSb, &AddressCount, NULL);\r
588 Ip6BuildEfiRouteTable (IpSb->RouteTable, &RouteCount, NULL);\r
589\r
590 Length += AddressCount * sizeof (EFI_IP6_ADDRESS_INFO) + RouteCount * sizeof (EFI_IP6_ROUTE_TABLE);\r
591\r
592 if (*DataSize < Length) {\r
593 *DataSize = Length;\r
594 return EFI_BUFFER_TOO_SMALL;\r
595 }\r
596\r
597 //\r
598 // Copy the fixed size part of the interface info.\r
599 //\r
600 Item = &Instance->DataItem[Ip6ConfigDataTypeInterfaceInfo];\r
601 IfInfo = (EFI_IP6_CONFIG_INTERFACE_INFO *) Data;\r
602 CopyMem (IfInfo, Item->Data.Ptr, sizeof (EFI_IP6_CONFIG_INTERFACE_INFO));\r
603\r
604 //\r
605 // AddressInfo\r
606 //\r
607 IfInfo->AddressInfo = (EFI_IP6_ADDRESS_INFO *) (IfInfo + 1);\r
608 Ip6BuildEfiAddressList (IpSb, &IfInfo->AddressInfoCount, &IfInfo->AddressInfo);\r
609\r
610 //\r
611 // RouteTable\r
612 //\r
613 IfInfo->RouteTable = (EFI_IP6_ROUTE_TABLE *) (IfInfo->AddressInfo + IfInfo->AddressInfoCount);\r
614 Ip6BuildEfiRouteTable (IpSb->RouteTable, &IfInfo->RouteCount, &IfInfo->RouteTable);\r
615\r
616 if (IfInfo->AddressInfoCount == 0) {\r
617 IfInfo->AddressInfo = NULL;\r
618 }\r
619\r
620 if (IfInfo->RouteCount == 0) {\r
621 IfInfo->RouteTable = NULL;\r
622 }\r
623\r
624 return EFI_SUCCESS;\r
625}\r
626\r
627/**\r
628 The work function for EfiIp6ConfigSetData() to set the alternative interface ID\r
629 for the communication device managed by this IP6Config instance, if the link local\r
630 IPv6 addresses generated from the interface ID based on the default source the\r
631 EFI IPv6 Protocol uses is a duplicate address.\r
632\r
633 @param[in] Instance Pointer to the IP6 configuration instance data.\r
634 @param[in] DataSize Size of the buffer pointed to by Data in bytes.\r
635 @param[in] Data The data buffer to set.\r
636\r
637 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type,\r
638 8 bytes.\r
639 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
640 network stack was set.\r
641\r
642**/\r
643EFI_STATUS\r
644Ip6ConfigSetAltIfId (\r
645 IN IP6_CONFIG_INSTANCE *Instance,\r
646 IN UINTN DataSize,\r
647 IN VOID *Data\r
648 )\r
649{\r
650 EFI_IP6_CONFIG_INTERFACE_ID *OldIfId;\r
651 EFI_IP6_CONFIG_INTERFACE_ID *NewIfId;\r
652 IP6_CONFIG_DATA_ITEM *DataItem;\r
653\r
654 if (DataSize != sizeof (EFI_IP6_CONFIG_INTERFACE_ID)) {\r
655 return EFI_BAD_BUFFER_SIZE;\r
656 }\r
657\r
658 DataItem = &Instance->DataItem[Ip6ConfigDataTypeAltInterfaceId];\r
659 OldIfId = DataItem->Data.AltIfId;\r
660 NewIfId = (EFI_IP6_CONFIG_INTERFACE_ID *) Data;\r
661\r
662 CopyMem (OldIfId, NewIfId, DataSize);\r
663 DataItem->Status = EFI_SUCCESS;\r
664\r
665 return EFI_SUCCESS;\r
666}\r
667\r
668/**\r
669 The work function for EfiIp6ConfigSetData() to set the general configuration\r
670 policy for the EFI IPv6 network stack that is running on the communication device\r
671 managed by this IP6Config instance. The policy will affect other configuration settings.\r
672\r
673 @param[in] Instance Pointer to the IP6 config instance data.\r
674 @param[in] DataSize Size of the buffer pointed to by Data in bytes.\r
675 @param[in] Data The data buffer to set.\r
676\r
677 @retval EFI_INVALID_PARAMETER The to be set policy is invalid.\r
678 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.\r
679 @retval EFI_ABORTED The new policy equals the current policy.\r
680 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
681 network stack was set.\r
682\r
683**/\r
684EFI_STATUS\r
685Ip6ConfigSetPolicy (\r
686 IN IP6_CONFIG_INSTANCE *Instance,\r
687 IN UINTN DataSize,\r
688 IN VOID *Data\r
689 )\r
690{\r
691 EFI_IP6_CONFIG_POLICY NewPolicy;\r
692 IP6_CONFIG_DATA_ITEM *DataItem;\r
693 IP6_SERVICE *IpSb;\r
694\r
695 if (DataSize != sizeof (EFI_IP6_CONFIG_POLICY)) {\r
696 return EFI_BAD_BUFFER_SIZE;\r
697 }\r
698\r
699 NewPolicy = *((EFI_IP6_CONFIG_POLICY *) Data);\r
700\r
701 if (NewPolicy > Ip6ConfigPolicyAutomatic) {\r
702 return EFI_INVALID_PARAMETER;\r
703 }\r
704\r
705 if (NewPolicy == Instance->Policy) {\r
706\r
707 return EFI_ABORTED;\r
708 } else {\r
709 //\r
710 // Clean the ManualAddress, Gateway and DnsServers, shrink the variable\r
711 // data size, and fire up all the related events.\r
712 //\r
713 DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];\r
714 if (DataItem->Data.Ptr != NULL) {\r
715 FreePool (DataItem->Data.Ptr);\r
716 }\r
717 DataItem->Data.Ptr = NULL;\r
718 DataItem->DataSize = 0;\r
719 DataItem->Status = EFI_NOT_FOUND;\r
720 NetMapIterate (&DataItem->EventMap, Ip6ConfigSignalEvent, NULL);\r
721\r
722 DataItem = &Instance->DataItem[Ip6ConfigDataTypeGateway];\r
723 if (DataItem->Data.Ptr != NULL) {\r
724 FreePool (DataItem->Data.Ptr);\r
725 }\r
726 DataItem->Data.Ptr = NULL;\r
727 DataItem->DataSize = 0;\r
728 DataItem->Status = EFI_NOT_FOUND;\r
729 NetMapIterate (&DataItem->EventMap, Ip6ConfigSignalEvent, NULL);\r
730\r
731 DataItem = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];\r
732 DataItem->Data.Ptr = NULL;\r
733 DataItem->DataSize = 0;\r
734 DataItem->Status = EFI_NOT_FOUND;\r
735 NetMapIterate (&DataItem->EventMap, Ip6ConfigSignalEvent, NULL);\r
736\r
737 if (NewPolicy == Ip6ConfigPolicyManual) {\r
738 //\r
739 // The policy is changed from automatic to manual. Stop the DHCPv6 process\r
740 // and destroy the DHCPv6 child.\r
741 //\r
742 if (Instance->Dhcp6Handle != NULL) {\r
743 Ip6ConfigDestroyDhcp6 (Instance);\r
744 }\r
745 }\r
746\r
747 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
748 Ip6ConfigOnPolicyChanged (IpSb, NewPolicy);\r
749\r
750 Instance->Policy = NewPolicy;\r
751\r
752 return EFI_SUCCESS;\r
753 }\r
754}\r
755\r
756/**\r
757 The work function for EfiIp6ConfigSetData() to set the number of consecutive\r
758 Neighbor Solicitation messages sent while performing Duplicate Address Detection\r
759 on a tentative address. A value of ZERO indicates that Duplicate Address Detection\r
760 will not be performed on a tentative address.\r
761\r
762 @param[in] Instance The Instance Pointer to the IP6 config instance data.\r
763 @param[in] DataSize Size of the buffer pointed to by Data in bytes.\r
764 @param[in] Data The data buffer to set.\r
765\r
766 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.\r
767 @retval EFI_ABORTED The new transmit count equals the current configuration.\r
768 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
769 network stack was set.\r
770\r
771**/\r
772EFI_STATUS\r
773Ip6ConfigSetDadXmits (\r
774 IN IP6_CONFIG_INSTANCE *Instance,\r
775 IN UINTN DataSize,\r
776 IN VOID *Data\r
777 )\r
778{\r
779 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS *OldDadXmits;\r
780\r
781 if (DataSize != sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS)) {\r
782 return EFI_BAD_BUFFER_SIZE;\r
783 }\r
784\r
785 OldDadXmits = Instance->DataItem[Ip6ConfigDataTypeDupAddrDetectTransmits].Data.DadXmits;\r
786\r
787 if ((*(UINT32 *) Data) == OldDadXmits->DupAddrDetectTransmits) {\r
788\r
789 return EFI_ABORTED;\r
790 } else {\r
791\r
792 OldDadXmits->DupAddrDetectTransmits = *((UINT32 *) Data);\r
793 return EFI_SUCCESS;\r
794 }\r
795}\r
796\r
797/**\r
798 The callback function for Ip6SetAddr. The prototype is defined\r
799 as IP6_DAD_CALLBACK. It is called after Duplicate Address Detection is performed\r
800 for the manual address set by Ip6ConfigSetManualAddress.\r
801\r
802 @param[in] IsDadPassed If TRUE, Duplicate Address Detection passed.\r
803 @param[in] TargetAddress The tentative IPv6 address to be checked.\r
804 @param[in] Context Pointer to the IP6 configuration instance data.\r
805\r
806**/\r
807VOID\r
808Ip6ManualAddrDadCallback (\r
809 IN BOOLEAN IsDadPassed,\r
810 IN EFI_IPv6_ADDRESS *TargetAddress,\r
811 IN VOID *Context\r
812 )\r
813{\r
814 IP6_CONFIG_INSTANCE *Instance;\r
815 UINTN Index;\r
816 IP6_CONFIG_DATA_ITEM *Item;\r
817 EFI_IP6_CONFIG_MANUAL_ADDRESS *ManualAddr;\r
818 EFI_IP6_CONFIG_MANUAL_ADDRESS *PassedAddr;\r
819 UINTN DadPassCount;\r
820 UINTN DadFailCount;\r
821 IP6_SERVICE *IpSb;\r
822\r
823 Instance = (IP6_CONFIG_INSTANCE *) Context;\r
824 NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);\r
825 Item = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];\r
826 ManualAddr = NULL;\r
827\r
828 if (Item->DataSize == 0) {\r
829 return;\r
830 }\r
831\r
832 for (Index = 0; Index < Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS); Index++) {\r
833 //\r
834 // Find the original tag used to place into the NET_MAP.\r
835 //\r
836 ManualAddr = Item->Data.ManualAddress + Index;\r
837 if (EFI_IP6_EQUAL (TargetAddress, &ManualAddr->Address)) {\r
838 break;\r
839 }\r
840 }\r
841\r
842 ASSERT (Index != Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));\r
843\r
844 if (IsDadPassed) {\r
845 NetMapInsertTail (&Instance->DadPassedMap, ManualAddr, NULL);\r
846 } else {\r
847 NetMapInsertTail (&Instance->DadFailedMap, ManualAddr, NULL);\r
848 }\r
849\r
850 DadPassCount = NetMapGetCount (&Instance->DadPassedMap);\r
851 DadFailCount = NetMapGetCount (&Instance->DadFailedMap);\r
852\r
853 if ((DadPassCount + DadFailCount) == (Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS))) {\r
854 //\r
855 // All addresses have finished the configuration process.\r
856 //\r
857 if (DadFailCount != 0) {\r
858 //\r
859 // There is at least one duplicate address.\r
860 //\r
861 FreePool (Item->Data.Ptr);\r
862\r
863 Item->DataSize = DadPassCount * sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);\r
864 if (Item->DataSize == 0) {\r
865 //\r
866 // All failed, bad luck.\r
867 //\r
868 Item->Data.Ptr = NULL;\r
869 Item->Status = EFI_NOT_FOUND;\r
870 } else {\r
871 //\r
872 // Part of addresses are detected to be duplicates, so update the\r
873 // data with those passed.\r
874 //\r
875 PassedAddr = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) AllocatePool (Item->DataSize);\r
876 ASSERT (PassedAddr != NULL);\r
877\r
878 Item->Data.Ptr = PassedAddr;\r
879 Item->Status = EFI_SUCCESS;\r
880\r
881 while (!NetMapIsEmpty (&Instance->DadPassedMap)) {\r
882 ManualAddr = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) NetMapRemoveHead (&Instance->DadPassedMap, NULL);\r
883 CopyMem (PassedAddr, ManualAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));\r
884\r
885 PassedAddr++;\r
886 }\r
887\r
888 ASSERT ((UINTN) PassedAddr - (UINTN) Item->Data.Ptr == Item->DataSize);\r
889 }\r
890 } else {\r
891 //\r
892 // All addresses are valid.\r
893 //\r
894 Item->Status = EFI_SUCCESS;\r
895 }\r
896\r
897 //\r
898 // Remove the tags we put in the NET_MAPs.\r
899 //\r
900 while (!NetMapIsEmpty (&Instance->DadFailedMap)) {\r
901 NetMapRemoveHead (&Instance->DadFailedMap, NULL);\r
902 }\r
903\r
904 while (!NetMapIsEmpty (&Instance->DadPassedMap)) {\r
905 NetMapRemoveHead (&Instance->DadPassedMap, NULL);\r
906 }\r
907\r
908 //\r
909 // Signal the waiting events.\r
910 //\r
911 NetMapIterate (&Item->EventMap, Ip6ConfigSignalEvent, NULL);\r
912 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
913 Ip6ConfigWriteConfigData (IpSb->MacString, Instance);\r
914 }\r
915}\r
916\r
917/**\r
918 The work function for EfiIp6ConfigSetData() to set the station addresses manually\r
919 for the EFI IPv6 network stack. It is only configurable when the policy is\r
920 Ip6ConfigPolicyManual.\r
921\r
922 @param[in] Instance Pointer to the IP6 configuration instance data.\r
923 @param[in] DataSize Size of the buffer pointed to by Data in bytes.\r
924 @param[in] Data The data buffer to set.\r
925\r
926 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.\r
927 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set\r
928 under the current policy.\r
929 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.\r
930 @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete the operation.\r
931 @retval EFI_NOT_READY An asynchronous process is invoked to set the specified\r
932 configuration data, and the process is not finished.\r
933 @retval EFI_ABORTED The manual addresses to be set equal current\r
934 configuration.\r
935 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
936 network stack was set.\r
937\r
938**/\r
939EFI_STATUS\r
940Ip6ConfigSetManualAddress (\r
941 IN IP6_CONFIG_INSTANCE *Instance,\r
942 IN UINTN DataSize,\r
943 IN VOID *Data\r
944 )\r
945{\r
946 EFI_IP6_CONFIG_MANUAL_ADDRESS *NewAddress;\r
947 EFI_IP6_CONFIG_MANUAL_ADDRESS *TmpAddress;\r
948 IP6_CONFIG_DATA_ITEM *DataItem;\r
949 UINTN NewAddressCount;\r
950 UINTN Index1;\r
951 UINTN Index2;\r
952 IP6_SERVICE *IpSb;\r
953 IP6_ADDRESS_INFO *CurrentAddrInfo;\r
954 IP6_ADDRESS_INFO *Copy;\r
955 LIST_ENTRY CurrentSourceList;\r
956 UINT32 CurrentSourceCount;\r
957 LIST_ENTRY *Entry;\r
958 LIST_ENTRY *Entry2;\r
959 IP6_INTERFACE *IpIf;\r
960 IP6_PREFIX_LIST_ENTRY *PrefixEntry;\r
961 EFI_STATUS Status;\r
962 BOOLEAN IsUpdated;\r
963 LIST_ENTRY *Next;\r
964 IP6_DAD_ENTRY *DadEntry;\r
965 IP6_DELAY_JOIN_LIST *DelayNode;\r
966\r
967 NewAddress = NULL;\r
968 TmpAddress = NULL;\r
969 CurrentAddrInfo = NULL;\r
970 Copy = NULL;\r
971 Entry = NULL;\r
972 Entry2 = NULL;\r
973 IpIf = NULL;\r
974 PrefixEntry = NULL;\r
975 Next = NULL;\r
976 DadEntry = NULL;\r
977 DelayNode = NULL;\r
978 Status = EFI_SUCCESS;\r
979\r
980 ASSERT (Instance->DataItem[Ip6ConfigDataTypeManualAddress].Status != EFI_NOT_READY);\r
981\r
982 if ((DataSize != 0) && ((DataSize % sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)) != 0)) {\r
983 return EFI_BAD_BUFFER_SIZE;\r
984 }\r
985\r
986 if (Instance->Policy != Ip6ConfigPolicyManual) {\r
987 return EFI_WRITE_PROTECTED;\r
988 }\r
989\r
990 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
991\r
992 DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];\r
993\r
994 if (Data != NULL && DataSize != 0) {\r
995 NewAddressCount = DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);\r
996 NewAddress = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) Data;\r
997\r
998 for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {\r
999\r
1000 if (NetIp6IsLinkLocalAddr (&NewAddress->Address) ||\r
1001 !NetIp6IsValidUnicast (&NewAddress->Address) ||\r
1002 (NewAddress->PrefixLength > 128)\r
1003 ) {\r
1004 //\r
1005 // make sure the IPv6 address is unicast and not link-local address &&\r
1006 // the prefix length is valid.\r
1007 //\r
1008 return EFI_INVALID_PARAMETER;\r
1009 }\r
1010\r
1011 TmpAddress = NewAddress + 1;\r
1012 for (Index2 = Index1 + 1; Index2 < NewAddressCount; Index2++, TmpAddress++) {\r
1013 //\r
1014 // Any two addresses in the array can't be equal.\r
1015 //\r
1016 if (EFI_IP6_EQUAL (&TmpAddress->Address, &NewAddress->Address)) {\r
1017\r
1018 return EFI_INVALID_PARAMETER;\r
1019 }\r
1020 }\r
1021 }\r
1022\r
1023 //\r
1024 // Build the current source address list.\r
1025 //\r
1026 InitializeListHead (&CurrentSourceList);\r
1027 CurrentSourceCount = 0;\r
1028\r
1029 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
1030 IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);\r
1031\r
1032 NET_LIST_FOR_EACH (Entry2, &IpIf->AddressList) {\r
1033 CurrentAddrInfo = NET_LIST_USER_STRUCT_S (Entry2, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);\r
1034\r
1035 Copy = AllocateCopyPool (sizeof (IP6_ADDRESS_INFO), CurrentAddrInfo);\r
1036 if (Copy == NULL) {\r
1037 break;\r
1038 }\r
1039\r
1040 InsertTailList (&CurrentSourceList, &Copy->Link);\r
1041 CurrentSourceCount++;\r
1042 }\r
1043 }\r
1044\r
1045 //\r
1046 // Update the value... a long journey starts\r
1047 //\r
1048 NewAddress = AllocateCopyPool (DataSize, Data);\r
1049 if (NewAddress == NULL) {\r
1050 Ip6RemoveAddr (NULL, &CurrentSourceList, &CurrentSourceCount, NULL, 0);\r
1051\r
1052 return EFI_OUT_OF_RESOURCES;\r
1053 }\r
1054\r
1055 //\r
1056 // Store the new data, and init the DataItem status to EFI_NOT_READY because\r
1057 // we may have an asynchronous configuration process.\r
1058 //\r
1059 if (DataItem->Data.Ptr != NULL) {\r
1060 FreePool (DataItem->Data.Ptr);\r
1061 }\r
1062 DataItem->Data.Ptr = NewAddress;\r
1063 DataItem->DataSize = DataSize;\r
1064 DataItem->Status = EFI_NOT_READY;\r
1065\r
1066 //\r
1067 // Trigger DAD, it's an asynchronous process.\r
1068 //\r
1069 IsUpdated = FALSE;\r
1070\r
1071 for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {\r
1072 if (Ip6IsOneOfSetAddress (IpSb, &NewAddress->Address, NULL, &CurrentAddrInfo)) {\r
1073 ASSERT (CurrentAddrInfo != NULL);\r
1074 //\r
1075 // Remove this already existing source address from the CurrentSourceList\r
1076 // built before.\r
1077 //\r
1078 Ip6RemoveAddr (\r
1079 NULL,\r
1080 &CurrentSourceList,\r
1081 &CurrentSourceCount,\r
1082 &CurrentAddrInfo->Address,\r
1083 128\r
1084 );\r
1085\r
1086 //\r
1087 // If the new address's prefix length is not specified, just use the previous configured\r
1088 // prefix length for this address.\r
1089 //\r
1090 if (NewAddress->PrefixLength == 0) {\r
1091 NewAddress->PrefixLength = CurrentAddrInfo->PrefixLength;\r
1092 }\r
1093\r
1094 //\r
1095 // This manual address is already in use, see whether prefix length is changed.\r
1096 //\r
1097 if (NewAddress->PrefixLength != CurrentAddrInfo->PrefixLength) {\r
1098 //\r
1099 // Remove the on-link prefix table, the route entry will be removed\r
1100 // implicitly.\r
1101 //\r
1102 PrefixEntry = Ip6FindPrefixListEntry (\r
1103 IpSb,\r
1104 TRUE,\r
1105 CurrentAddrInfo->PrefixLength,\r
1106 &CurrentAddrInfo->Address\r
1107 );\r
1108 if (PrefixEntry != NULL) {\r
1109 Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);\r
1110 }\r
1111\r
1112 //\r
1113 // Save the prefix length.\r
1114 //\r
1115 CurrentAddrInfo->PrefixLength = NewAddress->PrefixLength;\r
1116 IsUpdated = TRUE;\r
1117 }\r
1118\r
1119 //\r
1120 // create a new on-link prefix entry.\r
1121 //\r
1122 PrefixEntry = Ip6FindPrefixListEntry (\r
1123 IpSb,\r
1124 TRUE,\r
1125 NewAddress->PrefixLength,\r
1126 &NewAddress->Address\r
1127 );\r
1128 if (PrefixEntry == NULL) {\r
1129 Ip6CreatePrefixListEntry (\r
1130 IpSb,\r
1131 TRUE,\r
1132 (UINT32) IP6_INFINIT_LIFETIME,\r
1133 (UINT32) IP6_INFINIT_LIFETIME,\r
1134 NewAddress->PrefixLength,\r
1135 &NewAddress->Address\r
1136 );\r
1137 }\r
1138\r
1139 CurrentAddrInfo->IsAnycast = NewAddress->IsAnycast;\r
1140 //\r
1141 // Artificially mark this address passed DAD be'coz it is already in use.\r
1142 //\r
1143 Ip6ManualAddrDadCallback (TRUE, &NewAddress->Address, Instance);\r
1144 } else {\r
1145 //\r
1146 // A new address.\r
1147 //\r
1148 IsUpdated = TRUE;\r
1149\r
1150 //\r
1151 // Set the new address, this will trigger DAD and activate the address if\r
1152 // DAD succeeds.\r
1153 //\r
1154 Ip6SetAddress (\r
1155 IpSb->DefaultInterface,\r
1156 &NewAddress->Address,\r
1157 NewAddress->IsAnycast,\r
1158 NewAddress->PrefixLength,\r
1159 (UINT32) IP6_INFINIT_LIFETIME,\r
1160 (UINT32) IP6_INFINIT_LIFETIME,\r
1161 Ip6ManualAddrDadCallback,\r
1162 Instance\r
1163 );\r
1164 }\r
1165 }\r
1166\r
1167 //\r
1168 // Check the CurrentSourceList, it now contains those addresses currently in\r
1169 // use and will be removed.\r
1170 //\r
1171 IpIf = IpSb->DefaultInterface;\r
1172\r
1173 while (!IsListEmpty (&CurrentSourceList)) {\r
1174 IsUpdated = TRUE;\r
1175\r
1176 CurrentAddrInfo = NET_LIST_HEAD (&CurrentSourceList, IP6_ADDRESS_INFO, Link);\r
1177\r
1178 //\r
1179 // This local address is going to be removed, the IP instances that are\r
1180 // currently using it will be destroyed.\r
1181 //\r
1182 Ip6RemoveAddr (\r
1183 IpSb,\r
1184 &IpIf->AddressList,\r
1185 &IpIf->AddressCount,\r
1186 &CurrentAddrInfo->Address,\r
1187 128\r
1188 );\r
1189\r
1190 //\r
1191 // Remove the on-link prefix table, the route entry will be removed\r
1192 // implicitly.\r
1193 //\r
1194 PrefixEntry = Ip6FindPrefixListEntry (\r
1195 IpSb,\r
1196 TRUE,\r
1197 CurrentAddrInfo->PrefixLength,\r
1198 &CurrentAddrInfo->Address\r
1199 );\r
1200 if (PrefixEntry != NULL) {\r
1201 Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);\r
1202 }\r
1203\r
1204 RemoveEntryList (&CurrentAddrInfo->Link);\r
1205 FreePool (CurrentAddrInfo);\r
1206 }\r
1207\r
1208 if (IsUpdated) {\r
1209 if (DataItem->Status == EFI_NOT_READY) {\r
1210 //\r
1211 // If DAD is disabled on this interface, the configuration process is\r
1212 // actually synchronous, and the data item's status will be changed to\r
1213 // the final status before we reach here, just check it.\r
1214 //\r
1215 Status = EFI_NOT_READY;\r
1216 } else {\r
1217 Status = EFI_SUCCESS;\r
1218 }\r
1219 } else {\r
1220 //\r
1221 // No update is taken, reset the status to success and return EFI_ABORTED.\r
1222 //\r
1223 DataItem->Status = EFI_SUCCESS;\r
1224 Status = EFI_ABORTED;\r
1225 }\r
1226 } else {\r
1227 //\r
1228 // DataSize is 0 and Data is NULL, clean up the manual address.\r
1229 //\r
1230 if (DataItem->Data.Ptr != NULL) {\r
1231 FreePool (DataItem->Data.Ptr);\r
1232 }\r
1233 DataItem->Data.Ptr = NULL;\r
1234 DataItem->DataSize = 0;\r
1235 DataItem->Status = EFI_NOT_FOUND;\r
1236\r
1237 Ip6CleanDefaultRouterList (IpSb);\r
1238 Ip6CleanPrefixListTable (IpSb, &IpSb->OnlinkPrefix);\r
1239 Ip6CleanPrefixListTable (IpSb, &IpSb->AutonomousPrefix);\r
1240 Ip6CleanAssembleTable (&IpSb->Assemble);\r
1241\r
1242 if (IpSb->LinkLocalOk) {\r
1243 Ip6CreatePrefixListEntry (\r
1244 IpSb,\r
1245 TRUE,\r
1246 (UINT32) IP6_INFINIT_LIFETIME,\r
1247 (UINT32) IP6_INFINIT_LIFETIME,\r
1248 IP6_LINK_LOCAL_PREFIX_LENGTH,\r
1249 &IpSb->LinkLocalAddr\r
1250 );\r
1251 }\r
1252\r
1253 Ip6RemoveAddr (\r
1254 IpSb,\r
1255 &IpSb->DefaultInterface->AddressList,\r
1256 &IpSb->DefaultInterface->AddressCount,\r
1257 NULL,\r
1258 0\r
1259 );\r
1260\r
1261 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
1262 //\r
1263 // Remove all pending delay node and DAD entries for the global addresses.\r
1264 //\r
1265 IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);\r
1266\r
1267 NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DelayJoinList) {\r
1268 DelayNode = NET_LIST_USER_STRUCT (Entry2, IP6_DELAY_JOIN_LIST, Link);\r
1269 if (!NetIp6IsLinkLocalAddr (&DelayNode->AddressInfo->Address)) {\r
1270 RemoveEntryList (&DelayNode->Link);\r
1271 FreePool (DelayNode);\r
1272 }\r
1273 }\r
1274\r
1275 NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DupAddrDetectList) {\r
1276 DadEntry = NET_LIST_USER_STRUCT_S (Entry2, IP6_DAD_ENTRY, Link, IP6_DAD_ENTRY_SIGNATURE);\r
1277\r
1278 if (!NetIp6IsLinkLocalAddr (&DadEntry->AddressInfo->Address)) {\r
1279 //\r
1280 // Fail this DAD entry if the address is not link-local.\r
1281 //\r
1282 Ip6OnDADFinished (FALSE, IpIf, DadEntry);\r
1283 }\r
1284 }\r
1285 }\r
1286 }\r
1287\r
1288 return Status;\r
1289}\r
1290\r
1291/**\r
1292 The work function for EfiIp6ConfigSetData() to set the gateway addresses manually\r
1293 for the EFI IPv6 network stack that is running on the communication device that\r
1294 this EFI IPv6 Configuration Protocol manages. It is not configurable when the policy is\r
1295 Ip6ConfigPolicyAutomatic. The gateway addresses must be unicast IPv6 addresses.\r
1296\r
1297 @param[in] Instance The pointer to the IP6 config instance data.\r
1298 @param[in] DataSize The size of the buffer pointed to by Data in bytes.\r
1299 @param[in] Data The data buffer to set. This points to an array of\r
1300 EFI_IPv6_ADDRESS instances.\r
1301\r
1302 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.\r
1303 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set\r
1304 under the current policy.\r
1305 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.\r
1306 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to complete the operation.\r
1307 @retval EFI_ABORTED The manual gateway addresses to be set equal the\r
1308 current configuration.\r
1309 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
1310 network stack was set.\r
1311\r
1312**/\r
1313EFI_STATUS\r
1314Ip6ConfigSetGateway (\r
1315 IN IP6_CONFIG_INSTANCE *Instance,\r
1316 IN UINTN DataSize,\r
1317 IN VOID *Data\r
1318 )\r
1319{\r
1320 UINTN Index1;\r
1321 UINTN Index2;\r
1322 EFI_IPv6_ADDRESS *OldGateway;\r
1323 EFI_IPv6_ADDRESS *NewGateway;\r
1324 UINTN OldGatewayCount;\r
1325 UINTN NewGatewayCount;\r
1326 IP6_CONFIG_DATA_ITEM *Item;\r
1327 BOOLEAN OneRemoved;\r
1328 BOOLEAN OneAdded;\r
1329 IP6_SERVICE *IpSb;\r
1330 IP6_DEFAULT_ROUTER *DefaultRouter;\r
1331 VOID *Tmp;\r
1332\r
1333 OldGateway = NULL;\r
1334 NewGateway = NULL;\r
1335 Item = NULL;\r
1336 DefaultRouter = NULL;\r
1337 Tmp = NULL;\r
1338 OneRemoved = FALSE;\r
1339 OneAdded = FALSE;\r
1340\r
1341 if ((DataSize != 0) && (DataSize % sizeof (EFI_IPv6_ADDRESS) != 0)) {\r
1342 return EFI_BAD_BUFFER_SIZE;\r
1343 }\r
1344\r
1345 if (Instance->Policy != Ip6ConfigPolicyManual) {\r
1346 return EFI_WRITE_PROTECTED;\r
1347 }\r
1348\r
1349 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
1350 Item = &Instance->DataItem[Ip6ConfigDataTypeGateway];\r
1351 OldGateway = Item->Data.Gateway;\r
1352 OldGatewayCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);\r
1353\r
1354 for (Index1 = 0; Index1 < OldGatewayCount; Index1++) {\r
1355 //\r
1356 // Remove this default router.\r
1357 //\r
1358 DefaultRouter = Ip6FindDefaultRouter (IpSb, OldGateway + Index1);\r
1359 if (DefaultRouter != NULL) {\r
1360 Ip6DestroyDefaultRouter (IpSb, DefaultRouter);\r
1361 OneRemoved = TRUE;\r
1362 }\r
1363 }\r
1364\r
1365 if (Data != NULL && DataSize != 0) {\r
1366 NewGateway = (EFI_IPv6_ADDRESS *) Data;\r
1367 NewGatewayCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
1368 for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\r
1369\r
1370 if (!NetIp6IsValidUnicast (NewGateway + Index1)) {\r
1371\r
1372 return EFI_INVALID_PARAMETER;\r
1373 }\r
1374\r
1375 for (Index2 = Index1 + 1; Index2 < NewGatewayCount; Index2++) {\r
1376 if (EFI_IP6_EQUAL (NewGateway + Index1, NewGateway + Index2)) {\r
1377 return EFI_INVALID_PARAMETER;\r
1378 }\r
1379 }\r
1380 }\r
1381\r
1382 if (NewGatewayCount != OldGatewayCount) {\r
1383 Tmp = AllocatePool (DataSize);\r
1384 if (Tmp == NULL) {\r
1385 return EFI_OUT_OF_RESOURCES;\r
1386 }\r
1387 } else {\r
1388 Tmp = NULL;\r
1389 }\r
1390\r
1391 for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\r
1392\r
1393 DefaultRouter = Ip6FindDefaultRouter (IpSb, NewGateway + Index1);\r
1394 if (DefaultRouter == NULL) {\r
1395 Ip6CreateDefaultRouter (IpSb, NewGateway + Index1, IP6_INF_ROUTER_LIFETIME);\r
1396 OneAdded = TRUE;\r
1397 }\r
1398 }\r
1399\r
1400 if (!OneRemoved && !OneAdded) {\r
1401 Item->Status = EFI_SUCCESS;\r
1402 return EFI_ABORTED;\r
1403 } else {\r
1404\r
1405 if (Tmp != NULL) {\r
1406 if (Item->Data.Ptr != NULL) {\r
1407 FreePool (Item->Data.Ptr);\r
1408 }\r
1409 Item->Data.Ptr = Tmp;\r
1410 }\r
1411\r
1412 CopyMem (Item->Data.Ptr, Data, DataSize);\r
1413 Item->DataSize = DataSize;\r
1414 Item->Status = EFI_SUCCESS;\r
1415 return EFI_SUCCESS;\r
1416 }\r
1417 } else {\r
1418 //\r
1419 // DataSize is 0 and Data is NULL, clean up the Gateway address.\r
1420 //\r
1421 if (Item->Data.Ptr != NULL) {\r
1422 FreePool (Item->Data.Ptr);\r
1423 }\r
1424 Item->Data.Ptr = NULL;\r
1425 Item->DataSize = 0;\r
1426 Item->Status = EFI_NOT_FOUND;\r
1427 }\r
1428\r
1429 return EFI_SUCCESS;\r
1430}\r
1431\r
1432/**\r
1433 The work function for EfiIp6ConfigSetData() to set the DNS server list for the\r
1434 EFI IPv6 network stack running on the communication device that this EFI IPv6\r
1435 Configuration Protocol manages. It is not configurable when the policy is\r
1436 Ip6ConfigPolicyAutomatic. The DNS server addresses must be unicast IPv6 addresses.\r
1437\r
1438 @param[in] Instance The pointer to the IP6 config instance data.\r
1439 @param[in] DataSize The size of the buffer pointed to by Data in bytes.\r
1440 @param[in] Data The data buffer to set, points to an array of\r
1441 EFI_IPv6_ADDRESS instances.\r
1442\r
1443 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.\r
1444 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set\r
1445 under the current policy.\r
1446 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.\r
1447 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.\r
1448 @retval EFI_ABORTED The DNS server addresses to be set equal the current\r
1449 configuration.\r
1450 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
1451 network stack was set.\r
1452\r
1453**/\r
1454EFI_STATUS\r
1455Ip6ConfigSetDnsServer (\r
1456 IN IP6_CONFIG_INSTANCE *Instance,\r
1457 IN UINTN DataSize,\r
1458 IN VOID *Data\r
1459 )\r
1460{\r
1461 UINTN OldIndex;\r
1462 UINTN NewIndex;\r
1463 EFI_IPv6_ADDRESS *OldDns;\r
1464 EFI_IPv6_ADDRESS *NewDns;\r
1465 UINTN OldDnsCount;\r
1466 UINTN NewDnsCount;\r
1467 IP6_CONFIG_DATA_ITEM *Item;\r
1468 BOOLEAN OneAdded;\r
1469 VOID *Tmp;\r
1470\r
1471 OldDns = NULL;\r
1472 NewDns = NULL;\r
1473 Item = NULL;\r
1474 Tmp = NULL;\r
1475\r
1476 if ((DataSize != 0) && (DataSize % sizeof (EFI_IPv6_ADDRESS) != 0)) {\r
1477 return EFI_BAD_BUFFER_SIZE;\r
1478 }\r
1479\r
1480 if (Instance->Policy != Ip6ConfigPolicyManual) {\r
1481 return EFI_WRITE_PROTECTED;\r
1482 }\r
1483\r
1484 Item = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];\r
1485\r
1486 if (Data != NULL && DataSize != 0) {\r
1487 NewDns = (EFI_IPv6_ADDRESS *) Data;\r
1488 OldDns = Item->Data.DnsServers;\r
1489 NewDnsCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
1490 OldDnsCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);\r
1491 OneAdded = FALSE;\r
1492\r
1493 if (NewDnsCount != OldDnsCount) {\r
1494 Tmp = AllocatePool (DataSize);\r
1495 if (Tmp == NULL) {\r
1496 return EFI_OUT_OF_RESOURCES;\r
1497 }\r
1498 } else {\r
1499 Tmp = NULL;\r
1500 }\r
1501\r
1502 for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) {\r
1503\r
1504 if (!NetIp6IsValidUnicast (NewDns + NewIndex)) {\r
1505 //\r
1506 // The dns server address must be unicast.\r
1507 //\r
1508 if (Tmp != NULL) {\r
1509 FreePool (Tmp);\r
1510 }\r
1511 return EFI_INVALID_PARAMETER;\r
1512 }\r
1513\r
1514 if (OneAdded) {\r
1515 //\r
1516 // If any address in the new setting is not in the old settings, skip the\r
1517 // comparision below.\r
1518 //\r
1519 continue;\r
1520 }\r
1521\r
1522 for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) {\r
1523 if (EFI_IP6_EQUAL (NewDns + NewIndex, OldDns + OldIndex)) {\r
1524 //\r
1525 // If found break out.\r
1526 //\r
1527 break;\r
1528 }\r
1529 }\r
1530\r
1531 if (OldIndex == OldDnsCount) {\r
1532 OneAdded = TRUE;\r
1533 }\r
1534 }\r
1535\r
1536 if (!OneAdded && (DataSize == Item->DataSize)) {\r
1537 //\r
1538 // No new item is added and the size is the same.\r
1539 //\r
1540 Item->Status = EFI_SUCCESS;\r
1541 return EFI_ABORTED;\r
1542 } else {\r
1543 if (Tmp != NULL) {\r
1544 if (Item->Data.Ptr != NULL) {\r
1545 FreePool (Item->Data.Ptr);\r
1546 }\r
1547 Item->Data.Ptr = Tmp;\r
1548 }\r
1549\r
1550 CopyMem (Item->Data.Ptr, Data, DataSize);\r
1551 Item->DataSize = DataSize;\r
1552 Item->Status = EFI_SUCCESS;\r
1553 }\r
1554 } else {\r
1555 //\r
1556 // DataSize is 0 and Data is NULL, clean up the DnsServer address.\r
1557 //\r
1558 if (Item->Data.Ptr != NULL) {\r
1559 FreePool (Item->Data.Ptr);\r
1560 }\r
1561 Item->Data.Ptr = NULL;\r
1562 Item->DataSize = 0;\r
1563 Item->Status = EFI_NOT_FOUND;\r
1564 }\r
1565\r
1566 return EFI_SUCCESS;\r
1567}\r
1568\r
1569/**\r
1570 Generate the operational state of the interface this IP6 config instance manages\r
1571 and output in EFI_IP6_CONFIG_INTERFACE_INFO.\r
1572\r
1573 @param[in] IpSb The pointer to the IP6 service binding instance.\r
1574 @param[out] IfInfo The pointer to the IP6 configuration interface information structure.\r
1575\r
1576**/\r
1577VOID\r
1578Ip6ConfigInitIfInfo (\r
1579 IN IP6_SERVICE *IpSb,\r
1580 OUT EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo\r
1581 )\r
1582{\r
1583 UnicodeSPrint (\r
1584 IfInfo->Name,\r
1585 sizeof (IfInfo->Name),\r
1586 L"eth%d",\r
1587 IpSb->Ip6ConfigInstance.IfIndex\r
1588 );\r
1589\r
1590 IfInfo->IfType = IpSb->SnpMode.IfType;\r
1591 IfInfo->HwAddressSize = IpSb->SnpMode.HwAddressSize;\r
1592 CopyMem (&IfInfo->HwAddress, &IpSb->SnpMode.CurrentAddress, IfInfo->HwAddressSize);\r
1593}\r
1594\r
1595/**\r
1596 Parse DHCPv6 reply packet to get the DNS server list.\r
1597 It is the work function for Ip6ConfigOnDhcp6Reply and Ip6ConfigOnDhcp6Event.\r
1598\r
1599 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL instance.\r
1600 @param[in, out] Instance The pointer to the IP6 configuration instance data.\r
1601 @param[in] Reply The pointer to the DHCPv6 reply packet.\r
1602\r
1603 @retval EFI_SUCCESS The DNS server address was retrieved from the reply packet.\r
1604 @retval EFI_NOT_READY The reply packet does not contain the DNS server option, or\r
1605 the DNS server address is not valid.\r
1606\r
1607**/\r
1608EFI_STATUS\r
1609Ip6ConfigParseDhcpReply (\r
1610 IN EFI_DHCP6_PROTOCOL *Dhcp6,\r
1611 IN OUT IP6_CONFIG_INSTANCE *Instance,\r
1612 IN EFI_DHCP6_PACKET *Reply\r
1613 )\r
1614{\r
1615 EFI_STATUS Status;\r
1616 UINT32 OptCount;\r
1617 EFI_DHCP6_PACKET_OPTION **OptList;\r
1618 UINT16 OpCode;\r
1619 UINT16 Length;\r
1620 UINTN Index;\r
1621 UINTN Index2;\r
1622 EFI_IPv6_ADDRESS *DnsServer;\r
1623 IP6_CONFIG_DATA_ITEM *Item;\r
1624\r
1625 //\r
1626 // A DHCPv6 reply packet is received as the response to our InfoRequest\r
1627 // packet.\r
1628 //\r
1629 OptCount = 0;\r
1630 Status = Dhcp6->Parse (Dhcp6, Reply, &OptCount, NULL);\r
1631 if (Status != EFI_BUFFER_TOO_SMALL) {\r
1632 return EFI_NOT_READY;\r
1633 }\r
1634\r
1635 OptList = AllocatePool (OptCount * sizeof (EFI_DHCP6_PACKET_OPTION *));\r
1636 if (OptList == NULL) {\r
1637 return EFI_NOT_READY;\r
1638 }\r
1639\r
1640 Status = Dhcp6->Parse (Dhcp6, Reply, &OptCount, OptList);\r
1641 if (EFI_ERROR (Status)) {\r
1642 Status = EFI_NOT_READY;\r
1643 goto ON_EXIT;\r
1644 }\r
1645\r
1646 Status = EFI_SUCCESS;\r
1647\r
1648 for (Index = 0; Index < OptCount; Index++) {\r
1649 //\r
1650 // Go through all the options to check the ones we are interested in.\r
1651 // The OpCode and Length are in network byte-order and may not be naturally\r
1652 // aligned.\r
1653 //\r
1654 CopyMem (&OpCode, &OptList[Index]->OpCode, sizeof (OpCode));\r
1655 OpCode = NTOHS (OpCode);\r
1656\r
1657 if (OpCode == DHCP6_OPT_DNS_SERVERS) {\r
1658 CopyMem (&Length, &OptList[Index]->OpLen, sizeof (Length));\r
1659 Length = NTOHS (Length);\r
1660\r
1661 if ((Length == 0) || ((Length % sizeof (EFI_IPv6_ADDRESS)) != 0)) {\r
1662 //\r
1663 // The length should be a multiple of 16 bytes.\r
1664 //\r
1665 Status = EFI_NOT_READY;\r
1666 break;\r
1667 }\r
1668\r
1669 //\r
1670 // Validate the DnsServers: whether they are unicast addresses.\r
1671 //\r
1672 DnsServer = (EFI_IPv6_ADDRESS *) OptList[Index]->Data;\r
1673 for (Index2 = 0; Index2 < Length / sizeof (EFI_IPv6_ADDRESS); Index2++) {\r
1674 if (!NetIp6IsValidUnicast (DnsServer)) {\r
1675 Status = EFI_NOT_READY;\r
1676 goto ON_EXIT;\r
1677 }\r
1678\r
1679 DnsServer++;\r
1680 }\r
1681\r
1682 Item = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];\r
1683\r
1684 if (Item->DataSize != Length) {\r
1685 if (Item->Data.Ptr != NULL) {\r
1686 FreePool (Item->Data.Ptr);\r
1687 }\r
1688\r
1689 Item->Data.Ptr = AllocatePool (Length);\r
1690 ASSERT (Item->Data.Ptr != NULL);\r
1691 }\r
1692\r
1693 CopyMem (Item->Data.Ptr, OptList[Index]->Data, Length);\r
1694 Item->DataSize = Length;\r
1695 Item->Status = EFI_SUCCESS;\r
1696\r
1697 //\r
1698 // Signal the waiting events.\r
1699 //\r
1700 NetMapIterate (&Item->EventMap, Ip6ConfigSignalEvent, NULL);\r
1701\r
1702 break;\r
1703 }\r
1704 }\r
1705\r
1706ON_EXIT:\r
1707\r
1708 FreePool (OptList);\r
1709 return Status;\r
1710}\r
1711\r
1712/**\r
1713 The callback function for Ip6SetAddr. The prototype is defined\r
1714 as IP6_DAD_CALLBACK. It is called after Duplicate Address Detection is performed\r
1715 on the tentative address by DHCPv6 in Ip6ConfigOnDhcp6Event().\r
1716\r
1717 @param[in] IsDadPassed If TRUE, Duplicate Address Detection passes.\r
1718 @param[in] TargetAddress The tentative IPv6 address to be checked.\r
1719 @param[in] Context Pointer to the IP6 configuration instance data.\r
1720\r
1721**/\r
1722VOID\r
1723Ip6ConfigSetStatefulAddrCallback (\r
1724 IN BOOLEAN IsDadPassed,\r
1725 IN EFI_IPv6_ADDRESS *TargetAddress,\r
1726 IN VOID *Context\r
1727 )\r
1728{\r
1729 IP6_CONFIG_INSTANCE *Instance;\r
1730\r
1731 Instance = (IP6_CONFIG_INSTANCE *) Context;\r
1732 NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);\r
1733\r
1734 //\r
1735 // We should record the addresses that fail the DAD, and DECLINE them.\r
1736 //\r
1737 if (IsDadPassed) {\r
1738 //\r
1739 // Decrease the count, no interests in those passed DAD.\r
1740 //\r
1741 if (Instance->FailedIaAddressCount > 0 ) {\r
1742 Instance->FailedIaAddressCount--;\r
1743 }\r
1744 } else {\r
1745 //\r
1746 // Record it.\r
1747 //\r
1748 IP6_COPY_ADDRESS (Instance->DeclineAddress + Instance->DeclineAddressCount, TargetAddress);\r
1749 Instance->DeclineAddressCount++;\r
1750 }\r
1751\r
1752 if (Instance->FailedIaAddressCount == Instance->DeclineAddressCount) {\r
1753 //\r
1754 // The checking on all addresses are finished.\r
1755 //\r
1756 if (Instance->DeclineAddressCount != 0) {\r
1757 //\r
1758 // Decline those duplicates.\r
1759 //\r
1760 if (Instance->Dhcp6 != NULL) {\r
1761 Instance->Dhcp6->Decline (\r
1762 Instance->Dhcp6,\r
1763 Instance->DeclineAddressCount,\r
1764 Instance->DeclineAddress\r
1765 );\r
1766 }\r
1767 }\r
1768\r
1769 if (Instance->DeclineAddress != NULL) {\r
1770 FreePool (Instance->DeclineAddress);\r
1771 }\r
1772 Instance->DeclineAddress = NULL;\r
1773 Instance->DeclineAddressCount = 0;\r
1774 }\r
1775}\r
1776\r
1777/**\r
1778 The event handle routine when DHCPv6 process is finished or is updated.\r
1779\r
1780 @param[in] Event Not used.\r
1781 @param[in] Context The pointer to the IP6 configuration instance data.\r
1782\r
1783**/\r
1784VOID\r
1785EFIAPI\r
1786Ip6ConfigOnDhcp6Event (\r
1787 IN EFI_EVENT Event,\r
1788 IN VOID *Context\r
1789 )\r
1790{\r
1791 IP6_CONFIG_INSTANCE *Instance;\r
1792 EFI_DHCP6_PROTOCOL *Dhcp6;\r
1793 EFI_STATUS Status;\r
1794 EFI_DHCP6_MODE_DATA Dhcp6ModeData;\r
1795 EFI_DHCP6_IA *Ia;\r
1796 EFI_DHCP6_IA_ADDRESS *IaAddr;\r
1797 UINT32 Index;\r
1798 IP6_SERVICE *IpSb;\r
1799 IP6_ADDRESS_INFO *AddrInfo;\r
1800 IP6_INTERFACE *IpIf;\r
1801\r
1802 Instance = (IP6_CONFIG_INSTANCE *) Context;\r
1803\r
1804 if ((Instance->Policy != Ip6ConfigPolicyAutomatic) || Instance->OtherInfoOnly) {\r
1805 //\r
1806 // IPv6 is not operating in the automatic policy now or\r
1807 // the DHCPv6 information request message exchange is aborted.\r
1808 //\r
1809 return ;\r
1810 }\r
1811\r
1812 //\r
1813 // The stateful address autoconfiguration is done or updated.\r
1814 //\r
1815 Dhcp6 = Instance->Dhcp6;\r
1816\r
1817 Status = Dhcp6->GetModeData (Dhcp6, &Dhcp6ModeData, NULL);\r
1818 if (EFI_ERROR (Status)) {\r
1819 return ;\r
1820 }\r
1821\r
1822 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
1823 IpIf = IpSb->DefaultInterface;\r
1824 Ia = Dhcp6ModeData.Ia;\r
1825 IaAddr = Ia->IaAddress;\r
1826\r
1827 if (Instance->DeclineAddress != NULL) {\r
1828 FreePool (Instance->DeclineAddress);\r
1829 }\r
1830\r
1831 Instance->DeclineAddress = (EFI_IPv6_ADDRESS *) AllocatePool (Ia->IaAddressCount * sizeof (EFI_IPv6_ADDRESS));\r
1832 if (Instance->DeclineAddress == NULL) {\r
1833 goto ON_EXIT;\r
1834 }\r
1835\r
1836 Instance->FailedIaAddressCount = Ia->IaAddressCount;\r
1837 Instance->DeclineAddressCount = 0;\r
1838\r
1839 for (Index = 0; Index < Ia->IaAddressCount; Index++, IaAddr++) {\r
1840 if (Ia->IaAddress[Index].ValidLifetime != 0 && Ia->State == Dhcp6Bound) {\r
1841 //\r
1842 // Set this address, either it's a new address or with updated lifetimes.\r
1843 // An appropriate prefix length will be set.\r
1844 //\r
1845 Ip6SetAddress (\r
1846 IpIf,\r
1847 &IaAddr->IpAddress,\r
1848 FALSE,\r
1849 0,\r
1850 IaAddr->ValidLifetime,\r
1851 IaAddr->PreferredLifetime,\r
1852 Ip6ConfigSetStatefulAddrCallback,\r
1853 Instance\r
1854 );\r
1855 } else {\r
1856 //\r
1857 // discard this address, artificially decrease the count as if this address\r
1858 // passed DAD.\r
1859 //\r
1860 if (Ip6IsOneOfSetAddress (IpSb, &IaAddr->IpAddress, NULL, &AddrInfo)) {\r
1861 ASSERT (AddrInfo != NULL);\r
1862 Ip6RemoveAddr (\r
1863 IpSb,\r
1864 &IpIf->AddressList,\r
1865 &IpIf->AddressCount,\r
1866 &AddrInfo->Address,\r
1867 AddrInfo->PrefixLength\r
1868 );\r
1869 }\r
1870\r
1871 if (Instance->FailedIaAddressCount > 0) {\r
1872 Instance->FailedIaAddressCount--;\r
1873 }\r
1874 }\r
1875 }\r
1876\r
1877 //\r
1878 // Parse the Reply packet to get the options we need.\r
1879 //\r
1880 if (Dhcp6ModeData.Ia->ReplyPacket != NULL) {\r
1881 Ip6ConfigParseDhcpReply (Dhcp6, Instance, Dhcp6ModeData.Ia->ReplyPacket);\r
1882 }\r
1883\r
1884ON_EXIT:\r
1885\r
1886 FreePool (Dhcp6ModeData.ClientId);\r
1887 FreePool (Dhcp6ModeData.Ia);\r
1888}\r
1889\r
1890/**\r
1891 The event process routine when the DHCPv6 server is answered with a reply packet\r
1892 for an information request.\r
1893\r
1894 @param[in] This Points to the EFI_DHCP6_PROTOCOL.\r
1895 @param[in] Context The pointer to the IP6 configuration instance data.\r
1896 @param[in] Packet The DHCPv6 reply packet.\r
1897\r
1898 @retval EFI_SUCCESS The DNS server address was retrieved from the reply packet.\r
1899 @retval EFI_NOT_READY The reply packet does not contain the DNS server option, or\r
1900 the DNS server address is not valid.\r
1901\r
1902**/\r
1903EFI_STATUS\r
1904EFIAPI\r
1905Ip6ConfigOnDhcp6Reply (\r
1906 IN EFI_DHCP6_PROTOCOL *This,\r
1907 IN VOID *Context,\r
1908 IN EFI_DHCP6_PACKET *Packet\r
1909 )\r
1910{\r
1911 return Ip6ConfigParseDhcpReply (This, (IP6_CONFIG_INSTANCE *) Context, Packet);\r
1912}\r
1913\r
1914/**\r
1915 The event process routine when the DHCPv6 service binding protocol is installed\r
1916 in the system.\r
1917\r
1918 @param[in] Event Not used.\r
1919 @param[in] Context The pointer to the IP6 config instance data.\r
1920\r
1921**/\r
1922VOID\r
1923EFIAPI\r
1924Ip6ConfigOnDhcp6SbInstalled (\r
1925 IN EFI_EVENT Event,\r
1926 IN VOID *Context\r
1927 )\r
1928{\r
1929 IP6_CONFIG_INSTANCE *Instance;\r
1930\r
1931 Instance = (IP6_CONFIG_INSTANCE *) Context;\r
1932\r
1933 if ((Instance->Dhcp6Handle != NULL) || (Instance->Policy != Ip6ConfigPolicyAutomatic)) {\r
1934 //\r
1935 // The DHCP6 child is already created or the policy is no longer AUTOMATIC.\r
1936 //\r
1937 return ;\r
1938 }\r
1939\r
1940 Ip6ConfigStartStatefulAutoConfig (Instance, Instance->OtherInfoOnly);\r
1941}\r
1942\r
1943/**\r
1944 Set the configuration for the EFI IPv6 network stack running on the communication\r
1945 device this EFI IPv6 Configuration Protocol instance manages.\r
1946\r
1947 This function is used to set the configuration data of type DataType for the EFI\r
1948 IPv6 network stack that is running on the communication device that this EFI IPv6\r
1949 Configuration Protocol instance manages.\r
1950\r
1951 DataSize is used to calculate the count of structure instances in the Data for\r
1952 a DataType in which multiple structure instances are allowed.\r
1953\r
1954 This function is always non-blocking. When setting some type of configuration data,\r
1955 an asynchronous process is invoked to check the correctness of the data, such as\r
1956 performing Duplicate Address Detection on the manually set local IPv6 addresses.\r
1957 EFI_NOT_READY is returned immediately to indicate that such an asynchronous process\r
1958 is invoked, and the process is not finished yet. The caller wanting to get the result\r
1959 of the asynchronous process is required to call RegisterDataNotify() to register an\r
1960 event on the specified configuration data. Once the event is signaled, the caller\r
1961 can call GetData() to obtain the configuration data and know the result.\r
1962 For other types of configuration data that do not require an asynchronous configuration\r
1963 process, the result of the operation is immediately returned.\r
1964\r
1965 @param[in] This The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.\r
1966 @param[in] DataType The type of data to set.\r
1967 @param[in] DataSize Size of the buffer pointed to by Data in bytes.\r
1968 @param[in] Data The data buffer to set. The type of the data buffer is\r
1969 associated with the DataType.\r
1970\r
1971 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
1972 network stack was set successfully.\r
1973 @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:\r
1974 - This is NULL.\r
1975 - One or more fields in Data and DataSizedo not match the\r
1976 requirement of the data type indicated by DataType.\r
1977 @retval EFI_WRITE_PROTECTED The specified configuration data is read-only or the specified\r
1978 configuration data cannot be set under the current policy.\r
1979 @retval EFI_ACCESS_DENIED Another set operation on the specified configuration\r
1980 data is already in process.\r
1981 @retval EFI_NOT_READY An asynchronous process was invoked to set the specified\r
1982 configuration data, and the process is not finished yet.\r
1983 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type\r
1984 indicated by DataType.\r
1985 @retval EFI_UNSUPPORTED This DataType is not supported.\r
1986 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
1987 @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred.\r
1988\r
1989**/\r
1990EFI_STATUS\r
1991EFIAPI\r
1992EfiIp6ConfigSetData (\r
1993 IN EFI_IP6_CONFIG_PROTOCOL *This,\r
1994 IN EFI_IP6_CONFIG_DATA_TYPE DataType,\r
1995 IN UINTN DataSize,\r
1996 IN VOID *Data\r
1997 )\r
1998{\r
1999 EFI_TPL OldTpl;\r
2000 EFI_STATUS Status;\r
2001 IP6_CONFIG_INSTANCE *Instance;\r
2002 IP6_SERVICE *IpSb;\r
2003\r
2004 if ((This == NULL) || (Data == NULL && DataSize != 0) || (Data != NULL && DataSize == 0)) {\r
2005 return EFI_INVALID_PARAMETER;\r
2006 }\r
2007\r
2008 if (DataType >= Ip6ConfigDataTypeMaximum) {\r
2009 return EFI_UNSUPPORTED;\r
2010 }\r
2011\r
2012 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);\r
2013 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
2014 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);\r
2015\r
2016 if (IpSb->LinkLocalDadFail) {\r
2017 return EFI_DEVICE_ERROR;\r
2018 }\r
2019\r
2020 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
2021\r
2022 Status = Instance->DataItem[DataType].Status;\r
2023 if (Status != EFI_NOT_READY) {\r
2024\r
2025 if (Instance->DataItem[DataType].SetData == NULL) {\r
2026 //\r
2027 // This type of data is readonly.\r
2028 //\r
2029 Status = EFI_WRITE_PROTECTED;\r
2030 } else {\r
2031\r
2032 Status = Instance->DataItem[DataType].SetData (Instance, DataSize, Data);\r
2033 if (!EFI_ERROR (Status)) {\r
2034 //\r
2035 // Fire up the events registered with this type of data.\r
2036 //\r
2037 NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip6ConfigSignalEvent, NULL);\r
2038 Ip6ConfigWriteConfigData (IpSb->MacString, Instance);\r
2039 } else if (Status == EFI_ABORTED) {\r
2040 //\r
2041 // The SetData is aborted because the data to set is the same with\r
2042 // the one maintained.\r
2043 //\r
2044 Status = EFI_SUCCESS;\r
2045 NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip6ConfigSignalEvent, NULL);\r
2046 }\r
2047 }\r
2048 } else {\r
2049 //\r
2050 // Another asynchronous process is on the way.\r
2051 //\r
2052 Status = EFI_ACCESS_DENIED;\r
2053 }\r
2054\r
2055 gBS->RestoreTPL (OldTpl);\r
2056\r
2057 return Status;\r
2058}\r
2059\r
2060/**\r
2061 Get the configuration data for the EFI IPv6 network stack running on the communication\r
2062 device that this EFI IPv6 Configuration Protocol instance manages.\r
2063\r
2064 This function returns the configuration data of type DataType for the EFI IPv6 network\r
2065 stack running on the communication device that this EFI IPv6 Configuration Protocol instance\r
2066 manages.\r
2067\r
2068 The caller is responsible for allocating the buffer used to return the specified\r
2069 configuration data. The required size will be returned to the caller if the size of\r
2070 the buffer is too small.\r
2071\r
2072 EFI_NOT_READY is returned if the specified configuration data is not ready due to an\r
2073 asynchronous configuration process already in progress. The caller can call RegisterDataNotify()\r
2074 to register an event on the specified configuration data. Once the asynchronous configuration\r
2075 process is finished, the event will be signaled, and a subsequent GetData() call will return\r
2076 the specified configuration data.\r
2077\r
2078 @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance.\r
2079 @param[in] DataType The type of data to get.\r
2080 @param[in, out] DataSize On input, in bytes, the size of Data. On output, in bytes, the\r
2081 size of buffer required to store the specified configuration data.\r
2082 @param[in] Data The data buffer in which the configuration data is returned. The\r
2083 type of the data buffer is associated with the DataType.\r
2084 This is an optional parameter that may be NULL.\r
2085\r
2086 @retval EFI_SUCCESS The specified configuration data was obtained successfully.\r
2087 @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:\r
2088 - This is NULL.\r
2089 - DataSize is NULL.\r
2090 - Data is NULL if *DataSize is not zero.\r
2091 @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified configuration data,\r
2092 and the required size is returned in DataSize.\r
2093 @retval EFI_NOT_READY The specified configuration data is not ready due to an\r
2094 asynchronous configuration process already in progress.\r
2095 @retval EFI_NOT_FOUND The specified configuration data is not found.\r
2096\r
2097**/\r
2098EFI_STATUS\r
2099EFIAPI\r
2100EfiIp6ConfigGetData (\r
2101 IN EFI_IP6_CONFIG_PROTOCOL *This,\r
2102 IN EFI_IP6_CONFIG_DATA_TYPE DataType,\r
2103 IN OUT UINTN *DataSize,\r
2104 IN VOID *Data OPTIONAL\r
2105 )\r
2106{\r
2107 EFI_TPL OldTpl;\r
2108 EFI_STATUS Status;\r
2109 IP6_CONFIG_INSTANCE *Instance;\r
2110 IP6_CONFIG_DATA_ITEM *DataItem;\r
2111\r
2112 if ((This == NULL) || (DataSize == NULL) || ((*DataSize != 0) && (Data == NULL))) {\r
2113 return EFI_INVALID_PARAMETER;\r
2114 }\r
2115\r
2116 if (DataType >= Ip6ConfigDataTypeMaximum) {\r
2117 return EFI_NOT_FOUND;\r
2118 }\r
2119\r
2120 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
2121\r
2122 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);\r
2123 DataItem = &Instance->DataItem[DataType];\r
2124\r
2125 Status = Instance->DataItem[DataType].Status;\r
2126 if (!EFI_ERROR (Status)) {\r
2127\r
2128 if (DataItem->GetData != NULL) {\r
2129\r
2130 Status = DataItem->GetData (Instance, DataSize, Data);\r
2131 } else if (*DataSize < Instance->DataItem[DataType].DataSize) {\r
2132 //\r
2133 // Update the buffer length.\r
2134 //\r
2135 *DataSize = Instance->DataItem[DataType].DataSize;\r
2136 Status = EFI_BUFFER_TOO_SMALL;\r
2137 } else {\r
2138\r
2139 *DataSize = Instance->DataItem[DataType].DataSize;\r
2140 CopyMem (Data, Instance->DataItem[DataType].Data.Ptr, *DataSize);\r
2141 }\r
2142 }\r
2143\r
2144 gBS->RestoreTPL (OldTpl);\r
2145\r
2146 return Status;\r
2147}\r
2148\r
2149/**\r
2150 Register an event that is signaled whenever a configuration process on the specified\r
2151 configuration data is done.\r
2152\r
2153 This function registers an event that is to be signaled whenever a configuration\r
2154 process on the specified configuration data is performed. An event can be registered\r
2155 for a different DataType simultaneously. The caller is responsible for determining\r
2156 which type of configuration data causes the signaling of the event in such an event.\r
2157\r
2158 @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance.\r
2159 @param[in] DataType The type of data to unregister the event for.\r
2160 @param[in] Event The event to register.\r
2161\r
2162 @retval EFI_SUCCESS The notification event for the specified configuration data is\r
2163 registered.\r
2164 @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.\r
2165 @retval EFI_UNSUPPORTED The configuration data type specified by DataType is not\r
2166 supported.\r
2167 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
2168 @retval EFI_ACCESS_DENIED The Event is already registered for the DataType.\r
2169\r
2170**/\r
2171EFI_STATUS\r
2172EFIAPI\r
2173EfiIp6ConfigRegisterDataNotify (\r
2174 IN EFI_IP6_CONFIG_PROTOCOL *This,\r
2175 IN EFI_IP6_CONFIG_DATA_TYPE DataType,\r
2176 IN EFI_EVENT Event\r
2177 )\r
2178{\r
2179 EFI_TPL OldTpl;\r
2180 EFI_STATUS Status;\r
2181 IP6_CONFIG_INSTANCE *Instance;\r
2182 NET_MAP *EventMap;\r
2183 NET_MAP_ITEM *Item;\r
2184\r
2185 if ((This == NULL) || (Event == NULL)) {\r
2186 return EFI_INVALID_PARAMETER;\r
2187 }\r
2188\r
2189 if (DataType >= Ip6ConfigDataTypeMaximum) {\r
2190 return EFI_UNSUPPORTED;\r
2191 }\r
2192\r
2193 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
2194\r
2195 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);\r
2196 EventMap = &Instance->DataItem[DataType].EventMap;\r
2197\r
2198 //\r
2199 // Check whether this event is already registered for this DataType.\r
2200 //\r
2201 Item = NetMapFindKey (EventMap, Event);\r
2202 if (Item == NULL) {\r
2203\r
2204 Status = NetMapInsertTail (EventMap, Event, NULL);\r
2205\r
2206 if (EFI_ERROR (Status)) {\r
2207\r
2208 Status = EFI_OUT_OF_RESOURCES;\r
2209 }\r
2210\r
2211 } else {\r
2212\r
2213 Status = EFI_ACCESS_DENIED;\r
2214 }\r
2215\r
2216 gBS->RestoreTPL (OldTpl);\r
2217\r
2218 return Status;\r
2219}\r
2220\r
2221/**\r
2222 Remove a previously registered event for the specified configuration data.\r
2223\r
2224 @param This The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.\r
2225 @param DataType The type of data to remove from the previously\r
2226 registered event.\r
2227 @param Event The event to be unregistered.\r
2228\r
2229 @retval EFI_SUCCESS The event registered for the specified\r
2230 configuration data was removed.\r
2231 @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.\r
2232 @retval EFI_NOT_FOUND The Event has not been registered for the\r
2233 specified DataType.\r
2234\r
2235**/\r
2236EFI_STATUS\r
2237EFIAPI\r
2238EfiIp6ConfigUnregisterDataNotify (\r
2239 IN EFI_IP6_CONFIG_PROTOCOL *This,\r
2240 IN EFI_IP6_CONFIG_DATA_TYPE DataType,\r
2241 IN EFI_EVENT Event\r
2242 )\r
2243{\r
2244 EFI_TPL OldTpl;\r
2245 EFI_STATUS Status;\r
2246 IP6_CONFIG_INSTANCE *Instance;\r
2247 NET_MAP_ITEM *Item;\r
2248\r
2249 if ((This == NULL) || (Event == NULL)) {\r
2250 return EFI_INVALID_PARAMETER;\r
2251 }\r
2252\r
2253 if (DataType >= Ip6ConfigDataTypeMaximum) {\r
2254 return EFI_NOT_FOUND;\r
2255 }\r
2256\r
2257 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
2258\r
2259 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);\r
2260\r
2261 Item = NetMapFindKey (&Instance->DataItem[DataType].EventMap, Event);\r
2262 if (Item != NULL) {\r
2263\r
2264 NetMapRemoveItem (&Instance->DataItem[DataType].EventMap, Item, NULL);\r
2265 Status = EFI_SUCCESS;\r
2266 } else {\r
2267\r
2268 Status = EFI_NOT_FOUND;\r
2269 }\r
2270\r
2271 gBS->RestoreTPL (OldTpl);\r
2272\r
2273 return Status;\r
2274}\r
2275\r
2276/**\r
2277 Initialize an IP6_CONFIG_INSTANCE.\r
2278\r
2279 @param[out] Instance The buffer of IP6_CONFIG_INSTANCE to be initialized.\r
2280\r
2281 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.\r
2282 @retval EFI_SUCCESS The IP6_CONFIG_INSTANCE initialized successfully.\r
2283\r
2284**/\r
2285EFI_STATUS\r
2286Ip6ConfigInitInstance (\r
2287 OUT IP6_CONFIG_INSTANCE *Instance\r
2288 )\r
2289{\r
2290 IP6_SERVICE *IpSb;\r
2291 IP6_CONFIG_INSTANCE *TmpInstance;\r
2292 LIST_ENTRY *Entry;\r
2293 EFI_STATUS Status;\r
2294 UINTN Index;\r
2295 UINT16 IfIndex;\r
2296 IP6_CONFIG_DATA_ITEM *DataItem;\r
2297\r
2298 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
2299\r
2300 Instance->Signature = IP6_CONFIG_INSTANCE_SIGNATURE;\r
2301\r
2302 //\r
2303 // Determine the index of this interface.\r
2304 //\r
2305 IfIndex = 0;\r
2306 NET_LIST_FOR_EACH (Entry, &mIp6ConfigInstanceList) {\r
2307 TmpInstance = NET_LIST_USER_STRUCT_S (Entry, IP6_CONFIG_INSTANCE, Link, IP6_CONFIG_INSTANCE_SIGNATURE);\r
2308\r
2309 if (TmpInstance->IfIndex > IfIndex) {\r
2310 //\r
2311 // There is a sequence hole because some interface is down.\r
2312 //\r
2313 break;\r
2314 }\r
2315\r
2316 IfIndex++;\r
2317 }\r
2318\r
2319 Instance->IfIndex = IfIndex;\r
2320 NetListInsertBefore (Entry, &Instance->Link);\r
2321\r
2322 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {\r
2323 //\r
2324 // Initialize the event map for each data item.\r
2325 //\r
2326 NetMapInit (&Instance->DataItem[Index].EventMap);\r
2327 }\r
2328\r
2329 //\r
2330 // Initialize the NET_MAPs used for DAD on manually configured source addresses.\r
2331 //\r
2332 NetMapInit (&Instance->DadFailedMap);\r
2333 NetMapInit (&Instance->DadPassedMap);\r
2334\r
2335 //\r
2336 // Initialize each data type: associate storage and set data size for the\r
2337 // fixed size data types, hook the SetData function, set the data attribute.\r
2338 //\r
2339 DataItem = &Instance->DataItem[Ip6ConfigDataTypeInterfaceInfo];\r
2340 DataItem->GetData = Ip6ConfigGetIfInfo;\r
2341 DataItem->Data.Ptr = &Instance->InterfaceInfo;\r
2342 DataItem->DataSize = sizeof (Instance->InterfaceInfo);\r
2343 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED | DATA_ATTRIB_VOLATILE);\r
2344 Ip6ConfigInitIfInfo (IpSb, &Instance->InterfaceInfo);\r
2345\r
2346 DataItem = &Instance->DataItem[Ip6ConfigDataTypeAltInterfaceId];\r
2347 DataItem->SetData = Ip6ConfigSetAltIfId;\r
2348 DataItem->Data.Ptr = &Instance->AltIfId;\r
2349 DataItem->DataSize = sizeof (Instance->AltIfId);\r
2350 DataItem->Status = EFI_NOT_FOUND;\r
2351 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);\r
2352\r
2353 DataItem = &Instance->DataItem[Ip6ConfigDataTypePolicy];\r
2354 DataItem->SetData = Ip6ConfigSetPolicy;\r
2355 DataItem->Data.Ptr = &Instance->Policy;\r
2356 DataItem->DataSize = sizeof (Instance->Policy);\r
2357 Instance->Policy = Ip6ConfigPolicyManual;\r
2358 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);\r
2359\r
2360 DataItem = &Instance->DataItem[Ip6ConfigDataTypeDupAddrDetectTransmits];\r
2361 DataItem->SetData = Ip6ConfigSetDadXmits;\r
2362 DataItem->Data.Ptr = &Instance->DadXmits;\r
2363 DataItem->DataSize = sizeof (Instance->DadXmits);\r
2364 Instance->DadXmits.DupAddrDetectTransmits = IP6_CONFIG_DEFAULT_DAD_XMITS;\r
2365 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);\r
2366\r
2367 DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];\r
2368 DataItem->SetData = Ip6ConfigSetManualAddress;\r
2369 DataItem->Status = EFI_NOT_FOUND;\r
2370\r
2371 DataItem = &Instance->DataItem[Ip6ConfigDataTypeGateway];\r
2372 DataItem->SetData = Ip6ConfigSetGateway;\r
2373 DataItem->Status = EFI_NOT_FOUND;\r
2374\r
2375 DataItem = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];\r
2376 DataItem->SetData = Ip6ConfigSetDnsServer;\r
2377 DataItem->Status = EFI_NOT_FOUND;\r
2378\r
2379 //\r
2380 // Create the event used for DHCP.\r
2381 //\r
2382 Status = gBS->CreateEvent (\r
2383 EVT_NOTIFY_SIGNAL,\r
2384 TPL_CALLBACK,\r
2385 Ip6ConfigOnDhcp6Event,\r
2386 Instance,\r
2387 &Instance->Dhcp6Event\r
2388 );\r
2389 ASSERT_EFI_ERROR (Status);\r
2390\r
2391 Instance->Configured = TRUE;\r
2392\r
2393 //\r
2394 // Try to read the config data from NV variable.\r
2395 //\r
2396 Status = Ip6ConfigReadConfigData (IpSb->MacString, Instance);\r
2397 if (Status == EFI_NOT_FOUND) {\r
2398 //\r
2399 // The NV variable is not set, so generate a random IAID, and write down the\r
2400 // fresh new configuration as the NV variable now.\r
2401 //\r
2402 Instance->IaId = NET_RANDOM (NetRandomInitSeed ());\r
2403\r
2404 for (Index = 0; Index < IpSb->SnpMode.HwAddressSize; Index++) {\r
2405 Instance->IaId |= (IpSb->SnpMode.CurrentAddress.Addr[Index] << ((Index << 3) & 31));\r
2406 }\r
2407\r
2408 Ip6ConfigWriteConfigData (IpSb->MacString, Instance);\r
2409 } else if (EFI_ERROR (Status)) {\r
2410 return Status;\r
2411 }\r
2412\r
2413 Instance->Ip6Config.SetData = EfiIp6ConfigSetData;\r
2414 Instance->Ip6Config.GetData = EfiIp6ConfigGetData;\r
2415 Instance->Ip6Config.RegisterDataNotify = EfiIp6ConfigRegisterDataNotify;\r
2416 Instance->Ip6Config.UnregisterDataNotify = EfiIp6ConfigUnregisterDataNotify;\r
2417\r
2418\r
2419 //\r
2420 // Publish the IP6 configuration form\r
2421 //\r
2422 return Ip6ConfigFormInit (Instance);\r
2423}\r
2424\r
2425/**\r
2426 Release an IP6_CONFIG_INSTANCE.\r
2427\r
2428 @param[in, out] Instance The buffer of IP6_CONFIG_INSTANCE to be freed.\r
2429\r
2430**/\r
2431VOID\r
2432Ip6ConfigCleanInstance (\r
2433 IN OUT IP6_CONFIG_INSTANCE *Instance\r
2434 )\r
2435{\r
2436 UINTN Index;\r
2437 IP6_CONFIG_DATA_ITEM *DataItem;\r
2438\r
2439 if (Instance->DeclineAddress != NULL) {\r
2440 FreePool (Instance->DeclineAddress);\r
2441 }\r
2442\r
2443 if (!Instance->Configured) {\r
2444 return ;\r
2445 }\r
2446\r
2447 if (Instance->Dhcp6Handle != NULL) {\r
2448\r
2449 Ip6ConfigDestroyDhcp6 (Instance);\r
2450 }\r
2451\r
2452 //\r
2453 // Close the event.\r
2454 //\r
2455 if (Instance->Dhcp6Event != NULL) {\r
2456 gBS->CloseEvent (Instance->Dhcp6Event);\r
2457 }\r
2458\r
2459 NetMapClean (&Instance->DadPassedMap);\r
2460 NetMapClean (&Instance->DadFailedMap);\r
2461\r
2462 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {\r
2463\r
2464 DataItem = &Instance->DataItem[Index];\r
2465\r
2466 if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED)) {\r
2467 if (DataItem->Data.Ptr != NULL) {\r
2468 FreePool (DataItem->Data.Ptr);\r
2469 }\r
2470 DataItem->Data.Ptr = NULL;\r
2471 DataItem->DataSize = 0;\r
2472 }\r
2473\r
2474 NetMapClean (&Instance->DataItem[Index].EventMap);\r
2475 }\r
2476\r
2477 Ip6ConfigFormUnload (Instance);\r
2478\r
2479 RemoveEntryList (&Instance->Link);\r
2480}\r
2481\r
2482/**\r
2483 Destroy the Dhcp6 child in IP6_CONFIG_INSTANCE and release the resources.\r
2484\r
2485 @param[in, out] Instance The buffer of IP6_CONFIG_INSTANCE to be freed.\r
2486\r
2487 @retval EFI_SUCCESS The child was successfully destroyed.\r
2488 @retval Others Failed to destroy the child.\r
2489\r
2490**/\r
2491EFI_STATUS\r
2492Ip6ConfigDestroyDhcp6 (\r
2493 IN OUT IP6_CONFIG_INSTANCE *Instance\r
2494 )\r
2495{\r
2496 IP6_SERVICE *IpSb;\r
2497 EFI_STATUS Status;\r
2498 EFI_DHCP6_PROTOCOL *Dhcp6;\r
2499\r
2500 Dhcp6 = Instance->Dhcp6;\r
2501 ASSERT (Dhcp6 != NULL);\r
2502\r
2503 Dhcp6->Stop (Dhcp6);\r
2504 Dhcp6->Configure (Dhcp6, NULL);\r
2505 Instance->Dhcp6 = NULL;\r
2506\r
2507 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
2508\r
2509 //\r
2510 // Close DHCPv6 protocol and destroy the child.\r
2511 //\r
2512 Status = gBS->CloseProtocol (\r
2513 Instance->Dhcp6Handle,\r
2514 &gEfiDhcp6ProtocolGuid,\r
2515 IpSb->Image,\r
2516 IpSb->Controller\r
2517 );\r
2518 if (EFI_ERROR (Status)) {\r
2519 return Status;\r
2520 }\r
2521\r
2522 Status = NetLibDestroyServiceChild (\r
2523 IpSb->Controller,\r
2524 IpSb->Image,\r
2525 &gEfiDhcp6ServiceBindingProtocolGuid,\r
2526 Instance->Dhcp6Handle\r
2527 );\r
2528\r
2529 Instance->Dhcp6Handle = NULL;\r
2530\r
2531 return Status;\r
2532}\r
2533\r