2 ISci 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] 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 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 for (FieldIndex
= RP_FIELD_IDX_SERVERNAME
; FieldIndex
!= RP_FIELD_IDX_TARGETNAME
; FieldIndex
= RP_FIELD_IDX_TARGETNAME
) {
100 if (Fields
[FieldIndex
].Str
== NULL
) {
101 Status
= EFI_INVALID_PARAMETER
;
106 FieldIndex
= RP_FIELD_IDX_PROTOCOL
;
107 if (Fields
[RP_FIELD_IDX_PROTOCOL
].Len
> 1) {
108 Status
= EFI_INVALID_PARAMETER
;
113 // Get the IP address of the target.
115 FieldIndex
= RP_FIELD_IDX_SERVERNAME
;
116 Field
= &Fields
[FieldIndex
];
117 Status
= IScsiAsciiStrToIp (Field
->Str
, &ConfigNvData
->TargetIp
);
118 if (EFI_ERROR (Status
)) {
122 // Check the protocol type.
124 FieldIndex
= RP_FIELD_IDX_PROTOCOL
;
125 Field
= &Fields
[FieldIndex
];
126 if ((Field
->Str
!= NULL
) && ((*(Field
->Str
) - '0') != EFI_IP_PROTO_TCP
)) {
127 Status
= EFI_INVALID_PARAMETER
;
131 // Get the port of the iSCSI target.
133 FieldIndex
= RP_FIELD_IDX_PORT
;
134 Field
= &Fields
[FieldIndex
];
135 if (Field
->Str
!= NULL
) {
136 ConfigNvData
->TargetPort
= (UINT16
) AsciiStrDecimalToUintn (Field
->Str
);
138 ConfigNvData
->TargetPort
= ISCSI_WELL_KNOWN_PORT
;
143 FieldIndex
= RP_FIELD_IDX_LUN
;
144 Field
= &Fields
[FieldIndex
];
145 if (Field
->Str
!= NULL
) {
146 Status
= IScsiAsciiStrToLun (Field
->Str
, ConfigNvData
->BootLun
);
147 if (EFI_ERROR (Status
)) {
151 ZeroMem (ConfigNvData
->BootLun
, sizeof (ConfigNvData
->BootLun
));
154 // Get the target iSCSI Name.
156 FieldIndex
= RP_FIELD_IDX_TARGETNAME
;
157 Field
= &Fields
[FieldIndex
];
158 if (AsciiStrLen (Field
->Str
) > ISCSI_NAME_MAX_SIZE
- 1) {
159 Status
= EFI_INVALID_PARAMETER
;
163 // Validate the iSCSI name.
165 Status
= IScsiNormalizeName (Field
->Str
, AsciiStrLen (Field
->Str
));
166 if (EFI_ERROR (Status
)) {
170 AsciiStrCpy (ConfigNvData
->TargetName
, Field
->Str
);
174 gBS
->FreePool (TmpStr
);
180 The callback function registerd to the DHCP4 instance which is used to select
181 the qualified DHCP OFFER.
183 @param[in] This The DHCP4 protocol.
184 @param[in] Context The context set when configuring the DHCP4 protocol.
185 @param[in] CurrentState The current state of the DHCP4 protocol.
186 @param[in] Dhcp4Event The event occurs in the current state.
187 @param[in] Packet The DHCP packet that is to be sent or already received.
188 @param[out] NewPacket The packet used to replace the above Packet.
190 @retval EFI_SUCCESS Either the DHCP OFFER is qualified or we're not intereseted
192 @retval EFI_NOT_READY The DHCP OFFER packet doesn't match our requirements.
193 @retval Others Some unexpected error happened.
196 IScsiDhcpSelectOffer (
197 IN EFI_DHCP4_PROTOCOL
* This
,
199 IN EFI_DHCP4_STATE CurrentState
,
200 IN EFI_DHCP4_EVENT Dhcp4Event
,
201 IN EFI_DHCP4_PACKET
* Packet
, OPTIONAL
202 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
207 EFI_DHCP4_PACKET_OPTION
**OptionList
;
210 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) && (Dhcp4Event
!= Dhcp4SelectOffer
)) {
216 Status
= This
->Parse (This
, Packet
, &OptionCount
, NULL
);
217 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
218 return EFI_NOT_READY
;
221 OptionList
= AllocatePool (OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*));
222 if (OptionList
== NULL
) {
223 return EFI_NOT_READY
;
226 Status
= This
->Parse (This
, Packet
, &OptionCount
, OptionList
);
227 if (EFI_ERROR (Status
)) {
228 gBS
->FreePool (OptionList
);
229 return EFI_NOT_READY
;
232 for (Index
= 0; Index
< OptionCount
; Index
++) {
233 if (OptionList
[Index
]->OpCode
!= DHCP4_TAG_ROOT_PATH
) {
237 Status
= IScsiDhcpExtractRootPath (
238 (CHAR8
*) &OptionList
[Index
]->Data
[0],
239 OptionList
[Index
]->Length
,
240 (ISCSI_SESSION_CONFIG_NVDATA
*) Context
246 if ((Index
== OptionCount
)) {
247 Status
= EFI_NOT_READY
;
250 gBS
->FreePool (OptionList
);
256 Parse the DHCP ACK to get the address configuration and DNS information.
258 @param[in] Dhcp4 The DHCP4 protocol.
259 @param[in] ConfigData The session configuration data.
261 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
262 @retval EFI_NO_MAPPING DHCP failed to acquire address and other information.
263 @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is mal-formatted.
264 @retval EFI_DEVICE_ERROR Some unexpected error happened.
268 IN EFI_DHCP4_PROTOCOL
*Dhcp4
,
269 IN ISCSI_SESSION_CONFIG_DATA
*ConfigData
273 EFI_DHCP4_MODE_DATA Dhcp4ModeData
;
275 EFI_DHCP4_PACKET_OPTION
**OptionList
;
278 Status
= Dhcp4
->GetModeData (Dhcp4
, &Dhcp4ModeData
);
279 if (EFI_ERROR (Status
)) {
283 if (Dhcp4ModeData
.State
!= Dhcp4Bound
) {
284 return EFI_NO_MAPPING
;
287 CopyMem (&ConfigData
->NvData
.LocalIp
, &Dhcp4ModeData
.ClientAddress
, sizeof (EFI_IPv4_ADDRESS
));
288 CopyMem (&ConfigData
->NvData
.SubnetMask
, &Dhcp4ModeData
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
289 CopyMem (&ConfigData
->NvData
.Gateway
, &Dhcp4ModeData
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
294 Status
= Dhcp4
->Parse (Dhcp4
, Dhcp4ModeData
.ReplyPacket
, &OptionCount
, OptionList
);
295 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
296 return EFI_DEVICE_ERROR
;
299 OptionList
= AllocatePool (OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*));
300 if (OptionList
== NULL
) {
301 return EFI_OUT_OF_RESOURCES
;
304 Status
= Dhcp4
->Parse (Dhcp4
, Dhcp4ModeData
.ReplyPacket
, &OptionCount
, OptionList
);
305 if (EFI_ERROR (Status
)) {
306 gBS
->FreePool (OptionList
);
307 return EFI_DEVICE_ERROR
;
310 for (Index
= 0; Index
< OptionCount
; Index
++) {
312 // Get DNS server addresses and DHCP server address from this offer.
314 if (OptionList
[Index
]->OpCode
== DHCP4_TAG_DNS
) {
316 if (((OptionList
[Index
]->Length
& 0x3) != 0) || (OptionList
[Index
]->Length
== 0)) {
317 Status
= EFI_INVALID_PARAMETER
;
321 // Primary DNS server address.
323 CopyMem (&ConfigData
->PrimaryDns
, &OptionList
[Index
]->Data
[0], sizeof (EFI_IPv4_ADDRESS
));
325 if (OptionList
[Index
]->Length
> 4) {
327 // Secondary DNS server address
329 CopyMem (&ConfigData
->SecondaryDns
, &OptionList
[Index
]->Data
[4], sizeof (EFI_IPv4_ADDRESS
));
331 } else if (OptionList
[Index
]->OpCode
== DHCP4_TAG_SERVER_ID
) {
332 if (OptionList
[Index
]->Length
!= 4) {
333 Status
= EFI_INVALID_PARAMETER
;
337 CopyMem (&ConfigData
->DhcpServer
, &OptionList
[Index
]->Data
[0], sizeof (EFI_IPv4_ADDRESS
));
341 gBS
->FreePool (OptionList
);
347 Parse the DHCP ACK to get the address configuration and DNS information.
349 @param[in] Image The handle of the driver image.
350 @param[in] Controller The handle of the controller;
351 @param[in] ConfigData The session configuration data.
353 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
354 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
355 @retval Others Some unexpected error happened.
360 IN EFI_HANDLE Controller
,
361 IN ISCSI_SESSION_CONFIG_DATA
*ConfigData
364 EFI_HANDLE Dhcp4Handle
;
365 EFI_DHCP4_PROTOCOL
*Dhcp4
;
367 EFI_DHCP4_PACKET_OPTION
*ParaList
;
368 EFI_DHCP4_CONFIG_DATA Dhcp4ConfigData
;
375 // Create a DHCP4 child instance and get the protocol.
377 Status
= NetLibCreateServiceChild (
380 &gEfiDhcp4ServiceBindingProtocolGuid
,
383 if (EFI_ERROR (Status
)) {
387 Status
= gBS
->OpenProtocol (
389 &gEfiDhcp4ProtocolGuid
,
393 EFI_OPEN_PROTOCOL_BY_DRIVER
395 if (EFI_ERROR (Status
)) {
399 ParaList
= AllocatePool (sizeof (EFI_DHCP4_PACKET_OPTION
) + 3);
400 if (ParaList
== NULL
) {
401 Status
= EFI_OUT_OF_RESOURCES
;
405 // Ask the server to reply with Netmask, Router, DNS and RootPath options.
407 ParaList
->OpCode
= DHCP4_TAG_PARA_LIST
;
408 ParaList
->Length
= (UINT8
) (ConfigData
->NvData
.TargetInfoFromDhcp
? 4 : 3);
409 ParaList
->Data
[0] = DHCP4_TAG_NETMASK
;
410 ParaList
->Data
[1] = DHCP4_TAG_ROUTER
;
411 ParaList
->Data
[2] = DHCP4_TAG_DNS
;
412 ParaList
->Data
[3] = DHCP4_TAG_ROOT_PATH
;
414 ZeroMem (&Dhcp4ConfigData
, sizeof (EFI_DHCP4_CONFIG_DATA
));
415 Dhcp4ConfigData
.OptionCount
= 1;
416 Dhcp4ConfigData
.OptionList
= &ParaList
;
418 if (ConfigData
->NvData
.TargetInfoFromDhcp
) {
420 // Use callback to select an offer which contains target information.
422 Dhcp4ConfigData
.Dhcp4Callback
= IScsiDhcpSelectOffer
;
423 Dhcp4ConfigData
.CallbackContext
= &ConfigData
->NvData
;
426 Status
= Dhcp4
->Configure (Dhcp4
, &Dhcp4ConfigData
);
427 if (EFI_ERROR (Status
)) {
431 Status
= Dhcp4
->Start (Dhcp4
, NULL
);
432 if (EFI_ERROR (Status
)) {
436 // Parse the ACK to get required information.
438 Status
= IScsiParseDhcpAck (Dhcp4
, ConfigData
);
442 if (ParaList
!= NULL
) {
443 gBS
->FreePool (ParaList
);
448 Dhcp4
->Configure (Dhcp4
, NULL
);
452 &gEfiDhcp4ProtocolGuid
,
458 NetLibDestroyServiceChild (
461 &gEfiDhcp4ServiceBindingProtocolGuid
,