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
),
62 proto_decoder_(new ProtoDecoder(this)),
66 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_
);
91 if (!permanent_id_
.empty())
92 host_status
.mutable_parameters()->set_permanent_id(permanent_id_
);
94 // TODO(zork): Get these values from the UI. (http://crbug.com/405744)
95 host_status
.mutable_parameters()->set_connectivity(
96 pairing_api::HostStatusParameters::CONNECTIVITY_CONNECTED
);
97 host_status
.mutable_parameters()->set_update_status(
98 PairingApiUpdateStatus(update_status_
));
99 host_status
.mutable_parameters()->set_enrollment_status(
100 PairingApiEnrollmentStatus(enrollment_status_
));
102 // TODO(zork): Get a list of other paired controllers.
103 // (http://crbug.com/405757)
106 scoped_refptr
<net::IOBuffer
> io_buffer(
107 ProtoDecoder::SendHostStatus(host_status
, &size
));
109 controller_socket_
->Send(
111 base::Bind(&BluetoothHostPairingController::OnSendComplete
,
112 ptr_factory_
.GetWeakPtr()),
113 base::Bind(&BluetoothHostPairingController::OnSendError
,
114 ptr_factory_
.GetWeakPtr()));
117 void BluetoothHostPairingController::AbortWithError(
119 const std::string
& message
) {
120 if (controller_socket_
.get()) {
121 pairing_api::Error error
;
123 error
.set_api_version(kPairingAPIVersion
);
124 error
.mutable_parameters()->set_code(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
);
125 error
.mutable_parameters()->set_description(message
);
128 scoped_refptr
<net::IOBuffer
> io_buffer(
129 ProtoDecoder::SendError(error
, &size
));
131 controller_socket_
->Send(
133 base::Bind(&BluetoothHostPairingController::OnSendComplete
,
134 ptr_factory_
.GetWeakPtr()),
135 base::Bind(&BluetoothHostPairingController::OnSendError
,
136 ptr_factory_
.GetWeakPtr()));
141 void BluetoothHostPairingController::Reset() {
142 if (controller_socket_
.get()) {
143 controller_socket_
->Close();
144 controller_socket_
= NULL
;
147 if (service_socket_
.get()) {
148 service_socket_
->Close();
149 service_socket_
= NULL
;
151 ChangeStage(STAGE_NONE
);
154 void BluetoothHostPairingController::OnGetAdapter(
155 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
156 DCHECK(thread_checker_
.CalledOnValidThread());
157 DCHECK(!adapter_
.get());
160 if (adapter_
->IsPresent()) {
163 // Set the name once the adapter is present.
164 adapter_
->AddObserver(this);
168 void BluetoothHostPairingController::SetName() {
169 // Hash the bluetooth address and take the lower 2 bytes to create a human
170 // readable device name.
171 const uint32 device_id
= base::Hash(adapter_
->GetAddress()) & 0xFFFF;
172 device_name_
= base::StringPrintf("%s%04X", kDeviceNamePrefix
, device_id
);
176 base::Bind(&BluetoothHostPairingController::OnSetName
,
177 ptr_factory_
.GetWeakPtr()),
178 base::Bind(&BluetoothHostPairingController::OnSetError
,
179 ptr_factory_
.GetWeakPtr()));
182 void BluetoothHostPairingController::OnSetName() {
183 DCHECK(thread_checker_
.CalledOnValidThread());
184 if (adapter_
->IsPowered()) {
187 adapter_
->SetPowered(
189 base::Bind(&BluetoothHostPairingController::OnSetPowered
,
190 ptr_factory_
.GetWeakPtr()),
191 base::Bind(&BluetoothHostPairingController::OnSetError
,
192 ptr_factory_
.GetWeakPtr()));
196 void BluetoothHostPairingController::OnSetPowered() {
197 DCHECK(thread_checker_
.CalledOnValidThread());
198 adapter_
->AddPairingDelegate(
199 this, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH
);
201 device::BluetoothAdapter::ServiceOptions options
;
202 options
.name
.reset(new std::string(kPairingServiceName
));
204 adapter_
->CreateRfcommService(
205 device::BluetoothUUID(kPairingServiceUUID
), options
,
206 base::Bind(&BluetoothHostPairingController::OnCreateService
,
207 ptr_factory_
.GetWeakPtr()),
208 base::Bind(&BluetoothHostPairingController::OnCreateServiceError
,
209 ptr_factory_
.GetWeakPtr()));
212 void BluetoothHostPairingController::OnCreateService(
213 scoped_refptr
<device::BluetoothSocket
> socket
) {
214 DCHECK(thread_checker_
.CalledOnValidThread());
215 service_socket_
= socket
;
217 service_socket_
->Accept(
218 base::Bind(&BluetoothHostPairingController::OnAccept
,
219 ptr_factory_
.GetWeakPtr()),
220 base::Bind(&BluetoothHostPairingController::OnAcceptError
,
221 ptr_factory_
.GetWeakPtr()));
223 adapter_
->SetDiscoverable(
225 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable
,
226 ptr_factory_
.GetWeakPtr(), true),
227 base::Bind(&BluetoothHostPairingController::OnSetError
,
228 ptr_factory_
.GetWeakPtr()));
231 void BluetoothHostPairingController::OnAccept(
232 const device::BluetoothDevice
* device
,
233 scoped_refptr
<device::BluetoothSocket
> socket
) {
234 DCHECK(thread_checker_
.CalledOnValidThread());
235 adapter_
->SetDiscoverable(
237 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable
,
238 ptr_factory_
.GetWeakPtr(), false),
239 base::Bind(&BluetoothHostPairingController::OnSetError
,
240 ptr_factory_
.GetWeakPtr()));
242 controller_socket_
= socket
;
243 service_socket_
= NULL
;
247 controller_socket_
->Receive(
249 base::Bind(&BluetoothHostPairingController::OnReceiveComplete
,
250 ptr_factory_
.GetWeakPtr()),
251 base::Bind(&BluetoothHostPairingController::OnReceiveError
,
252 ptr_factory_
.GetWeakPtr()));
255 void BluetoothHostPairingController::OnSetDiscoverable(bool change_stage
) {
256 DCHECK(thread_checker_
.CalledOnValidThread());
258 DCHECK_EQ(current_stage_
, STAGE_NONE
);
259 ChangeStage(STAGE_WAITING_FOR_CONTROLLER
);
263 void BluetoothHostPairingController::OnSendComplete(int bytes_sent
) {}
265 void BluetoothHostPairingController::OnReceiveComplete(
266 int bytes
, scoped_refptr
<net::IOBuffer
> io_buffer
) {
267 DCHECK(thread_checker_
.CalledOnValidThread());
268 proto_decoder_
->DecodeIOBuffer(bytes
, io_buffer
);
270 controller_socket_
->Receive(
272 base::Bind(&BluetoothHostPairingController::OnReceiveComplete
,
273 ptr_factory_
.GetWeakPtr()),
274 base::Bind(&BluetoothHostPairingController::OnReceiveError
,
275 ptr_factory_
.GetWeakPtr()));
278 void BluetoothHostPairingController::OnCreateServiceError(
279 const std::string
& message
) {
280 LOG(ERROR
) << message
;
281 ChangeStage(STAGE_INITIALIZATION_ERROR
);
284 void BluetoothHostPairingController::OnSetError() {
285 adapter_
->RemovePairingDelegate(this);
286 ChangeStage(STAGE_INITIALIZATION_ERROR
);
289 void BluetoothHostPairingController::OnAcceptError(
290 const std::string
& error_message
) {
291 LOG(ERROR
) << error_message
;
294 void BluetoothHostPairingController::OnSendError(
295 const std::string
& error_message
) {
296 LOG(ERROR
) << error_message
;
299 void BluetoothHostPairingController::OnReceiveError(
300 device::BluetoothSocket::ErrorReason reason
,
301 const std::string
& error_message
) {
302 LOG(ERROR
) << reason
<< ", " << error_message
;
305 void BluetoothHostPairingController::OnHostStatusMessage(
306 const pairing_api::HostStatus
& message
) {
310 void BluetoothHostPairingController::OnConfigureHostMessage(
311 const pairing_api::ConfigureHost
& message
) {
312 FOR_EACH_OBSERVER(Observer
, observers_
,
313 ConfigureHostRequested(
314 message
.parameters().accepted_eula(),
315 message
.parameters().lang(),
316 message
.parameters().timezone(),
317 message
.parameters().send_reports(),
318 message
.parameters().keyboard_layout()));
321 void BluetoothHostPairingController::OnPairDevicesMessage(
322 const pairing_api::PairDevices
& message
) {
323 DCHECK(thread_checker_
.CalledOnValidThread());
324 ChangeStage(STAGE_ENROLLING
);
325 FOR_EACH_OBSERVER(Observer
, observers_
,
327 message
.parameters().admin_access_token()));
330 void BluetoothHostPairingController::OnCompleteSetupMessage(
331 const pairing_api::CompleteSetup
& message
) {
332 DCHECK(thread_checker_
.CalledOnValidThread());
333 if (current_stage_
!= STAGE_ENROLLMENT_SUCCESS
) {
334 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
, kErrorInvalidProtocol
);
338 // TODO(zork): Handle adding another controller. (http://crbug.com/405757)
339 ChangeStage(STAGE_FINISHED
);
342 void BluetoothHostPairingController::OnErrorMessage(
343 const pairing_api::Error
& message
) {
347 void BluetoothHostPairingController::OnAddNetworkMessage(
348 const pairing_api::AddNetwork
& message
) {
349 DCHECK(thread_checker_
.CalledOnValidThread());
350 FOR_EACH_OBSERVER(Observer
, observers_
,
351 AddNetworkRequested(message
.parameters().onc_spec()));
354 void BluetoothHostPairingController::AdapterPresentChanged(
355 device::BluetoothAdapter
* adapter
,
357 DCHECK_EQ(adapter
, adapter_
.get());
359 adapter_
->RemoveObserver(this);
364 void BluetoothHostPairingController::AddObserver(Observer
* observer
) {
365 observers_
.AddObserver(observer
);
368 void BluetoothHostPairingController::RemoveObserver(Observer
* observer
) {
369 observers_
.RemoveObserver(observer
);
372 HostPairingController::Stage
BluetoothHostPairingController::GetCurrentStage() {
373 return current_stage_
;
376 void BluetoothHostPairingController::StartPairing() {
377 DCHECK_EQ(current_stage_
, STAGE_NONE
);
378 bool bluetooth_available
=
379 device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
380 if (!bluetooth_available
) {
381 ChangeStage(STAGE_INITIALIZATION_ERROR
);
385 device::BluetoothAdapterFactory::GetAdapter(
386 base::Bind(&BluetoothHostPairingController::OnGetAdapter
,
387 ptr_factory_
.GetWeakPtr()));
390 std::string
BluetoothHostPairingController::GetDeviceName() {
394 std::string
BluetoothHostPairingController::GetConfirmationCode() {
395 DCHECK_EQ(current_stage_
, STAGE_WAITING_FOR_CODE_CONFIRMATION
);
396 return confirmation_code_
;
399 std::string
BluetoothHostPairingController::GetEnrollmentDomain() {
400 return enrollment_domain_
;
403 void BluetoothHostPairingController::OnUpdateStatusChanged(
404 UpdateStatus update_status
) {
405 update_status_
= update_status
;
406 if (update_status
== UPDATE_STATUS_UPDATED
)
407 ChangeStage(STAGE_WAITING_FOR_CREDENTIALS
);
411 void BluetoothHostPairingController::OnEnrollmentStatusChanged(
412 EnrollmentStatus enrollment_status
) {
413 DCHECK_EQ(current_stage_
, STAGE_ENROLLING
);
414 DCHECK(thread_checker_
.CalledOnValidThread());
416 enrollment_status_
= enrollment_status
;
417 if (enrollment_status
== ENROLLMENT_STATUS_SUCCESS
) {
418 ChangeStage(STAGE_ENROLLMENT_SUCCESS
);
419 } else if (enrollment_status
== ENROLLMENT_STATUS_FAILURE
) {
420 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
,
421 kErrorEnrollmentFailed
);
426 void BluetoothHostPairingController::SetPermanentId(
427 const std::string
& permanent_id
) {
428 permanent_id_
= permanent_id
;
431 void BluetoothHostPairingController::RequestPinCode(
432 device::BluetoothDevice
* device
) {
433 // Disallow unknown device.
434 device
->RejectPairing();
437 void BluetoothHostPairingController::RequestPasskey(
438 device::BluetoothDevice
* device
) {
439 // Disallow unknown device.
440 device
->RejectPairing();
443 void BluetoothHostPairingController::DisplayPinCode(
444 device::BluetoothDevice
* device
,
445 const std::string
& pincode
) {
446 // Disallow unknown device.
447 device
->RejectPairing();
450 void BluetoothHostPairingController::DisplayPasskey(
451 device::BluetoothDevice
* device
,
453 // Disallow unknown device.
454 device
->RejectPairing();
457 void BluetoothHostPairingController::KeysEntered(
458 device::BluetoothDevice
* device
,
460 // Disallow unknown device.
461 device
->RejectPairing();
464 void BluetoothHostPairingController::ConfirmPasskey(
465 device::BluetoothDevice
* device
,
467 // If a new connection is occurring, reset the stage. This can occur if the
468 // pairing times out, or a new controller connects.
469 if (current_stage_
== STAGE_WAITING_FOR_CODE_CONFIRMATION
)
470 ChangeStage(STAGE_WAITING_FOR_CONTROLLER
);
472 confirmation_code_
= base::StringPrintf("%06d", passkey
);
473 device
->ConfirmPairing();
474 ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION
);
477 void BluetoothHostPairingController::AuthorizePairing(
478 device::BluetoothDevice
* device
) {
479 // Disallow unknown device.
480 device
->RejectPairing();
483 } // namespace pairing_chromeos