]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Driver.c
1. Update the UdpIo to a combined UdpIo to support both v4 and v6 stack.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Mtftp4Dxe / Mtftp4Driver.c
1 /** @file
2 Implementation of Mtftp drivers.
3
4 Copyright (c) 2006 - 2009, Intel Corporation<BR>
5 All rights reserved. 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 Mtftp4ConfigNullUdp (
118 IN UDP_IO *UdpIo,
119 IN VOID *Context
120 )
121 {
122 return EFI_SUCCESS;
123 }
124
125
126 /**
127 Create then initialize a MTFTP service binding instance.
128
129 @param Controller The controller to install the MTFTP service
130 binding on
131 @param Image The driver binding image of the MTFTP driver
132 @param Service The variable to receive the created service
133 binding instance.
134
135 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to create the instance
136 @retval EFI_DEVICE_ERROR Failed to create a NULL UDP port to keep
137 connection with UDP.
138 @retval EFI_SUCCESS The service instance is created for the
139 controller.
140
141 **/
142 EFI_STATUS
143 Mtftp4CreateService (
144 IN EFI_HANDLE Controller,
145 IN EFI_HANDLE Image,
146 OUT MTFTP4_SERVICE **Service
147 )
148 {
149 MTFTP4_SERVICE *MtftpSb;
150 EFI_STATUS Status;
151
152 *Service = NULL;
153 MtftpSb = AllocatePool (sizeof (MTFTP4_SERVICE));
154
155 if (MtftpSb == NULL) {
156 return EFI_OUT_OF_RESOURCES;
157 }
158
159 MtftpSb->Signature = MTFTP4_SERVICE_SIGNATURE;
160 MtftpSb->ServiceBinding = gMtftp4ServiceBindingTemplete;
161 MtftpSb->InDestory = FALSE;
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 gBS->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 gBS->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 gBS->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
290 Status = gBS->SetTimer (MtftpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
291
292 if (EFI_ERROR (Status)) {
293 goto ON_ERROR;
294 }
295
296 //
297 // Install the Mtftp4ServiceBinding Protocol onto Controller
298 //
299 Status = gBS->InstallMultipleProtocolInterfaces (
300 &Controller,
301 &gEfiMtftp4ServiceBindingProtocolGuid,
302 &MtftpSb->ServiceBinding,
303 NULL
304 );
305
306 if (EFI_ERROR (Status)) {
307 goto ON_ERROR;
308 }
309
310 return EFI_SUCCESS;
311
312 ON_ERROR:
313 Mtftp4CleanService (MtftpSb);
314 gBS->FreePool (MtftpSb);
315
316 return Status;
317 }
318
319
320 /**
321 Stop the MTFTP driver on controller. The controller is a UDP
322 child handle.
323
324 @param This The MTFTP driver binding protocol
325 @param Controller The controller to stop
326 @param NumberOfChildren The number of children
327 @param ChildHandleBuffer The array of the child handle.
328
329 @retval EFI_SUCCESS The driver is stopped on the controller.
330 @retval EFI_DEVICE_ERROR Failed to stop the driver on the controller.
331
332 **/
333 EFI_STATUS
334 EFIAPI
335 Mtftp4DriverBindingStop (
336 IN EFI_DRIVER_BINDING_PROTOCOL *This,
337 IN EFI_HANDLE Controller,
338 IN UINTN NumberOfChildren,
339 IN EFI_HANDLE *ChildHandleBuffer
340 )
341 {
342 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
343 MTFTP4_SERVICE *MtftpSb;
344 MTFTP4_PROTOCOL *Instance;
345 EFI_HANDLE NicHandle;
346 EFI_STATUS Status;
347 EFI_TPL OldTpl;
348
349 //
350 // MTFTP driver opens UDP child, So, Controller is a UDP
351 // child handle. Locate the Nic handle first. Then get the
352 // MTFTP private data back.
353 //
354 NicHandle = NetLibGetNicHandle (Controller, &gEfiUdp4ProtocolGuid);
355
356 if (NicHandle == NULL) {
357 return EFI_DEVICE_ERROR;
358 }
359
360 Status = gBS->OpenProtocol (
361 NicHandle,
362 &gEfiMtftp4ServiceBindingProtocolGuid,
363 (VOID **) &ServiceBinding,
364 This->DriverBindingHandle,
365 NicHandle,
366 EFI_OPEN_PROTOCOL_GET_PROTOCOL
367 );
368
369 if (EFI_ERROR (Status)) {
370 return EFI_DEVICE_ERROR;
371 }
372
373 MtftpSb = MTFTP4_SERVICE_FROM_THIS (ServiceBinding);
374
375 if (MtftpSb->InDestory) {
376 return EFI_SUCCESS;
377 }
378
379 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
380
381 if (NumberOfChildren == 0) {
382
383 MtftpSb->InDestory = TRUE;
384
385 gBS->UninstallProtocolInterface (
386 NicHandle,
387 &gEfiMtftp4ServiceBindingProtocolGuid,
388 ServiceBinding
389 );
390
391 Mtftp4CleanService (MtftpSb);
392
393 gBS->FreePool (MtftpSb);
394 } else {
395
396 while (!IsListEmpty (&MtftpSb->Children)) {
397 Instance = NET_LIST_HEAD (&MtftpSb->Children, MTFTP4_PROTOCOL, Link);
398 Mtftp4ServiceBindingDestroyChild (ServiceBinding, Instance->Handle);
399 }
400
401 if (MtftpSb->ChildrenNum != 0) {
402 Status = EFI_DEVICE_ERROR;
403 }
404 }
405
406 gBS->RestoreTPL (OldTpl);
407 return Status;
408 }
409
410
411 /**
412 Initialize a MTFTP protocol instance which is the child of MtftpSb.
413
414 @param MtftpSb The MTFTP service binding protocol.
415 @param Instance The MTFTP instance to initialize.
416
417 **/
418 VOID
419 Mtftp4InitProtocol (
420 IN MTFTP4_SERVICE *MtftpSb,
421 OUT MTFTP4_PROTOCOL *Instance
422 )
423 {
424 ZeroMem (Instance, sizeof (MTFTP4_PROTOCOL));
425
426 Instance->Signature = MTFTP4_PROTOCOL_SIGNATURE;
427 InitializeListHead (&Instance->Link);
428 CopyMem (&Instance->Mtftp4, &gMtftp4ProtocolTemplate, sizeof (Instance->Mtftp4));
429 Instance->State = MTFTP4_STATE_UNCONFIGED;
430 Instance->InDestory = FALSE;
431 Instance->Service = MtftpSb;
432
433 InitializeListHead (&Instance->Blocks);
434 }
435
436
437 /**
438 Create a MTFTP child for the service binding instance, then
439 install the MTFTP protocol to the ChildHandle.
440
441 @param This The MTFTP service binding instance.
442 @param ChildHandle The Child handle to install the MTFTP protocol.
443
444 @retval EFI_INVALID_PARAMETER The parameter is invalid.
445 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the new child.
446 @retval EFI_SUCCESS The child is successfully create.
447
448 **/
449 EFI_STATUS
450 EFIAPI
451 Mtftp4ServiceBindingCreateChild (
452 IN EFI_SERVICE_BINDING_PROTOCOL *This,
453 IN EFI_HANDLE *ChildHandle
454 )
455 {
456 MTFTP4_SERVICE *MtftpSb;
457 MTFTP4_PROTOCOL *Instance;
458 EFI_STATUS Status;
459 EFI_TPL OldTpl;
460 VOID *Udp4;
461
462 if ((This == NULL) || (ChildHandle == NULL)) {
463 return EFI_INVALID_PARAMETER;
464 }
465
466 Instance = AllocatePool (sizeof (*Instance));
467
468 if (Instance == NULL) {
469 return EFI_OUT_OF_RESOURCES;
470 }
471
472 MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
473
474 Mtftp4InitProtocol (MtftpSb, Instance);
475
476 Instance->UnicastPort = UdpIoCreateIo (
477 MtftpSb->Controller,
478 MtftpSb->Image,
479 Mtftp4ConfigNullUdp,
480 UDP_IO_UDP4_VERSION,
481 Instance
482 );
483
484 if (Instance->UnicastPort == NULL) {
485 gBS->FreePool (Instance);
486 return EFI_OUT_OF_RESOURCES;
487 }
488
489 //
490 // Install the MTFTP protocol onto ChildHandle
491 //
492 Status = gBS->InstallMultipleProtocolInterfaces (
493 ChildHandle,
494 &gEfiMtftp4ProtocolGuid,
495 &Instance->Mtftp4,
496 NULL
497 );
498
499 if (EFI_ERROR (Status)) {
500 goto ON_ERROR;
501 }
502
503 Instance->Handle = *ChildHandle;
504
505 //
506 // Open the Udp4 protocol BY_CHILD.
507 //
508 Status = gBS->OpenProtocol (
509 MtftpSb->ConnectUdp->UdpHandle,
510 &gEfiUdp4ProtocolGuid,
511 (VOID **) &Udp4,
512 gMtftp4DriverBinding.DriverBindingHandle,
513 Instance->Handle,
514 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
515 );
516 if (EFI_ERROR (Status)) {
517 gBS->UninstallMultipleProtocolInterfaces (
518 Instance->Handle,
519 &gEfiMtftp4ProtocolGuid,
520 &Instance->Mtftp4,
521 NULL
522 );
523
524 goto ON_ERROR;
525 }
526
527 //
528 // Add it to the parent's child list.
529 //
530 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
531
532 InsertTailList (&MtftpSb->Children, &Instance->Link);
533 MtftpSb->ChildrenNum++;
534
535 gBS->RestoreTPL (OldTpl);
536
537 ON_ERROR:
538
539 if (EFI_ERROR (Status)) {
540 UdpIoFreeIo (Instance->UnicastPort);
541 gBS->FreePool (Instance);
542 }
543
544 return Status;
545 }
546
547
548 /**
549 Destory one of the service binding's child.
550
551 @param This The service binding instance
552 @param ChildHandle The child handle to destory
553
554 @retval EFI_INVALID_PARAMETER The parameter is invaid.
555 @retval EFI_UNSUPPORTED The child may have already been destoried.
556 @retval EFI_SUCCESS The child is destoried and removed from the
557 parent's child list.
558
559 **/
560 EFI_STATUS
561 EFIAPI
562 Mtftp4ServiceBindingDestroyChild (
563 IN EFI_SERVICE_BINDING_PROTOCOL *This,
564 IN EFI_HANDLE ChildHandle
565 )
566 {
567 MTFTP4_SERVICE *MtftpSb;
568 MTFTP4_PROTOCOL *Instance;
569 EFI_MTFTP4_PROTOCOL *Mtftp4;
570 EFI_STATUS Status;
571 EFI_TPL OldTpl;
572
573 if ((This == NULL) || (ChildHandle == NULL)) {
574 return EFI_INVALID_PARAMETER;
575 }
576
577 //
578 // Retrieve the private context data structures
579 //
580 Status = gBS->OpenProtocol (
581 ChildHandle,
582 &gEfiMtftp4ProtocolGuid,
583 (VOID **) &Mtftp4,
584 gMtftp4DriverBinding.DriverBindingHandle,
585 ChildHandle,
586 EFI_OPEN_PROTOCOL_GET_PROTOCOL
587 );
588
589 if (EFI_ERROR (Status)) {
590 return EFI_UNSUPPORTED;
591 }
592
593 Instance = MTFTP4_PROTOCOL_FROM_THIS (Mtftp4);
594 MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
595
596 if (Instance->Service != MtftpSb) {
597 return EFI_INVALID_PARAMETER;
598 }
599
600 if (Instance->InDestory) {
601 return EFI_SUCCESS;
602 }
603
604 Instance->InDestory = TRUE;
605
606 //
607 // Close the Udp4 protocol.
608 //
609 gBS->CloseProtocol (
610 MtftpSb->ConnectUdp->UdpHandle,
611 &gEfiUdp4ProtocolGuid,
612 gMtftp4DriverBinding.DriverBindingHandle,
613 ChildHandle
614 );
615
616 //
617 // Uninstall the MTFTP4 protocol first to enable a top down destruction.
618 //
619 Status = gBS->UninstallProtocolInterface (
620 ChildHandle,
621 &gEfiMtftp4ProtocolGuid,
622 Mtftp4
623 );
624
625 if (EFI_ERROR (Status)) {
626 Instance->InDestory = FALSE;
627 return Status;
628 }
629
630 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
631
632 Mtftp4CleanOperation (Instance, EFI_DEVICE_ERROR);
633 UdpIoFreeIo (Instance->UnicastPort);
634
635 RemoveEntryList (&Instance->Link);
636 MtftpSb->ChildrenNum--;
637
638 gBS->RestoreTPL (OldTpl);
639
640 gBS->FreePool (Instance);
641 return EFI_SUCCESS;
642 }