3 Copyright (c) 2006 - 2008, 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
];
28 Callback function when DHCP process finished. It will save the
29 retrieved IP configure parameter from DHCP to the NVRam.
31 @param Event The callback event
32 @param Context Opaque context to the callback
39 Ip4ConfigOnDhcp4Complete (
46 Return the name and MAC address for the NIC. The Name, if not NULL,
47 has at least IP4_NIC_NAME_LENGTH bytes.
49 @param This The NIC IP4 CONFIG protocol
50 @param Name The buffer to return the name
51 @param NicAddr The buffer to return the MAC addr
53 @retval EFI_INVALID_PARAMETER This is NULL
54 @retval EFI_SUCCESS The name or address of the NIC are returned.
59 EfiNicIp4ConfigGetName (
60 IN EFI_NIC_IP4_CONFIG_PROTOCOL
*This
,
61 IN UINT16
*Name
, OPTIONAL
62 IN NIC_ADDR
*NicAddr OPTIONAL
65 IP4_CONFIG_INSTANCE
*Instance
;
68 return EFI_INVALID_PARAMETER
;
71 Instance
= IP4_CONFIG_INSTANCE_FROM_NIC_IP4CONFIG (This
);
74 CopyMem (Name
, Instance
->NicName
, IP4_NIC_NAME_LENGTH
);
77 if (NicAddr
!= NULL
) {
78 CopyMem (NicAddr
, &Instance
->NicAddr
, sizeof (*NicAddr
));
86 Get the NIC's configure information from the IP4 configure variable.
87 It will remove the invalid variable.
89 @param NicAddr The NIC to check
91 @return NULL if no configure for the NIC in the variable, or it is invalid.
92 @return Otherwise the NIC's IP configure parameter.
100 IP4_CONFIG_VARIABLE
*Variable
;
101 IP4_CONFIG_VARIABLE
*NewVariable
;
102 NIC_IP4_CONFIG_INFO
*Config
;
105 // Read the configuration parameter for this NicAddr from
108 Variable
= Ip4ConfigReadVariable ();
110 if (Variable
== NULL
) {
114 Config
= Ip4ConfigFindNicVariable (Variable
, NicAddr
);
116 if (Config
== NULL
) {
117 gBS
->FreePool (Variable
);
122 // Validate the configuration, if the configuration is invalid,
123 // remove it from the variable.
125 if (!Ip4ConfigIsValid (Config
)) {
126 NewVariable
= Ip4ConfigModifyVariable (Variable
, &Config
->NicAddr
, NULL
);
127 Ip4ConfigWriteVariable (NewVariable
);
129 if (NewVariable
!= NULL
) {
130 gBS
->FreePool (NewVariable
);
133 gBS
->FreePool (Config
);
137 gBS
->FreePool (Variable
);
143 Get the configure parameter for this NIC.
145 @param This The NIC IP4 CONFIG protocol
146 @param ConfigLen The length of the NicConfig buffer.
147 @param NicConfig The buffer to receive the NIC's configure
150 @retval EFI_INVALID_PARAMETER This or ConfigLen is NULL
151 @retval EFI_NOT_FOUND There is no configure parameter for the NIC in
157 EfiNicIp4ConfigGetInfo (
158 IN EFI_NIC_IP4_CONFIG_PROTOCOL
*This
,
159 IN OUT UINTN
*ConfigLen
,
160 OUT NIC_IP4_CONFIG_INFO
*NicConfig
163 IP4_CONFIG_INSTANCE
*Instance
;
164 NIC_IP4_CONFIG_INFO
*Config
;
168 if ((This
== NULL
) || (ConfigLen
== NULL
)) {
169 return EFI_INVALID_PARAMETER
;
173 // Read the Nic's configuration parameter from variable
175 Instance
= IP4_CONFIG_INSTANCE_FROM_NIC_IP4CONFIG (This
);
176 Config
= Ip4ConfigGetNicInfo (&Instance
->NicAddr
);
178 if (Config
== NULL
) {
179 return EFI_NOT_FOUND
;
183 // Copy the data to user's buffer
185 Len
= SIZEOF_NIC_IP4_CONFIG_INFO (Config
);
187 if ((*ConfigLen
< Len
) || (NicConfig
== NULL
)) {
188 Status
= EFI_BUFFER_TOO_SMALL
;
190 Status
= EFI_SUCCESS
;
191 CopyMem (NicConfig
, Config
, Len
);
192 Ip4ConfigFixRouteTablePointer (&NicConfig
->Ip4Info
);
197 gBS
->FreePool (Config
);
203 Set the IP configure parameters for this NIC. If Reconfig is TRUE,
204 the IP driver will be informed to discard current auto configure
205 parameter and restart the auto configuration process. If current
206 there is a pending auto configuration, EFI_ALREADY_STARTED is
207 returned. You can only change the configure setting when either
208 the configure has finished or not started yet. If NicConfig, the
209 NIC's configure parameter is removed from the variable.
211 @param This The NIC IP4 CONFIG protocol
212 @param NicConfig The new NIC IP4 configure parameter
213 @param Reconfig Inform the IP4 driver to restart the auto
216 @retval EFI_INVALID_PARAMETER This is NULL or the configure parameter is
218 @retval EFI_ALREADY_STARTED There is a pending auto configuration.
219 @retval EFI_NOT_FOUND No auto configure parameter is found
224 EfiNicIp4ConfigSetInfo (
225 IN EFI_NIC_IP4_CONFIG_PROTOCOL
*This
,
226 IN NIC_IP4_CONFIG_INFO
*NicConfig
, OPTIONAL
230 IP4_CONFIG_INSTANCE
*Instance
;
231 IP4_CONFIG_VARIABLE
*Variable
;
232 IP4_CONFIG_VARIABLE
*NewVariable
;
236 // Validate the parameters
239 return EFI_INVALID_PARAMETER
;
242 Instance
= IP4_CONFIG_INSTANCE_FROM_NIC_IP4CONFIG (This
);
244 if ((NicConfig
!= NULL
) && (!Ip4ConfigIsValid (NicConfig
) ||
245 !NIC_ADDR_EQUAL (&NicConfig
->NicAddr
, &Instance
->NicAddr
))) {
246 return EFI_INVALID_PARAMETER
;
249 if (Instance
->State
== IP4_CONFIG_STATE_STARTED
) {
250 return EFI_ALREADY_STARTED
;
254 // Update the parameter in the configure variable
256 Variable
= Ip4ConfigReadVariable ();
258 if ((Variable
== NULL
) && (NicConfig
== NULL
)) {
259 return EFI_NOT_FOUND
;
262 NewVariable
= Ip4ConfigModifyVariable (Variable
, &Instance
->NicAddr
, NicConfig
);
263 Status
= Ip4ConfigWriteVariable (NewVariable
);
265 if (NewVariable
!= NULL
) {
266 gBS
->FreePool (NewVariable
);
270 // Variable is NULL when saving the first configure parameter
272 if (Variable
!= NULL
) {
273 gBS
->FreePool (Variable
);
276 if (EFI_ERROR (Status
)) {
281 // Signal the IP4 to run the auto configuration again
283 if (Reconfig
&& (Instance
->ReconfigEvent
!= NULL
)) {
284 Status
= gBS
->SignalEvent (Instance
->ReconfigEvent
);
285 NetLibDispatchDpc ();
293 Start the auto configuration process.
295 @param This The IP4 configure protocol
296 @param DoneEvent The event to signal when auto configure is done
297 @param ReconfigEvent The event to signal when reconfigure is necessary.
299 @retval EFI_INVALID_PARAMETER One of the function parameters is NULL.
300 @retval EFI_ALREADY_STARTED The auto configuration has already started.
301 @retval EFI_SUCCESS The auto configure is successfully started.
307 IN EFI_IP4_CONFIG_PROTOCOL
*This
,
308 IN EFI_EVENT DoneEvent
,
309 IN EFI_EVENT ReconfigEvent
312 IP4_CONFIG_INSTANCE
*Instance
;
313 EFI_DHCP4_PROTOCOL
*Dhcp4
;
314 EFI_DHCP4_MODE_DATA Dhcp4Mode
;
315 EFI_DHCP4_PACKET_OPTION
*OptionList
[1];
316 IP4_CONFIG_DHCP4_OPTION ParaList
;
321 if ((This
== NULL
) || (DoneEvent
== NULL
) || (ReconfigEvent
== NULL
)) {
322 return EFI_INVALID_PARAMETER
;
325 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
327 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
329 if (Instance
->State
!= IP4_CONFIG_STATE_IDLE
) {
330 Status
= EFI_ALREADY_STARTED
;
335 Instance
->DoneEvent
= DoneEvent
;
336 Instance
->ReconfigEvent
= ReconfigEvent
;
338 Instance
->NicConfig
= Ip4ConfigGetNicInfo (&Instance
->NicAddr
);
340 if (Instance
->NicConfig
== NULL
) {
341 Source
= IP4_CONFIG_SOURCE_DHCP
;
343 Source
= Instance
->NicConfig
->Source
;
347 // If the source is static, the auto configuration is done.
350 if (Source
== IP4_CONFIG_SOURCE_STATIC
) {
351 Instance
->State
= IP4_CONFIG_STATE_CONFIGURED
;
352 Instance
->Result
= EFI_SUCCESS
;
354 gBS
->SignalEvent (Instance
->DoneEvent
);
355 Status
= EFI_SUCCESS
;
360 // Start the dhcp process
362 ASSERT ((Source
== IP4_CONFIG_SOURCE_DHCP
) && (Instance
->Dhcp4
== NULL
));
364 Status
= NetLibCreateServiceChild (
365 Instance
->Controller
,
367 &gEfiDhcp4ServiceBindingProtocolGuid
,
368 &Instance
->Dhcp4Handle
371 if (EFI_ERROR (Status
)) {
375 Status
= gBS
->OpenProtocol (
376 Instance
->Dhcp4Handle
,
377 &gEfiDhcp4ProtocolGuid
,
378 (VOID
**) &Instance
->Dhcp4
,
380 Instance
->Controller
,
381 EFI_OPEN_PROTOCOL_BY_DRIVER
384 if (EFI_ERROR (Status
)) {
389 // Check the current DHCP status, if the DHCP process has
390 // already finished, return now.
392 Dhcp4
= Instance
->Dhcp4
;
393 Status
= Dhcp4
->GetModeData (Dhcp4
, &Dhcp4Mode
);
395 if (EFI_ERROR (Status
)) {
399 if (Dhcp4Mode
.State
== Dhcp4Bound
) {
400 Ip4ConfigOnDhcp4Complete (NULL
, Instance
);
406 // Try to start the DHCP process. Use most of the current
407 // DHCP configuration to avoid problems if some DHCP client
408 // yields the control of this DHCP service to us.
410 ParaList
.Head
.OpCode
= DHCP_TAG_PARA_LIST
;
411 ParaList
.Head
.Length
= 2;
412 ParaList
.Head
.Data
[0] = DHCP_TAG_NETMASK
;
413 ParaList
.Route
= DHCP_TAG_ROUTER
;
414 OptionList
[0] = &ParaList
.Head
;
415 Dhcp4Mode
.ConfigData
.OptionCount
= 1;
416 Dhcp4Mode
.ConfigData
.OptionList
= OptionList
;
418 Status
= Dhcp4
->Configure (Dhcp4
, &Dhcp4Mode
.ConfigData
);
420 if (EFI_ERROR (Status
)) {
425 // Start the DHCP process
427 Status
= gBS
->CreateEvent (
430 Ip4ConfigOnDhcp4Complete
,
432 &Instance
->Dhcp4Event
435 if (EFI_ERROR (Status
)) {
439 Status
= Dhcp4
->Start (Dhcp4
, Instance
->Dhcp4Event
);
441 if (EFI_ERROR (Status
)) {
445 Instance
->State
= IP4_CONFIG_STATE_STARTED
;
446 Instance
->Result
= EFI_NOT_READY
;
449 if (EFI_ERROR (Status
)) {
450 Ip4ConfigCleanConfig (Instance
);
454 gBS
->RestoreTPL (OldTpl
);
456 NetLibDispatchDpc ();
463 Stop the current auto configuration
465 @param This The IP4 CONFIG protocol
467 @retval EFI_INVALID_PARAMETER This is NULL.
468 @retval EFI_NOT_STARTED The auto configuration hasn't been started.
469 @retval EFI_SUCCESS The auto configuration has been stopped.
475 IN EFI_IP4_CONFIG_PROTOCOL
*This
478 IP4_CONFIG_INSTANCE
*Instance
;
483 return EFI_INVALID_PARAMETER
;
486 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
488 Status
= EFI_SUCCESS
;
489 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
491 if (Instance
->State
== IP4_CONFIG_STATE_IDLE
) {
492 Status
= EFI_NOT_STARTED
;
497 // Release all the configure parameters. Don't signal the user
498 // event. The user wants to abort the configuration, this isn't
499 // the configuration done or reconfiguration.
501 Ip4ConfigCleanConfig (Instance
);
504 gBS
->RestoreTPL (OldTpl
);
511 Get the current outcome of the auto configuration process
513 @param This The IP4 CONFIG protocol
514 @param ConfigDataSize The size of the configure data
515 @param ConfigData The buffer to save the configure data
517 @retval EFI_INVALID_PARAMETER This or ConfigDataSize is NULL
518 @retval EFI_BUFFER_TOO_SMALL The buffer is too small. The needed size is
519 returned in the ConfigDataSize.
520 @retval EFI_SUCCESS The configure data is put in the buffer
525 EfiIp4ConfigGetData (
526 IN EFI_IP4_CONFIG_PROTOCOL
*This
,
527 IN OUT UINTN
*ConfigDataSize
,
528 OUT EFI_IP4_IPCONFIG_DATA
*ConfigData OPTIONAL
531 IP4_CONFIG_INSTANCE
*Instance
;
532 NIC_IP4_CONFIG_INFO
*NicConfig
;
537 if ((This
== NULL
) || (ConfigDataSize
== NULL
)) {
538 return EFI_INVALID_PARAMETER
;
541 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
543 Status
= EFI_SUCCESS
;
544 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
546 if (Instance
->State
== IP4_CONFIG_STATE_IDLE
) {
547 Status
= EFI_NOT_STARTED
;
548 } else if (Instance
->State
== IP4_CONFIG_STATE_STARTED
) {
549 Status
= EFI_NOT_READY
;
552 if (EFI_ERROR (Status
)) {
557 // Copy the configure data if auto configuration succeeds.
559 Status
= Instance
->Result
;
561 if (Status
== EFI_SUCCESS
) {
562 ASSERT (Instance
->NicConfig
!= NULL
);
564 NicConfig
= Instance
->NicConfig
;
565 Len
= SIZEOF_IP4_CONFIG_INFO (&NicConfig
->Ip4Info
);
567 if ((*ConfigDataSize
< Len
) || (ConfigData
== NULL
)) {
568 Status
= EFI_BUFFER_TOO_SMALL
;
570 CopyMem (ConfigData
, &NicConfig
->Ip4Info
, Len
);
571 Ip4ConfigFixRouteTablePointer (ConfigData
);
574 *ConfigDataSize
= Len
;
578 gBS
->RestoreTPL (OldTpl
);
585 Callback function when DHCP process finished. It will save the
586 retrieved IP configure parameter from DHCP to the NVRam.
588 @param Event The callback event
589 @param Context Opaque context to the callback
596 Ip4ConfigOnDhcp4Complete (
601 IP4_CONFIG_INSTANCE
*Instance
;
602 EFI_DHCP4_MODE_DATA Dhcp4Mode
;
603 EFI_IP4_IPCONFIG_DATA
*Ip4Config
;
610 Instance
= (IP4_CONFIG_INSTANCE
*) Context
;
611 ASSERT (Instance
->Dhcp4
!= NULL
);
613 Instance
->State
= IP4_CONFIG_STATE_CONFIGURED
;
614 Instance
->Result
= EFI_TIMEOUT
;
617 // Get the DHCP retrieved parameters
619 Status
= Instance
->Dhcp4
->GetModeData (Instance
->Dhcp4
, &Dhcp4Mode
);
621 if (EFI_ERROR (Status
)) {
625 if (Dhcp4Mode
.State
== Dhcp4Bound
) {
627 // Save the new configuration retrieved by DHCP both in
628 // the instance and to NVRam. So, both the IP4 driver and
629 // other user can get that address.
633 if (Instance
->NicConfig
!= NULL
) {
634 ASSERT (Instance
->NicConfig
->Source
== IP4_CONFIG_SOURCE_DHCP
);
635 Perment
= Instance
->NicConfig
->Perment
;
636 gBS
->FreePool (Instance
->NicConfig
);
639 Instance
->NicConfig
= AllocatePool (sizeof (NIC_IP4_CONFIG_INFO
) + 2* sizeof (EFI_IP4_ROUTE_TABLE
));
641 if (Instance
->NicConfig
== NULL
) {
642 Instance
->Result
= EFI_OUT_OF_RESOURCES
;
646 Instance
->NicConfig
->Ip4Info
.RouteTable
= (EFI_IP4_ROUTE_TABLE
*) (Instance
->NicConfig
+ 1);
648 CopyMem (&Instance
->NicConfig
->NicAddr
, &Instance
->NicAddr
, sizeof (Instance
->NicConfig
->NicAddr
));
649 Instance
->NicConfig
->Source
= IP4_CONFIG_SOURCE_DHCP
;
650 Instance
->NicConfig
->Perment
= Perment
;
652 Ip4Config
= &Instance
->NicConfig
->Ip4Info
;
653 Ip4Config
->StationAddress
= Dhcp4Mode
.ClientAddress
;
654 Ip4Config
->SubnetMask
= Dhcp4Mode
.SubnetMask
;
657 // Create a route for the connected network
659 Ip4Config
->RouteTableSize
= 1;
661 CopyMem (&Ip1
, &Dhcp4Mode
.ClientAddress
, sizeof (IP4_ADDR
));
662 CopyMem (&Ip2
, &Dhcp4Mode
.SubnetMask
, sizeof (IP4_ADDR
));
666 CopyMem (&Ip4Config
->RouteTable
[0].SubnetAddress
, &Subnet
, sizeof (EFI_IPv4_ADDRESS
));
667 CopyMem (&Ip4Config
->RouteTable
[0].SubnetMask
, &Dhcp4Mode
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
668 ZeroMem (&Ip4Config
->RouteTable
[0].GatewayAddress
, sizeof (EFI_IPv4_ADDRESS
));
671 // Create a route if there is a default router.
673 if (!EFI_IP4_EQUAL (&Dhcp4Mode
.RouterAddress
, &mZeroIp4Addr
)) {
674 Ip4Config
->RouteTableSize
= 2;
676 ZeroMem (&Ip4Config
->RouteTable
[1].SubnetAddress
, sizeof (EFI_IPv4_ADDRESS
));
677 ZeroMem (&Ip4Config
->RouteTable
[1].SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
678 CopyMem (&Ip4Config
->RouteTable
[1].GatewayAddress
, &Dhcp4Mode
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
681 Instance
->Result
= EFI_SUCCESS
;
684 // ignore the return status of EfiNicIp4ConfigSetInfo. Network
685 // stack can operate even that failed.
687 EfiNicIp4ConfigSetInfo (&Instance
->NicIp4Protocol
, Instance
->NicConfig
, FALSE
);
691 gBS
->SignalEvent (Instance
->DoneEvent
);
692 Ip4ConfigCleanDhcp4 (Instance
);
694 NetLibDispatchDpc ();
701 Release all the DHCP related resources.
703 @param This The IP4 configure instance
709 Ip4ConfigCleanDhcp4 (
710 IN IP4_CONFIG_INSTANCE
*This
713 if (This
->Dhcp4
!= NULL
) {
714 This
->Dhcp4
->Stop (This
->Dhcp4
);
718 &gEfiDhcp4ProtocolGuid
,
726 if (This
->Dhcp4Handle
!= NULL
) {
727 NetLibDestroyServiceChild (
730 &gEfiDhcp4ServiceBindingProtocolGuid
,
734 This
->Dhcp4Handle
= NULL
;
737 if (This
->Dhcp4Event
== NULL
) {
738 gBS
->CloseEvent (This
->Dhcp4Event
);
739 This
->Dhcp4Event
= NULL
;
745 Clean up all the configuration parameters.
747 @param Instance The IP4 configure instance
753 Ip4ConfigCleanConfig (
754 IN IP4_CONFIG_INSTANCE
*Instance
757 if (Instance
->NicConfig
!= NULL
) {
758 gBS
->FreePool (Instance
->NicConfig
);
759 Instance
->NicConfig
= NULL
;
762 Instance
->State
= IP4_CONFIG_STATE_IDLE
;
763 Instance
->DoneEvent
= NULL
;
764 Instance
->ReconfigEvent
= NULL
;
766 Ip4ConfigCleanDhcp4 (Instance
);
769 EFI_IP4_CONFIG_PROTOCOL mIp4ConfigProtocolTemplate
= {
775 EFI_NIC_IP4_CONFIG_PROTOCOL mNicIp4ConfigProtocolTemplate
= {
776 EfiNicIp4ConfigGetName
,
777 EfiNicIp4ConfigGetInfo
,
778 EfiNicIp4ConfigSetInfo