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.
44 IScsiDhcpExtractRootPath (
47 IN ISCSI_SESSION_CONFIG_NVDATA
*ConfigNvData
51 UINT8 IScsiRootPathIdLen
;
53 ISCSI_ROOT_PATH_FIELD Fields
[RP_FIELD_IDX_MAX
];
54 ISCSI_ROOT_PATH_FIELD
*Field
;
59 // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>
61 IScsiRootPathIdLen
= (UINT8
) AsciiStrLen (ISCSI_ROOT_PATH_ID
);
63 if ((Length
<= IScsiRootPathIdLen
) || (CompareMem (RootPath
, ISCSI_ROOT_PATH_ID
, IScsiRootPathIdLen
) != 0)) {
67 // Skip the iSCSI RootPath ID "iscsi:".
69 RootPath
+= IScsiRootPathIdLen
;
70 Length
= (UINT8
) (Length
- IScsiRootPathIdLen
);
72 TmpStr
= (CHAR8
*) AllocatePool (Length
+ 1);
74 return EFI_OUT_OF_RESOURCES
;
77 CopyMem (TmpStr
, RootPath
, Length
);
78 TmpStr
[Length
] = '\0';
82 ZeroMem (&Fields
[0], sizeof (Fields
));
85 // Extract the fields in the Root Path option string.
87 for (FieldIndex
= 0; (FieldIndex
< RP_FIELD_IDX_MAX
) && (Index
< Length
); FieldIndex
++) {
88 if (TmpStr
[Index
] != ISCSI_ROOT_PATH_FIELD_DELIMITER
) {
89 Fields
[FieldIndex
].Str
= &TmpStr
[Index
];
92 while ((TmpStr
[Index
] != ISCSI_ROOT_PATH_FIELD_DELIMITER
) && (Index
< Length
)) {
96 if (TmpStr
[Index
] == ISCSI_ROOT_PATH_FIELD_DELIMITER
) {
97 if (FieldIndex
!= RP_FIELD_IDX_TARGETNAME
) {
102 if (Fields
[FieldIndex
].Str
!= NULL
) {
103 Fields
[FieldIndex
].Len
= (UINT8
) AsciiStrLen (Fields
[FieldIndex
].Str
);
108 if (FieldIndex
!= RP_FIELD_IDX_MAX
) {
109 Status
= EFI_INVALID_PARAMETER
;
113 if ((Fields
[RP_FIELD_IDX_SERVERNAME
].Str
== NULL
) ||
114 (Fields
[RP_FIELD_IDX_TARGETNAME
].Str
== NULL
) ||
115 (Fields
[RP_FIELD_IDX_PROTOCOL
].Len
> 1)
118 Status
= EFI_INVALID_PARAMETER
;
122 // Get the IP address of the target.
124 Field
= &Fields
[RP_FIELD_IDX_SERVERNAME
];
125 Status
= IScsiAsciiStrToIp (Field
->Str
, &ConfigNvData
->TargetIp
);
126 if (EFI_ERROR (Status
)) {
130 // Check the protocol type.
132 Field
= &Fields
[RP_FIELD_IDX_PROTOCOL
];
133 if ((Field
->Str
!= NULL
) && ((*(Field
->Str
) - '0') != EFI_IP_PROTO_TCP
)) {
134 Status
= EFI_INVALID_PARAMETER
;
138 // Get the port of the iSCSI target.
140 Field
= &Fields
[RP_FIELD_IDX_PORT
];
141 if (Field
->Str
!= NULL
) {
142 ConfigNvData
->TargetPort
= (UINT16
) AsciiStrDecimalToUintn (Field
->Str
);
144 ConfigNvData
->TargetPort
= ISCSI_WELL_KNOWN_PORT
;
149 Field
= &Fields
[RP_FIELD_IDX_LUN
];
150 if (Field
->Str
!= NULL
) {
151 Status
= IScsiAsciiStrToLun (Field
->Str
, ConfigNvData
->BootLun
);
152 if (EFI_ERROR (Status
)) {
156 ZeroMem (ConfigNvData
->BootLun
, sizeof (ConfigNvData
->BootLun
));
159 // Get the target iSCSI Name.
161 Field
= &Fields
[RP_FIELD_IDX_TARGETNAME
];
163 if (AsciiStrLen (Field
->Str
) > ISCSI_NAME_MAX_SIZE
- 1) {
164 Status
= EFI_INVALID_PARAMETER
;
168 // Validate the iSCSI name.
170 Status
= IScsiNormalizeName (Field
->Str
, AsciiStrLen (Field
->Str
));
171 if (EFI_ERROR (Status
)) {
175 AsciiStrCpy (ConfigNvData
->TargetName
, Field
->Str
);
179 gBS
->FreePool (TmpStr
);
185 The callback function registerd to the DHCP4 instance which is used to select
186 the qualified DHCP OFFER.
188 @param This[in] The DHCP4 protocol.
190 @param Context[in] The context set when configuring the DHCP4 protocol.
192 @param CurrentState[in] The current state of the DHCP4 protocol.
194 @param Dhcp4Event[in] The event occurs in the current state.
196 @param Packet[in] The DHCP packet that is to be sent or already received.
198 @param NewPackt[out] The packet used to replace the above Packet.
200 @retval EFI_NOT_READY The DHCP OFFER packet doesn't match our requirements.
202 @retval EFI_SUCCESS Either the DHCP OFFER is qualified or we're not intereseted
207 IScsiDhcpSelectOffer (
208 IN EFI_DHCP4_PROTOCOL
* This
,
210 IN EFI_DHCP4_STATE CurrentState
,
211 IN EFI_DHCP4_EVENT Dhcp4Event
,
212 IN EFI_DHCP4_PACKET
* Packet
, OPTIONAL
213 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
218 EFI_DHCP4_PACKET_OPTION
**OptionList
;
221 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) && (Dhcp4Event
!= Dhcp4SelectOffer
)) {
227 Status
= This
->Parse (This
, Packet
, &OptionCount
, NULL
);
228 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
229 return EFI_NOT_READY
;
232 OptionList
= AllocatePool (OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*));
233 if (OptionList
== NULL
) {
234 return EFI_NOT_READY
;
237 Status
= This
->Parse (This
, Packet
, &OptionCount
, OptionList
);
238 if (EFI_ERROR (Status
)) {
239 gBS
->FreePool (OptionList
);
240 return EFI_NOT_READY
;
243 for (Index
= 0; Index
< OptionCount
; Index
++) {
244 if (OptionList
[Index
]->OpCode
!= DHCP4_TAG_ROOT_PATH
) {
248 Status
= IScsiDhcpExtractRootPath (
249 (CHAR8
*) &OptionList
[Index
]->Data
[0],
250 OptionList
[Index
]->Length
,
251 (ISCSI_SESSION_CONFIG_NVDATA
*) Context
257 if ((Index
== OptionCount
)) {
258 Status
= EFI_NOT_READY
;
261 gBS
->FreePool (OptionList
);
267 Parse the DHCP ACK to get the address configuration and DNS information.
269 @param Dhcp4[in] The DHCP4 protocol.
271 @param ConfigData[in] The session configuration data.
273 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
275 @retval EFI_NO_MAPPING DHCP failed to acquire address and other information.
277 @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is mal-formatted.
279 @retval EFI_DEVICE_ERROR Some unexpected error happened.
284 IN EFI_DHCP4_PROTOCOL
*Dhcp4
,
285 IN ISCSI_SESSION_CONFIG_DATA
*ConfigData
289 EFI_DHCP4_MODE_DATA Dhcp4ModeData
;
291 EFI_DHCP4_PACKET_OPTION
**OptionList
;
294 Status
= Dhcp4
->GetModeData (Dhcp4
, &Dhcp4ModeData
);
295 if (EFI_ERROR (Status
)) {
299 if (Dhcp4ModeData
.State
!= Dhcp4Bound
) {
300 return EFI_NO_MAPPING
;
303 CopyMem (&ConfigData
->NvData
.LocalIp
, &Dhcp4ModeData
.ClientAddress
, sizeof (EFI_IPv4_ADDRESS
));
304 CopyMem (&ConfigData
->NvData
.SubnetMask
, &Dhcp4ModeData
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
305 CopyMem (&ConfigData
->NvData
.Gateway
, &Dhcp4ModeData
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
310 Status
= Dhcp4
->Parse (Dhcp4
, Dhcp4ModeData
.ReplyPacket
, &OptionCount
, OptionList
);
311 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
312 return EFI_DEVICE_ERROR
;
315 OptionList
= AllocatePool (OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*));
316 if (OptionList
== NULL
) {
317 return EFI_OUT_OF_RESOURCES
;
320 Status
= Dhcp4
->Parse (Dhcp4
, Dhcp4ModeData
.ReplyPacket
, &OptionCount
, OptionList
);
321 if (EFI_ERROR (Status
)) {
322 gBS
->FreePool (OptionList
);
323 return EFI_DEVICE_ERROR
;
326 for (Index
= 0; Index
< OptionCount
; Index
++) {
328 // Get DNS server addresses and DHCP server address from this offer.
330 if (OptionList
[Index
]->OpCode
== DHCP4_TAG_DNS
) {
332 if (((OptionList
[Index
]->Length
& 0x3) != 0) || (OptionList
[Index
]->Length
== 0)) {
333 Status
= EFI_INVALID_PARAMETER
;
337 // Primary DNS server address.
339 CopyMem (&ConfigData
->PrimaryDns
, &OptionList
[Index
]->Data
[0], sizeof (EFI_IPv4_ADDRESS
));
341 if (OptionList
[Index
]->Length
> 4) {
343 // Secondary DNS server address
345 CopyMem (&ConfigData
->SecondaryDns
, &OptionList
[Index
]->Data
[4], sizeof (EFI_IPv4_ADDRESS
));
347 } else if (OptionList
[Index
]->OpCode
== DHCP4_TAG_SERVER_ID
) {
348 if (OptionList
[Index
]->Length
!= 4) {
349 Status
= EFI_INVALID_PARAMETER
;
353 CopyMem (&ConfigData
->DhcpServer
, &OptionList
[Index
]->Data
[0], sizeof (EFI_IPv4_ADDRESS
));
357 gBS
->FreePool (OptionList
);
363 Parse the DHCP ACK to get the address configuration and DNS information.
365 @param Image[in] The handle of the driver image.
367 @param Controller[in] The handle of the controller;
369 @param ConfigData[in] The session configuration data.
371 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
373 @retval EFI_NO_MAPPING DHCP failed to acquire address and other information.
375 @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is mal-formatted.
377 @retval EFI_DEVICE_ERROR Some unexpected error happened.
383 IN EFI_HANDLE Controller
,
384 IN ISCSI_SESSION_CONFIG_DATA
*ConfigData
387 EFI_HANDLE Dhcp4Handle
;
388 EFI_DHCP4_PROTOCOL
*Dhcp4
;
390 EFI_DHCP4_PACKET_OPTION
*ParaList
;
391 EFI_DHCP4_CONFIG_DATA Dhcp4ConfigData
;
398 // Create a DHCP4 child instance and get the protocol.
400 Status
= NetLibCreateServiceChild (
403 &gEfiDhcp4ServiceBindingProtocolGuid
,
406 if (EFI_ERROR (Status
)) {
410 Status
= gBS
->OpenProtocol (
412 &gEfiDhcp4ProtocolGuid
,
416 EFI_OPEN_PROTOCOL_BY_DRIVER
418 if (EFI_ERROR (Status
)) {
422 ParaList
= AllocatePool (sizeof (EFI_DHCP4_PACKET_OPTION
) + 3);
423 if (ParaList
== NULL
) {
424 Status
= EFI_OUT_OF_RESOURCES
;
428 // Ask the server to reply with Netmask, Router, DNS and RootPath options.
430 ParaList
->OpCode
= DHCP4_TAG_PARA_LIST
;
431 ParaList
->Length
= (UINT8
) (ConfigData
->NvData
.TargetInfoFromDhcp
? 4 : 3);
432 ParaList
->Data
[0] = DHCP4_TAG_NETMASK
;
433 ParaList
->Data
[1] = DHCP4_TAG_ROUTER
;
434 ParaList
->Data
[2] = DHCP4_TAG_DNS
;
435 ParaList
->Data
[3] = DHCP4_TAG_ROOT_PATH
;
437 ZeroMem (&Dhcp4ConfigData
, sizeof (EFI_DHCP4_CONFIG_DATA
));
438 Dhcp4ConfigData
.OptionCount
= 1;
439 Dhcp4ConfigData
.OptionList
= &ParaList
;
441 if (ConfigData
->NvData
.TargetInfoFromDhcp
) {
443 // Use callback to select an offer which contains target information.
445 Dhcp4ConfigData
.Dhcp4Callback
= IScsiDhcpSelectOffer
;
446 Dhcp4ConfigData
.CallbackContext
= &ConfigData
->NvData
;
449 Status
= Dhcp4
->Configure (Dhcp4
, &Dhcp4ConfigData
);
450 if (EFI_ERROR (Status
)) {
454 Status
= Dhcp4
->Start (Dhcp4
, NULL
);
455 if (EFI_ERROR (Status
)) {
459 // Parse the ACK to get required information.
461 Status
= IScsiParseDhcpAck (Dhcp4
, ConfigData
);
465 if (ParaList
!= NULL
) {
466 gBS
->FreePool (ParaList
);
471 Dhcp4
->Configure (Dhcp4
, NULL
);
475 &gEfiDhcp4ProtocolGuid
,
481 NetLibDestroyServiceChild (
484 &gEfiDhcp4ServiceBindingProtocolGuid
,