2 iSCSI DHCP4 related configuration routines.
4 Copyright (c) 2004 - 2016, 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"
19 Extract the Root Path option and get the required target information.
21 @param[in] RootPath The RootPath.
22 @param[in] Length Length of the RootPath option payload.
23 @param[in, out] ConfigData The iSCSI attempt configuration data read
24 from a nonvolatile device.
26 @retval EFI_SUCCESS All required information is extracted from the RootPath option.
27 @retval EFI_NOT_FOUND The RootPath is not an iSCSI RootPath.
28 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
29 @retval EFI_INVALID_PARAMETER The RootPath is malformatted.
33 IScsiDhcpExtractRootPath (
36 IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA
*ConfigData
40 UINT8 IScsiRootPathIdLen
;
42 ISCSI_ROOT_PATH_FIELD Fields
[RP_FIELD_IDX_MAX
];
43 ISCSI_ROOT_PATH_FIELD
*Field
;
46 ISCSI_SESSION_CONFIG_NVDATA
*ConfigNvData
;
50 ConfigNvData
= &ConfigData
->SessionConfigData
;
53 // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>
55 IScsiRootPathIdLen
= (UINT8
) AsciiStrLen (ISCSI_ROOT_PATH_ID
);
57 if ((Length
<= IScsiRootPathIdLen
) || (CompareMem (RootPath
, ISCSI_ROOT_PATH_ID
, IScsiRootPathIdLen
) != 0)) {
61 // Skip the iSCSI RootPath ID "iscsi:".
63 RootPath
+= IScsiRootPathIdLen
;
64 Length
= (UINT8
) (Length
- IScsiRootPathIdLen
);
66 TmpStr
= (CHAR8
*) AllocatePool (Length
+ 1);
68 return EFI_OUT_OF_RESOURCES
;
71 CopyMem (TmpStr
, RootPath
, Length
);
72 TmpStr
[Length
] = '\0';
75 FieldIndex
= RP_FIELD_IDX_SERVERNAME
;
76 ZeroMem (&Fields
[0], sizeof (Fields
));
79 // Extract the fields in the Root Path option string.
81 for (FieldIndex
= RP_FIELD_IDX_SERVERNAME
; (FieldIndex
< RP_FIELD_IDX_MAX
) && (Index
< Length
); FieldIndex
++) {
82 if (TmpStr
[Index
] != ISCSI_ROOT_PATH_FIELD_DELIMITER
) {
83 Fields
[FieldIndex
].Str
= &TmpStr
[Index
];
86 while ((TmpStr
[Index
] != ISCSI_ROOT_PATH_FIELD_DELIMITER
) && (Index
< Length
)) {
90 if (TmpStr
[Index
] == ISCSI_ROOT_PATH_FIELD_DELIMITER
) {
91 if (FieldIndex
!= RP_FIELD_IDX_TARGETNAME
) {
96 if (Fields
[FieldIndex
].Str
!= NULL
) {
97 Fields
[FieldIndex
].Len
= (UINT8
) AsciiStrLen (Fields
[FieldIndex
].Str
);
102 if (FieldIndex
!= RP_FIELD_IDX_MAX
) {
103 Status
= EFI_INVALID_PARAMETER
;
107 if ((Fields
[RP_FIELD_IDX_SERVERNAME
].Str
== NULL
) ||
108 (Fields
[RP_FIELD_IDX_TARGETNAME
].Str
== NULL
) ||
109 (Fields
[RP_FIELD_IDX_PROTOCOL
].Len
> 1)
112 Status
= EFI_INVALID_PARAMETER
;
116 // Get the IP address of the target.
118 Field
= &Fields
[RP_FIELD_IDX_SERVERNAME
];
120 if (ConfigNvData
->IpMode
< IP_MODE_AUTOCONFIG
) {
121 IpMode
= ConfigNvData
->IpMode
;
123 IpMode
= ConfigData
->AutoConfigureMode
;
126 Status
= IScsiAsciiStrToIp (Field
->Str
, IpMode
, &Ip
);
127 CopyMem (&ConfigNvData
->TargetIp
, &Ip
, sizeof (EFI_IP_ADDRESS
));
129 if (EFI_ERROR (Status
)) {
133 // Check the protocol type.
135 Field
= &Fields
[RP_FIELD_IDX_PROTOCOL
];
136 if ((Field
->Str
!= NULL
) && ((*(Field
->Str
) - '0') != EFI_IP_PROTO_TCP
)) {
137 Status
= EFI_INVALID_PARAMETER
;
141 // Get the port of the iSCSI target.
143 Field
= &Fields
[RP_FIELD_IDX_PORT
];
144 if (Field
->Str
!= NULL
) {
145 ConfigNvData
->TargetPort
= (UINT16
) AsciiStrDecimalToUintn (Field
->Str
);
147 ConfigNvData
->TargetPort
= ISCSI_WELL_KNOWN_PORT
;
152 Field
= &Fields
[RP_FIELD_IDX_LUN
];
153 if (Field
->Str
!= NULL
) {
154 Status
= IScsiAsciiStrToLun (Field
->Str
, ConfigNvData
->BootLun
);
155 if (EFI_ERROR (Status
)) {
159 ZeroMem (ConfigNvData
->BootLun
, sizeof (ConfigNvData
->BootLun
));
162 // Get the target iSCSI Name.
164 Field
= &Fields
[RP_FIELD_IDX_TARGETNAME
];
166 if (AsciiStrLen (Field
->Str
) > ISCSI_NAME_MAX_SIZE
- 1) {
167 Status
= EFI_INVALID_PARAMETER
;
171 // Validate the iSCSI name.
173 Status
= IScsiNormalizeName (Field
->Str
, AsciiStrLen (Field
->Str
));
174 if (EFI_ERROR (Status
)) {
178 AsciiStrCpyS (ConfigNvData
->TargetName
, ISCSI_NAME_MAX_SIZE
, Field
->Str
);
188 The callback function registerd to the DHCP4 instance that is used to select
189 the qualified DHCP OFFER.
191 @param[in] This The DHCP4 protocol.
192 @param[in] Context The context set when configuring the DHCP4 protocol.
193 @param[in] CurrentState The current state of the DHCP4 protocol.
194 @param[in] Dhcp4Event The event occurs in the current state.
195 @param[in] Packet The DHCP packet that is to be sent or was already received.
196 @param[out] NewPacket The packet used to replace the above Packet.
198 @retval EFI_SUCCESS Either the DHCP OFFER is qualified or we're not intereseted
200 @retval EFI_NOT_READY The DHCP OFFER packet doesn't match our requirements.
201 @retval Others Other errors as indicated.
206 IScsiDhcpSelectOffer (
207 IN EFI_DHCP4_PROTOCOL
*This
,
209 IN EFI_DHCP4_STATE CurrentState
,
210 IN EFI_DHCP4_EVENT Dhcp4Event
,
211 IN EFI_DHCP4_PACKET
*Packet
, OPTIONAL
212 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
217 EFI_DHCP4_PACKET_OPTION
**OptionList
;
220 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) && (Dhcp4Event
!= Dhcp4SelectOffer
)) {
226 Status
= This
->Parse (This
, Packet
, &OptionCount
, NULL
);
227 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
228 return EFI_NOT_READY
;
231 OptionList
= AllocatePool (OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*));
232 if (OptionList
== NULL
) {
233 return EFI_NOT_READY
;
236 Status
= This
->Parse (This
, Packet
, &OptionCount
, OptionList
);
237 if (EFI_ERROR (Status
)) {
238 FreePool (OptionList
);
239 return EFI_NOT_READY
;
242 for (Index
= 0; Index
< OptionCount
; Index
++) {
243 if (OptionList
[Index
]->OpCode
!= DHCP4_TAG_ROOTPATH
) {
247 Status
= IScsiDhcpExtractRootPath (
248 (CHAR8
*) &OptionList
[Index
]->Data
[0],
249 OptionList
[Index
]->Length
,
250 (ISCSI_ATTEMPT_CONFIG_NVDATA
*) Context
256 if ((Index
== OptionCount
)) {
257 Status
= EFI_NOT_READY
;
260 FreePool (OptionList
);
266 Parse the DHCP ACK to get the address configuration and DNS information.
268 @param[in] Dhcp4 The DHCP4 protocol.
269 @param[in, out] ConfigData The session configuration data.
271 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
272 @retval EFI_NO_MAPPING DHCP failed to acquire address and other information.
273 @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is malformatted.
274 @retval EFI_DEVICE_ERROR Other errors as indicated.
275 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
280 IN EFI_DHCP4_PROTOCOL
*Dhcp4
,
281 IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA
*ConfigData
285 EFI_DHCP4_MODE_DATA Dhcp4ModeData
;
287 EFI_DHCP4_PACKET_OPTION
**OptionList
;
289 ISCSI_SESSION_CONFIG_NVDATA
*NvData
;
291 Status
= Dhcp4
->GetModeData (Dhcp4
, &Dhcp4ModeData
);
292 if (EFI_ERROR (Status
)) {
296 if (Dhcp4ModeData
.State
!= Dhcp4Bound
) {
297 return EFI_NO_MAPPING
;
300 NvData
= &ConfigData
->SessionConfigData
;
302 CopyMem (&NvData
->LocalIp
, &Dhcp4ModeData
.ClientAddress
, sizeof (EFI_IPv4_ADDRESS
));
303 CopyMem (&NvData
->SubnetMask
, &Dhcp4ModeData
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
304 CopyMem (&NvData
->Gateway
, &Dhcp4ModeData
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
309 Status
= Dhcp4
->Parse (Dhcp4
, Dhcp4ModeData
.ReplyPacket
, &OptionCount
, OptionList
);
310 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
311 return EFI_DEVICE_ERROR
;
314 OptionList
= AllocatePool (OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*));
315 if (OptionList
== NULL
) {
316 return EFI_OUT_OF_RESOURCES
;
319 Status
= Dhcp4
->Parse (Dhcp4
, Dhcp4ModeData
.ReplyPacket
, &OptionCount
, OptionList
);
320 if (EFI_ERROR (Status
)) {
321 FreePool (OptionList
);
322 return EFI_DEVICE_ERROR
;
325 for (Index
= 0; Index
< OptionCount
; Index
++) {
327 // Get DNS server addresses and DHCP server address from this offer.
329 if (OptionList
[Index
]->OpCode
== DHCP4_TAG_DNS_SERVER
) {
331 if (((OptionList
[Index
]->Length
& 0x3) != 0) || (OptionList
[Index
]->Length
== 0)) {
332 Status
= EFI_INVALID_PARAMETER
;
336 // Primary DNS server address.
338 CopyMem (&ConfigData
->PrimaryDns
, &OptionList
[Index
]->Data
[0], sizeof (EFI_IPv4_ADDRESS
));
340 if (OptionList
[Index
]->Length
> 4) {
342 // Secondary DNS server address.
344 CopyMem (&ConfigData
->SecondaryDns
, &OptionList
[Index
]->Data
[4], sizeof (EFI_IPv4_ADDRESS
));
346 } else if (OptionList
[Index
]->OpCode
== DHCP4_TAG_SERVER_ID
) {
347 if (OptionList
[Index
]->Length
!= 4) {
348 Status
= EFI_INVALID_PARAMETER
;
352 CopyMem (&ConfigData
->DhcpServer
, &OptionList
[Index
]->Data
[0], sizeof (EFI_IPv4_ADDRESS
));
356 FreePool (OptionList
);
363 Parse the DHCP ACK to get the address configuration and DNS information.
365 @param[in] Image The handle of the driver image.
366 @param[in] Controller The handle of the controller.
367 @param[in, out] ConfigData The attempt configuration data.
369 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
370 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
371 @retval EFI_NO_MEDIA There was a media error.
372 @retval Others Other errors as indicated.
378 IN EFI_HANDLE Controller
,
379 IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA
*ConfigData
382 EFI_HANDLE Dhcp4Handle
;
383 EFI_DHCP4_PROTOCOL
*Dhcp4
;
385 EFI_DHCP4_PACKET_OPTION
*ParaList
;
386 EFI_DHCP4_CONFIG_DATA Dhcp4ConfigData
;
387 ISCSI_SESSION_CONFIG_NVDATA
*NvData
;
388 BOOLEAN MediaPresent
;
395 // Check media status before doing DHCP.
398 NetLibDetectMedia (Controller
, &MediaPresent
);
404 // Create a DHCP4 child instance and get the protocol.
406 Status
= NetLibCreateServiceChild (
409 &gEfiDhcp4ServiceBindingProtocolGuid
,
412 if (EFI_ERROR (Status
)) {
416 Status
= gBS
->OpenProtocol (
418 &gEfiDhcp4ProtocolGuid
,
422 EFI_OPEN_PROTOCOL_BY_DRIVER
424 if (EFI_ERROR (Status
)) {
428 NvData
= &ConfigData
->SessionConfigData
;
430 ParaList
= AllocatePool (sizeof (EFI_DHCP4_PACKET_OPTION
) + 3);
431 if (ParaList
== NULL
) {
432 Status
= EFI_OUT_OF_RESOURCES
;
437 // Ask the server to reply with Netmask, Router, DNS, and RootPath options.
439 ParaList
->OpCode
= DHCP4_TAG_PARA_LIST
;
440 ParaList
->Length
= (UINT8
) (NvData
->TargetInfoFromDhcp
? 4 : 3);
441 ParaList
->Data
[0] = DHCP4_TAG_NETMASK
;
442 ParaList
->Data
[1] = DHCP4_TAG_ROUTER
;
443 ParaList
->Data
[2] = DHCP4_TAG_DNS_SERVER
;
444 ParaList
->Data
[3] = DHCP4_TAG_ROOTPATH
;
446 ZeroMem (&Dhcp4ConfigData
, sizeof (EFI_DHCP4_CONFIG_DATA
));
447 Dhcp4ConfigData
.OptionCount
= 1;
448 Dhcp4ConfigData
.OptionList
= &ParaList
;
450 if (NvData
->TargetInfoFromDhcp
) {
452 // Use callback to select an offer that contains target information.
454 Dhcp4ConfigData
.Dhcp4Callback
= IScsiDhcpSelectOffer
;
455 Dhcp4ConfigData
.CallbackContext
= ConfigData
;
458 Status
= Dhcp4
->Configure (Dhcp4
, &Dhcp4ConfigData
);
459 if (EFI_ERROR (Status
)) {
463 Status
= Dhcp4
->Start (Dhcp4
, NULL
);
464 if (EFI_ERROR (Status
)) {
468 // Parse the ACK to get required information.
470 Status
= IScsiParseDhcpAck (Dhcp4
, ConfigData
);
474 if (ParaList
!= NULL
) {
480 Dhcp4
->Configure (Dhcp4
, NULL
);
484 &gEfiDhcp4ProtocolGuid
,
490 NetLibDestroyServiceChild (
493 &gEfiDhcp4ServiceBindingProtocolGuid
,