]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Driver.c
9b30b3d730a01a6d0bbc1e1758a4b0da690f79e0
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Mtftp4Dxe / Mtftp4Driver.c
1 /** @file
2
3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 Mtftp4Driver.c
15
16 Abstract:
17
18
19 **/
20
21 #include "Mtftp4Impl.h"
22
23 EFI_DRIVER_BINDING_PROTOCOL gMtftp4DriverBinding = {
24 Mtftp4DriverBindingSupported,
25 Mtftp4DriverBindingStart,
26 Mtftp4DriverBindingStop,
27 0xa,
28 NULL,
29 NULL
30 };
31
32 EFI_SERVICE_BINDING_PROTOCOL gMtftp4ServiceBindingTemplete = {
33 Mtftp4ServiceBindingCreateChild,
34 Mtftp4ServiceBindingDestroyChild
35 };
36
37 //@MT: EFI_DRIVER_ENTRY_POINT (Mtftp4DriverEntryPoint)
38
39 EFI_STATUS
40 EFIAPI
41 Mtftp4DriverEntryPoint (
42 IN EFI_HANDLE ImageHandle,
43 IN EFI_SYSTEM_TABLE *SystemTable
44 )
45 /*++
46
47 Routine Description:
48
49 The driver entry point which installs multiple protocols to the ImageHandle.
50
51 Arguments:
52
53 ImageHandle - The MTFTP's image handle
54 SystemTable - The system table
55
56 Returns:
57
58 EFI_SUCCESS - The handles are successfully installed on the image. Otherwise
59 some EFI_ERROR.
60
61 --*/
62 {
63 return NetLibInstallAllDriverProtocols (
64 ImageHandle,
65 SystemTable,
66 &gMtftp4DriverBinding,
67 ImageHandle,
68 &gMtftp4ComponentName,
69 NULL,
70 NULL
71 );
72 }
73
74
75 /**
76 Test whether MTFTP driver support this controller.
77
78 @param This The MTFTP driver binding instance
79 @param Controller The controller to test
80 @param RemainingDevicePath The remaining device path
81
82 @retval EFI_SUCCESS The controller has UDP service binding protocol
83 installed, MTFTP can support it.
84 @retval Others MTFTP can't support the controller.
85
86 **/
87 EFI_STATUS
88 Mtftp4DriverBindingSupported (
89 IN EFI_DRIVER_BINDING_PROTOCOL *This,
90 IN EFI_HANDLE Controller,
91 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
92 )
93 {
94 EFI_STATUS Status;
95
96 Status = gBS->OpenProtocol (
97 Controller,
98 &gEfiUdp4ServiceBindingProtocolGuid,
99 NULL,
100 This->DriverBindingHandle,
101 Controller,
102 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
103 );
104
105 return Status;
106 }
107
108
109 /**
110 Config a NULL UDP that is used to keep the connection between UDP
111 and MTFTP. Just leave the Udp child unconfigured. When UDP is
112 unloaded, MTFTP will be informed with DriverBinding Stop.
113
114 @param UdpIo The UDP port to configure
115 @param Context The opaque parameter to the callback
116
117 @retval EFI_SUCCESS It always return EFI_SUCCESS directly.
118
119 **/
120 EFI_STATUS
121 Mtftp4ConfigNullUdp (
122 IN UDP_IO_PORT *UdpIo,
123 IN VOID *Context
124 )
125 {
126 return EFI_SUCCESS;
127 }
128
129
130 /**
131 Create then initialize a MTFTP service binding instance.
132
133 @param Controller The controller to install the MTFTP service
134 binding on
135 @param Image The driver binding image of the MTFTP driver
136 @param Service The variable to receive the created service
137 binding instance.
138
139 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to create the instance
140 @retval EFI_DEVICE_ERROR Failed to create a NULL UDP port to keep
141 connection with UDP.
142 @retval EFI_SUCCESS The service instance is created for the
143 controller.
144
145 **/
146 EFI_STATUS
147 Mtftp4CreateService (
148 IN EFI_HANDLE Controller,
149 IN EFI_HANDLE Image,
150 OUT MTFTP4_SERVICE **Service
151 )
152 {
153 MTFTP4_SERVICE *MtftpSb;
154 EFI_STATUS Status;
155
156 *Service = NULL;
157 MtftpSb = NetAllocatePool (sizeof (MTFTP4_SERVICE));
158
159 if (MtftpSb == NULL) {
160 return EFI_OUT_OF_RESOURCES;
161 }
162
163 MtftpSb->Signature = MTFTP4_SERVICE_SIGNATURE;
164 MtftpSb->ServiceBinding = gMtftp4ServiceBindingTemplete;
165 MtftpSb->InDestory = FALSE;
166 MtftpSb->ChildrenNum = 0;
167 NetListInit (&MtftpSb->Children);
168
169 MtftpSb->Timer = NULL;
170 MtftpSb->TimerToGetMap = NULL;
171 MtftpSb->Controller = Controller;
172 MtftpSb->Image = Image;
173 MtftpSb->ConnectUdp = NULL;
174
175 //
176 // Create the timer and a udp to be notified when UDP is uninstalled
177 //
178 Status = gBS->CreateEvent (
179 EVT_NOTIFY_SIGNAL | EVT_TIMER,
180 TPL_CALLBACK,
181 Mtftp4OnTimerTick,
182 MtftpSb,
183 &MtftpSb->Timer
184 );
185
186 if (EFI_ERROR (Status)) {
187 NetFreePool (MtftpSb);
188 return Status;
189 }
190
191 //
192 // Create the timer used to time out the procedure which is used to
193 // get the default IP address.
194 //
195 Status = gBS->CreateEvent (
196 EVT_TIMER,
197 TPL_CALLBACK,
198 NULL,
199 NULL,
200 &MtftpSb->TimerToGetMap
201 );
202 if (EFI_ERROR (Status)) {
203 gBS->CloseEvent (MtftpSb->Timer);
204 NetFreePool (MtftpSb);
205 return Status;
206 }
207
208 MtftpSb->ConnectUdp = UdpIoCreatePort (Controller, Image, Mtftp4ConfigNullUdp, NULL);
209
210 if (MtftpSb->ConnectUdp == NULL) {
211 gBS->CloseEvent (MtftpSb->TimerToGetMap);
212 gBS->CloseEvent (MtftpSb->Timer);
213 NetFreePool (MtftpSb);
214 return EFI_DEVICE_ERROR;
215 }
216
217 *Service = MtftpSb;
218 return EFI_SUCCESS;
219 }
220
221
222 /**
223 Release all the resource used the MTFTP service binding instance.
224
225 @param MtftpSb The MTFTP service binding instance.
226
227 @return None
228
229 **/
230 VOID
231 Mtftp4CleanService (
232 IN MTFTP4_SERVICE *MtftpSb
233 )
234 {
235 UdpIoFreePort (MtftpSb->ConnectUdp);
236 gBS->CloseEvent (MtftpSb->TimerToGetMap);
237 gBS->CloseEvent (MtftpSb->Timer);
238 }
239
240
241 /**
242 Start the MTFTP driver on this controller. MTFTP driver will
243 install a MTFTP SERVICE BINDING protocol on the supported
244 controller, which can be used to create/destroy MTFTP children.
245
246 @param This The MTFTP driver binding protocol.
247 @param Controller The controller to manage.
248 @param RemainingDevicePath Remaining device path.
249
250 @retval EFI_ALREADY_STARTED The MTFTP service binding protocol has been
251 started on the controller.
252 @retval EFI_SUCCESS The MTFTP service binding is installed on the
253 controller.
254
255 **/
256 EFI_STATUS
257 Mtftp4DriverBindingStart (
258 IN EFI_DRIVER_BINDING_PROTOCOL *This,
259 IN EFI_HANDLE Controller,
260 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
261 )
262 {
263 MTFTP4_SERVICE *MtftpSb;
264 EFI_STATUS Status;
265
266 //
267 // Directly return if driver is already running.
268 //
269 Status = gBS->OpenProtocol (
270 Controller,
271 &gEfiMtftp4ServiceBindingProtocolGuid,
272 NULL,
273 This->DriverBindingHandle,
274 Controller,
275 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
276 );
277
278 if (Status == EFI_SUCCESS) {
279 return EFI_ALREADY_STARTED;
280 }
281
282 Status = Mtftp4CreateService (Controller, This->DriverBindingHandle, &MtftpSb);
283
284 if (EFI_ERROR (Status)) {
285 return Status;
286 }
287
288 Status = gBS->SetTimer (MtftpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
289
290 if (EFI_ERROR (Status)) {
291 goto ON_ERROR;
292 }
293
294 //
295 // Install the Mtftp4ServiceBinding Protocol onto Controller
296 //
297 Status = gBS->InstallMultipleProtocolInterfaces (
298 &Controller,
299 &gEfiMtftp4ServiceBindingProtocolGuid,
300 &MtftpSb->ServiceBinding,
301 NULL
302 );
303
304 if (EFI_ERROR (Status)) {
305 goto ON_ERROR;
306 }
307
308 return EFI_SUCCESS;
309
310 ON_ERROR:
311 Mtftp4CleanService (MtftpSb);
312 NetFreePool (MtftpSb);
313
314 return Status;
315 }
316
317
318 /**
319 Stop the MTFTP driver on controller. The controller is a UDP
320 child handle.
321
322 @param This The MTFTP driver binding protocol
323 @param Controller The controller to stop
324 @param NumberOfChildren The number of children
325 @param ChildHandleBuffer The array of the child handle.
326
327 @retval EFI_SUCCESS The driver is stopped on the controller.
328 @retval EFI_DEVICE_ERROR Failed to stop the driver on the controller.
329
330 **/
331 EFI_STATUS
332 Mtftp4DriverBindingStop (
333 IN EFI_DRIVER_BINDING_PROTOCOL *This,
334 IN EFI_HANDLE Controller,
335 IN UINTN NumberOfChildren,
336 IN EFI_HANDLE *ChildHandleBuffer
337 )
338 {
339 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
340 MTFTP4_SERVICE *MtftpSb;
341 MTFTP4_PROTOCOL *Instance;
342 EFI_HANDLE NicHandle;
343 EFI_STATUS Status;
344 EFI_TPL OldTpl;
345
346 //
347 // MTFTP driver opens UDP child, So, Controller is a UDP
348 // child handle. Locate the Nic handle first. Then get the
349 // MTFTP private data back.
350 //
351 NicHandle = NetLibGetNicHandle (Controller, &gEfiUdp4ProtocolGuid);
352
353 if (NicHandle == NULL) {
354 return EFI_SUCCESS;
355 }
356
357 Status = gBS->OpenProtocol (
358 NicHandle,
359 &gEfiMtftp4ServiceBindingProtocolGuid,
360 (VOID **) &ServiceBinding,
361 This->DriverBindingHandle,
362 NicHandle,
363 EFI_OPEN_PROTOCOL_GET_PROTOCOL
364 );
365
366 if (EFI_ERROR (Status)) {
367 return EFI_DEVICE_ERROR;
368 }
369
370 MtftpSb = MTFTP4_SERVICE_FROM_THIS (ServiceBinding);
371
372 if (MtftpSb->InDestory) {
373 return EFI_SUCCESS;
374 }
375
376 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
377 MtftpSb->InDestory = TRUE;
378
379 while (!NetListIsEmpty (&MtftpSb->Children)) {
380 Instance = NET_LIST_HEAD (&MtftpSb->Children, MTFTP4_PROTOCOL, Link);
381 Mtftp4ServiceBindingDestroyChild (ServiceBinding, Instance->Handle);
382 }
383
384 if (MtftpSb->ChildrenNum != 0) {
385 Status = EFI_DEVICE_ERROR;
386 goto ON_ERROR;
387 }
388
389 Status = gBS->UninstallProtocolInterface (
390 NicHandle,
391 &gEfiMtftp4ServiceBindingProtocolGuid,
392 ServiceBinding
393 );
394
395 if (EFI_ERROR (Status)) {
396 goto ON_ERROR;
397 }
398
399 Mtftp4CleanService (MtftpSb);
400 NetFreePool (MtftpSb);
401
402 NET_RESTORE_TPL (OldTpl);
403 return EFI_SUCCESS;
404
405 ON_ERROR:
406 MtftpSb->InDestory = FALSE;
407
408 NET_RESTORE_TPL (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 @return None
420
421 **/
422 VOID
423 Mtftp4InitProtocol (
424 IN MTFTP4_SERVICE *MtftpSb,
425 IN MTFTP4_PROTOCOL *Instance
426 )
427 {
428 NetZeroMem (Instance, sizeof (MTFTP4_PROTOCOL));
429
430 Instance->Signature = MTFTP4_PROTOCOL_SIGNATURE;
431 NetListInit (&Instance->Link);
432 CopyMem (&Instance->Mtftp4, &gMtftp4ProtocolTemplate, sizeof (EFI_MTFTP4_PROTOCOL));
433 Instance->State = MTFTP4_STATE_UNCONFIGED;
434 Instance->Indestory = FALSE;
435 Instance->Service = MtftpSb;
436
437 NetListInit (&Instance->Blocks);
438 }
439
440
441 /**
442 Create a MTFTP child for the service binding instance, then
443 install the MTFTP protocol to the ChildHandle.
444
445 @param This The MTFTP service binding instance.
446 @param ChildHandle The Child handle to install the MTFTP protocol.
447
448 @retval EFI_INVALID_PARAMETER The parameter is invalid.
449 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the new child.
450 @retval EFI_SUCCESS The child is successfully create.
451
452 **/
453 EFI_STATUS
454 Mtftp4ServiceBindingCreateChild (
455 IN EFI_SERVICE_BINDING_PROTOCOL *This,
456 IN OUT EFI_HANDLE *ChildHandle
457 )
458 {
459 MTFTP4_SERVICE *MtftpSb;
460 MTFTP4_PROTOCOL *Instance;
461 EFI_STATUS Status;
462 EFI_TPL OldTpl;
463 VOID *Udp4;
464
465 if ((This == NULL) || (ChildHandle == NULL)) {
466 return EFI_INVALID_PARAMETER;
467 }
468
469 Instance = NetAllocatePool (sizeof (*Instance));
470
471 if (Instance == NULL) {
472 return EFI_OUT_OF_RESOURCES;
473 }
474
475 MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
476
477 Mtftp4InitProtocol (MtftpSb, Instance);
478
479 Instance->UnicastPort = UdpIoCreatePort (
480 MtftpSb->Controller,
481 MtftpSb->Image,
482 Mtftp4ConfigNullUdp,
483 Instance
484 );
485
486 if (Instance->UnicastPort == NULL) {
487 NetFreePool (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 = NET_RAISE_TPL (NET_TPL_LOCK);
533
534 NetListInsertTail (&MtftpSb->Children, &Instance->Link);
535 MtftpSb->ChildrenNum++;
536
537 NET_RESTORE_TPL (OldTpl);
538
539 ON_ERROR:
540
541 if (EFI_ERROR (Status)) {
542 UdpIoFreePort (Instance->UnicastPort);
543 NetFreePool (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 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 = NET_RAISE_TPL (NET_TPL_LOCK);
632
633 Mtftp4CleanOperation (Instance, EFI_DEVICE_ERROR);
634 UdpIoFreePort (Instance->UnicastPort);
635
636 NetListRemoveEntry (&Instance->Link);
637 MtftpSb->ChildrenNum--;
638
639 NET_RESTORE_TPL (OldTpl);
640
641 NetFreePool (Instance);
642 return EFI_SUCCESS;
643 }