1 /** @file
2 
3 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
4 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 **/
13 
14 
15 #include "Udp4Impl.h"
16 
17 EFI_DRIVER_BINDING_PROTOCOL gUdp4DriverBinding = {
18   Udp4DriverBindingSupported,
19   Udp4DriverBindingStart,
20   Udp4DriverBindingStop,
21   0xa,
22   NULL,
23   NULL
24 };
25 
26 EFI_SERVICE_BINDING_PROTOCOL mUdp4ServiceBinding = {
27   Udp4ServiceBindingCreateChild,
28   Udp4ServiceBindingDestroyChild
29 };
30 
31 /**
32   Callback function which provided by user to remove one node in NetDestroyLinkList process.
33 
34   @param[in]    Entry           The entry to be removed.
35   @param[in]    Context         Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
36 
37   @retval EFI_SUCCESS           The entry has been removed successfully.
38   @retval Others                Fail to remove the entry.
39 
40 **/
41 EFI_STATUS
42 EFIAPI
Udp4DestroyChildEntryInHandleBuffer(IN LIST_ENTRY * Entry,IN VOID * Context)43 Udp4DestroyChildEntryInHandleBuffer (
44   IN LIST_ENTRY         *Entry,
45   IN VOID               *Context
46   )
47 {
48   UDP4_INSTANCE_DATA            *Instance;
49   EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
50   UINTN                         NumberOfChildren;
51   EFI_HANDLE                    *ChildHandleBuffer;
52 
53   if (Entry == NULL || Context == NULL) {
54     return EFI_INVALID_PARAMETER;
55   }
56 
57   Instance = NET_LIST_USER_STRUCT_S (Entry, UDP4_INSTANCE_DATA, Link, UDP4_INSTANCE_DATA_SIGNATURE);
58   ServiceBinding    = ((UDP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
59   NumberOfChildren  = ((UDP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
60   ChildHandleBuffer = ((UDP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
61 
62   if (!NetIsInHandleBuffer (Instance->ChildHandle, NumberOfChildren, ChildHandleBuffer)) {
63     return EFI_SUCCESS;
64   }
65 
66   return ServiceBinding->DestroyChild (ServiceBinding, Instance->ChildHandle);
67 }
68 
69 
70 /**
71   Test to see if this driver supports ControllerHandle. This service
72   is called by the EFI boot service ConnectController(). In
73   order to make drivers as small as possible, there are a few calling
74   restrictions for this service. ConnectController() must
75   follow these calling restrictions. If any other agent wishes to call
76   Supported() it must also follow these calling restrictions.
77 
78   @param[in]  This                Protocol instance pointer.
79   @param[in]  ControllerHandle    Handle of device to test
80   @param[in]  RemainingDevicePath Optional parameter use to pick a specific child
81                                   device to start.
82 
83   @retval EFI_SUCCESS         This driver supports this device
84   @retval EFI_ALREADY_STARTED This driver is already running on this device
85   @retval other               This driver does not support this device
86 
87 **/
88 EFI_STATUS
89 EFIAPI
Udp4DriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)90 Udp4DriverBindingSupported (
91   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
92   IN EFI_HANDLE                   ControllerHandle,
93   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath  OPTIONAL
94   )
95 {
96   EFI_STATUS  Status;
97 
98   //
99   // Test for the Udp4ServiceBinding Protocol
100   //
101   Status = gBS->OpenProtocol (
102                   ControllerHandle,
103                   &gEfiUdp4ServiceBindingProtocolGuid,
104                   NULL,
105                   This->DriverBindingHandle,
106                   ControllerHandle,
107                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
108                   );
109   if (!EFI_ERROR (Status)) {
110     return EFI_ALREADY_STARTED;
111   }
112 
113   //
114   // Test for the Ip4 Protocol
115   //
116   Status = gBS->OpenProtocol (
117                   ControllerHandle,
118                   &gEfiIp4ServiceBindingProtocolGuid,
119                   NULL,
120                   This->DriverBindingHandle,
121                   ControllerHandle,
122                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
123                   );
124 
125   return Status;
126 }
127 
128 
129 /**
130   Start this driver on ControllerHandle. This service is called by the
131   EFI boot service ConnectController(). In order to make
132   drivers as small as possible, there are a few calling restrictions for
133   this service. ConnectController() must follow these
134   calling restrictions. If any other agent wishes to call Start() it
135   must also follow these calling restrictions.
136 
137   @param[in]  This                 Protocol instance pointer.
138   @param[in]  ControllerHandle     Handle of device to bind driver to
139   @param[in]  RemainingDevicePath  Optional parameter use to pick a specific child
140                                    device to start.
141 
142   @retval EFI_SUCCESS          This driver is added to ControllerHandle
143   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
144   @retval other                This driver does not support this device
145 
146 **/
147 EFI_STATUS
148 EFIAPI
Udp4DriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)149 Udp4DriverBindingStart (
150   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
151   IN EFI_HANDLE                   ControllerHandle,
152   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath  OPTIONAL
153   )
154 {
155   EFI_STATUS         Status;
156   UDP4_SERVICE_DATA  *Udp4Service;
157 
158   //
159   // Allocate Private Context Data Structure.
160   //
161   Udp4Service = AllocatePool (sizeof (UDP4_SERVICE_DATA));
162   if (Udp4Service == NULL) {
163     return EFI_OUT_OF_RESOURCES;
164   }
165 
166   Status = Udp4CreateService (Udp4Service, This->DriverBindingHandle, ControllerHandle);
167   if (EFI_ERROR (Status)) {
168     FreePool (Udp4Service);
169     return Status;
170   }
171 
172   //
173   // Install the Udp4ServiceBindingProtocol on the ControllerHandle.
174   //
175   Status = gBS->InstallMultipleProtocolInterfaces (
176                   &ControllerHandle,
177                   &gEfiUdp4ServiceBindingProtocolGuid,
178                   &Udp4Service->ServiceBinding,
179                   NULL
180                   );
181   if (EFI_ERROR (Status)) {
182     Udp4CleanService (Udp4Service);
183     FreePool (Udp4Service);
184   }
185 
186   return Status;
187 }
188 
189 
190 /**
191   Stop this driver on ControllerHandle. This service is called by the
192   EFI boot service DisconnectController(). In order to
193   make drivers as small as possible, there are a few calling
194   restrictions for this service. DisconnectController()
195   must follow these calling restrictions. If any other agent wishes
196   to call Stop() it must also follow these calling restrictions.
197 
198   @param[in]  This              Protocol instance pointer.
199   @param[in]  ControllerHandle  Handle of device to stop driver on
200   @param[in]  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
201                                 children is zero stop the entire bus driver.
202   @param[in]  ChildHandleBuffer List of Child Handles to Stop.
203 
204   @retval EFI_SUCCESS       This driver is removed ControllerHandle
205   @retval other             This driver was not removed from this device
206 
207 **/
208 EFI_STATUS
209 EFIAPI
Udp4DriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)210 Udp4DriverBindingStop (
211   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
212   IN  EFI_HANDLE                   ControllerHandle,
213   IN  UINTN                        NumberOfChildren,
214   IN  EFI_HANDLE                   *ChildHandleBuffer
215   )
216 {
217   EFI_STATUS                                Status;
218   EFI_HANDLE                                NicHandle;
219   EFI_SERVICE_BINDING_PROTOCOL              *ServiceBinding;
220   UDP4_SERVICE_DATA                         *Udp4Service;
221   UDP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT  Context;
222   LIST_ENTRY                                *List;
223 
224   //
225   // Find the NicHandle where UDP4 ServiceBinding Protocol is installed.
226   //
227   NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiIp4ProtocolGuid);
228   if (NicHandle == NULL) {
229     return EFI_SUCCESS;
230   }
231 
232   //
233   // Retrieve the UDP4 ServiceBinding Protocol.
234   //
235   Status = gBS->OpenProtocol (
236                   NicHandle,
237                   &gEfiUdp4ServiceBindingProtocolGuid,
238                   (VOID **) &ServiceBinding,
239                   This->DriverBindingHandle,
240                   NicHandle,
241                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
242                   );
243   if (EFI_ERROR (Status)) {
244     return EFI_DEVICE_ERROR;
245   }
246 
247   Udp4Service = UDP4_SERVICE_DATA_FROM_THIS (ServiceBinding);
248   if (NumberOfChildren != 0) {
249     //
250     // NumberOfChildren is not zero, destroy the children instances in ChildHandleBuffer.
251     //
252     List = &Udp4Service->ChildrenList;
253     Context.ServiceBinding    = ServiceBinding;
254     Context.NumberOfChildren  = NumberOfChildren;
255     Context.ChildHandleBuffer = ChildHandleBuffer;
256     Status = NetDestroyLinkList (
257                List,
258                Udp4DestroyChildEntryInHandleBuffer,
259                &Context,
260                NULL
261                );
262   } else {
263     gBS->UninstallMultipleProtocolInterfaces (
264            NicHandle,
265            &gEfiUdp4ServiceBindingProtocolGuid,
266            &Udp4Service->ServiceBinding,
267            NULL
268            );
269 
270     Udp4CleanService (Udp4Service);
271 
272     if (gUdpControllerNameTable != NULL) {
273       FreeUnicodeStringTable (gUdpControllerNameTable);
274       gUdpControllerNameTable = NULL;
275     }
276     FreePool (Udp4Service);
277   }
278 
279   return Status;
280 }
281 
282 
283 /**
284   Creates a child handle and installs a protocol.
285 
286   The CreateChild() function installs a protocol on ChildHandle.
287   If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
288   If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
289 
290   @param[in] This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
291   @param[in] ChildHandle Pointer to the handle of the child to create. If it is NULL,
292                          then a new handle is created. If it is a pointer to an existing UEFI handle,
293                          then the protocol is added to the existing UEFI handle.
294 
295   @retval EFI_SUCCES            The protocol was added to ChildHandle.
296   @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
297   @retval EFI_OUT_OF_RESOURCES  There are not enough resources availabe to create
298                                 the child
299   @retval other                 The child handle was not created
300 
301 **/
302 EFI_STATUS
303 EFIAPI
Udp4ServiceBindingCreateChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN EFI_HANDLE * ChildHandle)304 Udp4ServiceBindingCreateChild (
305   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
306   IN EFI_HANDLE                    *ChildHandle
307   )
308 {
309   EFI_STATUS          Status;
310   UDP4_SERVICE_DATA   *Udp4Service;
311   UDP4_INSTANCE_DATA  *Instance;
312   EFI_TPL             OldTpl;
313   VOID                *Ip4;
314 
315   if ((This == NULL) || (ChildHandle == NULL)) {
316     return EFI_INVALID_PARAMETER;
317   }
318 
319   Udp4Service = UDP4_SERVICE_DATA_FROM_THIS (This);
320 
321   //
322   // Allocate the instance private data structure.
323   //
324   Instance = AllocateZeroPool (sizeof (UDP4_INSTANCE_DATA));
325   if (Instance == NULL) {
326     return EFI_OUT_OF_RESOURCES;
327   }
328 
329   Udp4InitInstance (Udp4Service, Instance);
330 
331   //
332   // Add an IpInfo for this instance.
333   //
334   Instance->IpInfo = IpIoAddIp (Udp4Service->IpIo);
335   if (Instance->IpInfo == NULL) {
336     Status = EFI_OUT_OF_RESOURCES;
337     goto ON_ERROR;
338   }
339 
340   //
341   // Install the Udp4Protocol for this instance.
342   //
343   Status = gBS->InstallMultipleProtocolInterfaces (
344                   ChildHandle,
345                   &gEfiUdp4ProtocolGuid,
346                   &Instance->Udp4Proto,
347                   NULL
348                   );
349   if (EFI_ERROR (Status)) {
350     goto ON_ERROR;
351   }
352 
353   Instance->ChildHandle = *ChildHandle;
354 
355   //
356   // Open the default Ip4 protocol in the IP_IO BY_CHILD.
357   //
358   Status = gBS->OpenProtocol (
359                   Udp4Service->IpIo->ChildHandle,
360                   &gEfiIp4ProtocolGuid,
361                   (VOID **) &Ip4,
362                   gUdp4DriverBinding.DriverBindingHandle,
363                   Instance->ChildHandle,
364                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
365                   );
366   if (EFI_ERROR (Status)) {
367     goto ON_ERROR;
368   }
369 
370   //
371   // Open this instance's Ip4 protocol in the IpInfo BY_CHILD.
372   //
373   Status = gBS->OpenProtocol (
374                   Instance->IpInfo->ChildHandle,
375                   &gEfiIp4ProtocolGuid,
376                   (VOID **) &Ip4,
377                   gUdp4DriverBinding.DriverBindingHandle,
378                   Instance->ChildHandle,
379                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
380                   );
381   if (EFI_ERROR (Status)) {
382     goto ON_ERROR;
383   }
384 
385   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
386 
387   //
388   // Link this instance into the service context data and increase the ChildrenNumber.
389   //
390   InsertTailList (&Udp4Service->ChildrenList, &Instance->Link);
391   Udp4Service->ChildrenNumber++;
392 
393   gBS->RestoreTPL (OldTpl);
394 
395   return EFI_SUCCESS;
396 
397 ON_ERROR:
398 
399   if (Instance->ChildHandle != NULL) {
400     gBS->UninstallMultipleProtocolInterfaces (
401            Instance->ChildHandle,
402            &gEfiUdp4ProtocolGuid,
403            &Instance->Udp4Proto,
404            NULL
405            );
406   }
407 
408   if (Instance->IpInfo != NULL) {
409     IpIoRemoveIp (Udp4Service->IpIo, Instance->IpInfo);
410   }
411 
412   Udp4CleanInstance (Instance);
413 
414   FreePool (Instance);
415 
416   return Status;
417 }
418 
419 
420 /**
421   Destroys a child handle with a protocol installed on it.
422 
423   The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
424   that was installed by CreateChild() from ChildHandle. If the removed protocol is the
425   last protocol on ChildHandle, then ChildHandle is destroyed.
426 
427   @param[in] This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
428   @param[in] ChildHandle Handle of the child to destroy
429 
430   @retval EFI_SUCCES            The protocol was removed from ChildHandle.
431   @retval EFI_UNSUPPORTED       ChildHandle does not support the protocol that is being removed.
432   @retval EFI_INVALID_PARAMETER Child handle is NULL.
433   @retval EFI_ACCESS_DENIED     The protocol could not be removed from the ChildHandle
434                                 because its services are being used.
435   @retval other                 The child handle was not destroyed
436 
437 **/
438 EFI_STATUS
439 EFIAPI
Udp4ServiceBindingDestroyChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN EFI_HANDLE ChildHandle)440 Udp4ServiceBindingDestroyChild (
441   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
442   IN EFI_HANDLE                    ChildHandle
443   )
444 {
445   EFI_STATUS          Status;
446   UDP4_SERVICE_DATA   *Udp4Service;
447   EFI_UDP4_PROTOCOL   *Udp4Proto;
448   UDP4_INSTANCE_DATA  *Instance;
449   EFI_TPL             OldTpl;
450 
451   if ((This == NULL) || (ChildHandle == NULL)) {
452     return EFI_INVALID_PARAMETER;
453   }
454 
455   Udp4Service = UDP4_SERVICE_DATA_FROM_THIS (This);
456 
457   //
458   // Try to get the Udp4 protocol from the ChildHandle.
459   //
460   Status = gBS->OpenProtocol (
461                   ChildHandle,
462                   &gEfiUdp4ProtocolGuid,
463                   (VOID **) &Udp4Proto,
464                   gUdp4DriverBinding.DriverBindingHandle,
465                   ChildHandle,
466                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
467                   );
468   if (EFI_ERROR (Status)) {
469     return EFI_UNSUPPORTED;
470   }
471 
472   Instance = UDP4_INSTANCE_DATA_FROM_THIS (Udp4Proto);
473 
474   if (Instance->InDestroy) {
475     return EFI_SUCCESS;
476   }
477 
478   //
479   // Use the Destroyed flag to avoid the re-entering of the following code.
480   //
481   Instance->InDestroy = TRUE;
482 
483   //
484   // Close the Ip4 protocol.
485   //
486   gBS->CloseProtocol (
487          Udp4Service->IpIo->ChildHandle,
488          &gEfiIp4ProtocolGuid,
489          gUdp4DriverBinding.DriverBindingHandle,
490          Instance->ChildHandle
491          );
492   //
493   // Close the Ip4 protocol on this instance's IpInfo.
494   //
495   gBS->CloseProtocol (
496          Instance->IpInfo->ChildHandle,
497          &gEfiIp4ProtocolGuid,
498          gUdp4DriverBinding.DriverBindingHandle,
499          Instance->ChildHandle
500          );
501 
502   //
503   // Uninstall the Udp4Protocol previously installed on the ChildHandle.
504   //
505   Status = gBS->UninstallMultipleProtocolInterfaces (
506                   ChildHandle,
507                   &gEfiUdp4ProtocolGuid,
508                   (VOID *) &Instance->Udp4Proto,
509                   NULL
510                   );
511   if (EFI_ERROR (Status)) {
512     Instance->InDestroy = FALSE;
513     return Status;
514   }
515 
516   //
517   // Reset the configuration in case the instance's consumer forgets to do this.
518   //
519   Udp4Proto->Configure (Udp4Proto, NULL);
520 
521   //
522   // Remove the IpInfo this instance consumes.
523   //
524   IpIoRemoveIp (Udp4Service->IpIo, Instance->IpInfo);
525 
526   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
527 
528   //
529   // Remove this instance from the service context data's ChildrenList.
530   //
531   RemoveEntryList (&Instance->Link);
532   Udp4Service->ChildrenNumber--;
533 
534   //
535   // Clean the instance.
536   //
537   Udp4CleanInstance (Instance);
538 
539   gBS->RestoreTPL (OldTpl);
540 
541   FreePool (Instance);
542 
543   return EFI_SUCCESS;
544 }
545 
546 /**
547   This is the declaration of an EFI image entry point. This entry point is
548   the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
549   both device drivers and bus drivers.
550 
551   The entry point for Udp4 driver which installs the driver binding
552   and component name protocol on its ImageHandle.
553 
554   @param[in] ImageHandle           The firmware allocated handle for the UEFI image.
555   @param[in] SystemTable           A pointer to the EFI System Table.
556 
557   @retval EFI_SUCCESS           The operation completed successfully.
558   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
559 
560 **/
561 EFI_STATUS
562 EFIAPI
Udp4DriverEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)563 Udp4DriverEntryPoint (
564   IN EFI_HANDLE        ImageHandle,
565   IN EFI_SYSTEM_TABLE  *SystemTable
566   )
567 {
568   EFI_STATUS  Status;
569 
570   //
571   // Install the Udp4DriverBinding and Udp4ComponentName protocols.
572   //
573   Status = EfiLibInstallDriverBindingComponentName2 (
574              ImageHandle,
575              SystemTable,
576              &gUdp4DriverBinding,
577              ImageHandle,
578              &gUdp4ComponentName,
579              &gUdp4ComponentName2
580              );
581   if (!EFI_ERROR (Status)) {
582     //
583     // Initialize the UDP random port.
584     //
585     mUdp4RandomPort = (UINT16) (((UINT16) NetRandomInitSeed ()) % UDP4_PORT_KNOWN + UDP4_PORT_KNOWN);
586   }
587 
588   return Status;
589 }
590 
591