pxe_bc_ip.c

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

C
860
字号
/*++

Copyright (c) 2004, 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:
  pxe_bc_ip.c

Abstract:

--*/

#include "bc.h"

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
BOOLEAN
OnSameSubnet (
  IN UINTN           IpLength,
  IN EFI_IP_ADDRESS  *Ip1,
  IN EFI_IP_ADDRESS  *Ip2,
  IN EFI_IP_ADDRESS  *SubnetMask
  )
/*++

  Routine Description:
    Check if two IP addresses are on the same subnet.

  Arguments:
    IpLength   - Length of IP address in bytes.
    Ip1        - IP address to check.
    Ip2        - IP address to check.
    SubnetMask - Subnet mask to check with.

  Returns:
    TRUE       - IP addresses are on the same subnet.
    FALSE      - IP addresses are on different subnets.

--*/
{
  if (IpLength == 0 || Ip1 == NULL || Ip2 == NULL || SubnetMask == NULL) {
    return FALSE;
  }

  while (IpLength-- != 0) {
    if ((Ip1->v6.Addr[IpLength] ^ Ip2->v6.Addr[IpLength]) & SubnetMask->v6.Addr[IpLength]) {
      return FALSE;
    }
  }

  return TRUE;
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
VOID
IpAddRouter (
  IN PXE_BASECODE_DEVICE *Private,
  IN EFI_IP_ADDRESS      *RouterIpPtr
  )
/*++

  Routine Description:
    Add router to router table.

  Arguments:
    Private     - Pointer PxeBc instance data.
    RouterIpPtr - Pointer to router IP address.

  Returns:
    Nothing

--*/
{
  EFI_PXE_BASE_CODE_MODE  *PxeBcMode;
  UINTN                   Index;

  if (Private == NULL || RouterIpPtr == NULL) {
    return ;
  }

  PxeBcMode = Private->EfiBc.Mode;

  //
  // if we are filled up or this is not on the same subnet, forget it
  //
  if ((PxeBcMode->RouteTableEntries == PXE_ROUTER_TABLE_SIZE) ||
    !OnSameSubnet(Private->IpLength, &PxeBcMode->StationIp, RouterIpPtr, &PxeBcMode->SubnetMask)) {
    return ;
  }
  //
  // make sure we don't already have it
  //
  for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {
    if (!EfiCompareMem (
          &PxeBcMode->RouteTable[Index].GwAddr,
          RouterIpPtr,
          Private->IpLength
          )) {
      return ;
    }
  }
  //
  // keep it
  //
  EfiZeroMem (
    &PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries],
    sizeof (EFI_PXE_BASE_CODE_ROUTE_ENTRY)
    );

  EfiCopyMem (
    &PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries++].GwAddr,
    RouterIpPtr,
    Private->IpLength
    );
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

//
// return router ip to use for DestIp (0 if none)
//
STATIC
EFI_IP_ADDRESS *
GetRouterIp (
  PXE_BASECODE_DEVICE *Private,
  EFI_IP_ADDRESS      *DestIpPtr
  )
{
  EFI_PXE_BASE_CODE_MODE  *PxeBcMode;
  UINTN                   Index;

  if (Private == NULL || DestIpPtr == NULL) {
    return NULL;
  }

  PxeBcMode = Private->EfiBc.Mode;

  for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {
    if (OnSameSubnet (
          Private->IpLength,
          &PxeBcMode->RouteTable[Index].IpAddr,
          DestIpPtr,
          &PxeBcMode->RouteTable[Index].SubnetMask
          )) {
      return &PxeBcMode->RouteTable[Index].GwAddr;
    }
  }

  return NULL;
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

//
// routine to send ipv4 packet
// ipv4 header of length HdrLth in TransmitBufferPtr
// routine fills in ipv4hdr Ver_Hdl, TotalLength, and Checksum, moves in Data
// and gets dest MAC address
//
#define IP_TX_BUFFER  ((IPV4_BUFFER *) Private->TransmitBufferPtr)
#define IP_TX_HEADER  IP_TX_BUFFER->IpHeader

EFI_STATUS
Ipv4Xmt (
  PXE_BASECODE_DEVICE         *Private,
  UINT32                      GatewayIp,
  UINTN                       IpHeaderLength,
  UINTN                       TotalHeaderLength,
  VOID                        *Data,
  UINTN                       DataLength,
  EFI_PXE_BASE_CODE_FUNCTION  Function
  )
{
  EFI_MAC_ADDRESS             DestMac;
  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
  EFI_PXE_BASE_CODE_MODE      *PxeBcMode;
  EFI_STATUS                  StatCode;
  UINTN                       PacketLength;

  Snp           = Private->SimpleNetwork;
  PxeBcMode     = Private->EfiBc.Mode;
  StatCode      = EFI_SUCCESS;
  PacketLength  = TotalHeaderLength + DataLength;

  //
  // get dest MAC address
  // multicast - convert to hw equiv
  // unicast on same net, use arp
  // on different net, arp for router
  //
  if (IP_TX_HEADER.DestAddr.L == BROADCAST_IPv4) {
    DestMac = Snp->Mode->BroadcastAddress;
  } else if (IS_MULTICAST (&IP_TX_HEADER.DestAddr)) {
    StatCode = (*Snp->MCastIpToMac) (Snp, PxeBcMode->UsingIpv6, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr, &DestMac);
  } else {
    UINT32  Ip;

    if (OnSameSubnet (
          Private->IpLength,
          &PxeBcMode->StationIp,
          (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr,
          &PxeBcMode->SubnetMask
          )) {
      Ip = IP_TX_HEADER.DestAddr.L;
    } else if (GatewayIp != 0) {
      Ip = GatewayIp;
    } else {
      EFI_IP_ADDRESS  *TmpIp;

      TmpIp = GetRouterIp (Private, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr);

      if (TmpIp == NULL) {
        DEBUG (
          (EFI_D_WARN,
          "\nIpv4Xmit()  Exit #1  %xh (%r)",
          EFI_NO_RESPONSE,
          EFI_NO_RESPONSE)
          );

        return EFI_NO_RESPONSE;
        //
        // no router
        //
      }

      Ip = TmpIp->Addr[0];
    }

    if (!GetHwAddr (
          Private,
          (EFI_IP_ADDRESS *) &Ip,
          (EFI_MAC_ADDRESS *) &DestMac
          )) {
      if (!PxeBcMode->AutoArp) {
        DEBUG (
          (EFI_D_WARN,
          "\nIpv4Xmit()  Exit #2  %xh (%r)",
          EFI_DEVICE_ERROR,
          EFI_DEVICE_ERROR)
          );

        return EFI_DEVICE_ERROR;
      } else {
        StatCode = DoArp (
                    Private,
                    (EFI_IP_ADDRESS *) &Ip,
                    (EFI_MAC_ADDRESS *) &DestMac
                    );
      }
    }
  }

  if (EFI_ERROR (StatCode)) {
    DEBUG ((EFI_D_WARN, "\nIpv4Xmit()  Exit #3  %xh (%r)", StatCode, StatCode));
    return StatCode;
  }
  //
  // fill in packet info
  //
  SET_IPV4_VER_HDL (&IP_TX_HEADER, IpHeaderLength);
  IP_TX_HEADER.TotalLength    = HTONS (PacketLength);
  IP_TX_HEADER.HeaderChecksum = IpChecksum ((UINT16 *) &IP_TX_HEADER, IpHeaderLength);
  EfiCopyMem (((UINT8 *) &IP_TX_HEADER) + TotalHeaderLength, Data, DataLength);

  //
  // send it
  //
  return SendPacket (
          Private,
          (UINT8 *) &IP_TX_HEADER - Snp->Mode->MediaHeaderSize,
          &IP_TX_HEADER,
          PacketLength,
          &DestMac,
          PXE_PROTOCOL_ETHERNET_IP,
          Function
          );
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

//
// send ipv4 packet with option
//
EFI_STATUS
Ipv4SendWOp (
  PXE_BASECODE_DEVICE         *Private,
  UINT32                      GatewayIp,
  UINT8                       *Msg,
  UINTN                       MessageLength,
  UINT8                       Prot,
  UINT8                       *Option,
  UINTN                       OptionLength,
  UINT32                      DestIp,
  EFI_PXE_BASE_CODE_FUNCTION  Function
  )
{
  EFI_PXE_BASE_CODE_MODE  *PxeBcMode;
  UINTN                   HdrLth;

  PxeBcMode = Private->EfiBc.Mode;
  HdrLth    = sizeof (IPV4_HEADER) + OptionLength;

  EfiZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER));
  IP_TX_HEADER.TimeToLive     = PxeBcMode->TTL;
  IP_TX_HEADER.TypeOfService  = PxeBcMode->ToS;
  IP_TX_HEADER.Protocol       = Prot;
  IP_TX_HEADER.SrcAddr.L      = *(UINT32 *) &PxeBcMode->StationIp;
  IP_TX_HEADER.DestAddr.L     = DestIp;
  IP_TX_HEADER.Id             = Random (Private);
  EfiCopyMem (IP_TX_BUFFER->u.Data, Option, OptionLength);
  return Ipv4Xmt (
          Private,
          GatewayIp,
          HdrLth,
          HdrLth,
          Msg,
          MessageLength,
          Function
          );
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

//
// send MessageLength message at MessagePtr - higher level protocol header already in TransmitBufferPtr, length HdrSize
//
EFI_STATUS
Ip4Send (
  PXE_BASECODE_DEVICE                          *Private,  // pointer to instance data
  UINTN               MayFrag,                            //
  UINT8                                    Prot,          // protocol
  UINT32                          SrcIp,                  // Source IP address
  UINT32                 DestIp,                          // Destination IP address
  UINT32              GatewayIp,                          // used if not NULL and needed
  UINTN               HdrSize,                            // protocol header byte length
  UINT8               *MessagePtr,                        // pointer to data
  UINTN               MessageLength                       // data byte length
  )
{
  EFI_STATUS  StatCode;
  UINTN       TotDataLength;

  TotDataLength = HdrSize + MessageLength;

  if (TotDataLength > MAX_IPV4_DATA_SIZE) {
    DEBUG (
      (EFI_D_WARN,
      "\nIp4Send()  Exit #1  %xh (%r)",
      EFI_BAD_BUFFER_SIZE,
      EFI_BAD_BUFFER_SIZE)
      );

    return EFI_BAD_BUFFER_SIZE;
  }

  EfiZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER));
  IP_TX_HEADER.TimeToLive = DEFAULT_TTL;
  IP_TX_HEADER.Protocol   = Prot;
  IP_TX_HEADER.SrcAddr.L  = SrcIp;
  IP_TX_HEADER.DestAddr.L = DestIp;
  IP_TX_HEADER.Id         = Random (Private);

  if (!MayFrag) {
    *(UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_NO_FRAG >> 8;
  }
  //
  // check for need to fragment
  //
  if (TotDataLength > MAX_IPV4_FRAME_DATA_SIZE) {
    UINTN   DataLengthSent;
    UINT16  FragmentOffset;

    FragmentOffset = IP_MORE_FRAG;
    //
    // frag offset field
    //
    if (!MayFrag) {
      DEBUG (
        (EFI_D_WARN,
        "\nIp4Send()  Exit #2  %xh (%r)",
        EFI_BAD_BUFFER_SIZE,
        EFI_BAD_BUFFER_SIZE)
        );

      return EFI_BAD_BUFFER_SIZE;
    }
    //
    // send out in fragments - first includes upper level header
    // all are max and include more frag bit except last
    //
    * (UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_MORE_FRAG >> 8;

#define IPV4_FRAG_SIZE    (MAX_IPV4_FRAME_DATA_SIZE & 0xfff8)
#define IPV4_FRAG_OFF_INC (IPV4_FRAG_SIZE >> 3)

    DataLengthSent = IPV4_FRAG_SIZE - HdrSize;

    StatCode = Ipv4Xmt (
                Private,
                GatewayIp,
                sizeof (IPV4_HEADER),
                sizeof (IPV4_HEADER) + HdrSize,
                MessagePtr,
                DataLengthSent,
                Private->Function
                );

    if (EFI_ERROR (StatCode)) {
      DEBUG (
        (EFI_D_WARN,
        "\nIp4Send()  Exit #3  %xh (%r)",
        StatCode,
        StatCode)
        );

      return StatCode;
    }

    MessagePtr += DataLengthSent;
    MessageLength -= DataLengthSent;
    FragmentOffset += IPV4_FRAG_OFF_INC;
    IP_TX_HEADER.FragmentFields = HTONS (FragmentOffset);

    while (MessageLength > IPV4_FRAG_SIZE) {
      StatCode = Ipv4Xmt (

⌨️ 快捷键说明

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