]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Driver.c
1. Add EFI_COMPONENT_NAME2_PROTOCOL.GetControllerName() support.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Mtftp4Dxe / Mtftp4Driver.c
1 /** @file
2 Implementation of Mtftp drivers.
3
4 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php<BR>
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "Mtftp4Impl.h"
16
17 EFI_DRIVER_BINDING_PROTOCOL gMtftp4DriverBinding = {
18 Mtftp4DriverBindingSupported,
19 Mtftp4DriverBindingStart,
20 Mtftp4DriverBindingStop,
21 0xa,
22 NULL,
23 NULL
24 };
25
26 EFI_SERVICE_BINDING_PROTOCOL gMtftp4ServiceBindingTemplete = {
27 Mtftp4ServiceBindingCreateChild,
28 Mtftp4ServiceBindingDestroyChild
29 };
30
31
32 /**
33 The driver entry point which installs multiple protocols to the ImageHandle.
34
35 @param ImageHandle The MTFTP's image handle.
36 @param SystemTable The system table.
37
38 @retval EFI_SUCCESS The handles are successfully installed on the image.
39 @retval others some EFI_ERROR occured.
40
41 **/
42 EFI_STATUS
43 EFIAPI
44 Mtftp4DriverEntryPoint (
45 IN EFI_HANDLE ImageHandle,
46 IN EFI_SYSTEM_TABLE *SystemTable
47 )
48 {
49 return EfiLibInstallDriverBindingComponentName2 (
50 ImageHandle,
51 SystemTable,
52 &gMtftp4DriverBinding,
53 ImageHandle,
54 &gMtftp4ComponentName,
55 &gMtftp4ComponentName2
56 );
57 }
58
59
60 /**
61 Test whether MTFTP driver support this controller.
62
63 @param This The MTFTP driver binding instance
64 @param Controller The controller to test
65 @param RemainingDevicePath The remaining device path
66
67 @retval EFI_SUCCESS The controller has UDP service binding protocol
68 installed, MTFTP can support it.
69 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
70 RemainingDevicePath is already being managed by
71 the driver specified by This.
72 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
73 RemainingDevicePath is already being managed by a
74 different driver or an application that requires
75 exclusive access.
76 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
77 RemainingDevicePath is not supported by the driver
78 specified by This.
79
80 **/
81 EFI_STATUS
82 EFIAPI
83 Mtftp4DriverBindingSupported (
84 IN EFI_DRIVER_BINDING_PROTOCOL *This,
85 IN EFI_HANDLE Controller,
86 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
87 )
88 {
89 EFI_STATUS Status;
90
91 Status = gBS->OpenProtocol (
92 Controller,
93 &gEfiUdp4ServiceBindingProtocolGuid,
94 NULL,
95 This->DriverBindingHandle,
96 Controller,
97 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
98 );
99
100 return Status;
101 }
102
103
104 /**
105 Config a NULL UDP that is used to keep the connection between UDP and MTFTP.
106
107 Just leave the Udp child unconfigured. When UDP is unloaded,
108 MTFTP will be informed with DriverBinding Stop.
109
110 @param UdpIo The UDP_IO to configure
111 @param Context The opaque parameter to the callback
112
113 @retval EFI_SUCCESS It always return EFI_SUCCESS directly.
114
115 **/
116 EFI_STATUS
117 EFIAPI
118 Mtftp4ConfigNullUdp (
119 IN UDP_IO *UdpIo,
120 IN VOID *Context
121 )
122 {
123 return EFI_SUCCESS;
124 }
125
126
127 /**
128 Create then initialize a MTFTP service binding instance.
129
130 @param Controller The controller to install the MTFTP service
131 binding on
132 @param Image The driver binding image of the MTFTP driver
133 @param Service The variable to receive the created service
134 binding instance.
135
136 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to create the instance
137 @retval EFI_DEVICE_ERROR Failed to create a NULL UDP port to keep
138 connection with UDP.
139 @retval EFI_SUCCESS The service instance is created for the
140 controller.
141
142 **/
143 EFI_STATUS
144 Mtftp4CreateService (
145 IN EFI_HANDLE Controller,
146 IN EFI_HANDLE Image,
147 OUT MTFTP4_SERVICE **Service
148 )
149 {
150 MTFTP4_SERVICE *MtftpSb;
151 EFI_STATUS Status;
152
153 *Service = NULL;
154 MtftpSb = AllocatePool (sizeof (MTFTP4_SERVICE));
155
156 if (MtftpSb == NULL) {
157 return EFI_OUT_OF_RESOURCES;
158 }
159
160 MtftpSb->Signature = MTFTP4_SERVICE_SIGNATURE;
161 MtftpSb->ServiceBinding = gMtftp4ServiceBindingTemplete;
162 MtftpSb->ChildrenNum = 0;
163 InitializeListHead (&MtftpSb->Children);
164
165 MtftpSb->Timer = NULL;
166 MtftpSb->TimerToGetMap = NULL;
167 MtftpSb->Controller = Controller;
168 MtftpSb->Image = Image;
169 MtftpSb->ConnectUdp = NULL;
170
171 //
172 // Create the timer and a udp to be notified when UDP is uninstalled
173 //
174 Status = gBS->CreateEvent (
175 EVT_NOTIFY_SIGNAL | EVT_TIMER,
176 TPL_CALLBACK,
177 Mtftp4OnTimerTick,
178 MtftpSb,
179 &MtftpSb->Timer
180 );
181
182 if (EFI_ERROR (Status)) {
183 FreePool (MtftpSb);
184 return Status;
185 }
186
187 //
188 // Create the timer used to time out the procedure which is used to
189 // get the default IP address.
190 //
191 Status = gBS->CreateEvent (
192 EVT_TIMER,
193 TPL_CALLBACK,
194 NULL,
195 NULL,
196 &MtftpSb->TimerToGetMap
197 );
198 if (EFI_ERROR (Status)) {
199 gBS->CloseEvent (MtftpSb->Timer);
200 FreePool (MtftpSb);
201 return Status;
202 }
203
204 MtftpSb->ConnectUdp = UdpIoCreateIo (
205 Controller,
206 Image,
207 Mtftp4ConfigNullUdp,
208 UDP_IO_UDP4_VERSION,
209 NULL
210 );
211
212 if (MtftpSb->ConnectUdp == NULL) {
213 gBS->CloseEvent (MtftpSb->TimerToGetMap);
214 gBS->CloseEvent (MtftpSb->Timer);
215 FreePool (MtftpSb);
216 return EFI_DEVICE_ERROR;
217 }
218
219 *Service = MtftpSb;
220 return EFI_SUCCESS;
221 }
222
223
224 /**
225 Release all the resource used the MTFTP service binding instance.
226
227 @param MtftpSb The MTFTP service binding instance.
228
229 **/
230 VOID
231 Mtftp4CleanService (
232 IN MTFTP4_SERVICE *MtftpSb
233 )
234 {
235 UdpIoFreeIo (MtftpSb->ConnectUdp);
236 gBS->CloseEvent (MtftpSb->TimerToGetMap);
237 gBS->CloseEvent (MtftpSb->Timer);
238 }
239
240
241 /**
242 Start the MTFTP driver on this controller.
243
244 MTFTP driver will install a MTFTP SERVICE BINDING protocol on the supported
245 controller, which can be used to create/destroy MTFTP children.
246
247 @param This The MTFTP driver binding protocol.
248 @param Controller The controller to manage.
249 @param RemainingDevicePath Remaining device path.
250
251 @retval EFI_ALREADY_STARTED The MTFTP service binding protocol has been
252 started on the controller.
253 @retval EFI_SUCCESS The MTFTP service binding is installed on the
254 controller.
255
256 **/
257 EFI_STATUS
258 EFIAPI
259 Mtftp4DriverBindingStart (
260 IN EFI_DRIVER_BINDING_PROTOCOL *This,
261 IN EFI_HANDLE Controller,
262 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
263 )
264 {
265 MTFTP4_SERVICE *MtftpSb;
266 EFI_STATUS Status;
267
268 //
269 // Directly return if driver is already running.
270 //
271 Status = gBS->OpenProtocol (
272 Controller,
273 &gEfiMtftp4ServiceBindingProtocolGuid,
274 NULL,
275 This->DriverBindingHandle,
276 Controller,
277 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
278 );
279
280 if (Status == EFI_SUCCESS) {
281 return EFI_ALREADY_STARTED;
282 }
283
284 Status = Mtftp4CreateService (Controller, This->DriverBindingHandle, &MtftpSb);
285
286 if (EFI_ERROR (Status)) {
287 return Status;
288 }
289 ASSERT (MtftpSb != NULL);
290
291 Status = gBS->SetTimer (MtftpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
292
293 if (EFI_ERROR (Status)) {
294 goto ON_ERROR;
295 }
296
297 //
298 // Install the Mtftp4ServiceBinding Protocol onto Controller
299 //
300 Status = gBS->InstallMultipleProtocolInterfaces (
301 &Controller,
302 &gEfiMtftp4ServiceBindingProtocolGuid,
303 &MtftpSb->ServiceBinding,
304 NULL
305 );
306
307 if (EFI_ERROR (Status)) {
308 goto ON_ERROR;
309 }
310
311 return EFI_SUCCESS;
312
313 ON_ERROR:
314 Mtftp4CleanService (MtftpSb);
315 FreePool (MtftpSb);
316
317 return Status;
318 }
319
320 /**
321 Callback function which provided by user to remove one node in NetDestroyLinkList process.
322
323 @param[in] Entry The entry to be removed.
324 @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
325
326 @retval EFI_SUCCESS The entry has been removed successfully.
327 @retval Others Fail to remove the entry.
328
329 **/
330 EFI_STATUS
331 Mtftp4DestroyChildEntryInHandleBuffer (
332 IN LIST_ENTRY *Entry,
333 IN VOID *Context
334 )
335 {
336 MTFTP4_PROTOCOL *Instance;
337 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
338 UINTN NumberOfChildren;
339 EFI_HANDLE *ChildHandleBuffer;
340
341 if (Entry == NULL || Context == NULL) {
342 return EFI_INVALID_PARAMETER;
343 }
344
345 Instance = NET_LIST_USER_STRUCT_S (Entry, MTFTP4_PROTOCOL, Link, MTFTP4_PROTOCOL_SIGNATURE);
346 ServiceBinding = ((MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
347 NumberOfChildren = ((MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
348 ChildHandleBuffer = ((MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
349
350 if (!NetIsInHandleBuffer (Instance->Handle, NumberOfChildren, ChildHandleBuffer)) {
351 return EFI_SUCCESS;
352 }
353
354 return ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
355 }
356
357 /**
358 Stop the MTFTP driver on controller. The controller is a UDP
359 child handle.
360
361 @param This The MTFTP driver binding protocol
362 @param Controller The controller to stop
363 @param NumberOfChildren The number of children
364 @param ChildHandleBuffer The array of the child handle.
365
366 @retval EFI_SUCCESS The driver is stopped on the controller.
367 @retval EFI_DEVICE_ERROR Failed to stop the driver on the controller.
368
369 **/
370 EFI_STATUS
371 EFIAPI
372 Mtftp4DriverBindingStop (
373 IN EFI_DRIVER_BINDING_PROTOCOL *This,
374 IN EFI_HANDLE Controller,
375 IN UINTN NumberOfChildren,
376 IN EFI_HANDLE *ChildHandleBuffer
377 )
378 {
379 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
380 MTFTP4_SERVICE *MtftpSb;
381 EFI_HANDLE NicHandle;
382 EFI_STATUS Status;
383 LIST_ENTRY *List;
384 MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;
385
386 //
387 // MTFTP driver opens UDP child, So, Controller is a UDP
388 // child handle. Locate the Nic handle first. Then get the
389 // MTFTP private data back.
390 //
391 NicHandle = NetLibGetNicHandle (Controller, &gEfiUdp4ProtocolGuid);
392
393 if (NicHandle == NULL) {
394 return EFI_SUCCESS;
395 }
396
397 Status = gBS->OpenProtocol (
398 NicHandle,
399 &gEfiMtftp4ServiceBindingProtocolGuid,
400 (VOID **) &ServiceBinding,
401 This->DriverBindingHandle,
402 NicHandle,
403 EFI_OPEN_PROTOCOL_GET_PROTOCOL
404 );
405
406 if (EFI_ERROR (Status)) {
407 return EFI_DEVICE_ERROR;
408 }
409
410 MtftpSb = MTFTP4_SERVICE_FROM_THIS (ServiceBinding);
411
412 if (!IsListEmpty (&MtftpSb->Children)) {
413 //
414 // Destroy the Mtftp4 child instance in ChildHandleBuffer.
415 //
416 List = &MtftpSb->Children;
417 Context.ServiceBinding = ServiceBinding;
418 Context.NumberOfChildren = NumberOfChildren;
419 Context.ChildHandleBuffer = ChildHandleBuffer;
420 Status = NetDestroyLinkList (
421 List,
422 Mtftp4DestroyChildEntryInHandleBuffer,
423 &Context,
424 NULL
425 );
426 }
427
428 if (NumberOfChildren == 0 && IsListEmpty (&MtftpSb->Children)) {
429 gBS->UninstallProtocolInterface (
430 NicHandle,
431 &gEfiMtftp4ServiceBindingProtocolGuid,
432 ServiceBinding
433 );
434
435 Mtftp4CleanService (MtftpSb);
436 if (gMtftp4ControllerNameTable != NULL) {
437 FreeUnicodeStringTable (gMtftp4ControllerNameTable);
438 gMtftp4ControllerNameTable = NULL;
439 }
440 FreePool (MtftpSb);
441
442 Status = EFI_SUCCESS;
443 }
444
445 return Status;
446 }
447
448
449 /**
450 Initialize a MTFTP protocol instance which is the child of MtftpSb.
451
452 @param MtftpSb The MTFTP service binding protocol.
453 @param Instance The MTFTP instance to initialize.
454
455 **/
456 VOID
457 Mtftp4InitProtocol (
458 IN MTFTP4_SERVICE *MtftpSb,
459 OUT MTFTP4_PROTOCOL *Instance
460 )
461 {
462 ZeroMem (Instance, sizeof (MTFTP4_PROTOCOL));
463
464 Instance->Signature = MTFTP4_PROTOCOL_SIGNATURE;
465 InitializeListHead (&Instance->Link);
466 CopyMem (&Instance->Mtftp4, &gMtftp4ProtocolTemplate, sizeof (Instance->Mtftp4));
467 Instance->State = MTFTP4_STATE_UNCONFIGED;
468 Instance->Service = MtftpSb;
469
470 InitializeListHead (&Instance->Blocks);
471 }
472
473
474 /**
475 Create a MTFTP child for the service binding instance, then
476 install the MTFTP protocol to the ChildHandle.
477
478 @param This The MTFTP service binding instance.
479 @param ChildHandle The Child handle to install the MTFTP protocol.
480
481 @retval EFI_INVALID_PARAMETER The parameter is invalid.
482 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the new child.
483 @retval EFI_SUCCESS The child is successfully create.
484
485 **/
486 EFI_STATUS
487 EFIAPI
488 Mtftp4ServiceBindingCreateChild (
489 IN EFI_SERVICE_BINDING_PROTOCOL *This,
490 IN EFI_HANDLE *ChildHandle
491 )
492 {
493 MTFTP4_SERVICE *MtftpSb;
494 MTFTP4_PROTOCOL *Instance;
495 EFI_STATUS Status;
496 EFI_TPL OldTpl;
497 VOID *Udp4;
498
499 if ((This == NULL) || (ChildHandle == NULL)) {
500 return EFI_INVALID_PARAMETER;
501 }
502
503 Instance = AllocatePool (sizeof (*Instance));
504
505 if (Instance == NULL) {
506 return EFI_OUT_OF_RESOURCES;
507 }
508
509 MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
510
511 Mtftp4InitProtocol (MtftpSb, Instance);
512
513 Instance->UnicastPort = UdpIoCreateIo (
514 MtftpSb->Controller,
515 MtftpSb->Image,
516 Mtftp4ConfigNullUdp,
517 UDP_IO_UDP4_VERSION,
518 Instance
519 );
520
521 if (Instance->UnicastPort == NULL) {
522 FreePool (Instance);
523 return EFI_OUT_OF_RESOURCES;
524 }
525
526 //
527 // Install the MTFTP protocol onto ChildHandle
528 //
529 Status = gBS->InstallMultipleProtocolInterfaces (
530 ChildHandle,
531 &gEfiMtftp4ProtocolGuid,
532 &Instance->Mtftp4,
533 NULL
534 );
535
536 if (EFI_ERROR (Status)) {
537 UdpIoFreeIo (Instance->UnicastPort);
538 FreePool (Instance);
539 return Status;
540 }
541
542 Instance->Handle = *ChildHandle;
543
544 //
545 // Open the Udp4 protocol BY_CHILD.
546 //
547 Status = gBS->OpenProtocol (
548 MtftpSb->ConnectUdp->UdpHandle,
549 &gEfiUdp4ProtocolGuid,
550 (VOID **) &Udp4,
551 gMtftp4DriverBinding.DriverBindingHandle,
552 Instance->Handle,
553 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
554 );
555 if (EFI_ERROR (Status)) {
556 goto ON_ERROR;
557 }
558
559 //
560 // Open the Udp4 protocol by child.
561 //
562 Status = gBS->OpenProtocol (
563 Instance->UnicastPort->UdpHandle,
564 &gEfiUdp4ProtocolGuid,
565 (VOID **) &Udp4,
566 gMtftp4DriverBinding.DriverBindingHandle,
567 Instance->Handle,
568 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
569 );
570 if (EFI_ERROR (Status)) {
571 //
572 // Close the Udp4 protocol.
573 //
574 gBS->CloseProtocol (
575 MtftpSb->ConnectUdp->UdpHandle,
576 &gEfiUdp4ProtocolGuid,
577 gMtftp4DriverBinding.DriverBindingHandle,
578 ChildHandle
579 );
580 goto ON_ERROR;
581 }
582
583 //
584 // Add it to the parent's child list.
585 //
586 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
587
588 InsertTailList (&MtftpSb->Children, &Instance->Link);
589 MtftpSb->ChildrenNum++;
590
591 gBS->RestoreTPL (OldTpl);
592
593 return EFI_SUCCESS;
594
595 ON_ERROR:
596 if (Instance->Handle != NULL) {
597 gBS->UninstallMultipleProtocolInterfaces (
598 Instance->Handle,
599 &gEfiMtftp4ProtocolGuid,
600 &Instance->Mtftp4,
601 NULL
602 );
603 }
604
605 UdpIoFreeIo (Instance->UnicastPort);
606 FreePool (Instance);
607
608 return Status;
609 }
610
611
612 /**
613 Destroy one of the service binding's child.
614
615 @param This The service binding instance
616 @param ChildHandle The child handle to destroy
617
618 @retval EFI_INVALID_PARAMETER The parameter is invaid.
619 @retval EFI_UNSUPPORTED The child may have already been destroyed.
620 @retval EFI_SUCCESS The child is destroyed and removed from the
621 parent's child list.
622
623 **/
624 EFI_STATUS
625 EFIAPI
626 Mtftp4ServiceBindingDestroyChild (
627 IN EFI_SERVICE_BINDING_PROTOCOL *This,
628 IN EFI_HANDLE ChildHandle
629 )
630 {
631 MTFTP4_SERVICE *MtftpSb;
632 MTFTP4_PROTOCOL *Instance;
633 EFI_MTFTP4_PROTOCOL *Mtftp4;
634 EFI_STATUS Status;
635 EFI_TPL OldTpl;
636
637 if ((This == NULL) || (ChildHandle == NULL)) {
638 return EFI_INVALID_PARAMETER;
639 }
640
641 //
642 // Retrieve the private context data structures
643 //
644 Status = gBS->OpenProtocol (
645 ChildHandle,
646 &gEfiMtftp4ProtocolGuid,
647 (VOID **) &Mtftp4,
648 gMtftp4DriverBinding.DriverBindingHandle,
649 ChildHandle,
650 EFI_OPEN_PROTOCOL_GET_PROTOCOL
651 );
652
653 if (EFI_ERROR (Status)) {
654 return EFI_UNSUPPORTED;
655 }
656
657 Instance = MTFTP4_PROTOCOL_FROM_THIS (Mtftp4);
658 MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
659
660 if (Instance->Service != MtftpSb) {
661 return EFI_INVALID_PARAMETER;
662 }
663
664 if (Instance->InDestroy) {
665 return EFI_SUCCESS;
666 }
667
668 Instance->InDestroy = TRUE;
669
670 //
671 // Close the Udp4 protocol.
672 //
673 gBS->CloseProtocol (
674 MtftpSb->ConnectUdp->UdpHandle,
675 &gEfiUdp4ProtocolGuid,
676 gMtftp4DriverBinding.DriverBindingHandle,
677 ChildHandle
678 );
679
680 gBS->CloseProtocol (
681 Instance->UnicastPort->UdpHandle,
682 &gEfiUdp4ProtocolGuid,
683 gMtftp4DriverBinding.DriverBindingHandle,
684 ChildHandle
685 );
686
687 if (Instance->McastUdpPort != NULL) {
688 gBS->CloseProtocol (
689 Instance->McastUdpPort->UdpHandle,
690 &gEfiUdp4ProtocolGuid,
691 gMtftp4DriverBinding.DriverBindingHandle,
692 ChildHandle
693 );
694 }
695
696 //
697 // Uninstall the MTFTP4 protocol first to enable a top down destruction.
698 //
699 Status = gBS->UninstallProtocolInterface (
700 ChildHandle,
701 &gEfiMtftp4ProtocolGuid,
702 Mtftp4
703 );
704
705 if (EFI_ERROR (Status)) {
706 Instance->InDestroy = FALSE;
707 return Status;
708 }
709
710 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
711
712 Mtftp4CleanOperation (Instance, EFI_DEVICE_ERROR);
713 UdpIoFreeIo (Instance->UnicastPort);
714
715 RemoveEntryList (&Instance->Link);
716 MtftpSb->ChildrenNum--;
717
718 gBS->RestoreTPL (OldTpl);
719
720 FreePool (Instance);
721 return EFI_SUCCESS;
722 }