-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdevice_id.cc
197 lines (164 loc) · 5.79 KB
/
device_id.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
// Copyright 2018 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "shill/device_id.h"
#include <inttypes.h>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <base/check.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
namespace shill {
namespace {
// Attribute file in sysfs for PCI devices that indicate whether the PCI device
// is internal or external (0=internal, 1=external). This works because the
// firmware tags the external facing PCI ports by a flag that the kernel looks
// at, to determine whether a device is internal or external. This sysfs
// is something we couldnt reach agreement upstream with yet, and are carrying
// ourselves currently. Ref:
// https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/2511510
constexpr char kExternalAttribute[] = "untrusted";
// Reads a file containing a string device ID and normalizes it by trimming
// whitespace and converting to lowercase.
bool ReadDeviceIdFile(const base::FilePath& path, std::string* out_id) {
DCHECK(out_id);
std::string contents;
if (!base::ReadFileToString(path, &contents))
return false;
*out_id = base::CollapseWhitespaceASCII(base::ToLowerASCII(contents), true);
return true;
}
bool HextetToUInt16(const std::string& input, uint16_t* output) {
DCHECK(output);
std::vector<uint8_t> bytes;
if (!base::HexStringToBytes(input, &bytes))
return false;
if (bytes.size() != 2)
return false;
*output = bytes[0] << 8 | bytes[1];
return true;
}
bool HexToUInt16(const std::string& input, uint16_t* output) {
DCHECK(output);
if (base::StartsWith(input, "0x", base::CompareCase::INSENSITIVE_ASCII)) {
return HextetToUInt16(input.substr(2), output);
}
return HextetToUInt16(input, output);
}
std::unique_ptr<DeviceId> ReadDeviceId(DeviceId::BusType bus_type,
const base::FilePath& vendor_path,
const base::FilePath& product_path) {
std::string vendor_id, product_id;
uint16_t parsed_vendor_id, parsed_product_id;
if (!ReadDeviceIdFile(vendor_path, &vendor_id) ||
!HexToUInt16(vendor_id, &parsed_vendor_id)) {
return std::make_unique<DeviceId>(bus_type);
}
if (!ReadDeviceIdFile(product_path, &product_id) ||
!HexToUInt16(product_id, &parsed_product_id)) {
return std::make_unique<DeviceId>(bus_type, parsed_vendor_id);
}
return std::make_unique<DeviceId>(bus_type, parsed_vendor_id,
parsed_product_id);
}
} // namespace
// static
std::unique_ptr<DeviceId> DeviceId::CreateFromSysfs(
const base::FilePath& syspath) {
if (syspath.empty()) {
return nullptr;
}
base::FilePath subsystem;
if (!base::ReadSymbolicLink(syspath.Append("subsystem"), &subsystem)) {
return nullptr;
}
std::string bus_type = subsystem.BaseName().value();
if (bus_type == "pci") {
auto dev = ReadDeviceId(DeviceId::BusType::kPci, syspath.Append("vendor"),
syspath.Append("device"));
std::string is_external;
if (base::ReadFileToString(syspath.Append(kExternalAttribute),
&is_external) &&
!is_external.empty()) {
is_external = base::CollapseWhitespaceASCII(is_external, true);
if (is_external == "0") {
dev->location_type_ = LocationType::kInternal;
} else {
dev->location_type_ = LocationType::kExternal;
}
}
return dev;
} else if (bus_type == "usb") {
return ReadDeviceId(DeviceId::BusType::kUsb, syspath.Append("idVendor"),
syspath.Append("idProduct"));
}
return nullptr;
}
std::string DeviceId::AsString() const {
const char* bus_name;
switch (bus_type_) {
case BusType::kUsb:
bus_name = "usb";
break;
case BusType::kPci:
bus_name = "pci";
break;
case BusType::kSoc:
bus_name = "soc";
break;
}
const char* loc;
if (location_type_ == LocationType::kExternal)
loc = " (External)";
else if (location_type_ == LocationType::kInternal)
loc = " (Internal)";
else
loc = "";
if (!vendor_id_.has_value()) {
return base::StringPrintf("%s:*:*%s", bus_name, loc);
}
if (!product_id_.has_value()) {
return base::StringPrintf("%s:%04" PRIx16 ":*%s", bus_name,
vendor_id_.value(), loc);
}
return base::StringPrintf("%s:%04" PRIx16 ":%04" PRIx16 "%s", bus_name,
vendor_id_.value(), product_id_.value(), loc);
}
bool DeviceId::Match(const DeviceId& pattern) const {
if (bus_type_ != pattern.bus_type_) {
return false;
}
// Check if match is specifically desired based on location type.
if (pattern.location_type_.has_value() &&
location_type_ != pattern.location_type_) {
return false;
}
// If |pattern| vendor id is *, then they don't have to match VID and PID
// values.
if (!pattern.vendor_id_.has_value()) {
return true;
}
// If |this| vendor id is *, then it can not match to |pattern| with specific
// vendor id.
if (!vendor_id_.has_value() ||
vendor_id_.value() != pattern.vendor_id_.value()) {
return false;
}
// If |pattern| product id is *, then they don't have to match PID values.
if (!pattern.product_id_.has_value()) {
return true;
}
// If |this| product id is *, then it can not match to |pattern| with specific
// product id.
return product_id_.has_value() &&
product_id_.value() == pattern.product_id_.value();
}
std::ostream& operator<<(std::ostream& stream, const DeviceId& device_id) {
return stream << device_id.AsString();
}
} // namespace shill