2a9fcb94e5b573344d81fee407ccf619799b576c
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4ConfigDxe / Ip4ConfigDriver.c
1 /** @file
2 The driver binding for IP4 CONFIG protocol.
3
4 Copyright (c) 2006 - 2012, 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
16 #include "Ip4Config.h"
17 #include "Ip4ConfigNv.h"
18 #include "NicIp4Variable.h"
19
20 EFI_DRIVER_BINDING_PROTOCOL gIp4ConfigDriverBinding = {
21 Ip4ConfigDriverBindingSupported,
22 Ip4ConfigDriverBindingStart,
23 Ip4ConfigDriverBindingStop,
24 0xa,
25 NULL,
26 NULL
27 };
28
29 //
30 // The intance of template of IP4 Config private data
31 //
32 IP4_CONFIG_INSTANCE mIp4ConfigTemplate = {
33 IP4_CONFIG_INSTANCE_SIGNATURE,
34 NULL,
35 NULL,
36 (EFI_DEVICE_PATH_PROTOCOL *) NULL,
37 {
38 NULL,
39 NULL,
40 NULL
41 },
42 {
43 NULL,
44 NULL,
45 NULL
46 },
47 NULL,
48 (EFI_DEVICE_PATH_PROTOCOL *) NULL,
49 NULL,
50 {
51 FALSE,
52 FALSE,
53 {
54 {
55 0
56 }
57 },
58 {
59 {
60 0
61 }
62 },
63 {
64 {
65 0
66 }
67 }
68 },
69 0,
70 (EFI_MANAGED_NETWORK_PROTOCOL *) NULL,
71 NULL,
72 NULL,
73 NULL,
74 EFI_NOT_READY,
75 {
76 0,
77 0,
78 {
79 {
80 0
81 }
82 }
83 },
84 (CHAR16 *) NULL,
85 (NIC_IP4_CONFIG_INFO *) NULL,
86 (EFI_DHCP4_PROTOCOL *) NULL,
87 NULL,
88 NULL,
89 NULL,
90 TRUE,
91 FALSE
92 };
93
94 /**
95 The entry point for IP4 config driver which install the driver
96 binding and component name protocol on its image.
97
98 @param ImageHandle The image handle of the driver.
99 @param SystemTable The system table.
100
101 @retval EFI_SUCCES All the related protocols are installed on the driver.
102 @retval Others Failed to install protocols.
103
104 **/
105 EFI_STATUS
106 EFIAPI
107 Ip4ConfigDriverEntryPoint (
108 IN EFI_HANDLE ImageHandle,
109 IN EFI_SYSTEM_TABLE *SystemTable
110 )
111 {
112 return EfiLibInstallDriverBindingComponentName2 (
113 ImageHandle,
114 SystemTable,
115 &gIp4ConfigDriverBinding,
116 ImageHandle,
117 &gIp4ConfigComponentName,
118 &gIp4ConfigComponentName2
119 );
120 }
121
122
123 /**
124 Test to see if this driver supports ControllerHandle.
125
126 @param This Protocol instance pointer.
127 @param ControllerHandle Handle of device to test
128 @param RemainingDevicePath Optional parameter use to pick a specific child
129 device to start.
130
131 @retval EFI_SUCCES This driver supports this device
132 @retval EFI_ALREADY_STARTED This driver is already running on this device
133 @retval other This driver does not support this device
134
135 **/
136 EFI_STATUS
137 EFIAPI
138 Ip4ConfigDriverBindingSupported (
139 IN EFI_DRIVER_BINDING_PROTOCOL *This,
140 IN EFI_HANDLE ControllerHandle,
141 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
142 )
143 {
144 EFI_STATUS Status;
145
146 Status = gBS->OpenProtocol (
147 ControllerHandle,
148 &gEfiManagedNetworkServiceBindingProtocolGuid,
149 NULL,
150 This->DriverBindingHandle,
151 ControllerHandle,
152 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
153 );
154
155 return Status;
156 }
157
158
159 /**
160 Start this driver on ControllerHandle.
161
162 @param This Protocol instance pointer.
163 @param ControllerHandle Handle of device to bind driver to
164 @param RemainingDevicePath Optional parameter use to pick a specific child
165 device to start.
166
167 @retval EFI_SUCCES This driver is added to ControllerHandle
168 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
169 @retval other This driver does not support this device
170
171 **/
172 EFI_STATUS
173 EFIAPI
174 Ip4ConfigDriverBindingStart (
175 IN EFI_DRIVER_BINDING_PROTOCOL *This,
176 IN EFI_HANDLE ControllerHandle,
177 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
178 )
179 {
180 EFI_IP4_CONFIG_PROTOCOL *Ip4Config;
181 EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
182 EFI_HANDLE MnpHandle;
183 IP4_CONFIG_INSTANCE *Instance;
184 EFI_SIMPLE_NETWORK_MODE SnpMode;
185 NIC_IP4_CONFIG_INFO *NicConfig;
186 EFI_STATUS Status;
187 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
188
189 Status = gBS->HandleProtocol (
190 ControllerHandle,
191 &gEfiDevicePathProtocolGuid,
192 (VOID **) &ParentDevicePath
193 );
194 if (EFI_ERROR (Status)) {
195 return Status;
196 }
197
198 //
199 // Check for multiple start.
200 //
201 Status = gBS->OpenProtocol (
202 ControllerHandle,
203 &gEfiIp4ConfigProtocolGuid,
204 (VOID **) &Ip4Config,
205 This->DriverBindingHandle,
206 ControllerHandle,
207 EFI_OPEN_PROTOCOL_GET_PROTOCOL
208 );
209
210 if (!EFI_ERROR (Status)) {
211 return EFI_ALREADY_STARTED;
212 }
213
214 //
215 // Create a MNP child
216 //
217 Mnp = NULL;
218 MnpHandle = NULL;
219 Instance = NULL;
220
221 Status = NetLibCreateServiceChild (
222 ControllerHandle,
223 This->DriverBindingHandle,
224 &gEfiManagedNetworkServiceBindingProtocolGuid,
225 &MnpHandle
226 );
227
228 if (EFI_ERROR (Status)) {
229 return Status;
230 }
231
232 Status = gBS->OpenProtocol (
233 MnpHandle,
234 &gEfiManagedNetworkProtocolGuid,
235 (VOID **) &Mnp,
236 This->DriverBindingHandle,
237 ControllerHandle,
238 EFI_OPEN_PROTOCOL_BY_DRIVER
239 );
240
241 if (EFI_ERROR (Status)) {
242 goto ON_ERROR;
243 }
244
245 //
246 // Allocate an instance then initialize it
247 //
248 Instance = AllocateCopyPool (sizeof (IP4_CONFIG_INSTANCE), &mIp4ConfigTemplate);
249
250 if (Instance == NULL) {
251 Status = EFI_OUT_OF_RESOURCES;
252 goto ON_ERROR;
253 }
254
255 Instance->Controller = ControllerHandle;
256 Instance->Image = This->DriverBindingHandle;
257 Instance->ParentDevicePath = ParentDevicePath;
258
259 CopyMem (&Instance->Ip4ConfigProtocol, &mIp4ConfigProtocolTemplate, sizeof (mIp4ConfigProtocolTemplate));
260
261 Instance->State = IP4_CONFIG_STATE_IDLE;
262 Instance->Mnp = Mnp;
263 Instance->MnpHandle = MnpHandle;
264
265 Status = Mnp->GetModeData (Mnp, NULL, &SnpMode);
266
267 if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {
268 goto ON_ERROR;
269 }
270
271 Instance->NicAddr.Type = (UINT16) SnpMode.IfType;
272 Instance->NicAddr.Len = (UINT8) SnpMode.HwAddressSize;
273 CopyMem (&Instance->NicAddr.MacAddr, &SnpMode.CurrentAddress, Instance->NicAddr.Len);
274
275 //
276 // Add it to the global list, and compose the name
277 //
278 Status = NetLibGetMacString (Instance->Controller, Instance->Image, &Instance->MacString);
279 if (EFI_ERROR (Status)) {
280 goto ON_ERROR;
281 }
282
283 Status = Ip4ConfigDeviceInit (Instance);
284
285 //
286 // Install the IP4_CONFIG protocols
287 //
288 Status = gBS->InstallMultipleProtocolInterfaces (
289 &ControllerHandle,
290 &gEfiIp4ConfigProtocolGuid,
291 &Instance->Ip4ConfigProtocol,
292 NULL
293 );
294
295 if (EFI_ERROR (Status)) {
296 goto ON_ERROR;
297 }
298
299 //
300 // A dedicated timer is used to poll underlying media status.
301 //
302 Status = gBS->CreateEvent (
303 EVT_NOTIFY_SIGNAL | EVT_TIMER,
304 TPL_CALLBACK,
305 MediaChangeDetect,
306 Instance,
307 &Instance->Timer
308 );
309
310 if (EFI_ERROR (Status)) {
311 goto ON_ERROR;
312 }
313
314 //
315 // Get the previous configure parameters. If an error happend here,
316 // just ignore it because the driver should be able to operate.
317 //
318 NicConfig = Ip4ConfigReadVariable (Instance);
319 if (NicConfig != NULL) {
320 if (!NicConfig->Perment) {
321 //
322 // Delete the non-permanent configuration.
323 //
324 Ip4ConfigWriteVariable (Instance, NULL);
325 }
326
327 FreePool (NicConfig);
328 }
329
330 return EFI_SUCCESS;
331
332 ON_ERROR:
333 if (Instance != NULL) {
334 FreePool (Instance);
335 }
336
337 if (Mnp != NULL) {
338 gBS->CloseProtocol (
339 MnpHandle,
340 &gEfiManagedNetworkProtocolGuid,
341 This->DriverBindingHandle,
342 ControllerHandle
343 );
344 }
345
346 NetLibDestroyServiceChild (
347 ControllerHandle,
348 This->DriverBindingHandle,
349 &gEfiManagedNetworkServiceBindingProtocolGuid,
350 MnpHandle
351 );
352
353 return Status;
354 }
355
356
357 /**
358 Stop this driver on ControllerHandle.
359
360 @param This Protocol instance pointer.
361 @param ControllerHandle Handle of device to stop driver on
362 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
363 children is zero stop the entire bus driver.
364 @param ChildHandleBuffer List of Child Handles to Stop.
365
366 @retval EFI_SUCCES This driver is removed ControllerHandle
367 @retval other This driver was not removed from this device
368
369 **/
370 EFI_STATUS
371 EFIAPI
372 Ip4ConfigDriverBindingStop (
373 IN EFI_DRIVER_BINDING_PROTOCOL *This,
374 IN EFI_HANDLE ControllerHandle,
375 IN UINTN NumberOfChildren,
376 IN EFI_HANDLE *ChildHandleBuffer
377 )
378 {
379 IP4_CONFIG_INSTANCE *Instance;
380 EFI_IP4_CONFIG_PROTOCOL *Ip4Config;
381 EFI_HANDLE NicHandle;
382 EFI_STATUS Status;
383
384 //
385 // IP4_CONFIG instance opens an MNP child. It may also create and open
386 // a DHCP child. If this is the DHCP handle, stop the DHCP process. If
387 // it is the MNP child, stop the whole driver.
388 //
389 //
390 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp4ProtocolGuid);
391
392 if (NicHandle != NULL) {
393 //
394 // Get our context back then clean the DHCP up. Notify the user if necessary.
395 //
396 Status = gBS->OpenProtocol (
397 NicHandle,
398 &gEfiIp4ConfigProtocolGuid,
399 (VOID **) &Ip4Config,
400 This->DriverBindingHandle,
401 ControllerHandle,
402 EFI_OPEN_PROTOCOL_GET_PROTOCOL
403 );
404
405 if (EFI_ERROR (Status)) {
406 return Status;
407 }
408
409 Instance = IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (Ip4Config);
410 ASSERT (ControllerHandle == Instance->Dhcp4Handle);
411
412 Ip4ConfigCleanDhcp4 (Instance);
413
414 Instance->State = IP4_CONFIG_STATE_CONFIGURED;
415 Instance->Result = EFI_DEVICE_ERROR;
416
417 if (Instance->DoneEvent != NULL) {
418 gBS->SignalEvent (Instance->DoneEvent);
419 }
420
421 return EFI_SUCCESS;
422 }
423
424 //
425 // This is a MNP handle, stop the whole driver
426 //
427 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);
428
429 if (NicHandle == NULL) {
430 return EFI_SUCCESS;
431 }
432
433 //
434 // Get our context back.
435 //
436 Status = gBS->OpenProtocol (
437 NicHandle,
438 &gEfiIp4ConfigProtocolGuid,
439 (VOID **) &Ip4Config,
440 This->DriverBindingHandle,
441 ControllerHandle,
442 EFI_OPEN_PROTOCOL_GET_PROTOCOL
443 );
444
445 if (EFI_ERROR (Status)) {
446 return Status;
447 }
448
449 Instance = IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (Ip4Config);
450
451 Ip4ConfigDeviceUnload (Instance);
452
453 //
454 // Unload the protocols first to inform the top drivers
455 //
456 Status = gBS->UninstallMultipleProtocolInterfaces (
457 NicHandle,
458 &gEfiIp4ConfigProtocolGuid,
459 &Instance->Ip4ConfigProtocol,
460 NULL
461 );
462
463 if (EFI_ERROR (Status)) {
464 return Status;
465 }
466
467 //
468 // Release all the resources
469 //
470 if (Instance->MnpHandle != NULL) {
471 gBS->CloseProtocol (
472 Instance->MnpHandle,
473 &gEfiManagedNetworkProtocolGuid,
474 This->DriverBindingHandle,
475 NicHandle
476 );
477
478 NetLibDestroyServiceChild (
479 NicHandle,
480 Instance->Image,
481 &gEfiManagedNetworkServiceBindingProtocolGuid,
482 Instance->MnpHandle
483 );
484
485 Instance->Mnp = NULL;
486 Instance->MnpHandle = NULL;
487 }
488
489 if (Instance->MacString != NULL) {
490 FreePool (Instance->MacString);
491 }
492
493 if (Instance->Timer != NULL) {
494 gBS->SetTimer (Instance->Timer, TimerCancel, 0);
495 gBS->CloseEvent (Instance->Timer);
496 Instance->Timer = NULL;
497 }
498
499 Ip4ConfigCleanConfig (Instance);
500 FreePool (Instance);
501
502 return EFI_SUCCESS;
503 }