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