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
];
29 Ip4ConfigOnDhcp4Complete (
36 Return the name and MAC address for the NIC. The Name, if not NULL,
37 has at least IP4_NIC_NAME_LENGTH bytes.
39 @param This The NIC IP4 CONFIG protocol
40 @param Name The buffer to return the name
41 @param NicAddr The buffer to return the MAC addr
43 @retval EFI_INVALID_PARAMETER This is NULL
44 @retval EFI_SUCCESS The name or address of the NIC are returned.
50 EfiNicIp4ConfigGetName (
51 IN EFI_NIC_IP4_CONFIG_PROTOCOL
*This
,
52 IN UINT16
*Name
, OPTIONAL
53 IN NIC_ADDR
*NicAddr OPTIONAL
56 IP4_CONFIG_INSTANCE
*Instance
;
59 return EFI_INVALID_PARAMETER
;
62 Instance
= IP4_CONFIG_INSTANCE_FROM_NIC_IP4CONFIG (This
);
65 CopyMem (Name
, Instance
->NicName
, IP4_NIC_NAME_LENGTH
);
68 if (NicAddr
!= NULL
) {
69 CopyMem (NicAddr
, &Instance
->NicAddr
, sizeof (*NicAddr
));
77 Get the NIC's configure information from the IP4 configure variable.
78 It will remove the invalid variable.
80 @param NicAddr The NIC to check
82 @return NULL if no configure for the NIC in the variable, or it is invalid.
83 @return Otherwise the NIC's IP configure parameter.
91 IP4_CONFIG_VARIABLE
*Variable
;
92 IP4_CONFIG_VARIABLE
*NewVariable
;
93 NIC_IP4_CONFIG_INFO
*Config
;
96 // Read the configuration parameter for this NicAddr from
99 Variable
= Ip4ConfigReadVariable ();
101 if (Variable
== NULL
) {
105 Config
= Ip4ConfigFindNicVariable (Variable
, NicAddr
);
107 if (Config
== NULL
) {
108 gBS
->FreePool (Variable
);
113 // Validate the configuration, if the configuration is invalid,
114 // remove it from the variable.
116 if (!Ip4ConfigIsValid (Config
)) {
117 NewVariable
= Ip4ConfigModifyVariable (Variable
, &Config
->NicAddr
, NULL
);
118 Ip4ConfigWriteVariable (NewVariable
);
120 if (NewVariable
!= NULL
) {
121 gBS
->FreePool (NewVariable
);
124 gBS
->FreePool (Config
);
128 gBS
->FreePool (Variable
);
134 Get the configure parameter for this NIC.
136 @param This The NIC IP4 CONFIG protocol
137 @param ConfigLen The length of the NicConfig buffer.
138 @param NicConfig The buffer to receive the NIC's configure
141 @retval EFI_INVALID_PARAMETER This or ConfigLen is NULL
142 @retval EFI_NOT_FOUND There is no configure parameter for the NIC in
148 EfiNicIp4ConfigGetInfo (
149 IN EFI_NIC_IP4_CONFIG_PROTOCOL
*This
,
150 IN OUT UINTN
*ConfigLen
,
151 OUT NIC_IP4_CONFIG_INFO
*NicConfig
154 IP4_CONFIG_INSTANCE
*Instance
;
155 NIC_IP4_CONFIG_INFO
*Config
;
159 if ((This
== NULL
) || (ConfigLen
== NULL
)) {
160 return EFI_INVALID_PARAMETER
;
164 // Read the Nic's configuration parameter from variable
166 Instance
= IP4_CONFIG_INSTANCE_FROM_NIC_IP4CONFIG (This
);
167 Config
= Ip4ConfigGetNicInfo (&Instance
->NicAddr
);
169 if (Config
== NULL
) {
170 return EFI_NOT_FOUND
;
174 // Copy the data to user's buffer
176 Len
= SIZEOF_NIC_IP4_CONFIG_INFO (Config
);
178 if ((*ConfigLen
< Len
) || (NicConfig
== NULL
)) {
179 Status
= EFI_BUFFER_TOO_SMALL
;
181 Status
= EFI_SUCCESS
;
182 CopyMem (NicConfig
, Config
, Len
);
183 Ip4ConfigFixRouteTablePointer (&NicConfig
->Ip4Info
);
188 gBS
->FreePool (Config
);
194 Set the IP configure parameters for this NIC. If Reconfig is TRUE,
195 the IP driver will be informed to discard current auto configure
196 parameter and restart the auto configuration process. If current
197 there is a pending auto configuration, EFI_ALREADY_STARTED is
198 returned. You can only change the configure setting when either
199 the configure has finished or not started yet. If NicConfig, the
200 NIC's configure parameter is removed from the variable.
202 @param This The NIC IP4 CONFIG protocol
203 @param NicConfig The new NIC IP4 configure parameter
204 @param Reconfig Inform the IP4 driver to restart the auto
207 @retval EFI_INVALID_PARAMETER This is NULL or the configure parameter is
209 @retval EFI_ALREADY_STARTED There is a pending auto configuration.
210 @retval EFI_NOT_FOUND No auto configure parameter is found
215 EfiNicIp4ConfigSetInfo (
216 IN EFI_NIC_IP4_CONFIG_PROTOCOL
*This
,
217 IN NIC_IP4_CONFIG_INFO
*NicConfig
, OPTIONAL
221 IP4_CONFIG_INSTANCE
*Instance
;
222 IP4_CONFIG_VARIABLE
*Variable
;
223 IP4_CONFIG_VARIABLE
*NewVariable
;
227 // Validate the parameters
230 return EFI_INVALID_PARAMETER
;
233 Instance
= IP4_CONFIG_INSTANCE_FROM_NIC_IP4CONFIG (This
);
235 if ((NicConfig
!= NULL
) && (!Ip4ConfigIsValid (NicConfig
) ||
236 !NIC_ADDR_EQUAL (&NicConfig
->NicAddr
, &Instance
->NicAddr
))) {
237 return EFI_INVALID_PARAMETER
;
240 if (Instance
->State
== IP4_CONFIG_STATE_STARTED
) {
241 return EFI_ALREADY_STARTED
;
245 // Update the parameter in the configure variable
247 Variable
= Ip4ConfigReadVariable ();
249 if ((Variable
== NULL
) && (NicConfig
== NULL
)) {
250 return EFI_NOT_FOUND
;
253 NewVariable
= Ip4ConfigModifyVariable (Variable
, &Instance
->NicAddr
, NicConfig
);
254 Status
= Ip4ConfigWriteVariable (NewVariable
);
256 if (NewVariable
!= NULL
) {
257 gBS
->FreePool (NewVariable
);
261 // Variable is NULL when saving the first configure parameter
263 if (Variable
!= NULL
) {
264 gBS
->FreePool (Variable
);
267 if (EFI_ERROR (Status
)) {
272 // Signal the IP4 to run the auto configuration again
274 if (Reconfig
&& (Instance
->ReconfigEvent
!= NULL
)) {
275 Status
= gBS
->SignalEvent (Instance
->ReconfigEvent
);
276 NetLibDispatchDpc ();
284 Start the auto configuration process.
286 @param This The IP4 configure protocol
287 @param DoneEvent The event to signal when auto configure is done
288 @param ReconfigEvent The event to signal when reconfigure is necessary.
290 @retval EFI_INVALID_PARAMETER One of the function parameters is NULL.
291 @retval EFI_ALREADY_STARTED The auto configuration has already started.
292 @retval EFI_SUCCESS The auto configure is successfully started.
298 IN EFI_IP4_CONFIG_PROTOCOL
*This
,
299 IN EFI_EVENT DoneEvent
,
300 IN EFI_EVENT ReconfigEvent
303 IP4_CONFIG_INSTANCE
*Instance
;
304 EFI_DHCP4_PROTOCOL
*Dhcp4
;
305 EFI_DHCP4_MODE_DATA Dhcp4Mode
;
306 EFI_DHCP4_PACKET_OPTION
*OptionList
[1];
307 IP4_CONFIG_DHCP4_OPTION ParaList
;
312 if ((This
== NULL
) || (DoneEvent
== NULL
) || (ReconfigEvent
== NULL
)) {
313 return EFI_INVALID_PARAMETER
;
316 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
318 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
320 if (Instance
->State
!= IP4_CONFIG_STATE_IDLE
) {
321 Status
= EFI_ALREADY_STARTED
;
326 Instance
->DoneEvent
= DoneEvent
;
327 Instance
->ReconfigEvent
= ReconfigEvent
;
329 Instance
->NicConfig
= Ip4ConfigGetNicInfo (&Instance
->NicAddr
);
331 if (Instance
->NicConfig
== NULL
) {
332 Source
= IP4_CONFIG_SOURCE_DHCP
;
334 Source
= Instance
->NicConfig
->Source
;
338 // If the source is static, the auto configuration is done.
341 if (Source
== IP4_CONFIG_SOURCE_STATIC
) {
342 Instance
->State
= IP4_CONFIG_STATE_CONFIGURED
;
343 Instance
->Result
= EFI_SUCCESS
;
345 gBS
->SignalEvent (Instance
->DoneEvent
);
346 Status
= EFI_SUCCESS
;
351 // Start the dhcp process
353 ASSERT ((Source
== IP4_CONFIG_SOURCE_DHCP
) && (Instance
->Dhcp4
== NULL
));
355 Status
= NetLibCreateServiceChild (
356 Instance
->Controller
,
358 &gEfiDhcp4ServiceBindingProtocolGuid
,
359 &Instance
->Dhcp4Handle
362 if (EFI_ERROR (Status
)) {
366 Status
= gBS
->OpenProtocol (
367 Instance
->Dhcp4Handle
,
368 &gEfiDhcp4ProtocolGuid
,
369 (VOID
**) &Instance
->Dhcp4
,
371 Instance
->Controller
,
372 EFI_OPEN_PROTOCOL_BY_DRIVER
375 if (EFI_ERROR (Status
)) {
380 // Check the current DHCP status, if the DHCP process has
381 // already finished, return now.
383 Dhcp4
= Instance
->Dhcp4
;
384 Status
= Dhcp4
->GetModeData (Dhcp4
, &Dhcp4Mode
);
386 if (EFI_ERROR (Status
)) {
390 if (Dhcp4Mode
.State
== Dhcp4Bound
) {
391 Ip4ConfigOnDhcp4Complete (NULL
, Instance
);
397 // Try to start the DHCP process. Use most of the current
398 // DHCP configuration to avoid problems if some DHCP client
399 // yields the control of this DHCP service to us.
401 ParaList
.Head
.OpCode
= DHCP_TAG_PARA_LIST
;
402 ParaList
.Head
.Length
= 2;
403 ParaList
.Head
.Data
[0] = DHCP_TAG_NETMASK
;
404 ParaList
.Route
= DHCP_TAG_ROUTER
;
405 OptionList
[0] = &ParaList
.Head
;
406 Dhcp4Mode
.ConfigData
.OptionCount
= 1;
407 Dhcp4Mode
.ConfigData
.OptionList
= OptionList
;
409 Status
= Dhcp4
->Configure (Dhcp4
, &Dhcp4Mode
.ConfigData
);
411 if (EFI_ERROR (Status
)) {
416 // Start the DHCP process
418 Status
= gBS
->CreateEvent (
421 Ip4ConfigOnDhcp4Complete
,
423 &Instance
->Dhcp4Event
426 if (EFI_ERROR (Status
)) {
430 Status
= Dhcp4
->Start (Dhcp4
, Instance
->Dhcp4Event
);
432 if (EFI_ERROR (Status
)) {
436 Instance
->State
= IP4_CONFIG_STATE_STARTED
;
437 Instance
->Result
= EFI_NOT_READY
;
440 if (EFI_ERROR (Status
)) {
441 Ip4ConfigCleanConfig (Instance
);
445 gBS
->RestoreTPL (OldTpl
);
447 NetLibDispatchDpc ();
454 Stop the current auto configuration
456 @param This The IP4 CONFIG protocol
458 @retval EFI_INVALID_PARAMETER This is NULL.
459 @retval EFI_NOT_STARTED The auto configuration hasn't been started.
460 @retval EFI_SUCCESS The auto configuration has been stopped.
466 IN EFI_IP4_CONFIG_PROTOCOL
*This
469 IP4_CONFIG_INSTANCE
*Instance
;
474 return EFI_INVALID_PARAMETER
;
477 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
479 Status
= EFI_SUCCESS
;
480 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
482 if (Instance
->State
== IP4_CONFIG_STATE_IDLE
) {
483 Status
= EFI_NOT_STARTED
;
488 // Release all the configure parameters. Don't signal the user
489 // event. The user wants to abort the configuration, this isn't
490 // the configuration done or reconfiguration.
492 Ip4ConfigCleanConfig (Instance
);
495 gBS
->RestoreTPL (OldTpl
);
502 Get the current outcome of the auto configuration process
504 @param This The IP4 CONFIG protocol
505 @param ConfigDataSize The size of the configure data
506 @param ConfigData The buffer to save the configure data
508 @retval EFI_INVALID_PARAMETER This or ConfigDataSize is NULL
509 @retval EFI_BUFFER_TOO_SMALL The buffer is too small. The needed size is
510 returned in the ConfigDataSize.
511 @retval EFI_SUCCESS The configure data is put in the buffer
516 EfiIp4ConfigGetData (
517 IN EFI_IP4_CONFIG_PROTOCOL
*This
,
518 IN OUT UINTN
*ConfigDataSize
,
519 OUT EFI_IP4_IPCONFIG_DATA
*ConfigData OPTIONAL
522 IP4_CONFIG_INSTANCE
*Instance
;
523 NIC_IP4_CONFIG_INFO
*NicConfig
;
528 if ((This
== NULL
) || (ConfigDataSize
== NULL
)) {
529 return EFI_INVALID_PARAMETER
;
532 Instance
= IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This
);
534 Status
= EFI_SUCCESS
;
535 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
537 if (Instance
->State
== IP4_CONFIG_STATE_IDLE
) {
538 Status
= EFI_NOT_STARTED
;
539 } else if (Instance
->State
== IP4_CONFIG_STATE_STARTED
) {
540 Status
= EFI_NOT_READY
;
543 if (EFI_ERROR (Status
)) {
548 // Copy the configure data if auto configuration succeeds.
550 Status
= Instance
->Result
;
552 if (Status
== EFI_SUCCESS
) {
553 ASSERT (Instance
->NicConfig
!= NULL
);
555 NicConfig
= Instance
->NicConfig
;
556 Len
= SIZEOF_IP4_CONFIG_INFO (&NicConfig
->Ip4Info
);
558 if ((*ConfigDataSize
< Len
) || (ConfigData
== NULL
)) {
559 Status
= EFI_BUFFER_TOO_SMALL
;
561 CopyMem (ConfigData
, &NicConfig
->Ip4Info
, Len
);
562 Ip4ConfigFixRouteTablePointer (ConfigData
);
565 *ConfigDataSize
= Len
;
569 gBS
->RestoreTPL (OldTpl
);
576 Callback function when DHCP process finished. It will save the
577 retrieved IP configure parameter from DHCP to the NVRam.
579 @param Event The callback event
580 @param Context Opaque context to the callback
587 Ip4ConfigOnDhcp4Complete (
592 IP4_CONFIG_INSTANCE
*Instance
;
593 EFI_DHCP4_MODE_DATA Dhcp4Mode
;
594 EFI_IP4_IPCONFIG_DATA
*Ip4Config
;
601 Instance
= (IP4_CONFIG_INSTANCE
*) Context
;
602 ASSERT (Instance
->Dhcp4
!= NULL
);
604 Instance
->State
= IP4_CONFIG_STATE_CONFIGURED
;
605 Instance
->Result
= EFI_TIMEOUT
;
608 // Get the DHCP retrieved parameters
610 Status
= Instance
->Dhcp4
->GetModeData (Instance
->Dhcp4
, &Dhcp4Mode
);
612 if (EFI_ERROR (Status
)) {
616 if (Dhcp4Mode
.State
== Dhcp4Bound
) {
618 // Save the new configuration retrieved by DHCP both in
619 // the instance and to NVRam. So, both the IP4 driver and
620 // other user can get that address.
624 if (Instance
->NicConfig
!= NULL
) {
625 ASSERT (Instance
->NicConfig
->Source
== IP4_CONFIG_SOURCE_DHCP
);
626 Perment
= Instance
->NicConfig
->Perment
;
627 gBS
->FreePool (Instance
->NicConfig
);
630 Instance
->NicConfig
= AllocatePool (sizeof (NIC_IP4_CONFIG_INFO
) + 2* sizeof (EFI_IP4_ROUTE_TABLE
));
632 if (Instance
->NicConfig
== NULL
) {
633 Instance
->Result
= EFI_OUT_OF_RESOURCES
;
637 Instance
->NicConfig
->Ip4Info
.RouteTable
= (EFI_IP4_ROUTE_TABLE
*) (Instance
->NicConfig
+ 1);
639 CopyMem (&Instance
->NicConfig
->NicAddr
, &Instance
->NicAddr
, sizeof (Instance
->NicConfig
->NicAddr
));
640 Instance
->NicConfig
->Source
= IP4_CONFIG_SOURCE_DHCP
;
641 Instance
->NicConfig
->Perment
= Perment
;
643 Ip4Config
= &Instance
->NicConfig
->Ip4Info
;
644 Ip4Config
->StationAddress
= Dhcp4Mode
.ClientAddress
;
645 Ip4Config
->SubnetMask
= Dhcp4Mode
.SubnetMask
;
648 // Create a route for the connected network
650 Ip4Config
->RouteTableSize
= 1;
652 CopyMem (&Ip1
, &Dhcp4Mode
.ClientAddress
, sizeof (IP4_ADDR
));
653 CopyMem (&Ip2
, &Dhcp4Mode
.SubnetMask
, sizeof (IP4_ADDR
));
657 CopyMem (&Ip4Config
->RouteTable
[0].SubnetAddress
, &Subnet
, sizeof (EFI_IPv4_ADDRESS
));
658 CopyMem (&Ip4Config
->RouteTable
[0].SubnetMask
, &Dhcp4Mode
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
659 ZeroMem (&Ip4Config
->RouteTable
[0].GatewayAddress
, sizeof (EFI_IPv4_ADDRESS
));
662 // Create a route if there is a default router.
664 if (!EFI_IP4_EQUAL (&Dhcp4Mode
.RouterAddress
, &mZeroIp4Addr
)) {
665 Ip4Config
->RouteTableSize
= 2;
667 ZeroMem (&Ip4Config
->RouteTable
[1].SubnetAddress
, sizeof (EFI_IPv4_ADDRESS
));
668 ZeroMem (&Ip4Config
->RouteTable
[1].SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
669 CopyMem (&Ip4Config
->RouteTable
[1].GatewayAddress
, &Dhcp4Mode
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
672 Instance
->Result
= EFI_SUCCESS
;
675 // ignore the return status of EfiNicIp4ConfigSetInfo. Network
676 // stack can operate even that failed.
678 EfiNicIp4ConfigSetInfo (&Instance
->NicIp4Protocol
, Instance
->NicConfig
, FALSE
);
682 gBS
->SignalEvent (Instance
->DoneEvent
);
683 Ip4ConfigCleanDhcp4 (Instance
);
685 NetLibDispatchDpc ();
692 Release all the DHCP related resources.
694 @param This The IP4 configure instance
700 Ip4ConfigCleanDhcp4 (
701 IN IP4_CONFIG_INSTANCE
*This
704 if (This
->Dhcp4
!= NULL
) {
705 This
->Dhcp4
->Stop (This
->Dhcp4
);
709 &gEfiDhcp4ProtocolGuid
,
717 if (This
->Dhcp4Handle
!= NULL
) {
718 NetLibDestroyServiceChild (
721 &gEfiDhcp4ServiceBindingProtocolGuid
,
725 This
->Dhcp4Handle
= NULL
;
728 if (This
->Dhcp4Event
== NULL
) {
729 gBS
->CloseEvent (This
->Dhcp4Event
);
730 This
->Dhcp4Event
= NULL
;
736 Clean up all the configuration parameters
738 @param Instance The IP4 configure instance
744 Ip4ConfigCleanConfig (
745 IN IP4_CONFIG_INSTANCE
*Instance
748 if (Instance
->NicConfig
!= NULL
) {
749 gBS
->FreePool (Instance
->NicConfig
);
750 Instance
->NicConfig
= NULL
;
753 Instance
->State
= IP4_CONFIG_STATE_IDLE
;
754 Instance
->DoneEvent
= NULL
;
755 Instance
->ReconfigEvent
= NULL
;
757 Ip4ConfigCleanDhcp4 (Instance
);
760 EFI_IP4_CONFIG_PROTOCOL mIp4ConfigProtocolTemplate
= {
766 EFI_NIC_IP4_CONFIG_PROTOCOL mNicIp4ConfigProtocolTemplate
= {
767 EfiNicIp4ConfigGetName
,
768 EfiNicIp4ConfigGetInfo
,
769 EfiNicIp4ConfigSetInfo