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