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() {
68 if (adapter_
->IsDiscoverable()) {
69 adapter_
->SetDiscoverable(false, base::Closure(), base::Closure());
71 adapter_
->RemoveObserver(this);
76 void BluetoothHostPairingController::ChangeStage(Stage new_stage
) {
77 if (current_stage_
== new_stage
)
79 VLOG(1) << "ChangeStage " << new_stage
;
80 current_stage_
= new_stage
;
81 FOR_EACH_OBSERVER(Observer
, observers_
, PairingStageChanged(new_stage
));
84 void BluetoothHostPairingController::SendHostStatus() {
85 pairing_api::HostStatus host_status
;
87 host_status
.set_api_version(kPairingAPIVersion
);
88 if (!enrollment_domain_
.empty())
89 host_status
.mutable_parameters()->set_domain(enrollment_domain_
);
91 // TODO(zork): Get these values from the UI. (http://crbug.com/405744)
92 host_status
.mutable_parameters()->set_connectivity(
93 pairing_api::HostStatusParameters::CONNECTIVITY_CONNECTED
);
94 host_status
.mutable_parameters()->set_update_status(
95 PairingApiUpdateStatus(update_status_
));
96 host_status
.mutable_parameters()->set_enrollment_status(
97 PairingApiEnrollmentStatus(enrollment_status_
));
99 // TODO(zork): Get a list of other paired controllers.
100 // (http://crbug.com/405757)
103 scoped_refptr
<net::IOBuffer
> io_buffer(
104 ProtoDecoder::SendHostStatus(host_status
, &size
));
106 controller_socket_
->Send(
108 base::Bind(&BluetoothHostPairingController::OnSendComplete
,
109 ptr_factory_
.GetWeakPtr()),
110 base::Bind(&BluetoothHostPairingController::OnSendError
,
111 ptr_factory_
.GetWeakPtr()));
114 void BluetoothHostPairingController::AbortWithError(
116 const std::string
& message
) {
117 if (controller_socket_
.get()) {
118 pairing_api::Error error
;
120 error
.set_api_version(kPairingAPIVersion
);
121 error
.mutable_parameters()->set_code(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
);
122 error
.mutable_parameters()->set_description(message
);
125 scoped_refptr
<net::IOBuffer
> io_buffer(
126 ProtoDecoder::SendError(error
, &size
));
128 controller_socket_
->Send(
130 base::Bind(&BluetoothHostPairingController::OnSendComplete
,
131 ptr_factory_
.GetWeakPtr()),
132 base::Bind(&BluetoothHostPairingController::OnSendError
,
133 ptr_factory_
.GetWeakPtr()));
138 void BluetoothHostPairingController::Reset() {
139 if (controller_socket_
.get()) {
140 controller_socket_
->Close();
141 controller_socket_
= NULL
;
144 if (service_socket_
.get()) {
145 service_socket_
->Close();
146 service_socket_
= NULL
;
148 ChangeStage(STAGE_NONE
);
151 void BluetoothHostPairingController::OnGetAdapter(
152 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
153 DCHECK(thread_checker_
.CalledOnValidThread());
154 DCHECK(!adapter_
.get());
157 if (adapter_
->IsPresent()) {
160 // Set the name once the adapter is present.
161 adapter_
->AddObserver(this);
165 void BluetoothHostPairingController::SetName() {
166 // Hash the bluetooth address and take the lower 2 bytes to create a human
167 // readable device name.
168 const uint32 device_id
= base::Hash(adapter_
->GetAddress()) & 0xFFFF;
169 device_name_
= base::StringPrintf("%s%04X", kDeviceNamePrefix
, device_id
);
173 base::Bind(&BluetoothHostPairingController::OnSetName
,
174 ptr_factory_
.GetWeakPtr()),
175 base::Bind(&BluetoothHostPairingController::OnSetError
,
176 ptr_factory_
.GetWeakPtr()));
179 void BluetoothHostPairingController::OnSetName() {
180 DCHECK(thread_checker_
.CalledOnValidThread());
181 if (adapter_
->IsPowered()) {
184 adapter_
->SetPowered(
186 base::Bind(&BluetoothHostPairingController::OnSetPowered
,
187 ptr_factory_
.GetWeakPtr()),
188 base::Bind(&BluetoothHostPairingController::OnSetError
,
189 ptr_factory_
.GetWeakPtr()));
193 void BluetoothHostPairingController::OnSetPowered() {
194 DCHECK(thread_checker_
.CalledOnValidThread());
195 adapter_
->AddPairingDelegate(
196 this, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH
);
198 device::BluetoothAdapter::ServiceOptions options
;
199 options
.name
.reset(new std::string(kPairingServiceName
));
201 adapter_
->CreateRfcommService(
202 device::BluetoothUUID(kPairingServiceUUID
), options
,
203 base::Bind(&BluetoothHostPairingController::OnCreateService
,
204 ptr_factory_
.GetWeakPtr()),
205 base::Bind(&BluetoothHostPairingController::OnCreateServiceError
,
206 ptr_factory_
.GetWeakPtr()));
209 void BluetoothHostPairingController::OnCreateService(
210 scoped_refptr
<device::BluetoothSocket
> socket
) {
211 DCHECK(thread_checker_
.CalledOnValidThread());
212 service_socket_
= socket
;
214 service_socket_
->Accept(
215 base::Bind(&BluetoothHostPairingController::OnAccept
,
216 ptr_factory_
.GetWeakPtr()),
217 base::Bind(&BluetoothHostPairingController::OnAcceptError
,
218 ptr_factory_
.GetWeakPtr()));
220 adapter_
->SetDiscoverable(
222 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable
,
223 ptr_factory_
.GetWeakPtr(), true),
224 base::Bind(&BluetoothHostPairingController::OnSetError
,
225 ptr_factory_
.GetWeakPtr()));
228 void BluetoothHostPairingController::OnAccept(
229 const device::BluetoothDevice
* device
,
230 scoped_refptr
<device::BluetoothSocket
> socket
) {
231 DCHECK(thread_checker_
.CalledOnValidThread());
232 adapter_
->SetDiscoverable(
234 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable
,
235 ptr_factory_
.GetWeakPtr(), false),
236 base::Bind(&BluetoothHostPairingController::OnSetError
,
237 ptr_factory_
.GetWeakPtr()));
239 controller_socket_
= socket
;
240 service_socket_
= NULL
;
244 controller_socket_
->Receive(
246 base::Bind(&BluetoothHostPairingController::OnReceiveComplete
,
247 ptr_factory_
.GetWeakPtr()),
248 base::Bind(&BluetoothHostPairingController::OnReceiveError
,
249 ptr_factory_
.GetWeakPtr()));
252 void BluetoothHostPairingController::OnSetDiscoverable(bool change_stage
) {
253 DCHECK(thread_checker_
.CalledOnValidThread());
255 DCHECK_EQ(current_stage_
, STAGE_NONE
);
256 ChangeStage(STAGE_WAITING_FOR_CONTROLLER
);
260 void BluetoothHostPairingController::OnSendComplete(int bytes_sent
) {}
262 void BluetoothHostPairingController::OnReceiveComplete(
263 int bytes
, scoped_refptr
<net::IOBuffer
> io_buffer
) {
264 DCHECK(thread_checker_
.CalledOnValidThread());
265 proto_decoder_
->DecodeIOBuffer(bytes
, io_buffer
);
267 controller_socket_
->Receive(
269 base::Bind(&BluetoothHostPairingController::OnReceiveComplete
,
270 ptr_factory_
.GetWeakPtr()),
271 base::Bind(&BluetoothHostPairingController::OnReceiveError
,
272 ptr_factory_
.GetWeakPtr()));
275 void BluetoothHostPairingController::OnCreateServiceError(
276 const std::string
& message
) {
277 LOG(ERROR
) << message
;
278 ChangeStage(STAGE_INITIALIZATION_ERROR
);
281 void BluetoothHostPairingController::OnSetError() {
282 adapter_
->RemovePairingDelegate(this);
283 ChangeStage(STAGE_INITIALIZATION_ERROR
);
286 void BluetoothHostPairingController::OnAcceptError(
287 const std::string
& error_message
) {
288 LOG(ERROR
) << error_message
;
291 void BluetoothHostPairingController::OnSendError(
292 const std::string
& error_message
) {
293 LOG(ERROR
) << error_message
;
296 void BluetoothHostPairingController::OnReceiveError(
297 device::BluetoothSocket::ErrorReason reason
,
298 const std::string
& error_message
) {
299 LOG(ERROR
) << reason
<< ", " << error_message
;
302 void BluetoothHostPairingController::OnHostStatusMessage(
303 const pairing_api::HostStatus
& message
) {
307 void BluetoothHostPairingController::OnConfigureHostMessage(
308 const pairing_api::ConfigureHost
& message
) {
309 FOR_EACH_OBSERVER(Observer
, observers_
,
310 ConfigureHost(message
.parameters().accepted_eula(),
311 message
.parameters().lang(),
312 message
.parameters().timezone(),
313 message
.parameters().send_reports(),
314 message
.parameters().keyboard_layout()));
317 void BluetoothHostPairingController::OnPairDevicesMessage(
318 const pairing_api::PairDevices
& message
) {
319 DCHECK(thread_checker_
.CalledOnValidThread());
320 ChangeStage(STAGE_ENROLLING
);
321 FOR_EACH_OBSERVER(Observer
, observers_
,
322 EnrollHost(message
.parameters().admin_access_token()));
325 void BluetoothHostPairingController::OnCompleteSetupMessage(
326 const pairing_api::CompleteSetup
& message
) {
327 DCHECK(thread_checker_
.CalledOnValidThread());
328 if (current_stage_
!= STAGE_ENROLLMENT_SUCCESS
) {
329 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
, kErrorInvalidProtocol
);
333 // TODO(zork): Handle adding another controller. (http://crbug.com/405757)
334 ChangeStage(STAGE_FINISHED
);
337 void BluetoothHostPairingController::OnErrorMessage(
338 const pairing_api::Error
& message
) {
342 void BluetoothHostPairingController::AdapterPresentChanged(
343 device::BluetoothAdapter
* adapter
,
345 DCHECK_EQ(adapter
, adapter_
.get());
347 adapter_
->RemoveObserver(this);
352 void BluetoothHostPairingController::AddObserver(Observer
* observer
) {
353 observers_
.AddObserver(observer
);
356 void BluetoothHostPairingController::RemoveObserver(Observer
* observer
) {
357 observers_
.RemoveObserver(observer
);
360 HostPairingController::Stage
BluetoothHostPairingController::GetCurrentStage() {
361 return current_stage_
;
364 void BluetoothHostPairingController::StartPairing() {
365 DCHECK_EQ(current_stage_
, STAGE_NONE
);
366 bool bluetooth_available
=
367 device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
368 if (!bluetooth_available
) {
369 ChangeStage(STAGE_INITIALIZATION_ERROR
);
373 device::BluetoothAdapterFactory::GetAdapter(
374 base::Bind(&BluetoothHostPairingController::OnGetAdapter
,
375 ptr_factory_
.GetWeakPtr()));
378 std::string
BluetoothHostPairingController::GetDeviceName() {
382 std::string
BluetoothHostPairingController::GetConfirmationCode() {
383 DCHECK_EQ(current_stage_
, STAGE_WAITING_FOR_CODE_CONFIRMATION
);
384 return confirmation_code_
;
387 std::string
BluetoothHostPairingController::GetEnrollmentDomain() {
388 return enrollment_domain_
;
391 void BluetoothHostPairingController::OnUpdateStatusChanged(
392 UpdateStatus update_status
) {
393 update_status_
= update_status
;
394 if (update_status
== UPDATE_STATUS_UPDATED
)
395 ChangeStage(STAGE_WAITING_FOR_CREDENTIALS
);
399 void BluetoothHostPairingController::OnEnrollmentStatusChanged(
400 EnrollmentStatus enrollment_status
) {
401 DCHECK_EQ(current_stage_
, STAGE_ENROLLING
);
402 DCHECK(thread_checker_
.CalledOnValidThread());
404 enrollment_status_
= enrollment_status
;
405 if (enrollment_status
== ENROLLMENT_STATUS_SUCCESS
) {
406 ChangeStage(STAGE_ENROLLMENT_SUCCESS
);
407 } else if (enrollment_status
== ENROLLMENT_STATUS_FAILURE
) {
408 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
,
409 kErrorEnrollmentFailed
);
414 void BluetoothHostPairingController::RequestPinCode(
415 device::BluetoothDevice
* device
) {
416 // Disallow unknown device.
417 device
->RejectPairing();
420 void BluetoothHostPairingController::RequestPasskey(
421 device::BluetoothDevice
* device
) {
422 // Disallow unknown device.
423 device
->RejectPairing();
426 void BluetoothHostPairingController::DisplayPinCode(
427 device::BluetoothDevice
* device
,
428 const std::string
& pincode
) {
429 // Disallow unknown device.
430 device
->RejectPairing();
433 void BluetoothHostPairingController::DisplayPasskey(
434 device::BluetoothDevice
* device
,
436 // Disallow unknown device.
437 device
->RejectPairing();
440 void BluetoothHostPairingController::KeysEntered(
441 device::BluetoothDevice
* device
,
443 // Disallow unknown device.
444 device
->RejectPairing();
447 void BluetoothHostPairingController::ConfirmPasskey(
448 device::BluetoothDevice
* device
,
450 // If a new connection is occurring, reset the stage. This can occur if the
451 // pairing times out, or a new controller connects.
452 if (current_stage_
== STAGE_WAITING_FOR_CODE_CONFIRMATION
)
453 ChangeStage(STAGE_WAITING_FOR_CONTROLLER
);
455 confirmation_code_
= base::StringPrintf("%06d", passkey
);
456 device
->ConfirmPairing();
457 ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION
);
460 void BluetoothHostPairingController::AuthorizePairing(
461 device::BluetoothDevice
* device
) {
462 // Disallow unknown device.
463 device
->RejectPairing();
466 } // namespace pairing_chromeos