]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c
MdeModulePkg/PciSioSerial: Fix bad EOL
[mirror_edk2.git] / NetworkPkg / Ip6Dxe / Ip6ConfigImpl.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 The implementation of EFI IPv6 Configuration Protocol.\r
3\r
4720106b 4 Copyright (c) 2009 - 2016, 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
d1c85a17 124 // Set parameters to trigger router solicitation sending in timer handler.\r
a3bcde70
HT
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
142c00c3 222 Oro->OpCode = HTONS (DHCP6_OPT_ORO);\r
a3bcde70 223 Oro->OpLen = HTONS (2);\r
142c00c3 224 *((UINT16 *) &Oro->Data[0]) = HTONS (DHCP6_OPT_DNS_SERVERS);\r
a3bcde70
HT
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
00df35fe
JW
668 //\r
669 // Clean the ManualAddress, Gateway and DnsServers, shrink the variable\r
670 // data size, and fire up all the related events.\r
671 //\r
672 DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];\r
673 if (DataItem->Data.Ptr != NULL) {\r
674 FreePool (DataItem->Data.Ptr);\r
675 }\r
676 DataItem->Data.Ptr = NULL;\r
677 DataItem->DataSize = 0;\r
678 DataItem->Status = EFI_NOT_FOUND;\r
679 NetMapIterate (&DataItem->EventMap, Ip6ConfigSignalEvent, NULL);\r
680\r
681 DataItem = &Instance->DataItem[Ip6ConfigDataTypeGateway];\r
682 if (DataItem->Data.Ptr != NULL) {\r
683 FreePool (DataItem->Data.Ptr);\r
684 }\r
685 DataItem->Data.Ptr = NULL;\r
686 DataItem->DataSize = 0;\r
687 DataItem->Status = EFI_NOT_FOUND;\r
688 NetMapIterate (&DataItem->EventMap, Ip6ConfigSignalEvent, NULL);\r
689\r
690 DataItem = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];\r
691 DataItem->Data.Ptr = NULL;\r
692 DataItem->DataSize = 0;\r
693 DataItem->Status = EFI_NOT_FOUND;\r
694 NetMapIterate (&DataItem->EventMap, Ip6ConfigSignalEvent, NULL);\r
695 \r
696 if (NewPolicy == Ip6ConfigPolicyManual) {\r
a3bcde70
HT
697 //\r
698 // The policy is changed from automatic to manual. Stop the DHCPv6 process\r
699 // and destroy the DHCPv6 child.\r
700 //\r
701 if (Instance->Dhcp6Handle != NULL) {\r
702 Ip6ConfigDestroyDhcp6 (Instance);\r
703 }\r
704 }\r
705\r
706 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
707 Ip6ConfigOnPolicyChanged (IpSb, NewPolicy);\r
708\r
709 Instance->Policy = NewPolicy;\r
710\r
711 return EFI_SUCCESS;\r
712 }\r
713}\r
714\r
715/**\r
716 The work function for EfiIp6ConfigSetData() to set the number of consecutive\r
717 Neighbor Solicitation messages sent while performing Duplicate Address Detection\r
718 on a tentative address. A value of ZERO indicates that Duplicate Address Detection\r
719 will not be performed on a tentative address.\r
720\r
76389e18 721 @param[in] Instance The Instance Pointer to the IP6 config instance data.\r
a3bcde70
HT
722 @param[in] DataSize Size of the buffer pointed to by Data in bytes.\r
723 @param[in] Data The data buffer to set.\r
724\r
725 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.\r
726 @retval EFI_ABORTED The new transmit count equals the current configuration.\r
727 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
728 network stack was set.\r
729\r
730**/\r
731EFI_STATUS\r
732Ip6ConfigSetDadXmits (\r
733 IN IP6_CONFIG_INSTANCE *Instance,\r
734 IN UINTN DataSize,\r
735 IN VOID *Data\r
736 )\r
737{\r
738 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS *OldDadXmits;\r
739\r
740 if (DataSize != sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS)) {\r
741 return EFI_BAD_BUFFER_SIZE;\r
742 }\r
743\r
744 OldDadXmits = Instance->DataItem[Ip6ConfigDataTypeDupAddrDetectTransmits].Data.DadXmits;\r
745\r
746 if ((*(UINT32 *) Data) == OldDadXmits->DupAddrDetectTransmits) {\r
747\r
748 return EFI_ABORTED;\r
749 } else {\r
750\r
751 OldDadXmits->DupAddrDetectTransmits = *((UINT32 *) Data);\r
752 return EFI_SUCCESS;\r
753 }\r
754}\r
755\r
756/**\r
757 The callback function for Ip6SetAddr. The prototype is defined\r
758 as IP6_DAD_CALLBACK. It is called after Duplicate Address Detection is performed\r
759 for the manual address set by Ip6ConfigSetMaunualAddress.\r
760\r
761 @param[in] IsDadPassed If TRUE, Duplicate Address Detection passed.\r
762 @param[in] TargetAddress The tentative IPv6 address to be checked.\r
763 @param[in] Context Pointer to the IP6 configuration instance data.\r
764\r
765**/\r
766VOID\r
767Ip6ManualAddrDadCallback (\r
768 IN BOOLEAN IsDadPassed,\r
769 IN EFI_IPv6_ADDRESS *TargetAddress,\r
770 IN VOID *Context\r
771 )\r
772{\r
773 IP6_CONFIG_INSTANCE *Instance;\r
774 UINTN Index;\r
775 IP6_CONFIG_DATA_ITEM *Item;\r
776 EFI_IP6_CONFIG_MANUAL_ADDRESS *ManualAddr;\r
777 EFI_IP6_CONFIG_MANUAL_ADDRESS *PassedAddr;\r
778 UINTN DadPassCount;\r
779 UINTN DadFailCount;\r
780 IP6_SERVICE *IpSb;\r
781\r
782 Instance = (IP6_CONFIG_INSTANCE *) Context;\r
783 NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);\r
784 Item = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];\r
785 ManualAddr = NULL;\r
786\r
787 for (Index = 0; Index < Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS); Index++) {\r
788 //\r
789 // Find the original tag used to place into the NET_MAP.\r
790 //\r
791 ManualAddr = Item->Data.ManualAddress + Index;\r
792 if (EFI_IP6_EQUAL (TargetAddress, &ManualAddr->Address)) {\r
793 break;\r
794 }\r
795 }\r
796\r
797 ASSERT (Index != Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));\r
798\r
799 if (IsDadPassed) {\r
800 NetMapInsertTail (&Instance->DadPassedMap, ManualAddr, NULL);\r
801 } else {\r
802 NetMapInsertTail (&Instance->DadFailedMap, ManualAddr, NULL);\r
803 }\r
804\r
805 DadPassCount = NetMapGetCount (&Instance->DadPassedMap);\r
806 DadFailCount = NetMapGetCount (&Instance->DadFailedMap);\r
807\r
808 if ((DadPassCount + DadFailCount) == (Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS))) {\r
809 //\r
810 // All addresses have finished the configuration process.\r
811 //\r
812 if (DadFailCount != 0) {\r
813 //\r
814 // There is at least one duplicate address.\r
815 //\r
816 FreePool (Item->Data.Ptr);\r
817\r
818 Item->DataSize = DadPassCount * sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);\r
819 if (Item->DataSize == 0) {\r
820 //\r
821 // All failed, bad luck.\r
822 //\r
823 Item->Data.Ptr = NULL;\r
824 Item->Status = EFI_NOT_FOUND;\r
825 } else {\r
826 //\r
827 // Part of addresses are detected to be duplicates, so update the\r
828 // data with those passed.\r
829 //\r
830 PassedAddr = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) AllocatePool (Item->DataSize);\r
831 ASSERT (PassedAddr != NULL);\r
832\r
833 Item->Data.Ptr = PassedAddr;\r
834 Item->Status = EFI_SUCCESS;\r
835\r
836 while (!NetMapIsEmpty (&Instance->DadPassedMap)) {\r
837 ManualAddr = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) NetMapRemoveHead (&Instance->DadPassedMap, NULL);\r
838 CopyMem (PassedAddr, ManualAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));\r
839\r
840 PassedAddr++;\r
841 }\r
842\r
843 ASSERT ((UINTN) PassedAddr - (UINTN) Item->Data.Ptr == Item->DataSize);\r
844 }\r
845 } else {\r
846 //\r
847 // All addresses are valid.\r
848 //\r
849 Item->Status = EFI_SUCCESS;\r
850 }\r
851\r
852 //\r
853 // Remove the tags we put in the NET_MAPs.\r
854 //\r
855 while (!NetMapIsEmpty (&Instance->DadFailedMap)) {\r
856 NetMapRemoveHead (&Instance->DadFailedMap, NULL);\r
857 }\r
858\r
859 while (!NetMapIsEmpty (&Instance->DadPassedMap)) {\r
860 NetMapRemoveHead (&Instance->DadPassedMap, NULL);\r
861 }\r
862\r
863 //\r
864 // Signal the waiting events.\r
865 //\r
866 NetMapIterate (&Item->EventMap, Ip6ConfigSignalEvent, NULL);\r
867 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
868 Ip6ConfigWriteConfigData (IpSb->MacString, Instance);\r
869 }\r
870}\r
871\r
872/**\r
873 The work function for EfiIp6ConfigSetData() to set the station addresses manually\r
874 for the EFI IPv6 network stack. It is only configurable when the policy is\r
875 Ip6ConfigPolicyManual.\r
876\r
877 @param[in] Instance Pointer to the IP6 configuration instance data.\r
878 @param[in] DataSize Size of the buffer pointed to by Data in bytes.\r
879 @param[in] Data The data buffer to set.\r
880\r
881 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.\r
882 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set\r
883 under the current policy.\r
884 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.\r
885 @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete the operation.\r
886 @retval EFI_NOT_READY An asynchrous process is invoked to set the specified\r
887 configuration data, and the process is not finished.\r
888 @retval EFI_ABORTED The manual addresses to be set equal current\r
889 configuration.\r
890 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
891 network stack was set.\r
892\r
893**/\r
894EFI_STATUS\r
895Ip6ConfigSetMaunualAddress (\r
896 IN IP6_CONFIG_INSTANCE *Instance,\r
897 IN UINTN DataSize,\r
898 IN VOID *Data\r
899 )\r
900{\r
901 EFI_IP6_CONFIG_MANUAL_ADDRESS *NewAddress;\r
902 EFI_IP6_CONFIG_MANUAL_ADDRESS *TmpAddress;\r
903 IP6_CONFIG_DATA_ITEM *DataItem;\r
904 UINTN NewAddressCount;\r
905 UINTN Index1;\r
906 UINTN Index2;\r
907 IP6_SERVICE *IpSb;\r
908 IP6_ADDRESS_INFO *CurrentAddrInfo;\r
909 IP6_ADDRESS_INFO *Copy;\r
910 LIST_ENTRY CurrentSourceList;\r
911 UINT32 CurrentSourceCount;\r
912 LIST_ENTRY *Entry;\r
913 LIST_ENTRY *Entry2;\r
914 IP6_INTERFACE *IpIf;\r
915 IP6_PREFIX_LIST_ENTRY *PrefixEntry;\r
916 EFI_STATUS Status;\r
917 BOOLEAN IsUpdated;\r
918\r
919 ASSERT (Instance->DataItem[Ip6ConfigDataTypeManualAddress].Status != EFI_NOT_READY);\r
920\r
921 if (((DataSize % sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)) != 0) || (DataSize == 0)) {\r
922 return EFI_BAD_BUFFER_SIZE;\r
923 }\r
924\r
925 if (Instance->Policy != Ip6ConfigPolicyManual) {\r
926 return EFI_WRITE_PROTECTED;\r
927 }\r
928\r
929 NewAddressCount = DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);\r
930 NewAddress = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) Data;\r
931\r
932 for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {\r
933\r
934 if (NetIp6IsLinkLocalAddr (&NewAddress->Address) ||\r
935 !NetIp6IsValidUnicast (&NewAddress->Address) ||\r
936 (NewAddress->PrefixLength > 128)\r
937 ) {\r
938 //\r
939 // make sure the IPv6 address is unicast and not link-local address &&\r
940 // the prefix length is valid.\r
941 //\r
942 return EFI_INVALID_PARAMETER;\r
943 }\r
944\r
945 TmpAddress = NewAddress + 1;\r
946 for (Index2 = Index1 + 1; Index2 < NewAddressCount; Index2++, TmpAddress++) {\r
947 //\r
948 // Any two addresses in the array can't be equal.\r
949 //\r
950 if (EFI_IP6_EQUAL (&TmpAddress->Address, &NewAddress->Address)) {\r
951\r
952 return EFI_INVALID_PARAMETER;\r
953 }\r
954 }\r
955 }\r
956\r
957 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
958\r
959 //\r
960 // Build the current source address list.\r
961 //\r
962 InitializeListHead (&CurrentSourceList);\r
963 CurrentSourceCount = 0;\r
964\r
965 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
966 IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);\r
967\r
968 NET_LIST_FOR_EACH (Entry2, &IpIf->AddressList) {\r
969 CurrentAddrInfo = NET_LIST_USER_STRUCT_S (Entry2, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);\r
970\r
971 Copy = AllocateCopyPool (sizeof (IP6_ADDRESS_INFO), CurrentAddrInfo);\r
972 if (Copy == NULL) {\r
973 break;\r
974 }\r
975\r
976 InsertTailList (&CurrentSourceList, &Copy->Link);\r
977 CurrentSourceCount++;\r
978 }\r
979 }\r
980\r
981 //\r
982 // Update the value... a long journey starts\r
983 //\r
984 NewAddress = AllocateCopyPool (DataSize, Data);\r
985 if (NewAddress == NULL) {\r
986 Ip6RemoveAddr (NULL, &CurrentSourceList, &CurrentSourceCount, NULL, 0);\r
987\r
988 return EFI_OUT_OF_RESOURCES;\r
989 }\r
990\r
991 //\r
992 // Store the new data, and init the DataItem status to EFI_NOT_READY because\r
993 // we may have an asynchronous configuration process.\r
994 //\r
995 DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];\r
996 if (DataItem->Data.Ptr != NULL) {\r
997 FreePool (DataItem->Data.Ptr);\r
998 }\r
999 DataItem->Data.Ptr = NewAddress;\r
1000 DataItem->DataSize = DataSize;\r
1001 DataItem->Status = EFI_NOT_READY;\r
1002\r
1003 //\r
1004 // Trigger DAD, it's an asynchronous process.\r
1005 //\r
1006 IsUpdated = FALSE;\r
1007\r
1008 for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {\r
1009 if (Ip6IsOneOfSetAddress (IpSb, &NewAddress->Address, NULL, &CurrentAddrInfo)) {\r
1010 ASSERT (CurrentAddrInfo != NULL);\r
1011 //\r
1012 // Remove this already existing source address from the CurrentSourceList\r
1013 // built before.\r
1014 //\r
1015 Ip6RemoveAddr (\r
1016 NULL,\r
1017 &CurrentSourceList,\r
1018 &CurrentSourceCount,\r
1019 &CurrentAddrInfo->Address,\r
1020 128\r
1021 );\r
1022\r
ae97201c
FS
1023 //\r
1024 // If the new address's prefix length is not specified, just use the previous configured\r
1025 // prefix length for this address.\r
1026 //\r
1027 if (NewAddress->PrefixLength == 0) {\r
1028 NewAddress->PrefixLength = CurrentAddrInfo->PrefixLength;\r
1029 }\r
1030\r
a3bcde70
HT
1031 //\r
1032 // This manual address is already in use, see whether prefix length is changed.\r
1033 //\r
1034 if (NewAddress->PrefixLength != CurrentAddrInfo->PrefixLength) {\r
1035 //\r
1036 // Remove the on-link prefix table, the route entry will be removed\r
1037 // implicitly.\r
1038 //\r
1039 PrefixEntry = Ip6FindPrefixListEntry (\r
1040 IpSb,\r
1041 TRUE,\r
1042 CurrentAddrInfo->PrefixLength,\r
1043 &CurrentAddrInfo->Address\r
1044 );\r
1045 if (PrefixEntry != NULL) {\r
1046 Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);\r
1047 }\r
1048\r
1049 //\r
1050 // Save the prefix length.\r
1051 //\r
1052 CurrentAddrInfo->PrefixLength = NewAddress->PrefixLength;\r
1053 IsUpdated = TRUE;\r
1054 }\r
1055\r
1056 //\r
1057 // create a new on-link prefix entry.\r
1058 //\r
1059 PrefixEntry = Ip6FindPrefixListEntry (\r
1060 IpSb,\r
1061 TRUE,\r
1062 NewAddress->PrefixLength,\r
1063 &NewAddress->Address\r
1064 );\r
1065 if (PrefixEntry == NULL) {\r
1066 Ip6CreatePrefixListEntry (\r
1067 IpSb,\r
1068 TRUE,\r
1069 (UINT32) IP6_INFINIT_LIFETIME,\r
1070 (UINT32) IP6_INFINIT_LIFETIME,\r
1071 NewAddress->PrefixLength,\r
1072 &NewAddress->Address\r
1073 );\r
1074 }\r
1075\r
1076 CurrentAddrInfo->IsAnycast = NewAddress->IsAnycast;\r
1077 //\r
1078 // Artificially mark this address passed DAD be'coz it is already in use.\r
1079 //\r
1080 Ip6ManualAddrDadCallback (TRUE, &NewAddress->Address, Instance);\r
1081 } else {\r
1082 //\r
1083 // A new address.\r
1084 //\r
1085 IsUpdated = TRUE;\r
1086\r
1087 //\r
1088 // Set the new address, this will trigger DAD and activate the address if\r
1089 // DAD succeeds.\r
1090 //\r
1091 Ip6SetAddress (\r
1092 IpSb->DefaultInterface,\r
1093 &NewAddress->Address,\r
1094 NewAddress->IsAnycast,\r
1095 NewAddress->PrefixLength,\r
1096 (UINT32) IP6_INFINIT_LIFETIME,\r
1097 (UINT32) IP6_INFINIT_LIFETIME,\r
1098 Ip6ManualAddrDadCallback,\r
1099 Instance\r
1100 );\r
1101 }\r
1102 }\r
1103\r
1104 //\r
1105 // Check the CurrentSourceList, it now contains those addresses currently in\r
1106 // use and will be removed.\r
1107 //\r
1108 IpIf = IpSb->DefaultInterface;\r
1109\r
1110 while (!IsListEmpty (&CurrentSourceList)) {\r
1111 IsUpdated = TRUE;\r
1112\r
1113 CurrentAddrInfo = NET_LIST_HEAD (&CurrentSourceList, IP6_ADDRESS_INFO, Link);\r
1114\r
1115 //\r
1116 // This local address is going to be removed, the IP instances that are\r
1117 // currently using it will be destroyed.\r
1118 //\r
1119 Ip6RemoveAddr (\r
1120 IpSb,\r
1121 &IpIf->AddressList,\r
1122 &IpIf->AddressCount,\r
1123 &CurrentAddrInfo->Address,\r
1124 128\r
1125 );\r
1126\r
1127 //\r
1128 // Remove the on-link prefix table, the route entry will be removed\r
1129 // implicitly.\r
1130 //\r
1131 PrefixEntry = Ip6FindPrefixListEntry (\r
1132 IpSb,\r
1133 TRUE,\r
1134 CurrentAddrInfo->PrefixLength,\r
1135 &CurrentAddrInfo->Address\r
1136 );\r
1137 if (PrefixEntry != NULL) {\r
1138 Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);\r
1139 }\r
1140\r
1141 RemoveEntryList (&CurrentAddrInfo->Link);\r
1142 FreePool (CurrentAddrInfo);\r
1143 }\r
1144\r
1145 if (IsUpdated) {\r
1146 if (DataItem->Status == EFI_NOT_READY) {\r
1147 //\r
1148 // If DAD is disabled on this interface, the configuration process is\r
1149 // actually synchronous, and the data item's status will be changed to\r
1150 // the final status before we reach here, just check it.\r
1151 //\r
1152 Status = EFI_NOT_READY;\r
1153 } else {\r
1154 Status = EFI_SUCCESS;\r
1155 }\r
1156 } else {\r
1157 //\r
1158 // No update is taken, reset the status to success and return EFI_ABORTED.\r
1159 //\r
1160 DataItem->Status = EFI_SUCCESS;\r
1161 Status = EFI_ABORTED;\r
1162 }\r
1163\r
1164 return Status;\r
1165}\r
1166\r
1167/**\r
1168 The work function for EfiIp6ConfigSetData() to set the gateway addresses manually\r
1169 for the EFI IPv6 network stack that is running on the communication device that\r
1170 this EFI IPv6 Configuration Protocol manages. It is not configurable when the policy is\r
1171 Ip6ConfigPolicyAutomatic. The gateway addresses must be unicast IPv6 addresses.\r
1172\r
1173 @param[in] Instance The pointer to the IP6 config instance data.\r
1174 @param[in] DataSize The size of the buffer pointed to by Data in bytes.\r
1175 @param[in] Data The data buffer to set. This points to an array of\r
1176 EFI_IPv6_ADDRESS instances.\r
1177\r
1178 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.\r
1179 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set\r
1180 under the current policy.\r
1181 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.\r
1182 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to complete the operation.\r
1183 @retval EFI_ABORTED The manual gateway addresses to be set equal the\r
1184 current configuration.\r
1185 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
1186 network stack was set.\r
1187\r
1188**/\r
1189EFI_STATUS\r
1190Ip6ConfigSetGateway (\r
1191 IN IP6_CONFIG_INSTANCE *Instance,\r
1192 IN UINTN DataSize,\r
1193 IN VOID *Data\r
1194 )\r
1195{\r
1196 UINTN Index1;\r
1197 UINTN Index2;\r
1198 EFI_IPv6_ADDRESS *OldGateway;\r
1199 EFI_IPv6_ADDRESS *NewGateway;\r
1200 UINTN OldGatewayCount;\r
1201 UINTN NewGatewayCount;\r
1202 IP6_CONFIG_DATA_ITEM *Item;\r
1203 BOOLEAN OneRemoved;\r
1204 BOOLEAN OneAdded;\r
1205 IP6_SERVICE *IpSb;\r
1206 IP6_DEFAULT_ROUTER *DefaultRouter;\r
1207 VOID *Tmp;\r
1208\r
1209 if ((DataSize % sizeof (EFI_IPv6_ADDRESS) != 0) || (DataSize == 0)) {\r
1210 return EFI_BAD_BUFFER_SIZE;\r
1211 }\r
1212\r
1213 if (Instance->Policy != Ip6ConfigPolicyManual) {\r
1214 return EFI_WRITE_PROTECTED;\r
1215 }\r
1216\r
1217 NewGateway = (EFI_IPv6_ADDRESS *) Data;\r
1218 NewGatewayCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
1219 for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\r
1220\r
1221 if (!NetIp6IsValidUnicast (NewGateway + Index1)) {\r
1222\r
1223 return EFI_INVALID_PARAMETER;\r
1224 }\r
1225\r
1226 for (Index2 = Index1 + 1; Index2 < NewGatewayCount; Index2++) {\r
1227 if (EFI_IP6_EQUAL (NewGateway + Index1, NewGateway + Index2)) {\r
1228 return EFI_INVALID_PARAMETER;\r
1229 }\r
1230 }\r
1231 }\r
1232\r
1233 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
1234 Item = &Instance->DataItem[Ip6ConfigDataTypeGateway];\r
1235 OldGateway = Item->Data.Gateway;\r
1236 OldGatewayCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);\r
1237 OneRemoved = FALSE;\r
1238 OneAdded = FALSE;\r
1239\r
1240 if (NewGatewayCount != OldGatewayCount) {\r
1241 Tmp = AllocatePool (DataSize);\r
1242 if (Tmp == NULL) {\r
1243 return EFI_OUT_OF_RESOURCES;\r
1244 }\r
1245 } else {\r
1246 Tmp = NULL;\r
1247 }\r
1248\r
1249 for (Index1 = 0; Index1 < OldGatewayCount; Index1++) {\r
1250 //\r
1251 // Find the gateways that are no long in the new setting and remove them.\r
1252 //\r
1253 for (Index2 = 0; Index2 < NewGatewayCount; Index2++) {\r
1254 if (EFI_IP6_EQUAL (OldGateway + Index1, NewGateway + Index2)) {\r
1255 OneRemoved = TRUE;\r
1256 break;\r
1257 }\r
1258 }\r
1259\r
1260 if (Index2 == NewGatewayCount) {\r
1261 //\r
1262 // Remove this default router.\r
1263 //\r
1264 DefaultRouter = Ip6FindDefaultRouter (IpSb, OldGateway + Index1);\r
1265 if (DefaultRouter != NULL) {\r
1266 Ip6DestroyDefaultRouter (IpSb, DefaultRouter);\r
1267 }\r
1268 }\r
1269 }\r
1270\r
1271 for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\r
1272\r
1273 DefaultRouter = Ip6FindDefaultRouter (IpSb, NewGateway + Index1);\r
1274 if (DefaultRouter == NULL) {\r
1275 Ip6CreateDefaultRouter (IpSb, NewGateway + Index1, IP6_INF_ROUTER_LIFETIME);\r
1276 OneAdded = TRUE;\r
1277 }\r
1278 }\r
1279\r
1280 if (!OneRemoved && !OneAdded) {\r
1281 Item->Status = EFI_SUCCESS;\r
1282 return EFI_ABORTED;\r
1283 } else {\r
1284\r
1285 if (Tmp != NULL) {\r
1286 if (Item->Data.Ptr != NULL) {\r
1287 FreePool (Item->Data.Ptr);\r
1288 }\r
1289 Item->Data.Ptr = Tmp;\r
1290 }\r
1291\r
1292 CopyMem (Item->Data.Ptr, Data, DataSize);\r
1293 Item->DataSize = DataSize;\r
1294 Item->Status = EFI_SUCCESS;\r
1295 return EFI_SUCCESS;\r
1296 }\r
1297}\r
1298\r
1299/**\r
1300 The work function for EfiIp6ConfigSetData() to set the DNS server list for the\r
1301 EFI IPv6 network stack running on the communication device that this EFI IPv6\r
1302 Configuration Protocol manages. It is not configurable when the policy is\r
1303 Ip6ConfigPolicyAutomatic. The DNS server addresses must be unicast IPv6 addresses.\r
1304\r
1305 @param[in] Instance The pointer to the IP6 config instance data.\r
1306 @param[in] DataSize The size of the buffer pointed to by Data in bytes.\r
1307 @param[in] Data The data buffer to set, points to an array of\r
1308 EFI_IPv6_ADDRESS instances.\r
1309\r
1310 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.\r
1311 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set\r
1312 under the current policy.\r
1313 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.\r
1314 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.\r
1315 @retval EFI_ABORTED The DNS server addresses to be set equal the current\r
1316 configuration.\r
1317 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
1318 network stack was set.\r
1319\r
1320**/\r
1321EFI_STATUS\r
1322Ip6ConfigSetDnsServer (\r
1323 IN IP6_CONFIG_INSTANCE *Instance,\r
1324 IN UINTN DataSize,\r
1325 IN VOID *Data\r
1326 )\r
1327{\r
1328 UINTN OldIndex;\r
1329 UINTN NewIndex;\r
1330 UINTN Index1;\r
1331 EFI_IPv6_ADDRESS *OldDns;\r
1332 EFI_IPv6_ADDRESS *NewDns;\r
1333 UINTN OldDnsCount;\r
1334 UINTN NewDnsCount;\r
1335 IP6_CONFIG_DATA_ITEM *Item;\r
1336 BOOLEAN OneAdded;\r
1337 VOID *Tmp;\r
1338\r
1339 if ((DataSize % sizeof (EFI_IPv6_ADDRESS) != 0) || (DataSize == 0)) {\r
1340 return EFI_BAD_BUFFER_SIZE;\r
1341 }\r
1342\r
1343 if (Instance->Policy != Ip6ConfigPolicyManual) {\r
1344 return EFI_WRITE_PROTECTED;\r
1345 }\r
1346\r
1347 Item = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];\r
1348 NewDns = (EFI_IPv6_ADDRESS *) Data;\r
1349 OldDns = Item->Data.DnsServers;\r
1350 NewDnsCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
1351 OldDnsCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);\r
1352 OneAdded = FALSE;\r
1353\r
1354 if (NewDnsCount != OldDnsCount) {\r
1355 Tmp = AllocatePool (DataSize);\r
1356 if (Tmp == NULL) {\r
1357 return EFI_OUT_OF_RESOURCES;\r
1358 }\r
1359 } else {\r
1360 Tmp = NULL;\r
1361 }\r
1362\r
1363 for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) {\r
1364\r
1365 if (!NetIp6IsValidUnicast (NewDns + NewIndex)) {\r
1366 //\r
1367 // The dns server address must be unicast.\r
1368 //\r
1369 FreePool (Tmp);\r
1370 return EFI_INVALID_PARAMETER;\r
1371 }\r
1372\r
1373 for (Index1 = NewIndex + 1; Index1 < NewDnsCount; Index1++) {\r
1374 if (EFI_IP6_EQUAL (NewDns + NewIndex, NewDns + Index1)) {\r
1375 FreePool (Tmp);\r
1376 return EFI_INVALID_PARAMETER;\r
1377 }\r
1378 }\r
1379\r
1380 if (OneAdded) {\r
1381 //\r
1382 // If any address in the new setting is not in the old settings, skip the\r
1383 // comparision below.\r
1384 //\r
1385 continue;\r
1386 }\r
1387\r
1388 for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) {\r
1389 if (EFI_IP6_EQUAL (NewDns + NewIndex, OldDns + OldIndex)) {\r
1390 //\r
1391 // If found break out.\r
1392 //\r
1393 break;\r
1394 }\r
1395 }\r
1396\r
1397 if (OldIndex == OldDnsCount) {\r
1398 OneAdded = TRUE;\r
1399 }\r
1400 }\r
1401\r
1402 if (!OneAdded && (DataSize == Item->DataSize)) {\r
1403 //\r
1404 // No new item is added and the size is the same.\r
1405 //\r
1406 Item->Status = EFI_SUCCESS;\r
1407 return EFI_ABORTED;\r
1408 } else {\r
1409 if (Tmp != NULL) {\r
1410 if (Item->Data.Ptr != NULL) {\r
1411 FreePool (Item->Data.Ptr);\r
1412 }\r
1413 Item->Data.Ptr = Tmp;\r
1414 }\r
1415\r
1416 CopyMem (Item->Data.Ptr, Data, DataSize);\r
1417 Item->DataSize = DataSize;\r
1418 Item->Status = EFI_SUCCESS;\r
1419 return EFI_SUCCESS;\r
1420 }\r
1421}\r
1422\r
1423/**\r
1424 Generate the operational state of the interface this IP6 config instance manages\r
1425 and output in EFI_IP6_CONFIG_INTERFACE_INFO.\r
1426\r
1427 @param[in] IpSb The pointer to the IP6 service binding instance.\r
1428 @param[out] IfInfo The pointer to the IP6 configuration interface information structure.\r
1429\r
1430**/\r
1431VOID\r
1432Ip6ConfigInitIfInfo (\r
1433 IN IP6_SERVICE *IpSb,\r
1434 OUT EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo\r
1435 )\r
1436{\r
1437 IfInfo->Name[0] = L'e';\r
1438 IfInfo->Name[1] = L't';\r
1439 IfInfo->Name[2] = L'h';\r
1440 IfInfo->Name[3] = (CHAR16) (L'0' + IpSb->Ip6ConfigInstance.IfIndex);\r
1441 IfInfo->Name[4] = 0;\r
1442\r
1443 IfInfo->IfType = IpSb->SnpMode.IfType;\r
1444 IfInfo->HwAddressSize = IpSb->SnpMode.HwAddressSize;\r
1445 CopyMem (&IfInfo->HwAddress, &IpSb->SnpMode.CurrentAddress, IfInfo->HwAddressSize);\r
1446}\r
1447\r
1448/**\r
1449 Parse DHCPv6 reply packet to get the DNS server list.\r
1450 It is the work function for Ip6ConfigOnDhcp6Reply and Ip6ConfigOnDhcp6Event.\r
1451\r
1452 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL instance.\r
1453 @param[in, out] Instance The pointer to the IP6 configuration instance data.\r
1454 @param[in] Reply The pointer to the DHCPv6 reply packet.\r
1455\r
1456 @retval EFI_SUCCESS The DNS server address was retrieved from the reply packet.\r
1457 @retval EFI_NOT_READY The reply packet does not contain the DNS server option, or\r
1458 the DNS server address is not valid.\r
1459\r
1460**/\r
1461EFI_STATUS\r
1462Ip6ConfigParseDhcpReply (\r
1463 IN EFI_DHCP6_PROTOCOL *Dhcp6,\r
1464 IN OUT IP6_CONFIG_INSTANCE *Instance,\r
1465 IN EFI_DHCP6_PACKET *Reply\r
1466 )\r
1467{\r
1468 EFI_STATUS Status;\r
1469 UINT32 OptCount;\r
1470 EFI_DHCP6_PACKET_OPTION **OptList;\r
1471 UINT16 OpCode;\r
1472 UINT16 Length;\r
1473 UINTN Index;\r
1474 UINTN Index2;\r
1475 EFI_IPv6_ADDRESS *DnsServer;\r
1476 IP6_CONFIG_DATA_ITEM *Item;\r
1477\r
1478 //\r
1479 // A DHCPv6 reply packet is received as the response to our InfoRequest\r
1480 // packet.\r
1481 //\r
1482 OptCount = 0;\r
1483 Status = Dhcp6->Parse (Dhcp6, Reply, &OptCount, NULL);\r
1484 if (Status != EFI_BUFFER_TOO_SMALL) {\r
1485 return EFI_NOT_READY;\r
1486 }\r
1487\r
1488 OptList = AllocatePool (OptCount * sizeof (EFI_DHCP6_PACKET_OPTION *));\r
1489 if (OptList == NULL) {\r
1490 return EFI_NOT_READY;\r
1491 }\r
1492\r
1493 Status = Dhcp6->Parse (Dhcp6, Reply, &OptCount, OptList);\r
1494 if (EFI_ERROR (Status)) {\r
1495 Status = EFI_NOT_READY;\r
1496 goto ON_EXIT;\r
1497 }\r
1498\r
1499 Status = EFI_SUCCESS;\r
1500\r
1501 for (Index = 0; Index < OptCount; Index++) {\r
1502 //\r
1503 // Go through all the options to check the ones we are interested in.\r
1504 // The OpCode and Length are in network byte-order and may not be naturally\r
1505 // aligned.\r
1506 //\r
1507 CopyMem (&OpCode, &OptList[Index]->OpCode, sizeof (OpCode));\r
1508 OpCode = NTOHS (OpCode);\r
1509\r
142c00c3 1510 if (OpCode == DHCP6_OPT_DNS_SERVERS) {\r
a3bcde70
HT
1511 CopyMem (&Length, &OptList[Index]->OpLen, sizeof (Length));\r
1512 Length = NTOHS (Length);\r
1513\r
1514 if ((Length == 0) || ((Length % sizeof (EFI_IPv6_ADDRESS)) != 0)) {\r
1515 //\r
1516 // The length should be a multiple of 16 bytes.\r
1517 //\r
1518 Status = EFI_NOT_READY;\r
1519 break;\r
1520 }\r
1521\r
1522 //\r
1523 // Validate the DnsServers: whether they are unicast addresses.\r
1524 //\r
1525 DnsServer = (EFI_IPv6_ADDRESS *) OptList[Index]->Data;\r
1526 for (Index2 = 0; Index2 < Length / sizeof (EFI_IPv6_ADDRESS); Index2++) {\r
1527 if (!NetIp6IsValidUnicast (DnsServer)) {\r
1528 Status = EFI_NOT_READY;\r
1529 goto ON_EXIT;\r
1530 }\r
1531\r
1532 DnsServer++;\r
1533 }\r
1534\r
1535 Item = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];\r
1536\r
1537 if (Item->DataSize != Length) {\r
1538 if (Item->Data.Ptr != NULL) {\r
1539 FreePool (Item->Data.Ptr);\r
1540 }\r
1541\r
1542 Item->Data.Ptr = AllocatePool (Length);\r
1543 ASSERT (Item->Data.Ptr != NULL);\r
1544 }\r
1545\r
1546 CopyMem (Item->Data.Ptr, OptList[Index]->Data, Length);\r
1547 Item->DataSize = Length;\r
1548 Item->Status = EFI_SUCCESS;\r
1549\r
1550 //\r
1551 // Signal the waiting events.\r
1552 //\r
1553 NetMapIterate (&Item->EventMap, Ip6ConfigSignalEvent, NULL);\r
1554\r
1555 break;\r
1556 }\r
1557 }\r
1558\r
1559ON_EXIT:\r
1560\r
1561 FreePool (OptList);\r
1562 return Status;\r
1563}\r
1564\r
1565/**\r
1566 The callback function for Ip6SetAddr. The prototype is defined\r
1567 as IP6_DAD_CALLBACK. It is called after Duplicate Address Detection is performed\r
1568 on the tentative address by DHCPv6 in Ip6ConfigOnDhcp6Event().\r
1569\r
1570 @param[in] IsDadPassed If TRUE, Duplicate Address Detection passes.\r
1571 @param[in] TargetAddress The tentative IPv6 address to be checked.\r
1572 @param[in] Context Pointer to the IP6 configuration instance data.\r
1573\r
1574**/\r
1575VOID\r
1576Ip6ConfigSetStatefulAddrCallback (\r
1577 IN BOOLEAN IsDadPassed,\r
1578 IN EFI_IPv6_ADDRESS *TargetAddress,\r
1579 IN VOID *Context\r
1580 )\r
1581{\r
1582 IP6_CONFIG_INSTANCE *Instance;\r
1583\r
1584 Instance = (IP6_CONFIG_INSTANCE *) Context;\r
1585 NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);\r
1586\r
1587 //\r
1588 // We should record the addresses that fail the DAD, and DECLINE them.\r
1589 //\r
1590 if (IsDadPassed) {\r
1591 //\r
1592 // Decrease the count, no interests in those passed DAD.\r
1593 //\r
1594 if (Instance->FailedIaAddressCount > 0 ) {\r
1595 Instance->FailedIaAddressCount--;\r
1596 }\r
1597 } else {\r
1598 //\r
1599 // Record it.\r
1600 //\r
1601 IP6_COPY_ADDRESS (Instance->DeclineAddress + Instance->DeclineAddressCount, TargetAddress);\r
1602 Instance->DeclineAddressCount++;\r
1603 }\r
1604\r
1605 if (Instance->FailedIaAddressCount == Instance->DeclineAddressCount) {\r
1606 //\r
1607 // The checking on all addresses are finished.\r
1608 //\r
1609 if (Instance->DeclineAddressCount != 0) {\r
1610 //\r
1611 // Decline those duplicates.\r
1612 //\r
ae97201c
FS
1613 if (Instance->Dhcp6 != NULL) {\r
1614 Instance->Dhcp6->Decline (\r
1615 Instance->Dhcp6,\r
1616 Instance->DeclineAddressCount,\r
1617 Instance->DeclineAddress\r
1618 );\r
1619 }\r
a3bcde70
HT
1620 }\r
1621\r
1622 if (Instance->DeclineAddress != NULL) {\r
1623 FreePool (Instance->DeclineAddress);\r
1624 }\r
1625 Instance->DeclineAddress = NULL;\r
1626 Instance->DeclineAddressCount = 0;\r
1627 }\r
1628}\r
1629\r
1630/**\r
1631 The event handle routine when DHCPv6 process is finished or is updated.\r
1632\r
1633 @param[in] Event Not used.\r
1634 @param[in] Context The pointer to the IP6 configuration instance data.\r
1635\r
1636**/\r
1637VOID\r
1638EFIAPI\r
1639Ip6ConfigOnDhcp6Event (\r
1640 IN EFI_EVENT Event,\r
1641 IN VOID *Context\r
1642 )\r
1643{\r
1644 IP6_CONFIG_INSTANCE *Instance;\r
1645 EFI_DHCP6_PROTOCOL *Dhcp6;\r
1646 EFI_STATUS Status;\r
1647 EFI_DHCP6_MODE_DATA Dhcp6ModeData;\r
1648 EFI_DHCP6_IA *Ia;\r
1649 EFI_DHCP6_IA_ADDRESS *IaAddr;\r
1650 UINT32 Index;\r
1651 IP6_SERVICE *IpSb;\r
1652 IP6_ADDRESS_INFO *AddrInfo;\r
1653 IP6_INTERFACE *IpIf;\r
1654\r
1655 Instance = (IP6_CONFIG_INSTANCE *) Context;\r
1656\r
1657 if ((Instance->Policy != Ip6ConfigPolicyAutomatic) || Instance->OtherInfoOnly) {\r
1658 //\r
1659 // IPv6 is not operating in the automatic policy now or\r
1660 // the DHCPv6 information request message exchange is aborted.\r
1661 //\r
1662 return ;\r
1663 }\r
1664\r
1665 //\r
1666 // The stateful address autoconfiguration is done or updated.\r
1667 //\r
1668 Dhcp6 = Instance->Dhcp6;\r
1669\r
1670 Status = Dhcp6->GetModeData (Dhcp6, &Dhcp6ModeData, NULL);\r
1671 if (EFI_ERROR (Status)) {\r
1672 return ;\r
1673 }\r
1674\r
1675 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
1676 IpIf = IpSb->DefaultInterface;\r
1677 Ia = Dhcp6ModeData.Ia;\r
1678 IaAddr = Ia->IaAddress;\r
1679\r
1680 if (Instance->DeclineAddress != NULL) {\r
1681 FreePool (Instance->DeclineAddress);\r
1682 }\r
1683\r
1684 Instance->DeclineAddress = (EFI_IPv6_ADDRESS *) AllocatePool (Ia->IaAddressCount * sizeof (EFI_IPv6_ADDRESS));\r
1685 if (Instance->DeclineAddress == NULL) {\r
1686 goto ON_EXIT;\r
1687 }\r
1688\r
1689 Instance->FailedIaAddressCount = Ia->IaAddressCount;\r
1690 Instance->DeclineAddressCount = 0;\r
1691\r
1692 for (Index = 0; Index < Ia->IaAddressCount; Index++, IaAddr++) {\r
1693 if (Ia->IaAddress[Index].ValidLifetime != 0 && Ia->State == Dhcp6Bound) {\r
1694 //\r
1695 // Set this address, either it's a new address or with updated lifetimes.\r
1696 // An appropriate prefix length will be set.\r
1697 //\r
1698 Ip6SetAddress (\r
1699 IpIf,\r
1700 &IaAddr->IpAddress,\r
1701 FALSE,\r
1702 0,\r
1703 IaAddr->ValidLifetime,\r
1704 IaAddr->PreferredLifetime,\r
1705 Ip6ConfigSetStatefulAddrCallback,\r
1706 Instance\r
1707 );\r
1708 } else {\r
1709 //\r
1710 // discard this address, artificially decrease the count as if this address\r
1711 // passed DAD.\r
1712 //\r
1713 if (Ip6IsOneOfSetAddress (IpSb, &IaAddr->IpAddress, NULL, &AddrInfo)) {\r
1714 ASSERT (AddrInfo != NULL);\r
1715 Ip6RemoveAddr (\r
1716 IpSb,\r
1717 &IpIf->AddressList,\r
1718 &IpIf->AddressCount,\r
1719 &AddrInfo->Address,\r
1720 AddrInfo->PrefixLength\r
1721 );\r
1722 }\r
1723\r
1724 if (Instance->FailedIaAddressCount > 0) {\r
1725 Instance->FailedIaAddressCount--;\r
1726 }\r
1727 }\r
1728 }\r
1729\r
1730 //\r
1731 // Parse the Reply packet to get the options we need.\r
1732 //\r
1733 if (Dhcp6ModeData.Ia->ReplyPacket != NULL) {\r
1734 Ip6ConfigParseDhcpReply (Dhcp6, Instance, Dhcp6ModeData.Ia->ReplyPacket);\r
1735 }\r
1736\r
1737ON_EXIT:\r
1738\r
1739 FreePool (Dhcp6ModeData.ClientId);\r
1740 FreePool (Dhcp6ModeData.Ia);\r
1741}\r
1742\r
1743/**\r
1744 The event process routine when the DHCPv6 server is answered with a reply packet\r
1745 for an information request.\r
1746\r
1747 @param[in] This Points to the EFI_DHCP6_PROTOCOL.\r
1748 @param[in] Context The pointer to the IP6 configuration instance data.\r
1749 @param[in] Packet The DHCPv6 reply packet.\r
1750\r
1751 @retval EFI_SUCCESS The DNS server address was retrieved from the reply packet.\r
1752 @retval EFI_NOT_READY The reply packet does not contain the DNS server option, or\r
1753 the DNS server address is not valid.\r
1754\r
1755**/\r
1756EFI_STATUS\r
1757EFIAPI\r
1758Ip6ConfigOnDhcp6Reply (\r
1759 IN EFI_DHCP6_PROTOCOL *This,\r
1760 IN VOID *Context,\r
1761 IN EFI_DHCP6_PACKET *Packet\r
1762 )\r
1763{\r
1764 return Ip6ConfigParseDhcpReply (This, (IP6_CONFIG_INSTANCE *) Context, Packet);\r
1765}\r
1766\r
1767/**\r
1768 The event process routine when the DHCPv6 service binding protocol is installed\r
1769 in the system.\r
1770\r
1771 @param[in] Event Not used.\r
1772 @param[in] Context The pointer to the IP6 config instance data.\r
1773\r
1774**/\r
1775VOID\r
1776EFIAPI\r
1777Ip6ConfigOnDhcp6SbInstalled (\r
1778 IN EFI_EVENT Event,\r
1779 IN VOID *Context\r
1780 )\r
1781{\r
1782 IP6_CONFIG_INSTANCE *Instance;\r
1783\r
1784 Instance = (IP6_CONFIG_INSTANCE *) Context;\r
1785\r
1786 if ((Instance->Dhcp6Handle != NULL) || (Instance->Policy != Ip6ConfigPolicyAutomatic)) {\r
1787 //\r
1788 // The DHCP6 child is already created or the policy is no longer AUTOMATIC.\r
1789 //\r
1790 return ;\r
1791 }\r
1792\r
1793 Ip6ConfigStartStatefulAutoConfig (Instance, Instance->OtherInfoOnly);\r
1794}\r
1795\r
1796/**\r
1797 Set the configuration for the EFI IPv6 network stack running on the communication\r
1798 device this EFI IPv6 Configuration Protocol instance manages.\r
1799\r
1800 This function is used to set the configuration data of type DataType for the EFI\r
1801 IPv6 network stack that is running on the communication device that this EFI IPv6\r
1802 Configuration Protocol instance manages.\r
1803\r
1804 DataSize is used to calculate the count of structure instances in the Data for\r
1805 a DataType in which multiple structure instances are allowed.\r
1806\r
1807 This function is always non-blocking. When setting some type of configuration data,\r
1808 an asynchronous process is invoked to check the correctness of the data, such as\r
1809 performing Duplicate Address Detection on the manually set local IPv6 addresses.\r
1810 EFI_NOT_READY is returned immediately to indicate that such an asynchronous process\r
1811 is invoked, and the process is not finished yet. The caller wanting to get the result\r
1812 of the asynchronous process is required to call RegisterDataNotify() to register an\r
1813 event on the specified configuration data. Once the event is signaled, the caller\r
1814 can call GetData() to obtain the configuration data and know the result.\r
1815 For other types of configuration data that do not require an asynchronous configuration\r
1816 process, the result of the operation is immediately returned.\r
1817\r
1818 @param[in] This The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.\r
1819 @param[in] DataType The type of data to set.\r
1820 @param[in] DataSize Size of the buffer pointed to by Data in bytes.\r
1821 @param[in] Data The data buffer to set. The type of the data buffer is\r
1822 associated with the DataType.\r
1823\r
1824 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
1825 network stack was set successfully.\r
1826 @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:\r
1827 - This is NULL.\r
1828 - Data is NULL.\r
1829 - One or more fields in Data do not match the requirement of the\r
1830 data type indicated by DataType.\r
1831 @retval EFI_WRITE_PROTECTED The specified configuration data is read-only or the specified\r
1832 configuration data cannot be set under the current policy.\r
1833 @retval EFI_ACCESS_DENIED Another set operation on the specified configuration\r
1834 data is already in process.\r
1835 @retval EFI_NOT_READY An asynchronous process was invoked to set the specified\r
1836 configuration data, and the process is not finished yet.\r
1837 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type\r
1838 indicated by DataType.\r
1839 @retval EFI_UNSUPPORTED This DataType is not supported.\r
1840 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
1841 @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred.\r
1842\r
1843**/\r
1844EFI_STATUS\r
1845EFIAPI\r
1846EfiIp6ConfigSetData (\r
1847 IN EFI_IP6_CONFIG_PROTOCOL *This,\r
1848 IN EFI_IP6_CONFIG_DATA_TYPE DataType,\r
1849 IN UINTN DataSize,\r
1850 IN VOID *Data\r
1851 )\r
1852{\r
1853 EFI_TPL OldTpl;\r
1854 EFI_STATUS Status;\r
1855 IP6_CONFIG_INSTANCE *Instance;\r
1856 IP6_SERVICE *IpSb;\r
1857\r
1858 if ((This == NULL) || (Data == NULL)) {\r
1859 return EFI_INVALID_PARAMETER;\r
1860 }\r
1861\r
1862 if (DataType >= Ip6ConfigDataTypeMaximum) {\r
1863 return EFI_UNSUPPORTED;\r
1864 }\r
1865\r
1866 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);\r
1867 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
1868 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);\r
1869\r
1870 if (IpSb->LinkLocalDadFail) {\r
1871 return EFI_DEVICE_ERROR;\r
1872 }\r
1873\r
1874 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1875\r
1876 Status = Instance->DataItem[DataType].Status;\r
1877 if (Status != EFI_NOT_READY) {\r
1878\r
1879 if (Instance->DataItem[DataType].SetData == NULL) {\r
1880 //\r
1881 // This type of data is readonly.\r
1882 //\r
1883 Status = EFI_WRITE_PROTECTED;\r
1884 } else {\r
1885\r
1886 Status = Instance->DataItem[DataType].SetData (Instance, DataSize, Data);\r
1887 if (!EFI_ERROR (Status)) {\r
1888 //\r
1889 // Fire up the events registered with this type of data.\r
1890 //\r
1891 NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip6ConfigSignalEvent, NULL);\r
1892 Ip6ConfigWriteConfigData (IpSb->MacString, Instance);\r
1893 } else if (Status == EFI_ABORTED) {\r
1894 //\r
1895 // The SetData is aborted because the data to set is the same with\r
1896 // the one maintained.\r
1897 //\r
1898 Status = EFI_SUCCESS;\r
1899 NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip6ConfigSignalEvent, NULL);\r
1900 }\r
1901 }\r
1902 } else {\r
1903 //\r
1904 // Another asynchornous process is on the way.\r
1905 //\r
1906 Status = EFI_ACCESS_DENIED;\r
1907 }\r
1908\r
1909 gBS->RestoreTPL (OldTpl);\r
1910\r
1911 return Status;\r
1912}\r
1913\r
1914/**\r
1915 Get the configuration data for the EFI IPv6 network stack running on the communication\r
1916 device that this EFI IPv6 Configuration Protocol instance manages.\r
1917\r
1918 This function returns the configuration data of type DataType for the EFI IPv6 network\r
1919 stack running on the communication device that this EFI IPv6 Configuration Protocol instance\r
1920 manages.\r
1921\r
1922 The caller is responsible for allocating the buffer used to return the specified\r
1923 configuration data. The required size will be returned to the caller if the size of\r
1924 the buffer is too small.\r
1925\r
1926 EFI_NOT_READY is returned if the specified configuration data is not ready due to an\r
1927 asynchronous configuration process already in progress. The caller can call RegisterDataNotify()\r
1928 to register an event on the specified configuration data. Once the asynchronous configuration\r
1929 process is finished, the event will be signaled, and a subsequent GetData() call will return\r
1930 the specified configuration data.\r
1931\r
1932 @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance.\r
1933 @param[in] DataType The type of data to get.\r
1934 @param[in, out] DataSize On input, in bytes, the size of Data. On output, in bytes, the\r
1935 size of buffer required to store the specified configuration data.\r
1936 @param[in] Data The data buffer in which the configuration data is returned. The\r
1937 type of the data buffer is associated with the DataType.\r
1938 This is an optional parameter that may be NULL.\r
1939\r
1940 @retval EFI_SUCCESS The specified configuration data was obtained successfully.\r
1941 @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:\r
1942 - This is NULL.\r
1943 - DataSize is NULL.\r
1944 - Data is NULL if *DataSize is not zero.\r
1945 @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified configuration data,\r
1946 and the required size is returned in DataSize.\r
1947 @retval EFI_NOT_READY The specified configuration data is not ready due to an\r
1948 asynchronous configuration process already in progress.\r
1949 @retval EFI_NOT_FOUND The specified configuration data is not found.\r
1950\r
1951**/\r
1952EFI_STATUS\r
1953EFIAPI\r
1954EfiIp6ConfigGetData (\r
1955 IN EFI_IP6_CONFIG_PROTOCOL *This,\r
1956 IN EFI_IP6_CONFIG_DATA_TYPE DataType,\r
1957 IN OUT UINTN *DataSize,\r
1958 IN VOID *Data OPTIONAL\r
1959 )\r
1960{\r
1961 EFI_TPL OldTpl;\r
1962 EFI_STATUS Status;\r
1963 IP6_CONFIG_INSTANCE *Instance;\r
1964 IP6_CONFIG_DATA_ITEM *DataItem;\r
1965\r
1966 if ((This == NULL) || (DataSize == NULL) || ((*DataSize != 0) && (Data == NULL))) {\r
1967 return EFI_INVALID_PARAMETER;\r
1968 }\r
1969\r
1970 if (DataType >= Ip6ConfigDataTypeMaximum) {\r
1971 return EFI_NOT_FOUND;\r
1972 }\r
1973\r
1974 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1975\r
1976 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);\r
1977 DataItem = &Instance->DataItem[DataType];\r
1978\r
1979 Status = Instance->DataItem[DataType].Status;\r
1980 if (!EFI_ERROR (Status)) {\r
1981\r
1982 if (DataItem->GetData != NULL) {\r
1983\r
1984 Status = DataItem->GetData (Instance, DataSize, Data);\r
1985 } else if (*DataSize < Instance->DataItem[DataType].DataSize) {\r
1986 //\r
1987 // Update the buffer length.\r
1988 //\r
1989 *DataSize = Instance->DataItem[DataType].DataSize;\r
1990 Status = EFI_BUFFER_TOO_SMALL;\r
1991 } else {\r
1992\r
1993 *DataSize = Instance->DataItem[DataType].DataSize;\r
1994 CopyMem (Data, Instance->DataItem[DataType].Data.Ptr, *DataSize);\r
1995 }\r
1996 }\r
1997\r
1998 gBS->RestoreTPL (OldTpl);\r
1999\r
2000 return Status;\r
2001}\r
2002\r
2003/**\r
2004 Register an event that is signaled whenever a configuration process on the specified\r
2005 configuration data is done.\r
2006\r
2007 This function registers an event that is to be signaled whenever a configuration\r
2008 process on the specified configuration data is performed. An event can be registered\r
2009 for a different DataType simultaneously. The caller is responsible for determining\r
2010 which type of configuration data causes the signaling of the event in such an event.\r
2011\r
2012 @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance.\r
2013 @param[in] DataType The type of data to unregister the event for.\r
2014 @param[in] Event The event to register.\r
2015\r
2016 @retval EFI_SUCCESS The notification event for the specified configuration data is\r
2017 registered.\r
2018 @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.\r
2019 @retval EFI_UNSUPPORTED The configuration data type specified by DataType is not\r
2020 supported.\r
2021 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
2022 @retval EFI_ACCESS_DENIED The Event is already registered for the DataType.\r
2023\r
2024**/\r
2025EFI_STATUS\r
2026EFIAPI\r
2027EfiIp6ConfigRegisterDataNotify (\r
2028 IN EFI_IP6_CONFIG_PROTOCOL *This,\r
2029 IN EFI_IP6_CONFIG_DATA_TYPE DataType,\r
2030 IN EFI_EVENT Event\r
2031 )\r
2032{\r
2033 EFI_TPL OldTpl;\r
2034 EFI_STATUS Status;\r
2035 IP6_CONFIG_INSTANCE *Instance;\r
2036 NET_MAP *EventMap;\r
2037 NET_MAP_ITEM *Item;\r
2038\r
2039 if ((This == NULL) || (Event == NULL)) {\r
2040 return EFI_INVALID_PARAMETER;\r
2041 }\r
2042\r
2043 if (DataType >= Ip6ConfigDataTypeMaximum) {\r
2044 return EFI_UNSUPPORTED;\r
2045 }\r
2046\r
2047 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
2048\r
2049 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);\r
2050 EventMap = &Instance->DataItem[DataType].EventMap;\r
2051\r
2052 //\r
2053 // Check whether this event is already registered for this DataType.\r
2054 //\r
2055 Item = NetMapFindKey (EventMap, Event);\r
2056 if (Item == NULL) {\r
2057\r
2058 Status = NetMapInsertTail (EventMap, Event, NULL);\r
2059\r
2060 if (EFI_ERROR (Status)) {\r
2061\r
2062 Status = EFI_OUT_OF_RESOURCES;\r
2063 }\r
2064\r
2065 } else {\r
2066\r
2067 Status = EFI_ACCESS_DENIED;\r
2068 }\r
2069\r
2070 gBS->RestoreTPL (OldTpl);\r
2071\r
2072 return Status;\r
2073}\r
2074\r
2075/**\r
2076 Remove a previously registered event for the specified configuration data.\r
2077\r
2078 @param This The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.\r
2079 @param DataType The type of data to remove from the previously\r
2080 registered event.\r
2081 @param Event The event to be unregistered.\r
2082\r
2083 @retval EFI_SUCCESS The event registered for the specified\r
2084 configuration data was removed.\r
2085 @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.\r
2086 @retval EFI_NOT_FOUND The Event has not been registered for the\r
2087 specified DataType.\r
2088\r
2089**/\r
2090EFI_STATUS\r
2091EFIAPI\r
2092EfiIp6ConfigUnregisterDataNotify (\r
2093 IN EFI_IP6_CONFIG_PROTOCOL *This,\r
2094 IN EFI_IP6_CONFIG_DATA_TYPE DataType,\r
2095 IN EFI_EVENT Event\r
2096 )\r
2097{\r
2098 EFI_TPL OldTpl;\r
2099 EFI_STATUS Status;\r
2100 IP6_CONFIG_INSTANCE *Instance;\r
2101 NET_MAP_ITEM *Item;\r
2102\r
2103 if ((This == NULL) || (Event == NULL)) {\r
2104 return EFI_INVALID_PARAMETER;\r
2105 }\r
2106\r
2107 if (DataType >= Ip6ConfigDataTypeMaximum) {\r
2108 return EFI_NOT_FOUND;\r
2109 }\r
2110\r
2111 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
2112\r
2113 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);\r
2114\r
2115 Item = NetMapFindKey (&Instance->DataItem[DataType].EventMap, Event);\r
2116 if (Item != NULL) {\r
2117\r
2118 NetMapRemoveItem (&Instance->DataItem[DataType].EventMap, Item, NULL);\r
2119 Status = EFI_SUCCESS;\r
2120 } else {\r
2121\r
2122 Status = EFI_NOT_FOUND;\r
2123 }\r
2124\r
2125 gBS->RestoreTPL (OldTpl);\r
2126\r
2127 return Status;\r
2128}\r
2129\r
2130/**\r
2131 Initialize an IP6_CONFIG_INSTANCE.\r
2132\r
2133 @param[out] Instance The buffer of IP6_CONFIG_INSTANCE to be initialized.\r
2134\r
2135 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.\r
2136 @retval EFI_SUCCESS The IP6_CONFIG_INSTANCE initialized successfully.\r
2137\r
2138**/\r
2139EFI_STATUS\r
2140Ip6ConfigInitInstance (\r
2141 OUT IP6_CONFIG_INSTANCE *Instance\r
2142 )\r
2143{\r
2144 IP6_SERVICE *IpSb;\r
2145 IP6_CONFIG_INSTANCE *TmpInstance;\r
2146 LIST_ENTRY *Entry;\r
2147 EFI_STATUS Status;\r
2148 UINTN Index;\r
2149 UINT16 IfIndex;\r
2150 IP6_CONFIG_DATA_ITEM *DataItem;\r
2151\r
2152 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
2153\r
2154 Instance->Signature = IP6_CONFIG_INSTANCE_SIGNATURE;\r
2155\r
2156 //\r
2157 // Determine the index of this interface.\r
2158 //\r
2159 IfIndex = 0;\r
2160 NET_LIST_FOR_EACH (Entry, &mIp6ConfigInstanceList) {\r
2161 TmpInstance = NET_LIST_USER_STRUCT_S (Entry, IP6_CONFIG_INSTANCE, Link, IP6_CONFIG_INSTANCE_SIGNATURE);\r
2162\r
2163 if (TmpInstance->IfIndex > IfIndex) {\r
2164 //\r
2165 // There is a sequence hole because some interface is down.\r
2166 //\r
2167 break;\r
2168 }\r
2169\r
2170 IfIndex++;\r
2171 }\r
2172\r
2173 Instance->IfIndex = IfIndex;\r
2174 NetListInsertBefore (Entry, &Instance->Link);\r
2175\r
2176 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {\r
2177 //\r
2178 // Initialize the event map for each data item.\r
2179 //\r
2180 NetMapInit (&Instance->DataItem[Index].EventMap);\r
2181 }\r
2182\r
2183 //\r
2184 // Initialize the NET_MAPs used for DAD on manually configured source addresses.\r
2185 //\r
2186 NetMapInit (&Instance->DadFailedMap);\r
2187 NetMapInit (&Instance->DadPassedMap);\r
2188\r
2189 //\r
2190 // Initialize each data type: associate storage and set data size for the\r
2191 // fixed size data types, hook the SetData function, set the data attribute.\r
2192 //\r
2193 DataItem = &Instance->DataItem[Ip6ConfigDataTypeInterfaceInfo];\r
2194 DataItem->GetData = Ip6ConfigGetIfInfo;\r
2195 DataItem->Data.Ptr = &Instance->InterfaceInfo;\r
2196 DataItem->DataSize = sizeof (Instance->InterfaceInfo);\r
2197 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED | DATA_ATTRIB_VOLATILE);\r
2198 Ip6ConfigInitIfInfo (IpSb, &Instance->InterfaceInfo);\r
2199\r
2200 DataItem = &Instance->DataItem[Ip6ConfigDataTypeAltInterfaceId];\r
2201 DataItem->SetData = Ip6ConfigSetAltIfId;\r
2202 DataItem->Data.Ptr = &Instance->AltIfId;\r
2203 DataItem->DataSize = sizeof (Instance->AltIfId);\r
2204 DataItem->Status = EFI_NOT_FOUND;\r
2205 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);\r
2206\r
2207 DataItem = &Instance->DataItem[Ip6ConfigDataTypePolicy];\r
2208 DataItem->SetData = Ip6ConfigSetPolicy;\r
2209 DataItem->Data.Ptr = &Instance->Policy;\r
2210 DataItem->DataSize = sizeof (Instance->Policy);\r
4720106b 2211 Instance->Policy = Ip6ConfigPolicyManual;\r
a3bcde70
HT
2212 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);\r
2213\r
2214 DataItem = &Instance->DataItem[Ip6ConfigDataTypeDupAddrDetectTransmits];\r
2215 DataItem->SetData = Ip6ConfigSetDadXmits;\r
2216 DataItem->Data.Ptr = &Instance->DadXmits;\r
2217 DataItem->DataSize = sizeof (Instance->DadXmits);\r
2218 Instance->DadXmits.DupAddrDetectTransmits = IP6_CONFIG_DEFAULT_DAD_XMITS;\r
2219 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);\r
2220\r
2221 DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];\r
2222 DataItem->SetData = Ip6ConfigSetMaunualAddress;\r
2223 DataItem->Status = EFI_NOT_FOUND;\r
2224\r
2225 DataItem = &Instance->DataItem[Ip6ConfigDataTypeGateway];\r
2226 DataItem->SetData = Ip6ConfigSetGateway;\r
2227 DataItem->Status = EFI_NOT_FOUND;\r
2228\r
2229 DataItem = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];\r
2230 DataItem->SetData = Ip6ConfigSetDnsServer;\r
2231 DataItem->Status = EFI_NOT_FOUND;\r
2232\r
2233 //\r
2234 // Create the event used for DHCP.\r
2235 //\r
2236 Status = gBS->CreateEvent (\r
2237 EVT_NOTIFY_SIGNAL,\r
2238 TPL_CALLBACK,\r
2239 Ip6ConfigOnDhcp6Event,\r
2240 Instance,\r
2241 &Instance->Dhcp6Event\r
2242 );\r
2243 ASSERT_EFI_ERROR (Status);\r
2244\r
2245 Instance->Configured = TRUE;\r
2246\r
2247 //\r
2248 // Try to read the config data from NV variable.\r
2249 //\r
2250 Status = Ip6ConfigReadConfigData (IpSb->MacString, Instance);\r
2251 if (Status == EFI_NOT_FOUND) {\r
2252 //\r
2253 // The NV variable is not set, so generate a random IAID, and write down the\r
2254 // fresh new configuration as the NV variable now.\r
2255 //\r
2256 Instance->IaId = NET_RANDOM (NetRandomInitSeed ());\r
2257\r
2258 for (Index = 0; Index < IpSb->SnpMode.HwAddressSize; Index++) {\r
2259 Instance->IaId |= (IpSb->SnpMode.CurrentAddress.Addr[Index] << ((Index << 3) & 31));\r
2260 }\r
2261\r
2262 Ip6ConfigWriteConfigData (IpSb->MacString, Instance);\r
2263 } else if (EFI_ERROR (Status)) {\r
2264 return Status;\r
2265 }\r
2266\r
2267 Instance->Ip6Config.SetData = EfiIp6ConfigSetData;\r
2268 Instance->Ip6Config.GetData = EfiIp6ConfigGetData;\r
2269 Instance->Ip6Config.RegisterDataNotify = EfiIp6ConfigRegisterDataNotify;\r
2270 Instance->Ip6Config.UnregisterDataNotify = EfiIp6ConfigUnregisterDataNotify;\r
2271\r
2272\r
2273 //\r
2274 // Publish the IP6 configuration form\r
2275 //\r
2276 return Ip6ConfigFormInit (Instance);\r
2277}\r
2278\r
2279/**\r
2280 Release an IP6_CONFIG_INSTANCE.\r
2281\r
2282 @param[in, out] Instance The buffer of IP6_CONFIG_INSTANCE to be freed.\r
2283\r
2284**/\r
2285VOID\r
2286Ip6ConfigCleanInstance (\r
2287 IN OUT IP6_CONFIG_INSTANCE *Instance\r
2288 )\r
2289{\r
2290 UINTN Index;\r
2291 IP6_CONFIG_DATA_ITEM *DataItem;\r
2292\r
2293 if (Instance->DeclineAddress != NULL) {\r
2294 FreePool (Instance->DeclineAddress);\r
2295 }\r
2296\r
2297 if (!Instance->Configured) {\r
2298 return ;\r
2299 }\r
2300\r
2301 if (Instance->Dhcp6Handle != NULL) {\r
2302\r
2303 Ip6ConfigDestroyDhcp6 (Instance);\r
2304 }\r
2305\r
2306 //\r
2307 // Close the event.\r
2308 //\r
2309 if (Instance->Dhcp6Event != NULL) {\r
2310 gBS->CloseEvent (Instance->Dhcp6Event);\r
2311 }\r
2312\r
2313 NetMapClean (&Instance->DadPassedMap);\r
2314 NetMapClean (&Instance->DadFailedMap);\r
2315\r
2316 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {\r
2317\r
2318 DataItem = &Instance->DataItem[Index];\r
2319\r
2320 if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED)) {\r
2321 if (DataItem->Data.Ptr != NULL) {\r
2322 FreePool (DataItem->Data.Ptr);\r
2323 }\r
2324 DataItem->Data.Ptr = NULL;\r
2325 DataItem->DataSize = 0;\r
2326 }\r
2327\r
2328 NetMapClean (&Instance->DataItem[Index].EventMap);\r
2329 }\r
2330\r
2331 Ip6ConfigFormUnload (Instance);\r
2332\r
2333 RemoveEntryList (&Instance->Link);\r
2334}\r
2335\r
2336/**\r
75dce340 2337 Destroy the Dhcp6 child in IP6_CONFIG_INSTANCE and release the resources.\r
a3bcde70
HT
2338\r
2339 @param[in, out] Instance The buffer of IP6_CONFIG_INSTANCE to be freed.\r
2340\r
2341 @retval EFI_SUCCESS The child was successfully destroyed.\r
75dce340 2342 @retval Others Failed to destroy the child.\r
a3bcde70
HT
2343\r
2344**/\r
2345EFI_STATUS\r
2346Ip6ConfigDestroyDhcp6 (\r
2347 IN OUT IP6_CONFIG_INSTANCE *Instance\r
2348 )\r
2349{\r
2350 IP6_SERVICE *IpSb;\r
2351 EFI_STATUS Status;\r
2352 EFI_DHCP6_PROTOCOL *Dhcp6;\r
2353\r
2354 Dhcp6 = Instance->Dhcp6;\r
2355 ASSERT (Dhcp6 != NULL);\r
2356\r
2357 Dhcp6->Stop (Dhcp6);\r
2358 Dhcp6->Configure (Dhcp6, NULL);\r
2359 Instance->Dhcp6 = NULL;\r
2360\r
2361 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
2362\r
2363 //\r
2364 // Close DHCPv6 protocol and destroy the child.\r
2365 //\r
2366 Status = gBS->CloseProtocol (\r
2367 Instance->Dhcp6Handle,\r
2368 &gEfiDhcp6ProtocolGuid,\r
2369 IpSb->Image,\r
2370 IpSb->Controller\r
2371 );\r
2372 if (EFI_ERROR (Status)) {\r
2373 return Status;\r
2374 }\r
2375\r
2376 Status = NetLibDestroyServiceChild (\r
2377 IpSb->Controller,\r
2378 IpSb->Image,\r
2379 &gEfiDhcp6ServiceBindingProtocolGuid,\r
2380 Instance->Dhcp6Handle\r
2381 );\r
2382\r
2383 Instance->Dhcp6Handle = NULL;\r
2384\r
2385 return Status;\r
2386}\r
2387\r