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