2 This code implements the IP4Config and NicIp4Config protocols.
4 Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at<BR>
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "Ip4Config.h"
17 #include "NicIp4Variable.h"
20 // Ip4 Config Protocol
22 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP4_CONFIG_PROTOCOL mIp4ConfigProtocolTemplate
= {
29 Get the NIC's configure information from the IP4 configure variable.
30 It will remove the invalid variable.
32 @param Instance The IP4 CONFIG instance.
34 @return NULL if no configure for the NIC in the variable, or it is invalid.
35 Otherwise the pointer to the NIC's IP configure parameter will be returned.
39 EfiNicIp4ConfigGetInfo (
40 IN IP4_CONFIG_INSTANCE
*Instance
43 NIC_IP4_CONFIG_INFO
*NicConfig
;
46 // Read the configuration parameter for this NIC from
49 NicConfig
= Ip4ConfigReadVariable (Instance
);
50 if (NicConfig
== NULL
) {
55 // Validate the configuration, if the configuration is invalid,
56 // remove it from the variable.
58 if (!Ip4ConfigIsValid (NicConfig
)) {
59 Ip4ConfigWriteVariable (Instance
, NULL
);
69 Set the IP configure parameters for this NIC.
71 If Reconfig is TRUE, the IP driver will be informed to discard current
72 auto configure parameter and restart the auto configuration process.
73 If current there is a pending auto configuration, EFI_ALREADY_STARTED is
74 returned. You can only change the configure setting when either
75 the configure has finished or not started yet. If NicConfig, the
76 NIC's configure parameter is removed from the variable.
78 @param Instance The IP4 CONFIG instance.
79 @param NicConfig The new NIC IP4 configure parameter.
80 @param Reconfig Inform the IP4 driver to restart the auto
83 @retval EFI_SUCCESS The configure parameter for this NIC was
85 @retval EFI_INVALID_PARAMETER This is NULL or the configure parameter is
87 @retval EFI_ALREADY_STARTED There is a pending auto configuration.
88 @retval EFI_NOT_FOUND No auto configure parameter is found.
93 EfiNicIp4ConfigSetInfo (
94 IN IP4_CONFIG_INSTANCE
*Instance
,
95 IN NIC_IP4_CONFIG_INFO
*NicConfig OPTIONAL
,
102 // Validate the parameters
104 if (Instance
== NULL
) {
105 return EFI_INVALID_PARAMETER
;
108 if ((NicConfig
!= NULL
) && (!Ip4ConfigIsValid (NicConfig
) ||
109 !NIC_ADDR_EQUAL (&NicConfig
->NicAddr
, &Instance
->NicAddr
))) {
110 return EFI_INVALID_PARAMETER
;
113 if (Instance
->State
== IP4_CONFIG_STATE_STARTED
) {
114 return EFI_ALREADY_STARTED
;
118 // Update the parameter in the configure variable
120 Status
= Ip4ConfigWriteVariable (Instance
, NicConfig
);
121 if (EFI_ERROR (Status
)) {
126 // Signal the IP4 to run the auto configuration again
128 if (Reconfig
&& (Instance
->ReconfigEvent
!= NULL
)) {
130 // When NicConfig is NULL, NIC IP4 configuration parameter is removed,
131 // the auto configuration process should stop running the configuration
132 // policy for the EFI IPv4 Protocol driver.
134 if (NicConfig
== NULL
) {
135 Instance
->DoNotStart
= TRUE
;
138 Status
= gBS
->SignalEvent (Instance
->ReconfigEvent
);
142 if (NicConfig
== NULL
) {
146 // A dedicated timer is used to poll underlying media status.In case of
147 // cable swap, a new round auto configuration will be initiated. The timer
148 // starts in DHCP policy only. STATIC policy stops the timer.
150 if (NicConfig
->Source
== IP4_CONFIG_SOURCE_DHCP
) {
151 gBS
->SetTimer (Instance
->Timer
, TimerPeriodic
, TICKS_PER_SECOND
);
152 } else if (NicConfig
->Source
== IP4_CONFIG_SOURCE_STATIC
) {
153 gBS
->SetTimer (Instance
->Timer
, TimerCancel
, 0);
160 Callback function when DHCP process finished. It will save the
161 retrieved IP configure parameter from DHCP to the NVRam.
163 @param Event The callback event
164 @param Context Opaque context to the callback
171 Ip4ConfigOnDhcp4Complete (
176 IP4_CONFIG_INSTANCE
*Instance
;
177 EFI_DHCP4_MODE_DATA Dhcp4Mode
;
178 EFI_IP4_IPCONFIG_DATA
*Ip4Config
;
185 Instance
= (IP4_CONFIG_INSTANCE
*) Context
;
186 ASSERT (Instance
->Dhcp4
!= NULL
);
188 Instance
->State
= IP4_CONFIG_STATE_CONFIGURED
;
189 Instance
->Result
= EFI_TIMEOUT
;
192 // Get the DHCP retrieved parameters
194 Status
= Instance
->Dhcp4
->GetModeData (Instance
->Dhcp4
, &Dhcp4Mode
);
196 if (EFI_ERROR (Status
)) {
200 if (Dhcp4Mode
.State
== Dhcp4Bound
) {
202 // Save the new configuration retrieved by DHCP both in
203 // the instance and to NVRam. So, both the IP4 driver and
204 // other user can get that address.
208 if (Instance
->NicConfig
!= NULL
) {
209 ASSERT (Instance
->NicConfig
->Source
== IP4_CONFIG_SOURCE_DHCP
);
210 Permanent
= Instance
->NicConfig
->Permanent
;
211 FreePool (Instance
->NicConfig
);
214 Instance
->NicConfig
= AllocatePool (sizeof (NIC_IP4_CONFIG_INFO
) + 2* sizeof (EFI_IP4_ROUTE_TABLE
));
216 if (Instance
->NicConfig
== NULL
) {
217 Instance
->Result
= EFI_OUT_OF_RESOURCES
;
221 Instance
->NicConfig
->Ip4Info
.RouteTable
= (EFI_IP4_ROUTE_TABLE
*) (Instance
->NicConfig
+ 1);
223 CopyMem (&Instance
->NicConfig
->NicAddr
, &Instance
->NicAddr
, sizeof (Instance
->NicConfig
->NicAddr
));
224 Instance
->NicConfig
->Source
= IP4_CONFIG_SOURCE_DHCP
;
225 Instance
->NicConfig
->Permanent
= Permanent
;
227 Ip4Config
= &Instance
->NicConfig
->Ip4Info
;
228 Ip4Config
->StationAddress
= Dhcp4Mode
.ClientAddress
;
229 Ip4Config
->SubnetMask
= Dhcp4Mode
.SubnetMask
;
232 // Create a route for the connected network
234 Ip4Config
->RouteTableSize
= 1;
236 CopyMem (&Ip1
, &Dhcp4Mode
.ClientAddress
, sizeof (IP4_ADDR
));
237 CopyMem (&Ip2
, &Dhcp4Mode
.SubnetMask
, sizeof (IP4_ADDR
));
241 CopyMem (&Ip4Config
->RouteTable
[0].SubnetAddress
, &Subnet
, sizeof (EFI_IPv4_ADDRESS
));
242 CopyMem (&Ip4Config
->RouteTable
[0].SubnetMask
, &Dhcp4Mode
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
243 ZeroMem (&Ip4Config
->RouteTable
[0].GatewayAddress
, sizeof (EFI_IPv4_ADDRESS
));
246 // Create a route if there is a default router.
248 if (!EFI_IP4_EQUAL (&Dhcp4Mode
.RouterAddress
, &mZeroIp4Addr
)) {
249 Ip4Config
->RouteTableSize
= 2;
251 ZeroMem (&Ip4Config
->RouteTable
[1].SubnetAddress
, sizeof (EFI_IPv4_ADDRESS
));
252 ZeroMem (&Ip4Config
->RouteTable
[1].SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
253 CopyMem (&Ip4Config
->RouteTable
[1].GatewayAddress
, &Dhcp4Mode
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
256 Instance
->Result
= EFI_SUCCESS
;
259 // ignore the return status of EfiNicIp4ConfigSetInfo. Network
260 // stack can operate even that failed.
262 EfiNicIp4ConfigSetInfo (Instance
, Instance
->NicConfig
, FALSE
);
266 gBS
->SignalEvent (Instance
->DoneEvent
);
267 Ip4ConfigCleanDhcp4 (Instance
);
275 Starts running the configuration policy for the EFI IPv4 Protocol driver.
277 The Start() function is called to determine and to begin the platform
278 configuration policy by the EFI IPv4 Protocol driver. This determination may
279 be as simple as returning EFI_UNSUPPORTED if there is no EFI IPv4 Protocol
280 driver configuration policy. It may be as involved as loading some defaults
281 from nonvolatile storage, downloading dynamic data from a DHCP server, and
282 checking permissions with a site policy server.
283 Starting the configuration policy is just the beginning. It may finish almost
284 instantly or it may take several minutes before it fails to retrieve configuration
285 information from one or more servers. Once the policy is started, drivers
286 should use the DoneEvent parameter to determine when the configuration policy
287 has completed. EFI_IP4_CONFIG_PROTOCOL.GetData() must then be called to
288 determine if the configuration succeeded or failed.
289 Until the configuration completes successfully, EFI IPv4 Protocol driver instances
290 that are attempting to use default configurations must return EFI_NO_MAPPING.
291 Once the configuration is complete, the EFI IPv4 Configuration Protocol driver
292 signals DoneEvent. The configuration may need to be updated in the future,
293 however; in this case, the EFI IPv4 Configuration Protocol driver must signal
294 ReconfigEvent, and all EFI IPv4 Protocol driver instances that are using default
295 configurations must return EFI_NO_MAPPING until the configuration policy has
298 @param This Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
299 @param DoneEvent Event that will be signaled when the EFI IPv4
300 Protocol driver configuration policy completes
301 execution. This event must be of type EVT_NOTIFY_SIGNAL.
302 @param ReconfigEvent Event that will be signaled when the EFI IPv4
303 Protocol driver configuration needs to be updated.
304 This event must be of type EVT_NOTIFY_SIGNAL.
306 @retval EFI_SUCCESS The configuration policy for the EFI IPv4 Protocol
307 driver is now running.
308 @retval EFI_INVALID_PARAMETER One or more of the following parameters is NULL:
312 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
313 @retval EFI_ALREADY_STARTED The configuration policy for the EFI IPv4 Protocol
314 driver was already started.
315 @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred.
316 @retval EFI_UNSUPPORTED This interface does not support the EFI IPv4 Protocol
317 driver configuration.
323 IN EFI_IP4_CONFIG_PROTOCOL
*This
,
324 IN EFI_EVENT DoneEvent
,
325 IN EFI_EVENT ReconfigEvent
328 IP4_CONFIG_INSTANCE
*Instance
;
329 EFI_DHCP4_PROTOCOL
*Dhcp4
;
330 EFI_DHCP4_MODE_DATA Dhcp4Mode
;
331 EFI_DHCP4_PACKET_OPTION
*OptionList
[1];
332 IP4_CONFIG_DHCP4_OPTION ParaList
;
337 if ((This
== NULL
) || (DoneEvent
== NULL
) || (ReconfigEvent
== NULL
)) {
338 return EFI_INVALID_PARAMETER
;
341 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
343 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
345 if (Instance
->State
!= IP4_CONFIG_STATE_IDLE
) {
346 Status
= EFI_ALREADY_STARTED
;
351 Instance
->DoneEvent
= DoneEvent
;
352 Instance
->ReconfigEvent
= ReconfigEvent
;
354 Instance
->NicConfig
= EfiNicIp4ConfigGetInfo (Instance
);
356 if (Instance
->NicConfig
== NULL
) {
357 if (Instance
->DoNotStart
) {
358 Instance
->DoNotStart
= FALSE
;
359 Status
= EFI_SUCCESS
;
363 Source
= IP4_CONFIG_SOURCE_DHCP
;
365 Source
= Instance
->NicConfig
->Source
;
369 // If the source is static, the auto configuration is done.
372 if (Source
== IP4_CONFIG_SOURCE_STATIC
) {
373 Instance
->State
= IP4_CONFIG_STATE_CONFIGURED
;
374 Instance
->Result
= EFI_SUCCESS
;
376 gBS
->SignalEvent (Instance
->DoneEvent
);
377 Status
= EFI_SUCCESS
;
382 // Start the dhcp process
384 ASSERT ((Source
== IP4_CONFIG_SOURCE_DHCP
) && (Instance
->Dhcp4
== NULL
));
386 Status
= NetLibCreateServiceChild (
387 Instance
->Controller
,
389 &gEfiDhcp4ServiceBindingProtocolGuid
,
390 &Instance
->Dhcp4Handle
393 if (EFI_ERROR (Status
)) {
397 Status
= gBS
->OpenProtocol (
398 Instance
->Dhcp4Handle
,
399 &gEfiDhcp4ProtocolGuid
,
400 (VOID
**) &Instance
->Dhcp4
,
402 Instance
->Controller
,
403 EFI_OPEN_PROTOCOL_BY_DRIVER
406 if (EFI_ERROR (Status
)) {
411 // Check the current DHCP status, if the DHCP process has
412 // already finished, return now.
414 Dhcp4
= Instance
->Dhcp4
;
415 Status
= Dhcp4
->GetModeData (Dhcp4
, &Dhcp4Mode
);
417 if (EFI_ERROR (Status
)) {
421 if (Dhcp4Mode
.State
== Dhcp4Bound
) {
422 Ip4ConfigOnDhcp4Complete (NULL
, Instance
);
428 // Try to start the DHCP process. Use most of the current
429 // DHCP configuration to avoid problems if some DHCP client
430 // yields the control of this DHCP service to us.
432 ParaList
.Head
.OpCode
= DHCP_TAG_PARA_LIST
;
433 ParaList
.Head
.Length
= 2;
434 ParaList
.Head
.Data
[0] = DHCP_TAG_NETMASK
;
435 ParaList
.Route
= DHCP_TAG_ROUTER
;
436 OptionList
[0] = &ParaList
.Head
;
437 Dhcp4Mode
.ConfigData
.OptionCount
= 1;
438 Dhcp4Mode
.ConfigData
.OptionList
= OptionList
;
440 Status
= Dhcp4
->Configure (Dhcp4
, &Dhcp4Mode
.ConfigData
);
442 if (EFI_ERROR (Status
)) {
447 // Start the DHCP process
449 Status
= gBS
->CreateEvent (
452 Ip4ConfigOnDhcp4Complete
,
454 &Instance
->Dhcp4Event
457 if (EFI_ERROR (Status
)) {
461 Status
= Dhcp4
->Start (Dhcp4
, Instance
->Dhcp4Event
);
463 if (EFI_ERROR (Status
)) {
467 Instance
->State
= IP4_CONFIG_STATE_STARTED
;
468 Instance
->Result
= EFI_NOT_READY
;
471 if (EFI_ERROR (Status
)) {
472 Ip4ConfigCleanConfig (Instance
);
476 gBS
->RestoreTPL (OldTpl
);
485 Stops running the configuration policy for the EFI IPv4 Protocol driver.
487 The Stop() function stops the configuration policy for the EFI IPv4 Protocol driver.
488 All configuration data will be lost after calling Stop().
490 @param This Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
492 @retval EFI_SUCCESS The configuration policy for the EFI IPv4 Protocol
493 driver has been stopped.
494 @retval EFI_INVALID_PARAMETER This is NULL.
495 @retval EFI_NOT_STARTED The configuration policy for the EFI IPv4 Protocol
496 driver was not started.
502 IN EFI_IP4_CONFIG_PROTOCOL
*This
505 IP4_CONFIG_INSTANCE
*Instance
;
510 return EFI_INVALID_PARAMETER
;
513 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
515 Status
= EFI_SUCCESS
;
516 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
518 if (Instance
->State
== IP4_CONFIG_STATE_IDLE
) {
519 Status
= EFI_NOT_STARTED
;
524 // Release all the configure parameters. Don't signal the user
525 // event. The user wants to abort the configuration, this isn't
526 // the configuration done or reconfiguration.
528 Ip4ConfigCleanConfig (Instance
);
531 gBS
->RestoreTPL (OldTpl
);
538 Returns the default configuration data (if any) for the EFI IPv4 Protocol driver.
540 The GetData() function returns the current configuration data for the EFI IPv4
541 Protocol driver after the configuration policy has completed.
543 @param This Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
544 @param ConfigDataSize On input, the size of the ConfigData buffer.
545 On output, the count of bytes that were written
546 into the ConfigData buffer.
547 @param ConfigData Pointer to the EFI IPv4 Configuration Protocol
548 driver configuration data structure.
549 Type EFI_IP4_IPCONFIG_DATA is defined in
550 "Related Definitions" below.
552 @retval EFI_SUCCESS The EFI IPv4 Protocol driver configuration has been returned.
553 @retval EFI_INVALID_PARAMETER This is NULL.
554 @retval EFI_NOT_STARTED The configuration policy for the EFI IPv4 Protocol
555 driver is not running.
556 @retval EFI_NOT_READY EFI IPv4 Protocol driver configuration is still running.
557 @retval EFI_ABORTED EFI IPv4 Protocol driver configuration could not complete.
558 Currently not implemented.
559 @retval EFI_BUFFER_TOO_SMALL *ConfigDataSize is smaller than the configuration
560 data buffer or ConfigData is NULL.
565 EfiIp4ConfigGetData (
566 IN EFI_IP4_CONFIG_PROTOCOL
*This
,
567 IN OUT UINTN
*ConfigDataSize
,
568 OUT EFI_IP4_IPCONFIG_DATA
*ConfigData OPTIONAL
571 IP4_CONFIG_INSTANCE
*Instance
;
572 NIC_IP4_CONFIG_INFO
*NicConfig
;
577 if ((This
== NULL
) || (ConfigDataSize
== NULL
)) {
578 return EFI_INVALID_PARAMETER
;
581 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
583 Status
= EFI_SUCCESS
;
584 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
586 if (Instance
->State
== IP4_CONFIG_STATE_IDLE
) {
587 Status
= EFI_NOT_STARTED
;
588 } else if (Instance
->State
== IP4_CONFIG_STATE_STARTED
) {
589 Status
= EFI_NOT_READY
;
592 if (EFI_ERROR (Status
)) {
597 // Copy the configure data if auto configuration succeeds.
599 Status
= Instance
->Result
;
601 if (Status
== EFI_SUCCESS
) {
602 ASSERT (Instance
->NicConfig
!= NULL
);
604 NicConfig
= Instance
->NicConfig
;
605 Len
= SIZEOF_IP4_CONFIG_INFO (&NicConfig
->Ip4Info
);
607 if ((*ConfigDataSize
< Len
) || (ConfigData
== NULL
)) {
608 Status
= EFI_BUFFER_TOO_SMALL
;
610 CopyMem (ConfigData
, &NicConfig
->Ip4Info
, Len
);
611 Ip4ConfigFixRouteTablePointer (ConfigData
);
614 *ConfigDataSize
= Len
;
618 gBS
->RestoreTPL (OldTpl
);
624 Release all the DHCP related resources.
626 @param This The IP4 configure instance
632 Ip4ConfigCleanDhcp4 (
633 IN IP4_CONFIG_INSTANCE
*This
636 if (This
->Dhcp4
!= NULL
) {
637 This
->Dhcp4
->Stop (This
->Dhcp4
);
641 &gEfiDhcp4ProtocolGuid
,
649 if (This
->Dhcp4Handle
!= NULL
) {
650 NetLibDestroyServiceChild (
653 &gEfiDhcp4ServiceBindingProtocolGuid
,
657 This
->Dhcp4Handle
= NULL
;
660 if (This
->Dhcp4Event
!= NULL
) {
661 gBS
->CloseEvent (This
->Dhcp4Event
);
662 This
->Dhcp4Event
= NULL
;
668 Clean up all the configuration parameters.
670 @param Instance The IP4 configure instance
676 Ip4ConfigCleanConfig (
677 IN IP4_CONFIG_INSTANCE
*Instance
680 if (Instance
->NicConfig
!= NULL
) {
681 FreePool (Instance
->NicConfig
);
682 Instance
->NicConfig
= NULL
;
685 Instance
->State
= IP4_CONFIG_STATE_IDLE
;
686 Instance
->DoneEvent
= NULL
;
687 Instance
->ReconfigEvent
= NULL
;
689 Ip4ConfigCleanDhcp4 (Instance
);
694 A dedicated timer is used to poll underlying media status. In case of
695 cable swap, a new round auto configuration will be initiated. The timer
696 will signal the IP4 to run the auto configuration again. IP4 driver will free
697 old IP address related resource, such as route table and Interface, then
698 initiate a DHCP process by IP4Config->Start to acquire new IP, eventually
699 create route table for new IP address.
701 @param[in] Event The IP4 service instance's heart beat timer.
702 @param[in] Context The IP4 service instance.
712 BOOLEAN OldMediaPresent
;
714 EFI_SIMPLE_NETWORK_MODE SnpModeData
;
715 IP4_CONFIG_INSTANCE
*Instance
;
717 Instance
= (IP4_CONFIG_INSTANCE
*) Context
;
719 OldMediaPresent
= Instance
->MediaPresent
;
722 // Get fresh mode data from MNP, since underlying media status may change
724 Status
= Instance
->Mnp
->GetModeData (Instance
->Mnp
, NULL
, &SnpModeData
);
725 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_STARTED
)) {
729 Instance
->MediaPresent
= SnpModeData
.MediaPresent
;
731 // Media transimit Unpresent to Present means new link movement is detected.
733 if (!OldMediaPresent
&& Instance
->MediaPresent
) {
735 // Signal the IP4 to run the auto configuration again. IP4 driver will free
736 // old IP address related resource, such as route table and Interface, then
737 // initiate a DHCP round by IP4Config->Start to acquire new IP, eventually
738 // create route table for new IP address.
740 if (Instance
->ReconfigEvent
!= NULL
) {
741 Status
= gBS
->SignalEvent (Instance
->ReconfigEvent
);