2 This code implements the IP4Config and NicIp4Config protocols.
4 Copyright (c) 2006 - 2012, 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<BR>
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 "Ip4Config.h"
16 #include "NicIp4Variable.h"
19 // Ip4 Config Protocol
21 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP4_CONFIG_PROTOCOL mIp4ConfigProtocolTemplate
= {
28 Get the NIC's configure information from the IP4 configure variable.
29 It will remove the invalid variable.
31 @param Instance The IP4 CONFIG instance.
33 @return NULL if no configure for the NIC in the variable, or it is invalid.
34 Otherwise the pointer to the NIC's IP configure parameter will be returned.
38 EfiNicIp4ConfigGetInfo (
39 IN IP4_CONFIG_INSTANCE
*Instance
42 NIC_IP4_CONFIG_INFO
*NicConfig
;
45 // Read the configuration parameter for this NIC from
48 NicConfig
= Ip4ConfigReadVariable (Instance
);
49 if (NicConfig
== NULL
) {
54 // Validate the configuration, if the configuration is invalid,
55 // remove it from the variable.
57 if (!Ip4ConfigIsValid (NicConfig
)) {
58 Ip4ConfigWriteVariable (Instance
, NULL
);
68 Set the IP configure parameters for this NIC.
70 If Reconfig is TRUE, the IP driver will be informed to discard current
71 auto configure parameter and restart the auto configuration process.
72 If current there is a pending auto configuration, EFI_ALREADY_STARTED is
73 returned. You can only change the configure setting when either
74 the configure has finished or not started yet. If NicConfig, the
75 NIC's configure parameter is removed from the variable.
77 @param Instance The IP4 CONFIG instance.
78 @param NicConfig The new NIC IP4 configure parameter.
79 @param Reconfig Inform the IP4 driver to restart the auto
82 @retval EFI_SUCCESS The configure parameter for this NIC was
84 @retval EFI_INVALID_PARAMETER This is NULL or the configure parameter is
86 @retval EFI_ALREADY_STARTED There is a pending auto configuration.
87 @retval EFI_NOT_FOUND No auto configure parameter is found.
92 EfiNicIp4ConfigSetInfo (
93 IN IP4_CONFIG_INSTANCE
*Instance
,
94 IN NIC_IP4_CONFIG_INFO
*NicConfig OPTIONAL
,
101 // Validate the parameters
103 if (Instance
== NULL
) {
104 return EFI_INVALID_PARAMETER
;
107 if ((NicConfig
!= NULL
) && (!Ip4ConfigIsValid (NicConfig
) ||
108 !NIC_ADDR_EQUAL (&NicConfig
->NicAddr
, &Instance
->NicAddr
))) {
109 return EFI_INVALID_PARAMETER
;
112 if (Instance
->State
== IP4_CONFIG_STATE_STARTED
) {
113 return EFI_ALREADY_STARTED
;
117 // Update the parameter in the configure variable
119 Status
= Ip4ConfigWriteVariable (Instance
, NicConfig
);
120 if (EFI_ERROR (Status
)) {
125 // Signal the IP4 to run the auto configuration again
127 if (Reconfig
&& (Instance
->ReconfigEvent
!= NULL
)) {
129 // When NicConfig is NULL, NIC IP4 configuration parameter is removed,
130 // the auto configuration process should stop running the configuration
131 // policy for the EFI IPv4 Protocol driver.
133 if (NicConfig
== NULL
) {
134 Instance
->DoNotStart
= TRUE
;
137 Status
= gBS
->SignalEvent (Instance
->ReconfigEvent
);
141 if (NicConfig
== NULL
) {
145 // A dedicated timer is used to poll underlying media status.In case of
146 // cable swap, a new round auto configuration will be initiated. The timer
147 // starts in DHCP policy only. STATIC policy stops the timer.
149 if (NicConfig
->Source
== IP4_CONFIG_SOURCE_DHCP
) {
150 gBS
->SetTimer (Instance
->Timer
, TimerPeriodic
, TICKS_PER_SECOND
);
151 } else if (NicConfig
->Source
== IP4_CONFIG_SOURCE_STATIC
) {
152 gBS
->SetTimer (Instance
->Timer
, TimerCancel
, 0);
159 Callback function when DHCP process finished. It will save the
160 retrieved IP configure parameter from DHCP to the NVRam.
162 @param Event The callback event
163 @param Context Opaque context to the callback
170 Ip4ConfigOnDhcp4Complete (
175 IP4_CONFIG_INSTANCE
*Instance
;
176 EFI_DHCP4_MODE_DATA Dhcp4Mode
;
177 EFI_IP4_IPCONFIG_DATA
*Ip4Config
;
184 Instance
= (IP4_CONFIG_INSTANCE
*) Context
;
185 ASSERT (Instance
->Dhcp4
!= NULL
);
187 Instance
->State
= IP4_CONFIG_STATE_CONFIGURED
;
188 Instance
->Result
= EFI_TIMEOUT
;
191 // Get the DHCP retrieved parameters
193 Status
= Instance
->Dhcp4
->GetModeData (Instance
->Dhcp4
, &Dhcp4Mode
);
195 if (EFI_ERROR (Status
)) {
199 if (Dhcp4Mode
.State
== Dhcp4Bound
) {
201 // Save the new configuration retrieved by DHCP both in
202 // the instance and to NVRam. So, both the IP4 driver and
203 // other user can get that address.
207 if (Instance
->NicConfig
!= NULL
) {
208 ASSERT (Instance
->NicConfig
->Source
== IP4_CONFIG_SOURCE_DHCP
);
209 Permanent
= Instance
->NicConfig
->Permanent
;
210 FreePool (Instance
->NicConfig
);
213 Instance
->NicConfig
= AllocatePool (sizeof (NIC_IP4_CONFIG_INFO
) + 2* sizeof (EFI_IP4_ROUTE_TABLE
));
215 if (Instance
->NicConfig
== NULL
) {
216 Instance
->Result
= EFI_OUT_OF_RESOURCES
;
220 Instance
->NicConfig
->Ip4Info
.RouteTable
= (EFI_IP4_ROUTE_TABLE
*) (Instance
->NicConfig
+ 1);
222 CopyMem (&Instance
->NicConfig
->NicAddr
, &Instance
->NicAddr
, sizeof (Instance
->NicConfig
->NicAddr
));
223 Instance
->NicConfig
->Source
= IP4_CONFIG_SOURCE_DHCP
;
224 Instance
->NicConfig
->Permanent
= Permanent
;
226 Ip4Config
= &Instance
->NicConfig
->Ip4Info
;
227 Ip4Config
->StationAddress
= Dhcp4Mode
.ClientAddress
;
228 Ip4Config
->SubnetMask
= Dhcp4Mode
.SubnetMask
;
231 // Create a route for the connected network
233 Ip4Config
->RouteTableSize
= 1;
235 CopyMem (&Ip1
, &Dhcp4Mode
.ClientAddress
, sizeof (IP4_ADDR
));
236 CopyMem (&Ip2
, &Dhcp4Mode
.SubnetMask
, sizeof (IP4_ADDR
));
240 CopyMem (&Ip4Config
->RouteTable
[0].SubnetAddress
, &Subnet
, sizeof (EFI_IPv4_ADDRESS
));
241 CopyMem (&Ip4Config
->RouteTable
[0].SubnetMask
, &Dhcp4Mode
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
242 ZeroMem (&Ip4Config
->RouteTable
[0].GatewayAddress
, sizeof (EFI_IPv4_ADDRESS
));
245 // Create a route if there is a default router.
247 if (!EFI_IP4_EQUAL (&Dhcp4Mode
.RouterAddress
, &mZeroIp4Addr
)) {
248 Ip4Config
->RouteTableSize
= 2;
250 ZeroMem (&Ip4Config
->RouteTable
[1].SubnetAddress
, sizeof (EFI_IPv4_ADDRESS
));
251 ZeroMem (&Ip4Config
->RouteTable
[1].SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
252 CopyMem (&Ip4Config
->RouteTable
[1].GatewayAddress
, &Dhcp4Mode
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
255 Instance
->Result
= EFI_SUCCESS
;
258 // ignore the return status of EfiNicIp4ConfigSetInfo. Network
259 // stack can operate even that failed.
261 EfiNicIp4ConfigSetInfo (Instance
, Instance
->NicConfig
, FALSE
);
265 gBS
->SignalEvent (Instance
->DoneEvent
);
266 Ip4ConfigCleanDhcp4 (Instance
);
274 Starts running the configuration policy for the EFI IPv4 Protocol driver.
276 The Start() function is called to determine and to begin the platform
277 configuration policy by the EFI IPv4 Protocol driver. This determination may
278 be as simple as returning EFI_UNSUPPORTED if there is no EFI IPv4 Protocol
279 driver configuration policy. It may be as involved as loading some defaults
280 from nonvolatile storage, downloading dynamic data from a DHCP server, and
281 checking permissions with a site policy server.
282 Starting the configuration policy is just the beginning. It may finish almost
283 instantly or it may take several minutes before it fails to retrieve configuration
284 information from one or more servers. Once the policy is started, drivers
285 should use the DoneEvent parameter to determine when the configuration policy
286 has completed. EFI_IP4_CONFIG_PROTOCOL.GetData() must then be called to
287 determine if the configuration succeeded or failed.
288 Until the configuration completes successfully, EFI IPv4 Protocol driver instances
289 that are attempting to use default configurations must return EFI_NO_MAPPING.
290 Once the configuration is complete, the EFI IPv4 Configuration Protocol driver
291 signals DoneEvent. The configuration may need to be updated in the future,
292 however; in this case, the EFI IPv4 Configuration Protocol driver must signal
293 ReconfigEvent, and all EFI IPv4 Protocol driver instances that are using default
294 configurations must return EFI_NO_MAPPING until the configuration policy has
297 @param This Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
298 @param DoneEvent Event that will be signaled when the EFI IPv4
299 Protocol driver configuration policy completes
300 execution. This event must be of type EVT_NOTIFY_SIGNAL.
301 @param ReconfigEvent Event that will be signaled when the EFI IPv4
302 Protocol driver configuration needs to be updated.
303 This event must be of type EVT_NOTIFY_SIGNAL.
305 @retval EFI_SUCCESS The configuration policy for the EFI IPv4 Protocol
306 driver is now running.
307 @retval EFI_INVALID_PARAMETER One or more of the following parameters is NULL:
311 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
312 @retval EFI_ALREADY_STARTED The configuration policy for the EFI IPv4 Protocol
313 driver was already started.
314 @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred.
315 @retval EFI_UNSUPPORTED This interface does not support the EFI IPv4 Protocol
316 driver configuration.
322 IN EFI_IP4_CONFIG_PROTOCOL
*This
,
323 IN EFI_EVENT DoneEvent
,
324 IN EFI_EVENT ReconfigEvent
327 IP4_CONFIG_INSTANCE
*Instance
;
328 EFI_DHCP4_PROTOCOL
*Dhcp4
;
329 EFI_DHCP4_MODE_DATA Dhcp4Mode
;
330 EFI_DHCP4_PACKET_OPTION
*OptionList
[1];
331 IP4_CONFIG_DHCP4_OPTION ParaList
;
336 if ((This
== NULL
) || (DoneEvent
== NULL
) || (ReconfigEvent
== NULL
)) {
337 return EFI_INVALID_PARAMETER
;
340 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
342 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
344 if (Instance
->State
!= IP4_CONFIG_STATE_IDLE
) {
345 Status
= EFI_ALREADY_STARTED
;
350 Instance
->DoneEvent
= DoneEvent
;
351 Instance
->ReconfigEvent
= ReconfigEvent
;
353 Instance
->NicConfig
= EfiNicIp4ConfigGetInfo (Instance
);
355 if (Instance
->NicConfig
== NULL
) {
356 if (Instance
->DoNotStart
) {
357 Instance
->DoNotStart
= FALSE
;
358 Status
= EFI_SUCCESS
;
362 Source
= IP4_CONFIG_SOURCE_DHCP
;
364 Source
= Instance
->NicConfig
->Source
;
368 // If the source is static, the auto configuration is done.
371 if (Source
== IP4_CONFIG_SOURCE_STATIC
) {
372 Instance
->State
= IP4_CONFIG_STATE_CONFIGURED
;
373 Instance
->Result
= EFI_SUCCESS
;
375 gBS
->SignalEvent (Instance
->DoneEvent
);
376 Status
= EFI_SUCCESS
;
381 // Start the dhcp process
383 ASSERT ((Source
== IP4_CONFIG_SOURCE_DHCP
) && (Instance
->Dhcp4
== NULL
));
385 Status
= NetLibCreateServiceChild (
386 Instance
->Controller
,
388 &gEfiDhcp4ServiceBindingProtocolGuid
,
389 &Instance
->Dhcp4Handle
392 if (EFI_ERROR (Status
)) {
396 Status
= gBS
->OpenProtocol (
397 Instance
->Dhcp4Handle
,
398 &gEfiDhcp4ProtocolGuid
,
399 (VOID
**) &Instance
->Dhcp4
,
401 Instance
->Controller
,
402 EFI_OPEN_PROTOCOL_BY_DRIVER
405 if (EFI_ERROR (Status
)) {
410 // Check the current DHCP status, if the DHCP process has
411 // already finished, return now.
413 Dhcp4
= Instance
->Dhcp4
;
414 Status
= Dhcp4
->GetModeData (Dhcp4
, &Dhcp4Mode
);
416 if (EFI_ERROR (Status
)) {
420 if (Dhcp4Mode
.State
== Dhcp4Bound
) {
421 Ip4ConfigOnDhcp4Complete (NULL
, Instance
);
427 // Try to start the DHCP process. Use most of the current
428 // DHCP configuration to avoid problems if some DHCP client
429 // yields the control of this DHCP service to us.
431 ParaList
.Head
.OpCode
= DHCP_TAG_PARA_LIST
;
432 ParaList
.Head
.Length
= 2;
433 ParaList
.Head
.Data
[0] = DHCP_TAG_NETMASK
;
434 ParaList
.Route
= DHCP_TAG_ROUTER
;
435 OptionList
[0] = &ParaList
.Head
;
436 Dhcp4Mode
.ConfigData
.OptionCount
= 1;
437 Dhcp4Mode
.ConfigData
.OptionList
= OptionList
;
439 Status
= Dhcp4
->Configure (Dhcp4
, &Dhcp4Mode
.ConfigData
);
441 if (EFI_ERROR (Status
)) {
446 // Start the DHCP process
448 Status
= gBS
->CreateEvent (
451 Ip4ConfigOnDhcp4Complete
,
453 &Instance
->Dhcp4Event
456 if (EFI_ERROR (Status
)) {
460 Status
= Dhcp4
->Start (Dhcp4
, Instance
->Dhcp4Event
);
462 if (EFI_ERROR (Status
)) {
466 Instance
->State
= IP4_CONFIG_STATE_STARTED
;
467 Instance
->Result
= EFI_NOT_READY
;
470 if (EFI_ERROR (Status
)) {
471 Ip4ConfigCleanConfig (Instance
);
475 gBS
->RestoreTPL (OldTpl
);
484 Stops running the configuration policy for the EFI IPv4 Protocol driver.
486 The Stop() function stops the configuration policy for the EFI IPv4 Protocol driver.
487 All configuration data will be lost after calling Stop().
489 @param This Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
491 @retval EFI_SUCCESS The configuration policy for the EFI IPv4 Protocol
492 driver has been stopped.
493 @retval EFI_INVALID_PARAMETER This is NULL.
494 @retval EFI_NOT_STARTED The configuration policy for the EFI IPv4 Protocol
495 driver was not started.
501 IN EFI_IP4_CONFIG_PROTOCOL
*This
504 IP4_CONFIG_INSTANCE
*Instance
;
509 return EFI_INVALID_PARAMETER
;
512 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
514 Status
= EFI_SUCCESS
;
515 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
517 if (Instance
->State
== IP4_CONFIG_STATE_IDLE
) {
518 Status
= EFI_NOT_STARTED
;
523 // Release all the configure parameters. Don't signal the user
524 // event. The user wants to abort the configuration, this isn't
525 // the configuration done or reconfiguration.
527 Ip4ConfigCleanConfig (Instance
);
530 gBS
->RestoreTPL (OldTpl
);
537 Returns the default configuration data (if any) for the EFI IPv4 Protocol driver.
539 The GetData() function returns the current configuration data for the EFI IPv4
540 Protocol driver after the configuration policy has completed.
542 @param This Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
543 @param ConfigDataSize On input, the size of the ConfigData buffer.
544 On output, the count of bytes that were written
545 into the ConfigData buffer.
546 @param ConfigData Pointer to the EFI IPv4 Configuration Protocol
547 driver configuration data structure.
548 Type EFI_IP4_IPCONFIG_DATA is defined in
549 "Related Definitions" below.
551 @retval EFI_SUCCESS The EFI IPv4 Protocol driver configuration has been returned.
552 @retval EFI_INVALID_PARAMETER This is NULL.
553 @retval EFI_NOT_STARTED The configuration policy for the EFI IPv4 Protocol
554 driver is not running.
555 @retval EFI_NOT_READY EFI IPv4 Protocol driver configuration is still running.
556 @retval EFI_ABORTED EFI IPv4 Protocol driver configuration could not complete.
557 Currently not implemented.
558 @retval EFI_BUFFER_TOO_SMALL *ConfigDataSize is smaller than the configuration
559 data buffer or ConfigData is NULL.
564 EfiIp4ConfigGetData (
565 IN EFI_IP4_CONFIG_PROTOCOL
*This
,
566 IN OUT UINTN
*ConfigDataSize
,
567 OUT EFI_IP4_IPCONFIG_DATA
*ConfigData OPTIONAL
570 IP4_CONFIG_INSTANCE
*Instance
;
571 NIC_IP4_CONFIG_INFO
*NicConfig
;
576 if ((This
== NULL
) || (ConfigDataSize
== NULL
)) {
577 return EFI_INVALID_PARAMETER
;
580 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
582 Status
= EFI_SUCCESS
;
583 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
585 if (Instance
->State
== IP4_CONFIG_STATE_IDLE
) {
586 Status
= EFI_NOT_STARTED
;
587 } else if (Instance
->State
== IP4_CONFIG_STATE_STARTED
) {
588 Status
= EFI_NOT_READY
;
591 if (EFI_ERROR (Status
)) {
596 // Copy the configure data if auto configuration succeeds.
598 Status
= Instance
->Result
;
600 if (Status
== EFI_SUCCESS
) {
601 ASSERT (Instance
->NicConfig
!= NULL
);
603 NicConfig
= Instance
->NicConfig
;
604 Len
= SIZEOF_IP4_CONFIG_INFO (&NicConfig
->Ip4Info
);
606 if ((*ConfigDataSize
< Len
) || (ConfigData
== NULL
)) {
607 Status
= EFI_BUFFER_TOO_SMALL
;
609 CopyMem (ConfigData
, &NicConfig
->Ip4Info
, Len
);
610 Ip4ConfigFixRouteTablePointer (ConfigData
);
613 *ConfigDataSize
= Len
;
617 gBS
->RestoreTPL (OldTpl
);
623 Release all the DHCP related resources.
625 @param This The IP4 configure instance
631 Ip4ConfigCleanDhcp4 (
632 IN IP4_CONFIG_INSTANCE
*This
635 if (This
->Dhcp4
!= NULL
) {
636 This
->Dhcp4
->Stop (This
->Dhcp4
);
640 &gEfiDhcp4ProtocolGuid
,
648 if (This
->Dhcp4Handle
!= NULL
) {
649 NetLibDestroyServiceChild (
652 &gEfiDhcp4ServiceBindingProtocolGuid
,
656 This
->Dhcp4Handle
= NULL
;
659 if (This
->Dhcp4Event
== NULL
) {
660 gBS
->CloseEvent (This
->Dhcp4Event
);
661 This
->Dhcp4Event
= NULL
;
667 Clean up all the configuration parameters.
669 @param Instance The IP4 configure instance
675 Ip4ConfigCleanConfig (
676 IN IP4_CONFIG_INSTANCE
*Instance
679 if (Instance
->NicConfig
!= NULL
) {
680 FreePool (Instance
->NicConfig
);
681 Instance
->NicConfig
= NULL
;
684 Instance
->State
= IP4_CONFIG_STATE_IDLE
;
685 Instance
->DoneEvent
= NULL
;
686 Instance
->ReconfigEvent
= NULL
;
688 Ip4ConfigCleanDhcp4 (Instance
);
693 A dedicated timer is used to poll underlying media status. In case of
694 cable swap, a new round auto configuration will be initiated. The timer
695 will signal the IP4 to run the auto configuration again. IP4 driver will free
696 old IP address related resource, such as route table and Interface, then
697 initiate a DHCP process by IP4Config->Start to acquire new IP, eventually
698 create route table for new IP address.
700 @param[in] Event The IP4 service instance's heart beat timer.
701 @param[in] Context The IP4 service instance.
711 BOOLEAN OldMediaPresent
;
713 EFI_SIMPLE_NETWORK_MODE SnpModeData
;
714 IP4_CONFIG_INSTANCE
*Instance
;
716 Instance
= (IP4_CONFIG_INSTANCE
*) Context
;
718 OldMediaPresent
= Instance
->MediaPresent
;
721 // Get fresh mode data from MNP, since underlying media status may change
723 Status
= Instance
->Mnp
->GetModeData (Instance
->Mnp
, NULL
, &SnpModeData
);
724 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_STARTED
)) {
728 Instance
->MediaPresent
= SnpModeData
.MediaPresent
;
730 // Media transimit Unpresent to Present means new link movement is detected.
732 if (!OldMediaPresent
&& Instance
->MediaPresent
) {
734 // Signal the IP4 to run the auto configuration again. IP4 driver will free
735 // old IP address related resource, such as route table and Interface, then
736 // initiate a DHCP round by IP4Config->Start to acquire new IP, eventually
737 // create route table for new IP address.
739 if (Instance
->ReconfigEvent
!= NULL
) {
740 Status
= gBS
->SignalEvent (Instance
->ReconfigEvent
);