3 Copyright (c) 2006 - 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 This code implements the IP4Config and NicIp4Config protocols.
23 #include "Ip4Config.h"
25 IP4_CONFIG_INSTANCE
*mIp4ConfigNicList
[MAX_IP4_CONFIG_IN_VARIABLE
];
29 Ip4ConfigOnDhcp4Complete (
36 Return the name and MAC address for the NIC. The Name, if not NULL,
37 has at least IP4_NIC_NAME_LENGTH bytes.
39 @param This The NIC IP4 CONFIG protocol
40 @param Name The buffer to return the name
41 @param NicAddr The buffer to return the MAC addr
43 @retval EFI_INVALID_PARAMETER This is NULL
44 @retval EFI_SUCCESS The name or address of the NIC are returned.
50 EfiNicIp4ConfigGetName (
51 IN EFI_NIC_IP4_CONFIG_PROTOCOL
*This
,
52 IN UINT16
*Name
, OPTIONAL
53 IN NIC_ADDR
*NicAddr OPTIONAL
56 IP4_CONFIG_INSTANCE
*Instance
;
59 return EFI_INVALID_PARAMETER
;
62 Instance
= IP4_CONFIG_INSTANCE_FROM_NIC_IP4CONFIG (This
);
65 CopyMem (Name
, Instance
->NicName
, IP4_NIC_NAME_LENGTH
);
68 if (NicAddr
!= NULL
) {
69 CopyMem (NicAddr
, &Instance
->NicAddr
, sizeof (*NicAddr
));
77 Get the NIC's configure information from the IP4 configure variable.
78 It will remove the invalid variable.
80 @param NicAddr The NIC to check
82 @return NULL if no configure for the NIC in the variable, or it is invalid.
83 @return Otherwise the NIC's IP configure parameter.
91 IP4_CONFIG_VARIABLE
*Variable
;
92 IP4_CONFIG_VARIABLE
*NewVariable
;
93 NIC_IP4_CONFIG_INFO
*Config
;
96 // Read the configuration parameter for this NicAddr from
99 Variable
= Ip4ConfigReadVariable ();
101 if (Variable
== NULL
) {
105 Config
= Ip4ConfigFindNicVariable (Variable
, NicAddr
);
107 if (Config
== NULL
) {
108 gBS
->FreePool (Variable
);
113 // Validate the configuration, if the configuration is invalid,
114 // remove it from the variable.
116 if (!Ip4ConfigIsValid (Config
)) {
117 NewVariable
= Ip4ConfigModifyVariable (Variable
, &Config
->NicAddr
, NULL
);
118 Ip4ConfigWriteVariable (NewVariable
);
120 if (NewVariable
!= NULL
) {
121 gBS
->FreePool (NewVariable
);
124 gBS
->FreePool (Config
);
128 gBS
->FreePool (Variable
);
134 Get the configure parameter for this NIC.
136 @param This The NIC IP4 CONFIG protocol
137 @param ConfigLen The length of the NicConfig buffer.
138 @param NicConfig The buffer to receive the NIC's configure
141 @retval EFI_INVALID_PARAMETER This or ConfigLen is NULL
142 @retval EFI_NOT_FOUND There is no configure parameter for the NIC in
148 EfiNicIp4ConfigGetInfo (
149 IN EFI_NIC_IP4_CONFIG_PROTOCOL
*This
,
150 IN OUT UINTN
*ConfigLen
,
151 OUT NIC_IP4_CONFIG_INFO
*NicConfig
154 IP4_CONFIG_INSTANCE
*Instance
;
155 NIC_IP4_CONFIG_INFO
*Config
;
159 if ((This
== NULL
) || (ConfigLen
== NULL
)) {
160 return EFI_INVALID_PARAMETER
;
164 // Read the Nic's configuration parameter from variable
166 Instance
= IP4_CONFIG_INSTANCE_FROM_NIC_IP4CONFIG (This
);
167 Config
= Ip4ConfigGetNicInfo (&Instance
->NicAddr
);
169 if (Config
== NULL
) {
170 return EFI_NOT_FOUND
;
174 // Copy the data to user's buffer
176 Len
= SIZEOF_NIC_IP4_CONFIG_INFO (Config
);
178 if ((*ConfigLen
< Len
) || (NicConfig
== NULL
)) {
179 Status
= EFI_BUFFER_TOO_SMALL
;
181 Status
= EFI_SUCCESS
;
182 CopyMem (NicConfig
, Config
, Len
);
187 gBS
->FreePool (Config
);
193 Set the IP configure parameters for this NIC. If Reconfig is TRUE,
194 the IP driver will be informed to discard current auto configure
195 parameter and restart the auto configuration process. If current
196 there is a pending auto configuration, EFI_ALREADY_STARTED is
197 returned. You can only change the configure setting when either
198 the configure has finished or not started yet. If NicConfig, the
199 NIC's configure parameter is removed from the variable.
201 @param This The NIC IP4 CONFIG protocol
202 @param NicConfig The new NIC IP4 configure parameter
203 @param Reconfig Inform the IP4 driver to restart the auto
206 @retval EFI_INVALID_PARAMETER This is NULL or the configure parameter is
208 @retval EFI_ALREADY_STARTED There is a pending auto configuration.
209 @retval EFI_NOT_FOUND No auto configure parameter is found
214 EfiNicIp4ConfigSetInfo (
215 IN EFI_NIC_IP4_CONFIG_PROTOCOL
*This
,
216 IN NIC_IP4_CONFIG_INFO
*NicConfig
, OPTIONAL
220 IP4_CONFIG_INSTANCE
*Instance
;
221 IP4_CONFIG_VARIABLE
*Variable
;
222 IP4_CONFIG_VARIABLE
*NewVariable
;
226 // Validate the parameters
229 return EFI_INVALID_PARAMETER
;
232 Instance
= IP4_CONFIG_INSTANCE_FROM_NIC_IP4CONFIG (This
);
234 if ((NicConfig
!= NULL
) && (!Ip4ConfigIsValid (NicConfig
) ||
235 !NIC_ADDR_EQUAL (&NicConfig
->NicAddr
, &Instance
->NicAddr
))) {
236 return EFI_INVALID_PARAMETER
;
239 if (Instance
->State
== IP4_CONFIG_STATE_STARTED
) {
240 return EFI_ALREADY_STARTED
;
244 // Update the parameter in the configure variable
246 Variable
= Ip4ConfigReadVariable ();
248 if ((Variable
== NULL
) && (NicConfig
== NULL
)) {
249 return EFI_NOT_FOUND
;
252 NewVariable
= Ip4ConfigModifyVariable (Variable
, &Instance
->NicAddr
, NicConfig
);
253 Status
= Ip4ConfigWriteVariable (NewVariable
);
255 if (NewVariable
!= NULL
) {
256 gBS
->FreePool (NewVariable
);
260 // Variable is NULL when saving the first configure parameter
262 if (Variable
!= NULL
) {
263 gBS
->FreePool (Variable
);
266 if (EFI_ERROR (Status
)) {
271 // Signal the IP4 to run the auto configuration again
273 if (Reconfig
&& (Instance
->ReconfigEvent
!= NULL
)) {
274 Status
= gBS
->SignalEvent (Instance
->ReconfigEvent
);
282 Start the auto configuration process.
284 @param This The IP4 configure protocol
285 @param DoneEvent The event to signal when auto configure is done
286 @param ReconfigEvent The event to signal when reconfigure is necessary.
288 @retval EFI_INVALID_PARAMETER One of the function parameters is NULL.
289 @retval EFI_ALREADY_STARTED The auto configuration has already started.
290 @retval EFI_SUCCESS The auto configure is successfully started.
296 IN EFI_IP4_CONFIG_PROTOCOL
*This
,
297 IN EFI_EVENT DoneEvent
,
298 IN EFI_EVENT ReconfigEvent
301 IP4_CONFIG_INSTANCE
*Instance
;
302 EFI_DHCP4_PROTOCOL
*Dhcp4
;
303 EFI_DHCP4_MODE_DATA Dhcp4Mode
;
304 EFI_DHCP4_PACKET_OPTION
*OptionList
[1];
305 IP4_CONFIG_DHCP4_OPTION ParaList
;
310 if ((This
== NULL
) || (DoneEvent
== NULL
) || (ReconfigEvent
== NULL
)) {
311 return EFI_INVALID_PARAMETER
;
314 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
316 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
318 if (Instance
->State
!= IP4_CONFIG_STATE_IDLE
) {
319 Status
= EFI_ALREADY_STARTED
;
324 Instance
->DoneEvent
= DoneEvent
;
325 Instance
->ReconfigEvent
= ReconfigEvent
;
327 Instance
->NicConfig
= Ip4ConfigGetNicInfo (&Instance
->NicAddr
);
329 if (Instance
->NicConfig
== NULL
) {
330 Source
= IP4_CONFIG_SOURCE_DHCP
;
332 Source
= Instance
->NicConfig
->Source
;
336 // If the source is static, the auto configuration is done.
339 if (Source
== IP4_CONFIG_SOURCE_STATIC
) {
340 Instance
->State
= IP4_CONFIG_STATE_CONFIGURED
;
341 Instance
->Result
= EFI_SUCCESS
;
343 gBS
->SignalEvent (Instance
->DoneEvent
);
344 Status
= EFI_SUCCESS
;
349 // Start the dhcp process
351 ASSERT ((Source
== IP4_CONFIG_SOURCE_DHCP
) && (Instance
->Dhcp4
== NULL
));
353 Status
= NetLibCreateServiceChild (
354 Instance
->Controller
,
356 &gEfiDhcp4ServiceBindingProtocolGuid
,
357 &Instance
->Dhcp4Handle
360 if (EFI_ERROR (Status
)) {
364 Status
= gBS
->OpenProtocol (
365 Instance
->Dhcp4Handle
,
366 &gEfiDhcp4ProtocolGuid
,
367 (VOID
**) &Instance
->Dhcp4
,
369 Instance
->Controller
,
370 EFI_OPEN_PROTOCOL_BY_DRIVER
373 if (EFI_ERROR (Status
)) {
378 // Check the current DHCP status, if the DHCP process has
379 // already finished, return now.
381 Dhcp4
= Instance
->Dhcp4
;
382 Status
= Dhcp4
->GetModeData (Dhcp4
, &Dhcp4Mode
);
384 if (EFI_ERROR (Status
)) {
388 if (Dhcp4Mode
.State
== Dhcp4Bound
) {
389 Ip4ConfigOnDhcp4Complete (NULL
, Instance
);
395 // Try to start the DHCP process. Use most of the current
396 // DHCP configuration to avoid problems if some DHCP client
397 // yields the control of this DHCP service to us.
399 ParaList
.Head
.OpCode
= DHCP_TAG_PARA_LIST
;
400 ParaList
.Head
.Length
= 2;
401 ParaList
.Head
.Data
[0] = DHCP_TAG_NETMASK
;
402 ParaList
.Route
= DHCP_TAG_ROUTER
;
403 OptionList
[0] = &ParaList
.Head
;
404 Dhcp4Mode
.ConfigData
.OptionCount
= 1;
405 Dhcp4Mode
.ConfigData
.OptionList
= OptionList
;
407 Status
= Dhcp4
->Configure (Dhcp4
, &Dhcp4Mode
.ConfigData
);
409 if (EFI_ERROR (Status
)) {
414 // Start the DHCP process
416 Status
= gBS
->CreateEvent (
419 Ip4ConfigOnDhcp4Complete
,
421 &Instance
->Dhcp4Event
424 if (EFI_ERROR (Status
)) {
428 Status
= Dhcp4
->Start (Dhcp4
, Instance
->Dhcp4Event
);
430 if (EFI_ERROR (Status
)) {
434 Instance
->State
= IP4_CONFIG_STATE_STARTED
;
435 Instance
->Result
= EFI_NOT_READY
;
438 if (EFI_ERROR (Status
)) {
439 Ip4ConfigCleanConfig (Instance
);
443 gBS
->RestoreTPL (OldTpl
);
450 Stop the current auto configuration
452 @param This The IP4 CONFIG protocol
454 @retval EFI_INVALID_PARAMETER This is NULL.
455 @retval EFI_NOT_STARTED The auto configuration hasn't been started.
456 @retval EFI_SUCCESS The auto configuration has been stopped.
462 IN EFI_IP4_CONFIG_PROTOCOL
*This
465 IP4_CONFIG_INSTANCE
*Instance
;
470 return EFI_INVALID_PARAMETER
;
473 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
475 Status
= EFI_SUCCESS
;
476 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
478 if (Instance
->State
== IP4_CONFIG_STATE_IDLE
) {
479 Status
= EFI_NOT_STARTED
;
484 // Release all the configure parameters. Don't signal the user
485 // event. The user wants to abort the configuration, this isn't
486 // the configuration done or reconfiguration.
488 Ip4ConfigCleanConfig (Instance
);
491 gBS
->RestoreTPL (OldTpl
);
498 Get the current outcome of the auto configuration process
500 @param This The IP4 CONFIG protocol
501 @param ConfigDataSize The size of the configure data
502 @param ConfigData The buffer to save the configure data
504 @retval EFI_INVALID_PARAMETER This or ConfigDataSize is NULL
505 @retval EFI_BUFFER_TOO_SMALL The buffer is too small. The needed size is
506 returned in the ConfigDataSize.
507 @retval EFI_SUCCESS The configure data is put in the buffer
512 EfiIp4ConfigGetData (
513 IN EFI_IP4_CONFIG_PROTOCOL
*This
,
514 IN OUT UINTN
*ConfigDataSize
,
515 OUT EFI_IP4_IPCONFIG_DATA
*ConfigData OPTIONAL
518 IP4_CONFIG_INSTANCE
*Instance
;
519 NIC_IP4_CONFIG_INFO
*NicConfig
;
524 if ((This
== NULL
) || (ConfigDataSize
== NULL
)) {
525 return EFI_INVALID_PARAMETER
;
528 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
530 Status
= EFI_SUCCESS
;
531 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
533 if (Instance
->State
== IP4_CONFIG_STATE_IDLE
) {
534 Status
= EFI_NOT_STARTED
;
535 } else if (Instance
->State
== IP4_CONFIG_STATE_STARTED
) {
536 Status
= EFI_NOT_READY
;
539 if (EFI_ERROR (Status
)) {
544 // Copy the configure data if auto configuration succeeds.
546 Status
= Instance
->Result
;
548 if (Status
== EFI_SUCCESS
) {
549 ASSERT (Instance
->NicConfig
!= NULL
);
551 NicConfig
= Instance
->NicConfig
;
552 Len
= SIZEOF_IP4_CONFIG_INFO (&NicConfig
->Ip4Info
);
554 if ((*ConfigDataSize
< Len
) || (ConfigData
== NULL
)) {
555 Status
= EFI_BUFFER_TOO_SMALL
;
557 CopyMem (ConfigData
, &NicConfig
->Ip4Info
, Len
);
560 *ConfigDataSize
= Len
;
564 gBS
->RestoreTPL (OldTpl
);
571 Callback function when DHCP process finished. It will save the
572 retrieved IP configure parameter from DHCP to the NVRam.
574 @param Event The callback event
575 @param Context Opaque context to the callback
582 Ip4ConfigOnDhcp4Complete (
587 IP4_CONFIG_INSTANCE
*Instance
;
588 EFI_DHCP4_MODE_DATA Dhcp4Mode
;
589 EFI_IP4_IPCONFIG_DATA
*Ip4Config
;
596 Instance
= (IP4_CONFIG_INSTANCE
*) Context
;
597 ASSERT (Instance
->Dhcp4
!= NULL
);
599 Instance
->State
= IP4_CONFIG_STATE_CONFIGURED
;
600 Instance
->Result
= EFI_TIMEOUT
;
603 // Get the DHCP retrieved parameters
605 Status
= Instance
->Dhcp4
->GetModeData (Instance
->Dhcp4
, &Dhcp4Mode
);
607 if (EFI_ERROR (Status
)) {
611 if (Dhcp4Mode
.State
== Dhcp4Bound
) {
613 // Save the new configuration retrieved by DHCP both in
614 // the instance and to NVRam. So, both the IP4 driver and
615 // other user can get that address.
619 if (Instance
->NicConfig
!= NULL
) {
620 ASSERT (Instance
->NicConfig
->Source
== IP4_CONFIG_SOURCE_DHCP
);
621 Perment
= Instance
->NicConfig
->Perment
;
622 gBS
->FreePool (Instance
->NicConfig
);
625 Instance
->NicConfig
= AllocatePool (sizeof (NIC_IP4_CONFIG_INFO
) + 2* sizeof (EFI_IP4_ROUTE_TABLE
));
627 if (Instance
->NicConfig
== NULL
) {
628 Instance
->Result
= EFI_OUT_OF_RESOURCES
;
632 Instance
->NicConfig
->Ip4Info
.RouteTable
= (EFI_IP4_ROUTE_TABLE
*) (Instance
->NicConfig
+ 1);
634 CopyMem (&Instance
->NicConfig
->NicAddr
, &Instance
->NicAddr
, sizeof (Instance
->NicConfig
->NicAddr
));
635 Instance
->NicConfig
->Source
= IP4_CONFIG_SOURCE_DHCP
;
636 Instance
->NicConfig
->Perment
= Perment
;
638 Ip4Config
= &Instance
->NicConfig
->Ip4Info
;
639 Ip4Config
->StationAddress
= Dhcp4Mode
.ClientAddress
;
640 Ip4Config
->SubnetMask
= Dhcp4Mode
.SubnetMask
;
643 // Create a route for the connected network
645 Ip4Config
->RouteTableSize
= 1;
647 CopyMem (&Ip1
, &Dhcp4Mode
.ClientAddress
, sizeof (IP4_ADDR
));
648 CopyMem (&Ip2
, &Dhcp4Mode
.SubnetMask
, sizeof (IP4_ADDR
));
652 CopyMem (&Ip4Config
->RouteTable
[0].SubnetAddress
, &Subnet
, sizeof (EFI_IPv4_ADDRESS
));
653 CopyMem (&Ip4Config
->RouteTable
[0].SubnetMask
, &Dhcp4Mode
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
654 ZeroMem (&Ip4Config
->RouteTable
[0].GatewayAddress
, sizeof (EFI_IPv4_ADDRESS
));
657 // Create a route if there is a default router.
659 if (!EFI_IP4_EQUAL (&Dhcp4Mode
.RouterAddress
, &mZeroIp4Addr
)) {
660 Ip4Config
->RouteTableSize
= 2;
662 ZeroMem (&Ip4Config
->RouteTable
[1].SubnetAddress
, sizeof (EFI_IPv4_ADDRESS
));
663 ZeroMem (&Ip4Config
->RouteTable
[1].SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
664 CopyMem (&Ip4Config
->RouteTable
[1].GatewayAddress
, &Dhcp4Mode
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
667 Instance
->Result
= EFI_SUCCESS
;
670 // ignore the return status of EfiNicIp4ConfigSetInfo. Network
671 // stack can operate even that failed.
673 EfiNicIp4ConfigSetInfo (&Instance
->NicIp4Protocol
, Instance
->NicConfig
, FALSE
);
677 gBS
->SignalEvent (Instance
->DoneEvent
);
678 Ip4ConfigCleanDhcp4 (Instance
);
684 Release all the DHCP related resources.
686 @param This The IP4 configure instance
692 Ip4ConfigCleanDhcp4 (
693 IN IP4_CONFIG_INSTANCE
*This
696 if (This
->Dhcp4
!= NULL
) {
697 This
->Dhcp4
->Stop (This
->Dhcp4
);
701 &gEfiDhcp4ProtocolGuid
,
709 if (This
->Dhcp4Handle
!= NULL
) {
710 NetLibDestroyServiceChild (
713 &gEfiDhcp4ServiceBindingProtocolGuid
,
717 This
->Dhcp4Handle
= NULL
;
720 if (This
->Dhcp4Event
== NULL
) {
721 gBS
->CloseEvent (This
->Dhcp4Event
);
722 This
->Dhcp4Event
= NULL
;
728 Clean up all the configuration parameters
730 @param Instance The IP4 configure instance
736 Ip4ConfigCleanConfig (
737 IN IP4_CONFIG_INSTANCE
*Instance
740 if (Instance
->NicConfig
!= NULL
) {
741 gBS
->FreePool (Instance
->NicConfig
);
742 Instance
->NicConfig
= NULL
;
745 Instance
->State
= IP4_CONFIG_STATE_IDLE
;
746 Instance
->DoneEvent
= NULL
;
747 Instance
->ReconfigEvent
= NULL
;
749 Ip4ConfigCleanDhcp4 (Instance
);
752 EFI_IP4_CONFIG_PROTOCOL mIp4ConfigProtocolTemplate
= {
758 EFI_NIC_IP4_CONFIG_PROTOCOL mNicIp4ConfigProtocolTemplate
= {
759 EfiNicIp4ConfigGetName
,
760 EfiNicIp4ConfigGetInfo
,
761 EfiNicIp4ConfigSetInfo