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
);
132 if (NicConfig
== NULL
) {
136 // A dedicated timer is used to poll underlying media status.In case of
137 // cable swap, a new round auto configuration will be initiated. The timer
138 // starts in DHCP policy only. STATIC policy stops the timer.
140 if (NicConfig
->Source
== IP4_CONFIG_SOURCE_DHCP
) {
141 gBS
->SetTimer (Instance
->Timer
, TimerPeriodic
, TICKS_PER_SECOND
);
142 } else if (NicConfig
->Source
== IP4_CONFIG_SOURCE_STATIC
) {
143 gBS
->SetTimer (Instance
->Timer
, TimerCancel
, 0);
150 Callback function when DHCP process finished. It will save the
151 retrieved IP configure parameter from DHCP to the NVRam.
153 @param Event The callback event
154 @param Context Opaque context to the callback
161 Ip4ConfigOnDhcp4Complete (
166 IP4_CONFIG_INSTANCE
*Instance
;
167 EFI_DHCP4_MODE_DATA Dhcp4Mode
;
168 EFI_IP4_IPCONFIG_DATA
*Ip4Config
;
175 Instance
= (IP4_CONFIG_INSTANCE
*) Context
;
176 ASSERT (Instance
->Dhcp4
!= NULL
);
178 Instance
->State
= IP4_CONFIG_STATE_CONFIGURED
;
179 Instance
->Result
= EFI_TIMEOUT
;
182 // Get the DHCP retrieved parameters
184 Status
= Instance
->Dhcp4
->GetModeData (Instance
->Dhcp4
, &Dhcp4Mode
);
186 if (EFI_ERROR (Status
)) {
190 if (Dhcp4Mode
.State
== Dhcp4Bound
) {
192 // Save the new configuration retrieved by DHCP both in
193 // the instance and to NVRam. So, both the IP4 driver and
194 // other user can get that address.
198 if (Instance
->NicConfig
!= NULL
) {
199 ASSERT (Instance
->NicConfig
->Source
== IP4_CONFIG_SOURCE_DHCP
);
200 Perment
= Instance
->NicConfig
->Perment
;
201 FreePool (Instance
->NicConfig
);
204 Instance
->NicConfig
= AllocatePool (sizeof (NIC_IP4_CONFIG_INFO
) + 2* sizeof (EFI_IP4_ROUTE_TABLE
));
206 if (Instance
->NicConfig
== NULL
) {
207 Instance
->Result
= EFI_OUT_OF_RESOURCES
;
211 Instance
->NicConfig
->Ip4Info
.RouteTable
= (EFI_IP4_ROUTE_TABLE
*) (Instance
->NicConfig
+ 1);
213 CopyMem (&Instance
->NicConfig
->NicAddr
, &Instance
->NicAddr
, sizeof (Instance
->NicConfig
->NicAddr
));
214 Instance
->NicConfig
->Source
= IP4_CONFIG_SOURCE_DHCP
;
215 Instance
->NicConfig
->Perment
= Perment
;
217 Ip4Config
= &Instance
->NicConfig
->Ip4Info
;
218 Ip4Config
->StationAddress
= Dhcp4Mode
.ClientAddress
;
219 Ip4Config
->SubnetMask
= Dhcp4Mode
.SubnetMask
;
222 // Create a route for the connected network
224 Ip4Config
->RouteTableSize
= 1;
226 CopyMem (&Ip1
, &Dhcp4Mode
.ClientAddress
, sizeof (IP4_ADDR
));
227 CopyMem (&Ip2
, &Dhcp4Mode
.SubnetMask
, sizeof (IP4_ADDR
));
231 CopyMem (&Ip4Config
->RouteTable
[0].SubnetAddress
, &Subnet
, sizeof (EFI_IPv4_ADDRESS
));
232 CopyMem (&Ip4Config
->RouteTable
[0].SubnetMask
, &Dhcp4Mode
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
233 ZeroMem (&Ip4Config
->RouteTable
[0].GatewayAddress
, sizeof (EFI_IPv4_ADDRESS
));
236 // Create a route if there is a default router.
238 if (!EFI_IP4_EQUAL (&Dhcp4Mode
.RouterAddress
, &mZeroIp4Addr
)) {
239 Ip4Config
->RouteTableSize
= 2;
241 ZeroMem (&Ip4Config
->RouteTable
[1].SubnetAddress
, sizeof (EFI_IPv4_ADDRESS
));
242 ZeroMem (&Ip4Config
->RouteTable
[1].SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
243 CopyMem (&Ip4Config
->RouteTable
[1].GatewayAddress
, &Dhcp4Mode
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
246 Instance
->Result
= EFI_SUCCESS
;
249 // ignore the return status of EfiNicIp4ConfigSetInfo. Network
250 // stack can operate even that failed.
252 EfiNicIp4ConfigSetInfo (Instance
, Instance
->NicConfig
, FALSE
);
256 gBS
->SignalEvent (Instance
->DoneEvent
);
257 Ip4ConfigCleanDhcp4 (Instance
);
265 Starts running the configuration policy for the EFI IPv4 Protocol driver.
267 The Start() function is called to determine and to begin the platform
268 configuration policy by the EFI IPv4 Protocol driver. This determination may
269 be as simple as returning EFI_UNSUPPORTED if there is no EFI IPv4 Protocol
270 driver configuration policy. It may be as involved as loading some defaults
271 from nonvolatile storage, downloading dynamic data from a DHCP server, and
272 checking permissions with a site policy server.
273 Starting the configuration policy is just the beginning. It may finish almost
274 instantly or it may take several minutes before it fails to retrieve configuration
275 information from one or more servers. Once the policy is started, drivers
276 should use the DoneEvent parameter to determine when the configuration policy
277 has completed. EFI_IP4_CONFIG_PROTOCOL.GetData() must then be called to
278 determine if the configuration succeeded or failed.
279 Until the configuration completes successfully, EFI IPv4 Protocol driver instances
280 that are attempting to use default configurations must return EFI_NO_MAPPING.
281 Once the configuration is complete, the EFI IPv4 Configuration Protocol driver
282 signals DoneEvent. The configuration may need to be updated in the future,
283 however; in this case, the EFI IPv4 Configuration Protocol driver must signal
284 ReconfigEvent, and all EFI IPv4 Protocol driver instances that are using default
285 configurations must return EFI_NO_MAPPING until the configuration policy has
288 @param This Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
289 @param DoneEvent Event that will be signaled when the EFI IPv4
290 Protocol driver configuration policy completes
291 execution. This event must be of type EVT_NOTIFY_SIGNAL.
292 @param ReconfigEvent Event that will be signaled when the EFI IPv4
293 Protocol driver configuration needs to be updated.
294 This event must be of type EVT_NOTIFY_SIGNAL.
296 @retval EFI_SUCCESS The configuration policy for the EFI IPv4 Protocol
297 driver is now running.
298 @retval EFI_INVALID_PARAMETER One or more of the following parameters is NULL:
302 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
303 @retval EFI_ALREADY_STARTED The configuration policy for the EFI IPv4 Protocol
304 driver was already started.
305 @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred.
306 @retval EFI_UNSUPPORTED This interface does not support the EFI IPv4 Protocol
307 driver configuration.
313 IN EFI_IP4_CONFIG_PROTOCOL
*This
,
314 IN EFI_EVENT DoneEvent
,
315 IN EFI_EVENT ReconfigEvent
318 IP4_CONFIG_INSTANCE
*Instance
;
319 EFI_DHCP4_PROTOCOL
*Dhcp4
;
320 EFI_DHCP4_MODE_DATA Dhcp4Mode
;
321 EFI_DHCP4_PACKET_OPTION
*OptionList
[1];
322 IP4_CONFIG_DHCP4_OPTION ParaList
;
327 if ((This
== NULL
) || (DoneEvent
== NULL
) || (ReconfigEvent
== NULL
)) {
328 return EFI_INVALID_PARAMETER
;
331 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
333 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
335 if (Instance
->State
!= IP4_CONFIG_STATE_IDLE
) {
336 Status
= EFI_ALREADY_STARTED
;
341 Instance
->DoneEvent
= DoneEvent
;
342 Instance
->ReconfigEvent
= ReconfigEvent
;
344 Instance
->NicConfig
= EfiNicIp4ConfigGetInfo (Instance
);
346 if (Instance
->NicConfig
== NULL
) {
347 Source
= IP4_CONFIG_SOURCE_DHCP
;
349 Source
= Instance
->NicConfig
->Source
;
353 // If the source is static, the auto configuration is done.
356 if (Source
== IP4_CONFIG_SOURCE_STATIC
) {
357 Instance
->State
= IP4_CONFIG_STATE_CONFIGURED
;
358 Instance
->Result
= EFI_SUCCESS
;
360 gBS
->SignalEvent (Instance
->DoneEvent
);
361 Status
= EFI_SUCCESS
;
366 // Start the dhcp process
368 ASSERT ((Source
== IP4_CONFIG_SOURCE_DHCP
) && (Instance
->Dhcp4
== NULL
));
370 Status
= NetLibCreateServiceChild (
371 Instance
->Controller
,
373 &gEfiDhcp4ServiceBindingProtocolGuid
,
374 &Instance
->Dhcp4Handle
377 if (EFI_ERROR (Status
)) {
381 Status
= gBS
->OpenProtocol (
382 Instance
->Dhcp4Handle
,
383 &gEfiDhcp4ProtocolGuid
,
384 (VOID
**) &Instance
->Dhcp4
,
386 Instance
->Controller
,
387 EFI_OPEN_PROTOCOL_BY_DRIVER
390 if (EFI_ERROR (Status
)) {
395 // Check the current DHCP status, if the DHCP process has
396 // already finished, return now.
398 Dhcp4
= Instance
->Dhcp4
;
399 Status
= Dhcp4
->GetModeData (Dhcp4
, &Dhcp4Mode
);
401 if (EFI_ERROR (Status
)) {
405 if (Dhcp4Mode
.State
== Dhcp4Bound
) {
406 Ip4ConfigOnDhcp4Complete (NULL
, Instance
);
412 // Try to start the DHCP process. Use most of the current
413 // DHCP configuration to avoid problems if some DHCP client
414 // yields the control of this DHCP service to us.
416 ParaList
.Head
.OpCode
= DHCP_TAG_PARA_LIST
;
417 ParaList
.Head
.Length
= 2;
418 ParaList
.Head
.Data
[0] = DHCP_TAG_NETMASK
;
419 ParaList
.Route
= DHCP_TAG_ROUTER
;
420 OptionList
[0] = &ParaList
.Head
;
421 Dhcp4Mode
.ConfigData
.OptionCount
= 1;
422 Dhcp4Mode
.ConfigData
.OptionList
= OptionList
;
424 Status
= Dhcp4
->Configure (Dhcp4
, &Dhcp4Mode
.ConfigData
);
426 if (EFI_ERROR (Status
)) {
431 // Start the DHCP process
433 Status
= gBS
->CreateEvent (
436 Ip4ConfigOnDhcp4Complete
,
438 &Instance
->Dhcp4Event
441 if (EFI_ERROR (Status
)) {
445 Status
= Dhcp4
->Start (Dhcp4
, Instance
->Dhcp4Event
);
447 if (EFI_ERROR (Status
)) {
451 Instance
->State
= IP4_CONFIG_STATE_STARTED
;
452 Instance
->Result
= EFI_NOT_READY
;
455 if (EFI_ERROR (Status
)) {
456 Ip4ConfigCleanConfig (Instance
);
460 gBS
->RestoreTPL (OldTpl
);
469 Stops running the configuration policy for the EFI IPv4 Protocol driver.
471 The Stop() function stops the configuration policy for the EFI IPv4 Protocol driver.
472 All configuration data will be lost after calling Stop().
474 @param This Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
476 @retval EFI_SUCCESS The configuration policy for the EFI IPv4 Protocol
477 driver has been stopped.
478 @retval EFI_INVALID_PARAMETER This is NULL.
479 @retval EFI_NOT_STARTED The configuration policy for the EFI IPv4 Protocol
480 driver was not started.
486 IN EFI_IP4_CONFIG_PROTOCOL
*This
489 IP4_CONFIG_INSTANCE
*Instance
;
494 return EFI_INVALID_PARAMETER
;
497 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
499 Status
= EFI_SUCCESS
;
500 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
502 if (Instance
->State
== IP4_CONFIG_STATE_IDLE
) {
503 Status
= EFI_NOT_STARTED
;
508 // Release all the configure parameters. Don't signal the user
509 // event. The user wants to abort the configuration, this isn't
510 // the configuration done or reconfiguration.
512 Ip4ConfigCleanConfig (Instance
);
515 gBS
->RestoreTPL (OldTpl
);
522 Returns the default configuration data (if any) for the EFI IPv4 Protocol driver.
524 The GetData() function returns the current configuration data for the EFI IPv4
525 Protocol driver after the configuration policy has completed.
527 @param This Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
528 @param ConfigDataSize On input, the size of the ConfigData buffer.
529 On output, the count of bytes that were written
530 into the ConfigData buffer.
531 @param ConfigData Pointer to the EFI IPv4 Configuration Protocol
532 driver configuration data structure.
533 Type EFI_IP4_IPCONFIG_DATA is defined in
534 "Related Definitions" below.
536 @retval EFI_SUCCESS The EFI IPv4 Protocol driver configuration has been returned.
537 @retval EFI_INVALID_PARAMETER This is NULL.
538 @retval EFI_NOT_STARTED The configuration policy for the EFI IPv4 Protocol
539 driver is not running.
540 @retval EFI_NOT_READY EFI IPv4 Protocol driver configuration is still running.
541 @retval EFI_ABORTED EFI IPv4 Protocol driver configuration could not complete.
542 Currently not implemented.
543 @retval EFI_BUFFER_TOO_SMALL *ConfigDataSize is smaller than the configuration
544 data buffer or ConfigData is NULL.
549 EfiIp4ConfigGetData (
550 IN EFI_IP4_CONFIG_PROTOCOL
*This
,
551 IN OUT UINTN
*ConfigDataSize
,
552 OUT EFI_IP4_IPCONFIG_DATA
*ConfigData OPTIONAL
555 IP4_CONFIG_INSTANCE
*Instance
;
556 NIC_IP4_CONFIG_INFO
*NicConfig
;
561 if ((This
== NULL
) || (ConfigDataSize
== NULL
)) {
562 return EFI_INVALID_PARAMETER
;
565 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
567 Status
= EFI_SUCCESS
;
568 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
570 if (Instance
->State
== IP4_CONFIG_STATE_IDLE
) {
571 Status
= EFI_NOT_STARTED
;
572 } else if (Instance
->State
== IP4_CONFIG_STATE_STARTED
) {
573 Status
= EFI_NOT_READY
;
576 if (EFI_ERROR (Status
)) {
581 // Copy the configure data if auto configuration succeeds.
583 Status
= Instance
->Result
;
585 if (Status
== EFI_SUCCESS
) {
586 ASSERT (Instance
->NicConfig
!= NULL
);
588 NicConfig
= Instance
->NicConfig
;
589 Len
= SIZEOF_IP4_CONFIG_INFO (&NicConfig
->Ip4Info
);
591 if ((*ConfigDataSize
< Len
) || (ConfigData
== NULL
)) {
592 Status
= EFI_BUFFER_TOO_SMALL
;
594 CopyMem (ConfigData
, &NicConfig
->Ip4Info
, Len
);
595 Ip4ConfigFixRouteTablePointer (ConfigData
);
598 *ConfigDataSize
= Len
;
602 gBS
->RestoreTPL (OldTpl
);
608 Release all the DHCP related resources.
610 @param This The IP4 configure instance
616 Ip4ConfigCleanDhcp4 (
617 IN IP4_CONFIG_INSTANCE
*This
620 if (This
->Dhcp4
!= NULL
) {
621 This
->Dhcp4
->Stop (This
->Dhcp4
);
625 &gEfiDhcp4ProtocolGuid
,
633 if (This
->Dhcp4Handle
!= NULL
) {
634 NetLibDestroyServiceChild (
637 &gEfiDhcp4ServiceBindingProtocolGuid
,
641 This
->Dhcp4Handle
= NULL
;
644 if (This
->Dhcp4Event
== NULL
) {
645 gBS
->CloseEvent (This
->Dhcp4Event
);
646 This
->Dhcp4Event
= NULL
;
652 Clean up all the configuration parameters.
654 @param Instance The IP4 configure instance
660 Ip4ConfigCleanConfig (
661 IN IP4_CONFIG_INSTANCE
*Instance
664 if (Instance
->NicConfig
!= NULL
) {
665 FreePool (Instance
->NicConfig
);
666 Instance
->NicConfig
= NULL
;
669 Instance
->State
= IP4_CONFIG_STATE_IDLE
;
670 Instance
->DoneEvent
= NULL
;
671 Instance
->ReconfigEvent
= NULL
;
673 Ip4ConfigCleanDhcp4 (Instance
);
678 A dedicated timer is used to poll underlying media status. In case of
679 cable swap, a new round auto configuration will be initiated. The timer
680 will signal the IP4 to run the auto configuration again. IP4 driver will free
681 old IP address related resource, such as route table and Interface, then
682 initiate a DHCP process by IP4Config->Start to acquire new IP, eventually
683 create route table for new IP address.
685 @param[in] Event The IP4 service instance's heart beat timer.
686 @param[in] Context The IP4 service instance.
696 BOOLEAN OldMediaPresent
;
698 EFI_SIMPLE_NETWORK_MODE SnpModeData
;
699 IP4_CONFIG_INSTANCE
*Instance
;
701 Instance
= (IP4_CONFIG_INSTANCE
*) Context
;
703 OldMediaPresent
= Instance
->MediaPresent
;
706 // Get fresh mode data from MNP, since underlying media status may change
708 Status
= Instance
->Mnp
->GetModeData (Instance
->Mnp
, NULL
, &SnpModeData
);
709 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_STARTED
)) {
713 Instance
->MediaPresent
= SnpModeData
.MediaPresent
;
715 // Media transimit Unpresent to Present means new link movement is detected.
717 if (!OldMediaPresent
&& Instance
->MediaPresent
) {
719 // Signal the IP4 to run the auto configuration again. IP4 driver will free
720 // old IP address related resource, such as route table and Interface, then
721 // initiate a DHCP round by IP4Config->Start to acquire new IP, eventually
722 // create route table for new IP address.
724 if (Instance
->ReconfigEvent
!= NULL
) {
725 Status
= gBS
->SignalEvent (Instance
->ReconfigEvent
);