]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c
NetworkPkg/Ip6Dxe: 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
bee7fe0e
JW
956 LIST_ENTRY *Next;\r
957 IP6_DAD_ENTRY *DadEntry;\r
958 IP6_DELAY_JOIN_LIST *DelayNode;\r
959\r
960 NewAddress = NULL;\r
961 TmpAddress = NULL;\r
962 CurrentAddrInfo = NULL;\r
963 Copy = NULL;\r
964 Entry = NULL;\r
965 Entry2 = NULL;\r
966 IpIf = NULL;\r
967 PrefixEntry = NULL;\r
968 Next = NULL;\r
969 DadEntry = NULL;\r
970 DelayNode = NULL;\r
971 Status = EFI_SUCCESS;\r
a3bcde70
HT
972\r
973 ASSERT (Instance->DataItem[Ip6ConfigDataTypeManualAddress].Status != EFI_NOT_READY);\r
974\r
bee7fe0e 975 if ((DataSize != 0) && ((DataSize % sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)) != 0)) {\r
a3bcde70
HT
976 return EFI_BAD_BUFFER_SIZE;\r
977 }\r
978\r
979 if (Instance->Policy != Ip6ConfigPolicyManual) {\r
980 return EFI_WRITE_PROTECTED;\r
981 }\r
982\r
bee7fe0e 983 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
a3bcde70 984\r
bee7fe0e 985 DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];\r
a3bcde70 986\r
bee7fe0e
JW
987 if (Data != NULL && DataSize != 0) {\r
988 NewAddressCount = DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);\r
989 NewAddress = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) Data;\r
a3bcde70 990\r
bee7fe0e 991 for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {\r
a3bcde70 992\r
bee7fe0e
JW
993 if (NetIp6IsLinkLocalAddr (&NewAddress->Address) ||\r
994 !NetIp6IsValidUnicast (&NewAddress->Address) ||\r
995 (NewAddress->PrefixLength > 128)\r
996 ) {\r
997 //\r
998 // make sure the IPv6 address is unicast and not link-local address &&\r
999 // the prefix length is valid.\r
1000 //\r
a3bcde70
HT
1001 return EFI_INVALID_PARAMETER;\r
1002 }\r
bee7fe0e
JW
1003\r
1004 TmpAddress = NewAddress + 1;\r
1005 for (Index2 = Index1 + 1; Index2 < NewAddressCount; Index2++, TmpAddress++) {\r
1006 //\r
1007 // Any two addresses in the array can't be equal.\r
1008 //\r
1009 if (EFI_IP6_EQUAL (&TmpAddress->Address, &NewAddress->Address)) {\r
1010\r
1011 return EFI_INVALID_PARAMETER;\r
1012 }\r
1013 }\r
a3bcde70 1014 }\r
a3bcde70 1015\r
bee7fe0e
JW
1016 //\r
1017 // Build the current source address list.\r
1018 //\r
1019 InitializeListHead (&CurrentSourceList);\r
1020 CurrentSourceCount = 0;\r
a3bcde70 1021\r
bee7fe0e
JW
1022 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
1023 IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);\r
a3bcde70 1024\r
bee7fe0e
JW
1025 NET_LIST_FOR_EACH (Entry2, &IpIf->AddressList) {\r
1026 CurrentAddrInfo = NET_LIST_USER_STRUCT_S (Entry2, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);\r
a3bcde70 1027\r
bee7fe0e
JW
1028 Copy = AllocateCopyPool (sizeof (IP6_ADDRESS_INFO), CurrentAddrInfo);\r
1029 if (Copy == NULL) {\r
1030 break;\r
1031 }\r
a3bcde70 1032\r
bee7fe0e
JW
1033 InsertTailList (&CurrentSourceList, &Copy->Link);\r
1034 CurrentSourceCount++;\r
a3bcde70 1035 }\r
bee7fe0e
JW
1036 }\r
1037\r
1038 //\r
1039 // Update the value... a long journey starts\r
1040 //\r
1041 NewAddress = AllocateCopyPool (DataSize, Data);\r
1042 if (NewAddress == NULL) {\r
1043 Ip6RemoveAddr (NULL, &CurrentSourceList, &CurrentSourceCount, NULL, 0);\r
a3bcde70 1044\r
bee7fe0e 1045 return EFI_OUT_OF_RESOURCES;\r
a3bcde70 1046 }\r
a3bcde70 1047\r
bee7fe0e
JW
1048 //\r
1049 // Store the new data, and init the DataItem status to EFI_NOT_READY because\r
1050 // we may have an asynchronous configuration process.\r
1051 //\r
1052 if (DataItem->Data.Ptr != NULL) {\r
1053 FreePool (DataItem->Data.Ptr);\r
1054 }\r
1055 DataItem->Data.Ptr = NewAddress;\r
1056 DataItem->DataSize = DataSize;\r
1057 DataItem->Status = EFI_NOT_READY;\r
a3bcde70 1058\r
bee7fe0e
JW
1059 //\r
1060 // Trigger DAD, it's an asynchronous process.\r
1061 //\r
1062 IsUpdated = FALSE;\r
a3bcde70 1063\r
bee7fe0e
JW
1064 for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {\r
1065 if (Ip6IsOneOfSetAddress (IpSb, &NewAddress->Address, NULL, &CurrentAddrInfo)) {\r
1066 ASSERT (CurrentAddrInfo != NULL);\r
1067 //\r
1068 // Remove this already existing source address from the CurrentSourceList\r
1069 // built before.\r
1070 //\r
1071 Ip6RemoveAddr (\r
1072 NULL,\r
1073 &CurrentSourceList,\r
1074 &CurrentSourceCount,\r
1075 &CurrentAddrInfo->Address,\r
1076 128\r
1077 );\r
a3bcde70 1078\r
bee7fe0e
JW
1079 //\r
1080 // If the new address's prefix length is not specified, just use the previous configured\r
1081 // prefix length for this address.\r
1082 //\r
1083 if (NewAddress->PrefixLength == 0) {\r
1084 NewAddress->PrefixLength = CurrentAddrInfo->PrefixLength;\r
1085 }\r
a3bcde70 1086\r
bee7fe0e
JW
1087 //\r
1088 // This manual address is already in use, see whether prefix length is changed.\r
1089 //\r
1090 if (NewAddress->PrefixLength != CurrentAddrInfo->PrefixLength) {\r
1091 //\r
1092 // Remove the on-link prefix table, the route entry will be removed\r
1093 // implicitly.\r
1094 //\r
1095 PrefixEntry = Ip6FindPrefixListEntry (\r
1096 IpSb,\r
1097 TRUE,\r
1098 CurrentAddrInfo->PrefixLength,\r
1099 &CurrentAddrInfo->Address\r
1100 );\r
1101 if (PrefixEntry != NULL) {\r
1102 Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);\r
1103 }\r
a3bcde70 1104\r
bee7fe0e
JW
1105 //\r
1106 // Save the prefix length.\r
1107 //\r
1108 CurrentAddrInfo->PrefixLength = NewAddress->PrefixLength;\r
1109 IsUpdated = TRUE;\r
1110 }\r
ae97201c 1111\r
a3bcde70 1112 //\r
bee7fe0e 1113 // create a new on-link prefix entry.\r
a3bcde70
HT
1114 //\r
1115 PrefixEntry = Ip6FindPrefixListEntry (\r
1116 IpSb,\r
1117 TRUE,\r
bee7fe0e
JW
1118 NewAddress->PrefixLength,\r
1119 &NewAddress->Address\r
a3bcde70 1120 );\r
bee7fe0e
JW
1121 if (PrefixEntry == NULL) {\r
1122 Ip6CreatePrefixListEntry (\r
1123 IpSb,\r
1124 TRUE,\r
1125 (UINT32) IP6_INFINIT_LIFETIME,\r
1126 (UINT32) IP6_INFINIT_LIFETIME,\r
1127 NewAddress->PrefixLength,\r
1128 &NewAddress->Address\r
1129 );\r
a3bcde70
HT
1130 }\r
1131\r
bee7fe0e 1132 CurrentAddrInfo->IsAnycast = NewAddress->IsAnycast;\r
a3bcde70 1133 //\r
bee7fe0e
JW
1134 // Artificially mark this address passed DAD be'coz it is already in use.\r
1135 //\r
1136 Ip6ManualAddrDadCallback (TRUE, &NewAddress->Address, Instance);\r
1137 } else {\r
1138 //\r
1139 // A new address.\r
a3bcde70 1140 //\r
a3bcde70 1141 IsUpdated = TRUE;\r
bee7fe0e
JW
1142\r
1143 //\r
1144 // Set the new address, this will trigger DAD and activate the address if\r
1145 // DAD succeeds.\r
1146 //\r
1147 Ip6SetAddress (\r
1148 IpSb->DefaultInterface,\r
1149 &NewAddress->Address,\r
1150 NewAddress->IsAnycast,\r
1151 NewAddress->PrefixLength,\r
1152 (UINT32) IP6_INFINIT_LIFETIME,\r
1153 (UINT32) IP6_INFINIT_LIFETIME,\r
1154 Ip6ManualAddrDadCallback,\r
1155 Instance\r
1156 );\r
a3bcde70 1157 }\r
bee7fe0e
JW
1158 }\r
1159\r
1160 //\r
1161 // Check the CurrentSourceList, it now contains those addresses currently in\r
1162 // use and will be removed.\r
1163 //\r
1164 IpIf = IpSb->DefaultInterface;\r
1165\r
1166 while (!IsListEmpty (&CurrentSourceList)) {\r
1167 IsUpdated = TRUE;\r
1168\r
1169 CurrentAddrInfo = NET_LIST_HEAD (&CurrentSourceList, IP6_ADDRESS_INFO, Link);\r
a3bcde70
HT
1170\r
1171 //\r
bee7fe0e
JW
1172 // This local address is going to be removed, the IP instances that are\r
1173 // currently using it will be destroyed.\r
1174 //\r
1175 Ip6RemoveAddr (\r
1176 IpSb,\r
1177 &IpIf->AddressList,\r
1178 &IpIf->AddressCount,\r
1179 &CurrentAddrInfo->Address,\r
1180 128\r
1181 );\r
1182\r
1183 //\r
1184 // Remove the on-link prefix table, the route entry will be removed\r
1185 // implicitly.\r
a3bcde70
HT
1186 //\r
1187 PrefixEntry = Ip6FindPrefixListEntry (\r
1188 IpSb,\r
1189 TRUE,\r
bee7fe0e
JW
1190 CurrentAddrInfo->PrefixLength,\r
1191 &CurrentAddrInfo->Address\r
a3bcde70 1192 );\r
bee7fe0e
JW
1193 if (PrefixEntry != NULL) {\r
1194 Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);\r
a3bcde70
HT
1195 }\r
1196\r
bee7fe0e
JW
1197 RemoveEntryList (&CurrentAddrInfo->Link);\r
1198 FreePool (CurrentAddrInfo);\r
1199 }\r
1200\r
1201 if (IsUpdated) {\r
1202 if (DataItem->Status == EFI_NOT_READY) {\r
1203 //\r
1204 // If DAD is disabled on this interface, the configuration process is\r
1205 // actually synchronous, and the data item's status will be changed to\r
1206 // the final status before we reach here, just check it.\r
1207 //\r
1208 Status = EFI_NOT_READY;\r
1209 } else {\r
1210 Status = EFI_SUCCESS;\r
1211 }\r
a3bcde70
HT
1212 } else {\r
1213 //\r
bee7fe0e 1214 // No update is taken, reset the status to success and return EFI_ABORTED.\r
a3bcde70 1215 //\r
bee7fe0e
JW
1216 DataItem->Status = EFI_SUCCESS;\r
1217 Status = EFI_ABORTED;\r
1218 }\r
1219 } else {\r
1220 //\r
1221 // DataSize is 0 and Data is NULL, clean up the manual address.\r
1222 //\r
1223 if (DataItem->Data.Ptr != NULL) {\r
1224 FreePool (DataItem->Data.Ptr);\r
1225 }\r
1226 DataItem->Data.Ptr = NULL;\r
1227 DataItem->DataSize = 0;\r
1228 DataItem->Status = EFI_NOT_FOUND;\r
a3bcde70 1229\r
bee7fe0e
JW
1230 Ip6CleanDefaultRouterList (IpSb);\r
1231 Ip6CleanPrefixListTable (IpSb, &IpSb->OnlinkPrefix);\r
1232 Ip6CleanPrefixListTable (IpSb, &IpSb->AutonomousPrefix);\r
1233 Ip6CleanAssembleTable (&IpSb->Assemble);\r
1234\r
1235 if (IpSb->LinkLocalOk) {\r
1236 Ip6CreatePrefixListEntry (\r
1237 IpSb,\r
1238 TRUE,\r
a3bcde70
HT
1239 (UINT32) IP6_INFINIT_LIFETIME,\r
1240 (UINT32) IP6_INFINIT_LIFETIME,\r
bee7fe0e
JW
1241 IP6_LINK_LOCAL_PREFIX_LENGTH,\r
1242 &IpSb->LinkLocalAddr\r
a3bcde70
HT
1243 );\r
1244 }\r
a3bcde70 1245\r
a3bcde70
HT
1246 Ip6RemoveAddr (\r
1247 IpSb,\r
bee7fe0e
JW
1248 &IpSb->DefaultInterface->AddressList,\r
1249 &IpSb->DefaultInterface->AddressCount,\r
1250 NULL,\r
1251 0\r
a3bcde70
HT
1252 );\r
1253\r
bee7fe0e 1254 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
a3bcde70 1255 //\r
bee7fe0e 1256 // Remove all pending delay node and DAD entries for the global addresses.\r
a3bcde70 1257 //\r
bee7fe0e
JW
1258 IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);\r
1259\r
1260 NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DelayJoinList) {\r
1261 DelayNode = NET_LIST_USER_STRUCT (Entry2, IP6_DELAY_JOIN_LIST, Link);\r
1262 if (!NetIp6IsLinkLocalAddr (&DelayNode->AddressInfo->Address)) {\r
1263 RemoveEntryList (&DelayNode->Link);\r
1264 FreePool (DelayNode);\r
1265 }\r
1266 }\r
1267\r
1268 NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DupAddrDetectList) {\r
1269 DadEntry = NET_LIST_USER_STRUCT_S (Entry2, IP6_DAD_ENTRY, Link, IP6_DAD_ENTRY_SIGNATURE);\r
1270\r
1271 if (!NetIp6IsLinkLocalAddr (&DadEntry->AddressInfo->Address)) {\r
1272 //\r
1273 // Fail this DAD entry if the address is not link-local.\r
1274 //\r
1275 Ip6OnDADFinished (FALSE, IpIf, DadEntry);\r
1276 }\r
1277 }\r
a3bcde70 1278 }\r
a3bcde70
HT
1279 }\r
1280\r
1281 return Status;\r
1282}\r
1283\r
1284/**\r
1285 The work function for EfiIp6ConfigSetData() to set the gateway addresses manually\r
1286 for the EFI IPv6 network stack that is running on the communication device that\r
1287 this EFI IPv6 Configuration Protocol manages. It is not configurable when the policy is\r
1288 Ip6ConfigPolicyAutomatic. The gateway addresses must be unicast IPv6 addresses.\r
1289\r
1290 @param[in] Instance The pointer to the IP6 config instance data.\r
1291 @param[in] DataSize The size of the buffer pointed to by Data in bytes.\r
1292 @param[in] Data The data buffer to set. This points to an array of\r
1293 EFI_IPv6_ADDRESS instances.\r
1294\r
1295 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.\r
1296 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set\r
1297 under the current policy.\r
1298 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.\r
1299 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to complete the operation.\r
1300 @retval EFI_ABORTED The manual gateway addresses to be set equal the\r
1301 current configuration.\r
1302 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
1303 network stack was set.\r
1304\r
1305**/\r
1306EFI_STATUS\r
1307Ip6ConfigSetGateway (\r
1308 IN IP6_CONFIG_INSTANCE *Instance,\r
1309 IN UINTN DataSize,\r
1310 IN VOID *Data\r
1311 )\r
1312{\r
1313 UINTN Index1;\r
1314 UINTN Index2;\r
1315 EFI_IPv6_ADDRESS *OldGateway;\r
1316 EFI_IPv6_ADDRESS *NewGateway;\r
1317 UINTN OldGatewayCount;\r
1318 UINTN NewGatewayCount;\r
1319 IP6_CONFIG_DATA_ITEM *Item;\r
1320 BOOLEAN OneRemoved;\r
1321 BOOLEAN OneAdded;\r
1322 IP6_SERVICE *IpSb;\r
1323 IP6_DEFAULT_ROUTER *DefaultRouter;\r
1324 VOID *Tmp;\r
1325\r
bee7fe0e
JW
1326 OldGateway = NULL;\r
1327 NewGateway = NULL;\r
1328 Item = NULL;\r
1329 DefaultRouter = NULL;\r
1330 Tmp = NULL;\r
1331 OneRemoved = FALSE;\r
1332 OneAdded = FALSE;\r
1333\r
1334 if ((DataSize != 0) && (DataSize % sizeof (EFI_IPv6_ADDRESS) != 0)) {\r
a3bcde70
HT
1335 return EFI_BAD_BUFFER_SIZE;\r
1336 }\r
1337\r
1338 if (Instance->Policy != Ip6ConfigPolicyManual) {\r
1339 return EFI_WRITE_PROTECTED;\r
1340 }\r
1341\r
a3bcde70
HT
1342 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
1343 Item = &Instance->DataItem[Ip6ConfigDataTypeGateway];\r
1344 OldGateway = Item->Data.Gateway;\r
1345 OldGatewayCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);\r
a3bcde70
HT
1346\r
1347 for (Index1 = 0; Index1 < OldGatewayCount; Index1++) {\r
1348 //\r
bee7fe0e 1349 // Remove this default router.\r
a3bcde70 1350 //\r
bee7fe0e
JW
1351 DefaultRouter = Ip6FindDefaultRouter (IpSb, OldGateway + Index1);\r
1352 if (DefaultRouter != NULL) {\r
1353 Ip6DestroyDefaultRouter (IpSb, DefaultRouter);\r
1354 OneRemoved = TRUE;\r
1355 }\r
1356 }\r
1357\r
1358 if (Data != NULL && DataSize != 0) {\r
1359 NewGateway = (EFI_IPv6_ADDRESS *) Data;\r
1360 NewGatewayCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
1361 for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\r
1362\r
1363 if (!NetIp6IsValidUnicast (NewGateway + Index1)) {\r
1364\r
1365 return EFI_INVALID_PARAMETER;\r
1366 }\r
1367\r
1368 for (Index2 = Index1 + 1; Index2 < NewGatewayCount; Index2++) {\r
1369 if (EFI_IP6_EQUAL (NewGateway + Index1, NewGateway + Index2)) {\r
1370 return EFI_INVALID_PARAMETER;\r
1371 }\r
a3bcde70
HT
1372 }\r
1373 }\r
1374\r
bee7fe0e
JW
1375 if (NewGatewayCount != OldGatewayCount) {\r
1376 Tmp = AllocatePool (DataSize);\r
1377 if (Tmp == NULL) {\r
1378 return EFI_OUT_OF_RESOURCES;\r
a3bcde70 1379 }\r
bee7fe0e
JW
1380 } else {\r
1381 Tmp = NULL;\r
a3bcde70 1382 }\r
a3bcde70 1383\r
bee7fe0e 1384 for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\r
a3bcde70 1385\r
bee7fe0e
JW
1386 DefaultRouter = Ip6FindDefaultRouter (IpSb, NewGateway + Index1);\r
1387 if (DefaultRouter == NULL) {\r
1388 Ip6CreateDefaultRouter (IpSb, NewGateway + Index1, IP6_INF_ROUTER_LIFETIME);\r
1389 OneAdded = TRUE;\r
1390 }\r
a3bcde70 1391 }\r
a3bcde70 1392\r
bee7fe0e
JW
1393 if (!OneRemoved && !OneAdded) {\r
1394 Item->Status = EFI_SUCCESS;\r
1395 return EFI_ABORTED;\r
1396 } else {\r
a3bcde70 1397\r
bee7fe0e
JW
1398 if (Tmp != NULL) {\r
1399 if (Item->Data.Ptr != NULL) {\r
1400 FreePool (Item->Data.Ptr);\r
1401 }\r
1402 Item->Data.Ptr = Tmp;\r
a3bcde70 1403 }\r
a3bcde70 1404\r
bee7fe0e
JW
1405 CopyMem (Item->Data.Ptr, Data, DataSize);\r
1406 Item->DataSize = DataSize;\r
1407 Item->Status = EFI_SUCCESS;\r
1408 return EFI_SUCCESS;\r
1409 }\r
1410 } else {\r
1411 //\r
1412 // DataSize is 0 and Data is NULL, clean up the Gateway address.\r
1413 //\r
1414 if (Item->Data.Ptr != NULL) {\r
1415 FreePool (Item->Data.Ptr);\r
1416 }\r
1417 Item->Data.Ptr = NULL;\r
1418 Item->DataSize = 0;\r
1419 Item->Status = EFI_NOT_FOUND;\r
a3bcde70 1420 }\r
bee7fe0e
JW
1421\r
1422 return EFI_SUCCESS;\r
a3bcde70
HT
1423}\r
1424\r
1425/**\r
1426 The work function for EfiIp6ConfigSetData() to set the DNS server list for the\r
1427 EFI IPv6 network stack running on the communication device that this EFI IPv6\r
1428 Configuration Protocol manages. It is not configurable when the policy is\r
1429 Ip6ConfigPolicyAutomatic. The DNS server addresses must be unicast IPv6 addresses.\r
1430\r
1431 @param[in] Instance The pointer to the IP6 config instance data.\r
1432 @param[in] DataSize The size of the buffer pointed to by Data in bytes.\r
1433 @param[in] Data The data buffer to set, points to an array of\r
1434 EFI_IPv6_ADDRESS instances.\r
1435\r
1436 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.\r
1437 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set\r
1438 under the current policy.\r
1439 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.\r
1440 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.\r
1441 @retval EFI_ABORTED The DNS server addresses to be set equal the current\r
1442 configuration.\r
1443 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
1444 network stack was set.\r
1445\r
1446**/\r
1447EFI_STATUS\r
1448Ip6ConfigSetDnsServer (\r
1449 IN IP6_CONFIG_INSTANCE *Instance,\r
1450 IN UINTN DataSize,\r
1451 IN VOID *Data\r
1452 )\r
1453{\r
1454 UINTN OldIndex;\r
1455 UINTN NewIndex;\r
a3bcde70
HT
1456 EFI_IPv6_ADDRESS *OldDns;\r
1457 EFI_IPv6_ADDRESS *NewDns;\r
1458 UINTN OldDnsCount;\r
1459 UINTN NewDnsCount;\r
1460 IP6_CONFIG_DATA_ITEM *Item;\r
1461 BOOLEAN OneAdded;\r
1462 VOID *Tmp;\r
1463\r
bee7fe0e
JW
1464 OldDns = NULL;\r
1465 NewDns = NULL;\r
1466 Item = NULL;\r
1467 Tmp = NULL;\r
1468\r
1469 if ((DataSize == 0) && (DataSize % sizeof (EFI_IPv6_ADDRESS) != 0)) {\r
a3bcde70
HT
1470 return EFI_BAD_BUFFER_SIZE;\r
1471 }\r
1472\r
1473 if (Instance->Policy != Ip6ConfigPolicyManual) {\r
1474 return EFI_WRITE_PROTECTED;\r
1475 }\r
1476\r
bee7fe0e 1477 Item = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];\r
a3bcde70 1478\r
bee7fe0e
JW
1479 if (Data != NULL && DataSize != 0) {\r
1480 NewDns = (EFI_IPv6_ADDRESS *) Data;\r
1481 OldDns = Item->Data.DnsServers;\r
1482 NewDnsCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
1483 OldDnsCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);\r
1484 OneAdded = FALSE;\r
a3bcde70 1485\r
bee7fe0e
JW
1486 if (NewDnsCount != OldDnsCount) {\r
1487 Tmp = AllocatePool (DataSize);\r
1488 if (Tmp == NULL) {\r
1489 return EFI_OUT_OF_RESOURCES;\r
ab50ab6e 1490 }\r
bee7fe0e
JW
1491 } else {\r
1492 Tmp = NULL;\r
a3bcde70
HT
1493 }\r
1494\r
bee7fe0e 1495 for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) {\r
a3bcde70 1496\r
bee7fe0e 1497 if (!NetIp6IsValidUnicast (NewDns + NewIndex)) {\r
a3bcde70 1498 //\r
bee7fe0e 1499 // The dns server address must be unicast.\r
a3bcde70 1500 //\r
bee7fe0e
JW
1501 if (Tmp != NULL) {\r
1502 FreePool (Tmp);\r
1503 }\r
1504 return EFI_INVALID_PARAMETER;\r
a3bcde70 1505 }\r
a3bcde70 1506\r
bee7fe0e
JW
1507 if (OneAdded) {\r
1508 //\r
1509 // If any address in the new setting is not in the old settings, skip the\r
1510 // comparision below.\r
1511 //\r
1512 continue;\r
1513 }\r
1514\r
1515 for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) {\r
1516 if (EFI_IP6_EQUAL (NewDns + NewIndex, OldDns + OldIndex)) {\r
1517 //\r
1518 // If found break out.\r
1519 //\r
1520 break;\r
1521 }\r
1522 }\r
1523\r
1524 if (OldIndex == OldDnsCount) {\r
1525 OneAdded = TRUE;\r
1526 }\r
a3bcde70 1527 }\r
a3bcde70 1528\r
bee7fe0e
JW
1529 if (!OneAdded && (DataSize == Item->DataSize)) {\r
1530 //\r
1531 // No new item is added and the size is the same.\r
1532 //\r
1533 Item->Status = EFI_SUCCESS;\r
1534 return EFI_ABORTED;\r
1535 } else {\r
1536 if (Tmp != NULL) {\r
1537 if (Item->Data.Ptr != NULL) {\r
1538 FreePool (Item->Data.Ptr);\r
1539 }\r
1540 Item->Data.Ptr = Tmp;\r
1541 }\r
1542\r
1543 CopyMem (Item->Data.Ptr, Data, DataSize);\r
1544 Item->DataSize = DataSize;\r
1545 Item->Status = EFI_SUCCESS;\r
1546 }\r
1547 } else {\r
a3bcde70 1548 //\r
bee7fe0e 1549 // DataSize is 0 and Data is NULL, clean up the DnsServer address. \r
a3bcde70 1550 //\r
bee7fe0e
JW
1551 if (Item->Data.Ptr != NULL) {\r
1552 FreePool (Item->Data.Ptr);\r
a3bcde70 1553 }\r
bee7fe0e
JW
1554 Item->Data.Ptr = NULL;\r
1555 Item->DataSize = 0;\r
1556 Item->Status = EFI_NOT_FOUND;\r
a3bcde70 1557 }\r
bee7fe0e
JW
1558\r
1559 return EFI_SUCCESS;\r
a3bcde70
HT
1560}\r
1561\r
1562/**\r
1563 Generate the operational state of the interface this IP6 config instance manages\r
1564 and output in EFI_IP6_CONFIG_INTERFACE_INFO.\r
1565\r
1566 @param[in] IpSb The pointer to the IP6 service binding instance.\r
1567 @param[out] IfInfo The pointer to the IP6 configuration interface information structure.\r
1568\r
1569**/\r
1570VOID\r
1571Ip6ConfigInitIfInfo (\r
1572 IN IP6_SERVICE *IpSb,\r
1573 OUT EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo\r
1574 )\r
1575{\r
80e63e84
ZL
1576 UnicodeSPrint (\r
1577 IfInfo->Name,\r
1578 sizeof (IfInfo->Name),\r
625b39ce 1579 L"eth%d",\r
80e63e84
ZL
1580 IpSb->Ip6ConfigInstance.IfIndex\r
1581 );\r
a3bcde70
HT
1582\r
1583 IfInfo->IfType = IpSb->SnpMode.IfType;\r
1584 IfInfo->HwAddressSize = IpSb->SnpMode.HwAddressSize;\r
1585 CopyMem (&IfInfo->HwAddress, &IpSb->SnpMode.CurrentAddress, IfInfo->HwAddressSize);\r
1586}\r
1587\r
1588/**\r
1589 Parse DHCPv6 reply packet to get the DNS server list.\r
1590 It is the work function for Ip6ConfigOnDhcp6Reply and Ip6ConfigOnDhcp6Event.\r
1591\r
1592 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL instance.\r
1593 @param[in, out] Instance The pointer to the IP6 configuration instance data.\r
1594 @param[in] Reply The pointer to the DHCPv6 reply packet.\r
1595\r
1596 @retval EFI_SUCCESS The DNS server address was retrieved from the reply packet.\r
1597 @retval EFI_NOT_READY The reply packet does not contain the DNS server option, or\r
1598 the DNS server address is not valid.\r
1599\r
1600**/\r
1601EFI_STATUS\r
1602Ip6ConfigParseDhcpReply (\r
1603 IN EFI_DHCP6_PROTOCOL *Dhcp6,\r
1604 IN OUT IP6_CONFIG_INSTANCE *Instance,\r
1605 IN EFI_DHCP6_PACKET *Reply\r
1606 )\r
1607{\r
1608 EFI_STATUS Status;\r
1609 UINT32 OptCount;\r
1610 EFI_DHCP6_PACKET_OPTION **OptList;\r
1611 UINT16 OpCode;\r
1612 UINT16 Length;\r
1613 UINTN Index;\r
1614 UINTN Index2;\r
1615 EFI_IPv6_ADDRESS *DnsServer;\r
1616 IP6_CONFIG_DATA_ITEM *Item;\r
1617\r
1618 //\r
1619 // A DHCPv6 reply packet is received as the response to our InfoRequest\r
1620 // packet.\r
1621 //\r
1622 OptCount = 0;\r
1623 Status = Dhcp6->Parse (Dhcp6, Reply, &OptCount, NULL);\r
1624 if (Status != EFI_BUFFER_TOO_SMALL) {\r
1625 return EFI_NOT_READY;\r
1626 }\r
1627\r
1628 OptList = AllocatePool (OptCount * sizeof (EFI_DHCP6_PACKET_OPTION *));\r
1629 if (OptList == NULL) {\r
1630 return EFI_NOT_READY;\r
1631 }\r
1632\r
1633 Status = Dhcp6->Parse (Dhcp6, Reply, &OptCount, OptList);\r
1634 if (EFI_ERROR (Status)) {\r
1635 Status = EFI_NOT_READY;\r
1636 goto ON_EXIT;\r
1637 }\r
1638\r
1639 Status = EFI_SUCCESS;\r
1640\r
1641 for (Index = 0; Index < OptCount; Index++) {\r
1642 //\r
1643 // Go through all the options to check the ones we are interested in.\r
1644 // The OpCode and Length are in network byte-order and may not be naturally\r
1645 // aligned.\r
1646 //\r
1647 CopyMem (&OpCode, &OptList[Index]->OpCode, sizeof (OpCode));\r
1648 OpCode = NTOHS (OpCode);\r
1649\r
142c00c3 1650 if (OpCode == DHCP6_OPT_DNS_SERVERS) {\r
a3bcde70
HT
1651 CopyMem (&Length, &OptList[Index]->OpLen, sizeof (Length));\r
1652 Length = NTOHS (Length);\r
1653\r
1654 if ((Length == 0) || ((Length % sizeof (EFI_IPv6_ADDRESS)) != 0)) {\r
1655 //\r
1656 // The length should be a multiple of 16 bytes.\r
1657 //\r
1658 Status = EFI_NOT_READY;\r
1659 break;\r
1660 }\r
1661\r
1662 //\r
1663 // Validate the DnsServers: whether they are unicast addresses.\r
1664 //\r
1665 DnsServer = (EFI_IPv6_ADDRESS *) OptList[Index]->Data;\r
1666 for (Index2 = 0; Index2 < Length / sizeof (EFI_IPv6_ADDRESS); Index2++) {\r
1667 if (!NetIp6IsValidUnicast (DnsServer)) {\r
1668 Status = EFI_NOT_READY;\r
1669 goto ON_EXIT;\r
1670 }\r
1671\r
1672 DnsServer++;\r
1673 }\r
1674\r
1675 Item = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];\r
1676\r
1677 if (Item->DataSize != Length) {\r
1678 if (Item->Data.Ptr != NULL) {\r
1679 FreePool (Item->Data.Ptr);\r
1680 }\r
1681\r
1682 Item->Data.Ptr = AllocatePool (Length);\r
1683 ASSERT (Item->Data.Ptr != NULL);\r
1684 }\r
1685\r
1686 CopyMem (Item->Data.Ptr, OptList[Index]->Data, Length);\r
1687 Item->DataSize = Length;\r
1688 Item->Status = EFI_SUCCESS;\r
1689\r
1690 //\r
1691 // Signal the waiting events.\r
1692 //\r
1693 NetMapIterate (&Item->EventMap, Ip6ConfigSignalEvent, NULL);\r
1694\r
1695 break;\r
1696 }\r
1697 }\r
1698\r
1699ON_EXIT:\r
1700\r
1701 FreePool (OptList);\r
1702 return Status;\r
1703}\r
1704\r
1705/**\r
1706 The callback function for Ip6SetAddr. The prototype is defined\r
1707 as IP6_DAD_CALLBACK. It is called after Duplicate Address Detection is performed\r
1708 on the tentative address by DHCPv6 in Ip6ConfigOnDhcp6Event().\r
1709\r
1710 @param[in] IsDadPassed If TRUE, Duplicate Address Detection passes.\r
1711 @param[in] TargetAddress The tentative IPv6 address to be checked.\r
1712 @param[in] Context Pointer to the IP6 configuration instance data.\r
1713\r
1714**/\r
1715VOID\r
1716Ip6ConfigSetStatefulAddrCallback (\r
1717 IN BOOLEAN IsDadPassed,\r
1718 IN EFI_IPv6_ADDRESS *TargetAddress,\r
1719 IN VOID *Context\r
1720 )\r
1721{\r
1722 IP6_CONFIG_INSTANCE *Instance;\r
1723\r
1724 Instance = (IP6_CONFIG_INSTANCE *) Context;\r
1725 NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);\r
1726\r
1727 //\r
1728 // We should record the addresses that fail the DAD, and DECLINE them.\r
1729 //\r
1730 if (IsDadPassed) {\r
1731 //\r
1732 // Decrease the count, no interests in those passed DAD.\r
1733 //\r
1734 if (Instance->FailedIaAddressCount > 0 ) {\r
1735 Instance->FailedIaAddressCount--;\r
1736 }\r
1737 } else {\r
1738 //\r
1739 // Record it.\r
1740 //\r
1741 IP6_COPY_ADDRESS (Instance->DeclineAddress + Instance->DeclineAddressCount, TargetAddress);\r
1742 Instance->DeclineAddressCount++;\r
1743 }\r
1744\r
1745 if (Instance->FailedIaAddressCount == Instance->DeclineAddressCount) {\r
1746 //\r
1747 // The checking on all addresses are finished.\r
1748 //\r
1749 if (Instance->DeclineAddressCount != 0) {\r
1750 //\r
1751 // Decline those duplicates.\r
1752 //\r
ae97201c
FS
1753 if (Instance->Dhcp6 != NULL) {\r
1754 Instance->Dhcp6->Decline (\r
1755 Instance->Dhcp6,\r
1756 Instance->DeclineAddressCount,\r
1757 Instance->DeclineAddress\r
1758 );\r
1759 }\r
a3bcde70
HT
1760 }\r
1761\r
1762 if (Instance->DeclineAddress != NULL) {\r
1763 FreePool (Instance->DeclineAddress);\r
1764 }\r
1765 Instance->DeclineAddress = NULL;\r
1766 Instance->DeclineAddressCount = 0;\r
1767 }\r
1768}\r
1769\r
1770/**\r
1771 The event handle routine when DHCPv6 process is finished or is updated.\r
1772\r
1773 @param[in] Event Not used.\r
1774 @param[in] Context The pointer to the IP6 configuration instance data.\r
1775\r
1776**/\r
1777VOID\r
1778EFIAPI\r
1779Ip6ConfigOnDhcp6Event (\r
1780 IN EFI_EVENT Event,\r
1781 IN VOID *Context\r
1782 )\r
1783{\r
1784 IP6_CONFIG_INSTANCE *Instance;\r
1785 EFI_DHCP6_PROTOCOL *Dhcp6;\r
1786 EFI_STATUS Status;\r
1787 EFI_DHCP6_MODE_DATA Dhcp6ModeData;\r
1788 EFI_DHCP6_IA *Ia;\r
1789 EFI_DHCP6_IA_ADDRESS *IaAddr;\r
1790 UINT32 Index;\r
1791 IP6_SERVICE *IpSb;\r
1792 IP6_ADDRESS_INFO *AddrInfo;\r
1793 IP6_INTERFACE *IpIf;\r
1794\r
1795 Instance = (IP6_CONFIG_INSTANCE *) Context;\r
1796\r
1797 if ((Instance->Policy != Ip6ConfigPolicyAutomatic) || Instance->OtherInfoOnly) {\r
1798 //\r
1799 // IPv6 is not operating in the automatic policy now or\r
1800 // the DHCPv6 information request message exchange is aborted.\r
1801 //\r
1802 return ;\r
1803 }\r
1804\r
1805 //\r
1806 // The stateful address autoconfiguration is done or updated.\r
1807 //\r
1808 Dhcp6 = Instance->Dhcp6;\r
1809\r
1810 Status = Dhcp6->GetModeData (Dhcp6, &Dhcp6ModeData, NULL);\r
1811 if (EFI_ERROR (Status)) {\r
1812 return ;\r
1813 }\r
1814\r
1815 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
1816 IpIf = IpSb->DefaultInterface;\r
1817 Ia = Dhcp6ModeData.Ia;\r
1818 IaAddr = Ia->IaAddress;\r
1819\r
1820 if (Instance->DeclineAddress != NULL) {\r
1821 FreePool (Instance->DeclineAddress);\r
1822 }\r
1823\r
1824 Instance->DeclineAddress = (EFI_IPv6_ADDRESS *) AllocatePool (Ia->IaAddressCount * sizeof (EFI_IPv6_ADDRESS));\r
1825 if (Instance->DeclineAddress == NULL) {\r
1826 goto ON_EXIT;\r
1827 }\r
1828\r
1829 Instance->FailedIaAddressCount = Ia->IaAddressCount;\r
1830 Instance->DeclineAddressCount = 0;\r
1831\r
1832 for (Index = 0; Index < Ia->IaAddressCount; Index++, IaAddr++) {\r
1833 if (Ia->IaAddress[Index].ValidLifetime != 0 && Ia->State == Dhcp6Bound) {\r
1834 //\r
1835 // Set this address, either it's a new address or with updated lifetimes.\r
1836 // An appropriate prefix length will be set.\r
1837 //\r
1838 Ip6SetAddress (\r
1839 IpIf,\r
1840 &IaAddr->IpAddress,\r
1841 FALSE,\r
1842 0,\r
1843 IaAddr->ValidLifetime,\r
1844 IaAddr->PreferredLifetime,\r
1845 Ip6ConfigSetStatefulAddrCallback,\r
1846 Instance\r
1847 );\r
1848 } else {\r
1849 //\r
1850 // discard this address, artificially decrease the count as if this address\r
1851 // passed DAD.\r
1852 //\r
1853 if (Ip6IsOneOfSetAddress (IpSb, &IaAddr->IpAddress, NULL, &AddrInfo)) {\r
1854 ASSERT (AddrInfo != NULL);\r
1855 Ip6RemoveAddr (\r
1856 IpSb,\r
1857 &IpIf->AddressList,\r
1858 &IpIf->AddressCount,\r
1859 &AddrInfo->Address,\r
1860 AddrInfo->PrefixLength\r
1861 );\r
1862 }\r
1863\r
1864 if (Instance->FailedIaAddressCount > 0) {\r
1865 Instance->FailedIaAddressCount--;\r
1866 }\r
1867 }\r
1868 }\r
1869\r
1870 //\r
1871 // Parse the Reply packet to get the options we need.\r
1872 //\r
1873 if (Dhcp6ModeData.Ia->ReplyPacket != NULL) {\r
1874 Ip6ConfigParseDhcpReply (Dhcp6, Instance, Dhcp6ModeData.Ia->ReplyPacket);\r
1875 }\r
1876\r
1877ON_EXIT:\r
1878\r
1879 FreePool (Dhcp6ModeData.ClientId);\r
1880 FreePool (Dhcp6ModeData.Ia);\r
1881}\r
1882\r
1883/**\r
1884 The event process routine when the DHCPv6 server is answered with a reply packet\r
1885 for an information request.\r
1886\r
1887 @param[in] This Points to the EFI_DHCP6_PROTOCOL.\r
1888 @param[in] Context The pointer to the IP6 configuration instance data.\r
1889 @param[in] Packet The DHCPv6 reply packet.\r
1890\r
1891 @retval EFI_SUCCESS The DNS server address was retrieved from the reply packet.\r
1892 @retval EFI_NOT_READY The reply packet does not contain the DNS server option, or\r
1893 the DNS server address is not valid.\r
1894\r
1895**/\r
1896EFI_STATUS\r
1897EFIAPI\r
1898Ip6ConfigOnDhcp6Reply (\r
1899 IN EFI_DHCP6_PROTOCOL *This,\r
1900 IN VOID *Context,\r
1901 IN EFI_DHCP6_PACKET *Packet\r
1902 )\r
1903{\r
1904 return Ip6ConfigParseDhcpReply (This, (IP6_CONFIG_INSTANCE *) Context, Packet);\r
1905}\r
1906\r
1907/**\r
1908 The event process routine when the DHCPv6 service binding protocol is installed\r
1909 in the system.\r
1910\r
1911 @param[in] Event Not used.\r
1912 @param[in] Context The pointer to the IP6 config instance data.\r
1913\r
1914**/\r
1915VOID\r
1916EFIAPI\r
1917Ip6ConfigOnDhcp6SbInstalled (\r
1918 IN EFI_EVENT Event,\r
1919 IN VOID *Context\r
1920 )\r
1921{\r
1922 IP6_CONFIG_INSTANCE *Instance;\r
1923\r
1924 Instance = (IP6_CONFIG_INSTANCE *) Context;\r
1925\r
1926 if ((Instance->Dhcp6Handle != NULL) || (Instance->Policy != Ip6ConfigPolicyAutomatic)) {\r
1927 //\r
1928 // The DHCP6 child is already created or the policy is no longer AUTOMATIC.\r
1929 //\r
1930 return ;\r
1931 }\r
1932\r
1933 Ip6ConfigStartStatefulAutoConfig (Instance, Instance->OtherInfoOnly);\r
1934}\r
1935\r
1936/**\r
1937 Set the configuration for the EFI IPv6 network stack running on the communication\r
1938 device this EFI IPv6 Configuration Protocol instance manages.\r
1939\r
1940 This function is used to set the configuration data of type DataType for the EFI\r
1941 IPv6 network stack that is running on the communication device that this EFI IPv6\r
1942 Configuration Protocol instance manages.\r
1943\r
1944 DataSize is used to calculate the count of structure instances in the Data for\r
1945 a DataType in which multiple structure instances are allowed.\r
1946\r
1947 This function is always non-blocking. When setting some type of configuration data,\r
1948 an asynchronous process is invoked to check the correctness of the data, such as\r
1949 performing Duplicate Address Detection on the manually set local IPv6 addresses.\r
1950 EFI_NOT_READY is returned immediately to indicate that such an asynchronous process\r
1951 is invoked, and the process is not finished yet. The caller wanting to get the result\r
1952 of the asynchronous process is required to call RegisterDataNotify() to register an\r
1953 event on the specified configuration data. Once the event is signaled, the caller\r
1954 can call GetData() to obtain the configuration data and know the result.\r
1955 For other types of configuration data that do not require an asynchronous configuration\r
1956 process, the result of the operation is immediately returned.\r
1957\r
1958 @param[in] This The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.\r
1959 @param[in] DataType The type of data to set.\r
1960 @param[in] DataSize Size of the buffer pointed to by Data in bytes.\r
1961 @param[in] Data The data buffer to set. The type of the data buffer is\r
1962 associated with the DataType.\r
1963\r
1964 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
1965 network stack was set successfully.\r
1966 @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:\r
1967 - This is NULL.\r
bee7fe0e
JW
1968 - One or more fields in Data and DataSizedo not match the \r
1969 requirement of the data type indicated by DataType.\r
a3bcde70
HT
1970 @retval EFI_WRITE_PROTECTED The specified configuration data is read-only or the specified\r
1971 configuration data cannot be set under the current policy.\r
1972 @retval EFI_ACCESS_DENIED Another set operation on the specified configuration\r
1973 data is already in process.\r
1974 @retval EFI_NOT_READY An asynchronous process was invoked to set the specified\r
1975 configuration data, and the process is not finished yet.\r
1976 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type\r
1977 indicated by DataType.\r
1978 @retval EFI_UNSUPPORTED This DataType is not supported.\r
1979 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
1980 @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred.\r
1981\r
1982**/\r
1983EFI_STATUS\r
1984EFIAPI\r
1985EfiIp6ConfigSetData (\r
1986 IN EFI_IP6_CONFIG_PROTOCOL *This,\r
1987 IN EFI_IP6_CONFIG_DATA_TYPE DataType,\r
1988 IN UINTN DataSize,\r
1989 IN VOID *Data\r
1990 )\r
1991{\r
1992 EFI_TPL OldTpl;\r
1993 EFI_STATUS Status;\r
1994 IP6_CONFIG_INSTANCE *Instance;\r
1995 IP6_SERVICE *IpSb;\r
1996\r
bee7fe0e 1997 if ((This == NULL) || (Data == NULL && DataSize != 0) || (Data != NULL && DataSize == 0)) {\r
a3bcde70
HT
1998 return EFI_INVALID_PARAMETER;\r
1999 }\r
2000\r
2001 if (DataType >= Ip6ConfigDataTypeMaximum) {\r
2002 return EFI_UNSUPPORTED;\r
2003 }\r
2004\r
2005 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);\r
2006 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
2007 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);\r
2008\r
2009 if (IpSb->LinkLocalDadFail) {\r
2010 return EFI_DEVICE_ERROR;\r
2011 }\r
2012\r
2013 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
2014\r
2015 Status = Instance->DataItem[DataType].Status;\r
2016 if (Status != EFI_NOT_READY) {\r
2017\r
2018 if (Instance->DataItem[DataType].SetData == NULL) {\r
2019 //\r
2020 // This type of data is readonly.\r
2021 //\r
2022 Status = EFI_WRITE_PROTECTED;\r
2023 } else {\r
2024\r
2025 Status = Instance->DataItem[DataType].SetData (Instance, DataSize, Data);\r
2026 if (!EFI_ERROR (Status)) {\r
2027 //\r
2028 // Fire up the events registered with this type of data.\r
2029 //\r
2030 NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip6ConfigSignalEvent, NULL);\r
2031 Ip6ConfigWriteConfigData (IpSb->MacString, Instance);\r
2032 } else if (Status == EFI_ABORTED) {\r
2033 //\r
2034 // The SetData is aborted because the data to set is the same with\r
2035 // the one maintained.\r
2036 //\r
2037 Status = EFI_SUCCESS;\r
2038 NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip6ConfigSignalEvent, NULL);\r
2039 }\r
2040 }\r
2041 } else {\r
2042 //\r
2043 // Another asynchornous process is on the way.\r
2044 //\r
2045 Status = EFI_ACCESS_DENIED;\r
2046 }\r
2047\r
2048 gBS->RestoreTPL (OldTpl);\r
2049\r
2050 return Status;\r
2051}\r
2052\r
2053/**\r
2054 Get the configuration data for the EFI IPv6 network stack running on the communication\r
2055 device that this EFI IPv6 Configuration Protocol instance manages.\r
2056\r
2057 This function returns the configuration data of type DataType for the EFI IPv6 network\r
2058 stack running on the communication device that this EFI IPv6 Configuration Protocol instance\r
2059 manages.\r
2060\r
2061 The caller is responsible for allocating the buffer used to return the specified\r
2062 configuration data. The required size will be returned to the caller if the size of\r
2063 the buffer is too small.\r
2064\r
2065 EFI_NOT_READY is returned if the specified configuration data is not ready due to an\r
2066 asynchronous configuration process already in progress. The caller can call RegisterDataNotify()\r
2067 to register an event on the specified configuration data. Once the asynchronous configuration\r
2068 process is finished, the event will be signaled, and a subsequent GetData() call will return\r
2069 the specified configuration data.\r
2070\r
2071 @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance.\r
2072 @param[in] DataType The type of data to get.\r
2073 @param[in, out] DataSize On input, in bytes, the size of Data. On output, in bytes, the\r
2074 size of buffer required to store the specified configuration data.\r
2075 @param[in] Data The data buffer in which the configuration data is returned. The\r
2076 type of the data buffer is associated with the DataType.\r
2077 This is an optional parameter that may be NULL.\r
2078\r
2079 @retval EFI_SUCCESS The specified configuration data was obtained successfully.\r
2080 @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:\r
2081 - This is NULL.\r
2082 - DataSize is NULL.\r
2083 - Data is NULL if *DataSize is not zero.\r
2084 @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified configuration data,\r
2085 and the required size is returned in DataSize.\r
2086 @retval EFI_NOT_READY The specified configuration data is not ready due to an\r
2087 asynchronous configuration process already in progress.\r
2088 @retval EFI_NOT_FOUND The specified configuration data is not found.\r
2089\r
2090**/\r
2091EFI_STATUS\r
2092EFIAPI\r
2093EfiIp6ConfigGetData (\r
2094 IN EFI_IP6_CONFIG_PROTOCOL *This,\r
2095 IN EFI_IP6_CONFIG_DATA_TYPE DataType,\r
2096 IN OUT UINTN *DataSize,\r
2097 IN VOID *Data OPTIONAL\r
2098 )\r
2099{\r
2100 EFI_TPL OldTpl;\r
2101 EFI_STATUS Status;\r
2102 IP6_CONFIG_INSTANCE *Instance;\r
2103 IP6_CONFIG_DATA_ITEM *DataItem;\r
2104\r
2105 if ((This == NULL) || (DataSize == NULL) || ((*DataSize != 0) && (Data == NULL))) {\r
2106 return EFI_INVALID_PARAMETER;\r
2107 }\r
2108\r
2109 if (DataType >= Ip6ConfigDataTypeMaximum) {\r
2110 return EFI_NOT_FOUND;\r
2111 }\r
2112\r
2113 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
2114\r
2115 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);\r
2116 DataItem = &Instance->DataItem[DataType];\r
2117\r
2118 Status = Instance->DataItem[DataType].Status;\r
2119 if (!EFI_ERROR (Status)) {\r
2120\r
2121 if (DataItem->GetData != NULL) {\r
2122\r
2123 Status = DataItem->GetData (Instance, DataSize, Data);\r
2124 } else if (*DataSize < Instance->DataItem[DataType].DataSize) {\r
2125 //\r
2126 // Update the buffer length.\r
2127 //\r
2128 *DataSize = Instance->DataItem[DataType].DataSize;\r
2129 Status = EFI_BUFFER_TOO_SMALL;\r
2130 } else {\r
2131\r
2132 *DataSize = Instance->DataItem[DataType].DataSize;\r
2133 CopyMem (Data, Instance->DataItem[DataType].Data.Ptr, *DataSize);\r
2134 }\r
2135 }\r
2136\r
2137 gBS->RestoreTPL (OldTpl);\r
2138\r
2139 return Status;\r
2140}\r
2141\r
2142/**\r
2143 Register an event that is signaled whenever a configuration process on the specified\r
2144 configuration data is done.\r
2145\r
2146 This function registers an event that is to be signaled whenever a configuration\r
2147 process on the specified configuration data is performed. An event can be registered\r
2148 for a different DataType simultaneously. The caller is responsible for determining\r
2149 which type of configuration data causes the signaling of the event in such an event.\r
2150\r
2151 @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance.\r
2152 @param[in] DataType The type of data to unregister the event for.\r
2153 @param[in] Event The event to register.\r
2154\r
2155 @retval EFI_SUCCESS The notification event for the specified configuration data is\r
2156 registered.\r
2157 @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.\r
2158 @retval EFI_UNSUPPORTED The configuration data type specified by DataType is not\r
2159 supported.\r
2160 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
2161 @retval EFI_ACCESS_DENIED The Event is already registered for the DataType.\r
2162\r
2163**/\r
2164EFI_STATUS\r
2165EFIAPI\r
2166EfiIp6ConfigRegisterDataNotify (\r
2167 IN EFI_IP6_CONFIG_PROTOCOL *This,\r
2168 IN EFI_IP6_CONFIG_DATA_TYPE DataType,\r
2169 IN EFI_EVENT Event\r
2170 )\r
2171{\r
2172 EFI_TPL OldTpl;\r
2173 EFI_STATUS Status;\r
2174 IP6_CONFIG_INSTANCE *Instance;\r
2175 NET_MAP *EventMap;\r
2176 NET_MAP_ITEM *Item;\r
2177\r
2178 if ((This == NULL) || (Event == NULL)) {\r
2179 return EFI_INVALID_PARAMETER;\r
2180 }\r
2181\r
2182 if (DataType >= Ip6ConfigDataTypeMaximum) {\r
2183 return EFI_UNSUPPORTED;\r
2184 }\r
2185\r
2186 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
2187\r
2188 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);\r
2189 EventMap = &Instance->DataItem[DataType].EventMap;\r
2190\r
2191 //\r
2192 // Check whether this event is already registered for this DataType.\r
2193 //\r
2194 Item = NetMapFindKey (EventMap, Event);\r
2195 if (Item == NULL) {\r
2196\r
2197 Status = NetMapInsertTail (EventMap, Event, NULL);\r
2198\r
2199 if (EFI_ERROR (Status)) {\r
2200\r
2201 Status = EFI_OUT_OF_RESOURCES;\r
2202 }\r
2203\r
2204 } else {\r
2205\r
2206 Status = EFI_ACCESS_DENIED;\r
2207 }\r
2208\r
2209 gBS->RestoreTPL (OldTpl);\r
2210\r
2211 return Status;\r
2212}\r
2213\r
2214/**\r
2215 Remove a previously registered event for the specified configuration data.\r
2216\r
2217 @param This The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.\r
2218 @param DataType The type of data to remove from the previously\r
2219 registered event.\r
2220 @param Event The event to be unregistered.\r
2221\r
2222 @retval EFI_SUCCESS The event registered for the specified\r
2223 configuration data was removed.\r
2224 @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.\r
2225 @retval EFI_NOT_FOUND The Event has not been registered for the\r
2226 specified DataType.\r
2227\r
2228**/\r
2229EFI_STATUS\r
2230EFIAPI\r
2231EfiIp6ConfigUnregisterDataNotify (\r
2232 IN EFI_IP6_CONFIG_PROTOCOL *This,\r
2233 IN EFI_IP6_CONFIG_DATA_TYPE DataType,\r
2234 IN EFI_EVENT Event\r
2235 )\r
2236{\r
2237 EFI_TPL OldTpl;\r
2238 EFI_STATUS Status;\r
2239 IP6_CONFIG_INSTANCE *Instance;\r
2240 NET_MAP_ITEM *Item;\r
2241\r
2242 if ((This == NULL) || (Event == NULL)) {\r
2243 return EFI_INVALID_PARAMETER;\r
2244 }\r
2245\r
2246 if (DataType >= Ip6ConfigDataTypeMaximum) {\r
2247 return EFI_NOT_FOUND;\r
2248 }\r
2249\r
2250 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
2251\r
2252 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);\r
2253\r
2254 Item = NetMapFindKey (&Instance->DataItem[DataType].EventMap, Event);\r
2255 if (Item != NULL) {\r
2256\r
2257 NetMapRemoveItem (&Instance->DataItem[DataType].EventMap, Item, NULL);\r
2258 Status = EFI_SUCCESS;\r
2259 } else {\r
2260\r
2261 Status = EFI_NOT_FOUND;\r
2262 }\r
2263\r
2264 gBS->RestoreTPL (OldTpl);\r
2265\r
2266 return Status;\r
2267}\r
2268\r
2269/**\r
2270 Initialize an IP6_CONFIG_INSTANCE.\r
2271\r
2272 @param[out] Instance The buffer of IP6_CONFIG_INSTANCE to be initialized.\r
2273\r
2274 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.\r
2275 @retval EFI_SUCCESS The IP6_CONFIG_INSTANCE initialized successfully.\r
2276\r
2277**/\r
2278EFI_STATUS\r
2279Ip6ConfigInitInstance (\r
2280 OUT IP6_CONFIG_INSTANCE *Instance\r
2281 )\r
2282{\r
2283 IP6_SERVICE *IpSb;\r
2284 IP6_CONFIG_INSTANCE *TmpInstance;\r
2285 LIST_ENTRY *Entry;\r
2286 EFI_STATUS Status;\r
2287 UINTN Index;\r
2288 UINT16 IfIndex;\r
2289 IP6_CONFIG_DATA_ITEM *DataItem;\r
2290\r
2291 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
2292\r
2293 Instance->Signature = IP6_CONFIG_INSTANCE_SIGNATURE;\r
2294\r
2295 //\r
2296 // Determine the index of this interface.\r
2297 //\r
2298 IfIndex = 0;\r
2299 NET_LIST_FOR_EACH (Entry, &mIp6ConfigInstanceList) {\r
2300 TmpInstance = NET_LIST_USER_STRUCT_S (Entry, IP6_CONFIG_INSTANCE, Link, IP6_CONFIG_INSTANCE_SIGNATURE);\r
2301\r
2302 if (TmpInstance->IfIndex > IfIndex) {\r
2303 //\r
2304 // There is a sequence hole because some interface is down.\r
2305 //\r
2306 break;\r
2307 }\r
2308\r
2309 IfIndex++;\r
2310 }\r
2311\r
2312 Instance->IfIndex = IfIndex;\r
2313 NetListInsertBefore (Entry, &Instance->Link);\r
2314\r
2315 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {\r
2316 //\r
2317 // Initialize the event map for each data item.\r
2318 //\r
2319 NetMapInit (&Instance->DataItem[Index].EventMap);\r
2320 }\r
2321\r
2322 //\r
2323 // Initialize the NET_MAPs used for DAD on manually configured source addresses.\r
2324 //\r
2325 NetMapInit (&Instance->DadFailedMap);\r
2326 NetMapInit (&Instance->DadPassedMap);\r
2327\r
2328 //\r
2329 // Initialize each data type: associate storage and set data size for the\r
2330 // fixed size data types, hook the SetData function, set the data attribute.\r
2331 //\r
2332 DataItem = &Instance->DataItem[Ip6ConfigDataTypeInterfaceInfo];\r
2333 DataItem->GetData = Ip6ConfigGetIfInfo;\r
2334 DataItem->Data.Ptr = &Instance->InterfaceInfo;\r
2335 DataItem->DataSize = sizeof (Instance->InterfaceInfo);\r
2336 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED | DATA_ATTRIB_VOLATILE);\r
2337 Ip6ConfigInitIfInfo (IpSb, &Instance->InterfaceInfo);\r
2338\r
2339 DataItem = &Instance->DataItem[Ip6ConfigDataTypeAltInterfaceId];\r
2340 DataItem->SetData = Ip6ConfigSetAltIfId;\r
2341 DataItem->Data.Ptr = &Instance->AltIfId;\r
2342 DataItem->DataSize = sizeof (Instance->AltIfId);\r
2343 DataItem->Status = EFI_NOT_FOUND;\r
2344 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);\r
2345\r
2346 DataItem = &Instance->DataItem[Ip6ConfigDataTypePolicy];\r
2347 DataItem->SetData = Ip6ConfigSetPolicy;\r
2348 DataItem->Data.Ptr = &Instance->Policy;\r
2349 DataItem->DataSize = sizeof (Instance->Policy);\r
4720106b 2350 Instance->Policy = Ip6ConfigPolicyManual;\r
a3bcde70
HT
2351 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);\r
2352\r
2353 DataItem = &Instance->DataItem[Ip6ConfigDataTypeDupAddrDetectTransmits];\r
2354 DataItem->SetData = Ip6ConfigSetDadXmits;\r
2355 DataItem->Data.Ptr = &Instance->DadXmits;\r
2356 DataItem->DataSize = sizeof (Instance->DadXmits);\r
2357 Instance->DadXmits.DupAddrDetectTransmits = IP6_CONFIG_DEFAULT_DAD_XMITS;\r
2358 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);\r
2359\r
2360 DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];\r
c3149709 2361 DataItem->SetData = Ip6ConfigSetManualAddress;\r
a3bcde70
HT
2362 DataItem->Status = EFI_NOT_FOUND;\r
2363\r
2364 DataItem = &Instance->DataItem[Ip6ConfigDataTypeGateway];\r
2365 DataItem->SetData = Ip6ConfigSetGateway;\r
2366 DataItem->Status = EFI_NOT_FOUND;\r
2367\r
2368 DataItem = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];\r
2369 DataItem->SetData = Ip6ConfigSetDnsServer;\r
2370 DataItem->Status = EFI_NOT_FOUND;\r
2371\r
2372 //\r
2373 // Create the event used for DHCP.\r
2374 //\r
2375 Status = gBS->CreateEvent (\r
2376 EVT_NOTIFY_SIGNAL,\r
2377 TPL_CALLBACK,\r
2378 Ip6ConfigOnDhcp6Event,\r
2379 Instance,\r
2380 &Instance->Dhcp6Event\r
2381 );\r
2382 ASSERT_EFI_ERROR (Status);\r
2383\r
2384 Instance->Configured = TRUE;\r
2385\r
2386 //\r
2387 // Try to read the config data from NV variable.\r
2388 //\r
2389 Status = Ip6ConfigReadConfigData (IpSb->MacString, Instance);\r
2390 if (Status == EFI_NOT_FOUND) {\r
2391 //\r
2392 // The NV variable is not set, so generate a random IAID, and write down the\r
2393 // fresh new configuration as the NV variable now.\r
2394 //\r
2395 Instance->IaId = NET_RANDOM (NetRandomInitSeed ());\r
2396\r
2397 for (Index = 0; Index < IpSb->SnpMode.HwAddressSize; Index++) {\r
2398 Instance->IaId |= (IpSb->SnpMode.CurrentAddress.Addr[Index] << ((Index << 3) & 31));\r
2399 }\r
2400\r
2401 Ip6ConfigWriteConfigData (IpSb->MacString, Instance);\r
2402 } else if (EFI_ERROR (Status)) {\r
2403 return Status;\r
2404 }\r
2405\r
2406 Instance->Ip6Config.SetData = EfiIp6ConfigSetData;\r
2407 Instance->Ip6Config.GetData = EfiIp6ConfigGetData;\r
2408 Instance->Ip6Config.RegisterDataNotify = EfiIp6ConfigRegisterDataNotify;\r
2409 Instance->Ip6Config.UnregisterDataNotify = EfiIp6ConfigUnregisterDataNotify;\r
2410\r
2411\r
2412 //\r
2413 // Publish the IP6 configuration form\r
2414 //\r
2415 return Ip6ConfigFormInit (Instance);\r
2416}\r
2417\r
2418/**\r
2419 Release an IP6_CONFIG_INSTANCE.\r
2420\r
2421 @param[in, out] Instance The buffer of IP6_CONFIG_INSTANCE to be freed.\r
2422\r
2423**/\r
2424VOID\r
2425Ip6ConfigCleanInstance (\r
2426 IN OUT IP6_CONFIG_INSTANCE *Instance\r
2427 )\r
2428{\r
2429 UINTN Index;\r
2430 IP6_CONFIG_DATA_ITEM *DataItem;\r
2431\r
2432 if (Instance->DeclineAddress != NULL) {\r
2433 FreePool (Instance->DeclineAddress);\r
2434 }\r
2435\r
2436 if (!Instance->Configured) {\r
2437 return ;\r
2438 }\r
2439\r
2440 if (Instance->Dhcp6Handle != NULL) {\r
2441\r
2442 Ip6ConfigDestroyDhcp6 (Instance);\r
2443 }\r
2444\r
2445 //\r
2446 // Close the event.\r
2447 //\r
2448 if (Instance->Dhcp6Event != NULL) {\r
2449 gBS->CloseEvent (Instance->Dhcp6Event);\r
2450 }\r
2451\r
2452 NetMapClean (&Instance->DadPassedMap);\r
2453 NetMapClean (&Instance->DadFailedMap);\r
2454\r
2455 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {\r
2456\r
2457 DataItem = &Instance->DataItem[Index];\r
2458\r
2459 if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED)) {\r
2460 if (DataItem->Data.Ptr != NULL) {\r
2461 FreePool (DataItem->Data.Ptr);\r
2462 }\r
2463 DataItem->Data.Ptr = NULL;\r
2464 DataItem->DataSize = 0;\r
2465 }\r
2466\r
2467 NetMapClean (&Instance->DataItem[Index].EventMap);\r
2468 }\r
2469\r
2470 Ip6ConfigFormUnload (Instance);\r
2471\r
2472 RemoveEntryList (&Instance->Link);\r
2473}\r
2474\r
2475/**\r
75dce340 2476 Destroy the Dhcp6 child in IP6_CONFIG_INSTANCE and release the resources.\r
a3bcde70
HT
2477\r
2478 @param[in, out] Instance The buffer of IP6_CONFIG_INSTANCE to be freed.\r
2479\r
2480 @retval EFI_SUCCESS The child was successfully destroyed.\r
75dce340 2481 @retval Others Failed to destroy the child.\r
a3bcde70
HT
2482\r
2483**/\r
2484EFI_STATUS\r
2485Ip6ConfigDestroyDhcp6 (\r
2486 IN OUT IP6_CONFIG_INSTANCE *Instance\r
2487 )\r
2488{\r
2489 IP6_SERVICE *IpSb;\r
2490 EFI_STATUS Status;\r
2491 EFI_DHCP6_PROTOCOL *Dhcp6;\r
2492\r
2493 Dhcp6 = Instance->Dhcp6;\r
2494 ASSERT (Dhcp6 != NULL);\r
2495\r
2496 Dhcp6->Stop (Dhcp6);\r
2497 Dhcp6->Configure (Dhcp6, NULL);\r
2498 Instance->Dhcp6 = NULL;\r
2499\r
2500 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
2501\r
2502 //\r
2503 // Close DHCPv6 protocol and destroy the child.\r
2504 //\r
2505 Status = gBS->CloseProtocol (\r
2506 Instance->Dhcp6Handle,\r
2507 &gEfiDhcp6ProtocolGuid,\r
2508 IpSb->Image,\r
2509 IpSb->Controller\r
2510 );\r
2511 if (EFI_ERROR (Status)) {\r
2512 return Status;\r
2513 }\r
2514\r
2515 Status = NetLibDestroyServiceChild (\r
2516 IpSb->Controller,\r
2517 IpSb->Image,\r
2518 &gEfiDhcp6ServiceBindingProtocolGuid,\r
2519 Instance->Dhcp6Handle\r
2520 );\r
2521\r
2522 Instance->Dhcp6Handle = NULL;\r
2523\r
2524 return Status;\r
2525}\r
2526\r