]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Driver.c
1c74b5b08344cf9014df2ce341f51991f1f2b9da
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Mtftp4Dxe / Mtftp4Driver.c
1 /** @file
2 Implementation of Mtftp drivers.
3
4 Copyright (c) 2006 - 2010, 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->InDestory = FALSE;
163 MtftpSb->ChildrenNum = 0;
164 InitializeListHead (&MtftpSb->Children);
165
166 MtftpSb->Timer = NULL;
167 MtftpSb->TimerToGetMap = NULL;
168 MtftpSb->Controller = Controller;
169 MtftpSb->Image = Image;
170 MtftpSb->ConnectUdp = NULL;
171
172 //
173 // Create the timer and a udp to be notified when UDP is uninstalled
174 //
175 Status = gBS->CreateEvent (
176 EVT_NOTIFY_SIGNAL | EVT_TIMER,
177 TPL_CALLBACK,
178 Mtftp4OnTimerTick,
179 MtftpSb,
180 &MtftpSb->Timer
181 );
182
183 if (EFI_ERROR (Status)) {
184 FreePool (MtftpSb);
185 return Status;
186 }
187
188 //
189 // Create the timer used to time out the procedure which is used to
190 // get the default IP address.
191 //
192 Status = gBS->CreateEvent (
193 EVT_TIMER,
194 TPL_CALLBACK,
195 NULL,
196 NULL,
197 &MtftpSb->TimerToGetMap
198 );
199 if (EFI_ERROR (Status)) {
200 gBS->CloseEvent (MtftpSb->Timer);
201 FreePool (MtftpSb);
202 return Status;
203 }
204
205 MtftpSb->ConnectUdp = UdpIoCreateIo (
206 Controller,
207 Image,
208 Mtftp4ConfigNullUdp,
209 UDP_IO_UDP4_VERSION,
210 NULL
211 );
212
213 if (MtftpSb->ConnectUdp == NULL) {
214 gBS->CloseEvent (MtftpSb->TimerToGetMap);
215 gBS->CloseEvent (MtftpSb->Timer);
216 FreePool (MtftpSb);
217 return EFI_DEVICE_ERROR;
218 }
219
220 *Service = MtftpSb;
221 return EFI_SUCCESS;
222 }
223
224
225 /**
226 Release all the resource used the MTFTP service binding instance.
227
228 @param MtftpSb The MTFTP service binding instance.
229
230 **/
231 VOID
232 Mtftp4CleanService (
233 IN MTFTP4_SERVICE *MtftpSb
234 )
235 {
236 UdpIoFreeIo (MtftpSb->ConnectUdp);
237 gBS->CloseEvent (MtftpSb->TimerToGetMap);
238 gBS->CloseEvent (MtftpSb->Timer);
239 }
240
241
242 /**
243 Start the MTFTP driver on this controller.
244
245 MTFTP driver will install a MTFTP SERVICE BINDING protocol on the supported
246 controller, which can be used to create/destroy MTFTP children.
247
248 @param This The MTFTP driver binding protocol.
249 @param Controller The controller to manage.
250 @param RemainingDevicePath Remaining device path.
251
252 @retval EFI_ALREADY_STARTED The MTFTP service binding protocol has been
253 started on the controller.
254 @retval EFI_SUCCESS The MTFTP service binding is installed on the
255 controller.
256
257 **/
258 EFI_STATUS
259 EFIAPI
260 Mtftp4DriverBindingStart (
261 IN EFI_DRIVER_BINDING_PROTOCOL *This,
262 IN EFI_HANDLE Controller,
263 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
264 )
265 {
266 MTFTP4_SERVICE *MtftpSb;
267 EFI_STATUS Status;
268
269 //
270 // Directly return if driver is already running.
271 //
272 Status = gBS->OpenProtocol (
273 Controller,
274 &gEfiMtftp4ServiceBindingProtocolGuid,
275 NULL,
276 This->DriverBindingHandle,
277 Controller,
278 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
279 );
280
281 if (Status == EFI_SUCCESS) {
282 return EFI_ALREADY_STARTED;
283 }
284
285 Status = Mtftp4CreateService (Controller, This->DriverBindingHandle, &MtftpSb);
286
287 if (EFI_ERROR (Status)) {
288 return Status;
289 }
290 ASSERT (MtftpSb != NULL);
291
292 Status = gBS->SetTimer (MtftpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
293
294 if (EFI_ERROR (Status)) {
295 goto ON_ERROR;
296 }
297
298 //
299 // Install the Mtftp4ServiceBinding Protocol onto Controller
300 //
301 Status = gBS->InstallMultipleProtocolInterfaces (
302 &Controller,
303 &gEfiMtftp4ServiceBindingProtocolGuid,
304 &MtftpSb->ServiceBinding,
305 NULL
306 );
307
308 if (EFI_ERROR (Status)) {
309 goto ON_ERROR;
310 }
311
312 return EFI_SUCCESS;
313
314 ON_ERROR:
315 Mtftp4CleanService (MtftpSb);
316 FreePool (MtftpSb);
317
318 return Status;
319 }
320
321
322 /**
323 Stop the MTFTP driver on controller. The controller is a UDP
324 child handle.
325
326 @param This The MTFTP driver binding protocol
327 @param Controller The controller to stop
328 @param NumberOfChildren The number of children
329 @param ChildHandleBuffer The array of the child handle.
330
331 @retval EFI_SUCCESS The driver is stopped on the controller.
332 @retval EFI_DEVICE_ERROR Failed to stop the driver on the controller.
333
334 **/
335 EFI_STATUS
336 EFIAPI
337 Mtftp4DriverBindingStop (
338 IN EFI_DRIVER_BINDING_PROTOCOL *This,
339 IN EFI_HANDLE Controller,
340 IN UINTN NumberOfChildren,
341 IN EFI_HANDLE *ChildHandleBuffer
342 )
343 {
344 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
345 MTFTP4_SERVICE *MtftpSb;
346 MTFTP4_PROTOCOL *Instance;
347 EFI_HANDLE NicHandle;
348 EFI_STATUS Status;
349 EFI_TPL OldTpl;
350
351 //
352 // MTFTP driver opens UDP child, So, Controller is a UDP
353 // child handle. Locate the Nic handle first. Then get the
354 // MTFTP private data back.
355 //
356 NicHandle = NetLibGetNicHandle (Controller, &gEfiUdp4ProtocolGuid);
357
358 if (NicHandle == NULL) {
359 return EFI_DEVICE_ERROR;
360 }
361
362 Status = gBS->OpenProtocol (
363 NicHandle,
364 &gEfiMtftp4ServiceBindingProtocolGuid,
365 (VOID **) &ServiceBinding,
366 This->DriverBindingHandle,
367 NicHandle,
368 EFI_OPEN_PROTOCOL_GET_PROTOCOL
369 );
370
371 if (EFI_ERROR (Status)) {
372 return EFI_DEVICE_ERROR;
373 }
374
375 MtftpSb = MTFTP4_SERVICE_FROM_THIS (ServiceBinding);
376
377 if (MtftpSb->InDestory) {
378 return EFI_SUCCESS;
379 }
380
381 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
382
383 if (NumberOfChildren == 0) {
384
385 MtftpSb->InDestory = TRUE;
386
387 gBS->UninstallProtocolInterface (
388 NicHandle,
389 &gEfiMtftp4ServiceBindingProtocolGuid,
390 ServiceBinding
391 );
392
393 Mtftp4CleanService (MtftpSb);
394
395 FreePool (MtftpSb);
396 } else {
397
398 while (!IsListEmpty (&MtftpSb->Children)) {
399 Instance = NET_LIST_HEAD (&MtftpSb->Children, MTFTP4_PROTOCOL, Link);
400 Mtftp4ServiceBindingDestroyChild (ServiceBinding, Instance->Handle);
401 }
402
403 if (MtftpSb->ChildrenNum != 0) {
404 Status = EFI_DEVICE_ERROR;
405 }
406 }
407
408 gBS->RestoreTPL (OldTpl);
409 return Status;
410 }
411
412
413 /**
414 Initialize a MTFTP protocol instance which is the child of MtftpSb.
415
416 @param MtftpSb The MTFTP service binding protocol.
417 @param Instance The MTFTP instance to initialize.
418
419 **/
420 VOID
421 Mtftp4InitProtocol (
422 IN MTFTP4_SERVICE *MtftpSb,
423 OUT MTFTP4_PROTOCOL *Instance
424 )
425 {
426 ZeroMem (Instance, sizeof (MTFTP4_PROTOCOL));
427
428 Instance->Signature = MTFTP4_PROTOCOL_SIGNATURE;
429 InitializeListHead (&Instance->Link);
430 CopyMem (&Instance->Mtftp4, &gMtftp4ProtocolTemplate, sizeof (Instance->Mtftp4));
431 Instance->State = MTFTP4_STATE_UNCONFIGED;
432 Instance->InDestory = FALSE;
433 Instance->Service = MtftpSb;
434
435 InitializeListHead (&Instance->Blocks);
436 }
437
438
439 /**
440 Create a MTFTP child for the service binding instance, then
441 install the MTFTP protocol to the ChildHandle.
442
443 @param This The MTFTP service binding instance.
444 @param ChildHandle The Child handle to install the MTFTP protocol.
445
446 @retval EFI_INVALID_PARAMETER The parameter is invalid.
447 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the new child.
448 @retval EFI_SUCCESS The child is successfully create.
449
450 **/
451 EFI_STATUS
452 EFIAPI
453 Mtftp4ServiceBindingCreateChild (
454 IN EFI_SERVICE_BINDING_PROTOCOL *This,
455 IN EFI_HANDLE *ChildHandle
456 )
457 {
458 MTFTP4_SERVICE *MtftpSb;
459 MTFTP4_PROTOCOL *Instance;
460 EFI_STATUS Status;
461 EFI_TPL OldTpl;
462 VOID *Udp4;
463
464 if ((This == NULL) || (ChildHandle == NULL)) {
465 return EFI_INVALID_PARAMETER;
466 }
467
468 Instance = AllocatePool (sizeof (*Instance));
469
470 if (Instance == NULL) {
471 return EFI_OUT_OF_RESOURCES;
472 }
473
474 MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
475
476 Mtftp4InitProtocol (MtftpSb, Instance);
477
478 Instance->UnicastPort = UdpIoCreateIo (
479 MtftpSb->Controller,
480 MtftpSb->Image,
481 Mtftp4ConfigNullUdp,
482 UDP_IO_UDP4_VERSION,
483 Instance
484 );
485
486 if (Instance->UnicastPort == NULL) {
487 FreePool (Instance);
488 return EFI_OUT_OF_RESOURCES;
489 }
490
491 //
492 // Install the MTFTP protocol onto ChildHandle
493 //
494 Status = gBS->InstallMultipleProtocolInterfaces (
495 ChildHandle,
496 &gEfiMtftp4ProtocolGuid,
497 &Instance->Mtftp4,
498 NULL
499 );
500
501 if (EFI_ERROR (Status)) {
502 goto ON_ERROR;
503 }
504
505 Instance->Handle = *ChildHandle;
506
507 //
508 // Open the Udp4 protocol BY_CHILD.
509 //
510 Status = gBS->OpenProtocol (
511 MtftpSb->ConnectUdp->UdpHandle,
512 &gEfiUdp4ProtocolGuid,
513 (VOID **) &Udp4,
514 gMtftp4DriverBinding.DriverBindingHandle,
515 Instance->Handle,
516 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
517 );
518 if (EFI_ERROR (Status)) {
519 gBS->UninstallMultipleProtocolInterfaces (
520 Instance->Handle,
521 &gEfiMtftp4ProtocolGuid,
522 &Instance->Mtftp4,
523 NULL
524 );
525
526 goto ON_ERROR;
527 }
528
529 //
530 // Add it to the parent's child list.
531 //
532 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
533
534 InsertTailList (&MtftpSb->Children, &Instance->Link);
535 MtftpSb->ChildrenNum++;
536
537 gBS->RestoreTPL (OldTpl);
538
539 ON_ERROR:
540
541 if (EFI_ERROR (Status)) {
542 UdpIoFreeIo (Instance->UnicastPort);
543 FreePool (Instance);
544 }
545
546 return Status;
547 }
548
549
550 /**
551 Destory one of the service binding's child.
552
553 @param This The service binding instance
554 @param ChildHandle The child handle to destory
555
556 @retval EFI_INVALID_PARAMETER The parameter is invaid.
557 @retval EFI_UNSUPPORTED The child may have already been destoried.
558 @retval EFI_SUCCESS The child is destoried and removed from the
559 parent's child list.
560
561 **/
562 EFI_STATUS
563 EFIAPI
564 Mtftp4ServiceBindingDestroyChild (
565 IN EFI_SERVICE_BINDING_PROTOCOL *This,
566 IN EFI_HANDLE ChildHandle
567 )
568 {
569 MTFTP4_SERVICE *MtftpSb;
570 MTFTP4_PROTOCOL *Instance;
571 EFI_MTFTP4_PROTOCOL *Mtftp4;
572 EFI_STATUS Status;
573 EFI_TPL OldTpl;
574
575 if ((This == NULL) || (ChildHandle == NULL)) {
576 return EFI_INVALID_PARAMETER;
577 }
578
579 //
580 // Retrieve the private context data structures
581 //
582 Status = gBS->OpenProtocol (
583 ChildHandle,
584 &gEfiMtftp4ProtocolGuid,
585 (VOID **) &Mtftp4,
586 gMtftp4DriverBinding.DriverBindingHandle,
587 ChildHandle,
588 EFI_OPEN_PROTOCOL_GET_PROTOCOL
589 );
590
591 if (EFI_ERROR (Status)) {
592 return EFI_UNSUPPORTED;
593 }
594
595 Instance = MTFTP4_PROTOCOL_FROM_THIS (Mtftp4);
596 MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
597
598 if (Instance->Service != MtftpSb) {
599 return EFI_INVALID_PARAMETER;
600 }
601
602 if (Instance->InDestory) {
603 return EFI_SUCCESS;
604 }
605
606 Instance->InDestory = TRUE;
607
608 //
609 // Close the Udp4 protocol.
610 //
611 gBS->CloseProtocol (
612 MtftpSb->ConnectUdp->UdpHandle,
613 &gEfiUdp4ProtocolGuid,
614 gMtftp4DriverBinding.DriverBindingHandle,
615 ChildHandle
616 );
617
618 //
619 // Uninstall the MTFTP4 protocol first to enable a top down destruction.
620 //
621 Status = gBS->UninstallProtocolInterface (
622 ChildHandle,
623 &gEfiMtftp4ProtocolGuid,
624 Mtftp4
625 );
626
627 if (EFI_ERROR (Status)) {
628 Instance->InDestory = FALSE;
629 return Status;
630 }
631
632 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
633
634 Mtftp4CleanOperation (Instance, EFI_DEVICE_ERROR);
635 UdpIoFreeIo (Instance->UnicastPort);
636
637 RemoveEntryList (&Instance->Link);
638 MtftpSb->ChildrenNum--;
639
640 gBS->RestoreTPL (OldTpl);
641
642 FreePool (Instance);
643 return EFI_SUCCESS;
644 }