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