2 This code implements the IP4Config and NicIp4Config protocols.
4 Copyright (c) 2006 - 2011, 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
)) {
128 Status
= gBS
->SignalEvent (Instance
->ReconfigEvent
);
133 // A dedicated timer is used to poll underlying media status.In case of
134 // cable swap, a new round auto configuration will be initiated. The timer
135 // starts in DHCP policy only. STATIC policy stops the timer.
137 if (NicConfig
->Source
== IP4_CONFIG_SOURCE_DHCP
) {
138 gBS
->SetTimer (Instance
->Timer
, TimerPeriodic
, TICKS_PER_SECOND
);
139 } else if (NicConfig
->Source
== IP4_CONFIG_SOURCE_STATIC
) {
140 gBS
->SetTimer (Instance
->Timer
, TimerCancel
, 0);
147 Callback function when DHCP process finished. It will save the
148 retrieved IP configure parameter from DHCP to the NVRam.
150 @param Event The callback event
151 @param Context Opaque context to the callback
158 Ip4ConfigOnDhcp4Complete (
163 IP4_CONFIG_INSTANCE
*Instance
;
164 EFI_DHCP4_MODE_DATA Dhcp4Mode
;
165 EFI_IP4_IPCONFIG_DATA
*Ip4Config
;
172 Instance
= (IP4_CONFIG_INSTANCE
*) Context
;
173 ASSERT (Instance
->Dhcp4
!= NULL
);
175 Instance
->State
= IP4_CONFIG_STATE_CONFIGURED
;
176 Instance
->Result
= EFI_TIMEOUT
;
179 // Get the DHCP retrieved parameters
181 Status
= Instance
->Dhcp4
->GetModeData (Instance
->Dhcp4
, &Dhcp4Mode
);
183 if (EFI_ERROR (Status
)) {
187 if (Dhcp4Mode
.State
== Dhcp4Bound
) {
189 // Save the new configuration retrieved by DHCP both in
190 // the instance and to NVRam. So, both the IP4 driver and
191 // other user can get that address.
195 if (Instance
->NicConfig
!= NULL
) {
196 ASSERT (Instance
->NicConfig
->Source
== IP4_CONFIG_SOURCE_DHCP
);
197 Perment
= Instance
->NicConfig
->Perment
;
198 FreePool (Instance
->NicConfig
);
201 Instance
->NicConfig
= AllocatePool (sizeof (NIC_IP4_CONFIG_INFO
) + 2* sizeof (EFI_IP4_ROUTE_TABLE
));
203 if (Instance
->NicConfig
== NULL
) {
204 Instance
->Result
= EFI_OUT_OF_RESOURCES
;
208 Instance
->NicConfig
->Ip4Info
.RouteTable
= (EFI_IP4_ROUTE_TABLE
*) (Instance
->NicConfig
+ 1);
210 CopyMem (&Instance
->NicConfig
->NicAddr
, &Instance
->NicAddr
, sizeof (Instance
->NicConfig
->NicAddr
));
211 Instance
->NicConfig
->Source
= IP4_CONFIG_SOURCE_DHCP
;
212 Instance
->NicConfig
->Perment
= Perment
;
214 Ip4Config
= &Instance
->NicConfig
->Ip4Info
;
215 Ip4Config
->StationAddress
= Dhcp4Mode
.ClientAddress
;
216 Ip4Config
->SubnetMask
= Dhcp4Mode
.SubnetMask
;
219 // Create a route for the connected network
221 Ip4Config
->RouteTableSize
= 1;
223 CopyMem (&Ip1
, &Dhcp4Mode
.ClientAddress
, sizeof (IP4_ADDR
));
224 CopyMem (&Ip2
, &Dhcp4Mode
.SubnetMask
, sizeof (IP4_ADDR
));
228 CopyMem (&Ip4Config
->RouteTable
[0].SubnetAddress
, &Subnet
, sizeof (EFI_IPv4_ADDRESS
));
229 CopyMem (&Ip4Config
->RouteTable
[0].SubnetMask
, &Dhcp4Mode
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
230 ZeroMem (&Ip4Config
->RouteTable
[0].GatewayAddress
, sizeof (EFI_IPv4_ADDRESS
));
233 // Create a route if there is a default router.
235 if (!EFI_IP4_EQUAL (&Dhcp4Mode
.RouterAddress
, &mZeroIp4Addr
)) {
236 Ip4Config
->RouteTableSize
= 2;
238 ZeroMem (&Ip4Config
->RouteTable
[1].SubnetAddress
, sizeof (EFI_IPv4_ADDRESS
));
239 ZeroMem (&Ip4Config
->RouteTable
[1].SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
240 CopyMem (&Ip4Config
->RouteTable
[1].GatewayAddress
, &Dhcp4Mode
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
243 Instance
->Result
= EFI_SUCCESS
;
246 // ignore the return status of EfiNicIp4ConfigSetInfo. Network
247 // stack can operate even that failed.
249 EfiNicIp4ConfigSetInfo (Instance
, Instance
->NicConfig
, FALSE
);
253 gBS
->SignalEvent (Instance
->DoneEvent
);
254 Ip4ConfigCleanDhcp4 (Instance
);
262 Starts running the configuration policy for the EFI IPv4 Protocol driver.
264 The Start() function is called to determine and to begin the platform
265 configuration policy by the EFI IPv4 Protocol driver. This determination may
266 be as simple as returning EFI_UNSUPPORTED if there is no EFI IPv4 Protocol
267 driver configuration policy. It may be as involved as loading some defaults
268 from nonvolatile storage, downloading dynamic data from a DHCP server, and
269 checking permissions with a site policy server.
270 Starting the configuration policy is just the beginning. It may finish almost
271 instantly or it may take several minutes before it fails to retrieve configuration
272 information from one or more servers. Once the policy is started, drivers
273 should use the DoneEvent parameter to determine when the configuration policy
274 has completed. EFI_IP4_CONFIG_PROTOCOL.GetData() must then be called to
275 determine if the configuration succeeded or failed.
276 Until the configuration completes successfully, EFI IPv4 Protocol driver instances
277 that are attempting to use default configurations must return EFI_NO_MAPPING.
278 Once the configuration is complete, the EFI IPv4 Configuration Protocol driver
279 signals DoneEvent. The configuration may need to be updated in the future,
280 however; in this case, the EFI IPv4 Configuration Protocol driver must signal
281 ReconfigEvent, and all EFI IPv4 Protocol driver instances that are using default
282 configurations must return EFI_NO_MAPPING until the configuration policy has
285 @param This Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
286 @param DoneEvent Event that will be signaled when the EFI IPv4
287 Protocol driver configuration policy completes
288 execution. This event must be of type EVT_NOTIFY_SIGNAL.
289 @param ReconfigEvent Event that will be signaled when the EFI IPv4
290 Protocol driver configuration needs to be updated.
291 This event must be of type EVT_NOTIFY_SIGNAL.
293 @retval EFI_SUCCESS The configuration policy for the EFI IPv4 Protocol
294 driver is now running.
295 @retval EFI_INVALID_PARAMETER One or more of the following parameters is NULL:
299 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
300 @retval EFI_ALREADY_STARTED The configuration policy for the EFI IPv4 Protocol
301 driver was already started.
302 @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred.
303 @retval EFI_UNSUPPORTED This interface does not support the EFI IPv4 Protocol
304 driver configuration.
310 IN EFI_IP4_CONFIG_PROTOCOL
*This
,
311 IN EFI_EVENT DoneEvent
,
312 IN EFI_EVENT ReconfigEvent
315 IP4_CONFIG_INSTANCE
*Instance
;
316 EFI_DHCP4_PROTOCOL
*Dhcp4
;
317 EFI_DHCP4_MODE_DATA Dhcp4Mode
;
318 EFI_DHCP4_PACKET_OPTION
*OptionList
[1];
319 IP4_CONFIG_DHCP4_OPTION ParaList
;
324 if ((This
== NULL
) || (DoneEvent
== NULL
) || (ReconfigEvent
== NULL
)) {
325 return EFI_INVALID_PARAMETER
;
328 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
330 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
332 if (Instance
->State
!= IP4_CONFIG_STATE_IDLE
) {
333 Status
= EFI_ALREADY_STARTED
;
338 Instance
->DoneEvent
= DoneEvent
;
339 Instance
->ReconfigEvent
= ReconfigEvent
;
341 Instance
->NicConfig
= EfiNicIp4ConfigGetInfo (Instance
);
343 if (Instance
->NicConfig
== NULL
) {
344 Source
= IP4_CONFIG_SOURCE_DHCP
;
346 Source
= Instance
->NicConfig
->Source
;
350 // If the source is static, the auto configuration is done.
353 if (Source
== IP4_CONFIG_SOURCE_STATIC
) {
354 Instance
->State
= IP4_CONFIG_STATE_CONFIGURED
;
355 Instance
->Result
= EFI_SUCCESS
;
357 gBS
->SignalEvent (Instance
->DoneEvent
);
358 Status
= EFI_SUCCESS
;
363 // Start the dhcp process
365 ASSERT ((Source
== IP4_CONFIG_SOURCE_DHCP
) && (Instance
->Dhcp4
== NULL
));
367 Status
= NetLibCreateServiceChild (
368 Instance
->Controller
,
370 &gEfiDhcp4ServiceBindingProtocolGuid
,
371 &Instance
->Dhcp4Handle
374 if (EFI_ERROR (Status
)) {
378 Status
= gBS
->OpenProtocol (
379 Instance
->Dhcp4Handle
,
380 &gEfiDhcp4ProtocolGuid
,
381 (VOID
**) &Instance
->Dhcp4
,
383 Instance
->Controller
,
384 EFI_OPEN_PROTOCOL_BY_DRIVER
387 if (EFI_ERROR (Status
)) {
392 // Check the current DHCP status, if the DHCP process has
393 // already finished, return now.
395 Dhcp4
= Instance
->Dhcp4
;
396 Status
= Dhcp4
->GetModeData (Dhcp4
, &Dhcp4Mode
);
398 if (EFI_ERROR (Status
)) {
402 if (Dhcp4Mode
.State
== Dhcp4Bound
) {
403 Ip4ConfigOnDhcp4Complete (NULL
, Instance
);
409 // Try to start the DHCP process. Use most of the current
410 // DHCP configuration to avoid problems if some DHCP client
411 // yields the control of this DHCP service to us.
413 ParaList
.Head
.OpCode
= DHCP_TAG_PARA_LIST
;
414 ParaList
.Head
.Length
= 2;
415 ParaList
.Head
.Data
[0] = DHCP_TAG_NETMASK
;
416 ParaList
.Route
= DHCP_TAG_ROUTER
;
417 OptionList
[0] = &ParaList
.Head
;
418 Dhcp4Mode
.ConfigData
.OptionCount
= 1;
419 Dhcp4Mode
.ConfigData
.OptionList
= OptionList
;
421 Status
= Dhcp4
->Configure (Dhcp4
, &Dhcp4Mode
.ConfigData
);
423 if (EFI_ERROR (Status
)) {
428 // Start the DHCP process
430 Status
= gBS
->CreateEvent (
433 Ip4ConfigOnDhcp4Complete
,
435 &Instance
->Dhcp4Event
438 if (EFI_ERROR (Status
)) {
442 Status
= Dhcp4
->Start (Dhcp4
, Instance
->Dhcp4Event
);
444 if (EFI_ERROR (Status
)) {
448 Instance
->State
= IP4_CONFIG_STATE_STARTED
;
449 Instance
->Result
= EFI_NOT_READY
;
452 if (EFI_ERROR (Status
)) {
453 Ip4ConfigCleanConfig (Instance
);
457 gBS
->RestoreTPL (OldTpl
);
466 Stops running the configuration policy for the EFI IPv4 Protocol driver.
468 The Stop() function stops the configuration policy for the EFI IPv4 Protocol driver.
469 All configuration data will be lost after calling Stop().
471 @param This Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
473 @retval EFI_SUCCESS The configuration policy for the EFI IPv4 Protocol
474 driver has been stopped.
475 @retval EFI_INVALID_PARAMETER This is NULL.
476 @retval EFI_NOT_STARTED The configuration policy for the EFI IPv4 Protocol
477 driver was not started.
483 IN EFI_IP4_CONFIG_PROTOCOL
*This
486 IP4_CONFIG_INSTANCE
*Instance
;
491 return EFI_INVALID_PARAMETER
;
494 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
496 Status
= EFI_SUCCESS
;
497 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
499 if (Instance
->State
== IP4_CONFIG_STATE_IDLE
) {
500 Status
= EFI_NOT_STARTED
;
505 // Release all the configure parameters. Don't signal the user
506 // event. The user wants to abort the configuration, this isn't
507 // the configuration done or reconfiguration.
509 Ip4ConfigCleanConfig (Instance
);
512 gBS
->RestoreTPL (OldTpl
);
519 Returns the default configuration data (if any) for the EFI IPv4 Protocol driver.
521 The GetData() function returns the current configuration data for the EFI IPv4
522 Protocol driver after the configuration policy has completed.
524 @param This Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
525 @param ConfigDataSize On input, the size of the ConfigData buffer.
526 On output, the count of bytes that were written
527 into the ConfigData buffer.
528 @param ConfigData Pointer to the EFI IPv4 Configuration Protocol
529 driver configuration data structure.
530 Type EFI_IP4_IPCONFIG_DATA is defined in
531 "Related Definitions" below.
533 @retval EFI_SUCCESS The EFI IPv4 Protocol driver configuration has been returned.
534 @retval EFI_INVALID_PARAMETER This is NULL.
535 @retval EFI_NOT_STARTED The configuration policy for the EFI IPv4 Protocol
536 driver is not running.
537 @retval EFI_NOT_READY EFI IPv4 Protocol driver configuration is still running.
538 @retval EFI_ABORTED EFI IPv4 Protocol driver configuration could not complete.
539 Currently not implemented.
540 @retval EFI_BUFFER_TOO_SMALL *ConfigDataSize is smaller than the configuration
541 data buffer or ConfigData is NULL.
546 EfiIp4ConfigGetData (
547 IN EFI_IP4_CONFIG_PROTOCOL
*This
,
548 IN OUT UINTN
*ConfigDataSize
,
549 OUT EFI_IP4_IPCONFIG_DATA
*ConfigData OPTIONAL
552 IP4_CONFIG_INSTANCE
*Instance
;
553 NIC_IP4_CONFIG_INFO
*NicConfig
;
558 if ((This
== NULL
) || (ConfigDataSize
== NULL
)) {
559 return EFI_INVALID_PARAMETER
;
562 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
564 Status
= EFI_SUCCESS
;
565 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
567 if (Instance
->State
== IP4_CONFIG_STATE_IDLE
) {
568 Status
= EFI_NOT_STARTED
;
569 } else if (Instance
->State
== IP4_CONFIG_STATE_STARTED
) {
570 Status
= EFI_NOT_READY
;
573 if (EFI_ERROR (Status
)) {
578 // Copy the configure data if auto configuration succeeds.
580 Status
= Instance
->Result
;
582 if (Status
== EFI_SUCCESS
) {
583 ASSERT (Instance
->NicConfig
!= NULL
);
585 NicConfig
= Instance
->NicConfig
;
586 Len
= SIZEOF_IP4_CONFIG_INFO (&NicConfig
->Ip4Info
);
588 if ((*ConfigDataSize
< Len
) || (ConfigData
== NULL
)) {
589 Status
= EFI_BUFFER_TOO_SMALL
;
591 CopyMem (ConfigData
, &NicConfig
->Ip4Info
, Len
);
592 Ip4ConfigFixRouteTablePointer (ConfigData
);
595 *ConfigDataSize
= Len
;
599 gBS
->RestoreTPL (OldTpl
);
605 Release all the DHCP related resources.
607 @param This The IP4 configure instance
613 Ip4ConfigCleanDhcp4 (
614 IN IP4_CONFIG_INSTANCE
*This
617 if (This
->Dhcp4
!= NULL
) {
618 This
->Dhcp4
->Stop (This
->Dhcp4
);
622 &gEfiDhcp4ProtocolGuid
,
630 if (This
->Dhcp4Handle
!= NULL
) {
631 NetLibDestroyServiceChild (
634 &gEfiDhcp4ServiceBindingProtocolGuid
,
638 This
->Dhcp4Handle
= NULL
;
641 if (This
->Dhcp4Event
== NULL
) {
642 gBS
->CloseEvent (This
->Dhcp4Event
);
643 This
->Dhcp4Event
= NULL
;
649 Clean up all the configuration parameters.
651 @param Instance The IP4 configure instance
657 Ip4ConfigCleanConfig (
658 IN IP4_CONFIG_INSTANCE
*Instance
661 if (Instance
->NicConfig
!= NULL
) {
662 FreePool (Instance
->NicConfig
);
663 Instance
->NicConfig
= NULL
;
666 Instance
->State
= IP4_CONFIG_STATE_IDLE
;
667 Instance
->DoneEvent
= NULL
;
668 Instance
->ReconfigEvent
= NULL
;
670 Ip4ConfigCleanDhcp4 (Instance
);
675 A dedicated timer is used to poll underlying media status. In case of
676 cable swap, a new round auto configuration will be initiated. The timer
677 will signal the IP4 to run the auto configuration again. IP4 driver will free
678 old IP address related resource, such as route table and Interface, then
679 initiate a DHCP process by IP4Config->Start to acquire new IP, eventually
680 create route table for new IP address.
682 @param[in] Event The IP4 service instance's heart beat timer.
683 @param[in] Context The IP4 service instance.
693 BOOLEAN OldMediaPresent
;
695 EFI_SIMPLE_NETWORK_MODE SnpModeData
;
696 IP4_CONFIG_INSTANCE
*Instance
;
698 Instance
= (IP4_CONFIG_INSTANCE
*) Context
;
700 OldMediaPresent
= Instance
->MediaPresent
;
703 // Get fresh mode data from MNP, since underlying media status may change
705 Status
= Instance
->Mnp
->GetModeData (Instance
->Mnp
, NULL
, &SnpModeData
);
706 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_STARTED
)) {
710 Instance
->MediaPresent
= SnpModeData
.MediaPresent
;
712 // Media transimit Unpresent to Present means new link movement is detected.
714 if (!OldMediaPresent
&& Instance
->MediaPresent
) {
716 // Signal the IP4 to run the auto configuration again. IP4 driver will free
717 // old IP address related resource, such as route table and Interface, then
718 // initiate a DHCP round by IP4Config->Start to acquire new IP, eventually
719 // create route table for new IP address.
721 if (Instance
->ReconfigEvent
!= NULL
) {
722 Status
= gBS
->SignalEvent (Instance
->ReconfigEvent
);