git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@5384 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1659 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1659 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| 
 | |
| Copyright (c) 2006 - 2008, Intel Corporation
 | |
| All rights reserved. This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions of the BSD License
 | |
| which accompanies this distribution.  The full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| Module Name:
 | |
| 
 | |
|   ArpImpl.c
 | |
| 
 | |
| Abstract:
 | |
| 
 | |
| 
 | |
| **/
 | |
| 
 | |
| 
 | |
| #include "ArpImpl.h"
 | |
| 
 | |
| EFI_ARP_PROTOCOL  mEfiArpProtocolTemplate = {
 | |
|   ArpConfigure,
 | |
|   ArpAdd,
 | |
|   ArpFind,
 | |
|   ArpDelete,
 | |
|   ArpFlush,
 | |
|   ArpRequest,
 | |
|   ArpCancel
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Initialize the instance context data.
 | |
| 
 | |
|   @param  ArpService             Pointer to the arp service context data this
 | |
|                                  instance belongs to.
 | |
|   @param  Instance               Pointer to the instance context data.
 | |
| 
 | |
|   @return None.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| ArpInitInstance (
 | |
|   IN ARP_SERVICE_DATA   *ArpService,
 | |
|   IN ARP_INSTANCE_DATA  *Instance
 | |
|   )
 | |
| {
 | |
|   NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);
 | |
| 
 | |
|   Instance->Signature  = ARP_INSTANCE_DATA_SIGNATURE;
 | |
|   Instance->ArpService = ArpService;
 | |
| 
 | |
|   CopyMem (&Instance->ArpProto, &mEfiArpProtocolTemplate, sizeof (Instance->ArpProto));
 | |
| 
 | |
|   Instance->Configured = FALSE;
 | |
|   Instance->Destroyed  = FALSE;
 | |
| 
 | |
|   InitializeListHead (&Instance->List);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Process the Arp packets received from Mnp, the procedure conforms to RFC826.
 | |
| 
 | |
|   @param  Context                Pointer to the context data registerd to the
 | |
|                                  Event.
 | |
| 
 | |
|   @return None.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| ArpOnFrameRcvdDpc (
 | |
|   IN VOID       *Context
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                            Status;
 | |
|   ARP_SERVICE_DATA                      *ArpService;
 | |
|   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *RxToken;
 | |
|   EFI_MANAGED_NETWORK_RECEIVE_DATA      *RxData;
 | |
|   ARP_HEAD                              *Head;
 | |
|   ARP_ADDRESS                           ArpAddress;
 | |
|   ARP_CACHE_ENTRY                       *CacheEntry;
 | |
|   LIST_ENTRY                            *Entry;
 | |
|   ARP_INSTANCE_DATA                     *Instance;
 | |
|   EFI_ARP_CONFIG_DATA                   *ConfigData;
 | |
|   NET_ARP_ADDRESS                       SenderAddress[2];
 | |
|   BOOLEAN                               ProtoMatched;
 | |
|   BOOLEAN                               IsTarget;
 | |
|   BOOLEAN                               MergeFlag;
 | |
| 
 | |
|   ArpService = (ARP_SERVICE_DATA *)Context;
 | |
|   NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);
 | |
| 
 | |
|   RxToken = &ArpService->RxToken;
 | |
| 
 | |
|   if (RxToken->Status == EFI_ABORTED) {
 | |
|     //
 | |
|     // The Token is aborted, possibly by arp itself, just return and the receiving
 | |
|     // process is stopped.
 | |
|     //
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (RxToken->Status)) {
 | |
|     //
 | |
|     // Restart the receiving if any other error Status occurs.
 | |
|     //
 | |
|     goto RESTART_RECEIVE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Status is EFI_SUCCESS, process the received frame.
 | |
|   //
 | |
|   RxData = RxToken->Packet.RxData;
 | |
|   Head   = (ARP_HEAD *) RxData->PacketData;
 | |
| 
 | |
|   //
 | |
|   // Convert the byte order of the multi-byte fields.
 | |
|   //
 | |
|   Head->HwType    = NTOHS (Head->HwType);
 | |
|   Head->ProtoType = NTOHS (Head->ProtoType);
 | |
|   Head->OpCode    = NTOHS (Head->OpCode);
 | |
| 
 | |
|   if ((Head->HwType != ArpService->SnpMode.IfType) ||
 | |
|     (Head->HwAddrLen != ArpService->SnpMode.HwAddressSize) ||
 | |
|     (RxData->ProtocolType != ARP_ETHER_PROTO_TYPE)) {
 | |
|     //
 | |
|     // The hardware type or the hardware address length doesn't match.
 | |
|     // There is a sanity check for the protocol type too.
 | |
|     //
 | |
|     goto RECYCLE_RXDATA;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set the pointers to the addresses contained in the arp packet.
 | |
|   //
 | |
|   ArpAddress.SenderHwAddr    = (UINT8 *)(Head + 1);
 | |
|   ArpAddress.SenderProtoAddr = ArpAddress.SenderHwAddr + Head->HwAddrLen;
 | |
|   ArpAddress.TargetHwAddr    = ArpAddress.SenderProtoAddr + Head->ProtoAddrLen;
 | |
|   ArpAddress.TargetProtoAddr = ArpAddress.TargetHwAddr + Head->HwAddrLen;
 | |
| 
 | |
|   SenderAddress[Hardware].Type       = Head->HwType;
 | |
|   SenderAddress[Hardware].Length     = Head->HwAddrLen;
 | |
|   SenderAddress[Hardware].AddressPtr = ArpAddress.SenderHwAddr;
 | |
| 
 | |
|   SenderAddress[Protocol].Type       = Head->ProtoType;
 | |
|   SenderAddress[Protocol].Length     = Head->ProtoAddrLen;
 | |
|   SenderAddress[Protocol].AddressPtr = ArpAddress.SenderProtoAddr;
 | |
| 
 | |
|   //
 | |
|   // First, check the denied cache table.
 | |
|   //
 | |
|   CacheEntry = ArpFindDeniedCacheEntry (
 | |
|                  ArpService,
 | |
|                  &SenderAddress[Protocol],
 | |
|                  &SenderAddress[Hardware]
 | |
|                  );
 | |
|   if (CacheEntry != NULL) {
 | |
|     //
 | |
|     // This address (either hardware or protocol address, or both) is configured to
 | |
|     // be a deny entry, silently skip the normal process.
 | |
|     //
 | |
|     goto RECYCLE_RXDATA;
 | |
|   }
 | |
| 
 | |
|   ProtoMatched = FALSE;
 | |
|   IsTarget     = FALSE;
 | |
|   Instance     = NULL;
 | |
|   NET_LIST_FOR_EACH (Entry, &ArpService->ChildrenList) {
 | |
|     //
 | |
|     // Iterate all the children.
 | |
|     //
 | |
|     Instance = NET_LIST_USER_STRUCT (Entry, ARP_INSTANCE_DATA, List);
 | |
|     NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);
 | |
|     ConfigData = &Instance->ConfigData;
 | |
| 
 | |
|     if ((Instance->Configured) &&
 | |
|       (Head->ProtoType == ConfigData->SwAddressType) &&
 | |
|       (Head->ProtoAddrLen == ConfigData->SwAddressLength)) {
 | |
|       //
 | |
|       // The protocol type is matched for the received arp packet.
 | |
|       //
 | |
|       ProtoMatched = TRUE;
 | |
|       if (0 == CompareMem (
 | |
|                  (VOID *)ArpAddress.TargetProtoAddr,
 | |
|                  ConfigData->StationAddress,
 | |
|                  ConfigData->SwAddressLength
 | |
|                  )) {
 | |
|         //
 | |
|         // The arp driver has the target address required by the received arp packet.
 | |
|         //
 | |
|         IsTarget = TRUE;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!ProtoMatched) {
 | |
|     //
 | |
|     // Protocol type unmatchable, skip.
 | |
|     //
 | |
|     goto RECYCLE_RXDATA;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check whether the sender's address information is already in the cache.
 | |
|   //
 | |
|   MergeFlag  = FALSE;
 | |
|   CacheEntry = ArpFindNextCacheEntryInTable (
 | |
|                  &ArpService->ResolvedCacheTable,
 | |
|                  NULL,
 | |
|                  ByProtoAddress,
 | |
|                  &SenderAddress[Protocol],
 | |
|                  NULL
 | |
|                  );
 | |
|   if (CacheEntry != NULL) {
 | |
|     //
 | |
|     // Update the entry with the new information.
 | |
|     //
 | |
|     ArpFillAddressInCacheEntry (CacheEntry, &SenderAddress[Hardware], NULL);
 | |
|     CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;
 | |
|     MergeFlag = TRUE;
 | |
|   }
 | |
| 
 | |
|   if (!IsTarget) {
 | |
|     //
 | |
|     // This arp packet isn't targeted to us, skip now.
 | |
|     //
 | |
|     goto RECYCLE_RXDATA;
 | |
|   }
 | |
| 
 | |
|   if (!MergeFlag) {
 | |
|     //
 | |
|     // Add the triplet <protocol type, sender protocol address, sender hardware address>
 | |
|     // to the translation table.
 | |
|     //
 | |
|     CacheEntry = ArpFindNextCacheEntryInTable (
 | |
|                    &ArpService->PendingRequestTable,
 | |
|                    NULL,
 | |
|                    ByProtoAddress,
 | |
|                    &SenderAddress[Protocol],
 | |
|                    NULL
 | |
|                    );
 | |
|     if (CacheEntry == NULL) {
 | |
|       //
 | |
|       // Allocate a new CacheEntry.
 | |
|       //
 | |
|       CacheEntry = ArpAllocCacheEntry (NULL);
 | |
|       if (CacheEntry == NULL) {
 | |
|         goto RECYCLE_RXDATA;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (!IsListEmpty (&CacheEntry->List)) {
 | |
|       RemoveEntryList (&CacheEntry->List);
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Fill the addresses into the CacheEntry.
 | |
|     //
 | |
|     ArpFillAddressInCacheEntry (
 | |
|       CacheEntry,
 | |
|       &SenderAddress[Hardware],
 | |
|       &SenderAddress[Protocol]
 | |
|       );
 | |
| 
 | |
|     //
 | |
|     // Inform the user.
 | |
|     //
 | |
|     ArpAddressResolved (CacheEntry, NULL, NULL);
 | |
| 
 | |
|     //
 | |
|     // Add this entry into the ResolvedCacheTable
 | |
|     //
 | |
|     InsertHeadList (&ArpService->ResolvedCacheTable, &CacheEntry->List);
 | |
|   }
 | |
| 
 | |
|   if (Head->OpCode == ARP_OPCODE_REQUEST) {
 | |
|     //
 | |
|     // Send back the ARP Reply. If we reach here, Instance is not NULL and CacheEntry
 | |
|     // is not NULL.
 | |
|     //
 | |
|     ArpSendFrame (Instance, CacheEntry, ARP_OPCODE_REPLY);
 | |
|   }
 | |
| 
 | |
| RECYCLE_RXDATA:
 | |
| 
 | |
|   //
 | |
|   // Signal Mnp to recycle the RxData.
 | |
|   //
 | |
|   gBS->SignalEvent (RxData->RecycleEvent);
 | |
| 
 | |
| RESTART_RECEIVE:
 | |
| 
 | |
|   //
 | |
|   // Continue to receive packets from Mnp.
 | |
|   //
 | |
|   Status = ArpService->Mnp->Receive (ArpService->Mnp, RxToken);
 | |
| 
 | |
|   DEBUG_CODE (
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "ArpOnFrameRcvd: ArpService->Mnp->Receive "
 | |
|         "failed, %r\n.", Status));
 | |
|     }
 | |
|   );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Queue ArpOnFrameRcvdDpc as a DPC at TPL_CALLBACK.
 | |
| 
 | |
|   @param  Event                  The Event this notify function registered to.
 | |
|   @param  Context                Pointer to the context data registerd to the
 | |
|                                  Event.
 | |
| 
 | |
|   @return None.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| ArpOnFrameRcvd (
 | |
|   IN EFI_EVENT  Event,
 | |
|   IN VOID       *Context
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // Request ArpOnFrameRcvdDpc as a DPC at TPL_CALLBACK
 | |
|   //
 | |
|   NetLibQueueDpc (TPL_CALLBACK, ArpOnFrameRcvdDpc, Context);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Process the already sent arp packets.
 | |
| 
 | |
|   @param  Context                Pointer to the context data registerd to the
 | |
|                                  Event.
 | |
| 
 | |
|   @return None.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| ArpOnFrameSentDpc (
 | |
|   IN VOID       *Context
 | |
|   )
 | |
| {
 | |
|   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TxToken;
 | |
|   EFI_MANAGED_NETWORK_TRANSMIT_DATA     *TxData;
 | |
| 
 | |
|   ASSERT (Context != NULL);
 | |
| 
 | |
|   TxToken = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *)Context;
 | |
|   TxData  = TxToken->Packet.TxData;
 | |
| 
 | |
|   DEBUG_CODE (
 | |
|     if (EFI_ERROR (TxToken->Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "ArpOnFrameSent: TxToken->Status, %r.\n", TxToken->Status));
 | |
|     }
 | |
|   );
 | |
| 
 | |
|   //
 | |
|   // Free the allocated memory and close the event.
 | |
|   //
 | |
|   gBS->FreePool (TxData->FragmentTable[0].FragmentBuffer);
 | |
|   gBS->FreePool (TxData);
 | |
|   gBS->CloseEvent (TxToken->Event);
 | |
|   gBS->FreePool (TxToken);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Request ArpOnFrameSentDpc as a DPC at TPL_CALLBACK.
 | |
| 
 | |
|   @param  Event                  The Event this notify function registered to.
 | |
|   @param  Context                Pointer to the context data registerd to the
 | |
|                                  Event.
 | |
| 
 | |
|   @return None.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| ArpOnFrameSent (
 | |
|   IN EFI_EVENT  Event,
 | |
|   IN VOID       *Context
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // Request ArpOnFrameSentDpc as a DPC at TPL_CALLBACK
 | |
|   //
 | |
|   NetLibQueueDpc (TPL_CALLBACK, ArpOnFrameSentDpc, Context);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Process the arp cache olding and drive the retrying arp requests.
 | |
| 
 | |
|   @param  Event                  The Event this notify function registered to.
 | |
|   @param  Context                Pointer to the context data registerd to the
 | |
|                                  Event.
 | |
| 
 | |
|   @return None.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| ArpTimerHandler (
 | |
|   IN EFI_EVENT  Event,
 | |
|   IN VOID       *Context
 | |
|   )
 | |
| {
 | |
|   ARP_SERVICE_DATA      *ArpService;
 | |
|   LIST_ENTRY            *Entry;
 | |
|   LIST_ENTRY            *NextEntry;
 | |
|   LIST_ENTRY            *ContextEntry;
 | |
|   ARP_CACHE_ENTRY       *CacheEntry;
 | |
|   USER_REQUEST_CONTEXT  *RequestContext;
 | |
| 
 | |
|   ASSERT (Context != NULL);
 | |
|   ArpService = (ARP_SERVICE_DATA *)Context;
 | |
| 
 | |
|   //
 | |
|   // Iterate all the pending requests to see whether a retry is needed to send out
 | |
|   // or the request finally fails because the retry time reaches the limitation.
 | |
|   //
 | |
|   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->PendingRequestTable) {
 | |
|     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
 | |
| 
 | |
|     if (CacheEntry->NextRetryTime <= ARP_PERIODIC_TIMER_INTERVAL) {
 | |
|       //
 | |
|       // Timeout, if we can retry more, send out the request again, otherwise abort
 | |
|       // this request.
 | |
|       //
 | |
|       if (CacheEntry->RetryCount == 0) {
 | |
|         //
 | |
|         // Abort this request.
 | |
|         //
 | |
|         ArpAddressResolved (CacheEntry, NULL, NULL);
 | |
|         ASSERT (IsListEmpty (&CacheEntry->UserRequestList));
 | |
| 
 | |
|         RemoveEntryList (&CacheEntry->List);
 | |
|         gBS->FreePool (CacheEntry);
 | |
|       } else {
 | |
|         //
 | |
|         // resend the ARP request.
 | |
|         //
 | |
|         ASSERT (!IsListEmpty(&CacheEntry->UserRequestList));
 | |
| 
 | |
|         ContextEntry   = CacheEntry->UserRequestList.ForwardLink;
 | |
|         RequestContext = NET_LIST_USER_STRUCT (ContextEntry, USER_REQUEST_CONTEXT, List);
 | |
| 
 | |
|         ArpSendFrame (RequestContext->Instance, CacheEntry, ARP_OPCODE_REQUEST);
 | |
| 
 | |
|         CacheEntry->RetryCount--;
 | |
|         CacheEntry->NextRetryTime = RequestContext->Instance->ConfigData.RetryTimeOut;
 | |
|       }
 | |
|     } else {
 | |
|       //
 | |
|       // Update the NextRetryTime.
 | |
|       //
 | |
|       CacheEntry->NextRetryTime -= ARP_PERIODIC_TIMER_INTERVAL;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check the timeouts for the DeniedCacheTable.
 | |
|   //
 | |
|   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->DeniedCacheTable) {
 | |
|     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
 | |
|     ASSERT (IsListEmpty (&CacheEntry->UserRequestList));
 | |
| 
 | |
|     if (CacheEntry->DefaultDecayTime == 0) {
 | |
|       //
 | |
|       // It's a static entry, skip it.
 | |
|       //
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (CacheEntry->DecayTime <= ARP_PERIODIC_TIMER_INTERVAL) {
 | |
|       //
 | |
|       // Time out, remove it.
 | |
|       //
 | |
|       RemoveEntryList (&CacheEntry->List);
 | |
|       gBS->FreePool (CacheEntry);
 | |
|     } else {
 | |
|       //
 | |
|       // Update the DecayTime.
 | |
|       //
 | |
|       CacheEntry->DecayTime -= ARP_PERIODIC_TIMER_INTERVAL;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check the timeouts for the ResolvedCacheTable.
 | |
|   //
 | |
|   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->ResolvedCacheTable) {
 | |
|     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
 | |
|     ASSERT (IsListEmpty (&CacheEntry->UserRequestList));
 | |
| 
 | |
|     if (CacheEntry->DefaultDecayTime == 0) {
 | |
|       //
 | |
|       // It's a static entry, skip it.
 | |
|       //
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (CacheEntry->DecayTime <= ARP_PERIODIC_TIMER_INTERVAL) {
 | |
|       //
 | |
|       // Time out, remove it.
 | |
|       //
 | |
|       RemoveEntryList (&CacheEntry->List);
 | |
|       gBS->FreePool (CacheEntry);
 | |
|     } else {
 | |
|       //
 | |
|       // Update the DecayTime.
 | |
|       //
 | |
|       CacheEntry->DecayTime -= ARP_PERIODIC_TIMER_INTERVAL;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Match the two NET_ARP_ADDRESSes.
 | |
| 
 | |
|   @param  AddressOne             Pointer to the first address to match.
 | |
|   @param  AddressTwo             Pointer to the second address to match.
 | |
| 
 | |
|   @return The two addresses match or not.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| ArpMatchAddress (
 | |
|   IN NET_ARP_ADDRESS  *AddressOne,
 | |
|   IN NET_ARP_ADDRESS  *AddressTwo
 | |
|   )
 | |
| {
 | |
|   if ((AddressOne->Type != AddressTwo->Type) ||
 | |
|     (AddressOne->Length != AddressTwo->Length)) {
 | |
|     //
 | |
|     // Either Type or Length doesn't match.
 | |
|     //
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if ((AddressOne->AddressPtr != NULL) &&
 | |
|     (CompareMem (
 | |
|       AddressOne->AddressPtr,
 | |
|       AddressTwo->AddressPtr,
 | |
|       AddressOne->Length
 | |
|       ) != 0)) {
 | |
|     //
 | |
|     // The address is not the same.
 | |
|     //
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Find the CacheEntry which matches the requirements in the specified CacheTable.
 | |
| 
 | |
|   @param  CacheTable             Pointer to the arp cache table.
 | |
|   @param  StartEntry             Pointer to the start entry this search begins with
 | |
|                                  in the cache table.
 | |
|   @param  FindOpType             The search type.
 | |
|   @param  ProtocolAddress        Pointer to the protocol address to match.
 | |
|   @param  HardwareAddress        Pointer to the hardware address to match.
 | |
| 
 | |
|   @return Pointer to the matched arp cache entry, if NULL, no match is found.
 | |
| 
 | |
| **/
 | |
| ARP_CACHE_ENTRY *
 | |
| ArpFindNextCacheEntryInTable (
 | |
|   IN LIST_ENTRY        *CacheTable,
 | |
|   IN LIST_ENTRY        *StartEntry,
 | |
|   IN FIND_OPTYPE       FindOpType,
 | |
|   IN NET_ARP_ADDRESS   *ProtocolAddress OPTIONAL,
 | |
|   IN NET_ARP_ADDRESS   *HardwareAddress OPTIONAL
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY       *Entry;
 | |
|   ARP_CACHE_ENTRY  *CacheEntry;
 | |
| 
 | |
|   if (StartEntry == NULL) {
 | |
|     //
 | |
|     // Start from the beginning of the table if no StartEntry is specified.
 | |
|     //
 | |
|     StartEntry = CacheTable;
 | |
|   }
 | |
| 
 | |
|   for (Entry = StartEntry->ForwardLink; Entry != CacheTable; Entry = Entry->ForwardLink) {
 | |
|     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
 | |
| 
 | |
|     if ((FindOpType & MATCH_SW_ADDRESS) != 0) {
 | |
|       //
 | |
|       // Find by the software address.
 | |
|       //
 | |
|       if (!ArpMatchAddress (ProtocolAddress, &CacheEntry->Addresses[Protocol])) {
 | |
|         //
 | |
|         // The ProtocolAddress doesn't match, continue to the next cache entry.
 | |
|         //
 | |
|         continue;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if ((FindOpType & MATCH_HW_ADDRESS) != 0) {
 | |
|       //
 | |
|       // Find by the hardware address.
 | |
|       //
 | |
|       if (!ArpMatchAddress (HardwareAddress, &CacheEntry->Addresses[Hardware])) {
 | |
|         //
 | |
|         // The HardwareAddress doesn't match, continue to the next cache entry.
 | |
|         //
 | |
|         continue;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // The CacheEntry meets the requirements now, return this entry.
 | |
|     //
 | |
|     return CacheEntry;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // No matching.
 | |
|   //
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Find the CacheEntry, using ProtocolAddress or HardwareAddress or both, as the keyword,
 | |
|   in the DeniedCacheTable.
 | |
| 
 | |
|   @param  ArpService             Pointer to the arp service context data.
 | |
|   @param  ProtocolAddress        Pointer to the protocol address.
 | |
|   @param  HardwareAddress        Pointer to the hardware address.
 | |
| 
 | |
|   @return Pointer to the matched cache entry, if NULL no match is found.
 | |
| 
 | |
| **/
 | |
| ARP_CACHE_ENTRY *
 | |
| ArpFindDeniedCacheEntry (
 | |
|   IN ARP_SERVICE_DATA  *ArpService,
 | |
|   IN NET_ARP_ADDRESS   *ProtocolAddress OPTIONAL,
 | |
|   IN NET_ARP_ADDRESS   *HardwareAddress OPTIONAL
 | |
|   )
 | |
| {
 | |
|   ARP_CACHE_ENTRY  *CacheEntry;
 | |
| 
 | |
|   ASSERT ((ProtocolAddress != NULL) || (HardwareAddress != NULL));
 | |
|   NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);
 | |
| 
 | |
|   CacheEntry = NULL;
 | |
| 
 | |
|   if ((ProtocolAddress != NULL) && (ProtocolAddress->AddressPtr != NULL)) {
 | |
|     //
 | |
|     // Find the cache entry in the DeniedCacheTable by the protocol address.
 | |
|     //
 | |
|     CacheEntry = ArpFindNextCacheEntryInTable (
 | |
|                    &ArpService->DeniedCacheTable,
 | |
|                    NULL,
 | |
|                    ByProtoAddress,
 | |
|                    ProtocolAddress,
 | |
|                    NULL
 | |
|                    );
 | |
|     if (CacheEntry != NULL) {
 | |
|       //
 | |
|       // There is a match.
 | |
|       //
 | |
|       return CacheEntry;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if ((HardwareAddress != NULL) && (HardwareAddress->AddressPtr != NULL)) {
 | |
|     //
 | |
|     // Find the cache entry in the DeniedCacheTable by the hardware address.
 | |
|     //
 | |
|     CacheEntry = ArpFindNextCacheEntryInTable (
 | |
|                    &ArpService->DeniedCacheTable,
 | |
|                    NULL,
 | |
|                    ByHwAddress,
 | |
|                    NULL,
 | |
|                    HardwareAddress
 | |
|                    );
 | |
|   }
 | |
| 
 | |
|   return CacheEntry;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Allocate a cache entry and initialize it.
 | |
| 
 | |
|   @param  Instance               Pointer to the instance context data.
 | |
| 
 | |
|   @return Pointer to the new created cache entry.
 | |
| 
 | |
| **/
 | |
| ARP_CACHE_ENTRY *
 | |
| ArpAllocCacheEntry (
 | |
|   IN ARP_INSTANCE_DATA  *Instance
 | |
|   )
 | |
| {
 | |
|   ARP_CACHE_ENTRY  *CacheEntry;
 | |
|   NET_ARP_ADDRESS  *Address;
 | |
|   UINT16           Index;
 | |
| 
 | |
|   //
 | |
|   // Allocate memory for the cache entry.
 | |
|   //
 | |
|   CacheEntry = AllocatePool (sizeof (ARP_CACHE_ENTRY));
 | |
|   if (CacheEntry == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Init the lists.
 | |
|   //
 | |
|   InitializeListHead (&CacheEntry->List);
 | |
|   InitializeListHead (&CacheEntry->UserRequestList);
 | |
| 
 | |
|   for (Index = 0; Index < 2; Index++) {
 | |
|     //
 | |
|     // Init the address pointers to point to the concrete buffer.
 | |
|     //
 | |
|     Address = &CacheEntry->Addresses[Index];
 | |
|     Address->AddressPtr = Address->Buffer.ProtoAddress;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Zero the hardware address first.
 | |
|   //
 | |
|   ZeroMem (CacheEntry->Addresses[Hardware].AddressPtr, ARP_MAX_HARDWARE_ADDRESS_LEN);
 | |
| 
 | |
|   if (Instance != NULL) {
 | |
|     //
 | |
|     // Inherit the parameters from the instance configuration.
 | |
|     //
 | |
|     CacheEntry->RetryCount       = Instance->ConfigData.RetryCount;
 | |
|     CacheEntry->NextRetryTime    = Instance->ConfigData.RetryTimeOut;
 | |
|     CacheEntry->DefaultDecayTime = Instance->ConfigData.EntryTimeOut;
 | |
|     CacheEntry->DecayTime        = Instance->ConfigData.EntryTimeOut;
 | |
|   } else {
 | |
|     //
 | |
|     // Use the default parameters if this cache entry isn't allocate in a
 | |
|     // instance's  scope.
 | |
|     //
 | |
|     CacheEntry->RetryCount       = ARP_DEFAULT_RETRY_COUNT;
 | |
|     CacheEntry->NextRetryTime    = ARP_DEFAULT_RETRY_INTERVAL;
 | |
|     CacheEntry->DefaultDecayTime = ARP_DEFAULT_TIMEOUT_VALUE;
 | |
|     CacheEntry->DecayTime        = ARP_DEFAULT_TIMEOUT_VALUE;
 | |
|   }
 | |
| 
 | |
|   return CacheEntry;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Turn the CacheEntry into the resolved status.
 | |
| 
 | |
|   @param  CacheEntry             Pointer to the resolved cache entry.
 | |
|   @param  Instance               Pointer to the instance context data.
 | |
|   @param  UserEvent              Pointer to the UserEvent to notify.
 | |
| 
 | |
|   @return The count of notifications sent to the instance.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| ArpAddressResolved (
 | |
|   IN ARP_CACHE_ENTRY    *CacheEntry,
 | |
|   IN ARP_INSTANCE_DATA  *Instance OPTIONAL,
 | |
|   IN EFI_EVENT          UserEvent OPTIONAL
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY            *Entry;
 | |
|   LIST_ENTRY            *NextEntry;
 | |
|   USER_REQUEST_CONTEXT  *Context;
 | |
|   UINTN                 Count;
 | |
| 
 | |
|   Count = 0;
 | |
| 
 | |
|   //
 | |
|   // Iterate all the linked user requests to notify them.
 | |
|   //
 | |
|   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &CacheEntry->UserRequestList) {
 | |
|     Context = NET_LIST_USER_STRUCT (Entry, USER_REQUEST_CONTEXT, List);
 | |
| 
 | |
|     if (((Instance == NULL) || (Context->Instance == Instance)) &&
 | |
|       ((UserEvent == NULL) || (Context->UserRequestEvent == UserEvent))) {
 | |
|       //
 | |
|       // Copy the address to the user-provided buffer and notify the user.
 | |
|       //
 | |
|       CopyMem (
 | |
|         Context->UserHwAddrBuffer,
 | |
|         CacheEntry->Addresses[Hardware].AddressPtr,
 | |
|         CacheEntry->Addresses[Hardware].Length
 | |
|         );
 | |
|       gBS->SignalEvent (Context->UserRequestEvent);
 | |
| 
 | |
|       //
 | |
|       // Remove this user request and free the context data.
 | |
|       //
 | |
|       RemoveEntryList (&Context->List);
 | |
|       gBS->FreePool (Context);
 | |
| 
 | |
|       Count++;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Dispatch the DPCs queued by the NotifyFunction of the Context->UserRequestEvent.
 | |
|   //
 | |
|   NetLibDispatchDpc ();
 | |
| 
 | |
|   return Count;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Fill the addresses in the CacheEntry using the information passed in by
 | |
|   HwAddr and SwAddr.
 | |
| 
 | |
|   @param  CacheEntry             Pointer to the cache entry.
 | |
|   @param  HwAddr                 Pointer to the software address.
 | |
|   @param  SwAddr                 Pointer to the hardware address.
 | |
| 
 | |
|   @return None.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| ArpFillAddressInCacheEntry (
 | |
|   IN ARP_CACHE_ENTRY  *CacheEntry,
 | |
|   IN NET_ARP_ADDRESS  *HwAddr OPTIONAL,
 | |
|   IN NET_ARP_ADDRESS  *SwAddr OPTIONAL
 | |
|   )
 | |
| {
 | |
|   NET_ARP_ADDRESS  *Address[2];
 | |
|   NET_ARP_ADDRESS  *CacheAddress;
 | |
|   UINT32           Index;
 | |
| 
 | |
|   Address[Hardware] = HwAddr;
 | |
|   Address[Protocol] = SwAddr;
 | |
| 
 | |
|   for (Index = 0; Index < 2; Index++) {
 | |
|     if (Address[Index] != NULL) {
 | |
|       //
 | |
|       // Fill the address if the passed in pointer is not NULL.
 | |
|       //
 | |
|       CacheAddress = &CacheEntry->Addresses[Index];
 | |
| 
 | |
|       CacheAddress->Type   = Address[Index]->Type;
 | |
|       CacheAddress->Length = Address[Index]->Length;
 | |
| 
 | |
|       if (Address[Index]->AddressPtr != NULL) {
 | |
|         //
 | |
|         // Copy it if the AddressPtr points to some buffer.
 | |
|         //
 | |
|         CopyMem (
 | |
|           CacheAddress->AddressPtr,
 | |
|           Address[Index]->AddressPtr,
 | |
|           CacheAddress->Length
 | |
|           );
 | |
|       } else {
 | |
|         //
 | |
|         // Zero the corresponding address buffer in the CacheEntry.
 | |
|         //
 | |
|         ZeroMem (CacheAddress->AddressPtr, CacheAddress->Length);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Configure the instance using the ConfigData. ConfigData is already validated.
 | |
| 
 | |
|   @param  Instance               Pointer to the instance context data to be
 | |
|                                  configured.
 | |
|   @param  ConfigData             Pointer to the configuration data used to
 | |
|                                  configure the instance.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The instance is configured with the ConfigData.
 | |
|   @retval EFI_ACCESS_DENIED      The instance is already configured and the
 | |
|                                  ConfigData tries to reset some unchangeable
 | |
|                                  fields.
 | |
|   @retval EFI_INVALID_PARAMETER  The ConfigData provides a non-unicast IPv4 address
 | |
|                                  when the SwAddressType is IPv4.
 | |
|   @retval EFI_OUT_OF_RESOURCES   The instance fails to configure due to memory
 | |
|                                  limitation.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ArpConfigureInstance (
 | |
|   IN ARP_INSTANCE_DATA    *Instance,
 | |
|   IN EFI_ARP_CONFIG_DATA  *ConfigData OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_ARP_CONFIG_DATA  *OldConfigData;
 | |
|   IP4_ADDR             Ip;
 | |
| 
 | |
|   OldConfigData = &Instance->ConfigData;
 | |
| 
 | |
|   if (ConfigData != NULL) {
 | |
| 
 | |
|     if (Instance->Configured) {
 | |
|       //
 | |
|       // The instance is configured, check the unchangeable fields.
 | |
|       //
 | |
|       if ((OldConfigData->SwAddressType != ConfigData->SwAddressType) ||
 | |
|         (OldConfigData->SwAddressLength != ConfigData->SwAddressLength) ||
 | |
|         (CompareMem (
 | |
|            OldConfigData->StationAddress,
 | |
|            ConfigData->StationAddress,
 | |
|            OldConfigData->SwAddressLength
 | |
|            ) != 0)) {
 | |
|         //
 | |
|         // Deny the unallowed changes.
 | |
|         //
 | |
|         return EFI_ACCESS_DENIED;
 | |
|       }
 | |
|     } else {
 | |
|       //
 | |
|       // The instance is not configured.
 | |
|       //
 | |
| 
 | |
|       if (ConfigData->SwAddressType == IPV4_ETHER_PROTO_TYPE) {
 | |
|         CopyMem (&Ip, ConfigData->StationAddress, sizeof (IP4_ADDR));
 | |
| 
 | |
|         if (!Ip4IsUnicast (NTOHL (Ip), 0)) {
 | |
|           //
 | |
|           // The station address is not a valid IPv4 unicast address.
 | |
|           //
 | |
|           return EFI_INVALID_PARAMETER;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Save the configuration.
 | |
|       //
 | |
|       CopyMem (OldConfigData, ConfigData, sizeof (*OldConfigData));
 | |
| 
 | |
|       OldConfigData->StationAddress = AllocatePool (OldConfigData->SwAddressLength);
 | |
|       if (OldConfigData->StationAddress == NULL) {
 | |
|         DEBUG ((EFI_D_ERROR, "ArpConfigInstance: AllocatePool for the StationAddress "
 | |
|           "failed.\n"));
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Save the StationAddress.
 | |
|       //
 | |
|       CopyMem (
 | |
|         OldConfigData->StationAddress,
 | |
|         ConfigData->StationAddress,
 | |
|         OldConfigData->SwAddressLength
 | |
|         );
 | |
| 
 | |
|       //
 | |
|       // Set the state to configured.
 | |
|       //
 | |
|       Instance->Configured = TRUE;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Use the implementation specific values if the following field is zero.
 | |
|     //
 | |
|     OldConfigData->EntryTimeOut = (ConfigData->EntryTimeOut == 0) ?
 | |
|       ARP_DEFAULT_TIMEOUT_VALUE : ConfigData->EntryTimeOut;
 | |
| 
 | |
|     OldConfigData->RetryCount   = (ConfigData->RetryCount == 0) ?
 | |
|       ARP_DEFAULT_RETRY_COUNT : ConfigData->RetryCount;
 | |
| 
 | |
|     OldConfigData->RetryTimeOut = (ConfigData->RetryTimeOut == 0) ?
 | |
|       ARP_DEFAULT_RETRY_INTERVAL : ConfigData->RetryTimeOut;
 | |
|   } else {
 | |
|     //
 | |
|     // Reset the configuration.
 | |
|     //
 | |
| 
 | |
|     if (Instance->Configured) {
 | |
|       //
 | |
|       // Cancel the arp requests issued by this instance.
 | |
|       //
 | |
|       Instance->ArpProto.Cancel (&Instance->ArpProto, NULL, NULL);
 | |
| 
 | |
|       //
 | |
|       // Free the buffer previously allocated to hold the station address.
 | |
|       //
 | |
|       gBS->FreePool (OldConfigData->StationAddress);
 | |
|     }
 | |
| 
 | |
|     Instance->Configured = FALSE;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Send out an arp frame using the CachEntry and the ArpOpCode.
 | |
| 
 | |
|   @param  Instance               Pointer to the instance context data.
 | |
|   @param  CacheEntry             Pointer to the configuration data used to
 | |
|                                  configure the instance.
 | |
|   @param  ArpOpCode              The opcode used to send out this Arp frame, either
 | |
|                                  request or reply.
 | |
| 
 | |
|   @return None.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| ArpSendFrame (
 | |
|   IN ARP_INSTANCE_DATA  *Instance,
 | |
|   IN ARP_CACHE_ENTRY    *CacheEntry,
 | |
|   IN UINT16             ArpOpCode
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                            Status;
 | |
|   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TxToken;
 | |
|   EFI_MANAGED_NETWORK_TRANSMIT_DATA     *TxData;
 | |
|   UINT32                                TotalLength;
 | |
|   UINT8                                 *Packet;
 | |
|   ARP_SERVICE_DATA                      *ArpService;
 | |
|   EFI_SIMPLE_NETWORK_MODE               *SnpMode;
 | |
|   EFI_ARP_CONFIG_DATA                   *ConfigData;
 | |
|   UINT8                                 *TmpPtr;
 | |
|   ARP_HEAD                              *ArpHead;
 | |
| 
 | |
|   ASSERT ((Instance != NULL) && (CacheEntry != NULL));
 | |
| 
 | |
|   //
 | |
|   // Allocate memory for the TxToken.
 | |
|   //
 | |
|   TxToken = AllocatePool (sizeof(EFI_MANAGED_NETWORK_COMPLETION_TOKEN));
 | |
|   if (TxToken == NULL) {
 | |
|     DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for TxToken failed.\n"));
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   TxToken->Event = NULL;
 | |
|   TxData         = NULL;
 | |
|   Packet         = NULL;
 | |
| 
 | |
|   //
 | |
|   // Create the event for this TxToken.
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   ArpOnFrameSent,
 | |
|                   (VOID *)TxToken,
 | |
|                   &TxToken->Event
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((EFI_D_ERROR, "ArpSendFrame: CreateEvent failed for TxToken->Event.\n"));
 | |
|     goto CLEAN_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate memory for the TxData used in the TxToken.
 | |
|   //
 | |
|   TxData = AllocatePool (sizeof(EFI_MANAGED_NETWORK_TRANSMIT_DATA));
 | |
|   if (TxData == NULL) {
 | |
|     DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for TxData failed.\n"));
 | |
|     goto CLEAN_EXIT;
 | |
|   }
 | |
| 
 | |
|   ArpService = Instance->ArpService;
 | |
|   SnpMode    = &ArpService->SnpMode;
 | |
|   ConfigData = &Instance->ConfigData;
 | |
| 
 | |
|   //
 | |
|   // Calculate the buffer length for this arp frame.
 | |
|   //
 | |
|   TotalLength = SnpMode->MediaHeaderSize + sizeof (ARP_HEAD) +
 | |
|                 2 * (ConfigData->SwAddressLength + SnpMode->HwAddressSize);
 | |
| 
 | |
|   //
 | |
|   // Allocate buffer for the arp frame.
 | |
|   //
 | |
|   Packet = AllocatePool (TotalLength);
 | |
|   if (Packet == NULL) {
 | |
|     DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for Packet failed.\n"));
 | |
|   }
 | |
| 
 | |
|   TmpPtr = Packet;
 | |
| 
 | |
|   //
 | |
|   // The destination MAC address.
 | |
|   //
 | |
|   if (ArpOpCode == ARP_OPCODE_REQUEST) {
 | |
|     CopyMem (TmpPtr, &SnpMode->BroadcastAddress, SnpMode->HwAddressSize);
 | |
|   } else {
 | |
|     CopyMem (
 | |
|       TmpPtr,
 | |
|       CacheEntry->Addresses[Hardware].AddressPtr,
 | |
|       SnpMode->HwAddressSize
 | |
|       );
 | |
|   }
 | |
|   TmpPtr += SnpMode->HwAddressSize;
 | |
| 
 | |
|   //
 | |
|   // The source MAC address.
 | |
|   //
 | |
|   CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);
 | |
|   TmpPtr += SnpMode->HwAddressSize;
 | |
| 
 | |
|   //
 | |
|   // The ethernet protocol type.
 | |
|   //
 | |
|   *(UINT16 *)TmpPtr = HTONS (ARP_ETHER_PROTO_TYPE);
 | |
|   TmpPtr            += 2;
 | |
| 
 | |
|   //
 | |
|   // The ARP Head.
 | |
|   //
 | |
|   ArpHead               = (ARP_HEAD *) TmpPtr;
 | |
|   ArpHead->HwType       = HTONS ((UINT16)SnpMode->IfType);
 | |
|   ArpHead->ProtoType    = HTONS (ConfigData->SwAddressType);
 | |
|   ArpHead->HwAddrLen    = (UINT8)SnpMode->HwAddressSize;
 | |
|   ArpHead->ProtoAddrLen = ConfigData->SwAddressLength;
 | |
|   ArpHead->OpCode       = HTONS (ArpOpCode);
 | |
|   TmpPtr                += sizeof (ARP_HEAD);
 | |
| 
 | |
|   //
 | |
|   // The sender hardware address.
 | |
|   //
 | |
|   CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);
 | |
|   TmpPtr += SnpMode->HwAddressSize;
 | |
| 
 | |
|   //
 | |
|   // The sender protocol address.
 | |
|   //
 | |
|   CopyMem (TmpPtr, ConfigData->StationAddress, ConfigData->SwAddressLength);
 | |
|   TmpPtr += ConfigData->SwAddressLength;
 | |
| 
 | |
|   //
 | |
|   // The target hardware address.
 | |
|   //
 | |
|   CopyMem (
 | |
|     TmpPtr,
 | |
|     CacheEntry->Addresses[Hardware].AddressPtr,
 | |
|     SnpMode->HwAddressSize
 | |
|     );
 | |
|   TmpPtr += SnpMode->HwAddressSize;
 | |
| 
 | |
|   //
 | |
|   // The target protocol address.
 | |
|   //
 | |
|   CopyMem (
 | |
|     TmpPtr,
 | |
|     CacheEntry->Addresses[Protocol].AddressPtr,
 | |
|     ConfigData->SwAddressLength
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Set all the fields of the TxData.
 | |
|   //
 | |
|   TxData->DestinationAddress = NULL;
 | |
|   TxData->SourceAddress      = NULL;
 | |
|   TxData->ProtocolType       = 0;
 | |
|   TxData->DataLength         = TotalLength - SnpMode->MediaHeaderSize;
 | |
|   TxData->HeaderLength       = (UINT16) SnpMode->MediaHeaderSize;
 | |
|   TxData->FragmentCount      = 1;
 | |
| 
 | |
|   TxData->FragmentTable[0].FragmentBuffer = Packet;
 | |
|   TxData->FragmentTable[0].FragmentLength = TotalLength;
 | |
| 
 | |
|   //
 | |
|   // Associate the TxData with the TxToken.
 | |
|   //
 | |
|   TxToken->Packet.TxData = TxData;
 | |
|   TxToken->Status        = EFI_NOT_READY;
 | |
| 
 | |
|   //
 | |
|   // Send out this arp packet by Mnp.
 | |
|   //
 | |
|   Status = ArpService->Mnp->Transmit (ArpService->Mnp, TxToken);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((EFI_D_ERROR, "Mnp->Transmit failed, %r.\n", Status));
 | |
|     goto CLEAN_EXIT;
 | |
|   }
 | |
| 
 | |
|   return;
 | |
| 
 | |
| CLEAN_EXIT:
 | |
| 
 | |
|   if (Packet != NULL) {
 | |
|     gBS->FreePool (Packet);
 | |
|   }
 | |
| 
 | |
|   if (TxData != NULL) {
 | |
|     gBS->FreePool (TxData);
 | |
|   }
 | |
| 
 | |
|   if (TxToken->Event != NULL) {
 | |
|     gBS->CloseEvent (TxToken->Event);
 | |
|   }
 | |
| 
 | |
|   gBS->FreePool (TxToken);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Delete the cache entries in the specified CacheTable, using the BySwAddress,
 | |
|   SwAddressType, AddressBuffer combination as the matching key, if Force is TRUE,
 | |
|   the cache is deleted event it's a static entry.
 | |
| 
 | |
|   @param  CacheTable             Pointer to the cache table to do the deletion.
 | |
|   @param  BySwAddress            Delete the cache entry by software address or by
 | |
|                                  hardware address.
 | |
|   @param  SwAddressType          The software address used to do the deletion.
 | |
|   @param  AddressBuffer          Pointer to the buffer containing the address to
 | |
|                                  match for the deletion.
 | |
|   @param  Force                  This deletion is forced or not.
 | |
| 
 | |
|   @return The count of the deleted cache entries.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| ArpDeleteCacheEntryInTable (
 | |
|   IN LIST_ENTRY      *CacheTable,
 | |
|   IN BOOLEAN         BySwAddress,
 | |
|   IN UINT16          SwAddressType,
 | |
|   IN UINT8           *AddressBuffer OPTIONAL,
 | |
|   IN BOOLEAN         Force
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY       *Entry;
 | |
|   LIST_ENTRY       *NextEntry;
 | |
|   ARP_CACHE_ENTRY  *CacheEntry;
 | |
|   UINTN            Count;
 | |
| 
 | |
|   Count = 0;
 | |
| 
 | |
|   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, CacheTable) {
 | |
|     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
 | |
| 
 | |
|     if ((CacheEntry->DefaultDecayTime == 0) && !Force) {
 | |
|       //
 | |
|       // It's a static entry and we are not forced to delete it, skip.
 | |
|       //
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (BySwAddress) {
 | |
|       if (SwAddressType == CacheEntry->Addresses[Protocol].Type) {
 | |
|         //
 | |
|         // Protocol address type matched. Check the address.
 | |
|         //
 | |
|         if ((AddressBuffer == NULL) ||
 | |
|           (CompareMem (
 | |
|              AddressBuffer,
 | |
|              CacheEntry->Addresses[Protocol].AddressPtr,
 | |
|              CacheEntry->Addresses[Protocol].Length
 | |
|              ) == 0)) {
 | |
|           //
 | |
|           // Address matched.
 | |
|           //
 | |
|           goto MATCHED;
 | |
|         }
 | |
|       }
 | |
|     } else {
 | |
|       if ((AddressBuffer == NULL) ||
 | |
|         (CompareMem (
 | |
|            AddressBuffer,
 | |
|            CacheEntry->Addresses[Hardware].AddressPtr,
 | |
|            CacheEntry->Addresses[Hardware].Length
 | |
|            ) == 0)) {
 | |
|         //
 | |
|         // Address matched.
 | |
|         //
 | |
|         goto MATCHED;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     continue;
 | |
| 
 | |
| MATCHED:
 | |
| 
 | |
|     //
 | |
|     // Delete this entry.
 | |
|     //
 | |
|     RemoveEntryList (&CacheEntry->List);
 | |
|     ASSERT (IsListEmpty (&CacheEntry->UserRequestList));
 | |
|     gBS->FreePool (CacheEntry);
 | |
| 
 | |
|     Count++;
 | |
|   }
 | |
| 
 | |
|   return Count;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Delete cache entries in all the cache tables.
 | |
| 
 | |
|   @param  Instance               Pointer to the instance context data.
 | |
|   @param  BySwAddress            Delete the cache entry by software address or by
 | |
|                                  hardware address.
 | |
|   @param  AddressBuffer          Pointer to the buffer containing the address to
 | |
|                                  match for the deletion.
 | |
|   @param  Force                  This deletion is forced or not.
 | |
| 
 | |
|   @return The count of the deleted cache entries.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| ArpDeleteCacheEntry (
 | |
|   IN ARP_INSTANCE_DATA  *Instance,
 | |
|   IN BOOLEAN            BySwAddress,
 | |
|   IN UINT8              *AddressBuffer OPTIONAL,
 | |
|   IN BOOLEAN            Force
 | |
|   )
 | |
| {
 | |
|   ARP_SERVICE_DATA  *ArpService;
 | |
|   UINTN             Count;
 | |
| 
 | |
|   NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);
 | |
| 
 | |
|   ArpService = Instance->ArpService;
 | |
| 
 | |
|   //
 | |
|   // Delete the cache entries in the DeniedCacheTable.
 | |
|   //
 | |
|   Count = ArpDeleteCacheEntryInTable (
 | |
|             &ArpService->DeniedCacheTable,
 | |
|             BySwAddress,
 | |
|             Instance->ConfigData.SwAddressType,
 | |
|             AddressBuffer,
 | |
|             Force
 | |
|             );
 | |
| 
 | |
|   //
 | |
|   // Delete the cache entries inthe ResolvedCacheTable.
 | |
|   //
 | |
|   Count += ArpDeleteCacheEntryInTable (
 | |
|              &ArpService->ResolvedCacheTable,
 | |
|              BySwAddress,
 | |
|              Instance->ConfigData.SwAddressType,
 | |
|              AddressBuffer,
 | |
|              Force
 | |
|              );
 | |
| 
 | |
|   return Count;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Cancel the arp request.
 | |
| 
 | |
|   @param  Instance               Pointer to the instance context data.
 | |
|   @param  TargetSwAddress        Pointer to the buffer containing the target
 | |
|                                  software address to match the arp request.
 | |
|   @param  UserEvent              The user event used to notify this request
 | |
|                                  cancellation.
 | |
| 
 | |
|   @return The count of the cancelled requests.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| ArpCancelRequest (
 | |
|   IN ARP_INSTANCE_DATA  *Instance,
 | |
|   IN VOID               *TargetSwAddress OPTIONAL,
 | |
|   IN EFI_EVENT          UserEvent        OPTIONAL
 | |
|   )
 | |
| {
 | |
|   ARP_SERVICE_DATA  *ArpService;
 | |
|   LIST_ENTRY        *Entry;
 | |
|   LIST_ENTRY        *NextEntry;
 | |
|   ARP_CACHE_ENTRY   *CacheEntry;
 | |
|   UINTN             Count;
 | |
| 
 | |
|   NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);
 | |
| 
 | |
|   ArpService = Instance->ArpService;
 | |
| 
 | |
|   Count = 0;
 | |
|   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->PendingRequestTable) {
 | |
|     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
 | |
| 
 | |
|     if ((TargetSwAddress == NULL) ||
 | |
|       (CompareMem (
 | |
|          TargetSwAddress,
 | |
|          CacheEntry->Addresses[Protocol].AddressPtr,
 | |
|          CacheEntry->Addresses[Protocol].Length
 | |
|          ) == 0)) {
 | |
|       //
 | |
|       // This request entry matches the TargetSwAddress or all requests are to be
 | |
|       // cancelled as TargetSwAddress is NULL.
 | |
|       //
 | |
|       Count += ArpAddressResolved (CacheEntry, Instance, UserEvent);
 | |
| 
 | |
|       if (IsListEmpty (&CacheEntry->UserRequestList)) {
 | |
|         //
 | |
|         // No user requests any more, remove this request cache entry.
 | |
|         //
 | |
|         RemoveEntryList (&CacheEntry->List);
 | |
|         gBS->FreePool (CacheEntry);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Count;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Find the cache entry in the cache table.
 | |
| 
 | |
|   @param  Instance               Pointer to the instance context data.
 | |
|   @param  BySwAddress            Set to TRUE to look for matching software protocol
 | |
|                                  addresses. Set to FALSE to look for matching
 | |
|                                  hardware protocol addresses.
 | |
|   @param  AddressBuffer          Pointer to address buffer. Set to NULL to match
 | |
|                                  all addresses.
 | |
|   @param  EntryLength            The size of an entry in the entries buffer.
 | |
|   @param  EntryCount             The number of ARP cache entries that are found by
 | |
|                                  the specified criteria.
 | |
|   @param  Entries                Pointer to the buffer that will receive the ARP
 | |
|                                  cache entries.
 | |
|   @param  Refresh                Set to TRUE to refresh the timeout value of the
 | |
|                                  matching ARP cache entry.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The requested ARP cache entries are copied into
 | |
|                                  the buffer.
 | |
|   @retval EFI_NOT_FOUND          No matching entries found.
 | |
|   @retval EFI_OUT_OF_RESOURCE    There is a memory allocation failure.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ArpFindCacheEntry (
 | |
|   IN ARP_INSTANCE_DATA   *Instance,
 | |
|   IN BOOLEAN             BySwAddress,
 | |
|   IN VOID                *AddressBuffer OPTIONAL,
 | |
|   OUT UINT32             *EntryLength   OPTIONAL,
 | |
|   OUT UINT32             *EntryCount    OPTIONAL,
 | |
|   OUT EFI_ARP_FIND_DATA  **Entries      OPTIONAL,
 | |
|   IN BOOLEAN             Refresh
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS         Status;
 | |
|   ARP_SERVICE_DATA   *ArpService;
 | |
|   NET_ARP_ADDRESS    MatchAddress;
 | |
|   FIND_OPTYPE        FindOpType;
 | |
|   LIST_ENTRY         *StartEntry;
 | |
|   ARP_CACHE_ENTRY    *CacheEntry;
 | |
|   NET_MAP            FoundEntries;
 | |
|   UINT32             FoundCount;
 | |
|   EFI_ARP_FIND_DATA  *FindData;
 | |
|   LIST_ENTRY         *CacheTable;
 | |
| 
 | |
|   ArpService = Instance->ArpService;
 | |
| 
 | |
|   //
 | |
|   // Init the FounEntries used to hold the found cache entries.
 | |
|   //
 | |
|   NetMapInit (&FoundEntries);
 | |
| 
 | |
|   //
 | |
|   // Set the MatchAddress.
 | |
|   //
 | |
|   if (BySwAddress) {
 | |
|     MatchAddress.Type   = Instance->ConfigData.SwAddressType;
 | |
|     MatchAddress.Length = Instance->ConfigData.SwAddressLength;
 | |
|     FindOpType          = ByProtoAddress;
 | |
|   } else {
 | |
|     MatchAddress.Type   = ArpService->SnpMode.IfType;
 | |
|     MatchAddress.Length = (UINT8)ArpService->SnpMode.HwAddressSize;
 | |
|     FindOpType          = ByHwAddress;
 | |
|   }
 | |
| 
 | |
|   MatchAddress.AddressPtr = AddressBuffer;
 | |
| 
 | |
|   //
 | |
|   // Search the DeniedCacheTable
 | |
|   //
 | |
|   StartEntry = NULL;
 | |
|   while (TRUE) {
 | |
|     //
 | |
|     // Try to find the matched entries in the DeniedCacheTable.
 | |
|     //
 | |
|     CacheEntry = ArpFindNextCacheEntryInTable (
 | |
|                    &ArpService->DeniedCacheTable,
 | |
|                    StartEntry,
 | |
|                    FindOpType,
 | |
|                    &MatchAddress,
 | |
|                    &MatchAddress
 | |
|                    );
 | |
|     if (CacheEntry == NULL) {
 | |
|       //
 | |
|       // Once the CacheEntry is NULL, there are no more matches.
 | |
|       //
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Insert the found entry into the map.
 | |
|     //
 | |
|     NetMapInsertTail (
 | |
|       &FoundEntries,
 | |
|       (VOID *)CacheEntry,
 | |
|       (VOID *)&ArpService->DeniedCacheTable
 | |
|       );
 | |
| 
 | |
|     //
 | |
|     // Let the next search start from this cache entry.
 | |
|     //
 | |
|     StartEntry = &CacheEntry->List;
 | |
| 
 | |
|     if (Refresh) {
 | |
|       //
 | |
|       // Refresh the DecayTime if needed.
 | |
|       //
 | |
|       CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Search the ResolvedCacheTable
 | |
|   //
 | |
|   StartEntry = NULL;
 | |
|   while (TRUE) {
 | |
|     CacheEntry = ArpFindNextCacheEntryInTable (
 | |
|                    &ArpService->ResolvedCacheTable,
 | |
|                    StartEntry,
 | |
|                    FindOpType,
 | |
|                    &MatchAddress,
 | |
|                    &MatchAddress
 | |
|                    );
 | |
|     if (CacheEntry == NULL) {
 | |
|       //
 | |
|       // Once the CacheEntry is NULL, there are no more matches.
 | |
|       //
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Insert the found entry into the map.
 | |
|     //
 | |
|     NetMapInsertTail (
 | |
|       &FoundEntries,
 | |
|       (VOID *)CacheEntry,
 | |
|       (VOID *)&ArpService->ResolvedCacheTable
 | |
|       );
 | |
| 
 | |
|     //
 | |
|     // Let the next search start from this cache entry.
 | |
|     //
 | |
|     StartEntry = &CacheEntry->List;
 | |
| 
 | |
|     if (Refresh) {
 | |
|       //
 | |
|       // Refresh the DecayTime if needed.
 | |
|       //
 | |
|       CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   FoundCount = (UINT32) NetMapGetCount (&FoundEntries);
 | |
|   if (FoundCount == 0) {
 | |
|     Status = EFI_NOT_FOUND;
 | |
|     goto CLEAN_EXIT;
 | |
|   }
 | |
| 
 | |
|   if (EntryLength != NULL) {
 | |
|     //
 | |
|     // Return the entry length, make sure its 8 bytes alignment.
 | |
|     //
 | |
|     *EntryLength = (((sizeof (EFI_ARP_FIND_DATA) + Instance->ConfigData.SwAddressLength +
 | |
|                    ArpService->SnpMode.HwAddressSize) + 3) & ~(0x3));
 | |
|   }
 | |
| 
 | |
|   if (EntryCount != NULL) {
 | |
|     //
 | |
|     // Return the found entry count.
 | |
|     //
 | |
|     *EntryCount = FoundCount;
 | |
|   }
 | |
| 
 | |
|   if (Entries == NULL) {
 | |
|     goto CLEAN_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate buffer to copy the found entries.
 | |
|   //
 | |
|   FindData = AllocatePool (FoundCount * (*EntryLength));
 | |
|   if (FindData == NULL) {
 | |
|     DEBUG ((EFI_D_ERROR, "ArpFindCacheEntry: Failed to allocate memory.\n"));
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto CLEAN_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Return the address to the user.
 | |
|   //
 | |
|   *Entries = FindData;
 | |
| 
 | |
|   //
 | |
|   // Dump the entries.
 | |
|   //
 | |
|   while (!NetMapIsEmpty (&FoundEntries)) {
 | |
|     //
 | |
|     // Get a cache entry from the map.
 | |
|     //
 | |
|     CacheEntry = NetMapRemoveHead (&FoundEntries, (VOID **)&CacheTable);
 | |
| 
 | |
|     //
 | |
|     // Set the fields in FindData.
 | |
|     //
 | |
|     FindData->Size            = *EntryLength;
 | |
|     FindData->DenyFlag        = (BOOLEAN)(CacheTable == &ArpService->DeniedCacheTable);
 | |
|     FindData->StaticFlag      = (BOOLEAN)(CacheEntry->DefaultDecayTime == 0);
 | |
|     FindData->HwAddressType   = ArpService->SnpMode.IfType;
 | |
|     FindData->SwAddressType   = Instance->ConfigData.SwAddressType;
 | |
|     FindData->HwAddressLength = (UINT8)ArpService->SnpMode.HwAddressSize;
 | |
|     FindData->SwAddressLength = Instance->ConfigData.SwAddressLength;
 | |
| 
 | |
|     //
 | |
|     // Copy the software address.
 | |
|     //
 | |
|     CopyMem (
 | |
|       FindData + 1,
 | |
|       CacheEntry->Addresses[Protocol].AddressPtr,
 | |
|       FindData->SwAddressLength
 | |
|       );
 | |
| 
 | |
|     //
 | |
|     // Copy the hardware address.
 | |
|     //
 | |
|     CopyMem (
 | |
|       (UINT8 *)(FindData + 1) + FindData->SwAddressLength,
 | |
|       CacheEntry->Addresses[Hardware].AddressPtr,
 | |
|       FindData->HwAddressLength
 | |
|       );
 | |
| 
 | |
|     //
 | |
|     // Slip to the next FindData.
 | |
|     //
 | |
|     FindData = (EFI_ARP_FIND_DATA *)((UINT8 *)FindData + *EntryLength);
 | |
|   }
 | |
| 
 | |
| CLEAN_EXIT:
 | |
| 
 | |
|   NetMapClean (&FoundEntries);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 |