-/**
- Return the length of the mask. If the mask is invalid,
- return the invalid length 33, which is IP4_MASK_NUM.
- NetMask is in the host byte order.
-
- @param NetMask The netmask to get the length from
-
- @return The length of the netmask, IP4_MASK_NUM if the mask isn't
- @return supported.
-
-**/
-INTN
-NetGetMaskLength (
- IN IP4_ADDR NetMask
- )
-{
- INTN Index;
-
- for (Index = 0; Index < IP4_MASK_NUM; Index++) {
- if (NetMask == mIp4AllMasks[Index]) {
- break;
- }
- }
-
- return Index;
-}
-
-
-
-/**
- Return the class of the address, such as class a, b, c.
- Addr is in host byte order.
-
- @param Addr The address to get the class from
-
- @return IP address class, such as IP4_ADDR_CLASSA
-
-**/
-INTN
-NetGetIpClass (
- IN IP4_ADDR Addr
- )
-{
- UINT8 ByteOne;
-
- ByteOne = (UINT8) (Addr >> 24);
-
- if ((ByteOne & 0x80) == 0) {
- return IP4_ADDR_CLASSA;
-
- } else if ((ByteOne & 0xC0) == 0x80) {
- return IP4_ADDR_CLASSB;
-
- } else if ((ByteOne & 0xE0) == 0xC0) {
- return IP4_ADDR_CLASSC;
-
- } else if ((ByteOne & 0xF0) == 0xE0) {
- return IP4_ADDR_CLASSD;
-
- } else {
- return IP4_ADDR_CLASSE;
-
- }
-}
-
-
-/**
- Check whether the IP is a valid unicast address according to
- the netmask. If NetMask is zero, use the IP address's class to
- get the default mask.
-
- @param Ip The IP to check againist
- @param NetMask The mask of the IP
-
- @return TRUE if IP is a valid unicast address on the network, otherwise FALSE
-
-**/
-BOOLEAN
-Ip4IsUnicast (
- IN IP4_ADDR Ip,
- IN IP4_ADDR NetMask
- )
-{
- INTN Class;
-
- Class = NetGetIpClass (Ip);
-
- if ((Ip == 0) || (Class >= IP4_ADDR_CLASSD)) {
- return FALSE;
- }
-
- if (NetMask == 0) {
- NetMask = mIp4AllMasks[Class << 3];
- }
-
- if (((Ip &~NetMask) == ~NetMask) || ((Ip &~NetMask) == 0)) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/**
- Initialize a random seed using current time.
-
- None
-
- @return The random seed initialized with current time.
-
-**/
-UINT32
-NetRandomInitSeed (
- VOID
- )
-{
- EFI_TIME Time;
- UINT32 Seed;
-
- gRT->GetTime (&Time, NULL);
- Seed = (~Time.Hour << 24 | Time.Second << 16 | Time.Minute << 8 | Time.Day);
- Seed ^= Time.Nanosecond;
- Seed ^= Time.Year << 7;
-
- return Seed;
-}
-
-
-/**
- Extract a UINT32 from a byte stream, then convert it to host
- byte order. Use this function to avoid alignment error.
-
- @param Buf The buffer to extract the UINT32.
-
- @return The UINT32 extracted.
-
-**/
-UINT32
-NetGetUint32 (
- IN UINT8 *Buf
- )
-{
- UINT32 Value;
-
- NetCopyMem (&Value, Buf, sizeof (UINT32));
- return NTOHL (Value);
-}
-
-
-/**
- Put a UINT32 to the byte stream. Convert it from host byte order
- to network byte order before putting.
-
- @param Buf The buffer to put the UINT32
- @param Data The data to put
-
- @return None
-
-**/
-VOID
-NetPutUint32 (
- IN UINT8 *Buf,
- IN UINT32 Data
- )
-{
- Data = HTONL (Data);
- NetCopyMem (Buf, &Data, sizeof (UINT32));
-}
-
-
-/**
- Remove the first entry on the list
-
- @param Head The list header
-
- @return The entry that is removed from the list, NULL if the list is empty.
-
-**/
-NET_LIST_ENTRY *
-NetListRemoveHead (
- NET_LIST_ENTRY *Head
- )
-{
- NET_LIST_ENTRY *First;
-
- ASSERT (Head != NULL);
-
- if (NetListIsEmpty (Head)) {
- return NULL;
- }
-
- First = Head->ForwardLink;
- Head->ForwardLink = First->ForwardLink;
- First->ForwardLink->BackLink = Head;
-
- DEBUG_CODE (
- First->ForwardLink = (LIST_ENTRY *) NULL;
- First->BackLink = (LIST_ENTRY *) NULL;
- );
-
- return First;
-}
-
-
-/**
- Remove the last entry on the list
-
- @param Head The list head
-
- @return The entry that is removed from the list, NULL if the list is empty.
-
-**/
-NET_LIST_ENTRY *
-NetListRemoveTail (
- NET_LIST_ENTRY *Head
- )
-{
- NET_LIST_ENTRY *Last;
-
- ASSERT (Head != NULL);
-
- if (NetListIsEmpty (Head)) {
- return NULL;
- }
-
- Last = Head->BackLink;
- Head->BackLink = Last->BackLink;
- Last->BackLink->ForwardLink = Head;
-
- DEBUG_CODE (
- Last->ForwardLink = (LIST_ENTRY *) NULL;
- Last->BackLink = (LIST_ENTRY *) NULL;
- );
-
- return Last;
-}
-
-
-/**
- Insert the NewEntry after the PrevEntry
-
- @param PrevEntry The previous entry to insert after
- @param NewEntry The new entry to insert
-
- @return None
-
-**/
-VOID
-NetListInsertAfter (
- IN NET_LIST_ENTRY *PrevEntry,
- IN NET_LIST_ENTRY *NewEntry
- )
-{
- NewEntry->BackLink = PrevEntry;
- NewEntry->ForwardLink = PrevEntry->ForwardLink;
- PrevEntry->ForwardLink->BackLink = NewEntry;
- PrevEntry->ForwardLink = NewEntry;
-}
-
-
-/**
- Insert the NewEntry before the PostEntry
-
- @param PostEntry The entry to insert before
- @param NewEntry The new entry to insert
-
- @return None
-
-**/
-VOID
-NetListInsertBefore (
- IN NET_LIST_ENTRY *PostEntry,
- IN NET_LIST_ENTRY *NewEntry
- )
-{
- NewEntry->ForwardLink = PostEntry;
- NewEntry->BackLink = PostEntry->BackLink;
- PostEntry->BackLink->ForwardLink = NewEntry;
- PostEntry->BackLink = NewEntry;
-}
-
-
-/**
- Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.
-
- @param Map The netmap to initialize
-
- @return None
-
-**/
-VOID
-NetMapInit (
- IN NET_MAP *Map
- )
-{
- ASSERT (Map != NULL);
-
- NetListInit (&Map->Used);
- NetListInit (&Map->Recycled);
- Map->Count = 0;
-}
-
-
-/**
- To clean up the netmap, that is, release allocated memories.
-
- @param Map The netmap to clean up.
-
- @return None
-
-**/
-VOID
-NetMapClean (
- IN NET_MAP *Map
- )
-{
- NET_MAP_ITEM *Item;
- NET_LIST_ENTRY *Entry;
- NET_LIST_ENTRY *Next;
-
- ASSERT (Map != NULL);
-
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Used) {
- Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
-
- NetListRemoveEntry (&Item->Link);
- Map->Count--;
-
- NetFreePool (Item);
- }
-
- ASSERT ((Map->Count == 0) && NetListIsEmpty (&Map->Used));
-
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Recycled) {
- Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
-
- NetListRemoveEntry (&Item->Link);
- NetFreePool (Item);
- }
-
- ASSERT (NetListIsEmpty (&Map->Recycled));
-}
-
-
-/**
- Test whether the netmap is empty
-
- @param Map The net map to test
-
- @return TRUE if the netmap is empty, otherwise FALSE.
-
-**/
-BOOLEAN
-NetMapIsEmpty (
- IN NET_MAP *Map
- )
-{
- ASSERT (Map != NULL);
- return (BOOLEAN) (Map->Count == 0);
-}
-
-
-/**
- Return the number of the <Key, Value> pairs in the netmap.
-
- @param Map The netmap to get the entry number
-
- @return The entry number in the netmap.
-
-**/
-UINTN
-NetMapGetCount (
- IN NET_MAP *Map
- )
-{
- return Map->Count;
-}
-
-
-/**
- Allocate an item for the netmap. It will try to allocate
- a batch of items and return one.
-
- @param Map The netmap to allocate item for
-
- @return The allocated item or NULL
-
-**/
-STATIC
-NET_MAP_ITEM *
-NetMapAllocItem (
- IN NET_MAP *Map
- )
-{
- NET_MAP_ITEM *Item;
- NET_LIST_ENTRY *Head;
- UINTN Index;
-
- ASSERT (Map != NULL);
-
- Head = &Map->Recycled;
-
- if (NetListIsEmpty (Head)) {
- for (Index = 0; Index < NET_MAP_INCREAMENT; Index++) {
- Item = NetAllocatePool (sizeof (NET_MAP_ITEM));
-
- if (Item == NULL) {
- if (Index == 0) {
- return NULL;
- }
-
- break;
- }
-
- NetListInsertHead (Head, &Item->Link);
- }
- }
-
- Item = NET_LIST_HEAD (Head, NET_MAP_ITEM, Link);
- NetListRemoveHead (Head);
-
- return Item;
-}
-
-
-/**
- Allocate an item to save the <Key, Value> pair to the head of the netmap.
-
- @param Map The netmap to insert into
- @param Key The user's key
- @param Value The user's value for the key
-
- @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item
- @retval EFI_SUCCESS The item is inserted to the head
-
-**/
-EFI_STATUS
-NetMapInsertHead (
- IN NET_MAP *Map,
- IN VOID *Key,
- IN VOID *Value OPTIONAL
- )
-{
- NET_MAP_ITEM *Item;
-
- ASSERT (Map != NULL);
-
- Item = NetMapAllocItem (Map);
-
- if (Item == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Item->Key = Key;
- Item->Value = Value;
- NetListInsertHead (&Map->Used, &Item->Link);
-
- Map->Count++;
- return EFI_SUCCESS;
-}
-
-
-/**
- Allocate an item to save the <Key, Value> pair to the tail of the netmap.
-
- @param Map The netmap to insert into
- @param Key The user's key
- @param Value The user's value for the key
-
- @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item
- @retval EFI_SUCCESS The item is inserted to the tail
-
-**/
-EFI_STATUS
-NetMapInsertTail (
- IN NET_MAP *Map,
- IN VOID *Key,
- IN VOID *Value OPTIONAL
- )
-{
- NET_MAP_ITEM *Item;
-
- ASSERT (Map != NULL);
-
- Item = NetMapAllocItem (Map);
-
- if (Item == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Item->Key = Key;
- Item->Value = Value;
- NetListInsertTail (&Map->Used, &Item->Link);
-
- Map->Count++;
-
- return EFI_SUCCESS;
-}
-
-
-/**
- Check whther the item is in the Map
-
- @param Map The netmap to search within
- @param Item The item to search
-
- @return TRUE if the item is in the netmap, otherwise FALSE.
-
-**/
-STATIC
-BOOLEAN
-NetItemInMap (
- IN NET_MAP *Map,
- IN NET_MAP_ITEM *Item
- )
-{
- NET_LIST_ENTRY *ListEntry;
-
- NET_LIST_FOR_EACH (ListEntry, &Map->Used) {
- if (ListEntry == &Item->Link) {
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-
-/**
- Find the key in the netmap
-
- @param Map The netmap to search within
- @param Key The key to search
-
- @return The point to the item contains the Key, or NULL if Key isn't in the map.
-
-**/
-NET_MAP_ITEM *
-NetMapFindKey (
- IN NET_MAP *Map,
- IN VOID *Key
- )
-{
- NET_LIST_ENTRY *Entry;
- NET_MAP_ITEM *Item;
-
- ASSERT (Map != NULL);
-
- NET_LIST_FOR_EACH (Entry, &Map->Used) {
- Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
-
- if (Item->Key == Key) {
- return Item;
- }
- }
-
- return NULL;
-}
-
-
-/**
- Remove the item from the netmap
-
- @param Map The netmap to remove the item from
- @param Item The item to remove
- @param Value The variable to receive the value if not NULL
-
- @return The key of the removed item.
-
-**/
-VOID *
-NetMapRemoveItem (
- IN NET_MAP *Map,
- IN NET_MAP_ITEM *Item,
- OUT VOID **Value OPTIONAL
- )
-{
- ASSERT ((Map != NULL) && (Item != NULL));
- ASSERT (NetItemInMap (Map, Item));
-
- NetListRemoveEntry (&Item->Link);
- Map->Count--;
- NetListInsertHead (&Map->Recycled, &Item->Link);
-
- if (Value != NULL) {
- *Value = Item->Value;
- }
-
- return Item->Key;
-}
-
-
-/**
- Remove the first entry on the netmap
-
- @param Map The netmap to remove the head from
- @param Value The variable to receive the value if not NULL
-
- @return The key of the item removed
-
-**/
-VOID *
-NetMapRemoveHead (
- IN NET_MAP *Map,
- OUT VOID **Value OPTIONAL
- )
-{
- NET_MAP_ITEM *Item;
-
- //
- // Often, it indicates a programming error to remove
- // the first entry in an empty list
- //
- ASSERT (Map && !NetListIsEmpty (&Map->Used));
-
- Item = NET_LIST_HEAD (&Map->Used, NET_MAP_ITEM, Link);
- NetListRemoveEntry (&Item->Link);
- Map->Count--;
- NetListInsertHead (&Map->Recycled, &Item->Link);
-
- if (Value != NULL) {
- *Value = Item->Value;
- }
-
- return Item->Key;
-}
-
-
-/**
- Remove the last entry on the netmap
-
- @param Map The netmap to remove the tail from
- @param Value The variable to receive the value if not NULL
-
- @return The key of the item removed
-
-**/
-VOID *
-NetMapRemoveTail (
- IN NET_MAP *Map,
- OUT VOID **Value OPTIONAL
- )
-{
- NET_MAP_ITEM *Item;
-
- //
- // Often, it indicates a programming error to remove
- // the last entry in an empty list
- //
- ASSERT (Map && !NetListIsEmpty (&Map->Used));
-
- Item = NET_LIST_TAIL (&Map->Used, NET_MAP_ITEM, Link);
- NetListRemoveEntry (&Item->Link);
- Map->Count--;
- NetListInsertHead (&Map->Recycled, &Item->Link);
-
- if (Value != NULL) {
- *Value = Item->Value;
- }
-
- return Item->Key;
-}
-
-
-/**
- Iterate through the netmap and call CallBack for each item. It will
- contiue the traverse if CallBack returns EFI_SUCCESS, otherwise, break
- from the loop. It returns the CallBack's last return value. This
- function is delete safe for the current item.
-
- @param Map The Map to iterate through
- @param CallBack The callback function to call for each item.
- @param Arg The opaque parameter to the callback
-
- @return It returns the CallBack's last return value.
-
-**/
-EFI_STATUS
-NetMapIterate (
- IN NET_MAP *Map,
- IN NET_MAP_CALLBACK CallBack,
- IN VOID *Arg
- )
-{
-
- NET_LIST_ENTRY *Entry;
- NET_LIST_ENTRY *Next;
- NET_LIST_ENTRY *Head;
- NET_MAP_ITEM *Item;
- EFI_STATUS Result;
-
- ASSERT ((Map != NULL) && (CallBack != NULL));
-
- Head = &Map->Used;
-
- if (NetListIsEmpty (Head)) {
- return EFI_SUCCESS;
- }
-
- NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {
- Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
- Result = CallBack (Map, Item, Arg);
-
- if (EFI_ERROR (Result)) {
- return Result;
- }
- }
-
- return EFI_SUCCESS;
-}
-
-
-/**
- This is the default unload handle for all the network drivers.
-
- @param ImageHandle The drivers' driver image.
-
- @retval EFI_SUCCESS The image is unloaded.
- @retval Others Failed to unload the image.
-
-**/
-EFI_STATUS
-EFIAPI
-NetLibDefaultUnload (
- IN EFI_HANDLE ImageHandle
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE *DeviceHandleBuffer;
- UINTN DeviceHandleCount;
- UINTN Index;
- EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
-#if (EFI_SPECIFICATION_VERSION >= 0x00020000)
- EFI_COMPONENT_NAME2_PROTOCOL *ComponentName;
-#else
- EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
-#endif
- EFI_DRIVER_CONFIGURATION_PROTOCOL *DriverConfiguration;
- EFI_DRIVER_DIAGNOSTICS_PROTOCOL *DriverDiagnostics;
-
- //
- // Get the list of all the handles in the handle database.
- // If there is an error getting the list, then the unload
- // operation fails.
- //
- Status = gBS->LocateHandleBuffer (
- AllHandles,
- NULL,
- NULL,
- &DeviceHandleCount,
- &DeviceHandleBuffer
- );
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Disconnect the driver specified by ImageHandle from all
- // the devices in the handle database.
- //
- for (Index = 0; Index < DeviceHandleCount; Index++) {
- Status = gBS->DisconnectController (
- DeviceHandleBuffer[Index],
- ImageHandle,
- NULL
- );
- }
-
- //
- // Uninstall all the protocols installed in the driver entry point
- //
- for (Index = 0; Index < DeviceHandleCount; Index++) {
- Status = gBS->HandleProtocol (
- DeviceHandleBuffer[Index],
- &gEfiDriverBindingProtocolGuid,
- (VOID **) &DriverBinding
- );
-
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- if (DriverBinding->ImageHandle != ImageHandle) {
- continue;
- }
-
- gBS->UninstallProtocolInterface (
- ImageHandle,
- &gEfiDriverBindingProtocolGuid,
- DriverBinding
- );
- Status = gBS->HandleProtocol (
- DeviceHandleBuffer[Index],
- &gEfiComponentNameProtocolGuid,
- (VOID **) &ComponentName
- );
- if (!EFI_ERROR (Status)) {
- gBS->UninstallProtocolInterface (
- ImageHandle,
- &gEfiComponentNameProtocolGuid,
- ComponentName
- );
- }
-
- Status = gBS->HandleProtocol (
- DeviceHandleBuffer[Index],
- &gEfiDriverConfigurationProtocolGuid,
- (VOID **) &DriverConfiguration
- );
-
- if (!EFI_ERROR (Status)) {
- gBS->UninstallProtocolInterface (
- ImageHandle,
- &gEfiDriverConfigurationProtocolGuid,
- DriverConfiguration
- );
- }
-
- Status = gBS->HandleProtocol (
- DeviceHandleBuffer[Index],
- &gEfiDriverDiagnosticsProtocolGuid,
- (VOID **) &DriverDiagnostics
- );
-
- if (!EFI_ERROR (Status)) {
- gBS->UninstallProtocolInterface (
- ImageHandle,
- &gEfiDriverDiagnosticsProtocolGuid,
- DriverDiagnostics
- );
- }
- }
-
- //
- // Free the buffer containing the list of handles from the handle database
- //
- if (DeviceHandleBuffer != NULL) {
- gBS->FreePool (DeviceHandleBuffer);
- }
-
- return EFI_SUCCESS;
-}
-
-
-
-/**
- Create a child of the service that is identified by ServiceBindingGuid.
-
- @param Controller The controller which has the service installed.
- @param Image The image handle used to open service.
- @param ServiceBindingGuid The service's Guid.
- @param ChildHandle The handle to receive the create child
-
- @retval EFI_SUCCESS The child is successfully created.
- @retval Others Failed to create the child.
-
-**/
-EFI_STATUS
-NetLibCreateServiceChild (
- IN EFI_HANDLE Controller,
- IN EFI_HANDLE Image,
- IN EFI_GUID *ServiceBindingGuid,
- OUT EFI_HANDLE *ChildHandle
- )
-{
- EFI_STATUS Status;
- EFI_SERVICE_BINDING_PROTOCOL *Service;
-
-
- ASSERT ((ServiceBindingGuid != NULL) && (ChildHandle != NULL));
-
- //
- // Get the ServiceBinding Protocol
- //
- Status = gBS->OpenProtocol (
- Controller,
- ServiceBindingGuid,
- (VOID **) &Service,
- Image,
- Controller,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Create a child
- //
- Status = Service->CreateChild (Service, ChildHandle);
- return Status;
-}
-
-
-/**
- Destory a child of the service that is identified by ServiceBindingGuid.
-
- @param Controller The controller which has the service installed.
- @param Image The image handle used to open service.
- @param ServiceBindingGuid The service's Guid.
- @param ChildHandle The child to destory
-
- @retval EFI_SUCCESS The child is successfully destoried.
- @retval Others Failed to destory the child.
-
-**/
-EFI_STATUS
-NetLibDestroyServiceChild (
- IN EFI_HANDLE Controller,
- IN EFI_HANDLE Image,
- IN EFI_GUID *ServiceBindingGuid,
- IN EFI_HANDLE ChildHandle
- )
-{
- EFI_STATUS Status;
- EFI_SERVICE_BINDING_PROTOCOL *Service;
-
- ASSERT (ServiceBindingGuid != NULL);
-
- //
- // Get the ServiceBinding Protocol
- //
- Status = gBS->OpenProtocol (
- Controller,
- ServiceBindingGuid,
- (VOID **) &Service,
- Image,
- Controller,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // destory the child
- //
- Status = Service->DestroyChild (Service, ChildHandle);
- return Status;
-}
-
-
-/**
- Convert the mac address of the simple network protocol installed on
- SnpHandle to a unicode string. Callers are responsible for freeing the
- string storage.
-
- @param SnpHandle The handle where the simple network protocol is
- installed on.
- @param ImageHandle The image handle used to act as the agent handle to
- get the simple network protocol.
- @param MacString The pointer to store the address of the string
- representation of the mac address.
-
- @retval EFI_OUT_OF_RESOURCES There are not enough memory resource.
- @retval other Failed to open the simple network protocol.
-
-**/
-EFI_STATUS
-NetLibGetMacString (
- IN EFI_HANDLE SnpHandle,
- IN EFI_HANDLE ImageHandle,
- IN OUT CHAR16 **MacString
- )
-{
- EFI_STATUS Status;
- EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
- EFI_SIMPLE_NETWORK_MODE *Mode;
- CHAR16 *MacAddress;
- UINTN Index;
-
- *MacString = NULL;
-
- //
- // Get the Simple Network protocol from the SnpHandle.
- //
- Status = gBS->OpenProtocol (
- SnpHandle,
- &gEfiSimpleNetworkProtocolGuid,
- (VOID **) &Snp,
- ImageHandle,
- SnpHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Mode = Snp->Mode;
-
- //
- // It takes 2 unicode characters to represent a 1 byte binary buffer.
- // Plus one unicode character for the null-terminator.
- //
- MacAddress = NetAllocatePool ((2 * Mode->HwAddressSize + 1) * sizeof (CHAR16));
- if (MacAddress == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Convert the mac address into a unicode string.
- //
- for (Index = 0; Index < Mode->HwAddressSize; Index++) {
- MacAddress[Index * 2] = NibbleToHexChar ((UINT8) (Mode->CurrentAddress.Addr[Index] >> 4));
- MacAddress[Index * 2 + 1] = NibbleToHexChar (Mode->CurrentAddress.Addr[Index]);
- }
-
- MacAddress[Mode->HwAddressSize * 2] = L'\0';
-
- *MacString = MacAddress;
-
- return EFI_SUCCESS;
-}
-
-
-/**
- Find the UNDI/SNP handle from controller and protocol GUID.
- For example, IP will open a MNP child to transmit/receive
- packets, when MNP is stopped, IP should also be stopped. IP
- needs to find its own private data which is related the IP's
- service binding instance that is install on UNDI/SNP handle.
- Now, the controller is either a MNP or ARP child handle. But
- IP opens these handle BY_DRIVER, use that info, we can get the
- UNDI/SNP handle.
-
- @param Controller Then protocol handle to check
- @param ProtocolGuid The protocol that is related with the handle.
-
- @return The UNDI/SNP handle or NULL.
-
-**/
-EFI_HANDLE
-NetLibGetNicHandle (
- IN EFI_HANDLE Controller,
- IN EFI_GUID *ProtocolGuid
- )
-{
- EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenBuffer;
- EFI_HANDLE Handle;
- EFI_STATUS Status;
- UINTN OpenCount;
- UINTN Index;
-
- Status = gBS->OpenProtocolInformation (
- Controller,
- ProtocolGuid,
- &OpenBuffer,
- &OpenCount
- );
-
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- Handle = NULL;
-
- for (Index = 0; Index < OpenCount; Index++) {
- if (OpenBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) {
- Handle = OpenBuffer[Index].ControllerHandle;
- break;
- }
- }
-
- gBS->FreePool (OpenBuffer);
- return Handle;
-}
-
-EFI_STATUS
-NetLibInstallAllDriverProtocols (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable,
- IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
- IN EFI_HANDLE DriverBindingHandle,
- IN EFI_COMPONENT_NAME_PROTOCOL *ComponentName, OPTIONAL
- IN EFI_DRIVER_CONFIGURATION_PROTOCOL *DriverConfiguration, OPTIONAL
- IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *DriverDiagnostics OPTIONAL
- )
-/*++
-
-Routine Description:
-
- Intialize a driver by installing the Driver Binding Protocol onto the
- driver's DriverBindingHandle. This is typically the same as the driver's
- ImageHandle, but it can be different if the driver produces multiple
- DriverBinding Protocols. This function also initializes the EFI Driver
- Library that initializes the global variables gST, gBS, gRT.
-
-Arguments:
-
- ImageHandle - The image handle of the driver
- SystemTable - The EFI System Table that was passed to the driver's
- entry point
- DriverBinding - A Driver Binding Protocol instance that this driver
- is producing.
- DriverBindingHandle - The handle that DriverBinding is to be installe onto.
- If this parameter is NULL, then a new handle is created.
- ComponentName - A Component Name Protocol instance that this driver is
- producing.
- DriverConfiguration - A Driver Configuration Protocol instance that this
- driver is producing.
- DriverDiagnostics - A Driver Diagnostics Protocol instance that this
- driver is producing.
-
-Returns:
-
- EFI_SUCCESS if all the protocols were installed onto DriverBindingHandle
- Otherwise, then return status from gBS->InstallProtocolInterface()
-
---*/
-{
- return NetLibInstallAllDriverProtocolsWithUnload (
- ImageHandle,
- SystemTable,
- DriverBinding,
- DriverBindingHandle,
- ComponentName,
- DriverConfiguration,
- DriverDiagnostics,
- NetLibDefaultUnload
- );
-}
-
-EFI_STATUS
-NetLibInstallAllDriverProtocolsWithUnload (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable,
- IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
- IN EFI_HANDLE DriverBindingHandle,
- IN EFI_COMPONENT_NAME_PROTOCOL *ComponentName, OPTIONAL
- IN EFI_DRIVER_CONFIGURATION_PROTOCOL *DriverConfiguration, OPTIONAL
- IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *DriverDiagnostics, OPTIONAL
- IN NET_LIB_DRIVER_UNLOAD Unload
- )
-/*++
-
-Routine Description:
-
- Intialize a driver by installing the Driver Binding Protocol onto the
- driver's DriverBindingHandle. This is typically the same as the driver's
- ImageHandle, but it can be different if the driver produces multiple
- DriverBinding Protocols. This function also initializes the EFI Driver
- Library that initializes the global variables gST, gBS, gRT.
-
-Arguments:
-
- ImageHandle - The image handle of the driver
- SystemTable - The EFI System Table that was passed to the driver's
- entry point
- DriverBinding - A Driver Binding Protocol instance that this driver
- is producing.
- DriverBindingHandle - The handle that DriverBinding is to be installe onto.
- If this parameter is NULL, then a new handle is created.
- ComponentName - A Component Name Protocol instance that this driver is
- producing.
- DriverConfiguration - A Driver Configuration Protocol instance that this
- driver is producing.
- DriverDiagnostics - A Driver Diagnostics Protocol instance that this
- driver is producing.
- Unload - The customized unload to install.
-
-Returns:
-
- EFI_SUCCESS if all the protocols were installed onto DriverBindingHandle
- Otherwise, then return status from gBS->InstallProtocolInterface()
-
---*/
-{
- EFI_STATUS Status;
- EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
-
- Status = EfiLibInstallAllDriverProtocols (
- ImageHandle,
- SystemTable,
- DriverBinding,
- DriverBindingHandle,
- ComponentName,
- DriverConfiguration,
- DriverDiagnostics
- );
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Retrieve the Loaded Image Protocol from Image Handle
- //
- Status = gBS->OpenProtocol (
- ImageHandle,
- &gEfiLoadedImageProtocolGuid,
- (VOID **) &LoadedImage,
- ImageHandle,
- ImageHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Fill in the Unload() service of the Loaded Image Protocol
- //
- LoadedImage->Unload = (Unload == NULL) ? NetLibDefaultUnload : Unload;
- return EFI_SUCCESS;
-}
-
+/**\r
+ Return the length of the mask. If the mask is invalid,\r
+ return the invalid length 33, which is IP4_MASK_NUM.\r
+ NetMask is in the host byte order.\r
+\r
+ @param NetMask The netmask to get the length from\r
+\r
+ @return The length of the netmask, IP4_MASK_NUM if the mask isn't\r
+ @return supported.\r
+\r
+**/\r
+INTN\r
+NetGetMaskLength (\r
+ IN IP4_ADDR NetMask\r
+ )\r
+{\r
+ INTN Index;\r
+\r
+ for (Index = 0; Index < IP4_MASK_NUM; Index++) {\r
+ if (NetMask == mIp4AllMasks[Index]) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ return Index;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Return the class of the address, such as class a, b, c.\r
+ Addr is in host byte order.\r
+\r
+ @param Addr The address to get the class from\r
+\r
+ @return IP address class, such as IP4_ADDR_CLASSA\r
+\r
+**/\r
+INTN\r
+NetGetIpClass (\r
+ IN IP4_ADDR Addr\r
+ )\r
+{\r
+ UINT8 ByteOne;\r
+\r
+ ByteOne = (UINT8) (Addr >> 24);\r
+\r
+ if ((ByteOne & 0x80) == 0) {\r
+ return IP4_ADDR_CLASSA;\r
+\r
+ } else if ((ByteOne & 0xC0) == 0x80) {\r
+ return IP4_ADDR_CLASSB;\r
+\r
+ } else if ((ByteOne & 0xE0) == 0xC0) {\r
+ return IP4_ADDR_CLASSC;\r
+\r
+ } else if ((ByteOne & 0xF0) == 0xE0) {\r
+ return IP4_ADDR_CLASSD;\r
+\r
+ } else {\r
+ return IP4_ADDR_CLASSE;\r
+\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Check whether the IP is a valid unicast address according to\r
+ the netmask. If NetMask is zero, use the IP address's class to\r
+ get the default mask.\r
+\r
+ @param Ip The IP to check againist\r
+ @param NetMask The mask of the IP\r
+\r
+ @return TRUE if IP is a valid unicast address on the network, otherwise FALSE\r
+\r
+**/\r
+BOOLEAN\r
+Ip4IsUnicast (\r
+ IN IP4_ADDR Ip,\r
+ IN IP4_ADDR NetMask\r
+ )\r
+{\r
+ INTN Class;\r
+\r
+ Class = NetGetIpClass (Ip);\r
+\r
+ if ((Ip == 0) || (Class >= IP4_ADDR_CLASSD)) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (NetMask == 0) {\r
+ NetMask = mIp4AllMasks[Class << 3];\r
+ }\r
+\r
+ if (((Ip &~NetMask) == ~NetMask) || ((Ip &~NetMask) == 0)) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+/**\r
+ Initialize a random seed using current time.\r
+\r
+ None\r
+\r
+ @return The random seed initialized with current time.\r
+\r
+**/\r
+UINT32\r
+NetRandomInitSeed (\r
+ VOID\r
+ )\r
+{\r
+ EFI_TIME Time;\r
+ UINT32 Seed;\r
+\r
+ gRT->GetTime (&Time, NULL);\r
+ Seed = (~Time.Hour << 24 | Time.Second << 16 | Time.Minute << 8 | Time.Day);\r
+ Seed ^= Time.Nanosecond;\r
+ Seed ^= Time.Year << 7;\r
+\r
+ return Seed;\r
+}\r
+\r
+\r
+/**\r
+ Extract a UINT32 from a byte stream, then convert it to host\r
+ byte order. Use this function to avoid alignment error.\r
+\r
+ @param Buf The buffer to extract the UINT32.\r
+\r
+ @return The UINT32 extracted.\r
+\r
+**/\r
+UINT32\r
+NetGetUint32 (\r
+ IN UINT8 *Buf\r
+ )\r
+{\r
+ UINT32 Value;\r
+\r
+ NetCopyMem (&Value, Buf, sizeof (UINT32));\r
+ return NTOHL (Value);\r
+}\r
+\r
+\r
+/**\r
+ Put a UINT32 to the byte stream. Convert it from host byte order\r
+ to network byte order before putting.\r
+\r
+ @param Buf The buffer to put the UINT32\r
+ @param Data The data to put\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+NetPutUint32 (\r
+ IN UINT8 *Buf,\r
+ IN UINT32 Data\r
+ )\r
+{\r
+ Data = HTONL (Data);\r
+ NetCopyMem (Buf, &Data, sizeof (UINT32));\r
+}\r
+\r
+\r
+/**\r
+ Remove the first entry on the list\r
+\r
+ @param Head The list header\r
+\r
+ @return The entry that is removed from the list, NULL if the list is empty.\r
+\r
+**/\r
+NET_LIST_ENTRY *\r
+NetListRemoveHead (\r
+ NET_LIST_ENTRY *Head\r
+ )\r
+{\r
+ NET_LIST_ENTRY *First;\r
+\r
+ ASSERT (Head != NULL);\r
+\r
+ if (NetListIsEmpty (Head)) {\r
+ return NULL;\r
+ }\r
+\r
+ First = Head->ForwardLink;\r
+ Head->ForwardLink = First->ForwardLink;\r
+ First->ForwardLink->BackLink = Head;\r
+\r
+ DEBUG_CODE (\r
+ First->ForwardLink = (LIST_ENTRY *) NULL;\r
+ First->BackLink = (LIST_ENTRY *) NULL;\r
+ );\r
+\r
+ return First;\r
+}\r
+\r
+\r
+/**\r
+ Remove the last entry on the list\r
+\r
+ @param Head The list head\r
+\r
+ @return The entry that is removed from the list, NULL if the list is empty.\r
+\r
+**/\r
+NET_LIST_ENTRY *\r
+NetListRemoveTail (\r
+ NET_LIST_ENTRY *Head\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Last;\r
+\r
+ ASSERT (Head != NULL);\r
+\r
+ if (NetListIsEmpty (Head)) {\r
+ return NULL;\r
+ }\r
+\r
+ Last = Head->BackLink;\r
+ Head->BackLink = Last->BackLink;\r
+ Last->BackLink->ForwardLink = Head;\r
+\r
+ DEBUG_CODE (\r
+ Last->ForwardLink = (LIST_ENTRY *) NULL;\r
+ Last->BackLink = (LIST_ENTRY *) NULL;\r
+ );\r
+\r
+ return Last;\r
+}\r
+\r
+\r
+/**\r
+ Insert the NewEntry after the PrevEntry\r
+\r
+ @param PrevEntry The previous entry to insert after\r
+ @param NewEntry The new entry to insert\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+NetListInsertAfter (\r
+ IN NET_LIST_ENTRY *PrevEntry,\r
+ IN NET_LIST_ENTRY *NewEntry\r
+ )\r
+{\r
+ NewEntry->BackLink = PrevEntry;\r
+ NewEntry->ForwardLink = PrevEntry->ForwardLink;\r
+ PrevEntry->ForwardLink->BackLink = NewEntry;\r
+ PrevEntry->ForwardLink = NewEntry;\r
+}\r
+\r
+\r
+/**\r
+ Insert the NewEntry before the PostEntry\r
+\r
+ @param PostEntry The entry to insert before\r
+ @param NewEntry The new entry to insert\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+NetListInsertBefore (\r
+ IN NET_LIST_ENTRY *PostEntry,\r
+ IN NET_LIST_ENTRY *NewEntry\r
+ )\r
+{\r
+ NewEntry->ForwardLink = PostEntry;\r
+ NewEntry->BackLink = PostEntry->BackLink;\r
+ PostEntry->BackLink->ForwardLink = NewEntry;\r
+ PostEntry->BackLink = NewEntry;\r
+}\r
+\r
+\r
+/**\r
+ Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.\r
+\r
+ @param Map The netmap to initialize\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+NetMapInit (\r
+ IN NET_MAP *Map\r
+ )\r
+{\r
+ ASSERT (Map != NULL);\r
+\r
+ NetListInit (&Map->Used);\r
+ NetListInit (&Map->Recycled);\r
+ Map->Count = 0;\r
+}\r
+\r
+\r
+/**\r
+ To clean up the netmap, that is, release allocated memories.\r
+\r
+ @param Map The netmap to clean up.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+NetMapClean (\r
+ IN NET_MAP *Map\r
+ )\r
+{\r
+ NET_MAP_ITEM *Item;\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+\r
+ ASSERT (Map != NULL);\r
+\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Used) {\r
+ Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
+\r
+ NetListRemoveEntry (&Item->Link);\r
+ Map->Count--;\r
+\r
+ NetFreePool (Item);\r
+ }\r
+\r
+ ASSERT ((Map->Count == 0) && NetListIsEmpty (&Map->Used));\r
+\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Recycled) {\r
+ Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
+\r
+ NetListRemoveEntry (&Item->Link);\r
+ NetFreePool (Item);\r
+ }\r
+\r
+ ASSERT (NetListIsEmpty (&Map->Recycled));\r
+}\r
+\r
+\r
+/**\r
+ Test whether the netmap is empty\r
+\r
+ @param Map The net map to test\r
+\r
+ @return TRUE if the netmap is empty, otherwise FALSE.\r
+\r
+**/\r
+BOOLEAN\r
+NetMapIsEmpty (\r
+ IN NET_MAP *Map\r
+ )\r
+{\r
+ ASSERT (Map != NULL);\r
+ return (BOOLEAN) (Map->Count == 0);\r
+}\r
+\r
+\r
+/**\r
+ Return the number of the <Key, Value> pairs in the netmap.\r
+\r
+ @param Map The netmap to get the entry number\r
+\r
+ @return The entry number in the netmap.\r
+\r
+**/\r
+UINTN\r
+NetMapGetCount (\r
+ IN NET_MAP *Map\r
+ )\r
+{\r
+ return Map->Count;\r
+}\r
+\r
+\r
+/**\r
+ Allocate an item for the netmap. It will try to allocate\r
+ a batch of items and return one.\r
+\r
+ @param Map The netmap to allocate item for\r
+\r
+ @return The allocated item or NULL\r
+\r
+**/\r
+STATIC\r
+NET_MAP_ITEM *\r
+NetMapAllocItem (\r
+ IN NET_MAP *Map\r
+ )\r
+{\r
+ NET_MAP_ITEM *Item;\r
+ NET_LIST_ENTRY *Head;\r
+ UINTN Index;\r
+\r
+ ASSERT (Map != NULL);\r
+\r
+ Head = &Map->Recycled;\r
+\r
+ if (NetListIsEmpty (Head)) {\r
+ for (Index = 0; Index < NET_MAP_INCREAMENT; Index++) {\r
+ Item = NetAllocatePool (sizeof (NET_MAP_ITEM));\r
+\r
+ if (Item == NULL) {\r
+ if (Index == 0) {\r
+ return NULL;\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ NetListInsertHead (Head, &Item->Link);\r
+ }\r
+ }\r
+\r
+ Item = NET_LIST_HEAD (Head, NET_MAP_ITEM, Link);\r
+ NetListRemoveHead (Head);\r
+\r
+ return Item;\r
+}\r
+\r
+\r
+/**\r
+ Allocate an item to save the <Key, Value> pair to the head of the netmap.\r
+\r
+ @param Map The netmap to insert into\r
+ @param Key The user's key\r
+ @param Value The user's value for the key\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item\r
+ @retval EFI_SUCCESS The item is inserted to the head\r
+\r
+**/\r
+EFI_STATUS\r
+NetMapInsertHead (\r
+ IN NET_MAP *Map,\r
+ IN VOID *Key,\r
+ IN VOID *Value OPTIONAL\r
+ )\r
+{\r
+ NET_MAP_ITEM *Item;\r
+\r
+ ASSERT (Map != NULL);\r
+\r
+ Item = NetMapAllocItem (Map);\r
+\r
+ if (Item == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Item->Key = Key;\r
+ Item->Value = Value;\r
+ NetListInsertHead (&Map->Used, &Item->Link);\r
+\r
+ Map->Count++;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Allocate an item to save the <Key, Value> pair to the tail of the netmap.\r
+\r
+ @param Map The netmap to insert into\r
+ @param Key The user's key\r
+ @param Value The user's value for the key\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item\r
+ @retval EFI_SUCCESS The item is inserted to the tail\r
+\r
+**/\r
+EFI_STATUS\r
+NetMapInsertTail (\r
+ IN NET_MAP *Map,\r
+ IN VOID *Key,\r
+ IN VOID *Value OPTIONAL\r
+ )\r
+{\r
+ NET_MAP_ITEM *Item;\r
+\r
+ ASSERT (Map != NULL);\r
+\r
+ Item = NetMapAllocItem (Map);\r
+\r
+ if (Item == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Item->Key = Key;\r
+ Item->Value = Value;\r
+ NetListInsertTail (&Map->Used, &Item->Link);\r
+\r
+ Map->Count++;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Check whther the item is in the Map\r
+\r
+ @param Map The netmap to search within\r
+ @param Item The item to search\r
+\r
+ @return TRUE if the item is in the netmap, otherwise FALSE.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+NetItemInMap (\r
+ IN NET_MAP *Map,\r
+ IN NET_MAP_ITEM *Item\r
+ )\r
+{\r
+ NET_LIST_ENTRY *ListEntry;\r
+\r
+ NET_LIST_FOR_EACH (ListEntry, &Map->Used) {\r
+ if (ListEntry == &Item->Link) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+\r
+/**\r
+ Find the key in the netmap\r
+\r
+ @param Map The netmap to search within\r
+ @param Key The key to search\r
+\r
+ @return The point to the item contains the Key, or NULL if Key isn't in the map.\r
+\r
+**/\r
+NET_MAP_ITEM *\r
+NetMapFindKey (\r
+ IN NET_MAP *Map,\r
+ IN VOID *Key\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_MAP_ITEM *Item;\r
+\r
+ ASSERT (Map != NULL);\r
+\r
+ NET_LIST_FOR_EACH (Entry, &Map->Used) {\r
+ Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
+\r
+ if (Item->Key == Key) {\r
+ return Item;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Remove the item from the netmap\r
+\r
+ @param Map The netmap to remove the item from\r
+ @param Item The item to remove\r
+ @param Value The variable to receive the value if not NULL\r
+\r
+ @return The key of the removed item.\r
+\r
+**/\r
+VOID *\r
+NetMapRemoveItem (\r
+ IN NET_MAP *Map,\r
+ IN NET_MAP_ITEM *Item,\r
+ OUT VOID **Value OPTIONAL\r
+ )\r
+{\r
+ ASSERT ((Map != NULL) && (Item != NULL));\r
+ ASSERT (NetItemInMap (Map, Item));\r
+\r
+ NetListRemoveEntry (&Item->Link);\r
+ Map->Count--;\r
+ NetListInsertHead (&Map->Recycled, &Item->Link);\r
+\r
+ if (Value != NULL) {\r
+ *Value = Item->Value;\r
+ }\r
+\r
+ return Item->Key;\r
+}\r
+\r
+\r
+/**\r
+ Remove the first entry on the netmap\r
+\r
+ @param Map The netmap to remove the head from\r
+ @param Value The variable to receive the value if not NULL\r
+\r
+ @return The key of the item removed\r
+\r
+**/\r
+VOID *\r
+NetMapRemoveHead (\r
+ IN NET_MAP *Map,\r
+ OUT VOID **Value OPTIONAL\r
+ )\r
+{\r
+ NET_MAP_ITEM *Item;\r
+\r
+ //\r
+ // Often, it indicates a programming error to remove\r
+ // the first entry in an empty list\r
+ //\r
+ ASSERT (Map && !NetListIsEmpty (&Map->Used));\r
+\r
+ Item = NET_LIST_HEAD (&Map->Used, NET_MAP_ITEM, Link);\r
+ NetListRemoveEntry (&Item->Link);\r
+ Map->Count--;\r
+ NetListInsertHead (&Map->Recycled, &Item->Link);\r
+\r
+ if (Value != NULL) {\r
+ *Value = Item->Value;\r
+ }\r
+\r
+ return Item->Key;\r
+}\r
+\r
+\r
+/**\r
+ Remove the last entry on the netmap\r
+\r
+ @param Map The netmap to remove the tail from\r
+ @param Value The variable to receive the value if not NULL\r
+\r
+ @return The key of the item removed\r
+\r
+**/\r
+VOID *\r
+NetMapRemoveTail (\r
+ IN NET_MAP *Map,\r
+ OUT VOID **Value OPTIONAL\r
+ )\r
+{\r
+ NET_MAP_ITEM *Item;\r
+\r
+ //\r
+ // Often, it indicates a programming error to remove\r
+ // the last entry in an empty list\r
+ //\r
+ ASSERT (Map && !NetListIsEmpty (&Map->Used));\r
+\r
+ Item = NET_LIST_TAIL (&Map->Used, NET_MAP_ITEM, Link);\r
+ NetListRemoveEntry (&Item->Link);\r
+ Map->Count--;\r
+ NetListInsertHead (&Map->Recycled, &Item->Link);\r
+\r
+ if (Value != NULL) {\r
+ *Value = Item->Value;\r
+ }\r
+\r
+ return Item->Key;\r
+}\r
+\r
+\r
+/**\r
+ Iterate through the netmap and call CallBack for each item. It will\r
+ contiue the traverse if CallBack returns EFI_SUCCESS, otherwise, break\r
+ from the loop. It returns the CallBack's last return value. This\r
+ function is delete safe for the current item.\r
+\r
+ @param Map The Map to iterate through\r
+ @param CallBack The callback function to call for each item.\r
+ @param Arg The opaque parameter to the callback\r
+\r
+ @return It returns the CallBack's last return value.\r
+\r
+**/\r
+EFI_STATUS\r
+NetMapIterate (\r
+ IN NET_MAP *Map,\r
+ IN NET_MAP_CALLBACK CallBack,\r
+ IN VOID *Arg\r
+ )\r
+{\r
+\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ NET_LIST_ENTRY *Head;\r
+ NET_MAP_ITEM *Item;\r
+ EFI_STATUS Result;\r
+\r
+ ASSERT ((Map != NULL) && (CallBack != NULL));\r
+\r
+ Head = &Map->Used;\r
+\r
+ if (NetListIsEmpty (Head)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {\r
+ Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
+ Result = CallBack (Map, Item, Arg);\r
+\r
+ if (EFI_ERROR (Result)) {\r
+ return Result;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This is the default unload handle for all the network drivers.\r
+\r
+ @param ImageHandle The drivers' driver image.\r
+\r
+ @retval EFI_SUCCESS The image is unloaded.\r
+ @retval Others Failed to unload the image.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NetLibDefaultUnload (\r
+ IN EFI_HANDLE ImageHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE *DeviceHandleBuffer;\r
+ UINTN DeviceHandleCount;\r
+ UINTN Index;\r
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;\r
+ EFI_COMPONENT_NAME_PROTOCOL *ComponentName;\r
+ EFI_DRIVER_CONFIGURATION_PROTOCOL *DriverConfiguration;\r
+ EFI_DRIVER_DIAGNOSTICS_PROTOCOL *DriverDiagnostics;\r
+\r
+ //\r
+ // Get the list of all the handles in the handle database.\r
+ // If there is an error getting the list, then the unload\r
+ // operation fails.\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ AllHandles,\r
+ NULL,\r
+ NULL,\r
+ &DeviceHandleCount,\r
+ &DeviceHandleBuffer\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Disconnect the driver specified by ImageHandle from all\r
+ // the devices in the handle database.\r
+ //\r
+ for (Index = 0; Index < DeviceHandleCount; Index++) {\r
+ Status = gBS->DisconnectController (\r
+ DeviceHandleBuffer[Index],\r
+ ImageHandle,\r
+ NULL\r
+ );\r
+ }\r
+\r
+ //\r
+ // Uninstall all the protocols installed in the driver entry point\r
+ //\r
+ for (Index = 0; Index < DeviceHandleCount; Index++) {\r
+ Status = gBS->HandleProtocol (\r
+ DeviceHandleBuffer[Index],\r
+ &gEfiDriverBindingProtocolGuid,\r
+ (VOID **) &DriverBinding\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ if (DriverBinding->ImageHandle != ImageHandle) {\r
+ continue;\r
+ }\r
+\r
+ gBS->UninstallProtocolInterface (\r
+ ImageHandle,\r
+ &gEfiDriverBindingProtocolGuid,\r
+ DriverBinding\r
+ );\r
+ Status = gBS->HandleProtocol (\r
+ DeviceHandleBuffer[Index],\r
+ &gEfiComponentNameProtocolGuid,\r
+ (VOID **) &ComponentName\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ gBS->UninstallProtocolInterface (\r
+ ImageHandle,\r
+ &gEfiComponentNameProtocolGuid,\r
+ ComponentName\r
+ );\r
+ }\r
+\r
+ Status = gBS->HandleProtocol (\r
+ DeviceHandleBuffer[Index],\r
+ &gEfiDriverConfigurationProtocolGuid,\r
+ (VOID **) &DriverConfiguration\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ gBS->UninstallProtocolInterface (\r
+ ImageHandle,\r
+ &gEfiDriverConfigurationProtocolGuid,\r
+ DriverConfiguration\r
+ );\r
+ }\r
+\r
+ Status = gBS->HandleProtocol (\r
+ DeviceHandleBuffer[Index],\r
+ &gEfiDriverDiagnosticsProtocolGuid,\r
+ (VOID **) &DriverDiagnostics\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ gBS->UninstallProtocolInterface (\r
+ ImageHandle,\r
+ &gEfiDriverDiagnosticsProtocolGuid,\r
+ DriverDiagnostics\r
+ );\r
+ }\r
+ }\r
+\r
+ //\r
+ // Free the buffer containing the list of handles from the handle database\r
+ //\r
+ if (DeviceHandleBuffer != NULL) {\r
+ gBS->FreePool (DeviceHandleBuffer);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Create a child of the service that is identified by ServiceBindingGuid.\r
+\r
+ @param Controller The controller which has the service installed.\r
+ @param Image The image handle used to open service.\r
+ @param ServiceBindingGuid The service's Guid.\r
+ @param ChildHandle The handle to receive the create child\r
+\r
+ @retval EFI_SUCCESS The child is successfully created.\r
+ @retval Others Failed to create the child.\r
+\r
+**/\r
+EFI_STATUS\r
+NetLibCreateServiceChild (\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_HANDLE Image,\r
+ IN EFI_GUID *ServiceBindingGuid,\r
+ OUT EFI_HANDLE *ChildHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SERVICE_BINDING_PROTOCOL *Service;\r
+\r
+\r
+ ASSERT ((ServiceBindingGuid != NULL) && (ChildHandle != NULL));\r
+\r
+ //\r
+ // Get the ServiceBinding Protocol\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ ServiceBindingGuid,\r
+ (VOID **) &Service,\r
+ Image,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Create a child\r
+ //\r
+ Status = Service->CreateChild (Service, ChildHandle);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Destory a child of the service that is identified by ServiceBindingGuid.\r
+\r
+ @param Controller The controller which has the service installed.\r
+ @param Image The image handle used to open service.\r
+ @param ServiceBindingGuid The service's Guid.\r
+ @param ChildHandle The child to destory\r
+\r
+ @retval EFI_SUCCESS The child is successfully destoried.\r
+ @retval Others Failed to destory the child.\r
+\r
+**/\r
+EFI_STATUS\r
+NetLibDestroyServiceChild (\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_HANDLE Image,\r
+ IN EFI_GUID *ServiceBindingGuid,\r
+ IN EFI_HANDLE ChildHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SERVICE_BINDING_PROTOCOL *Service;\r
+\r
+ ASSERT (ServiceBindingGuid != NULL);\r
+\r
+ //\r
+ // Get the ServiceBinding Protocol\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ ServiceBindingGuid,\r
+ (VOID **) &Service,\r
+ Image,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // destory the child\r
+ //\r
+ Status = Service->DestroyChild (Service, ChildHandle);\r
+ return Status;\r
+}\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
+\r
+ @param SnpHandle The handle where the simple network protocol is\r
+ installed on.\r
+ @param ImageHandle The image handle used to act as the agent handle to\r
+ get the simple network protocol.\r
+ @param MacString The pointer to store the address of the string\r
+ representation of the mac address.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough memory resource.\r
+ @retval other Failed to open the simple network protocol.\r
+\r
+**/\r
+EFI_STATUS\r
+NetLibGetMacString (\r
+ IN EFI_HANDLE SnpHandle,\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN 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
+ UINTN Index;\r
+\r
+ *MacString = NULL;\r
+\r
+ //\r
+ // Get the Simple Network protocol from the SnpHandle.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ SnpHandle,\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ (VOID **) &Snp,\r
+ ImageHandle,\r
+ SnpHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\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
+ // Plus one unicode character for the null-terminator.\r
+ //\r
+ MacAddress = NetAllocatePool ((2 * Mode->HwAddressSize + 1) * sizeof (CHAR16));\r
+ if (MacAddress == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Convert the mac address into a unicode string.\r
+ //\r
+ for (Index = 0; Index < Mode->HwAddressSize; Index++) {\r
+ MacAddress[Index * 2] = NibbleToHexChar ((UINT8) (Mode->CurrentAddress.Addr[Index] >> 4));\r
+ MacAddress[Index * 2 + 1] = NibbleToHexChar (Mode->CurrentAddress.Addr[Index]);\r
+ }\r
+\r
+ MacAddress[Mode->HwAddressSize * 2] = L'\0';\r
+\r
+ *MacString = MacAddress;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Check the default address used by the IPv4 driver is static or dynamic (acquired\r
+ from DHCP).\r
+\r
+ @param Controller The controller handle which has the NIC Ip4 Config Protocol\r
+ relative with the default address to judge.\r
+\r
+ @retval TRUE If the default address is static.\r
+ @retval FALSE If the default address is acquired from DHCP.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+NetLibDefaultAddressIsStatic (\r
+ IN EFI_HANDLE Controller\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_NIC_IP4_CONFIG_PROTOCOL *NicIp4;\r
+ UINTN Len;\r
+ NIC_IP4_CONFIG_INFO *ConfigInfo;\r
+ BOOLEAN IsStatic;\r
+\r
+ Status = gBS->HandleProtocol (\r
+ Controller,\r
+ &gEfiNicIp4ConfigProtocolGuid,\r
+ (VOID **) &NicIp4\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return TRUE;\r
+ }\r
+\r
+ Len = 0;\r
+ Status = NicIp4->GetInfo (NicIp4, &Len, NULL);\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ return TRUE;\r
+ }\r
+\r
+ ConfigInfo = NetAllocatePool (Len);\r
+ if (ConfigInfo == NULL) {\r
+ return TRUE;\r
+ }\r
+\r
+ IsStatic = TRUE;\r
+ Status = NicIp4->GetInfo (NicIp4, &Len, ConfigInfo);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ IsStatic = (BOOLEAN) (ConfigInfo->Source == IP4_CONFIG_SOURCE_STATIC);\r
+\r
+ON_EXIT:\r
+\r
+ NetFreePool (ConfigInfo);\r
+\r
+ return IsStatic;\r
+}\r
+\r
+/**\r
+ Create an IPv4 device path node.\r
+\r
+ @param Node Pointer to the IPv4 device path node.\r
+ @param Controller The handle where the NIC IP4 config protocol resides.\r
+ @param LocalIp The local IPv4 address.\r
+ @param LocalPort The local port.\r
+ @param RemoteIp The remote IPv4 address.\r
+ @param RemotePort The remote port.\r
+ @param Protocol The protocol type in the IP header.\r
+ @param UseDefaultAddress Whether this instance is using default address or not.\r
+\r
+ @retval None\r
+**/\r
+VOID\r
+NetLibCreateIPv4DPathNode (\r
+ IN OUT IPv4_DEVICE_PATH *Node,\r
+ IN EFI_HANDLE Controller,\r
+ IN IP4_ADDR LocalIp,\r
+ IN UINT16 LocalPort,\r
+ IN IP4_ADDR RemoteIp,\r
+ IN UINT16 RemotePort,\r
+ IN UINT16 Protocol,\r
+ IN BOOLEAN UseDefaultAddress\r
+ )\r
+{\r
+ Node->Header.Type = MESSAGING_DEVICE_PATH;\r
+ Node->Header.SubType = MSG_IPv4_DP;\r
+ SetDevicePathNodeLength (&Node->Header, 19);\r
+\r
+ NetCopyMem (&Node->LocalIpAddress, &LocalIp, sizeof (EFI_IPv4_ADDRESS));\r
+ NetCopyMem (&Node->RemoteIpAddress, &RemoteIp, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+ Node->LocalPort = LocalPort;\r
+ Node->RemotePort = RemotePort;\r
+\r
+ Node->Protocol = Protocol;\r
+\r
+ if (!UseDefaultAddress) {\r
+ Node->StaticIpAddress = TRUE;\r
+ } else {\r
+ Node->StaticIpAddress = NetLibDefaultAddressIsStatic (Controller);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Find the UNDI/SNP handle from controller and protocol GUID.\r
+ For example, IP will open a MNP child to transmit/receive\r
+ packets, when MNP is stopped, IP should also be stopped. IP\r
+ needs to find its own private data which is related the IP's\r
+ service binding instance that is install on UNDI/SNP handle.\r
+ Now, the controller is either a MNP or ARP child handle. But\r
+ IP opens these handle BY_DRIVER, use that info, we can get the\r
+ UNDI/SNP handle.\r
+\r
+ @param Controller Then protocol handle to check\r
+ @param ProtocolGuid The protocol that is related with the handle.\r
+\r
+ @return The UNDI/SNP handle or NULL.\r
+\r
+**/\r
+EFI_HANDLE\r
+NetLibGetNicHandle (\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_GUID *ProtocolGuid\r
+ )\r
+{\r
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenBuffer;\r
+ EFI_HANDLE Handle;\r
+ EFI_STATUS Status;\r
+ UINTN OpenCount;\r
+ UINTN Index;\r
+\r
+ Status = gBS->OpenProtocolInformation (\r
+ Controller,\r
+ ProtocolGuid,\r
+ &OpenBuffer,\r
+ &OpenCount\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ Handle = NULL;\r
+\r
+ for (Index = 0; Index < OpenCount; Index++) {\r
+ if (OpenBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) {\r
+ Handle = OpenBuffer[Index].ControllerHandle;\r
+ break;\r
+ }\r
+ }\r
+\r
+ gBS->FreePool (OpenBuffer);\r
+ return Handle;\r
+}\r
+\r