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