]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4Config.c
1. update to use 1 EFI Variable per NIC (instead of converge all NIC configuration...
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4ConfigDxe / Ip4Config.c
1 /** @file
2 This code implements the IP4Config and NicIp4Config protocols.
3
4 Copyright (c) 2006 - 2010, 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
9
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.
12
13 **/
14
15 #include "Ip4Config.h"
16 #include "NicIp4Variable.h"
17
18
19 /**
20 Get the NIC's configure information from the IP4 configure variable.
21 It will remove the invalid variable.
22
23 @param Instance The IP4 CONFIG instance.
24
25 @return NULL if no configure for the NIC in the variable, or it is invalid.
26 Otherwise the pointer to the NIC's IP configure parameter will be returned.
27
28 **/
29 NIC_IP4_CONFIG_INFO *
30 EfiNicIp4ConfigGetInfo (
31 IN IP4_CONFIG_INSTANCE *Instance
32 )
33 {
34 NIC_IP4_CONFIG_INFO *NicConfig;
35
36 //
37 // Read the configuration parameter for this NIC from
38 // the EFI variable
39 //
40 NicConfig = Ip4ConfigReadVariable (Instance);
41 if (NicConfig == NULL) {
42 return NULL;
43 }
44
45 //
46 // Validate the configuration, if the configuration is invalid,
47 // remove it from the variable.
48 //
49 if (!Ip4ConfigIsValid (NicConfig)) {
50 Ip4ConfigWriteVariable (Instance, NULL);
51
52 FreePool (NicConfig);
53 NicConfig = NULL;
54 }
55
56 return NicConfig;
57 }
58
59 /**
60 Set the IP configure parameters for this NIC.
61
62 If Reconfig is TRUE, the IP driver will be informed to discard current
63 auto configure parameter and restart the auto configuration process.
64 If current there is a pending auto configuration, EFI_ALREADY_STARTED is
65 returned. You can only change the configure setting when either
66 the configure has finished or not started yet. If NicConfig, the
67 NIC's configure parameter is removed from the variable.
68
69 @param Instance The IP4 CONFIG instance.
70 @param NicConfig The new NIC IP4 configure parameter.
71 @param Reconfig Inform the IP4 driver to restart the auto
72 configuration.
73
74 @retval EFI_SUCCESS The configure parameter for this NIC was
75 set successfully.
76 @retval EFI_INVALID_PARAMETER This is NULL or the configure parameter is
77 invalid.
78 @retval EFI_ALREADY_STARTED There is a pending auto configuration.
79 @retval EFI_NOT_FOUND No auto configure parameter is found.
80
81 **/
82 EFI_STATUS
83 EFIAPI
84 EfiNicIp4ConfigSetInfo (
85 IN IP4_CONFIG_INSTANCE *Instance,
86 IN NIC_IP4_CONFIG_INFO *NicConfig OPTIONAL,
87 IN BOOLEAN Reconfig
88 )
89 {
90 EFI_STATUS Status;
91
92 //
93 // Validate the parameters
94 //
95 if (Instance == NULL) {
96 return EFI_INVALID_PARAMETER;
97 }
98
99 if ((NicConfig != NULL) && (!Ip4ConfigIsValid (NicConfig) ||
100 !NIC_ADDR_EQUAL (&NicConfig->NicAddr, &Instance->NicAddr))) {
101 return EFI_INVALID_PARAMETER;
102 }
103
104 if (Instance->State == IP4_CONFIG_STATE_STARTED) {
105 return EFI_ALREADY_STARTED;
106 }
107
108 //
109 // Update the parameter in the configure variable
110 //
111 Status = Ip4ConfigWriteVariable (Instance, NicConfig);
112 if (EFI_ERROR (Status)) {
113 return Status;
114 }
115
116 //
117 // Signal the IP4 to run the auto configuration again
118 //
119 if (Reconfig && (Instance->ReconfigEvent != NULL)) {
120 Status = gBS->SignalEvent (Instance->ReconfigEvent);
121 DispatchDpc ();
122 }
123
124 return Status;
125 }
126
127 /**
128 Callback function when DHCP process finished. It will save the
129 retrieved IP configure parameter from DHCP to the NVRam.
130
131 @param Event The callback event
132 @param Context Opaque context to the callback
133
134 @return None
135
136 **/
137 VOID
138 EFIAPI
139 Ip4ConfigOnDhcp4Complete (
140 IN EFI_EVENT Event,
141 IN VOID *Context
142 )
143 {
144 IP4_CONFIG_INSTANCE *Instance;
145 EFI_DHCP4_MODE_DATA Dhcp4Mode;
146 EFI_IP4_IPCONFIG_DATA *Ip4Config;
147 EFI_STATUS Status;
148 BOOLEAN Perment;
149 IP4_ADDR Subnet;
150 IP4_ADDR Ip1;
151 IP4_ADDR Ip2;
152
153 Instance = (IP4_CONFIG_INSTANCE *) Context;
154 ASSERT (Instance->Dhcp4 != NULL);
155
156 Instance->State = IP4_CONFIG_STATE_CONFIGURED;
157 Instance->Result = EFI_TIMEOUT;
158
159 //
160 // Get the DHCP retrieved parameters
161 //
162 Status = Instance->Dhcp4->GetModeData (Instance->Dhcp4, &Dhcp4Mode);
163
164 if (EFI_ERROR (Status)) {
165 goto ON_EXIT;
166 }
167
168 if (Dhcp4Mode.State == Dhcp4Bound) {
169 //
170 // Save the new configuration retrieved by DHCP both in
171 // the instance and to NVRam. So, both the IP4 driver and
172 // other user can get that address.
173 //
174 Perment = FALSE;
175
176 if (Instance->NicConfig != NULL) {
177 ASSERT (Instance->NicConfig->Source == IP4_CONFIG_SOURCE_DHCP);
178 Perment = Instance->NicConfig->Perment;
179 FreePool (Instance->NicConfig);
180 }
181
182 Instance->NicConfig = AllocatePool (sizeof (NIC_IP4_CONFIG_INFO) + 2* sizeof (EFI_IP4_ROUTE_TABLE));
183
184 if (Instance->NicConfig == NULL) {
185 Instance->Result = EFI_OUT_OF_RESOURCES;
186 goto ON_EXIT;
187 }
188
189 Instance->NicConfig->Ip4Info.RouteTable = (EFI_IP4_ROUTE_TABLE *) (Instance->NicConfig + 1);
190
191 CopyMem (&Instance->NicConfig->NicAddr, &Instance->NicAddr, sizeof (Instance->NicConfig->NicAddr));
192 Instance->NicConfig->Source = IP4_CONFIG_SOURCE_DHCP;
193 Instance->NicConfig->Perment = Perment;
194
195 Ip4Config = &Instance->NicConfig->Ip4Info;
196 Ip4Config->StationAddress = Dhcp4Mode.ClientAddress;
197 Ip4Config->SubnetMask = Dhcp4Mode.SubnetMask;
198
199 //
200 // Create a route for the connected network
201 //
202 Ip4Config->RouteTableSize = 1;
203
204 CopyMem (&Ip1, &Dhcp4Mode.ClientAddress, sizeof (IP4_ADDR));
205 CopyMem (&Ip2, &Dhcp4Mode.SubnetMask, sizeof (IP4_ADDR));
206
207 Subnet = Ip1 & Ip2;
208
209 CopyMem (&Ip4Config->RouteTable[0].SubnetAddress, &Subnet, sizeof (EFI_IPv4_ADDRESS));
210 CopyMem (&Ip4Config->RouteTable[0].SubnetMask, &Dhcp4Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
211 ZeroMem (&Ip4Config->RouteTable[0].GatewayAddress, sizeof (EFI_IPv4_ADDRESS));
212
213 //
214 // Create a route if there is a default router.
215 //
216 if (!EFI_IP4_EQUAL (&Dhcp4Mode.RouterAddress, &mZeroIp4Addr)) {
217 Ip4Config->RouteTableSize = 2;
218
219 ZeroMem (&Ip4Config->RouteTable[1].SubnetAddress, sizeof (EFI_IPv4_ADDRESS));
220 ZeroMem (&Ip4Config->RouteTable[1].SubnetMask, sizeof (EFI_IPv4_ADDRESS));
221 CopyMem (&Ip4Config->RouteTable[1].GatewayAddress, &Dhcp4Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
222 }
223
224 Instance->Result = EFI_SUCCESS;
225
226 //
227 // ignore the return status of EfiNicIp4ConfigSetInfo. Network
228 // stack can operate even that failed.
229 //
230 EfiNicIp4ConfigSetInfo (Instance, Instance->NicConfig, FALSE);
231 }
232
233 ON_EXIT:
234 gBS->SignalEvent (Instance->DoneEvent);
235 Ip4ConfigCleanDhcp4 (Instance);
236
237 DispatchDpc ();
238
239 return ;
240 }
241
242 /**
243 Starts running the configuration policy for the EFI IPv4 Protocol driver.
244
245 The Start() function is called to determine and to begin the platform
246 configuration policy by the EFI IPv4 Protocol driver. This determination may
247 be as simple as returning EFI_UNSUPPORTED if there is no EFI IPv4 Protocol
248 driver configuration policy. It may be as involved as loading some defaults
249 from nonvolatile storage, downloading dynamic data from a DHCP server, and
250 checking permissions with a site policy server.
251 Starting the configuration policy is just the beginning. It may finish almost
252 instantly or it may take several minutes before it fails to retrieve configuration
253 information from one or more servers. Once the policy is started, drivers
254 should use the DoneEvent parameter to determine when the configuration policy
255 has completed. EFI_IP4_CONFIG_PROTOCOL.GetData() must then be called to
256 determine if the configuration succeeded or failed.
257 Until the configuration completes successfully, EFI IPv4 Protocol driver instances
258 that are attempting to use default configurations must return EFI_NO_MAPPING.
259 Once the configuration is complete, the EFI IPv4 Configuration Protocol driver
260 signals DoneEvent. The configuration may need to be updated in the future,
261 however; in this case, the EFI IPv4 Configuration Protocol driver must signal
262 ReconfigEvent, and all EFI IPv4 Protocol driver instances that are using default
263 configurations must return EFI_NO_MAPPING until the configuration policy has
264 been rerun.
265
266 @param This Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
267 @param DoneEvent Event that will be signaled when the EFI IPv4
268 Protocol driver configuration policy completes
269 execution. This event must be of type EVT_NOTIFY_SIGNAL.
270 @param ReconfigEvent Event that will be signaled when the EFI IPv4
271 Protocol driver configuration needs to be updated.
272 This event must be of type EVT_NOTIFY_SIGNAL.
273
274 @retval EFI_SUCCESS The configuration policy for the EFI IPv4 Protocol
275 driver is now running.
276 @retval EFI_INVALID_PARAMETER One or more of the following parameters is NULL:
277 This
278 DoneEvent
279 ReconfigEvent
280 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
281 @retval EFI_ALREADY_STARTED The configuration policy for the EFI IPv4 Protocol
282 driver was already started.
283 @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred.
284 @retval EFI_UNSUPPORTED This interface does not support the EFI IPv4 Protocol
285 driver configuration.
286
287 **/
288 EFI_STATUS
289 EFIAPI
290 EfiIp4ConfigStart (
291 IN EFI_IP4_CONFIG_PROTOCOL *This,
292 IN EFI_EVENT DoneEvent,
293 IN EFI_EVENT ReconfigEvent
294 )
295 {
296 IP4_CONFIG_INSTANCE *Instance;
297 EFI_DHCP4_PROTOCOL *Dhcp4;
298 EFI_DHCP4_MODE_DATA Dhcp4Mode;
299 EFI_DHCP4_PACKET_OPTION *OptionList[1];
300 IP4_CONFIG_DHCP4_OPTION ParaList;
301 EFI_STATUS Status;
302 UINT32 Source;
303 EFI_TPL OldTpl;
304
305 if ((This == NULL) || (DoneEvent == NULL) || (ReconfigEvent == NULL)) {
306 return EFI_INVALID_PARAMETER;
307 }
308
309 Instance = IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This);
310
311 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
312
313 if (Instance->State != IP4_CONFIG_STATE_IDLE) {
314 Status = EFI_ALREADY_STARTED;
315
316 goto ON_EXIT;
317 }
318
319 Instance->DoneEvent = DoneEvent;
320 Instance->ReconfigEvent = ReconfigEvent;
321
322 Instance->NicConfig = EfiNicIp4ConfigGetInfo (Instance);
323
324 if (Instance->NicConfig == NULL) {
325 Source = IP4_CONFIG_SOURCE_DHCP;
326 } else {
327 Source = Instance->NicConfig->Source;
328 }
329
330 //
331 // If the source is static, the auto configuration is done.
332 // return now.
333 //
334 if (Source == IP4_CONFIG_SOURCE_STATIC) {
335 Instance->State = IP4_CONFIG_STATE_CONFIGURED;
336 Instance->Result = EFI_SUCCESS;
337
338 gBS->SignalEvent (Instance->DoneEvent);
339 Status = EFI_SUCCESS;
340 goto ON_EXIT;
341 }
342
343 //
344 // Start the dhcp process
345 //
346 ASSERT ((Source == IP4_CONFIG_SOURCE_DHCP) && (Instance->Dhcp4 == NULL));
347
348 Status = NetLibCreateServiceChild (
349 Instance->Controller,
350 Instance->Image,
351 &gEfiDhcp4ServiceBindingProtocolGuid,
352 &Instance->Dhcp4Handle
353 );
354
355 if (EFI_ERROR (Status)) {
356 goto ON_ERROR;
357 }
358
359 Status = gBS->OpenProtocol (
360 Instance->Dhcp4Handle,
361 &gEfiDhcp4ProtocolGuid,
362 (VOID **) &Instance->Dhcp4,
363 Instance->Image,
364 Instance->Controller,
365 EFI_OPEN_PROTOCOL_BY_DRIVER
366 );
367
368 if (EFI_ERROR (Status)) {
369 goto ON_ERROR;
370 }
371
372 //
373 // Check the current DHCP status, if the DHCP process has
374 // already finished, return now.
375 //
376 Dhcp4 = Instance->Dhcp4;
377 Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode);
378
379 if (EFI_ERROR (Status)) {
380 goto ON_ERROR;
381 }
382
383 if (Dhcp4Mode.State == Dhcp4Bound) {
384 Ip4ConfigOnDhcp4Complete (NULL, Instance);
385
386 goto ON_EXIT;
387 }
388
389 //
390 // Try to start the DHCP process. Use most of the current
391 // DHCP configuration to avoid problems if some DHCP client
392 // yields the control of this DHCP service to us.
393 //
394 ParaList.Head.OpCode = DHCP_TAG_PARA_LIST;
395 ParaList.Head.Length = 2;
396 ParaList.Head.Data[0] = DHCP_TAG_NETMASK;
397 ParaList.Route = DHCP_TAG_ROUTER;
398 OptionList[0] = &ParaList.Head;
399 Dhcp4Mode.ConfigData.OptionCount = 1;
400 Dhcp4Mode.ConfigData.OptionList = OptionList;
401
402 Status = Dhcp4->Configure (Dhcp4, &Dhcp4Mode.ConfigData);
403
404 if (EFI_ERROR (Status)) {
405 goto ON_ERROR;
406 }
407
408 //
409 // Start the DHCP process
410 //
411 Status = gBS->CreateEvent (
412 EVT_NOTIFY_SIGNAL,
413 TPL_CALLBACK,
414 Ip4ConfigOnDhcp4Complete,
415 Instance,
416 &Instance->Dhcp4Event
417 );
418
419 if (EFI_ERROR (Status)) {
420 goto ON_ERROR;
421 }
422
423 Status = Dhcp4->Start (Dhcp4, Instance->Dhcp4Event);
424
425 if (EFI_ERROR (Status)) {
426 goto ON_ERROR;
427 }
428
429 Instance->State = IP4_CONFIG_STATE_STARTED;
430 Instance->Result = EFI_NOT_READY;
431
432 ON_ERROR:
433 if (EFI_ERROR (Status)) {
434 Ip4ConfigCleanConfig (Instance);
435 }
436
437 ON_EXIT:
438 gBS->RestoreTPL (OldTpl);
439
440 DispatchDpc ();
441
442 return Status;
443 }
444
445
446 /**
447 Stops running the configuration policy for the EFI IPv4 Protocol driver.
448
449 The Stop() function stops the configuration policy for the EFI IPv4 Protocol driver.
450 All configuration data will be lost after calling Stop().
451
452 @param This Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
453
454 @retval EFI_SUCCESS The configuration policy for the EFI IPv4 Protocol
455 driver has been stopped.
456 @retval EFI_INVALID_PARAMETER This is NULL.
457 @retval EFI_NOT_STARTED The configuration policy for the EFI IPv4 Protocol
458 driver was not started.
459
460 **/
461 EFI_STATUS
462 EFIAPI
463 EfiIp4ConfigStop (
464 IN EFI_IP4_CONFIG_PROTOCOL *This
465 )
466 {
467 IP4_CONFIG_INSTANCE *Instance;
468 EFI_STATUS Status;
469 EFI_TPL OldTpl;
470
471 if (This == NULL) {
472 return EFI_INVALID_PARAMETER;
473 }
474
475 Instance = IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This);
476
477 Status = EFI_SUCCESS;
478 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
479
480 if (Instance->State == IP4_CONFIG_STATE_IDLE) {
481 Status = EFI_NOT_STARTED;
482 goto ON_EXIT;
483 }
484
485 //
486 // Release all the configure parameters. Don't signal the user
487 // event. The user wants to abort the configuration, this isn't
488 // the configuration done or reconfiguration.
489 //
490 Ip4ConfigCleanConfig (Instance);
491
492 ON_EXIT:
493 gBS->RestoreTPL (OldTpl);
494
495 return Status;
496 }
497
498
499 /**
500 Returns the default configuration data (if any) for the EFI IPv4 Protocol driver.
501
502 The GetData() function returns the current configuration data for the EFI IPv4
503 Protocol driver after the configuration policy has completed.
504
505 @param This Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
506 @param ConfigDataSize On input, the size of the ConfigData buffer.
507 On output, the count of bytes that were written
508 into the ConfigData buffer.
509 @param ConfigData Pointer to the EFI IPv4 Configuration Protocol
510 driver configuration data structure.
511 Type EFI_IP4_IPCONFIG_DATA is defined in
512 "Related Definitions" below.
513
514 @retval EFI_SUCCESS The EFI IPv4 Protocol driver configuration has been returned.
515 @retval EFI_INVALID_PARAMETER This is NULL.
516 @retval EFI_NOT_STARTED The configuration policy for the EFI IPv4 Protocol
517 driver is not running.
518 @retval EFI_NOT_READY EFI IPv4 Protocol driver configuration is still running.
519 @retval EFI_ABORTED EFI IPv4 Protocol driver configuration could not complete.
520 Currently not implemented.
521 @retval EFI_BUFFER_TOO_SMALL *ConfigDataSize is smaller than the configuration
522 data buffer or ConfigData is NULL.
523
524 **/
525 EFI_STATUS
526 EFIAPI
527 EfiIp4ConfigGetData (
528 IN EFI_IP4_CONFIG_PROTOCOL *This,
529 IN OUT UINTN *ConfigDataSize,
530 OUT EFI_IP4_IPCONFIG_DATA *ConfigData OPTIONAL
531 )
532 {
533 IP4_CONFIG_INSTANCE *Instance;
534 NIC_IP4_CONFIG_INFO *NicConfig;
535 EFI_STATUS Status;
536 EFI_TPL OldTpl;
537 UINTN Len;
538
539 if ((This == NULL) || (ConfigDataSize == NULL)) {
540 return EFI_INVALID_PARAMETER;
541 }
542
543 Instance = IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This);
544
545 Status = EFI_SUCCESS;
546 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
547
548 if (Instance->State == IP4_CONFIG_STATE_IDLE) {
549 Status = EFI_NOT_STARTED;
550 } else if (Instance->State == IP4_CONFIG_STATE_STARTED) {
551 Status = EFI_NOT_READY;
552 }
553
554 if (EFI_ERROR (Status)) {
555 goto ON_EXIT;
556 }
557
558 //
559 // Copy the configure data if auto configuration succeeds.
560 //
561 Status = Instance->Result;
562
563 if (Status == EFI_SUCCESS) {
564 ASSERT (Instance->NicConfig != NULL);
565
566 NicConfig = Instance->NicConfig;
567 Len = SIZEOF_IP4_CONFIG_INFO (&NicConfig->Ip4Info);
568
569 if ((*ConfigDataSize < Len) || (ConfigData == NULL)) {
570 Status = EFI_BUFFER_TOO_SMALL;
571 } else {
572 CopyMem (ConfigData, &NicConfig->Ip4Info, Len);
573 Ip4ConfigFixRouteTablePointer (ConfigData);
574 }
575
576 *ConfigDataSize = Len;
577 }
578
579 ON_EXIT:
580 gBS->RestoreTPL (OldTpl);
581
582 return Status;
583 }
584
585 /**
586 Release all the DHCP related resources.
587
588 @param This The IP4 configure instance
589
590 @return None
591
592 **/
593 VOID
594 Ip4ConfigCleanDhcp4 (
595 IN IP4_CONFIG_INSTANCE *This
596 )
597 {
598 if (This->Dhcp4 != NULL) {
599 This->Dhcp4->Stop (This->Dhcp4);
600
601 gBS->CloseProtocol (
602 This->Dhcp4Handle,
603 &gEfiDhcp4ProtocolGuid,
604 This->Image,
605 This->Controller
606 );
607
608 This->Dhcp4 = NULL;
609 }
610
611 if (This->Dhcp4Handle != NULL) {
612 NetLibDestroyServiceChild (
613 This->Controller,
614 This->Image,
615 &gEfiDhcp4ServiceBindingProtocolGuid,
616 This->Dhcp4Handle
617 );
618
619 This->Dhcp4Handle = NULL;
620 }
621
622 if (This->Dhcp4Event == NULL) {
623 gBS->CloseEvent (This->Dhcp4Event);
624 This->Dhcp4Event = NULL;
625 }
626 }
627
628
629 /**
630 Clean up all the configuration parameters.
631
632 @param Instance The IP4 configure instance
633
634 @return None
635
636 **/
637 VOID
638 Ip4ConfigCleanConfig (
639 IN IP4_CONFIG_INSTANCE *Instance
640 )
641 {
642 if (Instance->NicConfig != NULL) {
643 FreePool (Instance->NicConfig);
644 Instance->NicConfig = NULL;
645 }
646
647 Instance->State = IP4_CONFIG_STATE_IDLE;
648 Instance->DoneEvent = NULL;
649 Instance->ReconfigEvent = NULL;
650
651 Ip4ConfigCleanDhcp4 (Instance);
652 }
653
654 EFI_IP4_CONFIG_PROTOCOL mIp4ConfigProtocolTemplate = {
655 EfiIp4ConfigStart,
656 EfiIp4ConfigStop,
657 EfiIp4ConfigGetData
658 };
659