]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Driver.c
Fix GCC build fail issue for MdeModulePkg and NetworkPkg.
[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 EFIAPI
332 Mtftp4DestroyChildEntryInHandleBuffer (
333 IN LIST_ENTRY *Entry,
334 IN VOID *Context
335 )
336 {
337 MTFTP4_PROTOCOL *Instance;
338 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
339 UINTN NumberOfChildren;
340 EFI_HANDLE *ChildHandleBuffer;
341
342 if (Entry == NULL || Context == NULL) {
343 return EFI_INVALID_PARAMETER;
344 }
345
346 Instance = NET_LIST_USER_STRUCT_S (Entry, MTFTP4_PROTOCOL, Link, MTFTP4_PROTOCOL_SIGNATURE);
347 ServiceBinding = ((MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
348 NumberOfChildren = ((MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
349 ChildHandleBuffer = ((MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
350
351 if (!NetIsInHandleBuffer (Instance->Handle, NumberOfChildren, ChildHandleBuffer)) {
352 return EFI_SUCCESS;
353 }
354
355 return ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
356 }
357
358 /**
359 Stop the MTFTP driver on controller. The controller is a UDP
360 child handle.
361
362 @param This The MTFTP driver binding protocol
363 @param Controller The controller to stop
364 @param NumberOfChildren The number of children
365 @param ChildHandleBuffer The array of the child handle.
366
367 @retval EFI_SUCCESS The driver is stopped on the controller.
368 @retval EFI_DEVICE_ERROR Failed to stop the driver on the controller.
369
370 **/
371 EFI_STATUS
372 EFIAPI
373 Mtftp4DriverBindingStop (
374 IN EFI_DRIVER_BINDING_PROTOCOL *This,
375 IN EFI_HANDLE Controller,
376 IN UINTN NumberOfChildren,
377 IN EFI_HANDLE *ChildHandleBuffer
378 )
379 {
380 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
381 MTFTP4_SERVICE *MtftpSb;
382 EFI_HANDLE NicHandle;
383 EFI_STATUS Status;
384 LIST_ENTRY *List;
385 MTFTP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;
386
387 //
388 // MTFTP driver opens UDP child, So, Controller is a UDP
389 // child handle. Locate the Nic handle first. Then get the
390 // MTFTP private data back.
391 //
392 NicHandle = NetLibGetNicHandle (Controller, &gEfiUdp4ProtocolGuid);
393
394 if (NicHandle == NULL) {
395 return EFI_SUCCESS;
396 }
397
398 Status = gBS->OpenProtocol (
399 NicHandle,
400 &gEfiMtftp4ServiceBindingProtocolGuid,
401 (VOID **) &ServiceBinding,
402 This->DriverBindingHandle,
403 NicHandle,
404 EFI_OPEN_PROTOCOL_GET_PROTOCOL
405 );
406
407 if (EFI_ERROR (Status)) {
408 return EFI_DEVICE_ERROR;
409 }
410
411 MtftpSb = MTFTP4_SERVICE_FROM_THIS (ServiceBinding);
412
413 if (!IsListEmpty (&MtftpSb->Children)) {
414 //
415 // Destroy the Mtftp4 child instance in ChildHandleBuffer.
416 //
417 List = &MtftpSb->Children;
418 Context.ServiceBinding = ServiceBinding;
419 Context.NumberOfChildren = NumberOfChildren;
420 Context.ChildHandleBuffer = ChildHandleBuffer;
421 Status = NetDestroyLinkList (
422 List,
423 Mtftp4DestroyChildEntryInHandleBuffer,
424 &Context,
425 NULL
426 );
427 }
428
429 if (NumberOfChildren == 0 && IsListEmpty (&MtftpSb->Children)) {
430 gBS->UninstallProtocolInterface (
431 NicHandle,
432 &gEfiMtftp4ServiceBindingProtocolGuid,
433 ServiceBinding
434 );
435
436 Mtftp4CleanService (MtftpSb);
437 if (gMtftp4ControllerNameTable != NULL) {
438 FreeUnicodeStringTable (gMtftp4ControllerNameTable);
439 gMtftp4ControllerNameTable = NULL;
440 }
441 FreePool (MtftpSb);
442
443 Status = EFI_SUCCESS;
444 }
445
446 return Status;
447 }
448
449
450 /**
451 Initialize a MTFTP protocol instance which is the child of MtftpSb.
452
453 @param MtftpSb The MTFTP service binding protocol.
454 @param Instance The MTFTP instance to initialize.
455
456 **/
457 VOID
458 Mtftp4InitProtocol (
459 IN MTFTP4_SERVICE *MtftpSb,
460 OUT MTFTP4_PROTOCOL *Instance
461 )
462 {
463 ZeroMem (Instance, sizeof (MTFTP4_PROTOCOL));
464
465 Instance->Signature = MTFTP4_PROTOCOL_SIGNATURE;
466 InitializeListHead (&Instance->Link);
467 CopyMem (&Instance->Mtftp4, &gMtftp4ProtocolTemplate, sizeof (Instance->Mtftp4));
468 Instance->State = MTFTP4_STATE_UNCONFIGED;
469 Instance->Service = MtftpSb;
470
471 InitializeListHead (&Instance->Blocks);
472 }
473
474
475 /**
476 Create a MTFTP child for the service binding instance, then
477 install the MTFTP protocol to the ChildHandle.
478
479 @param This The MTFTP service binding instance.
480 @param ChildHandle The Child handle to install the MTFTP protocol.
481
482 @retval EFI_INVALID_PARAMETER The parameter is invalid.
483 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the new child.
484 @retval EFI_SUCCESS The child is successfully create.
485
486 **/
487 EFI_STATUS
488 EFIAPI
489 Mtftp4ServiceBindingCreateChild (
490 IN EFI_SERVICE_BINDING_PROTOCOL *This,
491 IN EFI_HANDLE *ChildHandle
492 )
493 {
494 MTFTP4_SERVICE *MtftpSb;
495 MTFTP4_PROTOCOL *Instance;
496 EFI_STATUS Status;
497 EFI_TPL OldTpl;
498 VOID *Udp4;
499
500 if ((This == NULL) || (ChildHandle == NULL)) {
501 return EFI_INVALID_PARAMETER;
502 }
503
504 Instance = AllocatePool (sizeof (*Instance));
505
506 if (Instance == NULL) {
507 return EFI_OUT_OF_RESOURCES;
508 }
509
510 MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
511
512 Mtftp4InitProtocol (MtftpSb, Instance);
513
514 Instance->UnicastPort = UdpIoCreateIo (
515 MtftpSb->Controller,
516 MtftpSb->Image,
517 Mtftp4ConfigNullUdp,
518 UDP_IO_UDP4_VERSION,
519 Instance
520 );
521
522 if (Instance->UnicastPort == NULL) {
523 FreePool (Instance);
524 return EFI_OUT_OF_RESOURCES;
525 }
526
527 //
528 // Install the MTFTP protocol onto ChildHandle
529 //
530 Status = gBS->InstallMultipleProtocolInterfaces (
531 ChildHandle,
532 &gEfiMtftp4ProtocolGuid,
533 &Instance->Mtftp4,
534 NULL
535 );
536
537 if (EFI_ERROR (Status)) {
538 UdpIoFreeIo (Instance->UnicastPort);
539 FreePool (Instance);
540 return Status;
541 }
542
543 Instance->Handle = *ChildHandle;
544
545 //
546 // Open the Udp4 protocol BY_CHILD.
547 //
548 Status = gBS->OpenProtocol (
549 MtftpSb->ConnectUdp->UdpHandle,
550 &gEfiUdp4ProtocolGuid,
551 (VOID **) &Udp4,
552 gMtftp4DriverBinding.DriverBindingHandle,
553 Instance->Handle,
554 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
555 );
556 if (EFI_ERROR (Status)) {
557 goto ON_ERROR;
558 }
559
560 //
561 // Open the Udp4 protocol by child.
562 //
563 Status = gBS->OpenProtocol (
564 Instance->UnicastPort->UdpHandle,
565 &gEfiUdp4ProtocolGuid,
566 (VOID **) &Udp4,
567 gMtftp4DriverBinding.DriverBindingHandle,
568 Instance->Handle,
569 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
570 );
571 if (EFI_ERROR (Status)) {
572 //
573 // Close the Udp4 protocol.
574 //
575 gBS->CloseProtocol (
576 MtftpSb->ConnectUdp->UdpHandle,
577 &gEfiUdp4ProtocolGuid,
578 gMtftp4DriverBinding.DriverBindingHandle,
579 ChildHandle
580 );
581 goto ON_ERROR;
582 }
583
584 //
585 // Add it to the parent's child list.
586 //
587 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
588
589 InsertTailList (&MtftpSb->Children, &Instance->Link);
590 MtftpSb->ChildrenNum++;
591
592 gBS->RestoreTPL (OldTpl);
593
594 return EFI_SUCCESS;
595
596 ON_ERROR:
597 if (Instance->Handle != NULL) {
598 gBS->UninstallMultipleProtocolInterfaces (
599 Instance->Handle,
600 &gEfiMtftp4ProtocolGuid,
601 &Instance->Mtftp4,
602 NULL
603 );
604 }
605
606 UdpIoFreeIo (Instance->UnicastPort);
607 FreePool (Instance);
608
609 return Status;
610 }
611
612
613 /**
614 Destroy one of the service binding's child.
615
616 @param This The service binding instance
617 @param ChildHandle The child handle to destroy
618
619 @retval EFI_INVALID_PARAMETER The parameter is invaid.
620 @retval EFI_UNSUPPORTED The child may have already been destroyed.
621 @retval EFI_SUCCESS The child is destroyed and removed from the
622 parent's child list.
623
624 **/
625 EFI_STATUS
626 EFIAPI
627 Mtftp4ServiceBindingDestroyChild (
628 IN EFI_SERVICE_BINDING_PROTOCOL *This,
629 IN EFI_HANDLE ChildHandle
630 )
631 {
632 MTFTP4_SERVICE *MtftpSb;
633 MTFTP4_PROTOCOL *Instance;
634 EFI_MTFTP4_PROTOCOL *Mtftp4;
635 EFI_STATUS Status;
636 EFI_TPL OldTpl;
637
638 if ((This == NULL) || (ChildHandle == NULL)) {
639 return EFI_INVALID_PARAMETER;
640 }
641
642 //
643 // Retrieve the private context data structures
644 //
645 Status = gBS->OpenProtocol (
646 ChildHandle,
647 &gEfiMtftp4ProtocolGuid,
648 (VOID **) &Mtftp4,
649 gMtftp4DriverBinding.DriverBindingHandle,
650 ChildHandle,
651 EFI_OPEN_PROTOCOL_GET_PROTOCOL
652 );
653
654 if (EFI_ERROR (Status)) {
655 return EFI_UNSUPPORTED;
656 }
657
658 Instance = MTFTP4_PROTOCOL_FROM_THIS (Mtftp4);
659 MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
660
661 if (Instance->Service != MtftpSb) {
662 return EFI_INVALID_PARAMETER;
663 }
664
665 if (Instance->InDestroy) {
666 return EFI_SUCCESS;
667 }
668
669 Instance->InDestroy = TRUE;
670
671 //
672 // Close the Udp4 protocol.
673 //
674 gBS->CloseProtocol (
675 MtftpSb->ConnectUdp->UdpHandle,
676 &gEfiUdp4ProtocolGuid,
677 gMtftp4DriverBinding.DriverBindingHandle,
678 ChildHandle
679 );
680
681 gBS->CloseProtocol (
682 Instance->UnicastPort->UdpHandle,
683 &gEfiUdp4ProtocolGuid,
684 gMtftp4DriverBinding.DriverBindingHandle,
685 ChildHandle
686 );
687
688 if (Instance->McastUdpPort != NULL) {
689 gBS->CloseProtocol (
690 Instance->McastUdpPort->UdpHandle,
691 &gEfiUdp4ProtocolGuid,
692 gMtftp4DriverBinding.DriverBindingHandle,
693 ChildHandle
694 );
695 }
696
697 //
698 // Uninstall the MTFTP4 protocol first to enable a top down destruction.
699 //
700 Status = gBS->UninstallProtocolInterface (
701 ChildHandle,
702 &gEfiMtftp4ProtocolGuid,
703 Mtftp4
704 );
705
706 if (EFI_ERROR (Status)) {
707 Instance->InDestroy = FALSE;
708 return Status;
709 }
710
711 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
712
713 Mtftp4CleanOperation (Instance, EFI_DEVICE_ERROR);
714 UdpIoFreeIo (Instance->UnicastPort);
715
716 RemoveEntryList (&Instance->Link);
717 MtftpSb->ChildrenNum--;
718
719 gBS->RestoreTPL (OldTpl);
720
721 FreePool (Instance);
722 return EFI_SUCCESS;
723 }