#include <Library/UefiLib.h>\r
\r
#define NIC_ITEM_CONFIG_SIZE sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * MAX_IP4_CONFIG_IN_VARIABLE\r
+#define DEFAULT_ZERO_START ((UINTN) ~0)\r
\r
//\r
// All the supported IP4 maskes in host byte order.\r
PostEntry->BackLink = NewEntry;\r
}\r
\r
+/**\r
+ Safe destroy nodes in a linked list, and return the length of the list after all possible operations finished.\r
+\r
+ Destroy network child instance list by list traversals is not safe due to graph dependencies between nodes.\r
+ This function performs a safe traversal to destroy these nodes by checking to see if the node being destroyed\r
+ has been removed from the list or not.\r
+ If it has been removed, then restart the traversal from the head.\r
+ If it hasn't been removed, then continue with the next node directly.\r
+ This function will end the iterate and return the CallBack's last return value if error happens,\r
+ or retrun EFI_SUCCESS if 2 complete passes are made with no changes in the number of children in the list. \r
+\r
+ @param[in] List The head of the list.\r
+ @param[in] CallBack Pointer to the callback function to destroy one node in the list.\r
+ @param[in] Context Pointer to the callback function's context: corresponds to the\r
+ parameter Context in NET_DESTROY_LINK_LIST_CALLBACK.\r
+ @param[out] ListLength The length of the link list if the function returns successfully.\r
+\r
+ @retval EFI_SUCCESS Two complete passes are made with no changes in the number of children.\r
+ @retval EFI_INVALID_PARAMETER The input parameter is invalid.\r
+ @retval Others Return the CallBack's last return value.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NetDestroyLinkList (\r
+ IN LIST_ENTRY *List,\r
+ IN NET_DESTROY_LINK_LIST_CALLBACK CallBack,\r
+ IN VOID *Context, OPTIONAL\r
+ OUT UINTN *ListLength OPTIONAL\r
+)\r
+{\r
+ UINTN PreviousLength;\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *Ptr;\r
+ UINTN Length;\r
+ EFI_STATUS Status;\r
+\r
+ if (List == NULL || CallBack == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Length = 0;\r
+ do {\r
+ PreviousLength = Length;\r
+ Entry = GetFirstNode (List);\r
+ while (!IsNull (List, Entry)) {\r
+ Status = CallBack (Entry, Context);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Walk through the list to see whether the Entry has been removed or not.\r
+ // If the Entry still exists, just try to destroy the next one.\r
+ // If not, go back to the start point to iterate the list again.\r
+ //\r
+ for (Ptr = List->ForwardLink; Ptr != List; Ptr = Ptr->ForwardLink) {\r
+ if (Ptr == Entry) {\r
+ break;\r
+ }\r
+ }\r
+ if (Ptr == Entry) {\r
+ Entry = GetNextNode (List, Entry);\r
+ } else {\r
+ Entry = GetFirstNode (List);\r
+ }\r
+ }\r
+ for (Length = 0, Ptr = List->ForwardLink; Ptr != List; Length++, Ptr = Ptr->ForwardLink);\r
+ } while (Length != PreviousLength);\r
+\r
+ if (ListLength != NULL) {\r
+ *ListLength = Length;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function checks the input Handle to see if it's one of these handles in ChildHandleBuffer.\r
+\r
+ @param[in] Handle Handle to be checked.\r
+ @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer.\r
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+ if NumberOfChildren is 0.\r
+\r
+ @retval TURE Found the input Handle in ChildHandleBuffer.\r
+ @retval FALSE Can't find the input Handle in ChildHandleBuffer.\r
+\r
+**/\r
+BOOLEAN\r
+NetIsInHandleBuffer (\r
+ IN EFI_HANDLE Handle,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL\r
+)\r
+{\r
+ UINTN Index;\r
+ \r
+ if (NumberOfChildren == 0 || ChildHandleBuffer == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ for (Index = 0; Index < NumberOfChildren; Index++) {\r
+ if (Handle == ChildHandleBuffer[Index]) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
\r
/**\r
Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.\r
return Status;\r
}\r
\r
+/**\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