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