Newer
Older
AMI-Aptio-BIOS-Reversed / MnpDxe / MnpMain.c
@Ajax Dong Ajax Dong 2 days ago 12 KB Init
/**
 * @file MnpMain.c
 *
 * @brief MNP Protocol Implementation
 *
 * This file implements the EFI_MANAGED_NETWORK_PROTOCOL interfaces:
 *   - GetModeData:   Retrieve MNP and SNP mode data
 *   - Configure:     Configure or reset the MNP instance
 *   - MulticastReceive: Join/leave multicast groups
 *   - Transmit:      Transmit a packet via the MNP service
 *   - Receive:       Receive a packet asynchronously
 *   - Cancel:        Cancel a pending transmit/receive token
 *   - Poll:          Poll for incoming packets
 *
 * Source: AmiNetworkPkg/UefiNetworkStack/Common/MnpDxe/MnpMain.c
 */

#include "MnpDxe.h"

//
// External globals (defined in ModuleEntry.c or MnpDriver.c)
//
extern EFI_BOOT_SERVICES  *gBS;
extern EFI_HANDLE          gImageHandle;
extern VOID               *gDpcProtocol;   /* DPC protocol interface */

/* ====================================================================== */
/*  GetModeData                                                           */
/* ====================================================================== */

/**
 * Retrieve the current MNP configuration data and/or underlying SNP mode
 * data for this instance.
 *
 * @param[in]  This           Protocol instance pointer.
 * @param[out] MnpConfigData  Optional buffer to receive MNP config data.
 * @param[out] SnpModeData    Optional buffer to receive SNP mode data.
 *
 * @retval EFI_SUCCESS           Data retrieved successfully.
 * @retval EFI_NOT_STARTED       Instance has not been configured.
 * @retval EFI_INVALID_PARAMETER This is NULL.
 */
EFI_STATUS
EFIAPI
MnpGetModeData (
  IN  EFI_MANAGED_NETWORK_PROTOCOL  *This,
  OUT EFI_MNP_CONFIG_DATA           *MnpConfigData    OPTIONAL,
  OUT EFI_SIMPLE_NETWORK_MODE       *SnpModeData      OPTIONAL
  )
{
  MNP_INSTANCE_DATA  *Instance;
  MNP_SERVICE_DATA   *Service;
  MNP_DEVICE_DATA    *Device;
  EFI_TPL             OldTpl;

  if (This == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  Instance = MNP_INSTANCE_DATA_FROM_THIS (This);
  CR_CHECK (Instance, MNP_INSTANCE_DATA_SIGNATURE);

  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);

  Service = Instance->MnpServiceData;
  Device  = Service->MnpDeviceData;

  if (MnpConfigData != NULL) {
    CopyMem (MnpConfigData, &Instance->ConfigData, sizeof (EFI_MNP_CONFIG_DATA));
  }

  if (SnpModeData != NULL && Device->Snp != NULL) {
    CopyMem (SnpModeData, Device->Snp->Mode, sizeof (EFI_SIMPLE_NETWORK_MODE));
  }

  gBS->RestoreTPL (OldTpl);

  return Instance->IsConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;
}

/* ====================================================================== */
/*  Configure                                                            */
/* ====================================================================== */

/**
 * Configure or reset the MNP instance.
 *
 * When MnpConfigData is NULL, the instance is reset (stopped).
 * When MnpConfigData is valid, the instance is configured with the provided
 * settings.
 *
 * @param[in] This           Protocol instance pointer.
 * @param[in] MnpConfigData  Configuration data, or NULL to reset.
 *
 * @retval EFI_SUCCESS           Configured/reset successfully.
 * @retval EFI_INVALID_PARAMETER This is NULL, or config data is invalid.
 * @retval EFI_ALREADY_STARTED   Instance is already configured.
 */
EFI_STATUS
EFIAPI
MnpConfigure (
  IN EFI_MANAGED_NETWORK_PROTOCOL  *This,
  IN EFI_MNP_CONFIG_DATA           *MnpConfigData    OPTIONAL
  )
{
  MNP_INSTANCE_DATA  *Instance;
  EFI_STATUS          Status;
  EFI_TPL             OldTpl;

  if (This == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (MnpConfigData != NULL &&
      MnpConfigData->ProtocolType > 0 &&
      MnpConfigData->ProtocolType <= 1500) {
    return EFI_INVALID_PARAMETER;
  }

  Instance = MNP_INSTANCE_DATA_FROM_THIS (This);

  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);

  if (MnpConfigData != NULL || Instance->IsConfigured) {
    Status = MnpConfigureInstance (Instance, MnpConfigData);
  } else {
    Status = EFI_SUCCESS;
  }

  gBS->RestoreTPL (OldTpl);

  return Status;
}

/* ====================================================================== */
/*  MulticastReceive (protocol entry point)                               */
/* ====================================================================== */

/**
 * Build the multicast MAC address from the IP address into the provided
 * buffer. This wraps SNP's MCastIPtoMAC or handles it locally.
 *
 * @param[in]  This        Protocol instance pointer.
 * @param[in]  Flag        TRUE for join, FALSE for leave.
 * @param[in]  MacAddress  IP address to translate.
 * @param[out] buf         Buffer for the resulting MAC address.
 *
 * @retval EFI_SUCCESS           MAC address resolved.
 * @retval EFI_INVALID_PARAMETER Invalid parameters.
 */
EFI_STATUS
EFIAPI
MnpMulticastReceive (
  IN EFI_MANAGED_NETWORK_PROTOCOL  *This,
  IN BOOLEAN                       Flag,
  IN EFI_MAC_ADDRESS               *MacAddress,
  OUT EFI_MAC_ADDRESS              *buf
  )
{
  MNP_INSTANCE_DATA  *Instance;
  MNP_DEVICE_DATA    *Device;
  EFI_SIMPLE_NETWORK *Snp;
  EFI_STATUS          Status;
  EFI_TPL             OldTpl;
  UINT8              *SnpModeData;

  Status = EFI_SUCCESS;

  if (This == NULL || MacAddress == NULL || buf == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (!MnpIsValidMulticastAddress (Flag, MacAddress)) {
    return EFI_INVALID_PARAMETER;
  }

  Instance = MNP_INSTANCE_DATA_FROM_THIS (This);

  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);

  if (!Instance->IsConfigured) {
    Status = EFI_NOT_STARTED;
    goto Exit;
  }

  Device = Instance->MnpServiceData->MnpDeviceData;
  Snp    = Device->Snp;

  if (Snp == NULL) {
    Status = EFI_NOT_STARTED;
    goto Exit;
  }

  //
  // Clear the buffer and build the MAC.
  //
  ZeroMem (buf, sizeof (EFI_MAC_ADDRESS));

  SnpModeData = Snp->Mode;

  if (SnpModeData[648] == 1) {
    //
    // IP4: build ETH multicast MAC.
    //
    if (Flag) {
      *(UINT16 *)buf = 0x3333;
      buf->Addr[2] = MacAddress->Addr[12];
      buf->Addr[3] = MacAddress->Addr[13];
      buf->Addr[4] = MacAddress->Addr[14];
      buf->Addr[5] = MacAddress->Addr[15];
    } else {
      *(UINT16 *)buf = 0x0100;
      buf->Addr[2] = 0x5E;
      buf->Addr[3] = MacAddress->Addr[1] & 0x7F;
      buf->Addr[4] = MacAddress->Addr[2];
      buf->Addr[5] = MacAddress->Addr[3];
    }
  } else {
    Status = Snp->MCastIPtoMAC (Snp, Flag, MacAddress, buf);
  }

Exit:
  gBS->RestoreTPL (OldTpl);
  return Status;
}

/* ====================================================================== */
/*  Transmit                                                             */
/* ====================================================================== */

/**
 * Transmit a packet via the MNP service.
 *
 * @param[in] This   Protocol instance pointer.
 * @param[in] Token  Completion token containing TxData.
 *
 * @retval EFI_SUCCESS           Token queued for transmission.
 * @retval EFI_INVALID_PARAMETER This or Token is NULL.
 * @retval EFI_NOT_STARTED       Instance is not configured.
 */
EFI_STATUS
EFIAPI
MnpTransmit (
  IN EFI_MANAGED_NETWORK_PROTOCOL          *This,
  IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token
  )
{
  MNP_INSTANCE_DATA  *Instance;
  MNP_SERVICE_DATA   *Service;
  EFI_STATUS          Status;
  EFI_TPL             OldTpl;

  if (This == NULL || Token == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  Instance = MNP_INSTANCE_DATA_FROM_THIS (This);

  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);

  if (!Instance->IsConfigured) {
    Status = EFI_NOT_STARTED;
    goto Exit;
  }

  if (!MnpIsValidTxToken (Instance, Token)) {
    Status = EFI_INVALID_PARAMETER;
    goto Exit;
  }

  Service = Instance->MnpServiceData;
  if (Service == NULL || Service->Signature != MNP_SERVICE_DATA_SIGNATURE) {
    DEBUG ((DEBUG_ERROR, "Invalid MnpServiceData in MnpTransmit\n"));
    Status = EFI_INVALID_PARAMETER;
    goto Exit;
  }

  //
  // Serialize fragment table and send synchronously.
  //
  Status = MnpSerializeFragment (
             Service,
             Token->Packet.TxData,
             &Token->Packet.TxData->FragmentTable[0],
             &Token->Packet.TxData->FragmentCount
             );

  if (Status == EFI_SUCCESS) {
    Status = MnpSyncSendPacket (
               Service,
               Token->Packet.TxData->FragmentTable,
               Token->Packet.TxData->FragmentCount,
               Token
               );
  }

Exit:
  gBS->RestoreTPL (OldTpl);
  return Status;
}

/* ====================================================================== */
/*  Receive                                                              */
/* ====================================================================== */

/**
 * Receive a packet asynchronously. A token is queued and signalled when
 * data arrives.
 *
 * @param[in] This   Protocol instance pointer.
 * @param[in] Token  Completion token for the receive operation.
 *
 * @retval EFI_SUCCESS             Token queued for receive.
 * @retval EFI_INVALID_PARAMETER   This, Token, or Token->Event is NULL.
 * @retval EFI_NOT_STARTED         Instance is not configured.
 * @retval EFI_OUT_OF_RESOURCES    No resources for receive map entry.
 */
EFI_STATUS
EFIAPI
MnpReceive (
  IN EFI_MANAGED_NETWORK_PROTOCOL          *This,
  IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token
  )
{
  MNP_INSTANCE_DATA  *Instance;
  EFI_STATUS          Status;
  EFI_TPL             OldTpl;

  if (This == NULL || Token == NULL || Token->Event == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  Instance = MNP_INSTANCE_DATA_FROM_THIS (This);

  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);

  if (!Instance->IsConfigured) {
    Status = EFI_NOT_STARTED;
    goto Exit;
  }

  //
  // Check if token is already registered.
  //
  Status = NetMapFindPosition (
             &Instance->RcvMap,
             (NET_MAP_ITEM_CALLBACK)MnpFindRxToken,
             Token
             );

  if (Status == EFI_SUCCESS) {
    //
    // Token not found; allocate a map entry and queue it.
    //
    NET_MAP_ITEM  *MapItem;

    MapItem = NetMapAlloc (&Instance->RcvMap);
    if (MapItem == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      goto Exit;
    }

    MapItem->Token    = Token;
    MapItem->UserData = NULL;

    InsertTailList (&Instance->RcvMap.Free, &MapItem->Link);
    Instance->RcvMap.ItemCount++;

    //
    // Try to deliver any pending packet immediately.
    //
    Status = MnpDeliverPacket (Instance);
    ((DPC_PROTOCOL *)gDpcProtocol)->QueueDpc (gDpcProtocol);
  }

Exit:
  gBS->RestoreTPL (OldTpl);
  return Status;
}

/* ====================================================================== */
/*  Cancel                                                               */
/* ====================================================================== */

/**
 * Cancel a pending token.
 *
 * If Token is NULL, all pending tokens are cancelled.
 *
 * @param[in] This   Protocol instance pointer.
 * @param[in] Token  Optional token to cancel.
 *
 * @retval EFI_SUCCESS             Token(s) cancelled.
 * @retval EFI_INVALID_PARAMETER   This is NULL.
 * @retval EFI_NOT_STARTED         Instance is not configured.
 */
EFI_STATUS
EFIAPI
MnpCancel (
  IN EFI_MANAGED_NETWORK_PROTOCOL          *This,
  IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token    OPTIONAL
  )
{
  MNP_INSTANCE_DATA  *Instance;
  EFI_STATUS          Status;
  EFI_TPL             OldTpl;

  if (This == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  Instance = MNP_INSTANCE_DATA_FROM_THIS (This);

  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);

  if (!Instance->IsConfigured) {
    Status = EFI_NOT_STARTED;
    goto Exit;
  }

  Status = NetMapIterate (
             &Instance->RcvMap,
             (NET_MAP_ITEM_CALLBACK)MnpCancelRxToken,
             Token
             );

  ((DPC_PROTOCOL *)gDpcProtocol)->QueueDpc (gDpcProtocol);

Exit:
  gBS->RestoreTPL (OldTpl);
  return Status;
}

/* ====================================================================== */
/*  Poll                                                                 */
/* ====================================================================== */

/**
 * Poll for incoming packets.
 *
 * @param[in] This  Protocol instance pointer.
 *
 * @retval EFI_SUCCESS             Poll completed.
 * @retval EFI_INVALID_PARAMETER   This is NULL.
 * @retval EFI_NOT_STARTED         Instance is not configured.
 */
EFI_STATUS
EFIAPI
MnpPoll (
  IN EFI_MANAGED_NETWORK_PROTOCOL  *This
  )
{
  MNP_INSTANCE_DATA  *Instance;
  MNP_DEVICE_DATA    *Device;
  EFI_STATUS          Status;
  EFI_TPL             OldTpl;

  if (This == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  Instance = MNP_INSTANCE_DATA_FROM_THIS (This);

  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);

  if (!Instance->IsConfigured) {
    Status = EFI_NOT_STARTED;
    goto Exit;
  }

  Device = Instance->MnpServiceData->MnpDeviceData;
  Status = MnpReceivePacket (Device);

  ((DPC_PROTOCOL *)gDpcProtocol)->QueueDpc (gDpcProtocol);

Exit:
  gBS->RestoreTPL (OldTpl);
  return Status;
}