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