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