• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "device/hid/hid_connection.h"
6 
7 #include <algorithm>
8 
9 namespace device {
10 
11 namespace {
12 
13 // Functor used to filter collections by report ID.
14 struct CollectionHasReportId {
CollectionHasReportIddevice::__anonc0fabf9d0111::CollectionHasReportId15   explicit CollectionHasReportId(uint8_t report_id) : report_id_(report_id) {}
16 
operator ()device::__anonc0fabf9d0111::CollectionHasReportId17   bool operator()(const HidCollectionInfo& info) const {
18     if (info.report_ids.size() == 0 ||
19         report_id_ == HidConnection::kNullReportId)
20       return false;
21 
22     if (report_id_ == HidConnection::kAnyReportId)
23       return true;
24 
25     return std::find(info.report_ids.begin(),
26                      info.report_ids.end(),
27                      report_id_) != info.report_ids.end();
28   }
29 
30  private:
31   const uint8_t report_id_;
32 };
33 
34 // Functor returning true if collection has a protected usage.
35 struct CollectionIsProtected {
operator ()device::__anonc0fabf9d0111::CollectionIsProtected36   bool operator()(const HidCollectionInfo& info) const {
37     return info.usage.IsProtected();
38   }
39 };
40 
FindCollectionByReportId(const HidDeviceInfo & device_info,uint8_t report_id,HidCollectionInfo * collection_info)41 bool FindCollectionByReportId(const HidDeviceInfo& device_info,
42                               uint8_t report_id,
43                               HidCollectionInfo* collection_info) {
44   std::vector<HidCollectionInfo>::const_iterator collection_iter =
45       std::find_if(device_info.collections.begin(),
46                    device_info.collections.end(),
47                    CollectionHasReportId(report_id));
48   if (collection_iter != device_info.collections.end()) {
49     if (collection_info) {
50       *collection_info = *collection_iter;
51     }
52     return true;
53   }
54 
55   return false;
56 }
57 
HasProtectedCollection(const HidDeviceInfo & device_info)58 bool HasProtectedCollection(const HidDeviceInfo& device_info) {
59   return std::find_if(device_info.collections.begin(),
60                       device_info.collections.end(),
61                       CollectionIsProtected()) != device_info.collections.end();
62 }
63 
64 }  // namespace
65 
HidConnection(const HidDeviceInfo & device_info)66 HidConnection::HidConnection(const HidDeviceInfo& device_info)
67     : device_info_(device_info), closed_(false) {
68   has_protected_collection_ = HasProtectedCollection(device_info);
69 }
70 
~HidConnection()71 HidConnection::~HidConnection() {
72   DCHECK(thread_checker_.CalledOnValidThread());
73   DCHECK(closed_);
74 }
75 
Close()76 void HidConnection::Close() {
77   DCHECK(thread_checker_.CalledOnValidThread());
78   DCHECK(!closed_);
79 
80   PlatformClose();
81   closed_ = true;
82 }
83 
Read(const ReadCallback & callback)84 void HidConnection::Read(const ReadCallback& callback) {
85   DCHECK(thread_checker_.CalledOnValidThread());
86   if (device_info_.max_input_report_size == 0) {
87     VLOG(1) << "This device does not support input reports.";
88     callback.Run(false, NULL, 0);
89     return;
90   }
91 
92   PlatformRead(callback);
93 }
94 
Write(scoped_refptr<net::IOBuffer> buffer,size_t size,const WriteCallback & callback)95 void HidConnection::Write(scoped_refptr<net::IOBuffer> buffer,
96                           size_t size,
97                           const WriteCallback& callback) {
98   DCHECK(thread_checker_.CalledOnValidThread());
99   if (device_info_.max_output_report_size == 0) {
100     VLOG(1) << "This device does not support output reports.";
101     callback.Run(false);
102     return;
103   }
104   DCHECK_GE(size, 1u);
105   uint8_t report_id = buffer->data()[0];
106   if (device_info().has_report_id != (report_id != 0)) {
107     VLOG(1) << "Invalid output report ID.";
108     callback.Run(false);
109     return;
110   }
111   if (IsReportIdProtected(report_id)) {
112     VLOG(1) << "Attempt to set a protected output report.";
113     callback.Run(false);
114     return;
115   }
116 
117   PlatformWrite(buffer, size, callback);
118 }
119 
GetFeatureReport(uint8_t report_id,const ReadCallback & callback)120 void HidConnection::GetFeatureReport(uint8_t report_id,
121                                      const ReadCallback& callback) {
122   DCHECK(thread_checker_.CalledOnValidThread());
123   if (device_info_.max_feature_report_size == 0) {
124     VLOG(1) << "This device does not support feature reports.";
125     callback.Run(false, NULL, 0);
126     return;
127   }
128   if (device_info().has_report_id != (report_id != 0)) {
129     VLOG(1) << "Invalid feature report ID.";
130     callback.Run(false, NULL, 0);
131     return;
132   }
133   if (IsReportIdProtected(report_id)) {
134     VLOG(1) << "Attempt to get a protected feature report.";
135     callback.Run(false, NULL, 0);
136     return;
137   }
138 
139   PlatformGetFeatureReport(report_id, callback);
140 }
141 
SendFeatureReport(scoped_refptr<net::IOBuffer> buffer,size_t size,const WriteCallback & callback)142 void HidConnection::SendFeatureReport(scoped_refptr<net::IOBuffer> buffer,
143                                       size_t size,
144                                       const WriteCallback& callback) {
145   DCHECK(thread_checker_.CalledOnValidThread());
146   if (device_info_.max_feature_report_size == 0) {
147     VLOG(1) << "This device does not support feature reports.";
148     callback.Run(false);
149     return;
150   }
151   DCHECK_GE(size, 1u);
152   uint8_t report_id = buffer->data()[0];
153   if (device_info().has_report_id != (report_id != 0)) {
154     VLOG(1) << "Invalid feature report ID.";
155     callback.Run(false);
156     return;
157   }
158   if (IsReportIdProtected(report_id)) {
159     VLOG(1) << "Attempt to set a protected feature report.";
160     callback.Run(false);
161     return;
162   }
163 
164   PlatformSendFeatureReport(buffer, size, callback);
165 }
166 
CompleteRead(scoped_refptr<net::IOBuffer> buffer,size_t size,const ReadCallback & callback)167 bool HidConnection::CompleteRead(scoped_refptr<net::IOBuffer> buffer,
168                                  size_t size,
169                                  const ReadCallback& callback) {
170   DCHECK_GE(size, 1u);
171   uint8_t report_id = buffer->data()[0];
172   if (IsReportIdProtected(report_id)) {
173     VLOG(1) << "Filtered a protected input report.";
174     return false;
175   }
176 
177   callback.Run(true, buffer, size);
178   return true;
179 }
180 
IsReportIdProtected(uint8_t report_id)181 bool HidConnection::IsReportIdProtected(uint8_t report_id) {
182   HidCollectionInfo collection_info;
183   if (FindCollectionByReportId(device_info_, report_id, &collection_info)) {
184     return collection_info.usage.IsProtected();
185   }
186 
187   return has_protected_collection();
188 }
189 
PendingHidReport()190 PendingHidReport::PendingHidReport() {}
191 
~PendingHidReport()192 PendingHidReport::~PendingHidReport() {}
193 
PendingHidRead()194 PendingHidRead::PendingHidRead() {}
195 
~PendingHidRead()196 PendingHidRead::~PendingHidRead() {}
197 
198 }  // namespace device
199