/*
 * Copyright (c) 2020 The Fuchsia Authors
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "src/connectivity/wlan/drivers/third_party/broadcom/brcmfmac/sim/sim_errinj.h"

#include <cstring>

#include "src/connectivity/wlan/drivers/third_party/broadcom/brcmfmac/bcdc.h"
#include "src/connectivity/wlan/drivers/third_party/broadcom/brcmfmac/bits.h"
#include "src/connectivity/wlan/drivers/third_party/broadcom/brcmfmac/fwil.h"
#include "src/connectivity/wlan/drivers/third_party/broadcom/brcmfmac/fwsignal.h"

namespace wlan::brcmfmac {

SimErrorInjector::SimErrorInjector() {}
SimErrorInjector::~SimErrorInjector() {}

void SimErrorInjector::AddErrInjCmd(uint32_t cmd, zx_status_t status,
                                    std::optional<uint16_t> ifidx) {
  for (auto it = cmds_.begin(); it != cmds_.end(); ++it) {
    if (it->cmd == cmd) {
      // Entry already present, just replace with the new values
      BRCMF_DBG(SIMERRINJ, "entry cmd: %d if:%d status:%d present, replace", cmd,
                ifidx.value_or(-1), status);
      it->ifidx = ifidx;
      it->ret_status = status;
      return;
    }
  }
  ErrInjCmd err_inj_cmd(cmd, status, ifidx);
  cmds_.push_back(err_inj_cmd);
  BRCMF_DBG(SIMERRINJ, "Num entries in list: %lu\n", cmds_.size());
}

void SimErrorInjector::DelErrInjCmd(uint32_t cmd) {
  for (auto it = cmds_.begin(); it != cmds_.end(); ++it) {
    if (it->cmd == cmd) {
      BRCMF_DBG(SIMERRINJ, "Del Err Inj entry found status:%d cmd:%d", it->ret_status, cmd);
      cmds_.erase(it);
      BRCMF_DBG(SIMERRINJ, "Num entries in list: %lu\n", cmds_.size());
      return;
    }
  }
  BRCMF_DBG(SIMERRINJ, "Cmd: %d not found", cmd);
}

void SimErrorInjector::AddErrInjIovar(const char* iovar, zx_status_t status,
                                      std::optional<uint16_t> ifidx) {
  for (auto it = iovars_.begin(); it != iovars_.end(); ++it) {
    if (it->iovar.size() == strlen(iovar) + 1 &&
        (memcmp(iovar, it->iovar.data(), it->iovar.size()) == 0)) {
      // Entry already present
      BRCMF_DBG(SIMERRINJ, "entry iovar: %s if:%d status:%d present, replace", iovar,
                ifidx.value_or(-1), status);
      it->ifidx = ifidx;
      it->ret_status = status;
      return;
    }
  }
  ErrInjIovar err_inj_iovar(iovar, status, ifidx);
  iovars_.push_back(err_inj_iovar);
  BRCMF_DBG(SIMERRINJ, "Num entries in list: %lu\n", iovars_.size());
}

void SimErrorInjector::DelErrInjIovar(const char* iovar) {
  for (auto it = iovars_.begin(); it != iovars_.end(); ++it) {
    if (it->iovar.size() > 0 && memcmp(it->iovar.data(), iovar, strlen(iovar) + 1)) {
      BRCMF_DBG(SIMERRINJ, "Del Err Inj entry found status:%d iovar:%s", it->ret_status, iovar);
      iovars_.erase(it);
      BRCMF_DBG(SIMERRINJ, "Num entries in list: %lu\n", iovars_.size());
      return;
    }
  }
  BRCMF_DBG(SIMERRINJ, "iovar: %s not found", iovar);
}

bool SimErrorInjector::CheckIfErrInjCmdEnabled(uint32_t cmd, zx_status_t* ret_status,
                                               uint16_t ifidx) {
  for (auto it = cmds_.begin(); it != cmds_.end(); ++it) {
    if (((it->ifidx.has_value() && (it->ifidx == ifidx)) || !it->ifidx.has_value()) &&
        (it->cmd == cmd)) {
      BRCMF_DBG(SIMERRINJ, "Err Inj entry found if:%d status:%d cmd:%d", ifidx, it->ret_status,
                cmd);
      if (ret_status) {
        *ret_status = it->ret_status;
      }
      return true;
    }
  }
  BRCMF_DBG(SIMERRINJ, "Cmd: %d ifidx: %d not found", cmd, ifidx);
  return false;
}

bool SimErrorInjector::CheckIfErrInjIovarEnabled(const char* iovar, zx_status_t* ret_status,
                                                 uint16_t ifidx) {
  for (auto it = iovars_.begin(); it != iovars_.end(); ++it) {
    if (((it->ifidx.has_value() && (it->ifidx == ifidx)) || !it->ifidx.has_value()) &&
        it->iovar.size() == strlen(iovar) + 1 &&
        (!std::memcmp(it->iovar.data(), iovar, it->iovar.size()))) {
      BRCMF_DBG(SIMERRINJ, "Err Inj entry found if:%d status:%d iovar:%s", ifidx, it->ret_status,
                iovar);
      if (ret_status) {
        *ret_status = it->ret_status;
      }
      return true;
    }
  }
  BRCMF_DBG(SIMERRINJ, "iovar: %s ifidx: %d not found", iovar, ifidx);
  return false;
}

void SimErrorInjector::SetSignalErrInj(bool enable) { enable_rssi_sig_err_ = enable; }

// Rx frame related error injection. Currently, supports only rssi signal error injection.
bool SimErrorInjector::HandleRxFrameErrorInjection(uint8_t* buffer) {
  // This could potentially become a switch statement if we need to other types of
  // error injection into the Rx frame.
  if (enable_rssi_sig_err_ == false)
    return false;

  // This routine sets the rssi value (if signal is enabled) to zero.
  auto header = reinterpret_cast<brcmf_proto_bcdc_header*>(buffer);
  size_t header_offset = sizeof(brcmf_proto_bcdc_header);
  if (header->data_offset) {
    // data offset is in words
    uint8_t data_offset_bytes = header->data_offset << 2;
    uint8_t signal_size_bytes = FWS_TLV_TYPE_SIZE + FWS_TLV_LEN_SIZE + FWS_RSSI_DATA_LEN;
    if (data_offset_bytes < signal_size_bytes) {
      // Signal data not valid
      return false;
    }

    // If the signal is RSSI, set the rssi value to 0
    if (buffer[header_offset + FWS_TLV_TYPE_OFFSET] == BRCMF_FWS_TYPE_RSSI &&
        buffer[header_offset + FWS_TLV_LEN_OFFSET] == FWS_RSSI_DATA_LEN) {
      buffer[header_offset + FWS_TLV_DATA_OFFSET] = 0;
      // indicate that the rssi signal was modified.
      return true;
    }
  }
  return false;
}
}  // namespace wlan::brcmfmac
