+/**\r
+\r
+ Convert one EFI_IPv6_ADDRESS to Null-terminated Unicode string.\r
+ The text representation of address is defined in RFC 4291.\r
+ \r
+ @param[in] Ip6Address The pointer to the IPv6 address.\r
+ @param[out] String The buffer to return the converted string.\r
+ @param[in] StringSize The length in bytes of the input String.\r
+ \r
+ @retval EFI_SUCCESS Convert to string successfully.\r
+ @retval EFI_INVALID_PARAMETER The input parameter is invalid.\r
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result. BufferSize has been \r
+ updated with the size needed to complete the request.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NetLibIp6ToStr (\r
+ IN EFI_IPv6_ADDRESS *Ip6Address,\r
+ OUT CHAR16 *String,\r
+ IN UINTN StringSize\r
+ )\r
+{\r
+ UINT16 Ip6Addr[8];\r
+ UINTN Index;\r
+ UINTN LongestZerosStart;\r
+ UINTN LongestZerosLength;\r
+ UINTN CurrentZerosStart;\r
+ UINTN CurrentZerosLength;\r
+ CHAR16 Buffer[sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];\r
+ CHAR16 *Ptr;\r
+\r
+ if (Ip6Address == NULL || String == NULL || StringSize == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Convert the UINT8 array to an UINT16 array for easy handling.\r
+ // \r
+ ZeroMem (Ip6Addr, sizeof (Ip6Addr));\r
+ for (Index = 0; Index < 16; Index++) {\r
+ Ip6Addr[Index / 2] |= (Ip6Address->Addr[Index] << ((1 - (Index % 2)) << 3));\r
+ }\r
+\r
+ //\r
+ // Find the longest zeros and mark it.\r
+ //\r
+ CurrentZerosStart = DEFAULT_ZERO_START;\r
+ CurrentZerosLength = 0;\r
+ LongestZerosStart = DEFAULT_ZERO_START;\r
+ LongestZerosLength = 0;\r
+ for (Index = 0; Index < 8; Index++) {\r
+ if (Ip6Addr[Index] == 0) {\r
+ if (CurrentZerosStart == DEFAULT_ZERO_START) {\r
+ CurrentZerosStart = Index;\r
+ CurrentZerosLength = 1;\r
+ } else {\r
+ CurrentZerosLength++;\r
+ }\r
+ } else {\r
+ if (CurrentZerosStart != DEFAULT_ZERO_START) {\r
+ if (CurrentZerosLength > 2 && (LongestZerosStart == (DEFAULT_ZERO_START) || CurrentZerosLength > LongestZerosLength)) {\r
+ LongestZerosStart = CurrentZerosStart;\r
+ LongestZerosLength = CurrentZerosLength;\r
+ }\r
+ CurrentZerosStart = DEFAULT_ZERO_START;\r
+ CurrentZerosLength = 0;\r
+ }\r
+ }\r
+ }\r
+ \r
+ if (CurrentZerosStart != DEFAULT_ZERO_START && CurrentZerosLength > 2) {\r
+ if (LongestZerosStart == DEFAULT_ZERO_START || LongestZerosLength < CurrentZerosLength) {\r
+ LongestZerosStart = CurrentZerosStart;\r
+ LongestZerosLength = CurrentZerosLength;\r
+ }\r
+ }\r
+\r
+ Ptr = Buffer;\r
+ for (Index = 0; Index < 8; Index++) {\r
+ if (LongestZerosStart != DEFAULT_ZERO_START && Index >= LongestZerosStart && Index < LongestZerosStart + LongestZerosLength) {\r
+ if (Index == LongestZerosStart) {\r
+ *Ptr++ = L':';\r
+ }\r
+ continue;\r
+ }\r
+ if (Index != 0) {\r
+ *Ptr++ = L':';\r
+ }\r
+ Ptr += UnicodeSPrint(Ptr, 10, L"%x", Ip6Addr[Index]);\r
+ }\r
+ \r
+ if (LongestZerosStart != DEFAULT_ZERO_START && LongestZerosStart + LongestZerosLength == 8) {\r
+ *Ptr++ = L':';\r
+ }\r
+ *Ptr = L'\0';\r
+\r
+ if ((UINTN)Ptr - (UINTN)Buffer > StringSize) {\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ StrCpy (String, Buffer);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function obtains the system guid from the smbios table.\r
+\r
+ @param[out] SystemGuid The pointer of the returned system guid.\r
+\r
+ @retval EFI_SUCCESS Successfully obtained the system guid.\r
+ @retval EFI_NOT_FOUND Did not find the SMBIOS table.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NetLibGetSystemGuid (\r
+ OUT EFI_GUID *SystemGuid\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SMBIOS_TABLE_ENTRY_POINT *SmbiosTable;\r
+ SMBIOS_STRUCTURE_POINTER Smbios;\r
+ SMBIOS_STRUCTURE_POINTER SmbiosEnd;\r
+ CHAR8 *String;\r
+\r
+ SmbiosTable = NULL;\r
+ Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID **) &SmbiosTable);\r
+\r
+ if (EFI_ERROR (Status) || SmbiosTable == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Smbios.Hdr = (SMBIOS_STRUCTURE *) (UINTN) SmbiosTable->TableAddress;\r
+ SmbiosEnd.Raw = (UINT8 *) (UINTN) (SmbiosTable->TableAddress + SmbiosTable->TableLength);\r
+\r
+ do {\r
+ if (Smbios.Hdr->Type == 1) {\r
+ if (Smbios.Hdr->Length < 0x19) {\r
+ //\r
+ // Older version did not support UUID.\r
+ //\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ \r
+ //\r
+ // SMBIOS tables are byte packed so we need to do a byte copy to\r
+ // prevend alignment faults on Itanium-based platform.\r
+ //\r
+ CopyMem (SystemGuid, &Smbios.Type1->Uuid, sizeof (EFI_GUID));\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Go to the next SMBIOS structure. Each SMBIOS structure may include 2 parts:\r
+ // 1. Formatted section; 2. Unformatted string section. So, 2 steps are needed\r
+ // to skip one SMBIOS structure.\r
+ //\r
+ \r
+ //\r
+ // Step 1: Skip over formatted section.\r
+ //\r
+ String = (CHAR8 *) (Smbios.Raw + Smbios.Hdr->Length);\r
+ \r
+ //\r
+ // Step 2: Skip over unformated string section.\r
+ //\r
+ do {\r
+ //\r
+ // Each string is terminated with a NULL(00h) BYTE and the sets of strings\r
+ // is terminated with an additional NULL(00h) BYTE.\r
+ //\r
+ for ( ; *String != 0; String++) {\r
+ }\r
+\r
+ if (*(UINT8*)++String == 0) {\r
+ //\r
+ // Pointer to the next SMBIOS structure.\r
+ //\r
+ Smbios.Raw = (UINT8 *)++String;\r
+ break;\r
+ } \r
+ } while (TRUE);\r
+ } while (Smbios.Raw < SmbiosEnd.Raw);\r
+ return EFI_NOT_FOUND;\r
+}\r