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_
);
90 if (!permanent_id_
.empty())
91 host_status
.mutable_parameters()->set_permanent_id(permanent_id_
);
93 // TODO(zork): Get these values from the UI. (http://crbug.com/405744)
94 host_status
.mutable_parameters()->set_connectivity(
95 pairing_api::HostStatusParameters::CONNECTIVITY_CONNECTED
);
96 host_status
.mutable_parameters()->set_update_status(
97 PairingApiUpdateStatus(update_status_
));
98 host_status
.mutable_parameters()->set_enrollment_status(
99 PairingApiEnrollmentStatus(enrollment_status_
));
101 // TODO(zork): Get a list of other paired controllers.
102 // (http://crbug.com/405757)
105 scoped_refptr
<net::IOBuffer
> io_buffer(
106 ProtoDecoder::SendHostStatus(host_status
, &size
));
108 controller_socket_
->Send(
110 base::Bind(&BluetoothHostPairingController::OnSendComplete
,
111 ptr_factory_
.GetWeakPtr()),
112 base::Bind(&BluetoothHostPairingController::OnSendError
,
113 ptr_factory_
.GetWeakPtr()));
116 void BluetoothHostPairingController::AbortWithError(
118 const std::string
& message
) {
119 if (controller_socket_
.get()) {
120 pairing_api::Error error
;
122 error
.set_api_version(kPairingAPIVersion
);
123 error
.mutable_parameters()->set_code(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
);
124 error
.mutable_parameters()->set_description(message
);
127 scoped_refptr
<net::IOBuffer
> io_buffer(
128 ProtoDecoder::SendError(error
, &size
));
130 controller_socket_
->Send(
132 base::Bind(&BluetoothHostPairingController::OnSendComplete
,
133 ptr_factory_
.GetWeakPtr()),
134 base::Bind(&BluetoothHostPairingController::OnSendError
,
135 ptr_factory_
.GetWeakPtr()));
140 void BluetoothHostPairingController::Reset() {
141 if (controller_socket_
.get()) {
142 controller_socket_
->Close();
143 controller_socket_
= NULL
;
146 if (service_socket_
.get()) {
147 service_socket_
->Close();
148 service_socket_
= NULL
;
150 ChangeStage(STAGE_NONE
);
153 void BluetoothHostPairingController::OnGetAdapter(
154 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
155 DCHECK(thread_checker_
.CalledOnValidThread());
156 DCHECK(!adapter_
.get());
159 if (adapter_
->IsPresent()) {
162 // Set the name once the adapter is present.
163 adapter_
->AddObserver(this);
167 void BluetoothHostPairingController::SetName() {
168 // Hash the bluetooth address and take the lower 2 bytes to create a human
169 // readable device name.
170 const uint32 device_id
= base::Hash(adapter_
->GetAddress()) & 0xFFFF;
171 device_name_
= base::StringPrintf("%s%04X", kDeviceNamePrefix
, device_id
);
175 base::Bind(&BluetoothHostPairingController::OnSetName
,
176 ptr_factory_
.GetWeakPtr()),
177 base::Bind(&BluetoothHostPairingController::OnSetError
,
178 ptr_factory_
.GetWeakPtr()));
181 void BluetoothHostPairingController::OnSetName() {
182 DCHECK(thread_checker_
.CalledOnValidThread());
183 if (adapter_
->IsPowered()) {
186 adapter_
->SetPowered(
188 base::Bind(&BluetoothHostPairingController::OnSetPowered
,
189 ptr_factory_
.GetWeakPtr()),
190 base::Bind(&BluetoothHostPairingController::OnSetError
,
191 ptr_factory_
.GetWeakPtr()));
195 void BluetoothHostPairingController::OnSetPowered() {
196 DCHECK(thread_checker_
.CalledOnValidThread());
197 adapter_
->AddPairingDelegate(
198 this, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH
);
200 device::BluetoothAdapter::ServiceOptions options
;
201 options
.name
.reset(new std::string(kPairingServiceName
));
203 adapter_
->CreateRfcommService(
204 device::BluetoothUUID(kPairingServiceUUID
), options
,
205 base::Bind(&BluetoothHostPairingController::OnCreateService
,
206 ptr_factory_
.GetWeakPtr()),
207 base::Bind(&BluetoothHostPairingController::OnCreateServiceError
,
208 ptr_factory_
.GetWeakPtr()));
211 void BluetoothHostPairingController::OnCreateService(
212 scoped_refptr
<device::BluetoothSocket
> socket
) {
213 DCHECK(thread_checker_
.CalledOnValidThread());
214 service_socket_
= socket
;
216 service_socket_
->Accept(
217 base::Bind(&BluetoothHostPairingController::OnAccept
,
218 ptr_factory_
.GetWeakPtr()),
219 base::Bind(&BluetoothHostPairingController::OnAcceptError
,
220 ptr_factory_
.GetWeakPtr()));
222 adapter_
->SetDiscoverable(
224 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable
,
225 ptr_factory_
.GetWeakPtr(), true),
226 base::Bind(&BluetoothHostPairingController::OnSetError
,
227 ptr_factory_
.GetWeakPtr()));
230 void BluetoothHostPairingController::OnAccept(
231 const device::BluetoothDevice
* device
,
232 scoped_refptr
<device::BluetoothSocket
> socket
) {
233 DCHECK(thread_checker_
.CalledOnValidThread());
234 adapter_
->SetDiscoverable(
236 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable
,
237 ptr_factory_
.GetWeakPtr(), false),
238 base::Bind(&BluetoothHostPairingController::OnSetError
,
239 ptr_factory_
.GetWeakPtr()));
241 controller_socket_
= socket
;
242 service_socket_
= NULL
;
246 controller_socket_
->Receive(
248 base::Bind(&BluetoothHostPairingController::OnReceiveComplete
,
249 ptr_factory_
.GetWeakPtr()),
250 base::Bind(&BluetoothHostPairingController::OnReceiveError
,
251 ptr_factory_
.GetWeakPtr()));
254 void BluetoothHostPairingController::OnSetDiscoverable(bool change_stage
) {
255 DCHECK(thread_checker_
.CalledOnValidThread());
257 DCHECK_EQ(current_stage_
, STAGE_NONE
);
258 ChangeStage(STAGE_WAITING_FOR_CONTROLLER
);
262 void BluetoothHostPairingController::OnSendComplete(int bytes_sent
) {}
264 void BluetoothHostPairingController::OnReceiveComplete(
265 int bytes
, scoped_refptr
<net::IOBuffer
> io_buffer
) {
266 DCHECK(thread_checker_
.CalledOnValidThread());
267 proto_decoder_
->DecodeIOBuffer(bytes
, io_buffer
);
269 controller_socket_
->Receive(
271 base::Bind(&BluetoothHostPairingController::OnReceiveComplete
,
272 ptr_factory_
.GetWeakPtr()),
273 base::Bind(&BluetoothHostPairingController::OnReceiveError
,
274 ptr_factory_
.GetWeakPtr()));
277 void BluetoothHostPairingController::OnCreateServiceError(
278 const std::string
& message
) {
279 LOG(ERROR
) << message
;
280 ChangeStage(STAGE_INITIALIZATION_ERROR
);
283 void BluetoothHostPairingController::OnSetError() {
284 adapter_
->RemovePairingDelegate(this);
285 ChangeStage(STAGE_INITIALIZATION_ERROR
);
288 void BluetoothHostPairingController::OnAcceptError(
289 const std::string
& error_message
) {
290 LOG(ERROR
) << error_message
;
293 void BluetoothHostPairingController::OnSendError(
294 const std::string
& error_message
) {
295 LOG(ERROR
) << error_message
;
298 void BluetoothHostPairingController::OnReceiveError(
299 device::BluetoothSocket::ErrorReason reason
,
300 const std::string
& error_message
) {
301 LOG(ERROR
) << reason
<< ", " << error_message
;
304 void BluetoothHostPairingController::OnHostStatusMessage(
305 const pairing_api::HostStatus
& message
) {
309 void BluetoothHostPairingController::OnConfigureHostMessage(
310 const pairing_api::ConfigureHost
& message
) {
311 FOR_EACH_OBSERVER(Observer
, observers_
,
312 ConfigureHostRequested(
313 message
.parameters().accepted_eula(),
314 message
.parameters().lang(),
315 message
.parameters().timezone(),
316 message
.parameters().send_reports(),
317 message
.parameters().keyboard_layout()));
320 void BluetoothHostPairingController::OnPairDevicesMessage(
321 const pairing_api::PairDevices
& message
) {
322 DCHECK(thread_checker_
.CalledOnValidThread());
323 ChangeStage(STAGE_ENROLLING
);
324 FOR_EACH_OBSERVER(Observer
, observers_
,
326 message
.parameters().admin_access_token()));
329 void BluetoothHostPairingController::OnCompleteSetupMessage(
330 const pairing_api::CompleteSetup
& message
) {
331 DCHECK(thread_checker_
.CalledOnValidThread());
332 if (current_stage_
!= STAGE_ENROLLMENT_SUCCESS
) {
333 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
, kErrorInvalidProtocol
);
337 // TODO(zork): Handle adding another controller. (http://crbug.com/405757)
338 ChangeStage(STAGE_FINISHED
);
341 void BluetoothHostPairingController::OnErrorMessage(
342 const pairing_api::Error
& message
) {
346 void BluetoothHostPairingController::OnAddNetworkMessage(
347 const pairing_api::AddNetwork
& message
) {
348 DCHECK(thread_checker_
.CalledOnValidThread());
349 FOR_EACH_OBSERVER(Observer
, observers_
,
350 AddNetworkRequested(message
.parameters().onc_spec()));
353 void BluetoothHostPairingController::AdapterPresentChanged(
354 device::BluetoothAdapter
* adapter
,
356 DCHECK_EQ(adapter
, adapter_
.get());
358 adapter_
->RemoveObserver(this);
363 void BluetoothHostPairingController::AddObserver(Observer
* observer
) {
364 observers_
.AddObserver(observer
);
367 void BluetoothHostPairingController::RemoveObserver(Observer
* observer
) {
368 observers_
.RemoveObserver(observer
);
371 HostPairingController::Stage
BluetoothHostPairingController::GetCurrentStage() {
372 return current_stage_
;
375 void BluetoothHostPairingController::StartPairing() {
376 DCHECK_EQ(current_stage_
, STAGE_NONE
);
377 bool bluetooth_available
=
378 device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
379 if (!bluetooth_available
) {
380 ChangeStage(STAGE_INITIALIZATION_ERROR
);
384 device::BluetoothAdapterFactory::GetAdapter(
385 base::Bind(&BluetoothHostPairingController::OnGetAdapter
,
386 ptr_factory_
.GetWeakPtr()));
389 std::string
BluetoothHostPairingController::GetDeviceName() {
393 std::string
BluetoothHostPairingController::GetConfirmationCode() {
394 DCHECK_EQ(current_stage_
, STAGE_WAITING_FOR_CODE_CONFIRMATION
);
395 return confirmation_code_
;
398 std::string
BluetoothHostPairingController::GetEnrollmentDomain() {
399 return enrollment_domain_
;
402 void BluetoothHostPairingController::OnUpdateStatusChanged(
403 UpdateStatus update_status
) {
404 update_status_
= update_status
;
405 if (update_status
== UPDATE_STATUS_UPDATED
)
406 ChangeStage(STAGE_WAITING_FOR_CREDENTIALS
);
410 void BluetoothHostPairingController::OnEnrollmentStatusChanged(
411 EnrollmentStatus enrollment_status
) {
412 DCHECK_EQ(current_stage_
, STAGE_ENROLLING
);
413 DCHECK(thread_checker_
.CalledOnValidThread());
415 enrollment_status_
= enrollment_status
;
416 if (enrollment_status
== ENROLLMENT_STATUS_SUCCESS
) {
417 ChangeStage(STAGE_ENROLLMENT_SUCCESS
);
418 } else if (enrollment_status
== ENROLLMENT_STATUS_FAILURE
) {
419 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
,
420 kErrorEnrollmentFailed
);
425 void BluetoothHostPairingController::SetPermanentId(
426 const std::string
& permanent_id
) {
427 permanent_id_
= permanent_id
;
430 void BluetoothHostPairingController::RequestPinCode(
431 device::BluetoothDevice
* device
) {
432 // Disallow unknown device.
433 device
->RejectPairing();
436 void BluetoothHostPairingController::RequestPasskey(
437 device::BluetoothDevice
* device
) {
438 // Disallow unknown device.
439 device
->RejectPairing();
442 void BluetoothHostPairingController::DisplayPinCode(
443 device::BluetoothDevice
* device
,
444 const std::string
& pincode
) {
445 // Disallow unknown device.
446 device
->RejectPairing();
449 void BluetoothHostPairingController::DisplayPasskey(
450 device::BluetoothDevice
* device
,
452 // Disallow unknown device.
453 device
->RejectPairing();
456 void BluetoothHostPairingController::KeysEntered(
457 device::BluetoothDevice
* device
,
459 // Disallow unknown device.
460 device
->RejectPairing();
463 void BluetoothHostPairingController::ConfirmPasskey(
464 device::BluetoothDevice
* device
,
466 // If a new connection is occurring, reset the stage. This can occur if the
467 // pairing times out, or a new controller connects.
468 if (current_stage_
== STAGE_WAITING_FOR_CODE_CONFIRMATION
)
469 ChangeStage(STAGE_WAITING_FOR_CONTROLLER
);
471 confirmation_code_
= base::StringPrintf("%06d", passkey
);
472 device
->ConfirmPairing();
473 ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION
);
476 void BluetoothHostPairingController::AuthorizePairing(
477 device::BluetoothDevice
* device
) {
478 // Disallow unknown device.
479 device
->RejectPairing();
482 } // namespace pairing_chromeos