1/** @file
2
3Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
4This program and the accompanying materials
5are licensed and made available under the terms and conditions of the BSD License
6which accompanies this distribution.  The full text of the license may be found at
7http://opensource.org/licenses/bsd-license.php
8
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12**/
13
14
15#include "Udp4Impl.h"
16
17EFI_DRIVER_BINDING_PROTOCOL gUdp4DriverBinding = {
18  Udp4DriverBindingSupported,
19  Udp4DriverBindingStart,
20  Udp4DriverBindingStop,
21  0xa,
22  NULL,
23  NULL
24};
25
26EFI_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**/
41EFI_STATUS
42EFIAPI
43Udp4DestroyChildEntryInHandleBuffer (
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**/
88EFI_STATUS
89EFIAPI
90Udp4DriverBindingSupported (
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**/
147EFI_STATUS
148EFIAPI
149Udp4DriverBindingStart (
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**/
208EFI_STATUS
209EFIAPI
210Udp4DriverBindingStop (
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 available to create
298                                the child
299  @retval other                 The child handle was not created
300
301**/
302EFI_STATUS
303EFIAPI
304Udp4ServiceBindingCreateChild (
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
397ON_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**/
438EFI_STATUS
439EFIAPI
440Udp4ServiceBindingDestroyChild (
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**/
561EFI_STATUS
562EFIAPI
563Udp4DriverEntryPoint (
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