]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Driver.c
Clean codes per ECC.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Dhcp4Dxe / Dhcp4Driver.c
1 /** @file
2
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
8
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.
11
12
13 Module Name:
14
15 Dhcp4Driver.c
16
17 Abstract:
18
19
20 **/
21
22 #include "Dhcp4Impl.h"
23 #include "Dhcp4Driver.h"
24
25 EFI_DRIVER_BINDING_PROTOCOL gDhcp4DriverBinding = {
26 Dhcp4DriverBindingSupported,
27 Dhcp4DriverBindingStart,
28 Dhcp4DriverBindingStop,
29 0xa,
30 NULL,
31 NULL
32 };
33
34 EFI_SERVICE_BINDING_PROTOCOL mDhcp4ServiceBindingTemplete = {
35 Dhcp4ServiceBindingCreateChild,
36 Dhcp4ServiceBindingDestroyChild
37 };
38
39 /**
40 Entry point of the DHCP driver to install various protocols.
41
42 @param ImageHandle The image handle of the driver.
43 @param SystemTable The system table.
44
45 @retval EFI_SUCCES if the driver binding and component name protocols are successfully
46 @retval Others Failed to install the protocols.
47
48 **/
49 EFI_STATUS
50 EFIAPI
51 Dhcp4DriverEntryPoint (
52 IN EFI_HANDLE ImageHandle,
53 IN EFI_SYSTEM_TABLE *SystemTable
54 )
55 {
56 return EfiLibInstallDriverBindingComponentName2 (
57 ImageHandle,
58 SystemTable,
59 &gDhcp4DriverBinding,
60 ImageHandle,
61 &gDhcp4ComponentName,
62 &gDhcp4ComponentName2
63 );
64 }
65
66
67 /**
68 Test to see if DHCP driver supports the ControllerHandle.
69
70 @param This Protocol instance pointer.
71 @param ControllerHandle Handle of device to test
72 @param RemainingDevicePath Optional parameter use to pick a specific child
73 device to start.
74
75 @retval EFI_SUCCES This driver supports this device
76 @retval other This driver does not support this device
77
78 **/
79 EFI_STATUS
80 EFIAPI
81 Dhcp4DriverBindingSupported (
82 IN EFI_DRIVER_BINDING_PROTOCOL *This,
83 IN EFI_HANDLE ControllerHandle,
84 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
85 )
86 {
87 EFI_STATUS Status;
88
89 Status = gBS->OpenProtocol (
90 ControllerHandle,
91 &gEfiUdp4ServiceBindingProtocolGuid,
92 NULL,
93 This->DriverBindingHandle,
94 ControllerHandle,
95 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
96 );
97
98 return Status;
99 }
100
101
102
103 /**
104 Configure the default UDP child to receive all the DHCP traffics
105 on this network interface.
106
107 @param UdpIo The UDP IO port to configure
108 @param Context The context to the function
109
110 @retval EFI_SUCCESS The UDP IO port is successfully configured.
111 @retval Others Failed to configure the UDP child.
112
113 **/
114 EFI_STATUS
115 DhcpConfigUdpIo (
116 IN UDP_IO_PORT *UdpIo,
117 IN VOID *Context
118 )
119 {
120 EFI_UDP4_CONFIG_DATA UdpConfigData;
121
122 UdpConfigData.AcceptBroadcast = TRUE;
123 UdpConfigData.AcceptPromiscuous = FALSE;
124 UdpConfigData.AcceptAnyPort = FALSE;
125 UdpConfigData.AllowDuplicatePort = TRUE;
126 UdpConfigData.TypeOfService = 0;
127 UdpConfigData.TimeToLive = 64;
128 UdpConfigData.DoNotFragment = FALSE;
129 UdpConfigData.ReceiveTimeout = 0;
130 UdpConfigData.TransmitTimeout = 0;
131
132 UdpConfigData.UseDefaultAddress = FALSE;
133 UdpConfigData.StationPort = DHCP_CLIENT_PORT;
134 UdpConfigData.RemotePort = DHCP_SERVER_PORT;
135
136 ZeroMem (&UdpConfigData.StationAddress, sizeof (EFI_IPv4_ADDRESS));
137 ZeroMem (&UdpConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
138 ZeroMem (&UdpConfigData.RemoteAddress, sizeof (EFI_IPv4_ADDRESS));
139
140 return UdpIo->Udp->Configure (UdpIo->Udp, &UdpConfigData);;
141 }
142
143
144
145 /**
146 Destory the DHCP service. The Dhcp4 service may be partly initialized,
147 or partly destoried. If a resource is destoried, it is marked as so in
148 case the destory failed and being called again later.
149
150 @param DhcpSb The DHCP service instance to destory.
151
152 @retval EFI_SUCCESS The DHCP service is successfully closed.
153
154 **/
155 EFI_STATUS
156 Dhcp4CloseService (
157 IN DHCP_SERVICE *DhcpSb
158 )
159 {
160 DhcpCleanLease (DhcpSb);
161
162 if (DhcpSb->UdpIo != NULL) {
163 UdpIoFreePort (DhcpSb->UdpIo);
164 DhcpSb->UdpIo = NULL;
165 }
166
167 if (DhcpSb->Timer != NULL) {
168 gBS->SetTimer (DhcpSb->Timer, TimerCancel, 0);
169 gBS->CloseEvent (DhcpSb->Timer);
170
171 DhcpSb->Timer = NULL;
172 }
173
174 return EFI_SUCCESS;
175 }
176
177
178
179 /**
180 Create a new DHCP service binding instance for the controller.
181
182 @param Controller The controller to install DHCP service binding
183 protocol onto
184 @param ImageHandle The driver's image handle
185 @param Service The variable to receive the created DHCP service
186 instance.
187
188 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource .
189 @retval EFI_SUCCESS The DHCP service instance is created.
190
191 **/
192 EFI_STATUS
193 Dhcp4CreateService (
194 IN EFI_HANDLE Controller,
195 IN EFI_HANDLE ImageHandle,
196 OUT DHCP_SERVICE **Service
197 )
198 {
199 DHCP_SERVICE *DhcpSb;
200 EFI_STATUS Status;
201
202 *Service = NULL;
203 DhcpSb = AllocateZeroPool (sizeof (DHCP_SERVICE));
204
205 if (DhcpSb == NULL) {
206 return EFI_OUT_OF_RESOURCES;
207 }
208
209 DhcpSb->Signature = DHCP_SERVICE_SIGNATURE;
210 DhcpSb->ServiceBinding = mDhcp4ServiceBindingTemplete;
211 DhcpSb->ServiceState = DHCP_UNCONFIGED;
212 DhcpSb->InDestory = FALSE;
213 DhcpSb->Controller = Controller;
214 DhcpSb->Image = ImageHandle;
215 InitializeListHead (&DhcpSb->Children);
216 DhcpSb->DhcpState = Dhcp4Stopped;
217 DhcpSb->Xid = NET_RANDOM (NetRandomInitSeed ());
218
219 //
220 // Create various resources, UdpIo, Timer, and get Mac address
221 //
222 Status = gBS->CreateEvent (
223 EVT_NOTIFY_SIGNAL | EVT_TIMER,
224 TPL_CALLBACK,
225 DhcpOnTimerTick,
226 DhcpSb,
227 &DhcpSb->Timer
228 );
229
230 if (EFI_ERROR (Status)) {
231 goto ON_ERROR;
232 }
233
234 DhcpSb->UdpIo = UdpIoCreatePort (Controller, ImageHandle, DhcpConfigUdpIo, NULL);
235
236 if (DhcpSb->UdpIo == NULL) {
237 Status = EFI_OUT_OF_RESOURCES;
238 goto ON_ERROR;
239 }
240
241 DhcpSb->HwLen = (UINT8) DhcpSb->UdpIo->SnpMode.HwAddressSize;
242 DhcpSb->HwType = DhcpSb->UdpIo->SnpMode.IfType;
243 CopyMem (&DhcpSb->Mac, &DhcpSb->UdpIo->SnpMode.CurrentAddress, sizeof (DhcpSb->Mac));
244
245 *Service = DhcpSb;
246 return EFI_SUCCESS;
247
248 ON_ERROR:
249 Dhcp4CloseService (DhcpSb);
250 gBS->FreePool (DhcpSb);
251
252 return Status;
253 }
254
255
256 /**
257 Start this driver on ControllerHandle.
258
259 @param This Protocol instance pointer.
260 @param ControllerHandle Handle of device to bind driver to
261 @param RemainingDevicePath Optional parameter use to pick a specific child
262 device to start.
263
264 @retval EFI_SUCCES This driver is added to ControllerHandle
265 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
266 @retval other This driver does not support this device
267
268 **/
269 EFI_STATUS
270 EFIAPI
271 Dhcp4DriverBindingStart (
272 IN EFI_DRIVER_BINDING_PROTOCOL *This,
273 IN EFI_HANDLE ControllerHandle,
274 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
275 )
276 {
277 DHCP_SERVICE *DhcpSb;
278 EFI_STATUS Status;
279
280 //
281 // First: test for the DHCP4 Protocol
282 //
283 Status = gBS->OpenProtocol (
284 ControllerHandle,
285 &gEfiDhcp4ServiceBindingProtocolGuid,
286 NULL,
287 This->DriverBindingHandle,
288 ControllerHandle,
289 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
290 );
291
292 if (Status == EFI_SUCCESS) {
293 return EFI_ALREADY_STARTED;
294 }
295
296 Status = Dhcp4CreateService (ControllerHandle, This->DriverBindingHandle, &DhcpSb);
297
298 if (EFI_ERROR (Status)) {
299 return Status;
300 }
301
302 Status = gBS->SetTimer (DhcpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
303
304 if (EFI_ERROR (Status)) {
305 goto ON_ERROR;
306 }
307
308 //
309 // Install the Dhcp4ServiceBinding Protocol onto ControlerHandle
310 //
311 Status = gBS->InstallMultipleProtocolInterfaces (
312 &ControllerHandle,
313 &gEfiDhcp4ServiceBindingProtocolGuid,
314 &DhcpSb->ServiceBinding,
315 NULL
316 );
317
318 if (EFI_ERROR (Status)) {
319 goto ON_ERROR;
320 }
321
322 return Status;
323
324 ON_ERROR:
325 Dhcp4CloseService (DhcpSb);
326 gBS->FreePool (DhcpSb);
327 return Status;
328 }
329
330
331 /**
332 Stop this driver on ControllerHandle.
333
334 @param This Protocol instance pointer.
335 @param ControllerHandle Handle of device to stop driver on
336 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number
337 of children is zero stop the entire bus driver.
338 @param ChildHandleBuffer List of Child Handles to Stop.
339
340 @retval EFI_SUCCES This driver is removed ControllerHandle
341 @retval other This driver was not removed from this device
342
343 **/
344 EFI_STATUS
345 EFIAPI
346 Dhcp4DriverBindingStop (
347 IN EFI_DRIVER_BINDING_PROTOCOL *This,
348 IN EFI_HANDLE ControllerHandle,
349 IN UINTN NumberOfChildren,
350 IN EFI_HANDLE *ChildHandleBuffer
351 )
352 {
353 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
354 DHCP_SERVICE *DhcpSb;
355 DHCP_PROTOCOL *Instance;
356 EFI_HANDLE NicHandle;
357 EFI_STATUS Status;
358 EFI_TPL OldTpl;
359
360 //
361 // DHCP driver opens UDP child, So, the ControllerHandle is the
362 // UDP child handle. locate the Nic handle first.
363 //
364 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp4ProtocolGuid);
365
366 if (NicHandle == NULL) {
367 return EFI_DEVICE_ERROR;
368 }
369
370 Status = gBS->OpenProtocol (
371 NicHandle,
372 &gEfiDhcp4ServiceBindingProtocolGuid,
373 (VOID **) &ServiceBinding,
374 This->DriverBindingHandle,
375 NicHandle,
376 EFI_OPEN_PROTOCOL_GET_PROTOCOL
377 );
378
379 if (EFI_ERROR (Status)) {
380 return EFI_DEVICE_ERROR;
381 }
382
383 DhcpSb = DHCP_SERVICE_FROM_THIS (ServiceBinding);
384
385 if (DhcpSb->InDestory) {
386 return EFI_SUCCESS;
387 }
388
389 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
390
391 if (NumberOfChildren == 0) {
392
393 DhcpSb->InDestory = TRUE;
394 DhcpSb->ServiceState = DHCP_DESTORY;
395
396 gBS->UninstallProtocolInterface (
397 NicHandle,
398 &gEfiDhcp4ServiceBindingProtocolGuid,
399 ServiceBinding
400 );
401
402 Dhcp4CloseService (DhcpSb);
403
404 gBS->FreePool (DhcpSb);
405 } else {
406 //
407 // Don't use NET_LIST_FOR_EACH_SAFE here, Dhcp4ServiceBindingDestoryChild
408 // may cause other child to be deleted.
409 //
410 while (!IsListEmpty (&DhcpSb->Children)) {
411 Instance = NET_LIST_HEAD (&DhcpSb->Children, DHCP_PROTOCOL, Link);
412 ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
413 }
414
415 if (DhcpSb->NumChildren != 0) {
416 Status = EFI_DEVICE_ERROR;
417 }
418 }
419
420 gBS->RestoreTPL (OldTpl);
421
422 return Status;
423 }
424
425
426 /**
427 Initialize a new DHCP child.
428
429 @param DhcpSb The dhcp service instance
430 @param Instance The dhcp instance to initialize
431
432 @return None
433
434 **/
435 VOID
436 DhcpInitProtocol (
437 IN DHCP_SERVICE *DhcpSb,
438 IN DHCP_PROTOCOL *Instance
439 )
440 {
441 Instance->Signature = DHCP_PROTOCOL_SIGNATURE;
442 CopyMem (&Instance->Dhcp4Protocol, &mDhcp4ProtocolTemplate, sizeof (Instance->Dhcp4Protocol));
443 InitializeListHead (&Instance->Link);
444 Instance->Handle = NULL;
445 Instance->Service = DhcpSb;
446 Instance->InDestory = FALSE;
447 Instance->CompletionEvent = NULL;
448 Instance->RenewRebindEvent = NULL;
449 Instance->Token = NULL;
450 Instance->UdpIo = NULL;
451 NetbufQueInit (&Instance->ResponseQueue);
452 }
453
454
455 /**
456 Creates a child handle with a set of DHCP4 services.
457
458 @param This Protocol instance pointer.
459 @param ChildHandle Pointer to the handle of the child to create. If
460 it is NULL, then a new handle is created. If it
461 is not NULL, then the DHCP4 services are added to
462 the existing child handle.
463
464 @retval EFI_SUCCES The child handle was created with the DHCP4
465 services
466 @retval EFI_OUT_OF_RESOURCES There are not enough resources to create the child
467 @retval other The child handle was not created
468
469 **/
470 EFI_STATUS
471 EFIAPI
472 Dhcp4ServiceBindingCreateChild (
473 IN EFI_SERVICE_BINDING_PROTOCOL *This,
474 IN EFI_HANDLE *ChildHandle
475 )
476 {
477 DHCP_SERVICE *DhcpSb;
478 DHCP_PROTOCOL *Instance;
479 EFI_STATUS Status;
480 EFI_TPL OldTpl;
481 VOID *Udp4;
482
483 if ((This == NULL) || (ChildHandle == NULL)) {
484 return EFI_INVALID_PARAMETER;
485 }
486
487 Instance = AllocatePool (sizeof (*Instance));
488
489 if (Instance == NULL) {
490 return EFI_OUT_OF_RESOURCES;
491 }
492
493 DhcpSb = DHCP_SERVICE_FROM_THIS (This);
494 DhcpInitProtocol (DhcpSb, Instance);
495
496 //
497 // Install DHCP4 onto ChildHandle
498 //
499 Status = gBS->InstallMultipleProtocolInterfaces (
500 ChildHandle,
501 &gEfiDhcp4ProtocolGuid,
502 &Instance->Dhcp4Protocol,
503 NULL
504 );
505
506 if (EFI_ERROR (Status)) {
507 gBS->FreePool (Instance);
508 return Status;
509 }
510
511 Instance->Handle = *ChildHandle;
512
513 //
514 // Open the Udp4 protocol BY_CHILD.
515 //
516 Status = gBS->OpenProtocol (
517 DhcpSb->UdpIo->UdpHandle,
518 &gEfiUdp4ProtocolGuid,
519 (VOID **) &Udp4,
520 gDhcp4DriverBinding.DriverBindingHandle,
521 Instance->Handle,
522 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
523 );
524 if (EFI_ERROR (Status)) {
525 gBS->UninstallMultipleProtocolInterfaces (
526 Instance->Handle,
527 &gEfiDhcp4ProtocolGuid,
528 &Instance->Dhcp4Protocol,
529 NULL
530 );
531
532 gBS->FreePool (Instance);
533 return Status;
534 }
535
536 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
537
538 InsertTailList (&DhcpSb->Children, &Instance->Link);
539 DhcpSb->NumChildren++;
540
541 gBS->RestoreTPL (OldTpl);
542
543 return EFI_SUCCESS;
544 }
545
546
547 /**
548 Destroys a child handle with a set of DHCP4 services.
549
550 @param This Protocol instance pointer.
551 @param ChildHandle Handle of the child to destroy
552
553 @retval EFI_SUCCES The DHCP4 service is removed from the child handle
554 @retval EFI_UNSUPPORTED The child handle does not support the DHCP4
555 service
556 @retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.
557 @retval EFI_ACCESS_DENIED The child handle could not be destroyed because
558 its DHCP4 services are being used.
559 @retval other The child handle was not destroyed
560
561 **/
562 EFI_STATUS
563 EFIAPI
564 Dhcp4ServiceBindingDestroyChild (
565 IN EFI_SERVICE_BINDING_PROTOCOL *This,
566 IN EFI_HANDLE ChildHandle
567 )
568 {
569 DHCP_SERVICE *DhcpSb;
570 DHCP_PROTOCOL *Instance;
571 EFI_DHCP4_PROTOCOL *Dhcp;
572 EFI_TPL OldTpl;
573 EFI_STATUS Status;
574
575 if ((This == NULL) || (ChildHandle == NULL)) {
576 return EFI_INVALID_PARAMETER;
577 }
578
579 //
580 // Retrieve the private context data structures
581 //
582 Status = gBS->OpenProtocol (
583 ChildHandle,
584 &gEfiDhcp4ProtocolGuid,
585 (VOID **) &Dhcp,
586 gDhcp4DriverBinding.DriverBindingHandle,
587 ChildHandle,
588 EFI_OPEN_PROTOCOL_GET_PROTOCOL
589 );
590
591 if (EFI_ERROR (Status)) {
592 return EFI_UNSUPPORTED;
593 }
594
595 Instance = DHCP_INSTANCE_FROM_THIS (Dhcp);
596 DhcpSb = DHCP_SERVICE_FROM_THIS (This);
597
598 if (Instance->Service != DhcpSb) {
599 return EFI_INVALID_PARAMETER;
600 }
601
602 //
603 // A child can be destoried more than once. For example,
604 // Dhcp4DriverBindingStop will destory all of its children.
605 // when caller driver is being stopped, it will destory the
606 // dhcp child it opens.
607 //
608 if (Instance->InDestory) {
609 return EFI_SUCCESS;
610 }
611
612 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
613 Instance->InDestory = TRUE;
614
615 //
616 // Close the Udp4 protocol.
617 //
618 gBS->CloseProtocol (
619 DhcpSb->UdpIo->UdpHandle,
620 &gEfiUdp4ProtocolGuid,
621 gDhcp4DriverBinding.DriverBindingHandle,
622 ChildHandle
623 );
624
625 //
626 // Uninstall the DHCP4 protocol first to enable a top down destruction.
627 //
628 Status = gBS->UninstallProtocolInterface (
629 ChildHandle,
630 &gEfiDhcp4ProtocolGuid,
631 Dhcp
632 );
633
634 if (EFI_ERROR (Status)) {
635 Instance->InDestory = FALSE;
636
637 gBS->RestoreTPL (OldTpl);
638 return Status;
639 }
640
641 if (DhcpSb->ActiveChild == Instance) {
642 DhcpYieldControl (DhcpSb);
643 }
644
645 RemoveEntryList (&Instance->Link);
646 DhcpSb->NumChildren--;
647
648 gBS->RestoreTPL (OldTpl);
649
650 gBS->FreePool (Instance);
651 return EFI_SUCCESS;
652 }