]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Driver.c
Use Mde library and definition instead of some native definitions in NetLib, to simpl...
[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 ZeroMem (&UdpConfigData.StationAddress, sizeof (EFI_IPv4_ADDRESS));
145 ZeroMem (&UdpConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
146 ZeroMem (&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 = AllocateZeroPool (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 InitializeListHead (&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 gBS->FreePool (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 gBS->FreePool (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_DEVICE_ERROR;
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 = gBS->RaiseTPL (TPL_CALLBACK);
398
399 if (NumberOfChildren == 0) {
400
401 DhcpSb->InDestory = TRUE;
402 DhcpSb->ServiceState = DHCP_DESTORY;
403
404 gBS->UninstallProtocolInterface (
405 NicHandle,
406 &gEfiDhcp4ServiceBindingProtocolGuid,
407 ServiceBinding
408 );
409
410 Dhcp4CloseService (DhcpSb);
411
412 gBS->FreePool (DhcpSb);
413 } else {
414 //
415 // Don't use NET_LIST_FOR_EACH_SAFE here, Dhcp4ServiceBindingDestoryChild
416 // may cause other child to be deleted.
417 //
418 while (!IsListEmpty (&DhcpSb->Children)) {
419 Instance = NET_LIST_HEAD (&DhcpSb->Children, DHCP_PROTOCOL, Link);
420 ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
421 }
422
423 if (DhcpSb->NumChildren != 0) {
424 Status = EFI_DEVICE_ERROR;
425 }
426 }
427
428 gBS->RestoreTPL (OldTpl);
429
430 return Status;
431 }
432
433
434 /**
435 Initialize a new DHCP child
436
437 @param DhcpSb The dhcp service instance
438 @param Instance The dhcp instance to initialize
439
440 @return None
441
442 **/
443 VOID
444 DhcpInitProtocol (
445 IN DHCP_SERVICE *DhcpSb,
446 IN DHCP_PROTOCOL *Instance
447 )
448 {
449 Instance->Signature = DHCP_PROTOCOL_SIGNATURE;
450 CopyMem (&Instance->Dhcp4Protocol, &mDhcp4ProtocolTemplate, sizeof (Instance->Dhcp4Protocol));
451 InitializeListHead (&Instance->Link);
452 Instance->Handle = NULL;
453 Instance->Service = DhcpSb;
454 Instance->InDestory = FALSE;
455 Instance->CompletionEvent = NULL;
456 Instance->RenewRebindEvent = NULL;
457 Instance->Token = NULL;
458 Instance->UdpIo = NULL;
459 NetbufQueInit (&Instance->ResponseQueue);
460 }
461
462
463 /**
464 Creates a child handle with a set of DHCP4 services.
465
466 @param This Protocol instance pointer.
467 @param ChildHandle Pointer to the handle of the child to create. If
468 it is NULL, then a new handle is created. If it
469 is not NULL, then the DHCP4 services are added to
470 the existing child handle.
471
472 @retval EFI_SUCCES The child handle was created with the DHCP4
473 services
474 @retval EFI_OUT_OF_RESOURCES There are not enough resources to create the child
475 @retval other The child handle was not created
476
477 **/
478 EFI_STATUS
479 EFIAPI
480 Dhcp4ServiceBindingCreateChild (
481 IN EFI_SERVICE_BINDING_PROTOCOL *This,
482 IN EFI_HANDLE *ChildHandle
483 )
484 {
485 DHCP_SERVICE *DhcpSb;
486 DHCP_PROTOCOL *Instance;
487 EFI_STATUS Status;
488 EFI_TPL OldTpl;
489 VOID *Udp4;
490
491 if ((This == NULL) || (ChildHandle == NULL)) {
492 return EFI_INVALID_PARAMETER;
493 }
494
495 Instance = AllocatePool (sizeof (*Instance));
496
497 if (Instance == NULL) {
498 return EFI_OUT_OF_RESOURCES;
499 }
500
501 DhcpSb = DHCP_SERVICE_FROM_THIS (This);
502 DhcpInitProtocol (DhcpSb, Instance);
503
504 //
505 // Install DHCP4 onto ChildHandle
506 //
507 Status = gBS->InstallMultipleProtocolInterfaces (
508 ChildHandle,
509 &gEfiDhcp4ProtocolGuid,
510 &Instance->Dhcp4Protocol,
511 NULL
512 );
513
514 if (EFI_ERROR (Status)) {
515 gBS->FreePool (Instance);
516 return Status;
517 }
518
519 Instance->Handle = *ChildHandle;
520
521 //
522 // Open the Udp4 protocol BY_CHILD.
523 //
524 Status = gBS->OpenProtocol (
525 DhcpSb->UdpIo->UdpHandle,
526 &gEfiUdp4ProtocolGuid,
527 (VOID **) &Udp4,
528 gDhcp4DriverBinding.DriverBindingHandle,
529 Instance->Handle,
530 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
531 );
532 if (EFI_ERROR (Status)) {
533 gBS->UninstallMultipleProtocolInterfaces (
534 Instance->Handle,
535 &gEfiDhcp4ProtocolGuid,
536 &Instance->Dhcp4Protocol,
537 NULL
538 );
539
540 gBS->FreePool (Instance);
541 return Status;
542 }
543
544 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
545
546 InsertTailList (&DhcpSb->Children, &Instance->Link);
547 DhcpSb->NumChildren++;
548
549 gBS->RestoreTPL (OldTpl);
550
551 return EFI_SUCCESS;
552 }
553
554
555 /**
556 Destroys a child handle with a set of DHCP4 services.
557
558 @param This Protocol instance pointer.
559 @param ChildHandle Handle of the child to destroy
560
561 @retval EFI_SUCCES The DHCP4 service is removed from the child handle
562 @retval EFI_UNSUPPORTED The child handle does not support the DHCP4
563 service
564 @retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.
565 @retval EFI_ACCESS_DENIED The child handle could not be destroyed because
566 its DHCP4 services are being used.
567 @retval other The child handle was not destroyed
568
569 **/
570 EFI_STATUS
571 EFIAPI
572 Dhcp4ServiceBindingDestroyChild (
573 IN EFI_SERVICE_BINDING_PROTOCOL *This,
574 IN EFI_HANDLE ChildHandle
575 )
576 {
577 DHCP_SERVICE *DhcpSb;
578 DHCP_PROTOCOL *Instance;
579 EFI_DHCP4_PROTOCOL *Dhcp;
580 EFI_TPL OldTpl;
581 EFI_STATUS Status;
582
583 if ((This == NULL) || (ChildHandle == NULL)) {
584 return EFI_INVALID_PARAMETER;
585 }
586
587 //
588 // Retrieve the private context data structures
589 //
590 Status = gBS->OpenProtocol (
591 ChildHandle,
592 &gEfiDhcp4ProtocolGuid,
593 (VOID **) &Dhcp,
594 gDhcp4DriverBinding.DriverBindingHandle,
595 ChildHandle,
596 EFI_OPEN_PROTOCOL_GET_PROTOCOL
597 );
598
599 if (EFI_ERROR (Status)) {
600 return EFI_UNSUPPORTED;
601 }
602
603 Instance = DHCP_INSTANCE_FROM_THIS (Dhcp);
604 DhcpSb = DHCP_SERVICE_FROM_THIS (This);
605
606 if (Instance->Service != DhcpSb) {
607 return EFI_INVALID_PARAMETER;
608 }
609
610 //
611 // A child can be destoried more than once. For example,
612 // Dhcp4DriverBindingStop will destory all of its children.
613 // when caller driver is being stopped, it will destory the
614 // dhcp child it opens.
615 //
616 if (Instance->InDestory) {
617 return EFI_SUCCESS;
618 }
619
620 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
621 Instance->InDestory = TRUE;
622
623 //
624 // Close the Udp4 protocol.
625 //
626 gBS->CloseProtocol (
627 DhcpSb->UdpIo->UdpHandle,
628 &gEfiUdp4ProtocolGuid,
629 gDhcp4DriverBinding.DriverBindingHandle,
630 ChildHandle
631 );
632
633 //
634 // Uninstall the DHCP4 protocol first to enable a top down destruction.
635 //
636 Status = gBS->UninstallProtocolInterface (
637 ChildHandle,
638 &gEfiDhcp4ProtocolGuid,
639 Dhcp
640 );
641
642 if (EFI_ERROR (Status)) {
643 Instance->InDestory = FALSE;
644
645 gBS->RestoreTPL (OldTpl);
646 return Status;
647 }
648
649 if (DhcpSb->ActiveChild == Instance) {
650 DhcpYieldControl (DhcpSb);
651 }
652
653 RemoveEntryList (&Instance->Link);
654 DhcpSb->NumChildren--;
655
656 gBS->RestoreTPL (OldTpl);
657
658 gBS->FreePool (Instance);
659 return EFI_SUCCESS;
660 }