]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Driver.c
118624951351b6f4e9890ecf8f5a9148158b9a11
[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 EFI_STATUS
38 EFIAPI
39 Mtftp4DriverEntryPoint (
40 IN EFI_HANDLE ImageHandle,
41 IN EFI_SYSTEM_TABLE *SystemTable
42 )
43 /*++
44
45 Routine Description:
46
47 The driver entry point which installs multiple protocols to the ImageHandle.
48
49 Arguments:
50
51 ImageHandle - The MTFTP's image handle
52 SystemTable - The system table
53
54 Returns:
55
56 EFI_SUCCESS - The handles are successfully installed on the image. Otherwise
57 some EFI_ERROR.
58
59 --*/
60 {
61 return EfiLibInstallDriverBindingComponentName2 (
62 ImageHandle,
63 SystemTable,
64 &gMtftp4DriverBinding,
65 ImageHandle,
66 &gMtftp4ComponentName,
67 &gMtftp4ComponentName2
68 );
69 }
70
71
72 /**
73 Test whether MTFTP driver support this controller.
74
75 @param This The MTFTP driver binding instance
76 @param Controller The controller to test
77 @param RemainingDevicePath The remaining device path
78
79 @retval EFI_SUCCESS The controller has UDP service binding protocol
80 installed, MTFTP can support it.
81 @retval Others MTFTP can't support the controller.
82
83 **/
84 EFI_STATUS
85 Mtftp4DriverBindingSupported (
86 IN EFI_DRIVER_BINDING_PROTOCOL *This,
87 IN EFI_HANDLE Controller,
88 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
89 )
90 {
91 EFI_STATUS Status;
92
93 Status = gBS->OpenProtocol (
94 Controller,
95 &gEfiUdp4ServiceBindingProtocolGuid,
96 NULL,
97 This->DriverBindingHandle,
98 Controller,
99 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
100 );
101
102 return Status;
103 }
104
105
106 /**
107 Config a NULL UDP that is used to keep the connection between UDP
108 and MTFTP. Just leave the Udp child unconfigured. When UDP is
109 unloaded, MTFTP will be informed with DriverBinding Stop.
110
111 @param UdpIo The UDP port to configure
112 @param Context The opaque parameter to the callback
113
114 @retval EFI_SUCCESS It always return EFI_SUCCESS directly.
115
116 **/
117 EFI_STATUS
118 Mtftp4ConfigNullUdp (
119 IN UDP_IO_PORT *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 = NetAllocatePool (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 NetListInit (&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 NET_TPL_TIMER,
178 Mtftp4OnTimerTick,
179 MtftpSb,
180 &MtftpSb->Timer
181 );
182
183 if (EFI_ERROR (Status)) {
184 NetFreePool (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 NET_TPL_TIMER,
195 NULL,
196 NULL,
197 &MtftpSb->TimerToGetMap
198 );
199 if (EFI_ERROR (Status)) {
200 gBS->CloseEvent (MtftpSb->Timer);
201 NetFreePool (MtftpSb);
202 return Status;
203 }
204
205 MtftpSb->ConnectUdp = UdpIoCreatePort (Controller, Image, Mtftp4ConfigNullUdp, NULL);
206
207 if (MtftpSb->ConnectUdp == NULL) {
208 gBS->CloseEvent (MtftpSb->TimerToGetMap);
209 gBS->CloseEvent (MtftpSb->Timer);
210 NetFreePool (MtftpSb);
211 return EFI_DEVICE_ERROR;
212 }
213
214 *Service = MtftpSb;
215 return EFI_SUCCESS;
216 }
217
218
219 /**
220 Release all the resource used the MTFTP service binding instance.
221
222 @param MtftpSb The MTFTP service binding instance.
223
224 @return None
225
226 **/
227 VOID
228 Mtftp4CleanService (
229 IN MTFTP4_SERVICE *MtftpSb
230 )
231 {
232 UdpIoFreePort (MtftpSb->ConnectUdp);
233 gBS->CloseEvent (MtftpSb->TimerToGetMap);
234 gBS->CloseEvent (MtftpSb->Timer);
235 }
236
237
238 /**
239 Start the MTFTP driver on this controller. MTFTP driver will
240 install a MTFTP SERVICE BINDING protocol on the supported
241 controller, which can be used to create/destroy MTFTP children.
242
243 @param This The MTFTP driver binding protocol.
244 @param Controller The controller to manage.
245 @param RemainingDevicePath Remaining device path.
246
247 @retval EFI_ALREADY_STARTED The MTFTP service binding protocol has been
248 started on the controller.
249 @retval EFI_SUCCESS The MTFTP service binding is installed on the
250 controller.
251
252 **/
253 EFI_STATUS
254 Mtftp4DriverBindingStart (
255 IN EFI_DRIVER_BINDING_PROTOCOL *This,
256 IN EFI_HANDLE Controller,
257 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
258 )
259 {
260 MTFTP4_SERVICE *MtftpSb;
261 EFI_STATUS Status;
262
263 //
264 // Directly return if driver is already running.
265 //
266 Status = gBS->OpenProtocol (
267 Controller,
268 &gEfiMtftp4ServiceBindingProtocolGuid,
269 NULL,
270 This->DriverBindingHandle,
271 Controller,
272 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
273 );
274
275 if (Status == EFI_SUCCESS) {
276 return EFI_ALREADY_STARTED;
277 }
278
279 Status = Mtftp4CreateService (Controller, This->DriverBindingHandle, &MtftpSb);
280
281 if (EFI_ERROR (Status)) {
282 return Status;
283 }
284
285 Status = gBS->SetTimer (MtftpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
286
287 if (EFI_ERROR (Status)) {
288 goto ON_ERROR;
289 }
290
291 //
292 // Install the Mtftp4ServiceBinding Protocol onto Controller
293 //
294 Status = gBS->InstallMultipleProtocolInterfaces (
295 &Controller,
296 &gEfiMtftp4ServiceBindingProtocolGuid,
297 &MtftpSb->ServiceBinding,
298 NULL
299 );
300
301 if (EFI_ERROR (Status)) {
302 goto ON_ERROR;
303 }
304
305 return EFI_SUCCESS;
306
307 ON_ERROR:
308 Mtftp4CleanService (MtftpSb);
309 NetFreePool (MtftpSb);
310
311 return Status;
312 }
313
314
315 /**
316 Stop the MTFTP driver on controller. The controller is a UDP
317 child handle.
318
319 @param This The MTFTP driver binding protocol
320 @param Controller The controller to stop
321 @param NumberOfChildren The number of children
322 @param ChildHandleBuffer The array of the child handle.
323
324 @retval EFI_SUCCESS The driver is stopped on the controller.
325 @retval EFI_DEVICE_ERROR Failed to stop the driver on the controller.
326
327 **/
328 EFI_STATUS
329 Mtftp4DriverBindingStop (
330 IN EFI_DRIVER_BINDING_PROTOCOL *This,
331 IN EFI_HANDLE Controller,
332 IN UINTN NumberOfChildren,
333 IN EFI_HANDLE *ChildHandleBuffer
334 )
335 {
336 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
337 MTFTP4_SERVICE *MtftpSb;
338 MTFTP4_PROTOCOL *Instance;
339 EFI_HANDLE NicHandle;
340 EFI_STATUS Status;
341 EFI_TPL OldTpl;
342
343 //
344 // MTFTP driver opens UDP child, So, Controller is a UDP
345 // child handle. Locate the Nic handle first. Then get the
346 // MTFTP private data back.
347 //
348 NicHandle = NetLibGetNicHandle (Controller, &gEfiUdp4ProtocolGuid);
349
350 if (NicHandle == NULL) {
351 return EFI_SUCCESS;
352 }
353
354 Status = gBS->OpenProtocol (
355 NicHandle,
356 &gEfiMtftp4ServiceBindingProtocolGuid,
357 (VOID **) &ServiceBinding,
358 This->DriverBindingHandle,
359 NicHandle,
360 EFI_OPEN_PROTOCOL_GET_PROTOCOL
361 );
362
363 if (EFI_ERROR (Status)) {
364 return EFI_DEVICE_ERROR;
365 }
366
367 MtftpSb = MTFTP4_SERVICE_FROM_THIS (ServiceBinding);
368
369 if (MtftpSb->InDestory) {
370 return EFI_SUCCESS;
371 }
372
373 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
374 MtftpSb->InDestory = TRUE;
375
376 while (!NetListIsEmpty (&MtftpSb->Children)) {
377 Instance = NET_LIST_HEAD (&MtftpSb->Children, MTFTP4_PROTOCOL, Link);
378 Mtftp4ServiceBindingDestroyChild (ServiceBinding, Instance->Handle);
379 }
380
381 if (MtftpSb->ChildrenNum != 0) {
382 Status = EFI_DEVICE_ERROR;
383 goto ON_ERROR;
384 }
385
386 Status = gBS->UninstallProtocolInterface (
387 NicHandle,
388 &gEfiMtftp4ServiceBindingProtocolGuid,
389 ServiceBinding
390 );
391
392 if (EFI_ERROR (Status)) {
393 goto ON_ERROR;
394 }
395
396 Mtftp4CleanService (MtftpSb);
397 NetFreePool (MtftpSb);
398
399 NET_RESTORE_TPL (OldTpl);
400 return EFI_SUCCESS;
401
402 ON_ERROR:
403 MtftpSb->InDestory = FALSE;
404
405 NET_RESTORE_TPL (OldTpl);
406 return Status;
407 }
408
409
410 /**
411 Initialize a MTFTP protocol instance which is the child of MtftpSb.
412
413 @param MtftpSb The MTFTP service binding protocol.
414 @param Instance The MTFTP instance to initialize.
415
416 @return None
417
418 **/
419 VOID
420 Mtftp4InitProtocol (
421 IN MTFTP4_SERVICE *MtftpSb,
422 IN MTFTP4_PROTOCOL *Instance
423 )
424 {
425 NetZeroMem (Instance, sizeof (MTFTP4_PROTOCOL));
426
427 Instance->Signature = MTFTP4_PROTOCOL_SIGNATURE;
428 NetListInit (&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 NetListInit (&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 Mtftp4ServiceBindingCreateChild (
452 IN EFI_SERVICE_BINDING_PROTOCOL *This,
453 IN OUT 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 = NetAllocatePool (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 = UdpIoCreatePort (
477 MtftpSb->Controller,
478 MtftpSb->Image,
479 Mtftp4ConfigNullUdp,
480 Instance
481 );
482
483 if (Instance->UnicastPort == NULL) {
484 NetFreePool (Instance);
485 return EFI_OUT_OF_RESOURCES;
486 }
487
488 //
489 // Install the MTFTP protocol onto ChildHandle
490 //
491 Status = gBS->InstallMultipleProtocolInterfaces (
492 ChildHandle,
493 &gEfiMtftp4ProtocolGuid,
494 &Instance->Mtftp4,
495 NULL
496 );
497
498 if (EFI_ERROR (Status)) {
499 goto ON_ERROR;
500 }
501
502 Instance->Handle = *ChildHandle;
503
504 //
505 // Open the Udp4 protocol BY_CHILD.
506 //
507 Status = gBS->OpenProtocol (
508 MtftpSb->ConnectUdp->UdpHandle,
509 &gEfiUdp4ProtocolGuid,
510 (VOID **) &Udp4,
511 gMtftp4DriverBinding.DriverBindingHandle,
512 Instance->Handle,
513 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
514 );
515 if (EFI_ERROR (Status)) {
516 gBS->UninstallMultipleProtocolInterfaces (
517 Instance->Handle,
518 &gEfiMtftp4ProtocolGuid,
519 &Instance->Mtftp4,
520 NULL
521 );
522
523 goto ON_ERROR;
524 }
525
526 //
527 // Add it to the parent's child list.
528 //
529 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
530
531 NetListInsertTail (&MtftpSb->Children, &Instance->Link);
532 MtftpSb->ChildrenNum++;
533
534 NET_RESTORE_TPL (OldTpl);
535
536 ON_ERROR:
537
538 if (EFI_ERROR (Status)) {
539 UdpIoFreePort (Instance->UnicastPort);
540 NetFreePool (Instance);
541 }
542
543 return Status;
544 }
545
546
547 /**
548 Destory one of the service binding's child.
549
550 @param This The service binding instance
551 @param ChildHandle The child handle to destory
552
553 @retval EFI_INVALID_PARAMETER The parameter is invaid.
554 @retval EFI_UNSUPPORTED The child may have already been destoried.
555 @retval EFI_SUCCESS The child is destoried and removed from the
556 parent's child list.
557
558 **/
559 EFI_STATUS
560 Mtftp4ServiceBindingDestroyChild (
561 IN EFI_SERVICE_BINDING_PROTOCOL *This,
562 IN EFI_HANDLE ChildHandle
563 )
564 {
565 MTFTP4_SERVICE *MtftpSb;
566 MTFTP4_PROTOCOL *Instance;
567 EFI_MTFTP4_PROTOCOL *Mtftp4;
568 EFI_STATUS Status;
569 EFI_TPL OldTpl;
570
571 if ((This == NULL) || (ChildHandle == NULL)) {
572 return EFI_INVALID_PARAMETER;
573 }
574
575 //
576 // Retrieve the private context data structures
577 //
578 Status = gBS->OpenProtocol (
579 ChildHandle,
580 &gEfiMtftp4ProtocolGuid,
581 (VOID **) &Mtftp4,
582 gMtftp4DriverBinding.DriverBindingHandle,
583 ChildHandle,
584 EFI_OPEN_PROTOCOL_GET_PROTOCOL
585 );
586
587 if (EFI_ERROR (Status)) {
588 return EFI_UNSUPPORTED;
589 }
590
591 Instance = MTFTP4_PROTOCOL_FROM_THIS (Mtftp4);
592 MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
593
594 if (Instance->Service != MtftpSb) {
595 return EFI_INVALID_PARAMETER;
596 }
597
598 if (Instance->Indestory) {
599 return EFI_SUCCESS;
600 }
601
602 Instance->Indestory = TRUE;
603
604 //
605 // Close the Udp4 protocol.
606 //
607 gBS->CloseProtocol (
608 MtftpSb->ConnectUdp->UdpHandle,
609 &gEfiUdp4ProtocolGuid,
610 gMtftp4DriverBinding.DriverBindingHandle,
611 ChildHandle
612 );
613
614 //
615 // Uninstall the MTFTP4 protocol first to enable a top down destruction.
616 //
617 Status = gBS->UninstallProtocolInterface (
618 ChildHandle,
619 &gEfiMtftp4ProtocolGuid,
620 Mtftp4
621 );
622
623 if (EFI_ERROR (Status)) {
624 Instance->Indestory = FALSE;
625 return Status;
626 }
627
628 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
629
630 Mtftp4CleanOperation (Instance, EFI_DEVICE_ERROR);
631 UdpIoFreePort (Instance->UnicastPort);
632
633 NetListRemoveEntry (&Instance->Link);
634 MtftpSb->ChildrenNum--;
635
636 NET_RESTORE_TPL (OldTpl);
637
638 NetFreePool (Instance);
639 return EFI_SUCCESS;
640 }