2 iSCSI DHCP related configuration routines.
4 Copyright (c) 2004 - 2007, Intel Corporation.<BR>
5 All rights reserved. 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
;
41 RP_FIELD_IDX FieldIndex
;
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
);
165 gBS
->FreePool (TmpStr
);
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.
187 IScsiDhcpSelectOffer (
188 IN EFI_DHCP4_PROTOCOL
* This
,
190 IN EFI_DHCP4_STATE CurrentState
,
191 IN EFI_DHCP4_EVENT Dhcp4Event
,
192 IN EFI_DHCP4_PACKET
* Packet
, OPTIONAL
193 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
198 EFI_DHCP4_PACKET_OPTION
**OptionList
;
201 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) && (Dhcp4Event
!= Dhcp4SelectOffer
)) {
207 Status
= This
->Parse (This
, Packet
, &OptionCount
, NULL
);
208 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
209 return EFI_NOT_READY
;
212 OptionList
= AllocatePool (OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*));
213 if (OptionList
== NULL
) {
214 return EFI_NOT_READY
;
217 Status
= This
->Parse (This
, Packet
, &OptionCount
, OptionList
);
218 if (EFI_ERROR (Status
)) {
219 gBS
->FreePool (OptionList
);
220 return EFI_NOT_READY
;
223 for (Index
= 0; Index
< OptionCount
; Index
++) {
224 if (OptionList
[Index
]->OpCode
!= DHCP4_TAG_ROOT_PATH
) {
228 Status
= IScsiDhcpExtractRootPath (
229 (CHAR8
*) &OptionList
[Index
]->Data
[0],
230 OptionList
[Index
]->Length
,
231 (ISCSI_SESSION_CONFIG_NVDATA
*) Context
237 if ((Index
== OptionCount
)) {
238 Status
= EFI_NOT_READY
;
241 gBS
->FreePool (OptionList
);
247 Parse the DHCP ACK to get the address configuration and DNS information.
249 @param[in] Dhcp4 The DHCP4 protocol.
250 @param[in, out] ConfigData The session configuration data.
252 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
253 @retval EFI_NO_MAPPING DHCP failed to acquire address and other information.
254 @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is mal-formatted.
255 @retval EFI_DEVICE_ERROR Other errors as indicated.
259 IN EFI_DHCP4_PROTOCOL
*Dhcp4
,
260 IN OUT ISCSI_SESSION_CONFIG_DATA
*ConfigData
264 EFI_DHCP4_MODE_DATA Dhcp4ModeData
;
266 EFI_DHCP4_PACKET_OPTION
**OptionList
;
269 Status
= Dhcp4
->GetModeData (Dhcp4
, &Dhcp4ModeData
);
270 if (EFI_ERROR (Status
)) {
274 if (Dhcp4ModeData
.State
!= Dhcp4Bound
) {
275 return EFI_NO_MAPPING
;
278 CopyMem (&ConfigData
->NvData
.LocalIp
, &Dhcp4ModeData
.ClientAddress
, sizeof (EFI_IPv4_ADDRESS
));
279 CopyMem (&ConfigData
->NvData
.SubnetMask
, &Dhcp4ModeData
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
280 CopyMem (&ConfigData
->NvData
.Gateway
, &Dhcp4ModeData
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
285 Status
= Dhcp4
->Parse (Dhcp4
, Dhcp4ModeData
.ReplyPacket
, &OptionCount
, OptionList
);
286 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
287 return EFI_DEVICE_ERROR
;
290 OptionList
= AllocatePool (OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*));
291 if (OptionList
== NULL
) {
292 return EFI_OUT_OF_RESOURCES
;
295 Status
= Dhcp4
->Parse (Dhcp4
, Dhcp4ModeData
.ReplyPacket
, &OptionCount
, OptionList
);
296 if (EFI_ERROR (Status
)) {
297 gBS
->FreePool (OptionList
);
298 return EFI_DEVICE_ERROR
;
301 for (Index
= 0; Index
< OptionCount
; Index
++) {
303 // Get DNS server addresses and DHCP server address from this offer.
305 if (OptionList
[Index
]->OpCode
== DHCP4_TAG_DNS
) {
307 if (((OptionList
[Index
]->Length
& 0x3) != 0) || (OptionList
[Index
]->Length
== 0)) {
308 Status
= EFI_INVALID_PARAMETER
;
312 // Primary DNS server address.
314 CopyMem (&ConfigData
->PrimaryDns
, &OptionList
[Index
]->Data
[0], sizeof (EFI_IPv4_ADDRESS
));
316 if (OptionList
[Index
]->Length
> 4) {
318 // Secondary DNS server address
320 CopyMem (&ConfigData
->SecondaryDns
, &OptionList
[Index
]->Data
[4], sizeof (EFI_IPv4_ADDRESS
));
322 } else if (OptionList
[Index
]->OpCode
== DHCP4_TAG_SERVER_ID
) {
323 if (OptionList
[Index
]->Length
!= 4) {
324 Status
= EFI_INVALID_PARAMETER
;
328 CopyMem (&ConfigData
->DhcpServer
, &OptionList
[Index
]->Data
[0], sizeof (EFI_IPv4_ADDRESS
));
332 gBS
->FreePool (OptionList
);
338 Parse the DHCP ACK to get the address configuration and DNS information.
340 @param[in] Image The handle of the driver image.
341 @param[in] Controller The handle of the controller;
342 @param[in, out] ConfigData The session configuration data.
344 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
345 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
346 @retval Others Other errors as indicated.
351 IN EFI_HANDLE Controller
,
352 IN OUT ISCSI_SESSION_CONFIG_DATA
*ConfigData
355 EFI_HANDLE Dhcp4Handle
;
356 EFI_DHCP4_PROTOCOL
*Dhcp4
;
358 EFI_DHCP4_PACKET_OPTION
*ParaList
;
359 EFI_DHCP4_CONFIG_DATA Dhcp4ConfigData
;
366 // Create a DHCP4 child instance and get the protocol.
368 Status
= NetLibCreateServiceChild (
371 &gEfiDhcp4ServiceBindingProtocolGuid
,
374 if (EFI_ERROR (Status
)) {
378 Status
= gBS
->OpenProtocol (
380 &gEfiDhcp4ProtocolGuid
,
384 EFI_OPEN_PROTOCOL_BY_DRIVER
386 if (EFI_ERROR (Status
)) {
390 ParaList
= AllocatePool (sizeof (EFI_DHCP4_PACKET_OPTION
) + 3);
391 if (ParaList
== NULL
) {
392 Status
= EFI_OUT_OF_RESOURCES
;
396 // Ask the server to reply with Netmask, Router, DNS and RootPath options.
398 ParaList
->OpCode
= DHCP4_TAG_PARA_LIST
;
399 ParaList
->Length
= (UINT8
) (ConfigData
->NvData
.TargetInfoFromDhcp
? 4 : 3);
400 ParaList
->Data
[0] = DHCP4_TAG_NETMASK
;
401 ParaList
->Data
[1] = DHCP4_TAG_ROUTER
;
402 ParaList
->Data
[2] = DHCP4_TAG_DNS
;
403 ParaList
->Data
[3] = DHCP4_TAG_ROOT_PATH
;
405 ZeroMem (&Dhcp4ConfigData
, sizeof (EFI_DHCP4_CONFIG_DATA
));
406 Dhcp4ConfigData
.OptionCount
= 1;
407 Dhcp4ConfigData
.OptionList
= &ParaList
;
409 if (ConfigData
->NvData
.TargetInfoFromDhcp
) {
411 // Use callback to select an offer which contains target information.
413 Dhcp4ConfigData
.Dhcp4Callback
= IScsiDhcpSelectOffer
;
414 Dhcp4ConfigData
.CallbackContext
= &ConfigData
->NvData
;
417 Status
= Dhcp4
->Configure (Dhcp4
, &Dhcp4ConfigData
);
418 if (EFI_ERROR (Status
)) {
422 Status
= Dhcp4
->Start (Dhcp4
, NULL
);
423 if (EFI_ERROR (Status
)) {
427 // Parse the ACK to get required information.
429 Status
= IScsiParseDhcpAck (Dhcp4
, ConfigData
);
433 if (ParaList
!= NULL
) {
434 gBS
->FreePool (ParaList
);
439 Dhcp4
->Configure (Dhcp4
, NULL
);
443 &gEfiDhcp4ProtocolGuid
,
449 NetLibDestroyServiceChild (
452 &gEfiDhcp4ServiceBindingProtocolGuid
,