]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/IScsiDxe/IScsiDhcp.c
1)update function header coding style issue
[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
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
187IScsiDhcpSelectOffer (\r
188 IN EFI_DHCP4_PROTOCOL * This,\r
189 IN VOID *Context,\r
190 IN EFI_DHCP4_STATE CurrentState,\r
191 IN EFI_DHCP4_EVENT Dhcp4Event,\r
192 IN EFI_DHCP4_PACKET * Packet, OPTIONAL\r
193 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL\r
194 )\r
6a690e23 195{\r
196 EFI_STATUS Status;\r
197 UINT32 OptionCount;\r
198 EFI_DHCP4_PACKET_OPTION **OptionList;\r
199 UINT32 Index;\r
200\r
201 if ((Dhcp4Event != Dhcp4RcvdOffer) && (Dhcp4Event != Dhcp4SelectOffer)) {\r
202 return EFI_SUCCESS;\r
203 }\r
204\r
205 OptionCount = 0;\r
206\r
207 Status = This->Parse (This, Packet, &OptionCount, NULL);\r
208 if (Status != EFI_BUFFER_TOO_SMALL) {\r
69b0882d 209 return EFI_NOT_READY;\r
6a690e23 210 }\r
93e3992d 211\r
e48e37fc 212 OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
6a690e23 213 if (OptionList == NULL) {\r
214 return EFI_NOT_READY;\r
215 }\r
216\r
217 Status = This->Parse (This, Packet, &OptionCount, OptionList);\r
218 if (EFI_ERROR (Status)) {\r
e48e37fc 219 gBS->FreePool (OptionList);\r
6a690e23 220 return EFI_NOT_READY;\r
221 }\r
222\r
223 for (Index = 0; Index < OptionCount; Index++) {\r
224 if (OptionList[Index]->OpCode != DHCP4_TAG_ROOT_PATH) {\r
225 continue;\r
226 }\r
227\r
228 Status = IScsiDhcpExtractRootPath (\r
229 (CHAR8 *) &OptionList[Index]->Data[0],\r
230 OptionList[Index]->Length,\r
231 (ISCSI_SESSION_CONFIG_NVDATA *) Context\r
232 );\r
233\r
234 break;\r
235 }\r
236\r
237 if ((Index == OptionCount)) {\r
238 Status = EFI_NOT_READY;\r
239 }\r
240\r
e48e37fc 241 gBS->FreePool (OptionList);\r
6a690e23 242\r
243 return Status;\r
244}\r
245\r
12618416 246/**\r
247 Parse the DHCP ACK to get the address configuration and DNS information.\r
6a690e23 248\r
8e29a125 249 @param[in] Dhcp4 The DHCP4 protocol.\r
250 @param[in] ConfigData The session configuration data.\r
6a690e23 251\r
12618416 252 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.\r
12618416 253 @retval EFI_NO_MAPPING DHCP failed to acquire address and other information.\r
12618416 254 @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is mal-formatted.\r
963dbb30 255 @retval EFI_DEVICE_ERROR Other errors as indicated.\r
12618416 256**/\r
257EFI_STATUS\r
258IScsiParseDhcpAck (\r
259 IN EFI_DHCP4_PROTOCOL *Dhcp4,\r
260 IN ISCSI_SESSION_CONFIG_DATA *ConfigData\r
261 )\r
6a690e23 262{\r
263 EFI_STATUS Status;\r
264 EFI_DHCP4_MODE_DATA Dhcp4ModeData;\r
265 UINT32 OptionCount;\r
266 EFI_DHCP4_PACKET_OPTION **OptionList;\r
267 UINT32 Index;\r
268\r
269 Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4ModeData);\r
270 if (EFI_ERROR (Status)) {\r
271 return Status;\r
272 }\r
273\r
274 if (Dhcp4ModeData.State != Dhcp4Bound) {\r
275 return EFI_NO_MAPPING;\r
276 }\r
277\r
e48e37fc 278 CopyMem (&ConfigData->NvData.LocalIp, &Dhcp4ModeData.ClientAddress, sizeof (EFI_IPv4_ADDRESS));\r
279 CopyMem (&ConfigData->NvData.SubnetMask, &Dhcp4ModeData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
280 CopyMem (&ConfigData->NvData.Gateway, &Dhcp4ModeData.RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
6a690e23 281\r
282 OptionCount = 0;\r
283 OptionList = NULL;\r
284\r
285 Status = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);\r
286 if (Status != EFI_BUFFER_TOO_SMALL) {\r
287 return EFI_DEVICE_ERROR;\r
288 }\r
289\r
e48e37fc 290 OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
6a690e23 291 if (OptionList == NULL) {\r
292 return EFI_OUT_OF_RESOURCES;\r
293 }\r
294\r
295 Status = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);\r
296 if (EFI_ERROR (Status)) {\r
e48e37fc 297 gBS->FreePool (OptionList);\r
6a690e23 298 return EFI_DEVICE_ERROR;\r
299 }\r
300\r
301 for (Index = 0; Index < OptionCount; Index++) {\r
302 //\r
303 // Get DNS server addresses and DHCP server address from this offer.\r
304 //\r
305 if (OptionList[Index]->OpCode == DHCP4_TAG_DNS) {\r
306\r
307 if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {\r
308 Status = EFI_INVALID_PARAMETER;\r
309 break;\r
310 }\r
311 //\r
312 // Primary DNS server address.\r
313 //\r
e48e37fc 314 CopyMem (&ConfigData->PrimaryDns, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));\r
6a690e23 315\r
316 if (OptionList[Index]->Length > 4) {\r
317 //\r
318 // Secondary DNS server address\r
319 //\r
e48e37fc 320 CopyMem (&ConfigData->SecondaryDns, &OptionList[Index]->Data[4], sizeof (EFI_IPv4_ADDRESS));\r
6a690e23 321 }\r
322 } else if (OptionList[Index]->OpCode == DHCP4_TAG_SERVER_ID) {\r
323 if (OptionList[Index]->Length != 4) {\r
324 Status = EFI_INVALID_PARAMETER;\r
325 break;\r
326 }\r
327\r
e48e37fc 328 CopyMem (&ConfigData->DhcpServer, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));\r
6a690e23 329 }\r
330 }\r
331\r
e48e37fc 332 gBS->FreePool (OptionList);\r
6a690e23 333\r
334 return Status;\r
335}\r
336\r
12618416 337/**\r
6a690e23 338 Parse the DHCP ACK to get the address configuration and DNS information.\r
339 \r
8e29a125 340 @param[in] Image The handle of the driver image.\r
341 @param[in] Controller The handle of the controller;\r
342 @param[in] ConfigData The session configuration data.\r
6a690e23 343\r
12618416 344 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.\r
8e29a125 345 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
963dbb30 346 @retval Others Other errors as indicated.\r
12618416 347**/\r
348EFI_STATUS\r
349IScsiDoDhcp (\r
350 IN EFI_HANDLE Image,\r
351 IN EFI_HANDLE Controller,\r
352 IN ISCSI_SESSION_CONFIG_DATA *ConfigData\r
353 )\r
6a690e23 354{\r
355 EFI_HANDLE Dhcp4Handle;\r
356 EFI_DHCP4_PROTOCOL *Dhcp4;\r
357 EFI_STATUS Status;\r
358 EFI_DHCP4_PACKET_OPTION *ParaList;\r
359 EFI_DHCP4_CONFIG_DATA Dhcp4ConfigData;\r
360\r
361 Dhcp4Handle = NULL;\r
362 Dhcp4 = NULL;\r
363 ParaList = NULL;\r
364\r
365 //\r
366 // Create a DHCP4 child instance and get the protocol.\r
367 //\r
368 Status = NetLibCreateServiceChild (\r
369 Controller,\r
370 Image,\r
371 &gEfiDhcp4ServiceBindingProtocolGuid,\r
372 &Dhcp4Handle\r
373 );\r
374 if (EFI_ERROR (Status)) {\r
375 return Status;\r
376 }\r
377\r
378 Status = gBS->OpenProtocol (\r
379 Dhcp4Handle,\r
380 &gEfiDhcp4ProtocolGuid,\r
381 (VOID **)&Dhcp4,\r
382 Image,\r
383 Controller,\r
384 EFI_OPEN_PROTOCOL_BY_DRIVER\r
385 );\r
386 if (EFI_ERROR (Status)) {\r
387 goto ON_EXIT;\r
388 }\r
389\r
e48e37fc 390 ParaList = AllocatePool (sizeof (EFI_DHCP4_PACKET_OPTION) + 3);\r
6a690e23 391 if (ParaList == NULL) {\r
392 Status = EFI_OUT_OF_RESOURCES;\r
393 goto ON_EXIT;\r
394 }\r
395 //\r
396 // Ask the server to reply with Netmask, Router, DNS and RootPath options.\r
397 //\r
398 ParaList->OpCode = DHCP4_TAG_PARA_LIST;\r
69b0882d 399 ParaList->Length = (UINT8) (ConfigData->NvData.TargetInfoFromDhcp ? 4 : 3);\r
6a690e23 400 ParaList->Data[0] = DHCP4_TAG_NETMASK;\r
401 ParaList->Data[1] = DHCP4_TAG_ROUTER;\r
402 ParaList->Data[2] = DHCP4_TAG_DNS;\r
403 ParaList->Data[3] = DHCP4_TAG_ROOT_PATH;\r
404\r
e48e37fc 405 ZeroMem (&Dhcp4ConfigData, sizeof (EFI_DHCP4_CONFIG_DATA));\r
6a690e23 406 Dhcp4ConfigData.OptionCount = 1;\r
407 Dhcp4ConfigData.OptionList = &ParaList;\r
408\r
409 if (ConfigData->NvData.TargetInfoFromDhcp) {\r
410 //\r
411 // Use callback to select an offer which contains target information.\r
412 //\r
413 Dhcp4ConfigData.Dhcp4Callback = IScsiDhcpSelectOffer;\r
414 Dhcp4ConfigData.CallbackContext = &ConfigData->NvData;\r
415 }\r
416\r
417 Status = Dhcp4->Configure (Dhcp4, &Dhcp4ConfigData);\r
418 if (EFI_ERROR (Status)) {\r
419 goto ON_EXIT;\r
420 }\r
421\r
422 Status = Dhcp4->Start (Dhcp4, NULL);\r
423 if (EFI_ERROR (Status)) {\r
424 goto ON_EXIT;\r
425 }\r
426 //\r
427 // Parse the ACK to get required information.\r
428 //\r
429 Status = IScsiParseDhcpAck (Dhcp4, ConfigData);\r
430\r
431ON_EXIT:\r
432\r
433 if (ParaList != NULL) {\r
e48e37fc 434 gBS->FreePool (ParaList);\r
6a690e23 435 }\r
436\r
437 if (Dhcp4 != NULL) {\r
438 Dhcp4->Stop (Dhcp4);\r
439 Dhcp4->Configure (Dhcp4, NULL);\r
440\r
441 gBS->CloseProtocol (\r
442 Dhcp4Handle,\r
443 &gEfiDhcp4ProtocolGuid,\r
444 Image,\r
445 Controller\r
446 );\r
447 }\r
448\r
449 NetLibDestroyServiceChild (\r
450 Controller,\r
451 Image,\r
452 &gEfiDhcp4ServiceBindingProtocolGuid,\r
453 Dhcp4Handle\r
454 );\r
455\r
456 return Status;\r
457}\r