blob: 445285922f791929f850f4ef2adb13bfeed5e316 [file] [log] [blame]
// 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 <endian.h>
#include <fcntl.h>
#include <lib/fdio/watcher.h>
#include <lib/zx/channel.h>
#include <lib/zx/port.h>
#include <unistd.h>
#include <array>
#include <fbl/string.h>
#include <gtest/gtest.h>
#include <src/connectivity/telephony/drivers/qmi-usb-transport/qmi-usb-transport.h>
namespace {
constexpr std::array<uint8_t, qmi_usb::kMacAddrLen> kEthClientMacAddr = {10, 11, 12, 13, 14, 15};
constexpr std::array<uint8_t, qmi_usb::kMacAddrLen> kEthBroadcastMacAddr = {0xff, 0xff, 0xff,
0xff, 0xff, 0xff};
constexpr std::array<uint8_t, qmi_usb::kIpv4AddrLen> kEthClientIpAddr = {10, 0, 0, 2};
constexpr std::array<uint8_t, qmi_usb::kIpv4AddrLen> kEthHostIpAddr = {10, 0, 0, 3};
constexpr uint32_t kEthMtu = 1518;
class TelDriverUnitTest : public ::testing::Test {
public:
void SetEthData(const uint8_t* data, uint32_t data_len) {
if (data_len <= kEthMtu) {
data_.assign(data, data + data_len);
};
}
std::vector<uint8_t>& GetEthData() { return data_; }
uint32_t GetEthDataLen() { return data_.size(); }
private:
std::vector<uint8_t> data_;
};
static ethernet_ifc_protocol_ops_t ifc_ops = {
.recv =
[](void* ctx, const uint8_t* data_buffer, size_t data_size, uint32_t flags) {
static_cast<TelDriverUnitTest*>(ctx)->SetEthData(static_cast<const uint8_t*>(data_buffer),
data_size);
},
};
TEST_F(TelDriverUnitTest, EthArpHandling) {
std::array<uint8_t, 100> tmp;
zx_device_t* device_parent_ptr = reinterpret_cast<zx_device_t*>(tmp.data());
auto device = std::make_unique<::qmi_usb::Device>(device_parent_ptr);
ethernet_ifc_protocol_t ifc = {
.ops = &ifc_ops,
.ctx = this,
};
device->EthClientInit(&ifc);
device->EthTxListNodeInit();
qmi_usb::EthArpFrame eth_arp_frame;
std::copy(kEthClientMacAddr.begin(), kEthClientMacAddr.end(), eth_arp_frame.eth_hdr.src_mac_addr);
std::copy(kEthBroadcastMacAddr.begin(), kEthBroadcastMacAddr.end(),
eth_arp_frame.eth_hdr.dst_mac_addr);
eth_arp_frame.eth_hdr.ethertype = betoh16(qmi_usb::kEthertypeArp);
std::copy(kEthClientMacAddr.begin(), kEthClientMacAddr.end(), eth_arp_frame.arp.src_mac_addr);
std::copy(kEthBroadcastMacAddr.begin(), kEthBroadcastMacAddr.end(),
eth_arp_frame.arp.dst_mac_addr);
std::copy(kEthClientIpAddr.begin(), kEthClientIpAddr.end(), eth_arp_frame.arp.src_ip_addr);
std::copy(kEthHostIpAddr.begin(), kEthHostIpAddr.end(), eth_arp_frame.arp.dst_ip_addr);
std::copy(qmi_usb::kArpReqHdr.begin(), qmi_usb::kArpReqHdr.end(),
reinterpret_cast<uint8_t*>(&eth_arp_frame.arp.arp_hdr));
ethernet_netbuf_t netbuf;
netbuf.data_buffer = reinterpret_cast<uint8_t*>(&eth_arp_frame);
netbuf.data_size = sizeof(eth_arp_frame);
device->EthernetImplQueueTx(0, &netbuf, NULL, NULL);
ASSERT_EQ(GetEthDataLen(), static_cast<uint32_t>(qmi_usb::kEthFrameHdrSize + qmi_usb::kArpSize));
qmi_usb::EthArpFrame eth_arp_resp = *reinterpret_cast<qmi_usb::EthArpFrame*>(GetEthData().data());
ASSERT_EQ(
memcmp(eth_arp_resp.eth_hdr.dst_mac_addr, kEthClientMacAddr.data(), kEthClientMacAddr.size()),
0);
ASSERT_EQ(memcmp(eth_arp_resp.eth_hdr.src_mac_addr, qmi_usb::kFakeMacAddr.data(),
qmi_usb::kFakeMacAddr.size()),
0);
ASSERT_EQ(betoh16(eth_arp_frame.eth_hdr.ethertype), qmi_usb::kEthertypeArp);
ASSERT_EQ(
memcmp(eth_arp_resp.arp.dst_mac_addr, kEthClientMacAddr.data(), kEthClientMacAddr.size()), 0);
ASSERT_EQ(memcmp(eth_arp_resp.arp.src_mac_addr, qmi_usb::kFakeMacAddr.data(),
qmi_usb::kFakeMacAddr.size()),
0);
ASSERT_EQ(memcmp(eth_arp_resp.arp.dst_ip_addr, kEthClientIpAddr.data(), kEthClientIpAddr.size()),
0);
ASSERT_EQ(memcmp(eth_arp_resp.arp.src_ip_addr, kEthHostIpAddr.data(), kEthHostIpAddr.size()), 0);
ASSERT_EQ(
memcmp(&eth_arp_resp.arp.arp_hdr, qmi_usb::kArpRespHdr.data(), qmi_usb::kArpReqHdr.size()),
0);
}
} // namespace