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