]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/IScsiDxe/IScsiDhcp.c
Fix various 'EFIAPI' inconsistencies found while building MdeModulePkg.
[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
6d3ea23f 4Copyright (c) 2004 - 2007, 2009, Intel Corporation.<BR>\r
7a444476 5All rights reserved. This 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
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
8e29a125 41 RP_FIELD_IDX 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
161 AsciiStrCpy (ConfigNvData->TargetName, Field->Str);\r
162\r
163ON_EXIT:\r
164\r
e48e37fc 165 gBS->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
e48e37fc 220 gBS->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
238 if ((Index == OptionCount)) {\r
239 Status = EFI_NOT_READY;\r
240 }\r
241\r
e48e37fc 242 gBS->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
e48e37fc 298 gBS->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
e48e37fc 333 gBS->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
963dbb30 347 @retval Others Other errors as indicated.\r
12618416 348**/\r
349EFI_STATUS\r
350IScsiDoDhcp (\r
c5de0d55 351 IN EFI_HANDLE Image,\r
352 IN EFI_HANDLE Controller,\r
353 IN OUT ISCSI_SESSION_CONFIG_DATA *ConfigData\r
12618416 354 )\r
6a690e23 355{\r
356 EFI_HANDLE Dhcp4Handle;\r
357 EFI_DHCP4_PROTOCOL *Dhcp4;\r
358 EFI_STATUS Status;\r
359 EFI_DHCP4_PACKET_OPTION *ParaList;\r
360 EFI_DHCP4_CONFIG_DATA Dhcp4ConfigData;\r
361\r
362 Dhcp4Handle = NULL;\r
363 Dhcp4 = NULL;\r
364 ParaList = NULL;\r
365\r
366 //\r
367 // Create a DHCP4 child instance and get the protocol.\r
368 //\r
369 Status = NetLibCreateServiceChild (\r
370 Controller,\r
371 Image,\r
372 &gEfiDhcp4ServiceBindingProtocolGuid,\r
373 &Dhcp4Handle\r
374 );\r
375 if (EFI_ERROR (Status)) {\r
376 return Status;\r
377 }\r
378\r
379 Status = gBS->OpenProtocol (\r
380 Dhcp4Handle,\r
381 &gEfiDhcp4ProtocolGuid,\r
382 (VOID **)&Dhcp4,\r
383 Image,\r
384 Controller,\r
385 EFI_OPEN_PROTOCOL_BY_DRIVER\r
386 );\r
387 if (EFI_ERROR (Status)) {\r
388 goto ON_EXIT;\r
389 }\r
390\r
e48e37fc 391 ParaList = AllocatePool (sizeof (EFI_DHCP4_PACKET_OPTION) + 3);\r
6a690e23 392 if (ParaList == NULL) {\r
393 Status = EFI_OUT_OF_RESOURCES;\r
394 goto ON_EXIT;\r
395 }\r
396 //\r
397 // Ask the server to reply with Netmask, Router, DNS and RootPath options.\r
398 //\r
399 ParaList->OpCode = DHCP4_TAG_PARA_LIST;\r
69b0882d 400 ParaList->Length = (UINT8) (ConfigData->NvData.TargetInfoFromDhcp ? 4 : 3);\r
6a690e23 401 ParaList->Data[0] = DHCP4_TAG_NETMASK;\r
402 ParaList->Data[1] = DHCP4_TAG_ROUTER;\r
403 ParaList->Data[2] = DHCP4_TAG_DNS;\r
404 ParaList->Data[3] = DHCP4_TAG_ROOT_PATH;\r
405\r
e48e37fc 406 ZeroMem (&Dhcp4ConfigData, sizeof (EFI_DHCP4_CONFIG_DATA));\r
6a690e23 407 Dhcp4ConfigData.OptionCount = 1;\r
408 Dhcp4ConfigData.OptionList = &ParaList;\r
409\r
410 if (ConfigData->NvData.TargetInfoFromDhcp) {\r
411 //\r
412 // Use callback to select an offer which contains target information.\r
413 //\r
414 Dhcp4ConfigData.Dhcp4Callback = IScsiDhcpSelectOffer;\r
415 Dhcp4ConfigData.CallbackContext = &ConfigData->NvData;\r
416 }\r
417\r
418 Status = Dhcp4->Configure (Dhcp4, &Dhcp4ConfigData);\r
419 if (EFI_ERROR (Status)) {\r
420 goto ON_EXIT;\r
421 }\r
422\r
423 Status = Dhcp4->Start (Dhcp4, NULL);\r
424 if (EFI_ERROR (Status)) {\r
425 goto ON_EXIT;\r
426 }\r
427 //\r
428 // Parse the ACK to get required information.\r
429 //\r
430 Status = IScsiParseDhcpAck (Dhcp4, ConfigData);\r
431\r
432ON_EXIT:\r
433\r
434 if (ParaList != NULL) {\r
e48e37fc 435 gBS->FreePool (ParaList);\r
6a690e23 436 }\r
437\r
438 if (Dhcp4 != NULL) {\r
439 Dhcp4->Stop (Dhcp4);\r
440 Dhcp4->Configure (Dhcp4, NULL);\r
441\r
442 gBS->CloseProtocol (\r
443 Dhcp4Handle,\r
444 &gEfiDhcp4ProtocolGuid,\r
445 Image,\r
446 Controller\r
447 );\r
448 }\r
449\r
450 NetLibDestroyServiceChild (\r
451 Controller,\r
452 Image,\r
453 &gEfiDhcp4ServiceBindingProtocolGuid,\r
454 Dhcp4Handle\r
455 );\r
456\r
457 return Status;\r
458}\r