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