12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334 |
- /** @file
- Implement IP4 pseudo interface.
- Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "Ip4Impl.h"
- //
- // Mac address with all zero, used to determine whether the ARP
- // resolve succeeded. Failed ARP requests zero the MAC address buffer.
- //
- EFI_MAC_ADDRESS mZeroMacAddress;
- /**
- Callback function when frame transmission is finished. It will
- call the frame owner's callback function to tell it the result.
- @param[in] Context Context which is point to the token.
- **/
- VOID
- EFIAPI
- Ip4OnFrameSentDpc (
- IN VOID *Context
- );
- /**
- Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK.
- @param[in] Event The transmit token's event.
- @param[in] Context Context which is point to the token.
- **/
- VOID
- EFIAPI
- Ip4OnFrameSent (
- IN EFI_EVENT Event,
- IN VOID *Context
- );
- /**
- Callback function when ARP request are finished. It will cancelled
- all the queued frame if the ARP requests failed. Or transmit them
- if the request succeed.
- @param[in] Context The context of the callback, a point to the ARP
- queue
- **/
- VOID
- EFIAPI
- Ip4OnArpResolvedDpc (
- IN VOID *Context
- );
- /**
- Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK.
- @param Event The Arp request event.
- @param Context The context of the callback, a point to the ARP
- queue.
- **/
- VOID
- EFIAPI
- Ip4OnArpResolved (
- IN EFI_EVENT Event,
- IN VOID *Context
- );
- /**
- Received a frame from MNP, wrap it in net buffer then deliver
- it to IP's input function. The ownship of the packet also
- transferred to IP. When Ip is finished with this packet, it
- will call NetbufFree to release the packet, NetbufFree will
- again call the Ip4RecycleFrame to signal MNP's event and free
- the token used.
- @param Context Context for the callback.
- **/
- VOID
- EFIAPI
- Ip4OnFrameReceivedDpc (
- IN VOID *Context
- );
- /**
- Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK.
- @param Event The receive event delivered to MNP for receive.
- @param Context Context for the callback.
- **/
- VOID
- EFIAPI
- Ip4OnFrameReceived (
- IN EFI_EVENT Event,
- IN VOID *Context
- );
- /**
- Remove all the frames on the ARP queue that pass the FrameToCancel,
- that is, either FrameToCancel is NULL or it returns true for the frame.
- @param[in] ArpQue ARP frame to remove the frames from.
- @param[in] IoStatus The status returned to the cancelled frames'
- callback function.
- @param[in] FrameToCancel Function to select which frame to cancel.
- @param[in] Context Opaque parameter to the FrameToCancel.
- **/
- VOID
- Ip4CancelFrameArp (
- IN IP4_ARP_QUE *ArpQue,
- IN EFI_STATUS IoStatus,
- IN IP4_FRAME_TO_CANCEL FrameToCancel OPTIONAL,
- IN VOID *Context
- );
- /**
- Wrap a transmit request into a newly allocated IP4_LINK_TX_TOKEN.
- @param[in] Interface The interface to send out to.
- @param[in] IpInstance The IpInstance that transmit the packet. NULL if
- the packet is sent by the IP4 driver itself.
- @param[in] Packet The packet to transmit
- @param[in] CallBack Call back function to execute if transmission
- finished.
- @param[in] Context Opaque parameter to the call back.
- @param[in] IpSb The pointer to the IP4 service binding instance.
- @retval Token The wrapped token if succeed
- @retval NULL The wrapped token if NULL
- **/
- IP4_LINK_TX_TOKEN *
- Ip4WrapLinkTxToken (
- IN IP4_INTERFACE *Interface,
- IN IP4_PROTOCOL *IpInstance OPTIONAL,
- IN NET_BUF *Packet,
- IN IP4_FRAME_CALLBACK CallBack,
- IN VOID *Context,
- IN IP4_SERVICE *IpSb
- )
- {
- EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;
- EFI_MANAGED_NETWORK_TRANSMIT_DATA *MnpTxData;
- IP4_LINK_TX_TOKEN *Token;
- EFI_STATUS Status;
- UINT32 Count;
- Token = AllocatePool (
- sizeof (IP4_LINK_TX_TOKEN) + \
- (Packet->BlockOpNum - 1) * sizeof (EFI_MANAGED_NETWORK_FRAGMENT_DATA)
- );
- if (Token == NULL) {
- return NULL;
- }
- Token->Signature = IP4_FRAME_TX_SIGNATURE;
- InitializeListHead (&Token->Link);
- Token->Interface = Interface;
- Token->IpInstance = IpInstance;
- Token->IpSb = IpSb;
- Token->CallBack = CallBack;
- Token->Packet = Packet;
- Token->Context = Context;
- CopyMem (&Token->DstMac, &mZeroMacAddress, sizeof (Token->DstMac));
- CopyMem (&Token->SrcMac, &Interface->Mac, sizeof (Token->SrcMac));
- MnpToken = &(Token->MnpToken);
- MnpToken->Status = EFI_NOT_READY;
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- Ip4OnFrameSent,
- Token,
- &MnpToken->Event
- );
- if (EFI_ERROR (Status)) {
- FreePool (Token);
- return NULL;
- }
- MnpTxData = &Token->MnpTxData;
- MnpToken->Packet.TxData = MnpTxData;
- MnpTxData->DestinationAddress = &Token->DstMac;
- MnpTxData->SourceAddress = &Token->SrcMac;
- MnpTxData->ProtocolType = IP4_ETHER_PROTO;
- MnpTxData->DataLength = Packet->TotalSize;
- MnpTxData->HeaderLength = 0;
- Count = Packet->BlockOpNum;
- NetbufBuildExt (Packet, (NET_FRAGMENT *)MnpTxData->FragmentTable, &Count);
- MnpTxData->FragmentCount = (UINT16)Count;
- return Token;
- }
- /**
- Free the link layer transmit token. It will close the event
- then free the memory used.
- @param[in] Token Token to free
- **/
- VOID
- Ip4FreeLinkTxToken (
- IN IP4_LINK_TX_TOKEN *Token
- )
- {
- NET_CHECK_SIGNATURE (Token, IP4_FRAME_TX_SIGNATURE);
- gBS->CloseEvent (Token->MnpToken.Event);
- FreePool (Token);
- }
- /**
- Create an IP_ARP_QUE structure to request ARP service.
- @param[in] Interface The interface to send ARP from.
- @param[in] DestIp The destination IP (host byte order) to request MAC
- for
- @return Point to newly created IP4_ARP_QUE if succeed, otherwise NULL.
- **/
- IP4_ARP_QUE *
- Ip4CreateArpQue (
- IN IP4_INTERFACE *Interface,
- IN IP4_ADDR DestIp
- )
- {
- IP4_ARP_QUE *ArpQue;
- EFI_STATUS Status;
- ArpQue = AllocatePool (sizeof (IP4_ARP_QUE));
- if (ArpQue == NULL) {
- return NULL;
- }
- ArpQue->Signature = IP4_FRAME_ARP_SIGNATURE;
- InitializeListHead (&ArpQue->Link);
- InitializeListHead (&ArpQue->Frames);
- ArpQue->Interface = Interface;
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- Ip4OnArpResolved,
- ArpQue,
- &ArpQue->OnResolved
- );
- if (EFI_ERROR (Status)) {
- FreePool (ArpQue);
- return NULL;
- }
- ArpQue->Ip = DestIp;
- CopyMem (&ArpQue->Mac, &mZeroMacAddress, sizeof (ArpQue->Mac));
- return ArpQue;
- }
- /**
- Remove all the transmit requests queued on the ARP queue, then free it.
- @param[in] ArpQue Arp queue to free
- @param[in] IoStatus The transmit status returned to transmit requests'
- callback.
- **/
- VOID
- Ip4FreeArpQue (
- IN IP4_ARP_QUE *ArpQue,
- IN EFI_STATUS IoStatus
- )
- {
- NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);
- //
- // Remove all the frame waiting the ARP response
- //
- Ip4CancelFrameArp (ArpQue, IoStatus, NULL, NULL);
- gBS->CloseEvent (ArpQue->OnResolved);
- FreePool (ArpQue);
- }
- /**
- Create a link layer receive token to wrap the receive request
- @param[in] Interface The interface to receive from
- @param[in] IpInstance The instance that request the receive (NULL for IP4
- driver itself)
- @param[in] CallBack Call back function to execute when finished.
- @param[in] Context Opaque parameters to the callback
- @return Point to created IP4_LINK_RX_TOKEN if succeed, otherwise NULL.
- **/
- IP4_LINK_RX_TOKEN *
- Ip4CreateLinkRxToken (
- IN IP4_INTERFACE *Interface,
- IN IP4_PROTOCOL *IpInstance,
- IN IP4_FRAME_CALLBACK CallBack,
- IN VOID *Context
- )
- {
- EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;
- IP4_LINK_RX_TOKEN *Token;
- EFI_STATUS Status;
- Token = AllocatePool (sizeof (IP4_LINK_RX_TOKEN));
- if (Token == NULL) {
- return NULL;
- }
- Token->Signature = IP4_FRAME_RX_SIGNATURE;
- Token->Interface = Interface;
- Token->IpInstance = IpInstance;
- Token->CallBack = CallBack;
- Token->Context = Context;
- MnpToken = &Token->MnpToken;
- MnpToken->Status = EFI_NOT_READY;
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- Ip4OnFrameReceived,
- Token,
- &MnpToken->Event
- );
- if (EFI_ERROR (Status)) {
- FreePool (Token);
- return NULL;
- }
- MnpToken->Packet.RxData = NULL;
- return Token;
- }
- /**
- Free the link layer request token. It will close the event
- then free the memory used.
- @param[in] Token Request token to free.
- **/
- VOID
- Ip4FreeFrameRxToken (
- IN IP4_LINK_RX_TOKEN *Token
- )
- {
- NET_CHECK_SIGNATURE (Token, IP4_FRAME_RX_SIGNATURE);
- gBS->CloseEvent (Token->MnpToken.Event);
- FreePool (Token);
- }
- /**
- Remove all the frames on the ARP queue that pass the FrameToCancel,
- that is, either FrameToCancel is NULL or it returns true for the frame.
- @param[in] ArpQue ARP frame to remove the frames from.
- @param[in] IoStatus The status returned to the cancelled frames'
- callback function.
- @param[in] FrameToCancel Function to select which frame to cancel.
- @param[in] Context Opaque parameter to the FrameToCancel.
- **/
- VOID
- Ip4CancelFrameArp (
- IN IP4_ARP_QUE *ArpQue,
- IN EFI_STATUS IoStatus,
- IN IP4_FRAME_TO_CANCEL FrameToCancel OPTIONAL,
- IN VOID *Context
- )
- {
- LIST_ENTRY *Entry;
- LIST_ENTRY *Next;
- IP4_LINK_TX_TOKEN *Token;
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
- Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
- if ((FrameToCancel == NULL) || FrameToCancel (Token, Context)) {
- RemoveEntryList (Entry);
- Token->CallBack (Token->IpInstance, Token->Packet, IoStatus, 0, Token->Context);
- Ip4FreeLinkTxToken (Token);
- }
- }
- }
- /**
- Remove all the frames on the interface that pass the FrameToCancel,
- either queued on ARP queues or that have already been delivered to
- MNP and not yet recycled.
- @param[in] Interface Interface to remove the frames from.
- @param[in] IoStatus The transmit status returned to the frames'
- callback.
- @param[in] FrameToCancel Function to select the frame to cancel, NULL to
- select all.
- @param[in] Context Opaque parameters passed to FrameToCancel.
- **/
- VOID
- Ip4CancelFrames (
- IN IP4_INTERFACE *Interface,
- IN EFI_STATUS IoStatus,
- IN IP4_FRAME_TO_CANCEL FrameToCancel OPTIONAL,
- IN VOID *Context
- )
- {
- LIST_ENTRY *Entry;
- LIST_ENTRY *Next;
- IP4_ARP_QUE *ArpQue;
- IP4_LINK_TX_TOKEN *Token;
- //
- // Cancel all the pending frames on ARP requests
- //
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &Interface->ArpQues) {
- ArpQue = NET_LIST_USER_STRUCT (Entry, IP4_ARP_QUE, Link);
- Ip4CancelFrameArp (ArpQue, IoStatus, FrameToCancel, Context);
- if (IsListEmpty (&ArpQue->Frames)) {
- Interface->Arp->Cancel (Interface->Arp, &ArpQue->Ip, ArpQue->OnResolved);
- }
- }
- //
- // Cancel all the frames that have been delivered to MNP
- // but not yet recycled.
- //
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &Interface->SentFrames) {
- Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
- if ((FrameToCancel == NULL) || FrameToCancel (Token, Context)) {
- Interface->Mnp->Cancel (Interface->Mnp, &Token->MnpToken);
- }
- }
- }
- /**
- Create an IP4_INTERFACE. Delay the creation of ARP instance until
- the interface is configured.
- @param[in] Mnp The shared MNP child of this IP4 service binding
- instance.
- @param[in] Controller The controller this IP4 service binding instance
- is installed. Most like the UNDI handle.
- @param[in] ImageHandle This driver's image handle.
- @return Point to the created IP4_INTERFACE, otherwise NULL.
- **/
- IP4_INTERFACE *
- Ip4CreateInterface (
- IN EFI_MANAGED_NETWORK_PROTOCOL *Mnp,
- IN EFI_HANDLE Controller,
- IN EFI_HANDLE ImageHandle
- )
- {
- IP4_INTERFACE *Interface;
- EFI_SIMPLE_NETWORK_MODE SnpMode;
- if (Mnp == NULL) {
- return NULL;
- }
- Interface = AllocatePool (sizeof (IP4_INTERFACE));
- if (Interface == NULL) {
- return NULL;
- }
- Interface->Signature = IP4_INTERFACE_SIGNATURE;
- InitializeListHead (&Interface->Link);
- Interface->RefCnt = 1;
- Interface->Ip = IP4_ALLZERO_ADDRESS;
- Interface->SubnetMask = IP4_ALLZERO_ADDRESS;
- Interface->Configured = FALSE;
- Interface->Controller = Controller;
- Interface->Image = ImageHandle;
- Interface->Mnp = Mnp;
- Interface->Arp = NULL;
- Interface->ArpHandle = NULL;
- InitializeListHead (&Interface->ArpQues);
- InitializeListHead (&Interface->SentFrames);
- Interface->RecvRequest = NULL;
- //
- // Get the interface's Mac address and broadcast mac address from SNP
- //
- if (EFI_ERROR (Mnp->GetModeData (Mnp, NULL, &SnpMode))) {
- FreePool (Interface);
- return NULL;
- }
- CopyMem (&Interface->Mac, &SnpMode.CurrentAddress, sizeof (Interface->Mac));
- CopyMem (&Interface->BroadcastMac, &SnpMode.BroadcastAddress, sizeof (Interface->BroadcastMac));
- Interface->HwaddrLen = SnpMode.HwAddressSize;
- InitializeListHead (&Interface->IpInstances);
- Interface->PromiscRecv = FALSE;
- return Interface;
- }
- /**
- Set the interface's address, create and configure
- the ARP child if necessary.
- @param Interface The interface to set the address.
- @param IpAddr The interface's IP address.
- @param SubnetMask The interface's netmask.
- @retval EFI_SUCCESS The interface is configured with Ip/netmask pair,
- and a ARP is created for it.
- @retval Others Failed to set the interface's address.
- **/
- EFI_STATUS
- Ip4SetAddress (
- IN OUT IP4_INTERFACE *Interface,
- IN IP4_ADDR IpAddr,
- IN IP4_ADDR SubnetMask
- )
- {
- EFI_ARP_CONFIG_DATA ArpConfig;
- EFI_STATUS Status;
- NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
- //
- // Set the ip/netmask, then compute the subnet broadcast
- // and network broadcast for easy access. When computing
- // network broadcast, the subnet mask is most like longer
- // than the default netmask (not subneted) as defined in
- // RFC793. If that isn't the case, we are aggregating the
- // networks, use the subnet's mask instead.
- //
- Interface->Ip = IpAddr;
- Interface->SubnetMask = SubnetMask;
- Interface->SubnetBrdcast = (IpAddr | ~SubnetMask);
- Interface->NetBrdcast = (IpAddr | ~SubnetMask);
- //
- // Do clean up for Arp child
- //
- if (Interface->ArpHandle != NULL) {
- if (Interface->Arp != NULL) {
- gBS->CloseProtocol (
- Interface->ArpHandle,
- &gEfiArpProtocolGuid,
- Interface->Image,
- Interface->Controller
- );
- Interface->Arp = NULL;
- }
- NetLibDestroyServiceChild (
- Interface->Controller,
- Interface->Image,
- &gEfiArpServiceBindingProtocolGuid,
- Interface->ArpHandle
- );
- Interface->ArpHandle = NULL;
- }
- //
- // If the address is NOT all zero, create then configure an ARP child.
- // Pay attention: DHCP configures its station address as 0.0.0.0/0
- //
- if (IpAddr != IP4_ALLZERO_ADDRESS) {
- Status = NetLibCreateServiceChild (
- Interface->Controller,
- Interface->Image,
- &gEfiArpServiceBindingProtocolGuid,
- &Interface->ArpHandle
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Status = gBS->OpenProtocol (
- Interface->ArpHandle,
- &gEfiArpProtocolGuid,
- (VOID **)&Interface->Arp,
- Interface->Image,
- Interface->Controller,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status)) {
- goto ON_ERROR;
- }
- IpAddr = HTONL (IpAddr);
- ArpConfig.SwAddressType = IP4_ETHER_PROTO;
- ArpConfig.SwAddressLength = 4;
- ArpConfig.StationAddress = &IpAddr;
- ArpConfig.EntryTimeOut = 0;
- ArpConfig.RetryCount = 0;
- ArpConfig.RetryTimeOut = 0;
- Status = Interface->Arp->Configure (Interface->Arp, &ArpConfig);
- if (EFI_ERROR (Status)) {
- gBS->CloseProtocol (
- Interface->ArpHandle,
- &gEfiArpProtocolGuid,
- Interface->Image,
- Interface->Controller
- );
- goto ON_ERROR;
- }
- }
- Interface->Configured = TRUE;
- return EFI_SUCCESS;
- ON_ERROR:
- NetLibDestroyServiceChild (
- Interface->Controller,
- Interface->Image,
- &gEfiArpServiceBindingProtocolGuid,
- Interface->ArpHandle
- );
- return Status;
- }
- /**
- Filter function to cancel all the frame related to an IP instance.
- @param[in] Frame The transmit request to test whether to cancel
- @param[in] Context The context which is the Ip instance that issued
- the transmit.
- @retval TRUE The frame belongs to this instance and is to be
- removed
- @retval FALSE The frame doesn't belong to this instance.
- **/
- BOOLEAN
- Ip4CancelInstanceFrame (
- IN IP4_LINK_TX_TOKEN *Frame,
- IN VOID *Context
- )
- {
- if (Frame->IpInstance == (IP4_PROTOCOL *)Context) {
- return TRUE;
- }
- return FALSE;
- }
- /**
- If there is a pending receive request, cancel it. Don't call
- the receive request's callback because this function can be only
- called if the instance or driver is tearing itself down. It
- doesn't make sense to call it back. But it is necessary to call
- the transmit token's callback to give it a chance to free the
- packet and update the upper layer's transmit request status, say
- that from the UDP.
- @param[in] Interface The interface used by the IpInstance
- **/
- VOID
- Ip4CancelReceive (
- IN IP4_INTERFACE *Interface
- )
- {
- EFI_TPL OldTpl;
- IP4_LINK_RX_TOKEN *Token;
- if ((Token = Interface->RecvRequest) != NULL) {
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- Interface->RecvRequest = NULL;
- Interface->Mnp->Cancel (Interface->Mnp, &Token->MnpToken);
- gBS->RestoreTPL (OldTpl);
- }
- }
- /**
- Free the interface used by IpInstance. All the IP instance with
- the same Ip/Netmask pair share the same interface. It is reference
- counted. All the frames haven't been sent will be cancelled.
- Because the IpInstance is optional, the caller must remove
- IpInstance from the interface's instance list itself.
- @param[in] Interface The interface used by the IpInstance.
- @param[in] IpInstance The Ip instance that free the interface. NULL if
- the Ip driver is releasing the default interface.
- @retval EFI_SUCCESS The interface use IpInstance is freed.
- **/
- EFI_STATUS
- Ip4FreeInterface (
- IN IP4_INTERFACE *Interface,
- IN IP4_PROTOCOL *IpInstance OPTIONAL
- )
- {
- NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
- ASSERT (Interface->RefCnt > 0);
- //
- // Remove all the pending transmit token related to this IP instance.
- //
- Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, IpInstance);
- if (--Interface->RefCnt > 0) {
- return EFI_SUCCESS;
- }
- //
- // Destroy the interface if this is the last IP instance that
- // has the address. Remove all the system transmitted packets
- // from this interface, cancel the receive request if there is
- // one, and destroy the ARP requests.
- //
- Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, NULL);
- Ip4CancelReceive (Interface);
- ASSERT (IsListEmpty (&Interface->IpInstances));
- ASSERT (IsListEmpty (&Interface->ArpQues));
- ASSERT (IsListEmpty (&Interface->SentFrames));
- if (Interface->Arp != NULL) {
- gBS->CloseProtocol (
- Interface->ArpHandle,
- &gEfiArpProtocolGuid,
- Interface->Image,
- Interface->Controller
- );
- NetLibDestroyServiceChild (
- Interface->Controller,
- Interface->Image,
- &gEfiArpServiceBindingProtocolGuid,
- Interface->ArpHandle
- );
- }
- RemoveEntryList (&Interface->Link);
- FreePool (Interface);
- return EFI_SUCCESS;
- }
- /**
- This function tries to send all the queued frames in ArpQue to the default gateway if
- the ARP resolve for direct destination address is failed when using /32 subnet mask.
- @param[in] ArpQue The ARP queue of a failed request.
- @retval EFI_SUCCESS All the queued frames have been send to the default route.
- @retval Others Failed to send the queued frames.
- **/
- EFI_STATUS
- Ip4SendFrameToDefaultRoute (
- IN IP4_ARP_QUE *ArpQue
- )
- {
- LIST_ENTRY *Entry;
- LIST_ENTRY *Next;
- IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
- IP4_LINK_TX_TOKEN *Token;
- IP4_ADDR Gateway;
- EFI_STATUS Status;
- IP4_ROUTE_ENTRY *DefaultRoute;
- //
- // ARP resolve failed when using /32 subnet mask.
- //
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
- RemoveEntryList (Entry);
- Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
- ASSERT (Token->Interface->SubnetMask == IP4_ALLONE_ADDRESS);
- //
- // Find the default gateway IP address. The default route was saved to the RtCacheEntry->Tag in Ip4Route().
- //
- RtCacheEntry = NULL;
- if (Token->IpInstance != NULL) {
- RtCacheEntry = Ip4FindRouteCache (Token->IpInstance->RouteTable, NTOHL (ArpQue->Ip), Token->Interface->Ip);
- }
- if (RtCacheEntry == NULL) {
- RtCacheEntry = Ip4FindRouteCache (Token->IpSb->DefaultRouteTable, NTOHL (ArpQue->Ip), Token->Interface->Ip);
- }
- if (RtCacheEntry == NULL) {
- Status = EFI_NO_MAPPING;
- goto ON_ERROR;
- }
- DefaultRoute = (IP4_ROUTE_ENTRY *)RtCacheEntry->Tag;
- if (DefaultRoute == NULL) {
- Status = EFI_NO_MAPPING;
- goto ON_ERROR;
- }
- //
- // Try to send the frame to the default route.
- //
- Gateway = DefaultRoute->NextHop;
- if (ArpQue->Ip == Gateway) {
- //
- // ARP resolve for the default route is failed, return error to caller.
- //
- Status = EFI_NO_MAPPING;
- goto ON_ERROR;
- }
- RtCacheEntry->NextHop = Gateway;
- Status = Ip4SendFrame (Token->Interface, Token->IpInstance, Token->Packet, Gateway, Token->CallBack, Token->Context, Token->IpSb);
- if (EFI_ERROR (Status)) {
- Status = EFI_NO_MAPPING;
- goto ON_ERROR;
- }
- Ip4FreeRouteCacheEntry (RtCacheEntry);
- }
- return EFI_SUCCESS;
- ON_ERROR:
- if (RtCacheEntry != NULL) {
- Ip4FreeRouteCacheEntry (RtCacheEntry);
- }
- Token->CallBack (Token->IpInstance, Token->Packet, Status, 0, Token->Context);
- Ip4FreeLinkTxToken (Token);
- return Status;
- }
- /**
- Callback function when ARP request are finished. It will cancel
- all the queued frame if the ARP requests failed. Or transmit them
- if the request succeed.
- @param[in] Context The context of the callback, a point to the ARP
- queue
- **/
- VOID
- EFIAPI
- Ip4OnArpResolvedDpc (
- IN VOID *Context
- )
- {
- LIST_ENTRY *Entry;
- LIST_ENTRY *Next;
- IP4_ARP_QUE *ArpQue;
- IP4_INTERFACE *Interface;
- IP4_LINK_TX_TOKEN *Token;
- EFI_STATUS Status;
- EFI_STATUS IoStatus;
- ArpQue = (IP4_ARP_QUE *)Context;
- NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);
- RemoveEntryList (&ArpQue->Link);
- //
- // ARP resolve failed for some reason.
- //
- if (NET_MAC_EQUAL (&ArpQue->Mac, &mZeroMacAddress, ArpQue->Interface->HwaddrLen)) {
- if (ArpQue->Interface->SubnetMask != IP4_ALLONE_ADDRESS) {
- //
- // Release all the frame and ARP queue itself. Ip4FreeArpQue will call the frame's
- // owner back.
- //
- IoStatus = EFI_NO_MAPPING;
- } else {
- //
- // ARP resolve failed when using 32bit subnet mask, try to send the packets to the
- // default route.
- //
- IoStatus = Ip4SendFrameToDefaultRoute (ArpQue);
- }
- goto ON_EXIT;
- }
- //
- // ARP resolve succeeded, Transmit all the frame. Release the ARP
- // queue. It isn't necessary for us to cache the ARP binding because
- // we always check the ARP cache first before transmit.
- //
- IoStatus = EFI_SUCCESS;
- Interface = ArpQue->Interface;
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
- RemoveEntryList (Entry);
- Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
- CopyMem (&Token->DstMac, &ArpQue->Mac, sizeof (Token->DstMac));
- //
- // Insert the tx token before transmitting it via MNP as the FrameSentDpc
- // may be called before Mnp->Transmit returns which will remove this tx
- // token from the SentFrames list. Remove it from the list if the returned
- // Status of Mnp->Transmit is not EFI_SUCCESS as in this case the
- // FrameSentDpc won't be queued.
- //
- InsertTailList (&Interface->SentFrames, &Token->Link);
- Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);
- if (EFI_ERROR (Status)) {
- RemoveEntryList (&Token->Link);
- Token->CallBack (Token->IpInstance, Token->Packet, Status, 0, Token->Context);
- Ip4FreeLinkTxToken (Token);
- continue;
- }
- }
- ON_EXIT:
- Ip4FreeArpQue (ArpQue, IoStatus);
- }
- /**
- Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK.
- @param Event The Arp request event.
- @param Context The context of the callback, a point to the ARP
- queue.
- **/
- VOID
- EFIAPI
- Ip4OnArpResolved (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- //
- // Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK
- //
- QueueDpc (TPL_CALLBACK, Ip4OnArpResolvedDpc, Context);
- }
- /**
- Callback function when frame transmission is finished. It will
- call the frame owner's callback function to tell it the result.
- @param[in] Context Context which is point to the token.
- **/
- VOID
- EFIAPI
- Ip4OnFrameSentDpc (
- IN VOID *Context
- )
- {
- IP4_LINK_TX_TOKEN *Token;
- Token = (IP4_LINK_TX_TOKEN *)Context;
- NET_CHECK_SIGNATURE (Token, IP4_FRAME_TX_SIGNATURE);
- RemoveEntryList (&Token->Link);
- Token->CallBack (
- Token->IpInstance,
- Token->Packet,
- Token->MnpToken.Status,
- 0,
- Token->Context
- );
- Ip4FreeLinkTxToken (Token);
- }
- /**
- Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK.
- @param[in] Event The transmit token's event.
- @param[in] Context Context which is point to the token.
- **/
- VOID
- EFIAPI
- Ip4OnFrameSent (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- //
- // Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK
- //
- QueueDpc (TPL_CALLBACK, Ip4OnFrameSentDpc, Context);
- }
- /**
- Send a frame from the interface. If the next hop is broadcast or
- multicast address, it is transmitted immediately. If the next hop
- is a unicast, it will consult ARP to resolve the NextHop's MAC.
- If some error happened, the CallBack won't be called. So, the caller
- must test the return value, and take action when there is an error.
- @param[in] Interface The interface to send the frame from
- @param[in] IpInstance The IP child that request the transmission. NULL
- if it is the IP4 driver itself.
- @param[in] Packet The packet to transmit.
- @param[in] NextHop The immediate destination to transmit the packet
- to.
- @param[in] CallBack Function to call back when transmit finished.
- @param[in] Context Opaque parameter to the call back.
- @param[in] IpSb The pointer to the IP4 service binding instance.
- @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to send the frame
- @retval EFI_NO_MAPPING Can't resolve the MAC for the nexthop
- @retval EFI_SUCCESS The packet is successfully transmitted.
- @retval other Other error occurs.
- **/
- EFI_STATUS
- Ip4SendFrame (
- IN IP4_INTERFACE *Interface,
- IN IP4_PROTOCOL *IpInstance OPTIONAL,
- IN NET_BUF *Packet,
- IN IP4_ADDR NextHop,
- IN IP4_FRAME_CALLBACK CallBack,
- IN VOID *Context,
- IN IP4_SERVICE *IpSb
- )
- {
- IP4_LINK_TX_TOKEN *Token;
- LIST_ENTRY *Entry;
- IP4_ARP_QUE *ArpQue;
- EFI_ARP_PROTOCOL *Arp;
- EFI_STATUS Status;
- ASSERT (Interface->Configured);
- Token = Ip4WrapLinkTxToken (Interface, IpInstance, Packet, CallBack, Context, IpSb);
- if (Token == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- //
- // Get the destination MAC address for multicast and broadcasts.
- // Don't depend on ARP to solve the address since there maybe no
- // ARP at all. Ip4Output has set NextHop to 255.255.255.255 for
- // all the broadcasts.
- //
- if (NextHop == IP4_ALLONE_ADDRESS) {
- CopyMem (&Token->DstMac, &Interface->BroadcastMac, sizeof (Token->DstMac));
- goto SEND_NOW;
- } else if (IP4_IS_MULTICAST (NextHop)) {
- Status = Ip4GetMulticastMac (Interface->Mnp, NextHop, &Token->DstMac);
- if (EFI_ERROR (Status)) {
- goto ON_ERROR;
- }
- goto SEND_NOW;
- }
- //
- // Can only send out multicast/broadcast if the IP address is zero
- //
- if ((Arp = Interface->Arp) == NULL) {
- Status = EFI_NO_MAPPING;
- goto ON_ERROR;
- }
- //
- // First check whether this binding is in the ARP cache.
- //
- NextHop = HTONL (NextHop);
- Status = Arp->Request (Arp, &NextHop, NULL, &Token->DstMac);
- if (Status == EFI_SUCCESS) {
- goto SEND_NOW;
- } else if (Status != EFI_NOT_READY) {
- goto ON_ERROR;
- }
- //
- // Have to do asynchronous ARP resolution. First check
- // whether there is already a pending request.
- //
- ArpQue = NULL;
- NET_LIST_FOR_EACH (Entry, &Interface->ArpQues) {
- ArpQue = NET_LIST_USER_STRUCT (Entry, IP4_ARP_QUE, Link);
- if (ArpQue->Ip == NextHop) {
- break;
- }
- }
- //
- // Found a pending ARP request, enqueue the frame then return
- //
- if (Entry != &Interface->ArpQues) {
- InsertTailList (&ArpQue->Frames, &Token->Link);
- return EFI_SUCCESS;
- }
- //
- // First frame to NextHop, issue an asynchronous ARP requests
- //
- ArpQue = Ip4CreateArpQue (Interface, NextHop);
- if (ArpQue == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ON_ERROR;
- }
- Status = Arp->Request (Arp, &ArpQue->Ip, ArpQue->OnResolved, ArpQue->Mac.Addr);
- if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {
- Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);
- goto ON_ERROR;
- }
- InsertHeadList (&ArpQue->Frames, &Token->Link);
- InsertHeadList (&Interface->ArpQues, &ArpQue->Link);
- return EFI_SUCCESS;
- SEND_NOW:
- //
- // Insert the tx token into the SentFrames list before calling Mnp->Transmit.
- // Remove it if the returned status is not EFI_SUCCESS.
- //
- InsertTailList (&Interface->SentFrames, &Token->Link);
- Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);
- if (EFI_ERROR (Status)) {
- RemoveEntryList (&Token->Link);
- goto ON_ERROR;
- }
- return EFI_SUCCESS;
- ON_ERROR:
- Ip4FreeLinkTxToken (Token);
- return Status;
- }
- /**
- Call back function when the received packet is freed.
- Check Ip4OnFrameReceived for information.
- @param Context Context, which is the IP4_LINK_RX_TOKEN.
- **/
- VOID
- EFIAPI
- Ip4RecycleFrame (
- IN VOID *Context
- )
- {
- IP4_LINK_RX_TOKEN *Frame;
- Frame = (IP4_LINK_RX_TOKEN *)Context;
- NET_CHECK_SIGNATURE (Frame, IP4_FRAME_RX_SIGNATURE);
- gBS->SignalEvent (Frame->MnpToken.Packet.RxData->RecycleEvent);
- Ip4FreeFrameRxToken (Frame);
- }
- /**
- Received a frame from MNP, wrap it in net buffer then deliver
- it to IP's input function. The ownship of the packet also
- transferred to IP. When Ip is finished with this packet, it
- will call NetbufFree to release the packet, NetbufFree will
- again call the Ip4RecycleFrame to signal MNP's event and free
- the token used.
- @param Context Context for the callback.
- **/
- VOID
- EFIAPI
- Ip4OnFrameReceivedDpc (
- IN VOID *Context
- )
- {
- EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;
- EFI_MANAGED_NETWORK_RECEIVE_DATA *MnpRxData;
- IP4_LINK_RX_TOKEN *Token;
- NET_FRAGMENT Netfrag;
- NET_BUF *Packet;
- UINT32 Flag;
- Token = (IP4_LINK_RX_TOKEN *)Context;
- NET_CHECK_SIGNATURE (Token, IP4_FRAME_RX_SIGNATURE);
- //
- // First clear the interface's receive request in case the
- // caller wants to call Ip4ReceiveFrame in the callback.
- //
- Token->Interface->RecvRequest = NULL;
- MnpToken = &Token->MnpToken;
- MnpRxData = MnpToken->Packet.RxData;
- if (EFI_ERROR (MnpToken->Status) || (MnpRxData == NULL)) {
- Token->CallBack (Token->IpInstance, NULL, MnpToken->Status, 0, Token->Context);
- Ip4FreeFrameRxToken (Token);
- return;
- }
- //
- // Wrap the frame in a net buffer then deliver it to IP input.
- // IP will reassemble the packet, and deliver it to upper layer
- //
- Netfrag.Len = MnpRxData->DataLength;
- Netfrag.Bulk = MnpRxData->PacketData;
- Packet = NetbufFromExt (&Netfrag, 1, 0, IP4_MAX_HEADLEN, Ip4RecycleFrame, Token);
- if (Packet == NULL) {
- gBS->SignalEvent (MnpRxData->RecycleEvent);
- Token->CallBack (Token->IpInstance, NULL, EFI_OUT_OF_RESOURCES, 0, Token->Context);
- Ip4FreeFrameRxToken (Token);
- return;
- }
- Flag = (MnpRxData->BroadcastFlag ? IP4_LINK_BROADCAST : 0);
- Flag |= (MnpRxData->MulticastFlag ? IP4_LINK_MULTICAST : 0);
- Flag |= (MnpRxData->PromiscuousFlag ? IP4_LINK_PROMISC : 0);
- Token->CallBack (Token->IpInstance, Packet, EFI_SUCCESS, Flag, Token->Context);
- }
- /**
- Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK.
- @param Event The receive event delivered to MNP for receive.
- @param Context Context for the callback.
- **/
- VOID
- EFIAPI
- Ip4OnFrameReceived (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- //
- // Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK
- //
- QueueDpc (TPL_CALLBACK, Ip4OnFrameReceivedDpc, Context);
- }
- /**
- Request to receive the packet from the interface.
- @param[in] Interface The interface to receive the frames from.
- @param[in] IpInstance The instance that requests the receive. NULL for
- the driver itself.
- @param[in] CallBack Function to call when receive finished.
- @param[in] Context Opaque parameter to the callback.
- @retval EFI_ALREADY_STARTED There is already a pending receive request.
- @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to receive.
- @retval EFI_SUCCESS The receive request has been started.
- @retval other Other error occurs.
- **/
- EFI_STATUS
- Ip4ReceiveFrame (
- IN IP4_INTERFACE *Interface,
- IN IP4_PROTOCOL *IpInstance OPTIONAL,
- IN IP4_FRAME_CALLBACK CallBack,
- IN VOID *Context
- )
- {
- IP4_LINK_RX_TOKEN *Token;
- EFI_STATUS Status;
- NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
- if (Interface->RecvRequest != NULL) {
- return EFI_ALREADY_STARTED;
- }
- Token = Ip4CreateLinkRxToken (Interface, IpInstance, CallBack, Context);
- if (Token == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- Interface->RecvRequest = Token;
- Status = Interface->Mnp->Receive (Interface->Mnp, &Token->MnpToken);
- if (EFI_ERROR (Status)) {
- Interface->RecvRequest = NULL;
- Ip4FreeFrameRxToken (Token);
- return Status;
- }
- return EFI_SUCCESS;
- }
|