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