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