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