]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/DxeNetLib/DxeNetLib.c
Add VLAN support.
[mirror_edk2.git] / MdeModulePkg / Library / DxeNetLib / DxeNetLib.c
index ffcd70ca844109d3171ef01b10e11d5d2bf4efdd..f58783cdfd3f8046b77b3301fc9f6b97ee8f6339 100644 (file)
@@ -111,6 +111,21 @@ GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mMonthName[] = {
   "Dec"\r
 };\r
 \r
+//\r
+// VLAN device path node template\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED VLAN_DEVICE_PATH mNetVlanDevicePathTemplate = {\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_VLAN_DP,\r
+    {\r
+      (UINT8) (sizeof (VLAN_DEVICE_PATH)),\r
+      (UINT8) ((sizeof (VLAN_DEVICE_PATH)) >> 8)\r
+    }\r
+  },\r
+  0\r
+};\r
+\r
 /**\r
   Locate the handles that support SNP, then open one of them\r
   to send the syslog packets. The caller isn't required to close\r
@@ -1772,18 +1787,289 @@ NetLibDestroyServiceChild (
   return Status;\r
 }\r
 \r
+/**\r
+  Get handle with Simple Network Protocol installed on it.\r
+\r
+  There should be MNP Service Binding Protocol installed on the input ServiceHandle.\r
+  If Simple Network Protocol is already installed on the ServiceHandle, the\r
+  ServiceHandle will be returned. If SNP is not installed on the ServiceHandle,\r
+  try to find its parent handle with SNP installed.\r
+\r
+  @param[in]   ServiceHandle    The handle where network service binding protocols are\r
+                                installed on.\r
+  @param[out]  Snp              The pointer to store the address of the SNP instance.\r
+                                This is an optional parameter that may be NULL.\r
+\r
+  @return The SNP handle, or NULL if not found.\r
+\r
+**/\r
+EFI_HANDLE\r
+EFIAPI\r
+NetLibGetSnpHandle (\r
+  IN   EFI_HANDLE                  ServiceHandle,\r
+  OUT  EFI_SIMPLE_NETWORK_PROTOCOL **Snp  OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL  *SnpInstance;\r
+  EFI_DEVICE_PATH_PROTOCOL     *DevicePath;\r
+  EFI_HANDLE                   SnpHandle;\r
+\r
+  //\r
+  // Try to open SNP from ServiceHandle\r
+  //\r
+  SnpInstance = NULL;\r
+  Status = gBS->HandleProtocol (ServiceHandle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &SnpInstance);\r
+  if (!EFI_ERROR (Status)) {\r
+    if (Snp != NULL) {\r
+      *Snp = SnpInstance;\r
+    }\r
+    return ServiceHandle;\r
+  }\r
+\r
+  //\r
+  // Failed to open SNP, try to get SNP handle by LocateDevicePath()\r
+  //\r
+  DevicePath = DevicePathFromHandle (ServiceHandle);\r
+  if (DevicePath == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  SnpHandle = NULL;\r
+  Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &DevicePath, &SnpHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Failed to find SNP handle\r
+    //\r
+    return NULL;\r
+  }\r
+\r
+  Status = gBS->HandleProtocol (SnpHandle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &SnpInstance);\r
+  if (!EFI_ERROR (Status)) {\r
+    if (Snp != NULL) {\r
+      *Snp = SnpInstance;\r
+    }\r
+    return SnpHandle;\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Retrieve VLAN ID of a VLAN device handle.\r
+\r
+  Search VLAN device path node in Device Path of specified ServiceHandle and\r
+  return its VLAN ID. If no VLAN device path node found, then this ServiceHandle\r
+  is not a VLAN device handle, and 0 will be returned.\r
+\r
+  @param[in]   ServiceHandle    The handle where network service binding protocols are\r
+                                installed on.\r
+\r
+  @return VLAN ID of the device handle, or 0 if not a VLAN device.\r
+\r
+**/\r
+UINT16\r
+EFIAPI\r
+NetLibGetVlanId (\r
+  IN EFI_HANDLE             ServiceHandle\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *Node;\r
+\r
+  DevicePath = DevicePathFromHandle (ServiceHandle);\r
+  if (DevicePath == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  Node = DevicePath;\r
+  while (!IsDevicePathEnd (Node)) {\r
+    if (Node->Type == MESSAGING_DEVICE_PATH && Node->SubType == MSG_VLAN_DP) {\r
+      return ((VLAN_DEVICE_PATH *) Node)->VlanId;\r
+    }\r
+    Node = NextDevicePathNode (Node);\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
+/**\r
+  Find VLAN device handle with specified VLAN ID.\r
+\r
+  The VLAN child device handle is created by VLAN Config Protocol on ControllerHandle.\r
+  This function will append VLAN device path node to the parent device path,\r
+  and then use LocateDevicePath() to find the correct VLAN device handle.\r
+\r
+  @param[in]   ServiceHandle    The handle where network service binding protocols are\r
+                                installed on.\r
+  @param[in]   VLanId           The configured VLAN ID for the VLAN device.\r
+\r
+  @return The VLAN device handle, or NULL if not found.\r
+\r
+**/\r
+EFI_HANDLE\r
+EFIAPI\r
+NetLibGetVlanHandle (\r
+  IN EFI_HANDLE             ControllerHandle,\r
+  IN UINT16                 VlanId\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *VlanDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  VLAN_DEVICE_PATH          VlanNode;\r
+  EFI_HANDLE                Handle;\r
+\r
+  ParentDevicePath = DevicePathFromHandle (ControllerHandle);\r
+  if (ParentDevicePath == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Construct VLAN device path\r
+  //\r
+  CopyMem (&VlanNode, &mNetVlanDevicePathTemplate, sizeof (VLAN_DEVICE_PATH));\r
+  VlanNode.VlanId = VlanId;\r
+  VlanDevicePath = AppendDevicePathNode (\r
+                     ParentDevicePath,\r
+                     (EFI_DEVICE_PATH_PROTOCOL *) &VlanNode\r
+                     );\r
+  if (VlanDevicePath == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Find VLAN device handle\r
+  //\r
+  Handle = NULL;\r
+  DevicePath = VlanDevicePath;\r
+  gBS->LocateDevicePath (\r
+         &gEfiDevicePathProtocolGuid,\r
+         &DevicePath,\r
+         &Handle\r
+         );\r
+  if (!IsDevicePathEnd (DevicePath)) {\r
+    //\r
+    // Device path is not exactly match\r
+    //\r
+    Handle = NULL;\r
+  }\r
+\r
+  FreePool (VlanDevicePath);\r
+  return Handle;\r
+}\r
 \r
 /**\r
-  Convert the mac address of the simple network protocol installed on\r
-  SnpHandle to a unicode string. Callers are responsible for freeing the\r
-  string storage.\r
+  Get MAC address associated with the network service handle.\r
+\r
+  There should be MNP Service Binding Protocol installed on the input ServiceHandle.\r
+  If SNP is installed on the ServiceHandle or its parent handle, MAC address will\r
+  be retrieved from SNP. If no SNP found, try to get SNP mode data use MNP.\r
+\r
+  @param[in]   ServiceHandle    The handle where network service binding protocols are\r
+                                installed on.\r
+  @param[out]  MacAddress       The pointer to store the returned MAC address.\r
+  @param[out]  AddressSize      The length of returned MAC address.\r
+\r
+  @retval EFI_SUCCESS           MAC address is returned successfully.\r
+  @retval Others                Failed to get SNP mode data.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NetLibGetMacAddress (\r
+  IN  EFI_HANDLE            ServiceHandle,\r
+  OUT EFI_MAC_ADDRESS       *MacAddress,\r
+  OUT UINTN                 *AddressSize\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL  *Snp;\r
+  EFI_SIMPLE_NETWORK_MODE      *SnpMode;\r
+  EFI_SIMPLE_NETWORK_MODE      SnpModeData;\r
+  EFI_MANAGED_NETWORK_PROTOCOL *Mnp;\r
+  EFI_SERVICE_BINDING_PROTOCOL *MnpSb;\r
+  EFI_HANDLE                   *SnpHandle;\r
+  EFI_HANDLE                   MnpChildHandle;\r
+\r
+  ASSERT (MacAddress != NULL);\r
+  ASSERT (AddressSize != NULL);\r
+\r
+  //\r
+  // Try to get SNP handle\r
+  //\r
+  Snp = NULL;\r
+  SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);\r
+  if (SnpHandle != NULL) {\r
+    //\r
+    // SNP found, use it directly\r
+    //\r
+    SnpMode = Snp->Mode;\r
+  } else {\r
+    //\r
+    // Failed to get SNP handle, try to get MAC address from MNP\r
+    //\r
+    MnpChildHandle = NULL;\r
+    Status = gBS->HandleProtocol (\r
+                    ServiceHandle,\r
+                    &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+                    (VOID **) &MnpSb\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
 \r
-  Get the mac address of the Simple Network protocol from the SnpHandle. Then convert\r
-  the mac address into a unicode string. It takes 2 unicode characters to represent \r
-  a 1 byte binary buffer. Plus one unicode character for the null-terminator.\r
+    //\r
+    // Create a MNP child\r
+    //\r
+    Status = MnpSb->CreateChild (MnpSb, &MnpChildHandle);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Open MNP protocol\r
+    //\r
+    Status = gBS->HandleProtocol (\r
+                    MnpChildHandle,\r
+                    &gEfiManagedNetworkProtocolGuid,\r
+                    (VOID **) &Mnp\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Try to get SNP mode from MNP\r
+    //\r
+    Status = Mnp->GetModeData (Mnp, NULL, &SnpModeData);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    SnpMode = &SnpModeData;\r
+\r
+    //\r
+    // Destroy the MNP child\r
+    //\r
+    MnpSb->DestroyChild (MnpSb, MnpChildHandle);\r
+  }\r
+\r
+  *AddressSize = SnpMode->HwAddressSize;\r
+  CopyMem (MacAddress->Addr, SnpMode->CurrentAddress.Addr, SnpMode->HwAddressSize);\r
 \r
+  return EFI_SUCCESS;\r
+}\r
 \r
-  @param[in]   SnpHandle             The handle where the simple network protocol is\r
+/**\r
+  Convert MAC address of the NIC associated with specified Service Binding Handle\r
+  to a unicode string. Callers are responsible for freeing the string storage.\r
+\r
+  Locate simple network protocol associated with the Service Binding Handle and\r
+  get the mac address from SNP. Then convert the mac address into a unicode\r
+  string. It takes 2 unicode characters to represent a 1 byte binary buffer.\r
+  Plus one unicode character for the null-terminator.\r
+\r
+  @param[in]   ServiceHandle         The handle where network service binding protocol is\r
                                      installed on.\r
   @param[in]   ImageHandle           The image handle used to act as the agent handle to\r
                                      get the simple network protocol.\r
@@ -1798,57 +2084,61 @@ NetLibDestroyServiceChild (
 EFI_STATUS\r
 EFIAPI\r
 NetLibGetMacString (\r
-  IN  EFI_HANDLE            SnpHandle,\r
+  IN  EFI_HANDLE            ServiceHandle,\r
   IN  EFI_HANDLE            ImageHandle,\r
   OUT CHAR16                **MacString\r
   )\r
 {\r
   EFI_STATUS                   Status;\r
-  EFI_SIMPLE_NETWORK_PROTOCOL  *Snp;\r
-  EFI_SIMPLE_NETWORK_MODE      *Mode;\r
-  CHAR16                       *MacAddress;\r
+  EFI_MAC_ADDRESS              MacAddress;\r
   UINT8                        *HwAddress;\r
+  UINTN                        HwAddressSize;\r
+  UINT16                       VlanId;\r
+  CHAR16                       *String;\r
   UINTN                        Index;\r
 \r
-  *MacString = NULL;\r
+  ASSERT (MacString != NULL);\r
 \r
   //\r
-  // Get the Simple Network protocol from the SnpHandle.\r
+  // Get MAC address of the network device\r
   //\r
-  Status = gBS->OpenProtocol (\r
-                  SnpHandle,\r
-                  &gEfiSimpleNetworkProtocolGuid,\r
-                  (VOID **) &Snp,\r
-                  ImageHandle,\r
-                  SnpHandle,\r
-                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
-                  );\r
+  Status = NetLibGetMacAddress (ServiceHandle, &MacAddress, &HwAddressSize);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  Mode = Snp->Mode;\r
-\r
   //\r
   // It takes 2 unicode characters to represent a 1 byte binary buffer.\r
+  // If VLAN is configured, it will need extra 5 characters like "\0005".\r
   // Plus one unicode character for the null-terminator.\r
   //\r
-  MacAddress = AllocatePool ((2 * Mode->HwAddressSize + 1) * sizeof (CHAR16));\r
-  if (MacAddress == NULL) {\r
+  String = AllocateZeroPool ((2 * HwAddressSize + 5 + 1) * sizeof (CHAR16));\r
+  if (String == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
-  *MacString = MacAddress;\r
+  *MacString = String;\r
 \r
   //\r
-  // Convert the mac address into a unicode string.\r
+  // Convert the MAC address into a unicode string.\r
   //\r
-  HwAddress = Mode->CurrentAddress.Addr;\r
-  for (Index = 0; Index < Mode->HwAddressSize; Index++) {\r
-    MacAddress += UnicodeValueToString (MacAddress, PREFIX_ZERO | RADIX_HEX, *(HwAddress++), 2);\r
+  HwAddress = &MacAddress.Addr[0];\r
+  for (Index = 0; Index < HwAddressSize; Index++) {\r
+    String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(HwAddress++), 2);\r
   }\r
 \r
-  MacAddress[Mode->HwAddressSize * 2] = L'\0';\r
+  //\r
+  // Append VLAN ID if any\r
+  //\r
+  VlanId = NetLibGetVlanId (ServiceHandle);\r
+  if (VlanId != 0) {\r
+    *String++ = L'\\';\r
+    String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, VlanId, 4);\r
+  }\r
 \r
+  //\r
+  // Null terminate the Unicode string\r
+  //\r
+  *String = L'\0';\r
 \r
   return EFI_SUCCESS;\r
 }\r