2 iSCSI DHCP related configuration routines.
4 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "IScsiImpl.h"
18 Extract the Root Path option and get the required target information.
20 @param[in] RootPath The RootPath.
21 @param[in] Length Length of the RootPath option payload.
22 @param[in, out] ConfigNvData The iSCSI session configuration data read from nonvolatile device.
24 @retval EFI_SUCCESS All required information is extracted from the RootPath option.
25 @retval EFI_NOT_FOUND The RootPath is not an iSCSI RootPath.
26 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
27 @retval EFI_INVALID_PARAMETER The RootPath is mal-formatted.
30 IScsiDhcpExtractRootPath (
33 IN OUT ISCSI_SESSION_CONFIG_NVDATA
*ConfigNvData
37 UINT8 IScsiRootPathIdLen
;
39 ISCSI_ROOT_PATH_FIELD Fields
[RP_FIELD_IDX_MAX
];
40 ISCSI_ROOT_PATH_FIELD
*Field
;
45 // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>
47 IScsiRootPathIdLen
= (UINT8
) AsciiStrLen (ISCSI_ROOT_PATH_ID
);
49 if ((Length
<= IScsiRootPathIdLen
) || (CompareMem (RootPath
, ISCSI_ROOT_PATH_ID
, IScsiRootPathIdLen
) != 0)) {
53 // Skip the iSCSI RootPath ID "iscsi:".
55 RootPath
+= IScsiRootPathIdLen
;
56 Length
= (UINT8
) (Length
- IScsiRootPathIdLen
);
58 TmpStr
= (CHAR8
*) AllocatePool (Length
+ 1);
60 return EFI_OUT_OF_RESOURCES
;
63 CopyMem (TmpStr
, RootPath
, Length
);
64 TmpStr
[Length
] = '\0';
67 FieldIndex
= RP_FIELD_IDX_SERVERNAME
;
68 ZeroMem (&Fields
[0], sizeof (Fields
));
71 // Extract the fields in the Root Path option string.
73 for (FieldIndex
= RP_FIELD_IDX_SERVERNAME
; (FieldIndex
< RP_FIELD_IDX_MAX
) && (Index
< Length
); FieldIndex
++) {
74 if (TmpStr
[Index
] != ISCSI_ROOT_PATH_FIELD_DELIMITER
) {
75 Fields
[FieldIndex
].Str
= &TmpStr
[Index
];
78 while ((TmpStr
[Index
] != ISCSI_ROOT_PATH_FIELD_DELIMITER
) && (Index
< Length
)) {
82 if (TmpStr
[Index
] == ISCSI_ROOT_PATH_FIELD_DELIMITER
) {
83 if (FieldIndex
!= RP_FIELD_IDX_TARGETNAME
) {
88 if (Fields
[FieldIndex
].Str
!= NULL
) {
89 Fields
[FieldIndex
].Len
= (UINT8
) AsciiStrLen (Fields
[FieldIndex
].Str
);
94 if (FieldIndex
!= RP_FIELD_IDX_MAX
) {
95 Status
= EFI_INVALID_PARAMETER
;
99 if ((Fields
[RP_FIELD_IDX_SERVERNAME
].Str
== NULL
) ||
100 (Fields
[RP_FIELD_IDX_TARGETNAME
].Str
== NULL
) ||
101 (Fields
[RP_FIELD_IDX_PROTOCOL
].Len
> 1)
104 Status
= EFI_INVALID_PARAMETER
;
108 // Get the IP address of the target.
110 Field
= &Fields
[RP_FIELD_IDX_SERVERNAME
];
111 Status
= IScsiAsciiStrToIp (Field
->Str
, &ConfigNvData
->TargetIp
);
112 if (EFI_ERROR (Status
)) {
116 // Check the protocol type.
118 Field
= &Fields
[RP_FIELD_IDX_PROTOCOL
];
119 if ((Field
->Str
!= NULL
) && ((*(Field
->Str
) - '0') != EFI_IP_PROTO_TCP
)) {
120 Status
= EFI_INVALID_PARAMETER
;
124 // Get the port of the iSCSI target.
126 Field
= &Fields
[RP_FIELD_IDX_PORT
];
127 if (Field
->Str
!= NULL
) {
128 ConfigNvData
->TargetPort
= (UINT16
) AsciiStrDecimalToUintn (Field
->Str
);
130 ConfigNvData
->TargetPort
= ISCSI_WELL_KNOWN_PORT
;
135 Field
= &Fields
[RP_FIELD_IDX_LUN
];
136 if (Field
->Str
!= NULL
) {
137 Status
= IScsiAsciiStrToLun (Field
->Str
, ConfigNvData
->BootLun
);
138 if (EFI_ERROR (Status
)) {
142 ZeroMem (ConfigNvData
->BootLun
, sizeof (ConfigNvData
->BootLun
));
145 // Get the target iSCSI Name.
147 Field
= &Fields
[RP_FIELD_IDX_TARGETNAME
];
149 if (AsciiStrLen (Field
->Str
) > ISCSI_NAME_MAX_SIZE
- 1) {
150 Status
= EFI_INVALID_PARAMETER
;
154 // Validate the iSCSI name.
156 Status
= IScsiNormalizeName (Field
->Str
, AsciiStrLen (Field
->Str
));
157 if (EFI_ERROR (Status
)) {
161 AsciiStrCpy (ConfigNvData
->TargetName
, Field
->Str
);
171 The callback function registerd to the DHCP4 instance which is used to select
172 the qualified DHCP OFFER.
174 @param[in] This The DHCP4 protocol.
175 @param[in] Context The context set when configuring the DHCP4 protocol.
176 @param[in] CurrentState The current state of the DHCP4 protocol.
177 @param[in] Dhcp4Event The event occurs in the current state.
178 @param[in] Packet The DHCP packet that is to be sent or already received.
179 @param[out] NewPacket The packet used to replace the above Packet.
181 @retval EFI_SUCCESS Either the DHCP OFFER is qualified or we're not intereseted
183 @retval EFI_NOT_READY The DHCP OFFER packet doesn't match our requirements.
184 @retval Others Other errors as indicated.
188 IScsiDhcpSelectOffer (
189 IN EFI_DHCP4_PROTOCOL
* This
,
191 IN EFI_DHCP4_STATE CurrentState
,
192 IN EFI_DHCP4_EVENT Dhcp4Event
,
193 IN EFI_DHCP4_PACKET
* Packet
, OPTIONAL
194 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
199 EFI_DHCP4_PACKET_OPTION
**OptionList
;
202 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) && (Dhcp4Event
!= Dhcp4SelectOffer
)) {
208 Status
= This
->Parse (This
, Packet
, &OptionCount
, NULL
);
209 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
210 return EFI_NOT_READY
;
213 OptionList
= AllocatePool (OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*));
214 if (OptionList
== NULL
) {
215 return EFI_NOT_READY
;
218 Status
= This
->Parse (This
, Packet
, &OptionCount
, OptionList
);
219 if (EFI_ERROR (Status
)) {
220 FreePool (OptionList
);
221 return EFI_NOT_READY
;
224 for (Index
= 0; Index
< OptionCount
; Index
++) {
225 if (OptionList
[Index
]->OpCode
!= DHCP4_TAG_ROOT_PATH
) {
229 Status
= IScsiDhcpExtractRootPath (
230 (CHAR8
*) &OptionList
[Index
]->Data
[0],
231 OptionList
[Index
]->Length
,
232 (ISCSI_SESSION_CONFIG_NVDATA
*) Context
238 if ((Index
== OptionCount
)) {
239 Status
= EFI_NOT_READY
;
242 FreePool (OptionList
);
248 Parse the DHCP ACK to get the address configuration and DNS information.
250 @param[in] Dhcp4 The DHCP4 protocol.
251 @param[in, out] ConfigData The session configuration data.
253 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
254 @retval EFI_NO_MAPPING DHCP failed to acquire address and other information.
255 @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is mal-formatted.
256 @retval EFI_DEVICE_ERROR Other errors as indicated.
260 IN EFI_DHCP4_PROTOCOL
*Dhcp4
,
261 IN OUT ISCSI_SESSION_CONFIG_DATA
*ConfigData
265 EFI_DHCP4_MODE_DATA Dhcp4ModeData
;
267 EFI_DHCP4_PACKET_OPTION
**OptionList
;
270 Status
= Dhcp4
->GetModeData (Dhcp4
, &Dhcp4ModeData
);
271 if (EFI_ERROR (Status
)) {
275 if (Dhcp4ModeData
.State
!= Dhcp4Bound
) {
276 return EFI_NO_MAPPING
;
279 CopyMem (&ConfigData
->NvData
.LocalIp
, &Dhcp4ModeData
.ClientAddress
, sizeof (EFI_IPv4_ADDRESS
));
280 CopyMem (&ConfigData
->NvData
.SubnetMask
, &Dhcp4ModeData
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
281 CopyMem (&ConfigData
->NvData
.Gateway
, &Dhcp4ModeData
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
286 Status
= Dhcp4
->Parse (Dhcp4
, Dhcp4ModeData
.ReplyPacket
, &OptionCount
, OptionList
);
287 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
288 return EFI_DEVICE_ERROR
;
291 OptionList
= AllocatePool (OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*));
292 if (OptionList
== NULL
) {
293 return EFI_OUT_OF_RESOURCES
;
296 Status
= Dhcp4
->Parse (Dhcp4
, Dhcp4ModeData
.ReplyPacket
, &OptionCount
, OptionList
);
297 if (EFI_ERROR (Status
)) {
298 FreePool (OptionList
);
299 return EFI_DEVICE_ERROR
;
302 for (Index
= 0; Index
< OptionCount
; Index
++) {
304 // Get DNS server addresses and DHCP server address from this offer.
306 if (OptionList
[Index
]->OpCode
== DHCP4_TAG_DNS
) {
308 if (((OptionList
[Index
]->Length
& 0x3) != 0) || (OptionList
[Index
]->Length
== 0)) {
309 Status
= EFI_INVALID_PARAMETER
;
313 // Primary DNS server address.
315 CopyMem (&ConfigData
->PrimaryDns
, &OptionList
[Index
]->Data
[0], sizeof (EFI_IPv4_ADDRESS
));
317 if (OptionList
[Index
]->Length
> 4) {
319 // Secondary DNS server address
321 CopyMem (&ConfigData
->SecondaryDns
, &OptionList
[Index
]->Data
[4], sizeof (EFI_IPv4_ADDRESS
));
323 } else if (OptionList
[Index
]->OpCode
== DHCP4_TAG_SERVER_ID
) {
324 if (OptionList
[Index
]->Length
!= 4) {
325 Status
= EFI_INVALID_PARAMETER
;
329 CopyMem (&ConfigData
->DhcpServer
, &OptionList
[Index
]->Data
[0], sizeof (EFI_IPv4_ADDRESS
));
333 FreePool (OptionList
);
339 Parse the DHCP ACK to get the address configuration and DNS information.
341 @param[in] Image The handle of the driver image.
342 @param[in] Controller The handle of the controller;
343 @param[in, out] ConfigData The session configuration data.
345 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
346 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
347 @retval EFI_NO_MEDIA There was a media error.
348 @retval Others Other errors as indicated.
354 IN EFI_HANDLE Controller
,
355 IN OUT ISCSI_SESSION_CONFIG_DATA
*ConfigData
358 EFI_HANDLE Dhcp4Handle
;
359 EFI_DHCP4_PROTOCOL
*Dhcp4
;
361 EFI_DHCP4_PACKET_OPTION
*ParaList
;
362 EFI_DHCP4_CONFIG_DATA Dhcp4ConfigData
;
363 BOOLEAN MediaPresent
;
370 // Check media status before do DHCP
373 NetLibDetectMedia (Controller
, &MediaPresent
);
379 // Create a DHCP4 child instance and get the protocol.
381 Status
= NetLibCreateServiceChild (
384 &gEfiDhcp4ServiceBindingProtocolGuid
,
387 if (EFI_ERROR (Status
)) {
391 Status
= gBS
->OpenProtocol (
393 &gEfiDhcp4ProtocolGuid
,
397 EFI_OPEN_PROTOCOL_BY_DRIVER
399 if (EFI_ERROR (Status
)) {
403 ParaList
= AllocatePool (sizeof (EFI_DHCP4_PACKET_OPTION
) + 3);
404 if (ParaList
== NULL
) {
405 Status
= EFI_OUT_OF_RESOURCES
;
409 // Ask the server to reply with Netmask, Router, DNS and RootPath options.
411 ParaList
->OpCode
= DHCP4_TAG_PARA_LIST
;
412 ParaList
->Length
= (UINT8
) (ConfigData
->NvData
.TargetInfoFromDhcp
? 4 : 3);
413 ParaList
->Data
[0] = DHCP4_TAG_NETMASK
;
414 ParaList
->Data
[1] = DHCP4_TAG_ROUTER
;
415 ParaList
->Data
[2] = DHCP4_TAG_DNS
;
416 ParaList
->Data
[3] = DHCP4_TAG_ROOT_PATH
;
418 ZeroMem (&Dhcp4ConfigData
, sizeof (EFI_DHCP4_CONFIG_DATA
));
419 Dhcp4ConfigData
.OptionCount
= 1;
420 Dhcp4ConfigData
.OptionList
= &ParaList
;
422 if (ConfigData
->NvData
.TargetInfoFromDhcp
) {
424 // Use callback to select an offer which contains target information.
426 Dhcp4ConfigData
.Dhcp4Callback
= IScsiDhcpSelectOffer
;
427 Dhcp4ConfigData
.CallbackContext
= &ConfigData
->NvData
;
430 Status
= Dhcp4
->Configure (Dhcp4
, &Dhcp4ConfigData
);
431 if (EFI_ERROR (Status
)) {
435 Status
= Dhcp4
->Start (Dhcp4
, NULL
);
436 if (EFI_ERROR (Status
)) {
440 // Parse the ACK to get required information.
442 Status
= IScsiParseDhcpAck (Dhcp4
, ConfigData
);
446 if (ParaList
!= NULL
) {
452 Dhcp4
->Configure (Dhcp4
, NULL
);
456 &gEfiDhcp4ProtocolGuid
,
462 NetLibDestroyServiceChild (
465 &gEfiDhcp4ServiceBindingProtocolGuid
,