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