]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/IScsiDxe/IScsiDhcp.c
ArmPlatformPkg: create hw-agnostic LcdGraphicsOutputDxe driver
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiDhcp.c
CommitLineData
4c5a5e0c 1/** @file\r
2 iSCSI DHCP4 related configuration routines.\r
3\r
eabc6e59 4Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.<BR>\r
4c5a5e0c 5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "IScsiImpl.h"\r
16\r
17\r
18/**\r
19 Extract the Root Path option and get the required target information.\r
20\r
21 @param[in] RootPath The RootPath.\r
22 @param[in] Length Length of the RootPath option payload.\r
23 @param[in, out] ConfigData The iSCSI attempt configuration data read\r
24 from a nonvolatile device.\r
25\r
26 @retval EFI_SUCCESS All required information is extracted from the RootPath option.\r
27 @retval EFI_NOT_FOUND The RootPath is not an iSCSI RootPath.\r
28 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
29 @retval EFI_INVALID_PARAMETER The RootPath is malformatted.\r
30\r
31**/\r
32EFI_STATUS\r
33IScsiDhcpExtractRootPath (\r
34 IN CHAR8 *RootPath,\r
35 IN UINT8 Length,\r
36 IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData\r
37 )\r
38{\r
39 EFI_STATUS Status;\r
40 UINT8 IScsiRootPathIdLen;\r
41 CHAR8 *TmpStr;\r
42 ISCSI_ROOT_PATH_FIELD Fields[RP_FIELD_IDX_MAX];\r
43 ISCSI_ROOT_PATH_FIELD *Field;\r
44 UINT32 FieldIndex;\r
45 UINT8 Index;\r
46 ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData;\r
47 EFI_IP_ADDRESS Ip;\r
48 UINT8 IpMode;\r
49\r
50 ConfigNvData = &ConfigData->SessionConfigData;\r
51\r
52 //\r
53 // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>\r
54 //\r
55 IScsiRootPathIdLen = (UINT8) AsciiStrLen (ISCSI_ROOT_PATH_ID);\r
56\r
57 if ((Length <= IScsiRootPathIdLen) || (CompareMem (RootPath, ISCSI_ROOT_PATH_ID, IScsiRootPathIdLen) != 0)) {\r
58 return EFI_NOT_FOUND;\r
59 }\r
60 //\r
61 // Skip the iSCSI RootPath ID "iscsi:".\r
62 //\r
63 RootPath += IScsiRootPathIdLen;\r
64 Length = (UINT8) (Length - IScsiRootPathIdLen);\r
65\r
66 TmpStr = (CHAR8 *) AllocatePool (Length + 1);\r
67 if (TmpStr == NULL) {\r
68 return EFI_OUT_OF_RESOURCES;\r
69 }\r
70\r
71 CopyMem (TmpStr, RootPath, Length);\r
72 TmpStr[Length] = '\0';\r
73\r
74 Index = 0;\r
75 FieldIndex = RP_FIELD_IDX_SERVERNAME;\r
76 ZeroMem (&Fields[0], sizeof (Fields));\r
77\r
78 //\r
79 // Extract the fields in the Root Path option string.\r
80 //\r
81 for (FieldIndex = RP_FIELD_IDX_SERVERNAME; (FieldIndex < RP_FIELD_IDX_MAX) && (Index < Length); FieldIndex++) {\r
82 if (TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) {\r
83 Fields[FieldIndex].Str = &TmpStr[Index];\r
84 }\r
85\r
86 while ((TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) && (Index < Length)) {\r
87 Index++;\r
88 }\r
89\r
90 if (TmpStr[Index] == ISCSI_ROOT_PATH_FIELD_DELIMITER) {\r
91 if (FieldIndex != RP_FIELD_IDX_TARGETNAME) {\r
92 TmpStr[Index] = '\0';\r
93 Index++;\r
94 }\r
95\r
96 if (Fields[FieldIndex].Str != NULL) {\r
97 Fields[FieldIndex].Len = (UINT8) AsciiStrLen (Fields[FieldIndex].Str);\r
98 }\r
99 }\r
100 }\r
101\r
102 if (FieldIndex != RP_FIELD_IDX_MAX) {\r
103 Status = EFI_INVALID_PARAMETER;\r
104 goto ON_EXIT;\r
105 }\r
106\r
107 if ((Fields[RP_FIELD_IDX_SERVERNAME].Str == NULL) ||\r
108 (Fields[RP_FIELD_IDX_TARGETNAME].Str == NULL) ||\r
109 (Fields[RP_FIELD_IDX_PROTOCOL].Len > 1)\r
110 ) {\r
111\r
112 Status = EFI_INVALID_PARAMETER;\r
113 goto ON_EXIT;\r
114 }\r
115 //\r
116 // Get the IP address of the target.\r
117 //\r
118 Field = &Fields[RP_FIELD_IDX_SERVERNAME];\r
119\r
120 if (ConfigNvData->IpMode < IP_MODE_AUTOCONFIG) {\r
121 IpMode = ConfigNvData->IpMode;\r
122 } else {\r
123 IpMode = ConfigData->AutoConfigureMode;\r
124 }\r
125\r
eabc6e59
ZL
126 //\r
127 // Server name is expressed as domain name, just save it.\r
128 //\r
129 if ((!NET_IS_DIGIT (*(Field->Str))) && (*(Field->Str) != '[')) {\r
130 ConfigNvData->DnsMode = TRUE;\r
131 if (Field->Len > sizeof (ConfigNvData->TargetUrl)) {\r
132 return EFI_INVALID_PARAMETER;\r
133 }\r
134 CopyMem (&ConfigNvData->TargetUrl, Field->Str, Field->Len);\r
135 ConfigNvData->TargetUrl[Field->Len + 1] = '\0';\r
136 } else {\r
137 ZeroMem(ConfigNvData->TargetUrl, sizeof (ConfigNvData->TargetUrl));\r
138 Status = IScsiAsciiStrToIp (Field->Str, IpMode, &Ip);\r
139 CopyMem (&ConfigNvData->TargetIp, &Ip, sizeof (EFI_IP_ADDRESS));\r
4c5a5e0c 140\r
eabc6e59
ZL
141 if (EFI_ERROR (Status)) {\r
142 goto ON_EXIT;\r
143 }\r
4c5a5e0c 144 }\r
145 //\r
146 // Check the protocol type.\r
147 //\r
148 Field = &Fields[RP_FIELD_IDX_PROTOCOL];\r
149 if ((Field->Str != NULL) && ((*(Field->Str) - '0') != EFI_IP_PROTO_TCP)) {\r
150 Status = EFI_INVALID_PARAMETER;\r
151 goto ON_EXIT;\r
152 }\r
153 //\r
154 // Get the port of the iSCSI target.\r
155 //\r
156 Field = &Fields[RP_FIELD_IDX_PORT];\r
157 if (Field->Str != NULL) {\r
158 ConfigNvData->TargetPort = (UINT16) AsciiStrDecimalToUintn (Field->Str);\r
159 } else {\r
160 ConfigNvData->TargetPort = ISCSI_WELL_KNOWN_PORT;\r
161 }\r
162 //\r
163 // Get the LUN.\r
164 //\r
165 Field = &Fields[RP_FIELD_IDX_LUN];\r
166 if (Field->Str != NULL) {\r
167 Status = IScsiAsciiStrToLun (Field->Str, ConfigNvData->BootLun);\r
168 if (EFI_ERROR (Status)) {\r
169 goto ON_EXIT;\r
170 }\r
171 } else {\r
172 ZeroMem (ConfigNvData->BootLun, sizeof (ConfigNvData->BootLun));\r
173 }\r
174 //\r
175 // Get the target iSCSI Name.\r
176 //\r
177 Field = &Fields[RP_FIELD_IDX_TARGETNAME];\r
178\r
179 if (AsciiStrLen (Field->Str) > ISCSI_NAME_MAX_SIZE - 1) {\r
180 Status = EFI_INVALID_PARAMETER;\r
181 goto ON_EXIT;\r
182 }\r
183 //\r
184 // Validate the iSCSI name.\r
185 //\r
186 Status = IScsiNormalizeName (Field->Str, AsciiStrLen (Field->Str));\r
187 if (EFI_ERROR (Status)) {\r
188 goto ON_EXIT;\r
189 }\r
190\r
c960bdc2 191 AsciiStrCpyS (ConfigNvData->TargetName, ISCSI_NAME_MAX_SIZE, Field->Str);\r
4c5a5e0c 192\r
193ON_EXIT:\r
194\r
195 FreePool (TmpStr);\r
196\r
197 return Status;\r
198}\r
199\r
200/**\r
201 The callback function registerd to the DHCP4 instance that is used to select\r
202 the qualified DHCP OFFER.\r
203 \r
204 @param[in] This The DHCP4 protocol.\r
205 @param[in] Context The context set when configuring the DHCP4 protocol.\r
206 @param[in] CurrentState The current state of the DHCP4 protocol.\r
207 @param[in] Dhcp4Event The event occurs in the current state.\r
208 @param[in] Packet The DHCP packet that is to be sent or was already received. \r
209 @param[out] NewPacket The packet used to replace the above Packet.\r
210 \r
211 @retval EFI_SUCCESS Either the DHCP OFFER is qualified or we're not intereseted\r
212 in the Dhcp4Event.\r
213 @retval EFI_NOT_READY The DHCP OFFER packet doesn't match our requirements.\r
214 @retval Others Other errors as indicated.\r
215\r
216**/\r
217EFI_STATUS\r
218EFIAPI\r
219IScsiDhcpSelectOffer (\r
220 IN EFI_DHCP4_PROTOCOL *This,\r
221 IN VOID *Context,\r
222 IN EFI_DHCP4_STATE CurrentState,\r
223 IN EFI_DHCP4_EVENT Dhcp4Event,\r
224 IN EFI_DHCP4_PACKET *Packet, OPTIONAL\r
225 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL\r
226 )\r
227{\r
228 EFI_STATUS Status;\r
229 UINT32 OptionCount;\r
230 EFI_DHCP4_PACKET_OPTION **OptionList;\r
231 UINT32 Index;\r
232\r
233 if ((Dhcp4Event != Dhcp4RcvdOffer) && (Dhcp4Event != Dhcp4SelectOffer)) {\r
234 return EFI_SUCCESS;\r
235 }\r
236\r
237 OptionCount = 0;\r
238\r
239 Status = This->Parse (This, Packet, &OptionCount, NULL);\r
240 if (Status != EFI_BUFFER_TOO_SMALL) {\r
241 return EFI_NOT_READY;\r
242 }\r
243\r
244 OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
245 if (OptionList == NULL) {\r
246 return EFI_NOT_READY;\r
247 }\r
248\r
249 Status = This->Parse (This, Packet, &OptionCount, OptionList);\r
250 if (EFI_ERROR (Status)) {\r
251 FreePool (OptionList);\r
252 return EFI_NOT_READY;\r
253 }\r
254\r
255 for (Index = 0; Index < OptionCount; Index++) {\r
142c00c3 256 if (OptionList[Index]->OpCode != DHCP4_TAG_ROOTPATH) {\r
4c5a5e0c 257 continue;\r
258 }\r
259\r
260 Status = IScsiDhcpExtractRootPath (\r
261 (CHAR8 *) &OptionList[Index]->Data[0],\r
262 OptionList[Index]->Length,\r
263 (ISCSI_ATTEMPT_CONFIG_NVDATA *) Context\r
264 );\r
265\r
266 break;\r
267 }\r
268\r
cf260a47 269 if (Index == OptionCount) {\r
4c5a5e0c 270 Status = EFI_NOT_READY;\r
271 }\r
272\r
273 FreePool (OptionList);\r
274\r
275 return Status;\r
276}\r
277\r
278/**\r
279 Parse the DHCP ACK to get the address configuration and DNS information.\r
280\r
281 @param[in] Dhcp4 The DHCP4 protocol.\r
282 @param[in, out] ConfigData The session configuration data.\r
283\r
284 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.\r
285 @retval EFI_NO_MAPPING DHCP failed to acquire address and other information.\r
286 @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is malformatted.\r
287 @retval EFI_DEVICE_ERROR Other errors as indicated.\r
288 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
289\r
290**/\r
291EFI_STATUS\r
292IScsiParseDhcpAck (\r
293 IN EFI_DHCP4_PROTOCOL *Dhcp4,\r
294 IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData\r
295 )\r
296{\r
297 EFI_STATUS Status;\r
298 EFI_DHCP4_MODE_DATA Dhcp4ModeData;\r
299 UINT32 OptionCount;\r
300 EFI_DHCP4_PACKET_OPTION **OptionList;\r
301 UINT32 Index;\r
302 ISCSI_SESSION_CONFIG_NVDATA *NvData;\r
303\r
304 Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4ModeData);\r
305 if (EFI_ERROR (Status)) {\r
306 return Status;\r
307 }\r
308\r
309 if (Dhcp4ModeData.State != Dhcp4Bound) {\r
310 return EFI_NO_MAPPING;\r
311 }\r
312\r
313 NvData = &ConfigData->SessionConfigData;\r
314\r
315 CopyMem (&NvData->LocalIp, &Dhcp4ModeData.ClientAddress, sizeof (EFI_IPv4_ADDRESS));\r
316 CopyMem (&NvData->SubnetMask, &Dhcp4ModeData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
317 CopyMem (&NvData->Gateway, &Dhcp4ModeData.RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
318\r
319 OptionCount = 0;\r
320 OptionList = NULL;\r
321\r
322 Status = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);\r
323 if (Status != EFI_BUFFER_TOO_SMALL) {\r
324 return EFI_DEVICE_ERROR;\r
325 }\r
326\r
327 OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
328 if (OptionList == NULL) {\r
329 return EFI_OUT_OF_RESOURCES;\r
330 }\r
331\r
332 Status = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);\r
333 if (EFI_ERROR (Status)) {\r
334 FreePool (OptionList);\r
335 return EFI_DEVICE_ERROR;\r
336 }\r
337\r
338 for (Index = 0; Index < OptionCount; Index++) {\r
339 //\r
340 // Get DNS server addresses and DHCP server address from this offer.\r
341 //\r
142c00c3 342 if (OptionList[Index]->OpCode == DHCP4_TAG_DNS_SERVER) {\r
4c5a5e0c 343\r
344 if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {\r
345 Status = EFI_INVALID_PARAMETER;\r
346 break;\r
347 }\r
348 //\r
349 // Primary DNS server address.\r
350 //\r
351 CopyMem (&ConfigData->PrimaryDns, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));\r
352\r
353 if (OptionList[Index]->Length > 4) {\r
354 //\r
355 // Secondary DNS server address.\r
356 //\r
357 CopyMem (&ConfigData->SecondaryDns, &OptionList[Index]->Data[4], sizeof (EFI_IPv4_ADDRESS));\r
358 }\r
359 } else if (OptionList[Index]->OpCode == DHCP4_TAG_SERVER_ID) {\r
360 if (OptionList[Index]->Length != 4) {\r
361 Status = EFI_INVALID_PARAMETER;\r
362 break;\r
363 }\r
364\r
365 CopyMem (&ConfigData->DhcpServer, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));\r
366 }\r
367 }\r
368\r
369 FreePool (OptionList);\r
370\r
371 return Status;\r
372}\r
373\r
ef810bc8
JW
374/**\r
375 This function will switch the IP4 configuration policy to Static.\r
376\r
377 @param[in] Ip4Config2 Pointer to the IP4 configuration protocol.\r
378\r
379 @retval EFI_SUCCESS The policy is already configured to static.\r
380 @retval Others Other error as indicated.\r
381\r
382**/\r
383EFI_STATUS\r
384IScsiSetIp4Policy (\r
385 IN EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2\r
386 )\r
387{\r
388 EFI_IP4_CONFIG2_POLICY Policy;\r
389 EFI_STATUS Status;\r
390 UINTN DataSize;\r
391\r
392 DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);\r
393 Status = Ip4Config2->GetData (\r
394 Ip4Config2,\r
395 Ip4Config2DataTypePolicy,\r
396 &DataSize,\r
397 &Policy\r
398 );\r
399 if (EFI_ERROR (Status)) {\r
400 return Status;\r
401 }\r
402\r
403 if (Policy != Ip4Config2PolicyStatic) {\r
404 Policy = Ip4Config2PolicyStatic;\r
405 Status= Ip4Config2->SetData (\r
406 Ip4Config2,\r
407 Ip4Config2DataTypePolicy,\r
408 sizeof (EFI_IP4_CONFIG2_POLICY),\r
409 &Policy\r
410 );\r
411 if (EFI_ERROR (Status)) {\r
412 return Status;\r
413 } \r
414 }\r
415\r
416 return EFI_SUCCESS;\r
417}\r
4c5a5e0c 418\r
419/**\r
420 Parse the DHCP ACK to get the address configuration and DNS information.\r
421\r
422 @param[in] Image The handle of the driver image.\r
423 @param[in] Controller The handle of the controller.\r
424 @param[in, out] ConfigData The attempt configuration data.\r
425\r
426 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.\r
427 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
428 @retval EFI_NO_MEDIA There was a media error.\r
429 @retval Others Other errors as indicated.\r
430\r
431**/\r
432EFI_STATUS\r
433IScsiDoDhcp (\r
434 IN EFI_HANDLE Image,\r
435 IN EFI_HANDLE Controller,\r
436 IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData\r
437 )\r
438{\r
439 EFI_HANDLE Dhcp4Handle;\r
ef810bc8 440 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
4c5a5e0c 441 EFI_DHCP4_PROTOCOL *Dhcp4;\r
442 EFI_STATUS Status;\r
443 EFI_DHCP4_PACKET_OPTION *ParaList;\r
444 EFI_DHCP4_CONFIG_DATA Dhcp4ConfigData;\r
445 ISCSI_SESSION_CONFIG_NVDATA *NvData;\r
446 BOOLEAN MediaPresent;\r
447\r
448 Dhcp4Handle = NULL;\r
ef810bc8 449 Ip4Config2 = NULL;\r
4c5a5e0c 450 Dhcp4 = NULL;\r
451 ParaList = NULL;\r
452\r
453 //\r
454 // Check media status before doing DHCP.\r
455 //\r
456 MediaPresent = TRUE;\r
457 NetLibDetectMedia (Controller, &MediaPresent);\r
458 if (!MediaPresent) {\r
459 return EFI_NO_MEDIA;\r
460 }\r
461\r
ef810bc8
JW
462 //\r
463 // DHCP4 service allows only one of its children to be configured in \r
464 // the active state, If the DHCP4 D.O.R.A started by IP4 auto \r
465 // configuration and has not been completed, the Dhcp4 state machine \r
466 // will not be in the right state for the iSCSI to start a new round D.O.R.A. \r
467 // So, we need to switch it's policy to static.\r
468 //\r
469 Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2);\r
470 if (!EFI_ERROR (Status)) {\r
471 Status = IScsiSetIp4Policy (Ip4Config2);\r
472 if (EFI_ERROR (Status)) {\r
473 return Status;\r
474 }\r
475 }\r
476\r
4c5a5e0c 477 //\r
478 // Create a DHCP4 child instance and get the protocol.\r
479 //\r
480 Status = NetLibCreateServiceChild (\r
481 Controller,\r
482 Image,\r
483 &gEfiDhcp4ServiceBindingProtocolGuid,\r
484 &Dhcp4Handle\r
485 );\r
486 if (EFI_ERROR (Status)) {\r
487 return Status;\r
488 }\r
489\r
490 Status = gBS->OpenProtocol (\r
491 Dhcp4Handle,\r
492 &gEfiDhcp4ProtocolGuid,\r
493 (VOID **) &Dhcp4,\r
494 Image,\r
495 Controller,\r
496 EFI_OPEN_PROTOCOL_BY_DRIVER\r
497 );\r
498 if (EFI_ERROR (Status)) {\r
499 goto ON_EXIT;\r
500 }\r
501\r
502 NvData = &ConfigData->SessionConfigData;\r
503\r
504 ParaList = AllocatePool (sizeof (EFI_DHCP4_PACKET_OPTION) + 3);\r
505 if (ParaList == NULL) {\r
506 Status = EFI_OUT_OF_RESOURCES;\r
507 goto ON_EXIT;\r
508 }\r
509\r
510 //\r
511 // Ask the server to reply with Netmask, Router, DNS, and RootPath options.\r
512 //\r
513 ParaList->OpCode = DHCP4_TAG_PARA_LIST;\r
514 ParaList->Length = (UINT8) (NvData->TargetInfoFromDhcp ? 4 : 3);\r
515 ParaList->Data[0] = DHCP4_TAG_NETMASK;\r
516 ParaList->Data[1] = DHCP4_TAG_ROUTER;\r
142c00c3
ZL
517 ParaList->Data[2] = DHCP4_TAG_DNS_SERVER;\r
518 ParaList->Data[3] = DHCP4_TAG_ROOTPATH;\r
4c5a5e0c 519\r
520 ZeroMem (&Dhcp4ConfigData, sizeof (EFI_DHCP4_CONFIG_DATA));\r
521 Dhcp4ConfigData.OptionCount = 1;\r
522 Dhcp4ConfigData.OptionList = &ParaList;\r
523\r
524 if (NvData->TargetInfoFromDhcp) {\r
525 //\r
526 // Use callback to select an offer that contains target information.\r
527 //\r
528 Dhcp4ConfigData.Dhcp4Callback = IScsiDhcpSelectOffer;\r
529 Dhcp4ConfigData.CallbackContext = ConfigData;\r
530 }\r
531\r
532 Status = Dhcp4->Configure (Dhcp4, &Dhcp4ConfigData);\r
533 if (EFI_ERROR (Status)) {\r
534 goto ON_EXIT;\r
535 }\r
536\r
537 Status = Dhcp4->Start (Dhcp4, NULL);\r
538 if (EFI_ERROR (Status)) {\r
539 goto ON_EXIT;\r
540 }\r
541 //\r
542 // Parse the ACK to get required information.\r
543 //\r
544 Status = IScsiParseDhcpAck (Dhcp4, ConfigData);\r
545\r
546ON_EXIT:\r
547\r
548 if (ParaList != NULL) {\r
549 FreePool (ParaList);\r
550 }\r
551\r
552 if (Dhcp4 != NULL) {\r
553 Dhcp4->Stop (Dhcp4);\r
554 Dhcp4->Configure (Dhcp4, NULL);\r
555\r
556 gBS->CloseProtocol (\r
557 Dhcp4Handle,\r
558 &gEfiDhcp4ProtocolGuid,\r
559 Image,\r
560 Controller\r
561 );\r
562 }\r
563\r
564 NetLibDestroyServiceChild (\r
565 Controller,\r
566 Image,\r
567 &gEfiDhcp4ServiceBindingProtocolGuid,\r
568 Dhcp4Handle\r
569 );\r
570\r
571 return Status;\r
572}\r