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