]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Driver.c
Sync the latest version from R8.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Mtftp4Dxe / Mtftp4Driver.c
CommitLineData
772db4bb 1/** @file\r
2\r
3Copyright (c) 2006 - 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 Mtftp4Driver.c\r
15\r
16Abstract:\r
17\r
18\r
19**/\r
20\r
21#include "Mtftp4Impl.h"\r
22\r
23EFI_DRIVER_BINDING_PROTOCOL gMtftp4DriverBinding = {\r
24 Mtftp4DriverBindingSupported,\r
25 Mtftp4DriverBindingStart,\r
26 Mtftp4DriverBindingStop,\r
27 0xa,\r
28 NULL,\r
29 NULL\r
30};\r
31\r
32EFI_SERVICE_BINDING_PROTOCOL gMtftp4ServiceBindingTemplete = {\r
33 Mtftp4ServiceBindingCreateChild,\r
34 Mtftp4ServiceBindingDestroyChild\r
35};\r
36\r
772db4bb 37EFI_STATUS\r
38EFIAPI\r
39Mtftp4DriverEntryPoint (\r
40 IN EFI_HANDLE ImageHandle,\r
41 IN EFI_SYSTEM_TABLE *SystemTable\r
42 )\r
43/*++\r
44\r
45Routine Description:\r
46\r
47 The driver entry point which installs multiple protocols to the ImageHandle.\r
48\r
49Arguments:\r
50\r
51 ImageHandle - The MTFTP's image handle\r
52 SystemTable - The system table\r
53\r
54Returns:\r
55\r
56 EFI_SUCCESS - The handles are successfully installed on the image. Otherwise\r
57 some EFI_ERROR.\r
58\r
59--*/\r
60{\r
83cbd279 61 return EfiLibInstallDriverBindingComponentName2 (\r
772db4bb 62 ImageHandle,\r
63 SystemTable,\r
64 &gMtftp4DriverBinding,\r
65 ImageHandle,\r
66 &gMtftp4ComponentName,\r
83cbd279 67 &gMtftp4ComponentName2\r
772db4bb 68 );\r
69}\r
70\r
71\r
72/**\r
73 Test whether MTFTP driver support this controller.\r
74\r
75 @param This The MTFTP driver binding instance\r
76 @param Controller The controller to test\r
77 @param RemainingDevicePath The remaining device path\r
78\r
79 @retval EFI_SUCCESS The controller has UDP service binding protocol\r
80 installed, MTFTP can support it.\r
81 @retval Others MTFTP can't support the controller.\r
82\r
83**/\r
84EFI_STATUS\r
85Mtftp4DriverBindingSupported (\r
86 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
87 IN EFI_HANDLE Controller,\r
88 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
89 )\r
90{\r
91 EFI_STATUS Status;\r
92\r
93 Status = gBS->OpenProtocol (\r
94 Controller,\r
95 &gEfiUdp4ServiceBindingProtocolGuid,\r
96 NULL,\r
97 This->DriverBindingHandle,\r
98 Controller,\r
99 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
100 );\r
101\r
102 return Status;\r
103}\r
104\r
105\r
106/**\r
107 Config a NULL UDP that is used to keep the connection between UDP\r
108 and MTFTP. Just leave the Udp child unconfigured. When UDP is\r
109 unloaded, MTFTP will be informed with DriverBinding Stop.\r
110\r
111 @param UdpIo The UDP port to configure\r
112 @param Context The opaque parameter to the callback\r
113\r
114 @retval EFI_SUCCESS It always return EFI_SUCCESS directly.\r
115\r
116**/\r
117EFI_STATUS\r
118Mtftp4ConfigNullUdp (\r
119 IN UDP_IO_PORT *UdpIo,\r
120 IN VOID *Context\r
121 )\r
122{\r
123 return EFI_SUCCESS;\r
124}\r
125\r
126\r
127/**\r
128 Create then initialize a MTFTP service binding instance.\r
129\r
130 @param Controller The controller to install the MTFTP service\r
131 binding on\r
132 @param Image The driver binding image of the MTFTP driver\r
133 @param Service The variable to receive the created service\r
134 binding instance.\r
135\r
136 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to create the instance\r
137 @retval EFI_DEVICE_ERROR Failed to create a NULL UDP port to keep\r
138 connection with UDP.\r
139 @retval EFI_SUCCESS The service instance is created for the\r
140 controller.\r
141\r
142**/\r
143EFI_STATUS\r
144Mtftp4CreateService (\r
145 IN EFI_HANDLE Controller,\r
146 IN EFI_HANDLE Image,\r
147 OUT MTFTP4_SERVICE **Service\r
148 )\r
149{\r
150 MTFTP4_SERVICE *MtftpSb;\r
151 EFI_STATUS Status;\r
152\r
153 *Service = NULL;\r
154 MtftpSb = NetAllocatePool (sizeof (MTFTP4_SERVICE));\r
155\r
156 if (MtftpSb == NULL) {\r
157 return EFI_OUT_OF_RESOURCES;\r
158 }\r
159\r
160 MtftpSb->Signature = MTFTP4_SERVICE_SIGNATURE;\r
161 MtftpSb->ServiceBinding = gMtftp4ServiceBindingTemplete;\r
162 MtftpSb->InDestory = FALSE;\r
163 MtftpSb->ChildrenNum = 0;\r
164 NetListInit (&MtftpSb->Children);\r
165\r
166 MtftpSb->Timer = NULL;\r
167 MtftpSb->TimerToGetMap = NULL;\r
168 MtftpSb->Controller = Controller;\r
169 MtftpSb->Image = Image;\r
170 MtftpSb->ConnectUdp = NULL;\r
171\r
172 //\r
173 // Create the timer and a udp to be notified when UDP is uninstalled\r
174 //\r
175 Status = gBS->CreateEvent (\r
176 EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
36ee91ca 177 NET_TPL_TIMER,\r
772db4bb 178 Mtftp4OnTimerTick,\r
179 MtftpSb,\r
180 &MtftpSb->Timer\r
181 );\r
182\r
183 if (EFI_ERROR (Status)) {\r
184 NetFreePool (MtftpSb);\r
185 return Status;\r
186 }\r
187\r
188 //\r
189 // Create the timer used to time out the procedure which is used to\r
190 // get the default IP address.\r
191 //\r
192 Status = gBS->CreateEvent (\r
193 EVT_TIMER,\r
36ee91ca 194 NET_TPL_TIMER,\r
772db4bb 195 NULL,\r
196 NULL,\r
197 &MtftpSb->TimerToGetMap\r
198 );\r
199 if (EFI_ERROR (Status)) {\r
200 gBS->CloseEvent (MtftpSb->Timer);\r
201 NetFreePool (MtftpSb);\r
202 return Status;\r
203 }\r
204\r
205 MtftpSb->ConnectUdp = UdpIoCreatePort (Controller, Image, Mtftp4ConfigNullUdp, NULL);\r
206\r
207 if (MtftpSb->ConnectUdp == NULL) {\r
208 gBS->CloseEvent (MtftpSb->TimerToGetMap);\r
209 gBS->CloseEvent (MtftpSb->Timer);\r
210 NetFreePool (MtftpSb);\r
211 return EFI_DEVICE_ERROR;\r
212 }\r
213\r
214 *Service = MtftpSb;\r
215 return EFI_SUCCESS;\r
216}\r
217\r
218\r
219/**\r
220 Release all the resource used the MTFTP service binding instance.\r
221\r
222 @param MtftpSb The MTFTP service binding instance.\r
223\r
224 @return None\r
225\r
226**/\r
227VOID\r
228Mtftp4CleanService (\r
229 IN MTFTP4_SERVICE *MtftpSb\r
230 )\r
231{\r
232 UdpIoFreePort (MtftpSb->ConnectUdp);\r
233 gBS->CloseEvent (MtftpSb->TimerToGetMap);\r
234 gBS->CloseEvent (MtftpSb->Timer);\r
235}\r
236\r
237\r
238/**\r
239 Start the MTFTP driver on this controller. MTFTP driver will\r
240 install a MTFTP SERVICE BINDING protocol on the supported\r
241 controller, which can be used to create/destroy MTFTP children.\r
242\r
243 @param This The MTFTP driver binding protocol.\r
244 @param Controller The controller to manage.\r
245 @param RemainingDevicePath Remaining device path.\r
246\r
247 @retval EFI_ALREADY_STARTED The MTFTP service binding protocol has been\r
248 started on the controller.\r
249 @retval EFI_SUCCESS The MTFTP service binding is installed on the\r
250 controller.\r
251\r
252**/\r
253EFI_STATUS\r
254Mtftp4DriverBindingStart (\r
255 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
256 IN EFI_HANDLE Controller,\r
257 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
258 )\r
259{\r
260 MTFTP4_SERVICE *MtftpSb;\r
261 EFI_STATUS Status;\r
262\r
263 //\r
264 // Directly return if driver is already running.\r
265 //\r
266 Status = gBS->OpenProtocol (\r
267 Controller,\r
268 &gEfiMtftp4ServiceBindingProtocolGuid,\r
269 NULL,\r
270 This->DriverBindingHandle,\r
271 Controller,\r
272 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
273 );\r
274\r
275 if (Status == EFI_SUCCESS) {\r
276 return EFI_ALREADY_STARTED;\r
277 }\r
278\r
279 Status = Mtftp4CreateService (Controller, This->DriverBindingHandle, &MtftpSb);\r
280\r
281 if (EFI_ERROR (Status)) {\r
282 return Status;\r
283 }\r
284\r
285 Status = gBS->SetTimer (MtftpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);\r
286\r
287 if (EFI_ERROR (Status)) {\r
288 goto ON_ERROR;\r
289 }\r
290\r
291 //\r
292 // Install the Mtftp4ServiceBinding Protocol onto Controller\r
293 //\r
294 Status = gBS->InstallMultipleProtocolInterfaces (\r
295 &Controller,\r
296 &gEfiMtftp4ServiceBindingProtocolGuid,\r
297 &MtftpSb->ServiceBinding,\r
298 NULL\r
299 );\r
300\r
301 if (EFI_ERROR (Status)) {\r
302 goto ON_ERROR;\r
303 }\r
304\r
305 return EFI_SUCCESS;\r
306\r
307ON_ERROR:\r
308 Mtftp4CleanService (MtftpSb);\r
309 NetFreePool (MtftpSb);\r
310\r
311 return Status;\r
312}\r
313\r
314\r
315/**\r
316 Stop the MTFTP driver on controller. The controller is a UDP\r
317 child handle.\r
318\r
319 @param This The MTFTP driver binding protocol\r
320 @param Controller The controller to stop\r
321 @param NumberOfChildren The number of children\r
322 @param ChildHandleBuffer The array of the child handle.\r
323\r
324 @retval EFI_SUCCESS The driver is stopped on the controller.\r
325 @retval EFI_DEVICE_ERROR Failed to stop the driver on the controller.\r
326\r
327**/\r
328EFI_STATUS\r
329Mtftp4DriverBindingStop (\r
330 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
331 IN EFI_HANDLE Controller,\r
332 IN UINTN NumberOfChildren,\r
333 IN EFI_HANDLE *ChildHandleBuffer\r
334 )\r
335{\r
336 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;\r
337 MTFTP4_SERVICE *MtftpSb;\r
338 MTFTP4_PROTOCOL *Instance;\r
339 EFI_HANDLE NicHandle;\r
340 EFI_STATUS Status;\r
341 EFI_TPL OldTpl;\r
342\r
343 //\r
344 // MTFTP driver opens UDP child, So, Controller is a UDP\r
345 // child handle. Locate the Nic handle first. Then get the\r
346 // MTFTP private data back.\r
347 //\r
348 NicHandle = NetLibGetNicHandle (Controller, &gEfiUdp4ProtocolGuid);\r
349\r
350 if (NicHandle == NULL) {\r
c4a62a12 351 return EFI_DEVICE_ERROR;\r
772db4bb 352 }\r
353\r
354 Status = gBS->OpenProtocol (\r
355 NicHandle,\r
356 &gEfiMtftp4ServiceBindingProtocolGuid,\r
357 (VOID **) &ServiceBinding,\r
358 This->DriverBindingHandle,\r
359 NicHandle,\r
360 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
361 );\r
362\r
363 if (EFI_ERROR (Status)) {\r
364 return EFI_DEVICE_ERROR;\r
365 }\r
366\r
367 MtftpSb = MTFTP4_SERVICE_FROM_THIS (ServiceBinding);\r
368\r
369 if (MtftpSb->InDestory) {\r
370 return EFI_SUCCESS;\r
371 }\r
372\r
c4a62a12 373 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
772db4bb 374\r
c4a62a12 375 if (NumberOfChildren == 0) {\r
772db4bb 376\r
c4a62a12 377 MtftpSb->InDestory = TRUE;\r
772db4bb 378\r
c4a62a12 379 gBS->UninstallProtocolInterface (\r
380 NicHandle,\r
381 &gEfiMtftp4ServiceBindingProtocolGuid,\r
382 ServiceBinding\r
383 );\r
772db4bb 384\r
c4a62a12 385 Mtftp4CleanService (MtftpSb);\r
772db4bb 386\r
c4a62a12 387 NetFreePool (MtftpSb);\r
388 } else {\r
772db4bb 389\r
c4a62a12 390 while (!NetListIsEmpty (&MtftpSb->Children)) {\r
391 Instance = NET_LIST_HEAD (&MtftpSb->Children, MTFTP4_PROTOCOL, Link);\r
392 Mtftp4ServiceBindingDestroyChild (ServiceBinding, Instance->Handle);\r
393 }\r
772db4bb 394\r
c4a62a12 395 if (MtftpSb->ChildrenNum != 0) {\r
396 Status = EFI_DEVICE_ERROR;\r
397 }\r
398 }\r
772db4bb 399\r
400 NET_RESTORE_TPL (OldTpl);\r
401 return Status;\r
402}\r
403\r
404\r
405/**\r
406 Initialize a MTFTP protocol instance which is the child of MtftpSb.\r
407\r
408 @param MtftpSb The MTFTP service binding protocol.\r
409 @param Instance The MTFTP instance to initialize.\r
410\r
411 @return None\r
412\r
413**/\r
414VOID\r
415Mtftp4InitProtocol (\r
416 IN MTFTP4_SERVICE *MtftpSb,\r
417 IN MTFTP4_PROTOCOL *Instance\r
418 )\r
419{\r
420 NetZeroMem (Instance, sizeof (MTFTP4_PROTOCOL));\r
421\r
422 Instance->Signature = MTFTP4_PROTOCOL_SIGNATURE;\r
423 NetListInit (&Instance->Link);\r
687a2e5f 424 CopyMem (&Instance->Mtftp4, &gMtftp4ProtocolTemplate, sizeof (Instance->Mtftp4));\r
772db4bb 425 Instance->State = MTFTP4_STATE_UNCONFIGED;\r
426 Instance->Indestory = FALSE;\r
427 Instance->Service = MtftpSb;\r
428\r
429 NetListInit (&Instance->Blocks);\r
430}\r
431\r
432\r
433/**\r
434 Create a MTFTP child for the service binding instance, then\r
435 install the MTFTP protocol to the ChildHandle.\r
436\r
437 @param This The MTFTP service binding instance.\r
438 @param ChildHandle The Child handle to install the MTFTP protocol.\r
439\r
440 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
441 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the new child.\r
442 @retval EFI_SUCCESS The child is successfully create.\r
443\r
444**/\r
445EFI_STATUS\r
446Mtftp4ServiceBindingCreateChild (\r
447 IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
448 IN OUT EFI_HANDLE *ChildHandle\r
449 )\r
450{\r
451 MTFTP4_SERVICE *MtftpSb;\r
452 MTFTP4_PROTOCOL *Instance;\r
453 EFI_STATUS Status;\r
454 EFI_TPL OldTpl;\r
455 VOID *Udp4;\r
456\r
457 if ((This == NULL) || (ChildHandle == NULL)) {\r
458 return EFI_INVALID_PARAMETER;\r
459 }\r
460\r
461 Instance = NetAllocatePool (sizeof (*Instance));\r
462\r
463 if (Instance == NULL) {\r
464 return EFI_OUT_OF_RESOURCES;\r
465 }\r
466\r
467 MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);\r
468\r
469 Mtftp4InitProtocol (MtftpSb, Instance);\r
470\r
471 Instance->UnicastPort = UdpIoCreatePort (\r
472 MtftpSb->Controller,\r
473 MtftpSb->Image,\r
474 Mtftp4ConfigNullUdp,\r
475 Instance\r
476 );\r
477\r
478 if (Instance->UnicastPort == NULL) {\r
479 NetFreePool (Instance);\r
480 return EFI_OUT_OF_RESOURCES;\r
481 }\r
482\r
483 //\r
484 // Install the MTFTP protocol onto ChildHandle\r
485 //\r
486 Status = gBS->InstallMultipleProtocolInterfaces (\r
487 ChildHandle,\r
488 &gEfiMtftp4ProtocolGuid,\r
489 &Instance->Mtftp4,\r
490 NULL\r
491 );\r
492\r
493 if (EFI_ERROR (Status)) {\r
494 goto ON_ERROR;\r
495 }\r
496\r
497 Instance->Handle = *ChildHandle;\r
498\r
499 //\r
500 // Open the Udp4 protocol BY_CHILD.\r
501 //\r
502 Status = gBS->OpenProtocol (\r
503 MtftpSb->ConnectUdp->UdpHandle,\r
504 &gEfiUdp4ProtocolGuid,\r
505 (VOID **) &Udp4,\r
506 gMtftp4DriverBinding.DriverBindingHandle,\r
507 Instance->Handle,\r
508 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
509 );\r
510 if (EFI_ERROR (Status)) {\r
511 gBS->UninstallMultipleProtocolInterfaces (\r
512 Instance->Handle,\r
513 &gEfiMtftp4ProtocolGuid,\r
514 &Instance->Mtftp4,\r
515 NULL\r
516 );\r
517\r
518 goto ON_ERROR;\r
519 }\r
520\r
521 //\r
522 // Add it to the parent's child list.\r
523 //\r
524 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
525\r
526 NetListInsertTail (&MtftpSb->Children, &Instance->Link);\r
527 MtftpSb->ChildrenNum++;\r
528\r
529 NET_RESTORE_TPL (OldTpl);\r
530\r
531ON_ERROR:\r
532\r
533 if (EFI_ERROR (Status)) {\r
534 UdpIoFreePort (Instance->UnicastPort);\r
535 NetFreePool (Instance);\r
536 }\r
537\r
538 return Status;\r
539}\r
540\r
541\r
542/**\r
543 Destory one of the service binding's child.\r
544\r
545 @param This The service binding instance\r
546 @param ChildHandle The child handle to destory\r
547\r
548 @retval EFI_INVALID_PARAMETER The parameter is invaid.\r
549 @retval EFI_UNSUPPORTED The child may have already been destoried.\r
550 @retval EFI_SUCCESS The child is destoried and removed from the\r
551 parent's child list.\r
552\r
553**/\r
554EFI_STATUS\r
555Mtftp4ServiceBindingDestroyChild (\r
556 IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
557 IN EFI_HANDLE ChildHandle\r
558 )\r
559{\r
560 MTFTP4_SERVICE *MtftpSb;\r
561 MTFTP4_PROTOCOL *Instance;\r
562 EFI_MTFTP4_PROTOCOL *Mtftp4;\r
563 EFI_STATUS Status;\r
564 EFI_TPL OldTpl;\r
565\r
566 if ((This == NULL) || (ChildHandle == NULL)) {\r
567 return EFI_INVALID_PARAMETER;\r
568 }\r
569\r
570 //\r
571 // Retrieve the private context data structures\r
572 //\r
573 Status = gBS->OpenProtocol (\r
574 ChildHandle,\r
575 &gEfiMtftp4ProtocolGuid,\r
576 (VOID **) &Mtftp4,\r
577 gMtftp4DriverBinding.DriverBindingHandle,\r
578 ChildHandle,\r
579 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
580 );\r
581\r
582 if (EFI_ERROR (Status)) {\r
583 return EFI_UNSUPPORTED;\r
584 }\r
585\r
586 Instance = MTFTP4_PROTOCOL_FROM_THIS (Mtftp4);\r
587 MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);\r
588\r
589 if (Instance->Service != MtftpSb) {\r
590 return EFI_INVALID_PARAMETER;\r
591 }\r
592\r
593 if (Instance->Indestory) {\r
594 return EFI_SUCCESS;\r
595 }\r
596\r
597 Instance->Indestory = TRUE;\r
598\r
599 //\r
600 // Close the Udp4 protocol.\r
601 //\r
602 gBS->CloseProtocol (\r
603 MtftpSb->ConnectUdp->UdpHandle,\r
604 &gEfiUdp4ProtocolGuid,\r
605 gMtftp4DriverBinding.DriverBindingHandle,\r
606 ChildHandle\r
607 );\r
608\r
609 //\r
610 // Uninstall the MTFTP4 protocol first to enable a top down destruction.\r
611 //\r
612 Status = gBS->UninstallProtocolInterface (\r
613 ChildHandle,\r
614 &gEfiMtftp4ProtocolGuid,\r
615 Mtftp4\r
616 );\r
617\r
618 if (EFI_ERROR (Status)) {\r
619 Instance->Indestory = FALSE;\r
620 return Status;\r
621 }\r
622\r
623 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
624\r
625 Mtftp4CleanOperation (Instance, EFI_DEVICE_ERROR);\r
626 UdpIoFreePort (Instance->UnicastPort);\r
627\r
628 NetListRemoveEntry (&Instance->Link);\r
629 MtftpSb->ChildrenNum--;\r
630\r
631 NET_RESTORE_TPL (OldTpl);\r
632\r
633 NetFreePool (Instance);\r
634 return EFI_SUCCESS;\r
635}\r