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