2 ISci DHCP related configuration routines.
4 Copyright (c) 2004 - 2007, Intel Corporation
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.
19 IScsi DHCP related configuration routines.
23 #include "IScsiImpl.h"
26 Extract the Root Path option and get the required target information.
28 @param RootPath[in] The RootPath.
30 @param Length[in] Length of the RootPath option payload.
32 @param ConfigNvData[in] The iSCSI session configuration data read from nonvolatile device.
34 @retval EFI_SUCCESS All required information is extracted from the RootPath option.
36 @retval EFI_NOT_FOUND The RootPath is not an iSCSI RootPath.
38 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
40 @retval EFI_INVALID_PARAMETER The RootPath is mal-formatted.
45 IScsiDhcpExtractRootPath (
48 IN ISCSI_SESSION_CONFIG_NVDATA
*ConfigNvData
52 UINT8 IScsiRootPathIdLen
;
54 ISCSI_ROOT_PATH_FIELD Fields
[RP_FIELD_IDX_MAX
];
55 ISCSI_ROOT_PATH_FIELD
*Field
;
60 // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>
62 IScsiRootPathIdLen
= (UINT8
) AsciiStrLen (ISCSI_ROOT_PATH_ID
);
64 if ((Length
<= IScsiRootPathIdLen
) || (CompareMem (RootPath
, ISCSI_ROOT_PATH_ID
, IScsiRootPathIdLen
) != 0)) {
68 // Skip the iSCSI RootPath ID "iscsi:".
70 RootPath
+= IScsiRootPathIdLen
;
71 Length
= (UINT8
) (Length
- IScsiRootPathIdLen
);
73 TmpStr
= (CHAR8
*) AllocatePool (Length
+ 1);
75 return EFI_OUT_OF_RESOURCES
;
78 CopyMem (TmpStr
, RootPath
, Length
);
79 TmpStr
[Length
] = '\0';
83 ZeroMem (&Fields
[0], sizeof (Fields
));
86 // Extract the fields in the Root Path option string.
88 for (FieldIndex
= 0; (FieldIndex
< RP_FIELD_IDX_MAX
) && (Index
< Length
); FieldIndex
++) {
89 if (TmpStr
[Index
] != ISCSI_ROOT_PATH_FIELD_DELIMITER
) {
90 Fields
[FieldIndex
].Str
= &TmpStr
[Index
];
93 while ((TmpStr
[Index
] != ISCSI_ROOT_PATH_FIELD_DELIMITER
) && (Index
< Length
)) {
97 if (TmpStr
[Index
] == ISCSI_ROOT_PATH_FIELD_DELIMITER
) {
98 if (FieldIndex
!= RP_FIELD_IDX_TARGETNAME
) {
103 if (Fields
[FieldIndex
].Str
!= NULL
) {
104 Fields
[FieldIndex
].Len
= (UINT8
) AsciiStrLen (Fields
[FieldIndex
].Str
);
109 if (FieldIndex
!= RP_FIELD_IDX_MAX
) {
110 Status
= EFI_INVALID_PARAMETER
;
114 if ((Fields
[RP_FIELD_IDX_SERVERNAME
].Str
== NULL
) ||
115 (Fields
[RP_FIELD_IDX_TARGETNAME
].Str
== NULL
) ||
116 (Fields
[RP_FIELD_IDX_PROTOCOL
].Len
> 1)
119 Status
= EFI_INVALID_PARAMETER
;
123 // Get the IP address of the target.
125 Field
= &Fields
[RP_FIELD_IDX_SERVERNAME
];
126 Status
= IScsiAsciiStrToIp (Field
->Str
, &ConfigNvData
->TargetIp
);
127 if (EFI_ERROR (Status
)) {
131 // Check the protocol type.
133 Field
= &Fields
[RP_FIELD_IDX_PROTOCOL
];
134 if ((Field
->Str
!= NULL
) && ((*(Field
->Str
) - '0') != EFI_IP_PROTO_TCP
)) {
135 Status
= EFI_INVALID_PARAMETER
;
139 // Get the port of the iSCSI target.
141 Field
= &Fields
[RP_FIELD_IDX_PORT
];
142 if (Field
->Str
!= NULL
) {
143 ConfigNvData
->TargetPort
= (UINT16
) AsciiStrDecimalToUintn (Field
->Str
);
145 ConfigNvData
->TargetPort
= ISCSI_WELL_KNOWN_PORT
;
150 Field
= &Fields
[RP_FIELD_IDX_LUN
];
151 if (Field
->Str
!= NULL
) {
152 Status
= IScsiAsciiStrToLun (Field
->Str
, ConfigNvData
->BootLun
);
153 if (EFI_ERROR (Status
)) {
157 ZeroMem (ConfigNvData
->BootLun
, sizeof (ConfigNvData
->BootLun
));
160 // Get the target iSCSI Name.
162 Field
= &Fields
[RP_FIELD_IDX_TARGETNAME
];
164 if (AsciiStrLen (Field
->Str
) > ISCSI_NAME_MAX_SIZE
- 1) {
165 Status
= EFI_INVALID_PARAMETER
;
169 // Validate the iSCSI name.
171 Status
= IScsiNormalizeName (Field
->Str
, AsciiStrLen (Field
->Str
));
172 if (EFI_ERROR (Status
)) {
176 AsciiStrCpy (ConfigNvData
->TargetName
, Field
->Str
);
180 gBS
->FreePool (TmpStr
);
186 The callback function registerd to the DHCP4 instance which is used to select
187 the qualified DHCP OFFER.
189 @param This[in] The DHCP4 protocol.
191 @param Context[in] The context set when configuring the DHCP4 protocol.
193 @param CurrentState[in] The current state of the DHCP4 protocol.
195 @param Dhcp4Event[in] The event occurs in the current state.
197 @param Packet[in] The DHCP packet that is to be sent or already received.
199 @param NewPackt[out] The packet used to replace the above Packet.
201 @retval EFI_NOT_READY The DHCP OFFER packet doesn't match our requirements.
203 @retval EFI_SUCCESS Either the DHCP OFFER is qualified or we're not intereseted
209 IScsiDhcpSelectOffer (
210 IN EFI_DHCP4_PROTOCOL
* This
,
212 IN EFI_DHCP4_STATE CurrentState
,
213 IN EFI_DHCP4_EVENT Dhcp4Event
,
214 IN EFI_DHCP4_PACKET
* Packet
, OPTIONAL
215 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
220 EFI_DHCP4_PACKET_OPTION
**OptionList
;
223 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) && (Dhcp4Event
!= Dhcp4SelectOffer
)) {
229 Status
= This
->Parse (This
, Packet
, &OptionCount
, NULL
);
230 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
231 return EFI_NOT_READY
;
234 OptionList
= AllocatePool (OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*));
235 if (OptionList
== NULL
) {
236 return EFI_NOT_READY
;
239 Status
= This
->Parse (This
, Packet
, &OptionCount
, OptionList
);
240 if (EFI_ERROR (Status
)) {
241 gBS
->FreePool (OptionList
);
242 return EFI_NOT_READY
;
245 for (Index
= 0; Index
< OptionCount
; Index
++) {
246 if (OptionList
[Index
]->OpCode
!= DHCP4_TAG_ROOT_PATH
) {
250 Status
= IScsiDhcpExtractRootPath (
251 (CHAR8
*) &OptionList
[Index
]->Data
[0],
252 OptionList
[Index
]->Length
,
253 (ISCSI_SESSION_CONFIG_NVDATA
*) Context
259 if ((Index
== OptionCount
)) {
260 Status
= EFI_NOT_READY
;
263 gBS
->FreePool (OptionList
);
269 Parse the DHCP ACK to get the address configuration and DNS information.
271 @param Dhcp4[in] The DHCP4 protocol.
273 @param ConfigData[in] The session configuration data.
275 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
277 @retval EFI_NO_MAPPING DHCP failed to acquire address and other information.
279 @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is mal-formatted.
281 @retval EFI_DEVICE_ERROR Some unexpected error happened.
286 IN EFI_DHCP4_PROTOCOL
*Dhcp4
,
287 IN ISCSI_SESSION_CONFIG_DATA
*ConfigData
291 EFI_DHCP4_MODE_DATA Dhcp4ModeData
;
293 EFI_DHCP4_PACKET_OPTION
**OptionList
;
296 Status
= Dhcp4
->GetModeData (Dhcp4
, &Dhcp4ModeData
);
297 if (EFI_ERROR (Status
)) {
301 if (Dhcp4ModeData
.State
!= Dhcp4Bound
) {
302 return EFI_NO_MAPPING
;
305 CopyMem (&ConfigData
->NvData
.LocalIp
, &Dhcp4ModeData
.ClientAddress
, sizeof (EFI_IPv4_ADDRESS
));
306 CopyMem (&ConfigData
->NvData
.SubnetMask
, &Dhcp4ModeData
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
307 CopyMem (&ConfigData
->NvData
.Gateway
, &Dhcp4ModeData
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
312 Status
= Dhcp4
->Parse (Dhcp4
, Dhcp4ModeData
.ReplyPacket
, &OptionCount
, OptionList
);
313 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
314 return EFI_DEVICE_ERROR
;
317 OptionList
= AllocatePool (OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*));
318 if (OptionList
== NULL
) {
319 return EFI_OUT_OF_RESOURCES
;
322 Status
= Dhcp4
->Parse (Dhcp4
, Dhcp4ModeData
.ReplyPacket
, &OptionCount
, OptionList
);
323 if (EFI_ERROR (Status
)) {
324 gBS
->FreePool (OptionList
);
325 return EFI_DEVICE_ERROR
;
328 for (Index
= 0; Index
< OptionCount
; Index
++) {
330 // Get DNS server addresses and DHCP server address from this offer.
332 if (OptionList
[Index
]->OpCode
== DHCP4_TAG_DNS
) {
334 if (((OptionList
[Index
]->Length
& 0x3) != 0) || (OptionList
[Index
]->Length
== 0)) {
335 Status
= EFI_INVALID_PARAMETER
;
339 // Primary DNS server address.
341 CopyMem (&ConfigData
->PrimaryDns
, &OptionList
[Index
]->Data
[0], sizeof (EFI_IPv4_ADDRESS
));
343 if (OptionList
[Index
]->Length
> 4) {
345 // Secondary DNS server address
347 CopyMem (&ConfigData
->SecondaryDns
, &OptionList
[Index
]->Data
[4], sizeof (EFI_IPv4_ADDRESS
));
349 } else if (OptionList
[Index
]->OpCode
== DHCP4_TAG_SERVER_ID
) {
350 if (OptionList
[Index
]->Length
!= 4) {
351 Status
= EFI_INVALID_PARAMETER
;
355 CopyMem (&ConfigData
->DhcpServer
, &OptionList
[Index
]->Data
[0], sizeof (EFI_IPv4_ADDRESS
));
359 gBS
->FreePool (OptionList
);
365 Parse the DHCP ACK to get the address configuration and DNS information.
367 @param Image[in] The handle of the driver image.
369 @param Controller[in] The handle of the controller;
371 @param ConfigData[in] The session configuration data.
373 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
375 @retval EFI_NO_MAPPING DHCP failed to acquire address and other information.
377 @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is mal-formatted.
379 @retval EFI_DEVICE_ERROR Some unexpected error happened.
385 IN EFI_HANDLE Controller
,
386 IN ISCSI_SESSION_CONFIG_DATA
*ConfigData
389 EFI_HANDLE Dhcp4Handle
;
390 EFI_DHCP4_PROTOCOL
*Dhcp4
;
392 EFI_DHCP4_PACKET_OPTION
*ParaList
;
393 EFI_DHCP4_CONFIG_DATA Dhcp4ConfigData
;
400 // Create a DHCP4 child instance and get the protocol.
402 Status
= NetLibCreateServiceChild (
405 &gEfiDhcp4ServiceBindingProtocolGuid
,
408 if (EFI_ERROR (Status
)) {
412 Status
= gBS
->OpenProtocol (
414 &gEfiDhcp4ProtocolGuid
,
418 EFI_OPEN_PROTOCOL_BY_DRIVER
420 if (EFI_ERROR (Status
)) {
424 ParaList
= AllocatePool (sizeof (EFI_DHCP4_PACKET_OPTION
) + 3);
425 if (ParaList
== NULL
) {
426 Status
= EFI_OUT_OF_RESOURCES
;
430 // Ask the server to reply with Netmask, Router, DNS and RootPath options.
432 ParaList
->OpCode
= DHCP4_TAG_PARA_LIST
;
433 ParaList
->Length
= (UINT8
) (ConfigData
->NvData
.TargetInfoFromDhcp
? 4 : 3);
434 ParaList
->Data
[0] = DHCP4_TAG_NETMASK
;
435 ParaList
->Data
[1] = DHCP4_TAG_ROUTER
;
436 ParaList
->Data
[2] = DHCP4_TAG_DNS
;
437 ParaList
->Data
[3] = DHCP4_TAG_ROOT_PATH
;
439 ZeroMem (&Dhcp4ConfigData
, sizeof (EFI_DHCP4_CONFIG_DATA
));
440 Dhcp4ConfigData
.OptionCount
= 1;
441 Dhcp4ConfigData
.OptionList
= &ParaList
;
443 if (ConfigData
->NvData
.TargetInfoFromDhcp
) {
445 // Use callback to select an offer which contains target information.
447 Dhcp4ConfigData
.Dhcp4Callback
= IScsiDhcpSelectOffer
;
448 Dhcp4ConfigData
.CallbackContext
= &ConfigData
->NvData
;
451 Status
= Dhcp4
->Configure (Dhcp4
, &Dhcp4ConfigData
);
452 if (EFI_ERROR (Status
)) {
456 Status
= Dhcp4
->Start (Dhcp4
, NULL
);
457 if (EFI_ERROR (Status
)) {
461 // Parse the ACK to get required information.
463 Status
= IScsiParseDhcpAck (Dhcp4
, ConfigData
);
467 if (ParaList
!= NULL
) {
468 gBS
->FreePool (ParaList
);
473 Dhcp4
->Configure (Dhcp4
, NULL
);
477 &gEfiDhcp4ProtocolGuid
,
483 NetLibDestroyServiceChild (
486 &gEfiDhcp4ServiceBindingProtocolGuid
,