// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "mock_netstack.h"

#include <lib/fit/defer.h>
#include <netinet/icmp6.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <src/lib/fxl/logging.h>
#include <zircon/device/ethernet.h>

static constexpr size_t kMtu = 1500;
static constexpr size_t kVmoSize = kMtu * 2;

static constexpr uint8_t kHostMacAddress[ETH_ALEN] = {0x02, 0x1a, 0x11,
                                                      0x00, 0x00, 0x00};
static constexpr uint8_t kGuestMacAddress[ETH_ALEN] = {0x02, 0x1a, 0x11,
                                                       0x00, 0x01, 0x00};

static constexpr uint8_t kHostIpv4Address[4] = {192, 168, 0, 1};
static constexpr uint8_t kGuestIpv4Address[4] = {192, 168, 0, 10};

static constexpr uint16_t kProtocolIpv4 = 0x0800;
static constexpr uint8_t kPacketTypeUdp = 17;
static constexpr uint16_t kTestPort = 4242;

static constexpr uint32_t kMockNicId = 0;

void MockNetstack::AddEthernetDevice(
    std::string topological_path,
    fuchsia::netstack::InterfaceConfig interfaceConfig,
    fidl::InterfaceHandle<::fuchsia::hardware::ethernet::Device> device,
    AddEthernetDeviceCallback callback) {
  auto deferred =
      fit::defer([callback = std::move(callback)]() { callback(kMockNicId); });
  eth_device_ = device.BindSync();

  zx_status_t status;
  std::unique_ptr<fuchsia::hardware::ethernet::Fifos> fifos;
  eth_device_->GetFifos(&status, &fifos);
  if (status != ZX_OK) {
    FXL_LOG(ERROR) << "Failed to get fifos: " << status;
    return;
  }
  rx_ = std::move(fifos->rx);
  tx_ = std::move(fifos->tx);

  status = zx::vmo::create(kVmoSize, 0, &vmo_);
  if (status != ZX_OK) {
    FXL_LOG(ERROR) << "Failed to create vmo: " << status;
    return;
  }

  zx::vmo vmo_dup;
  status =
      vmo_.duplicate(ZX_RIGHTS_IO | ZX_RIGHT_MAP | ZX_RIGHT_TRANSFER, &vmo_dup);
  if (status != ZX_OK) {
    FXL_LOG(ERROR) << "Failed to duplicate vmo: " << status;
    return;
  }

  eth_device_->SetIOBuffer(std::move(vmo_dup), &status);
  if (status != ZX_OK) {
    FXL_LOG(ERROR) << "Failed to set IO buffer: " << status;
    return;
  }

  status = zx::vmar::root_self()->map(
      0, vmo_, 0, kVmoSize,
      ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_REQUIRE_NON_RESIZABLE,
      &io_addr_);
  if (status != ZX_OK) {
    FXL_LOG(ERROR) << "Failed to map vmo: " << status;
    return;
  }

  eth_fifo_entry_t entry;
  entry.offset = 0;
  entry.length = kMtu;
  entry.flags = 0;
  entry.cookie = 0;
  status = rx_.write(sizeof(eth_fifo_entry_t), &entry, 1, nullptr);
  if (status != ZX_OK) {
    FXL_LOG(ERROR) << "Failed to write to rx fifo: " << status;
    return;
  }

  eth_device_->Start(&status);
  if (status != ZX_OK) {
    FXL_LOG(ERROR) << "Failed to start ethernet device: " << status;
    return;
  }
}

void MockNetstack::SetInterfaceAddress(uint32_t nicid,
                                       fuchsia::net::IpAddress addr,
                                       uint8_t prefixLen,
                                       SetInterfaceAddressCallback callback) {
  fuchsia::netstack::NetErr err;

  if (nicid != kMockNicId) {
    err.status = fuchsia::netstack::Status::UNKNOWN_INTERFACE;
    err.message = "No such interface.";
  } else {
    err.status = fuchsia::netstack::Status::OK;
    err.message = "";
  }

  callback(std::move(err));
}

static uint16_t checksum(const void* _data, size_t len, uint16_t _sum) {
  uint32_t sum = _sum;
  auto data = static_cast<const uint16_t*>(_data);
  for (; len > 1; len -= 2) {
    sum += *data++;
  }
  if (len) {
    sum += (*data & UINT8_MAX);
  }
  while (sum > UINT16_MAX) {
    sum = (sum & UINT16_MAX) + (sum >> 16);
  }
  return ~sum;
}

static size_t make_ip_header(uint8_t packet_type, size_t length,
                             uint8_t* data) {
  // First construct the ethernet header.
  ethhdr* eth = reinterpret_cast<ethhdr*>(data);
  memcpy(eth->h_dest, kGuestMacAddress, ETH_ALEN);
  memcpy(eth->h_source, kHostMacAddress, ETH_ALEN);
  eth->h_proto = htons(kProtocolIpv4);

  // Now construct the IPv4 header.
  auto ip = reinterpret_cast<iphdr*>(data + sizeof(ethhdr));
  ip->version = 4;
  ip->ihl = sizeof(iphdr) >> 2;  // Header length in 32-bit words.
  ip->tos = 0;
  ip->tot_len = htons(sizeof(iphdr) + length);
  ip->id = 0;
  ip->frag_off = 0;
  ip->ttl = UINT8_MAX;
  ip->protocol = packet_type;
  memcpy(&ip->saddr, kHostIpv4Address, sizeof(kHostIpv4Address));
  memcpy(&ip->daddr, kGuestIpv4Address, sizeof(kGuestIpv4Address));
  ip->check = 0;
  ip->check = checksum(ip, sizeof(iphdr), 0);

  return sizeof(ethhdr) + sizeof(iphdr);
}

zx_status_t MockNetstack::SendUdpPacket(void* packet, size_t length) const {
  struct udp_hdr_t {
    uint16_t src_port;
    uint16_t dst_port;
    uint16_t length;
    uint16_t checksum;
  } __PACKED;

  size_t packet_length = sizeof(udp_hdr_t) + length;
  size_t total_length = sizeof(ethhdr) + sizeof(iphdr) + packet_length;
  if (total_length > kMtu) {
    return ZX_ERR_BUFFER_TOO_SMALL;
  }

  uint8_t data[kMtu];
  size_t header_len = make_ip_header(kPacketTypeUdp, packet_length, data);

  uintptr_t off = header_len;
  auto udp = reinterpret_cast<udp_hdr_t*>(data + off);
  udp->src_port = htons(kTestPort);
  udp->dst_port = htons(kTestPort);
  udp->length = htons(sizeof(udp_hdr_t) + length);
  // The checksum is optional for IPv4.
  udp->checksum = 0;

  off += sizeof(udp_hdr_t);
  memcpy(data + off, packet, length);

  return SendPacket(data, total_length);
}

zx_status_t MockNetstack::SendPacket(void* packet, size_t length) const {
  if (length > kMtu) {
    return ZX_ERR_INVALID_ARGS;
  }

  eth_fifo_entry_t entry;
  entry.offset = kMtu;
  entry.length = length;
  entry.flags = 0;
  entry.cookie = 0;
  size_t count;
  memcpy(reinterpret_cast<void*>(io_addr_ + entry.offset), packet, length);
  zx_status_t status = tx_.write(sizeof(eth_fifo_entry_t), &entry, 1, &count);
  if (status != ZX_OK) {
    return status;
  }
  if (count != 1) {
    return ZX_ERR_INTERNAL;
  }

  zx_signals_t pending = 0;
  status = tx_.wait_one(ZX_FIFO_READABLE | ZX_FIFO_PEER_CLOSED,
                        zx::deadline_after(kTestTimeout), &pending);
  if (status != ZX_OK) {
    return status;
  } else if (pending & ZX_SOCKET_PEER_CLOSED) {
    return ZX_ERR_PEER_CLOSED;
  }

  status = tx_.read(sizeof(eth_fifo_entry_t), &entry, 1, nullptr);
  if (status != ZX_OK) {
    return status;
  }
  if (entry.flags != ETH_FIFO_TX_OK) {
    return ZX_ERR_IO;
  }

  return ZX_OK;
}

zx_status_t MockNetstack::ReceivePacket(void* packet, size_t length,
                                        size_t* actual) const {
  eth_fifo_entry_t entry;

  zx_signals_t pending = 0;
  zx_status_t status = rx_.wait_one(ZX_FIFO_READABLE | ZX_FIFO_PEER_CLOSED,
                                    zx::deadline_after(kTestTimeout), &pending);
  if (status != ZX_OK) {
    return status;
  } else if (pending & ZX_SOCKET_PEER_CLOSED) {
    return ZX_ERR_PEER_CLOSED;
  }

  status = rx_.read(sizeof(eth_fifo_entry_t), &entry, 1, nullptr);
  if (status != ZX_OK) {
    return status;
  }
  if (entry.flags != ETH_FIFO_RX_OK) {
    return ZX_ERR_IO;
  }
  if (entry.length > length) {
    return ZX_ERR_BUFFER_TOO_SMALL;
  }
  memcpy(packet, reinterpret_cast<void*>(io_addr_ + entry.offset), length);
  *actual = entry.length;

  memset(reinterpret_cast<void*>(io_addr_), 0, kMtu);
  entry.offset = 0;
  entry.length = kMtu;
  entry.flags = 0;
  entry.cookie = 0;
  status = rx_.write(sizeof(eth_fifo_entry_t), &entry, 1, nullptr);
  if (status != ZX_OK) {
    FXL_LOG(ERROR) << "Failed to write to rx fifo: " << status;
    return status;
  }

  return ZX_OK;
}
