blob: 709fdc202ba725b8fd8e5f815b60767ba5db1f69 [file] [log] [blame]
// Copyright 2020 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 <vector>
#include <zxtest/zxtest.h>
#include "usb-cdc-ecm-lib.h"
namespace {
class UsbCdcEcmTest : public zxtest::Test {
public:
void SetUp() override {
proto_.ops = &ops_;
proto_.ctx = this;
ops_.get_descriptors_length = UsbGetDescriptorsLength;
ops_.get_descriptors = UsbGetDescriptors;
ops_.control_in = UsbControlIn;
iter = {};
}
void TearDown() override {
if (iter.desc) {
usb_desc_iter_release(&iter);
}
}
protected:
static void UsbGetDescriptors(void* ctx, uint8_t* out_descs_buffer, size_t descs_size,
size_t* out_descs_actual) {
auto test = reinterpret_cast<UsbCdcEcmTest*>(ctx);
size_t descriptors_length = test->GetDescriptorLength();
if (descs_size < descriptors_length) {
descriptors_length = descs_size;
}
memcpy(out_descs_buffer, test->GetDescriptors(), descriptors_length);
*out_descs_actual = descriptors_length;
}
static size_t UsbGetDescriptorsLength(void* ctx) {
auto test = reinterpret_cast<UsbCdcEcmTest*>(ctx);
return test->GetDescriptorLength();
}
static zx_status_t UsbControlIn(void* ctx, uint8_t request_type, uint8_t request, uint16_t value,
uint16_t index, int64_t timeout, uint8_t* out_read_buffer,
size_t read_size, size_t* out_read_actual) {
if (!(request_type & USB_DIR_IN && request == USB_REQ_GET_DESCRIPTOR)) {
return ZX_ERR_INTERNAL;
}
const size_t expected_str_size = sizeof(usb_string_descriptor_t) + ETH_MAC_SIZE * 4;
if (read_size < expected_str_size) {
return ZX_ERR_INVALID_ARGS;
}
*out_read_actual = expected_str_size;
usb_string_descriptor_t usb_str;
usb_str.bLength = expected_str_size;
usb_str.bDescriptorType = USB_DT_STRING;
memcpy(out_read_buffer, &usb_str, sizeof(usb_string_descriptor_t));
uint8_t* ptr = reinterpret_cast<uint8_t*>(out_read_buffer) + sizeof(usb_string_descriptor_t);
for (size_t i = 0; i < ETH_MAC_SIZE; i++) {
memcpy(ptr, "F\0F\0", 4);
ptr += 4;
}
return ZX_OK;
}
void SetDescriptors(void* descriptors) { descriptors_ = descriptors; }
void* GetDescriptors() { return descriptors_; }
void SetDescriptorLength(size_t descriptor_length) { descriptor_length_ = descriptor_length; }
size_t GetDescriptorLength() { return descriptor_length_; }
usb_protocol_t* GetUsbProto() { return &proto_; }
usb_protocol_t proto_{};
usb_protocol_ops_t ops_{};
void* descriptors_ = nullptr;
size_t descriptor_length_ = 0;
usb_desc_iter_t iter;
};
TEST_F(UsbCdcEcmTest, ParseUsbDescriptorTest) {
std::vector<uint8_t> buffer;
usb_interface_descriptor_t test_default_ifc = {
.b_length = sizeof(usb_interface_descriptor_t),
.b_descriptor_type = USB_DT_INTERFACE,
.b_interface_number = 0,
.b_alternate_setting = 0,
.b_num_endpoints = 0,
.b_interface_class = USB_CLASS_CDC,
.b_interface_sub_class = 0,
.b_interface_protocol = 0,
.i_interface = 0,
};
buffer.insert(buffer.end(), reinterpret_cast<uint8_t*>(&test_default_ifc),
reinterpret_cast<uint8_t*>(&test_default_ifc) + sizeof(test_default_ifc));
usb_interface_descriptor_t test_interrupt_ifc = {
.b_length = sizeof(usb_interface_descriptor_t),
.b_descriptor_type = USB_DT_INTERFACE,
.b_interface_number = 0,
.b_alternate_setting = 0,
.b_num_endpoints = 1,
.b_interface_class = USB_CLASS_CDC,
.b_interface_sub_class = 0,
.b_interface_protocol = 0,
.i_interface = 0,
};
buffer.insert(buffer.end(), reinterpret_cast<uint8_t*>(&test_interrupt_ifc),
reinterpret_cast<uint8_t*>(&test_interrupt_ifc) + sizeof(test_interrupt_ifc));
usb_endpoint_descriptor_t test_int_ep = {
.b_length = sizeof(usb_endpoint_descriptor_t),
.b_descriptor_type = USB_DT_ENDPOINT,
.b_endpoint_address = USB_ENDPOINT_IN,
.bm_attributes = USB_ENDPOINT_INTERRUPT,
.w_max_packet_size = 0,
.b_interval = 0,
};
buffer.insert(buffer.end(), reinterpret_cast<uint8_t*>(&test_int_ep),
reinterpret_cast<uint8_t*>(&test_int_ep) + sizeof(test_int_ep));
usb_interface_descriptor_t test_data_ifc = {
.b_length = sizeof(usb_interface_descriptor_t),
.b_descriptor_type = USB_DT_INTERFACE,
.b_interface_number = 0,
.b_alternate_setting = 0,
.b_num_endpoints = 2,
.b_interface_class = USB_CLASS_CDC,
.b_interface_sub_class = 0,
.b_interface_protocol = 0,
.i_interface = 0,
};
buffer.insert(buffer.end(), reinterpret_cast<uint8_t*>(&test_data_ifc),
reinterpret_cast<uint8_t*>(&test_data_ifc) + sizeof(test_data_ifc));
usb_endpoint_descriptor_t test_in_ep = {
.b_length = sizeof(usb_endpoint_descriptor_t),
.b_descriptor_type = USB_DT_ENDPOINT,
.b_endpoint_address = USB_ENDPOINT_IN,
.bm_attributes = USB_ENDPOINT_BULK,
.w_max_packet_size = 0,
.b_interval = 0,
};
buffer.insert(buffer.end(), reinterpret_cast<uint8_t*>(&test_in_ep),
reinterpret_cast<uint8_t*>(&test_in_ep) + sizeof(test_in_ep));
usb_endpoint_descriptor_t test_out_ep = {
.b_length = sizeof(usb_endpoint_descriptor_t),
.b_descriptor_type = USB_DT_ENDPOINT,
.b_endpoint_address = USB_ENDPOINT_OUT,
.bm_attributes = USB_ENDPOINT_BULK,
.w_max_packet_size = 0,
.b_interval = 0,
};
buffer.insert(buffer.end(), reinterpret_cast<uint8_t*>(&test_out_ep),
reinterpret_cast<uint8_t*>(&test_out_ep) + sizeof(test_out_ep));
usb_cs_header_interface_descriptor_t test_cdc_header_desc = {
.bLength = sizeof(usb_cs_header_interface_descriptor_t),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_DST_HEADER,
.bcdCDC = CDC_SUPPORTED_VERSION,
};
buffer.insert(buffer.end(), reinterpret_cast<uint8_t*>(&test_cdc_header_desc),
reinterpret_cast<uint8_t*>(&test_cdc_header_desc) + sizeof(test_cdc_header_desc));
usb_cs_ethernet_interface_descriptor_t test_cdc_eth_ifc = {
.bLength = sizeof(usb_cs_ethernet_interface_descriptor_t),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_DST_ETHERNET,
.iMACAddress = 1,
.bmEthernetStatistics = 0,
.wMaxSegmentSize = 1,
.wNumberMCFilters = 0,
.bNumberPowerFilters = 0,
};
buffer.insert(buffer.end(), reinterpret_cast<uint8_t*>(&test_cdc_eth_ifc),
reinterpret_cast<uint8_t*>(&test_cdc_eth_ifc) + sizeof(test_cdc_eth_ifc));
SetDescriptors(buffer.data());
SetDescriptorLength(buffer.size());
usb_endpoint_descriptor_t* int_ep = nullptr;
usb_endpoint_descriptor_t* tx_ep = nullptr;
usb_endpoint_descriptor_t* rx_ep = nullptr;
usb_interface_descriptor_t* default_ifc = nullptr;
usb_interface_descriptor_t* data_ifc = nullptr;
ecm_ctx_t ecm_ctx;
usb_protocol_t* usb = GetUsbProto();
ecm_ctx.usb = *usb;
ASSERT_OK(usb_desc_iter_init(usb, &iter));
ASSERT_OK(
parse_usb_descriptor(&iter, &int_ep, &tx_ep, &rx_ep, &default_ifc, &data_ifc, &ecm_ctx));
}
} // namespace