VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/NetworkPkg/IScsiDxe/IScsiDhcp.c@ 70372

最後變更 在這個檔案從70372是 58466,由 vboxsync 提交於 9 年 前

EFI/Firmware: Merged in the svn:eol-style, svn:mime-type and trailing whitespace cleanup that was done after the initial UDK2014.SP1 import: svn merge /vendor/edk2/UDK2014.SP1 /vendor/edk2/current .

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette