ip4if.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,274 行 · 第 1/3 页

C
1,274
字号

Returns:

  NONE

--*/
{
  NET_LIST_ENTRY            *Entry;
  NET_LIST_ENTRY            *Next;
  IP4_ARP_QUE               *ArpQue;
  IP4_LINK_TX_TOKEN         *Token;
  EFI_TPL                   OldTpl;

  //
  // Raise the TPL to cancel the ARP and MNP asynchronous requests
  // to prevent the callback of the signal being called to close it.
  //
  OldTpl = gBS->RaiseTPL (NET_TPL_LOCK);

  //
  // 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 (NetListIsEmpty (&ArpQue->Frames)) {
      NetListRemoveEntry (Entry);

      Interface->Arp->Cancel (Interface->Arp, &ArpQue->Ip, ArpQue->OnResolved);
      Ip4FreeArpQue (ArpQue, EFI_ABORTED);
    }
  }
  
  //
  // 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)) {
      NetListRemoveEntry (Entry);

      Interface->Mnp->Cancel (Interface->Mnp, &Token->MnpToken);
      Token->CallBack (Token->IpInstance, Token->Packet, IoStatus, 0, Token->Context);
      Ip4FreeLinkTxToken (Token);
    }
  }

  gBS->RestoreTPL (OldTpl);
}

IP4_INTERFACE *
Ip4CreateInterface (
  IN  EFI_MANAGED_NETWORK_PROTOCOL  *Mnp,
  IN  EFI_HANDLE                    Controller,
  IN  EFI_HANDLE                    ImageHandle
  )
/*++

Routine Description:

  Create an IP4_INTERFACE. Delay the creation of ARP instance until
  the interface is configured.

Arguments:

  Mnp         - The shared MNP child of this IP4 service binding instance
  Controller  - The controller this IP4 service binding instance 
                is installed. Most like the UNDI handle.
  ImageHandle - This driver's image handle

Returns:

  Point to the created IP4_INTERFACE, otherwise NULL.

--*/
{
  IP4_INTERFACE             *Interface;
  EFI_SIMPLE_NETWORK_MODE   SnpMode;

  Interface = NetAllocatePool (sizeof (IP4_INTERFACE));

  if ((Interface == NULL) || (Mnp == NULL)) {
    return NULL;
  }

  Interface->Signature = IP4_INTERFACE_SIGNATURE;
  NetListInit (&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;

  NetListInit (&Interface->ArpQues);
  NetListInit (&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))) {
    NetFreePool (Interface);
    return NULL;
  }

  Interface->Mac          = SnpMode.CurrentAddress;
  Interface->BroadcastMac = SnpMode.BroadcastAddress;
  Interface->HwaddrLen    = SnpMode.HwAddressSize;

  NetListInit (&Interface->IpInstances);
  Interface->PromiscRecv = FALSE;

  return Interface;
}

EFI_STATUS
Ip4SetAddress (
  IN  IP4_INTERFACE         *Interface,
  IN  IP4_ADDR              IpAddr,
  IN  IP4_ADDR              SubnetMask
  )
/*++

Routine Description:

  Set the interface's address, create and configure
  the ARP child if necessary.

Arguments:

  Interface   - The interface to set the address
  IpAddr      - The interface's IP address
  SubnetMask  - The interface's netmask

Returns:

  EFI_SUCCESS - The interface is configured with Ip/netmask pair, 
                and a ARP is created for it.
  Others      - Failed to set the interface's address.             

--*/
{
  EFI_ARP_CONFIG_DATA       ArpConfig;
  EFI_STATUS                Status;
  INTN                      Type;
  INTN                      Len;
  IP4_ADDR                  Netmask;

  NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);

  ASSERT (!Interface->Configured);

  //
  // Set the ip/netmask, then compute the subnet broadcast 
  // and network broadcast for easy access. When computing 
  // nework 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);

  Type                      = NetGetIpClass (IpAddr);
  Len                       = NetGetMaskLength (SubnetMask);
  Netmask                   = mIp4AllMasks[NET_MIN (Len, Type << 3)];
  Interface->NetBrdcast     = (IpAddr | ~Netmask);
  
  //
  // 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
  //
  Interface->Arp            = NULL;
  Interface->ArpHandle      = NULL;

  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,
                    &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;
}

STATIC
BOOLEAN
Ip4CancelInstanceFrame (
  IN IP4_LINK_TX_TOKEN *Frame,
  IN VOID              *Context
  )
/*++

Routine Description:

  Fileter function to cancel all the frame related to an IP instance.

Arguments:

  Frame   - The transmit request to test whether to cancel
  Context - The context which is the Ip instance that issued the transmit.

Returns:

  TRUE    - The frame belongs to this instance and is to be removed
  FALSE   - The frame doesn't belong to this instance.

--*/
{
  if (Frame->IpInstance == (IP4_PROTOCOL *) Context) {
    return TRUE;
  }

  return FALSE;
}


VOID
Ip4CancelReceive (
  IN IP4_INTERFACE          *Interface
  )
/*++

Routine Description:

  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.
  
Arguments:

  Interface   - The interface used by the IpInstance

Returns:

  None

--*/  
{
  EFI_TPL                   OldTpl;
  IP4_LINK_RX_TOKEN         *Token;

    
  if ((Token = Interface->RecvRequest) != NULL) {
    OldTpl = gBS->RaiseTPL (NET_TPL_LOCK);

    Interface->RecvRequest = NULL;
    Interface->Mnp->Cancel (Interface->Mnp, &Token->MnpToken);
    Ip4FreeFrameRxToken (Token);

    gBS->RestoreTPL (OldTpl);
  }
}

EFI_STATUS
Ip4FreeInterface (
  IN  IP4_INTERFACE         *Interface,
  IN  IP4_PROTOCOL          *IpInstance           OPTIONAL
  )
/*++

Routine Description:

  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.
  
Arguments:

  Interface   - The interface used by the IpInstance
  IpInstance  - The Ip instance that free the interface. NULL if the 
                Ip driver is releasing the default interface.

Returns:

  EFI_SUCCESS - The interface use IpInstance is freed.

--*/
{
  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;
  }
  
  //
  // Destory 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 destory the ARP requests.
  //
  Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, NULL);
  Ip4CancelReceive (Interface);

  ASSERT (NetListIsEmpty (&Interface->IpInstances));
  ASSERT (NetListIsEmpty (&Interface->ArpQues));
  ASSERT (NetListIsEmpty (&Interface->SentFrames));

  if (Interface->Arp != NULL) {
    gBS->CloseProtocol (
          Interface->ArpHandle,
          &gEfiArpProtocolGuid,
          Interface->Image,
          Interface->Controller
          );

    NetLibDestroyServiceChild (
      Interface->Controller,
      Interface->Image,
      &gEfiArpServiceBindingProtocolGuid,
      Interface->ArpHandle
      );
  }

  NetListRemoveEntry (&Interface->Link);
  NetFreePool (Interface);

  return EFI_SUCCESS;
}

STATIC
VOID
EFIAPI
Ip4OnArpResolved (
  IN EFI_EVENT              Event,
  IN VOID                   *Context
  )
/*++

Routine Description:

  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.

Arguments:

  Event   - The Arp request event
  Context - The context of the callback, a point to the ARP queue

Returns:

  None

--*/
{
  NET_LIST_ENTRY            *Entry;
  NET_LIST_ENTRY            *Next;
  IP4_ARP_QUE               *ArpQue;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?