1 // Copyright 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.
5 #include "components/pairing/bluetooth_host_pairing_controller.h"
9 #include "base/logging.h"
10 #include "base/strings/stringprintf.h"
11 #include "components/pairing/bluetooth_pairing_constants.h"
12 #include "components/pairing/pairing_api.pb.h"
13 #include "components/pairing/proto_decoder.h"
14 #include "device/bluetooth/bluetooth_adapter_factory.h"
15 #include "net/base/io_buffer.h"
17 namespace pairing_chromeos
{
20 const int kReceiveSize
= 16384;
22 pairing_api::HostStatusParameters::UpdateStatus
PairingApiUpdateStatus(
23 HostPairingController::UpdateStatus update_status
) {
24 switch(update_status
) {
25 case HostPairingController::UPDATE_STATUS_UNKNOWN
:
26 return pairing_api::HostStatusParameters::UPDATE_STATUS_UNKNOWN
;
27 case HostPairingController::UPDATE_STATUS_UPDATING
:
28 return pairing_api::HostStatusParameters::UPDATE_STATUS_UPDATING
;
29 case HostPairingController::UPDATE_STATUS_REBOOTING
:
30 return pairing_api::HostStatusParameters::UPDATE_STATUS_REBOOTING
;
31 case HostPairingController::UPDATE_STATUS_UPDATED
:
32 return pairing_api::HostStatusParameters::UPDATE_STATUS_UPDATED
;
35 return pairing_api::HostStatusParameters::UPDATE_STATUS_UNKNOWN
;
39 pairing_api::HostStatusParameters::EnrollmentStatus
PairingApiEnrollmentStatus(
40 HostPairingController::EnrollmentStatus enrollment_status
) {
41 switch(enrollment_status
) {
42 case HostPairingController::ENROLLMENT_STATUS_UNKNOWN
:
43 return pairing_api::HostStatusParameters::ENROLLMENT_STATUS_UNKNOWN
;
44 case HostPairingController::ENROLLMENT_STATUS_ENROLLING
:
45 return pairing_api::HostStatusParameters::ENROLLMENT_STATUS_ENROLLING
;
46 case HostPairingController::ENROLLMENT_STATUS_FAILURE
:
47 return pairing_api::HostStatusParameters::ENROLLMENT_STATUS_FAILURE
;
48 case HostPairingController::ENROLLMENT_STATUS_SUCCESS
:
49 return pairing_api::HostStatusParameters::ENROLLMENT_STATUS_SUCCESS
;
52 return pairing_api::HostStatusParameters::ENROLLMENT_STATUS_UNKNOWN
;
58 BluetoothHostPairingController::BluetoothHostPairingController()
59 : current_stage_(STAGE_NONE
),
60 update_status_(UPDATE_STATUS_UNKNOWN
),
61 enrollment_status_(ENROLLMENT_STATUS_UNKNOWN
),
63 proto_decoder_(new ProtoDecoder(this)),
67 BluetoothHostPairingController::~BluetoothHostPairingController() {
69 if (adapter_
->IsDiscoverable()) {
70 adapter_
->SetDiscoverable(false, base::Closure(), base::Closure());
72 adapter_
->RemoveObserver(this);
77 void BluetoothHostPairingController::ChangeStage(Stage new_stage
) {
78 if (current_stage_
== new_stage
)
80 VLOG(1) << "ChangeStage " << new_stage
;
81 current_stage_
= new_stage
;
82 FOR_EACH_OBSERVER(Observer
, observers_
, PairingStageChanged(new_stage
));
85 void BluetoothHostPairingController::SendHostStatus() {
86 pairing_api::HostStatus host_status
;
88 host_status
.set_api_version(kPairingAPIVersion
);
89 if (!enrollment_domain_
.empty())
90 host_status
.mutable_parameters()->set_domain(enrollment_domain_
);
92 // TODO(zork): Get these values from the UI. (http://crbug.com/405744)
93 host_status
.mutable_parameters()->set_connectivity(
94 pairing_api::HostStatusParameters::CONNECTIVITY_CONNECTED
);
95 host_status
.mutable_parameters()->set_update_status(
96 PairingApiUpdateStatus(update_status_
));
97 host_status
.mutable_parameters()->set_enrollment_status(
98 PairingApiEnrollmentStatus(enrollment_status_
));
100 // TODO(zork): Get a list of other paired controllers.
101 // (http://crbug.com/405757)
104 scoped_refptr
<net::IOBuffer
> io_buffer(
105 ProtoDecoder::SendHostStatus(host_status
, &size
));
107 controller_socket_
->Send(
109 base::Bind(&BluetoothHostPairingController::OnSendComplete
,
110 ptr_factory_
.GetWeakPtr()),
111 base::Bind(&BluetoothHostPairingController::OnSendError
,
112 ptr_factory_
.GetWeakPtr()));
115 void BluetoothHostPairingController::AbortWithError(
117 const std::string
& message
) {
118 if (controller_socket_
.get()) {
119 pairing_api::Error error
;
121 error
.set_api_version(kPairingAPIVersion
);
122 error
.mutable_parameters()->set_code(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
);
123 error
.mutable_parameters()->set_description(message
);
126 scoped_refptr
<net::IOBuffer
> io_buffer(
127 ProtoDecoder::SendError(error
, &size
));
129 controller_socket_
->Send(
131 base::Bind(&BluetoothHostPairingController::OnSendComplete
,
132 ptr_factory_
.GetWeakPtr()),
133 base::Bind(&BluetoothHostPairingController::OnSendError
,
134 ptr_factory_
.GetWeakPtr()));
139 void BluetoothHostPairingController::Reset() {
140 if (controller_socket_
.get()) {
141 controller_socket_
->Close();
142 controller_socket_
= NULL
;
145 if (service_socket_
.get()) {
146 service_socket_
->Close();
147 service_socket_
= NULL
;
149 ChangeStage(STAGE_NONE
);
152 void BluetoothHostPairingController::OnGetAdapter(
153 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
154 DCHECK(thread_checker_
.CalledOnValidThread());
155 DCHECK(!adapter_
.get());
158 if (adapter_
->IsPresent()) {
161 // Set the name once the adapter is present.
162 adapter_
->AddObserver(this);
166 void BluetoothHostPairingController::SetName() {
167 // Hash the bluetooth address and take the lower 2 bytes to create a human
168 // readable device name.
169 const uint32 device_id
= base::Hash(adapter_
->GetAddress()) & 0xFFFF;
170 device_name_
= base::StringPrintf("%s%04X", kDeviceNamePrefix
, device_id
);
174 base::Bind(&BluetoothHostPairingController::OnSetName
,
175 ptr_factory_
.GetWeakPtr()),
176 base::Bind(&BluetoothHostPairingController::OnSetError
,
177 ptr_factory_
.GetWeakPtr()));
180 void BluetoothHostPairingController::OnSetName() {
181 DCHECK(thread_checker_
.CalledOnValidThread());
182 if (adapter_
->IsPowered()) {
185 adapter_
->SetPowered(
187 base::Bind(&BluetoothHostPairingController::OnSetPowered
,
188 ptr_factory_
.GetWeakPtr()),
189 base::Bind(&BluetoothHostPairingController::OnSetError
,
190 ptr_factory_
.GetWeakPtr()));
194 void BluetoothHostPairingController::OnSetPowered() {
195 DCHECK(thread_checker_
.CalledOnValidThread());
196 adapter_
->AddPairingDelegate(
197 this, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH
);
199 device::BluetoothAdapter::ServiceOptions options
;
200 options
.name
.reset(new std::string(kPairingServiceName
));
202 adapter_
->CreateRfcommService(
203 device::BluetoothUUID(kPairingServiceUUID
), options
,
204 base::Bind(&BluetoothHostPairingController::OnCreateService
,
205 ptr_factory_
.GetWeakPtr()),
206 base::Bind(&BluetoothHostPairingController::OnCreateServiceError
,
207 ptr_factory_
.GetWeakPtr()));
210 void BluetoothHostPairingController::OnCreateService(
211 scoped_refptr
<device::BluetoothSocket
> socket
) {
212 DCHECK(thread_checker_
.CalledOnValidThread());
213 service_socket_
= socket
;
215 service_socket_
->Accept(
216 base::Bind(&BluetoothHostPairingController::OnAccept
,
217 ptr_factory_
.GetWeakPtr()),
218 base::Bind(&BluetoothHostPairingController::OnAcceptError
,
219 ptr_factory_
.GetWeakPtr()));
221 adapter_
->SetDiscoverable(
223 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable
,
224 ptr_factory_
.GetWeakPtr(), true),
225 base::Bind(&BluetoothHostPairingController::OnSetError
,
226 ptr_factory_
.GetWeakPtr()));
229 void BluetoothHostPairingController::OnAccept(
230 const device::BluetoothDevice
* device
,
231 scoped_refptr
<device::BluetoothSocket
> socket
) {
232 DCHECK(thread_checker_
.CalledOnValidThread());
233 adapter_
->SetDiscoverable(
235 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable
,
236 ptr_factory_
.GetWeakPtr(), false),
237 base::Bind(&BluetoothHostPairingController::OnSetError
,
238 ptr_factory_
.GetWeakPtr()));
240 controller_socket_
= socket
;
241 service_socket_
= NULL
;
245 controller_socket_
->Receive(
247 base::Bind(&BluetoothHostPairingController::OnReceiveComplete
,
248 ptr_factory_
.GetWeakPtr()),
249 base::Bind(&BluetoothHostPairingController::OnReceiveError
,
250 ptr_factory_
.GetWeakPtr()));
253 void BluetoothHostPairingController::OnSetDiscoverable(bool change_stage
) {
254 DCHECK(thread_checker_
.CalledOnValidThread());
256 DCHECK_EQ(current_stage_
, STAGE_NONE
);
257 ChangeStage(STAGE_WAITING_FOR_CONTROLLER
);
261 void BluetoothHostPairingController::OnSendComplete(int bytes_sent
) {}
263 void BluetoothHostPairingController::OnReceiveComplete(
264 int bytes
, scoped_refptr
<net::IOBuffer
> io_buffer
) {
265 DCHECK(thread_checker_
.CalledOnValidThread());
266 proto_decoder_
->DecodeIOBuffer(bytes
, io_buffer
);
268 controller_socket_
->Receive(
270 base::Bind(&BluetoothHostPairingController::OnReceiveComplete
,
271 ptr_factory_
.GetWeakPtr()),
272 base::Bind(&BluetoothHostPairingController::OnReceiveError
,
273 ptr_factory_
.GetWeakPtr()));
276 void BluetoothHostPairingController::OnCreateServiceError(
277 const std::string
& message
) {
278 LOG(ERROR
) << message
;
279 ChangeStage(STAGE_INITIALIZATION_ERROR
);
282 void BluetoothHostPairingController::OnSetError() {
283 adapter_
->RemovePairingDelegate(this);
284 ChangeStage(STAGE_INITIALIZATION_ERROR
);
287 void BluetoothHostPairingController::OnAcceptError(
288 const std::string
& error_message
) {
289 LOG(ERROR
) << error_message
;
292 void BluetoothHostPairingController::OnSendError(
293 const std::string
& error_message
) {
294 LOG(ERROR
) << error_message
;
297 void BluetoothHostPairingController::OnReceiveError(
298 device::BluetoothSocket::ErrorReason reason
,
299 const std::string
& error_message
) {
300 LOG(ERROR
) << reason
<< ", " << error_message
;
303 void BluetoothHostPairingController::OnHostStatusMessage(
304 const pairing_api::HostStatus
& message
) {
308 void BluetoothHostPairingController::OnConfigureHostMessage(
309 const pairing_api::ConfigureHost
& message
) {
310 FOR_EACH_OBSERVER(Observer
, observers_
,
311 ConfigureHost(message
.parameters().accepted_eula(),
312 message
.parameters().lang(),
313 message
.parameters().timezone(),
314 message
.parameters().send_reports(),
315 message
.parameters().keyboard_layout()));
318 void BluetoothHostPairingController::OnPairDevicesMessage(
319 const pairing_api::PairDevices
& message
) {
320 DCHECK(thread_checker_
.CalledOnValidThread());
321 ChangeStage(STAGE_ENROLLING
);
322 FOR_EACH_OBSERVER(Observer
, observers_
,
323 EnrollHost(message
.parameters().admin_access_token()));
326 void BluetoothHostPairingController::OnCompleteSetupMessage(
327 const pairing_api::CompleteSetup
& message
) {
328 DCHECK(thread_checker_
.CalledOnValidThread());
329 if (current_stage_
!= STAGE_ENROLLMENT_SUCCESS
) {
330 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
, kErrorInvalidProtocol
);
334 // TODO(zork): Handle adding another controller. (http://crbug.com/405757)
335 ChangeStage(STAGE_FINISHED
);
338 void BluetoothHostPairingController::OnErrorMessage(
339 const pairing_api::Error
& message
) {
343 void BluetoothHostPairingController::AdapterPresentChanged(
344 device::BluetoothAdapter
* adapter
,
346 DCHECK_EQ(adapter
, adapter_
.get());
348 adapter_
->RemoveObserver(this);
353 void BluetoothHostPairingController::AddObserver(Observer
* observer
) {
354 observers_
.AddObserver(observer
);
357 void BluetoothHostPairingController::RemoveObserver(Observer
* observer
) {
358 observers_
.RemoveObserver(observer
);
361 HostPairingController::Stage
BluetoothHostPairingController::GetCurrentStage() {
362 return current_stage_
;
365 void BluetoothHostPairingController::StartPairing() {
366 DCHECK_EQ(current_stage_
, STAGE_NONE
);
367 bool bluetooth_available
=
368 device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
369 if (!bluetooth_available
) {
370 ChangeStage(STAGE_INITIALIZATION_ERROR
);
374 device::BluetoothAdapterFactory::GetAdapter(
375 base::Bind(&BluetoothHostPairingController::OnGetAdapter
,
376 ptr_factory_
.GetWeakPtr()));
379 std::string
BluetoothHostPairingController::GetDeviceName() {
383 std::string
BluetoothHostPairingController::GetConfirmationCode() {
384 DCHECK_EQ(current_stage_
, STAGE_WAITING_FOR_CODE_CONFIRMATION
);
385 return confirmation_code_
;
388 std::string
BluetoothHostPairingController::GetEnrollmentDomain() {
389 return enrollment_domain_
;
392 void BluetoothHostPairingController::OnUpdateStatusChanged(
393 UpdateStatus update_status
) {
394 update_status_
= update_status
;
395 if (update_status
== UPDATE_STATUS_UPDATED
)
396 ChangeStage(STAGE_WAITING_FOR_CREDENTIALS
);
400 void BluetoothHostPairingController::OnEnrollmentStatusChanged(
401 EnrollmentStatus enrollment_status
) {
402 DCHECK_EQ(current_stage_
, STAGE_ENROLLING
);
403 DCHECK(thread_checker_
.CalledOnValidThread());
405 enrollment_status_
= enrollment_status
;
406 if (enrollment_status
== ENROLLMENT_STATUS_SUCCESS
) {
407 ChangeStage(STAGE_ENROLLMENT_SUCCESS
);
408 } else if (enrollment_status
== ENROLLMENT_STATUS_FAILURE
) {
409 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
,
410 kErrorEnrollmentFailed
);
415 void BluetoothHostPairingController::RequestPinCode(
416 device::BluetoothDevice
* device
) {
417 // Disallow unknown device.
418 device
->RejectPairing();
421 void BluetoothHostPairingController::RequestPasskey(
422 device::BluetoothDevice
* device
) {
423 // Disallow unknown device.
424 device
->RejectPairing();
427 void BluetoothHostPairingController::DisplayPinCode(
428 device::BluetoothDevice
* device
,
429 const std::string
& pincode
) {
430 // Disallow unknown device.
431 device
->RejectPairing();
434 void BluetoothHostPairingController::DisplayPasskey(
435 device::BluetoothDevice
* device
,
437 // Disallow unknown device.
438 device
->RejectPairing();
441 void BluetoothHostPairingController::KeysEntered(
442 device::BluetoothDevice
* device
,
444 // Disallow unknown device.
445 device
->RejectPairing();
448 void BluetoothHostPairingController::ConfirmPasskey(
449 device::BluetoothDevice
* device
,
451 // If a new connection is occurring, reset the stage. This can occur if the
452 // pairing times out, or a new controller connects.
453 if (current_stage_
== STAGE_WAITING_FOR_CODE_CONFIRMATION
)
454 ChangeStage(STAGE_WAITING_FOR_CONTROLLER
);
456 confirmation_code_
= base::StringPrintf("%06d", passkey
);
457 device
->ConfirmPairing();
458 ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION
);
461 void BluetoothHostPairingController::AuthorizePairing(
462 device::BluetoothDevice
* device
) {
463 // Disallow unknown device.
464 device
->RejectPairing();
467 } // namespace pairing_chromeos