]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Dhcp6Dxe/Dhcp6Impl.c
NetworkPkg/Dhcp6Dxe: Remove an unused global variable.
[mirror_edk2.git] / NetworkPkg / Dhcp6Dxe / Dhcp6Impl.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 This EFI_DHCP6_PROTOCOL interface implementation.\r
3\r
f75a7f56 4 Copyright (c) 2009 - 2018, 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 "Dhcp6Impl.h"\r
17\r
18//\r
19// Well-known multi-cast address defined in section-24.1 of rfc-3315\r
20//\r
21// ALL_DHCP_Relay_Agents_and_Servers address: FF02::1:2\r
a3bcde70
HT
22//\r
23EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress = {{0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2}};\r
a3bcde70
HT
24\r
25EFI_DHCP6_PROTOCOL gDhcp6ProtocolTemplate = {\r
26 EfiDhcp6GetModeData,\r
27 EfiDhcp6Configure,\r
28 EfiDhcp6Start,\r
29 EfiDhcp6InfoRequest,\r
30 EfiDhcp6RenewRebind,\r
31 EfiDhcp6Decline,\r
32 EfiDhcp6Release,\r
33 EfiDhcp6Stop,\r
34 EfiDhcp6Parse\r
35};\r
36\r
37/**\r
38 Starts the DHCPv6 standard S.A.R.R. process.\r
39\r
40 The Start() function starts the DHCPv6 standard process. This function can\r
41 be called only when the state of Dhcp6 instance is in the Dhcp6Init state.\r
42 If the DHCP process completes successfully, the state of the Dhcp6 instance\r
43 will be transferred through Dhcp6Selecting and Dhcp6Requesting to the\r
44 Dhcp6Bound state.\r
45 Refer to rfc-3315 for precise state transitions during this process. At the\r
46 time when each event occurs in this process, the callback function that was set\r
47 by EFI_DHCP6_PROTOCOL.Configure() will be called, and the user can take this\r
48 opportunity to control the process.\r
49\r
50 @param[in] This The pointer to Dhcp6 protocol.\r
51\r
52 @retval EFI_SUCCESS The DHCPv6 standard process has started, or it has\r
53 completed when CompletionEvent is NULL.\r
54 @retval EFI_ACCESS_DENIED The EFI DHCPv6 Child instance hasn't been configured.\r
55 @retval EFI_INVALID_PARAMETER This is NULL.\r
56 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
57 @retval EFI_TIMEOUT The DHCPv6 configuration process failed because no\r
58 response was received from the server within the\r
59 specified timeout value.\r
60 @retval EFI_ABORTED The user aborted the DHCPv6 process.\r
61 @retval EFI_ALREADY_STARTED Some other Dhcp6 instance already started the DHCPv6\r
62 standard process.\r
63 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
64 @retval EFI_NO_MEDIA There was a media error.\r
65\r
66**/\r
67EFI_STATUS\r
68EFIAPI\r
69EfiDhcp6Start (\r
70 IN EFI_DHCP6_PROTOCOL *This\r
71 )\r
72{\r
73 EFI_STATUS Status;\r
74 EFI_TPL OldTpl;\r
75 DHCP6_INSTANCE *Instance;\r
76 DHCP6_SERVICE *Service;\r
152f2d5e 77 EFI_STATUS MediaStatus;\r
a3bcde70
HT
78\r
79 if (This == NULL) {\r
80 return EFI_INVALID_PARAMETER;\r
81 }\r
82\r
83 Instance = DHCP6_INSTANCE_FROM_THIS (This);\r
84 Service = Instance->Service;\r
85\r
86 //\r
87 // The instance hasn't been configured.\r
88 //\r
89 if (Instance->Config == NULL) {\r
90 return EFI_ACCESS_DENIED;\r
91 }\r
92\r
93 ASSERT (Instance->IaCb.Ia != NULL);\r
94\r
95 //\r
96 // The instance has already been started.\r
97 //\r
98 if (Instance->IaCb.Ia->State != Dhcp6Init) {\r
99 return EFI_ALREADY_STARTED;\r
100 }\r
101\r
102 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
8a5ef41e
JW
103\r
104 //\r
105 // Check Media Satus.\r
106 //\r
152f2d5e 107 MediaStatus = EFI_SUCCESS;\r
108 NetLibDetectMediaWaitTimeout (Service->Controller, DHCP_CHECK_MEDIA_WAITING_TIME, &MediaStatus);\r
109 if (MediaStatus != EFI_SUCCESS) {\r
8a5ef41e
JW
110 Status = EFI_NO_MEDIA;\r
111 goto ON_ERROR;\r
112 }\r
113\r
a3bcde70
HT
114 Instance->UdpSts = EFI_ALREADY_STARTED;\r
115\r
a3bcde70
HT
116 //\r
117 // Send the solicit message to start S.A.R.R process.\r
118 //\r
119 Status = Dhcp6SendSolicitMsg (Instance);\r
120\r
121 if (EFI_ERROR (Status)) {\r
122 goto ON_ERROR;\r
123 }\r
124\r
125 //\r
126 // Register receive callback for the stateful exchange process.\r
127 //\r
128 Status = UdpIoRecvDatagram(\r
129 Service->UdpIo,\r
130 Dhcp6ReceivePacket,\r
131 Service,\r
132 0\r
133 );\r
134\r
135 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
136 goto ON_ERROR;\r
137 }\r
138\r
139 gBS->RestoreTPL (OldTpl);\r
140\r
141 //\r
142 // Poll udp out of the net tpl if synchronous call.\r
143 //\r
144 if (Instance->Config->IaInfoEvent == NULL) {\r
145\r
146 while (Instance->UdpSts == EFI_ALREADY_STARTED) {\r
147 Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);\r
148 }\r
149 return Instance->UdpSts;\r
150 }\r
151\r
152 return EFI_SUCCESS;\r
153\r
154ON_ERROR:\r
155\r
156 gBS->RestoreTPL (OldTpl);\r
157 return Status;\r
158}\r
159\r
160\r
161/**\r
162 Stops the DHCPv6 standard S.A.R.R. process.\r
163\r
164 The Stop() function is used to stop the DHCPv6 standard process. After this\r
165 function is called successfully, the state of Dhcp6 instance is transferred\r
166 into Dhcp6Init. EFI_DHCP6_PROTOCOL.Configure() needs to be called\r
167 before DHCPv6 standard process can be started again. This function can be\r
168 called when the Dhcp6 instance is in any state.\r
169\r
170 @param[in] This The pointer to the Dhcp6 protocol.\r
171\r
172 @retval EFI_SUCCESS The Dhcp6 instance is now in the Dhcp6Init state.\r
173 @retval EFI_INVALID_PARAMETER This is NULL.\r
174\r
175**/\r
176EFI_STATUS\r
177EFIAPI\r
178EfiDhcp6Stop (\r
179 IN EFI_DHCP6_PROTOCOL *This\r
180 )\r
181{\r
182 EFI_TPL OldTpl;\r
183 EFI_STATUS Status;\r
184 EFI_UDP6_PROTOCOL *Udp6;\r
185 DHCP6_INSTANCE *Instance;\r
186 DHCP6_SERVICE *Service;\r
187\r
188 if (This == NULL) {\r
189 return EFI_INVALID_PARAMETER;\r
190 }\r
191\r
192 Instance = DHCP6_INSTANCE_FROM_THIS (This);\r
193 Service = Instance->Service;\r
194 Udp6 = Service->UdpIo->Protocol.Udp6;\r
195 Status = EFI_SUCCESS;\r
196\r
197 //\r
198 // The instance hasn't been configured.\r
199 //\r
200 if (Instance->Config == NULL) {\r
201 return Status;\r
202 }\r
203\r
204 ASSERT (Instance->IaCb.Ia != NULL);\r
205\r
206 //\r
ed2bfecb 207 // No valid REPLY message received yet, cleanup this instance directly.\r
a3bcde70
HT
208 //\r
209 if (Instance->IaCb.Ia->State == Dhcp6Init ||\r
210 Instance->IaCb.Ia->State == Dhcp6Selecting ||\r
211 Instance->IaCb.Ia->State == Dhcp6Requesting\r
212 ) {\r
ed2bfecb 213 goto ON_EXIT;\r
a3bcde70
HT
214 }\r
215\r
216 //\r
217 // Release the current ready Ia.\r
218 //\r
219 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
220\r
221 Instance->UdpSts = EFI_ALREADY_STARTED;\r
ed2bfecb 222 Status = Dhcp6SendReleaseMsg (Instance, Instance->IaCb.Ia);\r
216f7970 223 gBS->RestoreTPL (OldTpl);\r
ed2bfecb 224 if (EFI_ERROR (Status)) {\r
225 goto ON_EXIT;\r
226 }\r
a3bcde70 227\r
a3bcde70
HT
228 //\r
229 // Poll udp out of the net tpl if synchoronus call.\r
230 //\r
231 if (Instance->Config->IaInfoEvent == NULL) {\r
232 ASSERT (Udp6 != NULL);\r
233 while (Instance->UdpSts == EFI_ALREADY_STARTED) {\r
234 Udp6->Poll (Udp6);\r
235 }\r
236 Status = Instance->UdpSts;\r
237 }\r
f75a7f56 238\r
ed2bfecb 239ON_EXIT:\r
a3bcde70
HT
240 //\r
241 // Clean up the session data for the released Ia.\r
242 //\r
243 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
244 Dhcp6CleanupSession (Instance, EFI_SUCCESS);\r
245 gBS->RestoreTPL (OldTpl);\r
246\r
247 return Status;\r
248}\r
249\r
250\r
251/**\r
252 Returns the current operating mode data for the Dhcp6 instance.\r
253\r
254 The GetModeData() function returns the current operating mode and\r
255 cached data packet for the Dhcp6 instance.\r
256\r
257 @param[in] This The pointer to the Dhcp6 protocol.\r
258 @param[out] Dhcp6ModeData The pointer to the Dhcp6 mode data.\r
259 @param[out] Dhcp6ConfigData The pointer to the Dhcp6 configure data.\r
260\r
261 @retval EFI_SUCCESS The mode data was returned.\r
262 @retval EFI_INVALID_PARAMETER This is NULL.\r
263 @retval EFI_ACCESS_DENIED The EFI DHCPv6 Protocol instance was not\r
264 configured.\r
265**/\r
266EFI_STATUS\r
267EFIAPI\r
268EfiDhcp6GetModeData (\r
269 IN EFI_DHCP6_PROTOCOL *This,\r
270 OUT EFI_DHCP6_MODE_DATA *Dhcp6ModeData OPTIONAL,\r
271 OUT EFI_DHCP6_CONFIG_DATA *Dhcp6ConfigData OPTIONAL\r
272 )\r
273{\r
274 EFI_TPL OldTpl;\r
275 EFI_DHCP6_IA *Ia;\r
276 DHCP6_INSTANCE *Instance;\r
277 DHCP6_SERVICE *Service;\r
278 UINT32 IaSize;\r
279 UINT32 IdSize;\r
280\r
281 if (This == NULL || (Dhcp6ModeData == NULL && Dhcp6ConfigData == NULL)) {\r
282 return EFI_INVALID_PARAMETER;\r
283 }\r
284\r
285 Instance = DHCP6_INSTANCE_FROM_THIS (This);\r
286 Service = Instance->Service;\r
287\r
288 if (Instance->Config == NULL && Dhcp6ConfigData != NULL) {\r
289 return EFI_ACCESS_DENIED;\r
290 }\r
291\r
292 ASSERT (Service->ClientId != NULL);\r
293\r
294 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
295\r
296 //\r
297 // User needs a copy of instance config data.\r
298 //\r
299 if (Dhcp6ConfigData != NULL) {\r
300 ZeroMem (Dhcp6ConfigData, sizeof(EFI_DHCP6_CONFIG_DATA));\r
301 //\r
302 // Duplicate config data, including all reference buffers.\r
303 //\r
304 if (EFI_ERROR (Dhcp6CopyConfigData (Dhcp6ConfigData, Instance->Config))) {\r
305 goto ON_ERROR;\r
306 }\r
307 }\r
308\r
309 //\r
310 // User need a copy of instance mode data.\r
311 //\r
312 if (Dhcp6ModeData != NULL) {\r
313 ZeroMem (Dhcp6ModeData, sizeof (EFI_DHCP6_MODE_DATA));\r
314 //\r
315 // Duplicate a copy of EFI_DHCP6_DUID for client Id.\r
316 //\r
317 IdSize = Service->ClientId->Length + sizeof (Service->ClientId->Length);\r
318\r
319 Dhcp6ModeData->ClientId = AllocateZeroPool (IdSize);\r
320 if (Dhcp6ModeData->ClientId == NULL) {\r
321 goto ON_ERROR;\r
322 }\r
323\r
324 CopyMem (\r
325 Dhcp6ModeData->ClientId,\r
326 Service->ClientId,\r
327 IdSize\r
328 );\r
329\r
330 Ia = Instance->IaCb.Ia;\r
331 if (Ia != NULL) {\r
332 //\r
333 // Duplicate a copy of EFI_DHCP6_IA for configured Ia.\r
334 //\r
335 IaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount -1) * sizeof (EFI_DHCP6_IA_ADDRESS);\r
336\r
337 Dhcp6ModeData->Ia = AllocateZeroPool (IaSize);\r
338 if (Dhcp6ModeData->Ia == NULL) {\r
339 goto ON_ERROR;\r
340 }\r
341\r
342 CopyMem (\r
343 Dhcp6ModeData->Ia,\r
344 Ia,\r
345 IaSize\r
346 );\r
347\r
348 //\r
349 // Duplicate a copy of reply packet if has.\r
350 //\r
351 if (Ia->ReplyPacket != NULL) {\r
352 Dhcp6ModeData->Ia->ReplyPacket = AllocateZeroPool (Ia->ReplyPacket->Size);\r
353 if (Dhcp6ModeData->Ia->ReplyPacket == NULL) {\r
354 goto ON_ERROR;\r
355 }\r
356 CopyMem (\r
357 Dhcp6ModeData->Ia->ReplyPacket,\r
358 Ia->ReplyPacket,\r
359 Ia->ReplyPacket->Size\r
360 );\r
361 }\r
362 }\r
363 }\r
364\r
365 gBS->RestoreTPL (OldTpl);\r
366\r
367 return EFI_SUCCESS;\r
368\r
369ON_ERROR:\r
370\r
371 if (Dhcp6ConfigData != NULL) {\r
372 Dhcp6CleanupConfigData (Dhcp6ConfigData);\r
373 }\r
374 if (Dhcp6ModeData != NULL) {\r
375 Dhcp6CleanupModeData (Dhcp6ModeData);\r
376 }\r
377 gBS->RestoreTPL (OldTpl);\r
378\r
379 return EFI_OUT_OF_RESOURCES;\r
380}\r
381\r
382\r
383/**\r
384 Initializes, changes, or resets the operational settings for the Dhcp6 instance.\r
385\r
386 The Configure() function is used to initialize or clean up the configuration\r
387 data of the Dhcp6 instance:\r
388 - When Dhcp6CfgData is not NULL and Configure() is called successfully, the\r
389 configuration data will be initialized in the Dhcp6 instance, and the state\r
390 of the configured IA will be transferred into Dhcp6Init.\r
391 - When Dhcp6CfgData is NULL and Configure() is called successfully, the\r
392 configuration data will be cleaned up and no IA will be associated with\r
393 the Dhcp6 instance.\r
394 To update the configuration data for an Dhcp6 instance, the original data\r
395 must be cleaned up before setting the new configuration data.\r
396\r
397 @param[in] This The pointer to the Dhcp6 protocol\r
398 @param[in] Dhcp6CfgData The pointer to the EFI_DHCP6_CONFIG_DATA.\r
399\r
400 @retval EFI_SUCCESS The Dhcp6 is configured successfully with the\r
401 Dhcp6Init state, or cleaned up the original\r
402 configuration setting.\r
403 @retval EFI_ACCESS_DENIED The Dhcp6 instance was already configured.\r
404 The Dhcp6 instance has already started the\r
405 DHCPv6 S.A.R.R when Dhcp6CfgData is NULL.\r
406 @retval EFI_INVALID_PARAMETER Some of the parameter is invalid.\r
407 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
408 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
409\r
410**/\r
411EFI_STATUS\r
412EFIAPI\r
413EfiDhcp6Configure (\r
414 IN EFI_DHCP6_PROTOCOL *This,\r
415 IN EFI_DHCP6_CONFIG_DATA *Dhcp6CfgData OPTIONAL\r
416 )\r
417{\r
418 EFI_TPL OldTpl;\r
419 EFI_STATUS Status;\r
420 LIST_ENTRY *Entry;\r
421 DHCP6_INSTANCE *Other;\r
422 DHCP6_INSTANCE *Instance;\r
423 DHCP6_SERVICE *Service;\r
424 UINTN Index;\r
425\r
426 if (This == NULL) {\r
427 return EFI_INVALID_PARAMETER;\r
428 }\r
429\r
430 Instance = DHCP6_INSTANCE_FROM_THIS (This);\r
431 Service = Instance->Service;\r
432\r
433 //\r
434 // Check the parameter of configure data.\r
435 //\r
436 if (Dhcp6CfgData != NULL) {\r
437 if (Dhcp6CfgData->OptionCount > 0 && Dhcp6CfgData->OptionList == NULL) {\r
438 return EFI_INVALID_PARAMETER;\r
439 }\r
440 if (Dhcp6CfgData->OptionList != NULL) {\r
441 for (Index = 0; Index < Dhcp6CfgData->OptionCount; Index++) {\r
442 if (Dhcp6CfgData->OptionList[Index]->OpCode == Dhcp6OptClientId ||\r
443 Dhcp6CfgData->OptionList[Index]->OpCode == Dhcp6OptRapidCommit ||\r
444 Dhcp6CfgData->OptionList[Index]->OpCode == Dhcp6OptReconfigureAccept ||\r
445 Dhcp6CfgData->OptionList[Index]->OpCode == Dhcp6OptIana ||\r
446 Dhcp6CfgData->OptionList[Index]->OpCode == Dhcp6OptIata\r
447 ) {\r
448 return EFI_INVALID_PARAMETER;\r
449 }\r
450 }\r
451 }\r
452\r
453 if (Dhcp6CfgData->IaDescriptor.Type != EFI_DHCP6_IA_TYPE_NA &&\r
454 Dhcp6CfgData->IaDescriptor.Type != EFI_DHCP6_IA_TYPE_TA\r
455 ) {\r
456 return EFI_INVALID_PARAMETER;\r
457 }\r
458\r
459 if (Dhcp6CfgData->IaInfoEvent == NULL && Dhcp6CfgData->SolicitRetransmission == NULL) {\r
460 return EFI_INVALID_PARAMETER;\r
461 }\r
462\r
463 if (Dhcp6CfgData->SolicitRetransmission != NULL &&\r
464 Dhcp6CfgData->SolicitRetransmission->Mrc == 0 &&\r
465 Dhcp6CfgData->SolicitRetransmission->Mrd == 0\r
466 ) {\r
467 return EFI_INVALID_PARAMETER;\r
468 }\r
469\r
470 //\r
471 // Make sure the (IaId, IaType) is unique over all the instances.\r
472 //\r
473 NET_LIST_FOR_EACH (Entry, &Service->Child) {\r
474 Other = NET_LIST_USER_STRUCT (Entry, DHCP6_INSTANCE, Link);\r
475 if (Other->IaCb.Ia != NULL &&\r
476 Other->IaCb.Ia->Descriptor.Type == Dhcp6CfgData->IaDescriptor.Type &&\r
477 Other->IaCb.Ia->Descriptor.IaId == Dhcp6CfgData->IaDescriptor.IaId\r
478 ) {\r
479 return EFI_INVALID_PARAMETER;\r
480 }\r
481 }\r
482 }\r
483\r
484 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
485\r
486 if (Dhcp6CfgData != NULL) {\r
487 //\r
488 // It's not allowed to configure one instance twice without configure null.\r
489 //\r
490 if (Instance->Config != NULL) {\r
491 gBS->RestoreTPL (OldTpl);\r
492 return EFI_ACCESS_DENIED;\r
493 }\r
494\r
495 //\r
496 // Duplicate config data including all reference buffers.\r
497 //\r
498 Instance->Config = AllocateZeroPool (sizeof (EFI_DHCP6_CONFIG_DATA));\r
499 if (Instance->Config == NULL) {\r
500 gBS->RestoreTPL (OldTpl);\r
501 return EFI_OUT_OF_RESOURCES;\r
502 }\r
503\r
504 Status = Dhcp6CopyConfigData (Instance->Config, Dhcp6CfgData);\r
505 if (EFI_ERROR(Status)) {\r
506 FreePool (Instance->Config);\r
507 gBS->RestoreTPL (OldTpl);\r
508 return EFI_OUT_OF_RESOURCES;\r
509 }\r
510\r
511 //\r
512 // Initialize the Ia descriptor from the config data, and leave the other\r
513 // fields of the Ia as default value 0.\r
514 //\r
515 Instance->IaCb.Ia = AllocateZeroPool (sizeof(EFI_DHCP6_IA));\r
516 if (Instance->IaCb.Ia == NULL) {\r
517 Dhcp6CleanupConfigData (Instance->Config);\r
518 FreePool (Instance->Config);\r
519 gBS->RestoreTPL (OldTpl);\r
520 return EFI_OUT_OF_RESOURCES;\r
521 }\r
522 CopyMem (\r
523 &Instance->IaCb.Ia->Descriptor,\r
524 &Dhcp6CfgData->IaDescriptor,\r
525 sizeof(EFI_DHCP6_IA_DESCRIPTOR)\r
526 );\r
527\r
528 } else {\r
529\r
530 if (Instance->Config == NULL) {\r
531 ASSERT (Instance->IaCb.Ia == NULL);\r
532 gBS->RestoreTPL (OldTpl);\r
533 return EFI_SUCCESS;\r
534 }\r
535\r
536 //\r
537 // It's not allowed to configure a started instance as null.\r
538 //\r
539 if (Instance->IaCb.Ia->State != Dhcp6Init) {\r
540 gBS->RestoreTPL (OldTpl);\r
541 return EFI_ACCESS_DENIED;\r
542 }\r
543\r
544 Dhcp6CleanupConfigData (Instance->Config);\r
545 FreePool (Instance->Config);\r
546 Instance->Config = NULL;\r
547\r
548 FreePool (Instance->IaCb.Ia);\r
549 Instance->IaCb.Ia = NULL;\r
550 }\r
551\r
552 gBS->RestoreTPL (OldTpl);\r
553\r
554 return EFI_SUCCESS;\r
555}\r
556\r
557\r
558/**\r
559 Request configuration information without the assignment of any\r
560 Ia addresses of the client.\r
561\r
562 The InfoRequest() function is used to request configuration information\r
563 without the assignment of any IPv6 address of the client. The client sends\r
564 out an Information Request packet to obtain the required configuration\r
565 information, and DHCPv6 server responds with a Reply packet containing\r
566 the information for the client. The received Reply packet will be passed\r
567 to the user by ReplyCallback function. If the user returns EFI_NOT_READY from\r
568 ReplyCallback, the Dhcp6 instance will continue to receive other Reply\r
569 packets unless timeout according to the Retransmission parameter.\r
570 Otherwise, the Information Request exchange process will be finished\r
571 successfully if user returns EFI_SUCCESS from ReplyCallback.\r
572\r
573 @param[in] This The pointer to the Dhcp6 protocol.\r
574 @param[in] SendClientId If TRUE, the DHCPv6 protocol instance will build Client\r
575 Identifier option and include it into Information Request\r
576 packet. Otherwise, Client Identifier option will not be included.\r
577 @param[in] OptionRequest The pointer to the buffer of option request options.\r
578 @param[in] OptionCount The option number in the OptionList.\r
579 @param[in] OptionList The list of appended options.\r
580 @param[in] Retransmission The pointer to the retransmission of the message.\r
581 @param[in] TimeoutEvent The event of timeout.\r
582 @param[in] ReplyCallback The callback function when the reply was received.\r
583 @param[in] CallbackContext The pointer to the parameter passed to the callback.\r
584\r
585 @retval EFI_SUCCESS The DHCPv6 information request exchange process\r
586 completed when TimeoutEvent is NULL. Information\r
587 Request packet has been sent to DHCPv6 server when\r
588 TimeoutEvent is not NULL.\r
589 @retval EFI_NO_RESPONSE The DHCPv6 information request exchange process failed\r
590 because of no response, or not all requested-options\r
591 are responded by DHCPv6 servers when Timeout happened.\r
592 @retval EFI_ABORTED The DHCPv6 information request exchange process was aborted\r
593 by user.\r
594 @retval EFI_INVALID_PARAMETER Some parameter is NULL.\r
595 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
596 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
597\r
598**/\r
599EFI_STATUS\r
600EFIAPI\r
601EfiDhcp6InfoRequest (\r
602 IN EFI_DHCP6_PROTOCOL *This,\r
603 IN BOOLEAN SendClientId,\r
604 IN EFI_DHCP6_PACKET_OPTION *OptionRequest,\r
605 IN UINT32 OptionCount,\r
606 IN EFI_DHCP6_PACKET_OPTION *OptionList[] OPTIONAL,\r
607 IN EFI_DHCP6_RETRANSMISSION *Retransmission,\r
608 IN EFI_EVENT TimeoutEvent OPTIONAL,\r
609 IN EFI_DHCP6_INFO_CALLBACK ReplyCallback,\r
610 IN VOID *CallbackContext OPTIONAL\r
611 )\r
612{\r
613 EFI_STATUS Status;\r
a3bcde70
HT
614 DHCP6_INSTANCE *Instance;\r
615 DHCP6_SERVICE *Service;\r
a3bcde70 616 UINTN Index;\r
cc658224 617 EFI_EVENT Timer;\r
618 EFI_STATUS TimerStatus;\r
619 UINTN GetMappingTimeOut;\r
a3bcde70
HT
620\r
621 if (This == NULL || OptionRequest == NULL || Retransmission == NULL || ReplyCallback == NULL) {\r
622 return EFI_INVALID_PARAMETER;\r
623 }\r
624\r
625 if (Retransmission != NULL && Retransmission->Mrc == 0 && Retransmission->Mrd == 0) {\r
626 return EFI_INVALID_PARAMETER;\r
627 }\r
628\r
629 if (OptionCount > 0 && OptionList == NULL) {\r
630 return EFI_INVALID_PARAMETER;\r
631 }\r
632\r
633 if (OptionList != NULL) {\r
634 for (Index = 0; Index < OptionCount; Index++) {\r
635 if (OptionList[Index]->OpCode == Dhcp6OptClientId || OptionList[Index]->OpCode == Dhcp6OptRequestOption) {\r
636 return EFI_INVALID_PARAMETER;\r
637 }\r
638 }\r
639 }\r
640\r
641 Instance = DHCP6_INSTANCE_FROM_THIS (This);\r
642 Service = Instance->Service;\r
643\r
cc658224 644 Status = Dhcp6StartInfoRequest (\r
a3bcde70 645 Instance,\r
a3bcde70
HT
646 SendClientId,\r
647 OptionRequest,\r
648 OptionCount,\r
649 OptionList,\r
cc658224 650 Retransmission,\r
651 TimeoutEvent,\r
652 ReplyCallback,\r
653 CallbackContext\r
a3bcde70 654 );\r
cc658224 655 if (Status == EFI_NO_MAPPING) {\r
656 //\r
657 // The link local address is not ready, wait for some time and restart\r
658 // the DHCP6 information request process.\r
659 //\r
660 Status = Dhcp6GetMappingTimeOut(Service->Ip6Cfg, &GetMappingTimeOut);\r
661 if (EFI_ERROR(Status)) {\r
662 return Status;\r
663 }\r
a3bcde70 664\r
cc658224 665 Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);\r
666 if (EFI_ERROR (Status)) {\r
667 return Status;\r
668 }\r
a3bcde70 669\r
cc658224 670 //\r
671 // Start the timer, wait for link local address DAD to finish.\r
672 //\r
673 Status = gBS->SetTimer (Timer, TimerRelative, GetMappingTimeOut);\r
674 if (EFI_ERROR (Status)) {\r
675 gBS->CloseEvent (Timer);\r
676 return Status;\r
677 }\r
a3bcde70 678\r
f75a7f56 679 do {\r
cc658224 680 TimerStatus = gBS->CheckEvent (Timer);\r
681 if (!EFI_ERROR (TimerStatus)) {\r
682 Status = Dhcp6StartInfoRequest (\r
683 Instance,\r
684 SendClientId,\r
685 OptionRequest,\r
686 OptionCount,\r
687 OptionList,\r
688 Retransmission,\r
689 TimeoutEvent,\r
690 ReplyCallback,\r
691 CallbackContext\r
692 );\r
693 }\r
694 } while (TimerStatus == EFI_NOT_READY);\r
f75a7f56 695\r
cc658224 696 gBS->CloseEvent (Timer);\r
697 }\r
698 if (EFI_ERROR (Status)) {\r
699 return Status;\r
a3bcde70 700 }\r
a3bcde70
HT
701\r
702 //\r
703 // Poll udp out of the net tpl if synchoronus call.\r
704 //\r
705 if (TimeoutEvent == NULL) {\r
706\r
707 while (Instance->UdpSts == EFI_ALREADY_STARTED) {\r
708 Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);\r
709 }\r
710 return Instance->UdpSts;\r
711 }\r
712\r
713 return EFI_SUCCESS;\r
a3bcde70
HT
714}\r
715\r
716\r
717/**\r
718 Manually extend the valid and preferred lifetimes for the IPv6 addresses\r
719 of the configured IA and update other configuration parameters by sending a\r
720 Renew or Rebind packet.\r
721\r
722 The RenewRebind() function is used to manually extend the valid and preferred\r
723 lifetimes for the IPv6 addresses of the configured IA, and update other\r
724 configuration parameters by sending Renew or Rebind packet.\r
725 - When RebindRequest is FALSE and the state of the configured IA is Dhcp6Bound,\r
726 it sends Renew packet to the previously DHCPv6 server and transfer the\r
727 state of the configured IA to Dhcp6Renewing. If valid Reply packet received,\r
728 the state transfers to Dhcp6Bound and the valid and preferred timer restarts.\r
729 If fails, the state transfers to Dhcp6Bound, but the timer continues.\r
730 - When RebindRequest is TRUE and the state of the configured IA is Dhcp6Bound,\r
731 it will send a Rebind packet. If valid Reply packet is received, the state transfers\r
732 to Dhcp6Bound and the valid and preferred timer restarts. If it fails, the state\r
733 transfers to Dhcp6Init, and the IA can't be used.\r
734\r
735 @param[in] This The pointer to the Dhcp6 protocol.\r
736 @param[in] RebindRequest If TRUE, Rebind packet will be sent and enter Dhcp6Rebinding state.\r
737 Otherwise, Renew packet will be sent and enter Dhcp6Renewing state.\r
738\r
739 @retval EFI_SUCCESS The DHCPv6 renew/rebind exchange process has\r
740 completed and at least one IPv6 address of the\r
741 configured IA has been bound again when\r
742 EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL.\r
743 The EFI DHCPv6 Protocol instance has sent Renew\r
744 or Rebind packet when\r
745 EFI_DHCP6_CONFIG_DATA.IaInfoEvent is not NULL.\r
746 @retval EFI_ACCESS_DENIED The Dhcp6 instance hasn't been configured, or the\r
747 state of the configured IA is not in Dhcp6Bound.\r
748 @retval EFI_ALREADY_STARTED The state of the configured IA has already entered\r
749 Dhcp6Renewing when RebindRequest is FALSE.\r
750 The state of the configured IA has already entered\r
751 Dhcp6Rebinding when RebindRequest is TRUE.\r
752 @retval EFI_ABORTED The DHCPv6 renew/rebind exchange process aborted\r
753 by the user.\r
754 @retval EFI_NO_RESPONSE The DHCPv6 renew/rebind exchange process failed\r
755 because of no response.\r
756 @retval EFI_NO_MAPPING No IPv6 address has been bound to the configured\r
757 IA after the DHCPv6 renew/rebind exchange process.\r
758 @retval EFI_INVALID_PARAMETER Some parameter is NULL.\r
759 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
760\r
761**/\r
762EFI_STATUS\r
763EFIAPI\r
764EfiDhcp6RenewRebind (\r
765 IN EFI_DHCP6_PROTOCOL *This,\r
766 IN BOOLEAN RebindRequest\r
767 )\r
768{\r
769 EFI_STATUS Status;\r
770 EFI_TPL OldTpl;\r
771 DHCP6_INSTANCE *Instance;\r
772 DHCP6_SERVICE *Service;\r
773\r
774 if (This == NULL) {\r
775 return EFI_INVALID_PARAMETER;\r
776 }\r
777\r
778 Instance = DHCP6_INSTANCE_FROM_THIS (This);\r
779 Service = Instance->Service;\r
780\r
781 //\r
782 // The instance hasn't been configured.\r
783 //\r
784 if (Instance->Config == NULL) {\r
785 return EFI_ACCESS_DENIED;\r
786 }\r
787\r
788 ASSERT (Instance->IaCb.Ia != NULL);\r
789\r
790 //\r
791 // The instance has already entered renewing or rebinding state.\r
792 //\r
793 if ((Instance->IaCb.Ia->State == Dhcp6Rebinding && RebindRequest) ||\r
794 (Instance->IaCb.Ia->State == Dhcp6Renewing && !RebindRequest)\r
795 ) {\r
796 return EFI_ALREADY_STARTED;\r
797 }\r
798\r
799 if (Instance->IaCb.Ia->State != Dhcp6Bound) {\r
800 return EFI_ACCESS_DENIED;\r
801 }\r
802\r
803 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
804 Instance->UdpSts = EFI_ALREADY_STARTED;\r
805\r
806 //\r
807 // Send renew/rebind message to start exchange process.\r
808 //\r
809 Status = Dhcp6SendRenewRebindMsg (Instance, RebindRequest);\r
810\r
811 if (EFI_ERROR (Status)) {\r
812 goto ON_ERROR;\r
813 }\r
814\r
815 //\r
816 // Register receive callback for the stateful exchange process.\r
817 //\r
818 Status = UdpIoRecvDatagram(\r
819 Service->UdpIo,\r
820 Dhcp6ReceivePacket,\r
821 Service,\r
822 0\r
823 );\r
824\r
825 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
826 goto ON_ERROR;\r
827 }\r
828\r
829 gBS->RestoreTPL (OldTpl);\r
830\r
831 //\r
832 // Poll udp out of the net tpl if synchoronus call.\r
833 //\r
834 if (Instance->Config->IaInfoEvent == NULL) {\r
835\r
836 while (Instance->UdpSts == EFI_ALREADY_STARTED) {\r
837 Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);\r
838 }\r
839 return Instance->UdpSts;\r
840 }\r
841\r
842 return EFI_SUCCESS;\r
843\r
844ON_ERROR:\r
845\r
846 gBS->RestoreTPL (OldTpl);\r
847 return Status;\r
848}\r
849\r
850\r
851/**\r
852 Inform that one or more addresses assigned by a server are already\r
853 in use by another node.\r
854\r
855 The Decline() function is used to manually decline the assignment of\r
856 IPv6 addresses, which have been already used by another node. If all\r
857 IPv6 addresses of the configured IA are declined through this function,\r
858 the state of the IA will switch through Dhcp6Declining to Dhcp6Init.\r
859 Otherwise, the state of the IA will restore to Dhcp6Bound after the\r
860 declining process. The Decline() can only be called when the IA is in\r
861 Dhcp6Bound state. If the EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL,\r
862 this function is a blocking operation. It will return after the\r
863 declining process finishes, or aborted by user.\r
864\r
865 @param[in] This The pointer to EFI_DHCP6_PROTOCOL.\r
866 @param[in] AddressCount The number of declining addresses.\r
867 @param[in] Addresses The pointer to the buffer stored the declining\r
868 addresses.\r
869\r
870 @retval EFI_SUCCESS The DHCPv6 decline exchange process completed\r
871 when EFI_DHCP6_CONFIG_DATA.IaInfoEvent was NULL.\r
872 The Dhcp6 instance sent Decline packet when\r
873 EFI_DHCP6_CONFIG_DATA.IaInfoEvent was not NULL.\r
874 @retval EFI_ACCESS_DENIED The Dhcp6 instance hasn't been configured, or the\r
875 state of the configured IA is not in Dhcp6Bound.\r
876 @retval EFI_ABORTED The DHCPv6 decline exchange process aborted by user.\r
877 @retval EFI_NOT_FOUND Any specified IPv6 address is not correlated with\r
878 the configured IA for this instance.\r
879 @retval EFI_INVALID_PARAMETER Some parameter is NULL.\r
880 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
881\r
882**/\r
883EFI_STATUS\r
884EFIAPI\r
885EfiDhcp6Decline (\r
886 IN EFI_DHCP6_PROTOCOL *This,\r
887 IN UINT32 AddressCount,\r
888 IN EFI_IPv6_ADDRESS *Addresses\r
889 )\r
890{\r
891 EFI_STATUS Status;\r
892 EFI_TPL OldTpl;\r
893 EFI_DHCP6_IA *DecIa;\r
894 DHCP6_INSTANCE *Instance;\r
895 DHCP6_SERVICE *Service;\r
896\r
897 if (This == NULL || AddressCount == 0 || Addresses == NULL) {\r
898 return EFI_INVALID_PARAMETER;\r
899 }\r
900\r
901 Instance = DHCP6_INSTANCE_FROM_THIS (This);\r
902 Service = Instance->Service;\r
903\r
904 //\r
905 // The instance hasn't been configured.\r
906 //\r
907 if (Instance->Config == NULL) {\r
908 return EFI_ACCESS_DENIED;\r
909 }\r
910\r
911 ASSERT (Instance->IaCb.Ia != NULL);\r
912\r
913 if (Instance->IaCb.Ia->State != Dhcp6Bound) {\r
914 return EFI_ACCESS_DENIED;\r
915 }\r
916\r
917 //\r
918 // Check whether all the declined addresses belongs to the configured Ia.\r
919 //\r
920 Status = Dhcp6CheckAddress (Instance->IaCb.Ia, AddressCount, Addresses);\r
921\r
922 if (EFI_ERROR(Status)) {\r
923 return Status;\r
924 }\r
925\r
926 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
927 Instance->UdpSts = EFI_ALREADY_STARTED;\r
928\r
929 //\r
930 // Deprive of all the declined addresses from the configured Ia, and create a\r
931 // DeclineIa used to create decline message.\r
932 //\r
933 DecIa = Dhcp6DepriveAddress (Instance->IaCb.Ia, AddressCount, Addresses);\r
934\r
935 if (DecIa == NULL) {\r
936 Status = EFI_OUT_OF_RESOURCES;\r
937 goto ON_ERROR;\r
938 }\r
939\r
940 //\r
941 // Send the decline message to start exchange process.\r
942 //\r
943 Status = Dhcp6SendDeclineMsg (Instance, DecIa);\r
944\r
945 if (EFI_ERROR (Status)) {\r
946 goto ON_ERROR;\r
947 }\r
948\r
949 //\r
950 // Register receive callback for the stateful exchange process.\r
951 //\r
952 Status = UdpIoRecvDatagram(\r
953 Service->UdpIo,\r
954 Dhcp6ReceivePacket,\r
955 Service,\r
956 0\r
957 );\r
958\r
959 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
960 goto ON_ERROR;\r
961 }\r
962\r
963 FreePool (DecIa);\r
964 gBS->RestoreTPL (OldTpl);\r
965\r
966 //\r
967 // Poll udp out of the net tpl if synchoronus call.\r
968 //\r
969 if (Instance->Config->IaInfoEvent == NULL) {\r
970\r
971 while (Instance->UdpSts == EFI_ALREADY_STARTED) {\r
972 Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);\r
973 }\r
974 return Instance->UdpSts;\r
975 }\r
976\r
977 return EFI_SUCCESS;\r
978\r
979ON_ERROR:\r
980\r
981 if (DecIa != NULL) {\r
982 FreePool (DecIa);\r
983 }\r
984 gBS->RestoreTPL (OldTpl);\r
985\r
986 return Status;\r
987}\r
988\r
989\r
990/**\r
991 Release one or more addresses associated with the configured Ia\r
992 for current instance.\r
993\r
994 The Release() function is used to manually release one or more\r
995 IPv6 addresses. If AddressCount is zero, it will release all IPv6\r
996 addresses of the configured IA. If all IPv6 addresses of the IA are\r
997 released through this function, the state of the IA will switch\r
998 through Dhcp6Releasing to Dhcp6Init, otherwise, the state of the\r
999 IA will restore to Dhcp6Bound after the releasing process.\r
1000 The Release() can only be called when the IA is in Dhcp6Bound state.\r
1001 If the EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL, the function is\r
1002 a blocking operation. It will return after the releasing process\r
1003 finishes, or is aborted by user.\r
1004\r
1005 @param[in] This The pointer to the Dhcp6 protocol.\r
1006 @param[in] AddressCount The number of releasing addresses.\r
1007 @param[in] Addresses The pointer to the buffer stored the releasing\r
1008 addresses.\r
1009\r
1010 @retval EFI_SUCCESS The DHCPv6 release exchange process\r
1011 completed when EFI_DHCP6_CONFIG_DATA.IaInfoEvent\r
1012 was NULL. The Dhcp6 instance was sent Release\r
1013 packet when EFI_DHCP6_CONFIG_DATA.IaInfoEvent\r
1014 was not NULL.\r
1015 @retval EFI_ACCESS_DENIED The Dhcp6 instance hasn't been configured, or the\r
1016 state of the configured IA is not in Dhcp6Bound.\r
1017 @retval EFI_ABORTED The DHCPv6 release exchange process aborted by user.\r
1018 @retval EFI_NOT_FOUND Any specified IPv6 address is not correlated with\r
1019 the configured IA for this instance.\r
1020 @retval EFI_INVALID_PARAMETER Some parameter is NULL.\r
1021 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
1022\r
1023**/\r
1024EFI_STATUS\r
1025EFIAPI\r
1026EfiDhcp6Release (\r
1027 IN EFI_DHCP6_PROTOCOL *This,\r
1028 IN UINT32 AddressCount,\r
1029 IN EFI_IPv6_ADDRESS *Addresses\r
1030 )\r
1031{\r
1032 EFI_STATUS Status;\r
1033 EFI_TPL OldTpl;\r
1034 EFI_DHCP6_IA *RelIa;\r
1035 DHCP6_INSTANCE *Instance;\r
1036 DHCP6_SERVICE *Service;\r
1037\r
1038 if (This == NULL || (AddressCount != 0 && Addresses == NULL)) {\r
1039 return EFI_INVALID_PARAMETER;\r
1040 }\r
1041\r
1042 Instance = DHCP6_INSTANCE_FROM_THIS (This);\r
1043 Service = Instance->Service;\r
1044\r
1045 //\r
1046 // The instance hasn't been configured.\r
1047 //\r
1048 if (Instance->Config == NULL) {\r
1049 return EFI_ACCESS_DENIED;\r
1050 }\r
1051\r
1052 ASSERT (Instance->IaCb.Ia != NULL);\r
1053\r
1054 if (Instance->IaCb.Ia->State != Dhcp6Bound) {\r
1055 return EFI_ACCESS_DENIED;\r
1056 }\r
1057\r
1058 //\r
1059 // Check whether all the released addresses belongs to the configured Ia.\r
1060 //\r
1061 Status = Dhcp6CheckAddress (Instance->IaCb.Ia, AddressCount, Addresses);\r
1062\r
1063 if (EFI_ERROR(Status)) {\r
1064 return Status;\r
1065 }\r
1066\r
1067 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1068 Instance->UdpSts = EFI_ALREADY_STARTED;\r
1069\r
1070 //\r
1071 // Deprive of all the released addresses from the configured Ia, and create a\r
1072 // ReleaseIa used to create release message.\r
1073 //\r
1074 RelIa = Dhcp6DepriveAddress (Instance->IaCb.Ia, AddressCount, Addresses);\r
1075\r
1076 if (RelIa == NULL) {\r
1077 Status = EFI_OUT_OF_RESOURCES;\r
1078 goto ON_ERROR;\r
1079 }\r
1080\r
1081 //\r
1082 // Send the release message to start exchange process.\r
1083 //\r
1084 Status = Dhcp6SendReleaseMsg (Instance, RelIa);\r
1085\r
1086 if (EFI_ERROR (Status)) {\r
1087 goto ON_ERROR;\r
1088 }\r
1089\r
1090 //\r
1091 // Register receive callback for the stateful exchange process.\r
1092 //\r
1093 Status = UdpIoRecvDatagram(\r
1094 Service->UdpIo,\r
1095 Dhcp6ReceivePacket,\r
1096 Service,\r
1097 0\r
1098 );\r
1099\r
1100 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
1101 goto ON_ERROR;\r
1102 }\r
1103\r
1104 FreePool (RelIa);\r
1105 gBS->RestoreTPL (OldTpl);\r
1106\r
1107 //\r
1108 // Poll udp out of the net tpl if synchoronus call.\r
1109 //\r
1110 if (Instance->Config->IaInfoEvent == NULL) {\r
1111 while (Instance->UdpSts == EFI_ALREADY_STARTED) {\r
1112 Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);\r
1113 }\r
1114 return Instance->UdpSts;\r
1115 }\r
1116\r
1117 return EFI_SUCCESS;\r
1118\r
1119ON_ERROR:\r
1120\r
1121 if (RelIa != NULL) {\r
1122 FreePool (RelIa);\r
1123 }\r
1124 gBS->RestoreTPL (OldTpl);\r
1125\r
1126 return Status;\r
1127}\r
1128\r
1129\r
1130/**\r
1131 Parse the option data in the Dhcp6 packet.\r
1132\r
1133 The Parse() function is used to retrieve the option list in the DHCPv6 packet.\r
1134\r
1135 @param[in] This The pointer to the Dhcp6 protocol.\r
1136 @param[in] Packet The pointer to the Dhcp6 packet.\r
1137 @param[in, out] OptionCount The number of option in the packet.\r
1138 @param[out] PacketOptionList The array of pointers to each option in the packet.\r
1139\r
1140 @retval EFI_SUCCESS The packet was successfully parsed.\r
1141 @retval EFI_INVALID_PARAMETER Some parameter is NULL.\r
1142 @retval EFI_BUFFER_TOO_SMALL *OptionCount is smaller than the number of options\r
1143 that were found in the Packet.\r
1144\r
1145**/\r
1146EFI_STATUS\r
1147EFIAPI\r
1148EfiDhcp6Parse (\r
1149 IN EFI_DHCP6_PROTOCOL *This,\r
1150 IN EFI_DHCP6_PACKET *Packet,\r
1151 IN OUT UINT32 *OptionCount,\r
1152 OUT EFI_DHCP6_PACKET_OPTION *PacketOptionList[] OPTIONAL\r
1153 )\r
1154{\r
1155 UINT32 OptCnt;\r
1156 UINT32 OptLen;\r
1157 UINT16 DataLen;\r
1158 UINT8 *Start;\r
1159 UINT8 *End;\r
1160\r
1161 if (This == NULL || Packet == NULL || OptionCount == NULL) {\r
1162 return EFI_INVALID_PARAMETER;\r
1163 }\r
1164\r
1165 if (*OptionCount != 0 && PacketOptionList == NULL) {\r
1166 return EFI_INVALID_PARAMETER;\r
1167 }\r
1168\r
1169 if (Packet->Length > Packet->Size || Packet->Length < sizeof (EFI_DHCP6_HEADER)) {\r
1170 return EFI_INVALID_PARAMETER;\r
1171 }\r
1172\r
1173 //\r
1174 // The format of Dhcp6 option:\r
1175 //\r
1176 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
1177 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
1178 // | option-code | option-len (option data) |\r
1179 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
1180 // | option-data |\r
1181 // | (option-len octets) |\r
1182 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
1183 //\r
1184\r
1185 OptCnt = 0;\r
1186 OptLen = Packet->Length - sizeof (EFI_DHCP6_HEADER);\r
1187 Start = Packet->Dhcp6.Option;\r
1188 End = Start + OptLen;\r
1189\r
1190 //\r
1191 // Calculate the number of option in the packet.\r
1192 //\r
1193 while (Start < End) {\r
1194 DataLen = ((EFI_DHCP6_PACKET_OPTION *) Start)->OpLen;\r
1195 Start += (NTOHS (DataLen) + 4);\r
1196 OptCnt++;\r
1197 }\r
1198\r
1199 //\r
1200 // It will return buffer too small if pass-in option count is smaller than the\r
1201 // actual count of options in the packet.\r
1202 //\r
1203 if (OptCnt > *OptionCount) {\r
1204 *OptionCount = OptCnt;\r
1205 return EFI_BUFFER_TOO_SMALL;\r
1206 }\r
1207\r
1208 ZeroMem (\r
1209 PacketOptionList,\r
1210 (*OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *))\r
1211 );\r
1212\r
1213 OptCnt = 0;\r
1214 Start = Packet->Dhcp6.Option;\r
1215\r
1216 while (Start < End) {\r
1217\r
1218 PacketOptionList[OptCnt] = (EFI_DHCP6_PACKET_OPTION *) Start;\r
1219 DataLen = ((EFI_DHCP6_PACKET_OPTION *) Start)->OpLen;\r
1220 Start += (NTOHS (DataLen) + 4);\r
1221 OptCnt++;\r
1222 }\r
1223\r
1224 return EFI_SUCCESS;\r
1225}\r
1226\r