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