]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/IScsiDxe/IScsiDhcp.c
MdeModulePkg: Replace unsafe string functions.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / IScsiDxe / IScsiDhcp.c
CommitLineData
8e29a125 1/** @file\r
55a64ae0 2 iSCSI DHCP related configuration routines.\r
6a690e23 3\r
206b5f51 4Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 5This program and the accompanying materials\r
7a444476 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
6a690e23 12\r
12618416 13**/\r
6a690e23 14\r
15#include "IScsiImpl.h"\r
16\r
12618416 17/**\r
18 Extract the Root Path option and get the required target information.\r
19\r
c5de0d55 20 @param[in] RootPath The RootPath.\r
21 @param[in] Length Length of the RootPath option payload.\r
22 @param[in, out] ConfigNvData The iSCSI session configuration data read from nonvolatile device.\r
12618416 23\r
24 @retval EFI_SUCCESS All required information is extracted from the RootPath option.\r
12618416 25 @retval EFI_NOT_FOUND The RootPath is not an iSCSI RootPath.\r
12618416 26 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
12618416 27 @retval EFI_INVALID_PARAMETER The RootPath is mal-formatted.\r
12618416 28**/\r
6a690e23 29EFI_STATUS\r
30IScsiDhcpExtractRootPath (\r
c5de0d55 31 IN CHAR8 *RootPath,\r
32 IN UINT8 Length,\r
33 IN OUT ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData\r
6a690e23 34 )\r
6a690e23 35{\r
36 EFI_STATUS Status;\r
37 UINT8 IScsiRootPathIdLen;\r
38 CHAR8 *TmpStr;\r
39 ISCSI_ROOT_PATH_FIELD Fields[RP_FIELD_IDX_MAX];\r
40 ISCSI_ROOT_PATH_FIELD *Field;\r
f6b7393c 41 UINT32 FieldIndex;\r
6a690e23 42 UINT8 Index;\r
43\r
44 //\r
45 // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>\r
46 //\r
47 IScsiRootPathIdLen = (UINT8) AsciiStrLen (ISCSI_ROOT_PATH_ID);\r
48\r
e48e37fc 49 if ((Length <= IScsiRootPathIdLen) || (CompareMem (RootPath, ISCSI_ROOT_PATH_ID, IScsiRootPathIdLen) != 0)) {\r
6a690e23 50 return EFI_NOT_FOUND;\r
51 }\r
52 //\r
53 // Skip the iSCSI RootPath ID "iscsi:".\r
54 //\r
55 RootPath += IScsiRootPathIdLen;\r
56 Length = (UINT8) (Length - IScsiRootPathIdLen);\r
57\r
e48e37fc 58 TmpStr = (CHAR8 *) AllocatePool (Length + 1);\r
6a690e23 59 if (TmpStr == NULL) {\r
60 return EFI_OUT_OF_RESOURCES;\r
61 }\r
62\r
e48e37fc 63 CopyMem (TmpStr, RootPath, Length);\r
6a690e23 64 TmpStr[Length] = '\0';\r
65\r
66 Index = 0;\r
8e29a125 67 FieldIndex = RP_FIELD_IDX_SERVERNAME;\r
e48e37fc 68 ZeroMem (&Fields[0], sizeof (Fields));\r
6a690e23 69\r
70 //\r
71 // Extract the fields in the Root Path option string.\r
72 //\r
8e29a125 73 for (FieldIndex = RP_FIELD_IDX_SERVERNAME; (FieldIndex < RP_FIELD_IDX_MAX) && (Index < Length); FieldIndex++) {\r
6a690e23 74 if (TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) {\r
75 Fields[FieldIndex].Str = &TmpStr[Index];\r
76 }\r
77\r
78 while ((TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) && (Index < Length)) {\r
79 Index++;\r
80 }\r
81\r
82 if (TmpStr[Index] == ISCSI_ROOT_PATH_FIELD_DELIMITER) {\r
83 if (FieldIndex != RP_FIELD_IDX_TARGETNAME) {\r
84 TmpStr[Index] = '\0';\r
85 Index++;\r
86 }\r
87\r
88 if (Fields[FieldIndex].Str != NULL) {\r
89 Fields[FieldIndex].Len = (UINT8) AsciiStrLen (Fields[FieldIndex].Str);\r
90 }\r
91 }\r
92 }\r
93\r
94 if (FieldIndex != RP_FIELD_IDX_MAX) {\r
95 Status = EFI_INVALID_PARAMETER;\r
96 goto ON_EXIT;\r
97 }\r
8e29a125 98 \r
963dbb30 99 if ((Fields[RP_FIELD_IDX_SERVERNAME].Str == NULL) ||\r
100 (Fields[RP_FIELD_IDX_TARGETNAME].Str == NULL) ||\r
101 (Fields[RP_FIELD_IDX_PROTOCOL].Len > 1)\r
102 ) {\r
103\r
6a690e23 104 Status = EFI_INVALID_PARAMETER;\r
105 goto ON_EXIT;\r
106 }\r
107 //\r
108 // Get the IP address of the target.\r
109 //\r
963dbb30 110 Field = &Fields[RP_FIELD_IDX_SERVERNAME];\r
6a690e23 111 Status = IScsiAsciiStrToIp (Field->Str, &ConfigNvData->TargetIp);\r
112 if (EFI_ERROR (Status)) {\r
113 goto ON_EXIT;\r
114 }\r
115 //\r
116 // Check the protocol type.\r
117 //\r
963dbb30 118 Field = &Fields[RP_FIELD_IDX_PROTOCOL];\r
6a690e23 119 if ((Field->Str != NULL) && ((*(Field->Str) - '0') != EFI_IP_PROTO_TCP)) {\r
120 Status = EFI_INVALID_PARAMETER;\r
121 goto ON_EXIT;\r
122 }\r
123 //\r
124 // Get the port of the iSCSI target.\r
125 //\r
963dbb30 126 Field = &Fields[RP_FIELD_IDX_PORT];\r
6a690e23 127 if (Field->Str != NULL) {\r
128 ConfigNvData->TargetPort = (UINT16) AsciiStrDecimalToUintn (Field->Str);\r
129 } else {\r
130 ConfigNvData->TargetPort = ISCSI_WELL_KNOWN_PORT;\r
131 }\r
132 //\r
133 // Get the LUN.\r
134 //\r
963dbb30 135 Field = &Fields[RP_FIELD_IDX_LUN];\r
6a690e23 136 if (Field->Str != NULL) {\r
137 Status = IScsiAsciiStrToLun (Field->Str, ConfigNvData->BootLun);\r
138 if (EFI_ERROR (Status)) {\r
139 goto ON_EXIT;\r
140 }\r
141 } else {\r
e48e37fc 142 ZeroMem (ConfigNvData->BootLun, sizeof (ConfigNvData->BootLun));\r
6a690e23 143 }\r
144 //\r
145 // Get the target iSCSI Name.\r
146 //\r
963dbb30 147 Field = &Fields[RP_FIELD_IDX_TARGETNAME];\r
148\r
6a690e23 149 if (AsciiStrLen (Field->Str) > ISCSI_NAME_MAX_SIZE - 1) {\r
150 Status = EFI_INVALID_PARAMETER;\r
151 goto ON_EXIT;\r
152 }\r
153 //\r
154 // Validate the iSCSI name.\r
155 //\r
156 Status = IScsiNormalizeName (Field->Str, AsciiStrLen (Field->Str));\r
157 if (EFI_ERROR (Status)) {\r
158 goto ON_EXIT;\r
159 }\r
160\r
206b5f51 161 AsciiStrCpyS (ConfigNvData->TargetName, ISCSI_NAME_MAX_SIZE, Field->Str);\r
6a690e23 162\r
163ON_EXIT:\r
164\r
766c7483 165 FreePool (TmpStr);\r
6a690e23 166\r
167 return Status;\r
168}\r
169\r
12618416 170/**\r
171 The callback function registerd to the DHCP4 instance which is used to select\r
172 the qualified DHCP OFFER.\r
173 \r
8e29a125 174 @param[in] This The DHCP4 protocol.\r
175 @param[in] Context The context set when configuring the DHCP4 protocol.\r
176 @param[in] CurrentState The current state of the DHCP4 protocol.\r
177 @param[in] Dhcp4Event The event occurs in the current state.\r
178 @param[in] Packet The DHCP packet that is to be sent or already received. \r
179 @param[out] NewPacket The packet used to replace the above Packet.\r
180 \r
12618416 181 @retval EFI_SUCCESS Either the DHCP OFFER is qualified or we're not intereseted\r
182 in the Dhcp4Event.\r
8e29a125 183 @retval EFI_NOT_READY The DHCP OFFER packet doesn't match our requirements.\r
963dbb30 184 @retval Others Other errors as indicated.\r
12618416 185**/\r
6a690e23 186EFI_STATUS\r
6d3ea23f 187EFIAPI\r
6a690e23 188IScsiDhcpSelectOffer (\r
189 IN EFI_DHCP4_PROTOCOL * This,\r
190 IN VOID *Context,\r
191 IN EFI_DHCP4_STATE CurrentState,\r
192 IN EFI_DHCP4_EVENT Dhcp4Event,\r
193 IN EFI_DHCP4_PACKET * Packet, OPTIONAL\r
194 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL\r
195 )\r
6a690e23 196{\r
197 EFI_STATUS Status;\r
198 UINT32 OptionCount;\r
199 EFI_DHCP4_PACKET_OPTION **OptionList;\r
200 UINT32 Index;\r
201\r
202 if ((Dhcp4Event != Dhcp4RcvdOffer) && (Dhcp4Event != Dhcp4SelectOffer)) {\r
203 return EFI_SUCCESS;\r
204 }\r
205\r
206 OptionCount = 0;\r
207\r
208 Status = This->Parse (This, Packet, &OptionCount, NULL);\r
209 if (Status != EFI_BUFFER_TOO_SMALL) {\r
69b0882d 210 return EFI_NOT_READY;\r
6a690e23 211 }\r
93e3992d 212\r
e48e37fc 213 OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
6a690e23 214 if (OptionList == NULL) {\r
215 return EFI_NOT_READY;\r
216 }\r
217\r
218 Status = This->Parse (This, Packet, &OptionCount, OptionList);\r
219 if (EFI_ERROR (Status)) {\r
766c7483 220 FreePool (OptionList);\r
6a690e23 221 return EFI_NOT_READY;\r
222 }\r
223\r
224 for (Index = 0; Index < OptionCount; Index++) {\r
225 if (OptionList[Index]->OpCode != DHCP4_TAG_ROOT_PATH) {\r
226 continue;\r
227 }\r
228\r
229 Status = IScsiDhcpExtractRootPath (\r
230 (CHAR8 *) &OptionList[Index]->Data[0],\r
231 OptionList[Index]->Length,\r
232 (ISCSI_SESSION_CONFIG_NVDATA *) Context\r
233 );\r
234\r
235 break;\r
236 }\r
237\r
63e78d52 238 if (Index == OptionCount) {\r
6a690e23 239 Status = EFI_NOT_READY;\r
240 }\r
241\r
766c7483 242 FreePool (OptionList);\r
6a690e23 243\r
244 return Status;\r
245}\r
246\r
12618416 247/**\r
248 Parse the DHCP ACK to get the address configuration and DNS information.\r
6a690e23 249\r
c5de0d55 250 @param[in] Dhcp4 The DHCP4 protocol.\r
251 @param[in, out] ConfigData The session configuration data.\r
6a690e23 252\r
12618416 253 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.\r
12618416 254 @retval EFI_NO_MAPPING DHCP failed to acquire address and other information.\r
12618416 255 @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is mal-formatted.\r
963dbb30 256 @retval EFI_DEVICE_ERROR Other errors as indicated.\r
12618416 257**/\r
258EFI_STATUS\r
259IScsiParseDhcpAck (\r
c5de0d55 260 IN EFI_DHCP4_PROTOCOL *Dhcp4,\r
261 IN OUT ISCSI_SESSION_CONFIG_DATA *ConfigData\r
12618416 262 )\r
6a690e23 263{\r
264 EFI_STATUS Status;\r
265 EFI_DHCP4_MODE_DATA Dhcp4ModeData;\r
266 UINT32 OptionCount;\r
267 EFI_DHCP4_PACKET_OPTION **OptionList;\r
268 UINT32 Index;\r
269\r
270 Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4ModeData);\r
271 if (EFI_ERROR (Status)) {\r
272 return Status;\r
273 }\r
274\r
275 if (Dhcp4ModeData.State != Dhcp4Bound) {\r
276 return EFI_NO_MAPPING;\r
277 }\r
278\r
e48e37fc 279 CopyMem (&ConfigData->NvData.LocalIp, &Dhcp4ModeData.ClientAddress, sizeof (EFI_IPv4_ADDRESS));\r
280 CopyMem (&ConfigData->NvData.SubnetMask, &Dhcp4ModeData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
281 CopyMem (&ConfigData->NvData.Gateway, &Dhcp4ModeData.RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
6a690e23 282\r
283 OptionCount = 0;\r
284 OptionList = NULL;\r
285\r
286 Status = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);\r
287 if (Status != EFI_BUFFER_TOO_SMALL) {\r
288 return EFI_DEVICE_ERROR;\r
289 }\r
290\r
e48e37fc 291 OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
6a690e23 292 if (OptionList == NULL) {\r
293 return EFI_OUT_OF_RESOURCES;\r
294 }\r
295\r
296 Status = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);\r
297 if (EFI_ERROR (Status)) {\r
766c7483 298 FreePool (OptionList);\r
6a690e23 299 return EFI_DEVICE_ERROR;\r
300 }\r
301\r
302 for (Index = 0; Index < OptionCount; Index++) {\r
303 //\r
304 // Get DNS server addresses and DHCP server address from this offer.\r
305 //\r
306 if (OptionList[Index]->OpCode == DHCP4_TAG_DNS) {\r
307\r
308 if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {\r
309 Status = EFI_INVALID_PARAMETER;\r
310 break;\r
311 }\r
312 //\r
313 // Primary DNS server address.\r
314 //\r
e48e37fc 315 CopyMem (&ConfigData->PrimaryDns, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));\r
6a690e23 316\r
317 if (OptionList[Index]->Length > 4) {\r
318 //\r
319 // Secondary DNS server address\r
320 //\r
e48e37fc 321 CopyMem (&ConfigData->SecondaryDns, &OptionList[Index]->Data[4], sizeof (EFI_IPv4_ADDRESS));\r
6a690e23 322 }\r
323 } else if (OptionList[Index]->OpCode == DHCP4_TAG_SERVER_ID) {\r
324 if (OptionList[Index]->Length != 4) {\r
325 Status = EFI_INVALID_PARAMETER;\r
326 break;\r
327 }\r
328\r
e48e37fc 329 CopyMem (&ConfigData->DhcpServer, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));\r
6a690e23 330 }\r
331 }\r
332\r
766c7483 333 FreePool (OptionList);\r
6a690e23 334\r
335 return Status;\r
336}\r
337\r
12618416 338/**\r
6a690e23 339 Parse the DHCP ACK to get the address configuration and DNS information.\r
340 \r
c5de0d55 341 @param[in] Image The handle of the driver image.\r
342 @param[in] Controller The handle of the controller;\r
343 @param[in, out] ConfigData The session configuration data.\r
6a690e23 344\r
12618416 345 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.\r
8e29a125 346 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
dd29f3ed 347 @retval EFI_NO_MEDIA There was a media error.\r
963dbb30 348 @retval Others Other errors as indicated.\r
dd29f3ed 349\r
12618416 350**/\r
351EFI_STATUS\r
352IScsiDoDhcp (\r
c5de0d55 353 IN EFI_HANDLE Image,\r
354 IN EFI_HANDLE Controller,\r
355 IN OUT ISCSI_SESSION_CONFIG_DATA *ConfigData\r
12618416 356 )\r
6a690e23 357{\r
358 EFI_HANDLE Dhcp4Handle;\r
359 EFI_DHCP4_PROTOCOL *Dhcp4;\r
360 EFI_STATUS Status;\r
361 EFI_DHCP4_PACKET_OPTION *ParaList;\r
362 EFI_DHCP4_CONFIG_DATA Dhcp4ConfigData;\r
dd29f3ed 363 BOOLEAN MediaPresent;\r
63e78d52 364 UINT8 *Data;\r
6a690e23 365\r
366 Dhcp4Handle = NULL;\r
367 Dhcp4 = NULL;\r
368 ParaList = NULL;\r
369\r
dd29f3ed 370 //\r
371 // Check media status before do DHCP\r
372 //\r
373 MediaPresent = TRUE;\r
374 NetLibDetectMedia (Controller, &MediaPresent);\r
375 if (!MediaPresent) {\r
376 return EFI_NO_MEDIA;\r
377 }\r
378\r
6a690e23 379 //\r
380 // Create a DHCP4 child instance and get the protocol.\r
381 //\r
382 Status = NetLibCreateServiceChild (\r
383 Controller,\r
384 Image,\r
385 &gEfiDhcp4ServiceBindingProtocolGuid,\r
386 &Dhcp4Handle\r
387 );\r
388 if (EFI_ERROR (Status)) {\r
389 return Status;\r
390 }\r
391\r
392 Status = gBS->OpenProtocol (\r
393 Dhcp4Handle,\r
394 &gEfiDhcp4ProtocolGuid,\r
395 (VOID **)&Dhcp4,\r
396 Image,\r
397 Controller,\r
398 EFI_OPEN_PROTOCOL_BY_DRIVER\r
399 );\r
400 if (EFI_ERROR (Status)) {\r
401 goto ON_EXIT;\r
402 }\r
403\r
e48e37fc 404 ParaList = AllocatePool (sizeof (EFI_DHCP4_PACKET_OPTION) + 3);\r
6a690e23 405 if (ParaList == NULL) {\r
406 Status = EFI_OUT_OF_RESOURCES;\r
407 goto ON_EXIT;\r
408 }\r
409 //\r
410 // Ask the server to reply with Netmask, Router, DNS and RootPath options.\r
411 //\r
412 ParaList->OpCode = DHCP4_TAG_PARA_LIST;\r
69b0882d 413 ParaList->Length = (UINT8) (ConfigData->NvData.TargetInfoFromDhcp ? 4 : 3);\r
63e78d52 414 Data = &ParaList->Data[0];\r
415 Data[0] = DHCP4_TAG_NETMASK;\r
416 Data[1] = DHCP4_TAG_ROUTER;\r
417 Data[2] = DHCP4_TAG_DNS;\r
418 Data[3] = DHCP4_TAG_ROOT_PATH;\r
6a690e23 419\r
e48e37fc 420 ZeroMem (&Dhcp4ConfigData, sizeof (EFI_DHCP4_CONFIG_DATA));\r
6a690e23 421 Dhcp4ConfigData.OptionCount = 1;\r
422 Dhcp4ConfigData.OptionList = &ParaList;\r
423\r
424 if (ConfigData->NvData.TargetInfoFromDhcp) {\r
425 //\r
426 // Use callback to select an offer which contains target information.\r
427 //\r
428 Dhcp4ConfigData.Dhcp4Callback = IScsiDhcpSelectOffer;\r
429 Dhcp4ConfigData.CallbackContext = &ConfigData->NvData;\r
430 }\r
431\r
432 Status = Dhcp4->Configure (Dhcp4, &Dhcp4ConfigData);\r
433 if (EFI_ERROR (Status)) {\r
434 goto ON_EXIT;\r
435 }\r
436\r
437 Status = Dhcp4->Start (Dhcp4, NULL);\r
438 if (EFI_ERROR (Status)) {\r
439 goto ON_EXIT;\r
440 }\r
441 //\r
442 // Parse the ACK to get required information.\r
443 //\r
444 Status = IScsiParseDhcpAck (Dhcp4, ConfigData);\r
445\r
446ON_EXIT:\r
447\r
448 if (ParaList != NULL) {\r
766c7483 449 FreePool (ParaList);\r
6a690e23 450 }\r
451\r
452 if (Dhcp4 != NULL) {\r
453 Dhcp4->Stop (Dhcp4);\r
454 Dhcp4->Configure (Dhcp4, NULL);\r
455\r
456 gBS->CloseProtocol (\r
457 Dhcp4Handle,\r
458 &gEfiDhcp4ProtocolGuid,\r
459 Image,\r
460 Controller\r
461 );\r
462 }\r
463\r
464 NetLibDestroyServiceChild (\r
465 Controller,\r
466 Image,\r
467 &gEfiDhcp4ServiceBindingProtocolGuid,\r
468 Dhcp4Handle\r
469 );\r
470\r
471 return Status;\r
472}\r