3 Copyright (c) 2004 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
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
) || (CompareMem (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
*) AllocatePool (Length
+ 1);
76 return EFI_OUT_OF_RESOURCES
;
79 CopyMem (TmpStr
, RootPath
, Length
);
80 TmpStr
[Length
] = '\0';
84 ZeroMem (&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 ZeroMem (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 gBS
->FreePool (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
= AllocatePool (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 gBS
->FreePool (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 gBS
->FreePool (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 CopyMem (&ConfigData
->NvData
.LocalIp
, &Dhcp4ModeData
.ClientAddress
, sizeof (EFI_IPv4_ADDRESS
));
311 CopyMem (&ConfigData
->NvData
.SubnetMask
, &Dhcp4ModeData
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
312 CopyMem (&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
= AllocatePool (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 gBS
->FreePool (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 CopyMem (&ConfigData
->PrimaryDns
, &OptionList
[Index
]->Data
[0], sizeof (EFI_IPv4_ADDRESS
));
348 if (OptionList
[Index
]->Length
> 4) {
350 // Secondary DNS server address
352 CopyMem (&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 CopyMem (&ConfigData
->DhcpServer
, &OptionList
[Index
]->Data
[0], sizeof (EFI_IPv4_ADDRESS
));
364 gBS
->FreePool (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
= AllocatePool (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 ZeroMem (&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 gBS
->FreePool (ParaList
);
480 Dhcp4
->Configure (Dhcp4
, NULL
);
484 &gEfiDhcp4ProtocolGuid
,
490 NetLibDestroyServiceChild (
493 &gEfiDhcp4ServiceBindingProtocolGuid
,