3 Copyright (c) 2007 Intel Corporation. All rights reserved
4 This software and associated documentation (if any) is furnished
5 under a license and may only be used or copied in accordance
6 with the terms of the license. Except as permitted by such
7 license, no part of this software or documentation may be
8 reproduced, stored in a retrieval system, or transmitted in any
9 form or by any means without the express written consent of
18 iSCSI DHCP related configuration routines.
22 #include "IScsiImpl.h"
26 IScsiDhcpExtractRootPath (
29 IN ISCSI_SESSION_CONFIG_NVDATA
*ConfigNvData
35 Extract the Root Path option and get the required target information.
39 RootPath - The RootPath.
40 Length - Length of the RootPath option payload.
41 ConfigNvData - The iSCSI session configuration data read from nonvolatile device.
45 EFI_SUCCESS - All required information is extracted from the RootPath option.
46 EFI_NOT_FOUND - The RootPath is not an iSCSI RootPath.
47 EFI_OUT_OF_RESOURCES - Failed to allocate memory.
48 EFI_INVALID_PARAMETER - The RootPath is mal-formatted.
53 UINT8 IScsiRootPathIdLen
;
55 ISCSI_ROOT_PATH_FIELD Fields
[RP_FIELD_IDX_MAX
];
56 ISCSI_ROOT_PATH_FIELD
*Field
;
61 // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>
63 IScsiRootPathIdLen
= (UINT8
) AsciiStrLen (ISCSI_ROOT_PATH_ID
);
65 if ((Length
<= IScsiRootPathIdLen
) || (NetCompareMem (RootPath
, ISCSI_ROOT_PATH_ID
, IScsiRootPathIdLen
) != 0)) {
69 // Skip the iSCSI RootPath ID "iscsi:".
71 RootPath
+= IScsiRootPathIdLen
;
72 Length
= (UINT8
) (Length
- IScsiRootPathIdLen
);
74 TmpStr
= (CHAR8
*) NetAllocatePool (Length
+ 1);
76 return EFI_OUT_OF_RESOURCES
;
79 NetCopyMem (TmpStr
, RootPath
, Length
);
80 TmpStr
[Length
] = '\0';
84 NetZeroMem (&Fields
[0], sizeof (Fields
));
87 // Extract the fields in the Root Path option string.
89 for (FieldIndex
= 0; (FieldIndex
< RP_FIELD_IDX_MAX
) && (Index
< Length
); FieldIndex
++) {
90 if (TmpStr
[Index
] != ISCSI_ROOT_PATH_FIELD_DELIMITER
) {
91 Fields
[FieldIndex
].Str
= &TmpStr
[Index
];
94 while ((TmpStr
[Index
] != ISCSI_ROOT_PATH_FIELD_DELIMITER
) && (Index
< Length
)) {
98 if (TmpStr
[Index
] == ISCSI_ROOT_PATH_FIELD_DELIMITER
) {
99 if (FieldIndex
!= RP_FIELD_IDX_TARGETNAME
) {
100 TmpStr
[Index
] = '\0';
104 if (Fields
[FieldIndex
].Str
!= NULL
) {
105 Fields
[FieldIndex
].Len
= (UINT8
) AsciiStrLen (Fields
[FieldIndex
].Str
);
110 if (FieldIndex
!= RP_FIELD_IDX_MAX
) {
111 Status
= EFI_INVALID_PARAMETER
;
115 if ((Fields
[RP_FIELD_IDX_SERVERNAME
].Str
== NULL
) ||
116 (Fields
[RP_FIELD_IDX_TARGETNAME
].Str
== NULL
) ||
117 (Fields
[RP_FIELD_IDX_PROTOCOL
].Len
> 1)
120 Status
= EFI_INVALID_PARAMETER
;
124 // Get the IP address of the target.
126 Field
= &Fields
[RP_FIELD_IDX_SERVERNAME
];
127 Status
= IScsiAsciiStrToIp (Field
->Str
, &ConfigNvData
->TargetIp
);
128 if (EFI_ERROR (Status
)) {
132 // Check the protocol type.
134 Field
= &Fields
[RP_FIELD_IDX_PROTOCOL
];
135 if ((Field
->Str
!= NULL
) && ((*(Field
->Str
) - '0') != EFI_IP_PROTO_TCP
)) {
136 Status
= EFI_INVALID_PARAMETER
;
140 // Get the port of the iSCSI target.
142 Field
= &Fields
[RP_FIELD_IDX_PORT
];
143 if (Field
->Str
!= NULL
) {
144 ConfigNvData
->TargetPort
= (UINT16
) AsciiStrDecimalToUintn (Field
->Str
);
146 ConfigNvData
->TargetPort
= ISCSI_WELL_KNOWN_PORT
;
151 Field
= &Fields
[RP_FIELD_IDX_LUN
];
152 if (Field
->Str
!= NULL
) {
153 Status
= IScsiAsciiStrToLun (Field
->Str
, ConfigNvData
->BootLun
);
154 if (EFI_ERROR (Status
)) {
158 NetZeroMem (ConfigNvData
->BootLun
, sizeof (ConfigNvData
->BootLun
));
161 // Get the target iSCSI Name.
163 Field
= &Fields
[RP_FIELD_IDX_TARGETNAME
];
165 if (AsciiStrLen (Field
->Str
) > ISCSI_NAME_MAX_SIZE
- 1) {
166 Status
= EFI_INVALID_PARAMETER
;
170 // Validate the iSCSI name.
172 Status
= IScsiNormalizeName (Field
->Str
, AsciiStrLen (Field
->Str
));
173 if (EFI_ERROR (Status
)) {
177 AsciiStrCpy (ConfigNvData
->TargetName
, Field
->Str
);
181 NetFreePool (TmpStr
);
188 IScsiDhcpSelectOffer (
189 IN EFI_DHCP4_PROTOCOL
* This
,
191 IN EFI_DHCP4_STATE CurrentState
,
192 IN EFI_DHCP4_EVENT Dhcp4Event
,
193 IN EFI_DHCP4_PACKET
* Packet
, OPTIONAL
194 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
200 The callback function registerd to the DHCP4 instance which is used to select
201 the qualified DHCP OFFER.
205 This - The DHCP4 protocol.
206 Context - The context set when configuring the DHCP4 protocol.
207 CurrentState - The current state of the DHCP4 protocol.
208 Dhcp4Event - The event occurs in the current state.
209 Packet - The DHCP packet that is to be sent or already received.
210 NewPackt - The packet used to replace the above Packet.
214 EFI_NOT_READY - The DHCP OFFER packet doesn't match our requirements.
215 EFI_SUCCESS - Either the DHCP OFFER is qualified or we're not intereseted
222 EFI_DHCP4_PACKET_OPTION
**OptionList
;
225 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) && (Dhcp4Event
!= Dhcp4SelectOffer
)) {
231 Status
= This
->Parse (This
, Packet
, &OptionCount
, NULL
);
232 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
233 return EFI_NOT_READY
;
236 OptionList
= NetAllocatePool (OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*));
237 if (OptionList
== NULL
) {
238 return EFI_NOT_READY
;
241 Status
= This
->Parse (This
, Packet
, &OptionCount
, OptionList
);
242 if (EFI_ERROR (Status
)) {
243 NetFreePool (OptionList
);
244 return EFI_NOT_READY
;
247 for (Index
= 0; Index
< OptionCount
; Index
++) {
248 if (OptionList
[Index
]->OpCode
!= DHCP4_TAG_ROOT_PATH
) {
252 Status
= IScsiDhcpExtractRootPath (
253 (CHAR8
*) &OptionList
[Index
]->Data
[0],
254 OptionList
[Index
]->Length
,
255 (ISCSI_SESSION_CONFIG_NVDATA
*) Context
261 if ((Index
== OptionCount
)) {
262 Status
= EFI_NOT_READY
;
265 NetFreePool (OptionList
);
272 IN EFI_DHCP4_PROTOCOL
*Dhcp4
,
273 IN ISCSI_SESSION_CONFIG_DATA
*ConfigData
279 Parse the DHCP ACK to get the address configuration and DNS information.
283 Dhcp4 - The DHCP4 protocol.
284 ConfigData - The session configuration data.
288 EFI_SUCCESS - The DNS information is got from the DHCP ACK.
289 EFI_NO_MAPPING - DHCP failed to acquire address and other information.
290 EFI_INVALID_PARAMETER - The DHCP ACK's DNS option is mal-formatted.
291 EFI_DEVICE_ERROR - Some unexpected error happened.
296 EFI_DHCP4_MODE_DATA Dhcp4ModeData
;
298 EFI_DHCP4_PACKET_OPTION
**OptionList
;
301 Status
= Dhcp4
->GetModeData (Dhcp4
, &Dhcp4ModeData
);
302 if (EFI_ERROR (Status
)) {
306 if (Dhcp4ModeData
.State
!= Dhcp4Bound
) {
307 return EFI_NO_MAPPING
;
310 NetCopyMem (&ConfigData
->NvData
.LocalIp
, &Dhcp4ModeData
.ClientAddress
, sizeof (EFI_IPv4_ADDRESS
));
311 NetCopyMem (&ConfigData
->NvData
.SubnetMask
, &Dhcp4ModeData
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
312 NetCopyMem (&ConfigData
->NvData
.Gateway
, &Dhcp4ModeData
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
317 Status
= Dhcp4
->Parse (Dhcp4
, Dhcp4ModeData
.ReplyPacket
, &OptionCount
, OptionList
);
318 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
319 return EFI_DEVICE_ERROR
;
322 OptionList
= NetAllocatePool (OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*));
323 if (OptionList
== NULL
) {
324 return EFI_OUT_OF_RESOURCES
;
327 Status
= Dhcp4
->Parse (Dhcp4
, Dhcp4ModeData
.ReplyPacket
, &OptionCount
, OptionList
);
328 if (EFI_ERROR (Status
)) {
329 NetFreePool (OptionList
);
330 return EFI_DEVICE_ERROR
;
333 for (Index
= 0; Index
< OptionCount
; Index
++) {
335 // Get DNS server addresses and DHCP server address from this offer.
337 if (OptionList
[Index
]->OpCode
== DHCP4_TAG_DNS
) {
339 if (((OptionList
[Index
]->Length
& 0x3) != 0) || (OptionList
[Index
]->Length
== 0)) {
340 Status
= EFI_INVALID_PARAMETER
;
344 // Primary DNS server address.
346 NetCopyMem (&ConfigData
->PrimaryDns
, &OptionList
[Index
]->Data
[0], sizeof (EFI_IPv4_ADDRESS
));
348 if (OptionList
[Index
]->Length
> 4) {
350 // Secondary DNS server address
352 NetCopyMem (&ConfigData
->SecondaryDns
, &OptionList
[Index
]->Data
[4], sizeof (EFI_IPv4_ADDRESS
));
354 } else if (OptionList
[Index
]->OpCode
== DHCP4_TAG_SERVER_ID
) {
355 if (OptionList
[Index
]->Length
!= 4) {
356 Status
= EFI_INVALID_PARAMETER
;
360 NetCopyMem (&ConfigData
->DhcpServer
, &OptionList
[Index
]->Data
[0], sizeof (EFI_IPv4_ADDRESS
));
364 NetFreePool (OptionList
);
372 IN EFI_HANDLE Controller
,
373 IN ISCSI_SESSION_CONFIG_DATA
*ConfigData
379 Parse the DHCP ACK to get the address configuration and DNS information.
383 Image - The handle of the driver image.
384 Controller - The handle of the controller;
385 ConfigData - The session configuration data.
389 EFI_SUCCESS - The DNS information is got from the DHCP ACK.
390 EFI_NO_MAPPING - DHCP failed to acquire address and other information.
391 EFI_INVALID_PARAMETER - The DHCP ACK's DNS option is mal-formatted.
392 EFI_DEVICE_ERROR - Some unexpected error happened.
396 EFI_HANDLE Dhcp4Handle
;
397 EFI_DHCP4_PROTOCOL
*Dhcp4
;
399 EFI_DHCP4_PACKET_OPTION
*ParaList
;
400 EFI_DHCP4_CONFIG_DATA Dhcp4ConfigData
;
407 // Create a DHCP4 child instance and get the protocol.
409 Status
= NetLibCreateServiceChild (
412 &gEfiDhcp4ServiceBindingProtocolGuid
,
415 if (EFI_ERROR (Status
)) {
419 Status
= gBS
->OpenProtocol (
421 &gEfiDhcp4ProtocolGuid
,
425 EFI_OPEN_PROTOCOL_BY_DRIVER
427 if (EFI_ERROR (Status
)) {
431 ParaList
= NetAllocatePool (sizeof (EFI_DHCP4_PACKET_OPTION
) + 3);
432 if (ParaList
== NULL
) {
433 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
)(ConfigData
->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
;
444 ParaList
->Data
[3] = DHCP4_TAG_ROOT_PATH
;
446 NetZeroMem (&Dhcp4ConfigData
, sizeof (EFI_DHCP4_CONFIG_DATA
));
447 Dhcp4ConfigData
.OptionCount
= 1;
448 Dhcp4ConfigData
.OptionList
= &ParaList
;
450 if (ConfigData
->NvData
.TargetInfoFromDhcp
) {
452 // Use callback to select an offer which contains target information.
454 Dhcp4ConfigData
.Dhcp4Callback
= IScsiDhcpSelectOffer
;
455 Dhcp4ConfigData
.CallbackContext
= &ConfigData
->NvData
;
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
) {
475 NetFreePool (ParaList
);
480 Dhcp4
->Configure (Dhcp4
, NULL
);
484 &gEfiDhcp4ProtocolGuid
,
490 NetLibDestroyServiceChild (
493 &gEfiDhcp4ServiceBindingProtocolGuid
,