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