blob: 17a841291bbaa85329206d4a8a35f14b9f7faab5 [file] [log] [blame]
// Copyright 2018 The Chromium OS 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 "load_config.h"
#include <climits>
#include <cstdio>
#include <map>
#include <string>
#include <vector>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/json/json_reader.h>
#include <base/values.h>
#include <brillo/syslog_logging.h>
#include "device_descriptors.h"
#include "usbip_constants.h"
namespace {
// Represents the maximum number of characters in a USB string descriptor.
const size_t kMaxStringDescriptorSize = 126;
} // namespace
uint8_t GetByteValue(const base::DictionaryValue* dict,
const std::string& path) {
int val;
CHECK(dict->GetInteger(path, &val))
<< "Failed to extract path" << path << " from printer config";
CHECK_LE(val, UCHAR_MAX) << "Extracted value " << val
<< " is too large to fit into a byte";
return static_cast<uint8_t>(val);
}
uint16_t GetWordValue(const base::DictionaryValue* dict,
const std::string& path) {
int val;
CHECK(dict->GetInteger(path, &val))
<< "Failed to extract path " << path << " from printer config";
CHECK_LE(val, USHRT_MAX) << "Extracted value " << val
<< " is too large to fit into a word";
return static_cast<uint16_t>(val);
}
const base::DictionaryValue* GetDescriptorDictionary(
const base::DictionaryValue* printer, const std::string& path) {
const base::DictionaryValue* descriptor;
CHECK(printer->GetDictionary(path, &descriptor))
<< "Failed to extract " << path << " object from printer config";
return descriptor;
}
const base::ListValue* GetDescriptorList(const base::DictionaryValue* printer,
const std::string& path) {
const base::ListValue* list;
CHECK(printer->GetList(path, &list))
<< "Failed to extract " << path << " list from printer config";
return list;
}
UsbDeviceDescriptor GetDeviceDescriptor(
const base::DictionaryValue* printer) {
const base::DictionaryValue* descriptor =
GetDescriptorDictionary(printer, "device_descriptor");
UsbDeviceDescriptor dev_dsc;
dev_dsc.bLength = GetByteValue(descriptor, "bLength");
CHECK_EQ(dev_dsc.bLength, sizeof(dev_dsc))
<< "bLength value " << dev_dsc.bLength
<< " is not the same as the size of the device descriptor";
dev_dsc.bDescriptorType = GetByteValue(descriptor, "bDescriptorType");
dev_dsc.bcdUSB = GetWordValue(descriptor, "bcdUSB");
dev_dsc.bDeviceClass = GetByteValue(descriptor, "bDeviceClass");
dev_dsc.bDeviceSubClass = GetByteValue(descriptor, "bDeviceSubClass");
dev_dsc.bDeviceProtocol = GetByteValue(descriptor, "bDeviceProtocol");
dev_dsc.bMaxPacketSize0 = GetByteValue(descriptor, "bMaxPacketSize0");
dev_dsc.idVendor = GetWordValue(descriptor, "idVendor");
dev_dsc.idProduct = GetWordValue(descriptor, "idProduct");
dev_dsc.bcdDevice = GetWordValue(descriptor, "bcdDevice");
dev_dsc.iManufacturer = GetByteValue(descriptor, "iManufacturer");
dev_dsc.iProduct = GetByteValue(descriptor, "iProduct");
dev_dsc.iSerialNumber = GetByteValue(descriptor, "iSerialNumber");
dev_dsc.bNumConfigurations = GetByteValue(descriptor, "bNumConfigurations");
return dev_dsc;
}
UsbConfigurationDescriptor GetConfigurationDescriptor(
const base::DictionaryValue* printer) {
const base::DictionaryValue* descriptor =
GetDescriptorDictionary(printer, "configuration_descriptor");
UsbConfigurationDescriptor cfg_dsc;
cfg_dsc.bLength = GetByteValue(descriptor, "bLength");
CHECK_EQ(cfg_dsc.bLength, sizeof(cfg_dsc))
<< "bLength value " << cfg_dsc.bLength
<< " is not the same as the size of the configuration descriptor";
cfg_dsc.bDescriptorType = GetByteValue(descriptor, "bDescriptorType");
cfg_dsc.wTotalLength = GetWordValue(descriptor, "wTotalLength");
cfg_dsc.bNumInterfaces = GetByteValue(descriptor, "bNumInterfaces");
cfg_dsc.bConfigurationValue = GetByteValue(descriptor, "bConfigurationValue");
cfg_dsc.iConfiguration = GetByteValue(descriptor, "iConfiguration");
cfg_dsc.bmAttributes = GetByteValue(descriptor, "bmAttributes");
cfg_dsc.bMaxPower = GetByteValue(descriptor, "bMaxPower");
return cfg_dsc;
}
UsbDeviceQualifierDescriptor GetDeviceQualifierDescriptor(
const base::DictionaryValue* printer) {
const base::DictionaryValue* descriptor =
GetDescriptorDictionary(printer, "device_qualifier_descriptor");
UsbDeviceQualifierDescriptor devq_dsc;
devq_dsc.bLength = GetByteValue(descriptor, "bLength");
CHECK_EQ(devq_dsc.bLength, sizeof(devq_dsc))
<< "bLength value " << devq_dsc.bLength
<< " is not the same as the size of the device qualifier descriptor";
devq_dsc.bDescriptorType = GetByteValue(descriptor, "bDescriptorType");
devq_dsc.bcdUSB = GetWordValue(descriptor, "bcdUSB");
devq_dsc.bDeviceClass = GetByteValue(descriptor, "bDeviceClass");
devq_dsc.bDeviceSubClass = GetByteValue(descriptor, "bDeviceSubClass");
devq_dsc.bDeviceProtocol = GetByteValue(descriptor, "bDeviceProtocol");
devq_dsc.bMaxPacketSize0 = GetByteValue(descriptor, "bMaxPacketSize0");
devq_dsc.bNumConfigurations = GetByteValue(descriptor, "bNumConfigurations");
devq_dsc.bReserved = GetByteValue(descriptor, "bReserved");
return devq_dsc;
}
std::vector<UsbInterfaceDescriptor> GetInterfaceDescriptors(
const base::DictionaryValue* printer) {
const base::ListValue* list =
GetDescriptorList(printer, "interface_descriptors");
std::size_t size = list->GetSize();
std::vector<UsbInterfaceDescriptor> interfaces(size);
for (std::size_t i = 0; i < size; ++i) {
const base::DictionaryValue* descriptor;
CHECK(list->GetDictionary(i, &descriptor))
<< "Failed to extract object from list index " << i;
interfaces[i] = GetInterfaceDescriptor(descriptor);
}
return interfaces;
}
UsbInterfaceDescriptor GetInterfaceDescriptor(
const base::DictionaryValue* descriptor) {
UsbInterfaceDescriptor intf_dsc;
intf_dsc.bLength = GetByteValue(descriptor, "bLength");
CHECK_EQ(intf_dsc.bLength, sizeof(intf_dsc))
<< "bLength value " << intf_dsc.bLength
<< " is not the same as the size of the interface descriptor";
intf_dsc.bDescriptorType = GetByteValue(descriptor, "bDescriptorType");
intf_dsc.bInterfaceNumber = GetByteValue(descriptor, "bInterfaceNumber");
intf_dsc.bAlternateSetting = GetByteValue(descriptor, "bAlternateSetting");
intf_dsc.bNumEndpoints = GetByteValue(descriptor, "bNumEndpoints");
intf_dsc.bInterfaceClass = GetByteValue(descriptor, "bInterfaceClass");
intf_dsc.bInterfaceSubClass = GetByteValue(descriptor, "bInterfaceSubClass");
intf_dsc.bInterfaceProtocol = GetByteValue(descriptor, "bInterfaceProtocol");
intf_dsc.iInterface = GetByteValue(descriptor, "iInterface");
return intf_dsc;
}
std::map<uint8_t, std::vector<UsbEndpointDescriptor>> GetEndpointDescriptorMap(
const base::DictionaryValue* printer) {
const base::ListValue* interfaces_list =
GetDescriptorList(printer, "interface_descriptors");
std::map<uint8_t, std::vector<UsbEndpointDescriptor>> endpoints_map;
for (size_t i = 0; i < interfaces_list->GetSize(); ++i) {
const base::DictionaryValue* interface_dictionary;
CHECK(interfaces_list->GetDictionary(i, &interface_dictionary))
<< "Failed to extract object from list index " << i;
UsbInterfaceDescriptor interface =
GetInterfaceDescriptor(interface_dictionary);
const base::ListValue* endpoints_list =
GetDescriptorList(interface_dictionary, "endpoints");
for (size_t j = 0; j < endpoints_list->GetSize(); ++j) {
const base::DictionaryValue* endpoint_dictionary;
CHECK(endpoints_list->GetDictionary(j, &endpoint_dictionary))
<< "Failed to extract the object from list index " << j;
UsbEndpointDescriptor endpoint =
GetEndpointDescriptor(endpoint_dictionary);
endpoints_map[interface.bInterfaceNumber].push_back(endpoint);
}
}
return endpoints_map;
}
UsbEndpointDescriptor GetEndpointDescriptor(
const base::DictionaryValue* descriptor) {
UsbEndpointDescriptor endp_dsc;
endp_dsc.bLength = GetByteValue(descriptor, "bLength");
CHECK_EQ(endp_dsc.bLength, sizeof(endp_dsc))
<< "bLength value " << endp_dsc.bLength
<< " is not the same as the size of the endpoint descriptor";
endp_dsc.bDescriptorType = GetByteValue(descriptor, "bDescriptorType");
endp_dsc.bEndpointAddress = GetByteValue(descriptor, "bEndpointAddress");
endp_dsc.bmAttributes = GetByteValue(descriptor, "bmAttributes");
endp_dsc.wMaxPacketSize = GetWordValue(descriptor, "wMaxPacketSize");
endp_dsc.bInterval = GetByteValue(descriptor, "bInterval");
return endp_dsc;
}
std::vector<char> ConvertStringToStringDescriptor(const std::string& str) {
CHECK_LE(str.size(), kMaxStringDescriptorSize)
<< str << " is too large to fit into a string descriptor";
// A string descriptor uses 2 bytes per character, and also requires an
// additional 2 bytes to store the length and language code.
const uint8_t size = static_cast<char>(str.size()) * 2 + 2;
std::vector<char> descriptor(size);
descriptor[0] = size;
descriptor[1] = USB_DESCRIPTOR_STRING;
int i = 2;
for (const char c : str) {
descriptor[i] = c;
descriptor[i + 1] = 0x00;
i += 2;
}
return descriptor;
}
std::vector<std::vector<char>> GetStringDescriptors(
const base::DictionaryValue* printer) {
const base::DictionaryValue* descriptor =
GetDescriptorDictionary(printer, "language_descriptor");
std::vector<char> language(4);
language[0] = GetByteValue(descriptor, "bLength");
language[1] = GetByteValue(descriptor, "bDescriptorType");
language[2] = GetByteValue(descriptor, "langID1");
language[3] = GetByteValue(descriptor, "langID2");
const base::ListValue* list =
GetDescriptorList(printer, "string_descriptors");
std::vector<std::vector<char>> strings;
strings.push_back(language);
for (std::size_t i = 0; i < list->GetSize(); ++i) {
std::string str;
CHECK(list->GetString(i, &str))
<< "Failed to extract string from list index " << i;
strings.emplace_back(ConvertStringToStringDescriptor(str));
}
return strings;
}
std::vector<char> GetIEEEDeviceId(const base::DictionaryValue* printer) {
const base::DictionaryValue* descriptor =
GetDescriptorDictionary(printer, "ieee_device_id");
std::vector<char> ieee_device_id;
ieee_device_id.push_back(
static_cast<char>(GetByteValue(descriptor, "bLength1")));
ieee_device_id.push_back(
static_cast<char>(GetByteValue(descriptor, "bLength2")));
std::string message;
CHECK(descriptor->GetString("message", &message))
<< "Failed to extract \"message\" from ieee_device_id object";
ieee_device_id.insert(ieee_device_id.end(), message.begin(), message.end());
return ieee_device_id;
}