From: Alex Deymo <deymo@chromium.org>
To: linux-bluetooth@vger.kernel.org
Cc: marcel@holtmann.org, keybuk@chromium.org,
Alex Deymo <deymo@chromium.org>
Subject: [PATCH v3 4/8] core: retry bonding attempt until the iterator reaches the end.
Date: Tue, 23 Apr 2013 11:04:03 -0700 [thread overview]
Message-ID: <1366740247-368-5-git-send-email-deymo@chromium.org> (raw)
In-Reply-To: <1366740247-368-1-git-send-email-deymo@chromium.org>
This patch splits the bonding process in an interative process consisting
of one or more "bonding attempts". The user/agent starts a new "bonding"
that may involve several rounds of "bonding attempts" with the device
before it gets back to the user/agent.
Some functions were split in two parts to reflect this change. When a
bonding attempt fails with an authentication error, a new bonding attempt
is initiated (after a short delay) to retry with the next function (or
next call to the same function) in the pincode callback list. This
effectively allows a plugin try different pincodes for the same device
during the same bonding.
---
src/adapter.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++---------
src/adapter.h | 3 ++
src/device.c | 41 +++++++++++++++++++++++++++
src/device.h | 2 ++
4 files changed, 124 insertions(+), 13 deletions(-)
diff --git a/src/adapter.c b/src/adapter.c
index b2231d7..1c8b9db 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -4934,6 +4934,45 @@ static void bonding_complete(struct btd_adapter *adapter,
check_oob_bonding_complete(adapter, bdaddr, status);
}
+/* bonding_attempt_complete() handles the end of a "bonding attempt" checking if
+ * it should begin a new attempt or complete the bonding.
+ */
+static void bonding_attempt_complete(struct btd_adapter *adapter,
+ const bdaddr_t *bdaddr,
+ uint8_t addr_type, uint8_t status)
+{
+ int err = 0;
+ struct btd_device *device;
+ char addr[18];
+
+ ba2str(bdaddr, addr);
+ DBG("hci%u bdaddr %s type %u status 0x%x", adapter->dev_id, addr,
+ addr_type, status);
+
+ if (status == 0)
+ device = adapter_get_device(adapter, bdaddr, addr_type);
+ else
+ device = adapter_find_device(adapter, bdaddr);
+
+ if (status == MGMT_STATUS_AUTH_FAILED) {
+
+ /* On faliure, issue a bonding_retry if possible. */
+ if (device != NULL) {
+ err = device_bonding_attempt_retry(device);
+ if (err == 0)
+ return;
+ }
+ }
+
+ /* Ignore disconnects during retry. */
+ if (status == MGMT_STATUS_DISCONNECTED &&
+ device && device_is_retrying(device))
+ return;
+
+ /* In any other case, finish the bonding. */
+ bonding_complete(adapter, bdaddr, addr_type, status);
+}
+
struct pair_device_data {
struct btd_adapter *adapter;
bdaddr_t bdaddr;
@@ -4987,7 +5026,7 @@ static void pair_device_complete(uint8_t status, uint16_t length,
error("Pair device failed: %s (0x%02x)",
mgmt_errstr(status), status);
- bonding_complete(adapter, &data->bdaddr,
+ bonding_attempt_complete(adapter, &data->bdaddr,
data->addr_type, status);
return;
}
@@ -4997,17 +5036,13 @@ static void pair_device_complete(uint8_t status, uint16_t length,
return;
}
- bonding_complete(adapter, &rp->addr.bdaddr, rp->addr.type, status);
+ bonding_attempt_complete(adapter, &rp->addr.bdaddr, rp->addr.type,
+ status);
}
int adapter_create_bonding(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
uint8_t addr_type, uint8_t io_cap)
{
- struct mgmt_cp_pair_device cp;
- char addr[18];
- struct pair_device_data *data;
- unsigned int id;
-
if (adapter->pair_device_id > 0) {
error("Unable pair since another pairing is in progress");
return -EBUSY;
@@ -5015,6 +5050,18 @@ int adapter_create_bonding(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
suspend_discovery(adapter);
+ return adapter_bonding_attempt(adapter, bdaddr, addr_type, io_cap);
+}
+
+/* Starts a new bonding attempt in a fresh new bonding_req or a retried one. */
+int adapter_bonding_attempt(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
+ uint8_t addr_type, uint8_t io_cap)
+{
+ struct mgmt_cp_pair_device cp;
+ char addr[18];
+ struct pair_device_data *data;
+ unsigned int id;
+
ba2str(bdaddr, addr);
DBG("hci%u bdaddr %s type %d io_cap 0x%02x",
adapter->dev_id, addr, addr_type, io_cap);
@@ -5067,7 +5114,7 @@ static void dev_disconnected(struct btd_adapter *adapter,
if (device)
adapter_remove_connection(adapter, device);
- bonding_complete(adapter, &addr->bdaddr, addr->type,
+ bonding_attempt_complete(adapter, &addr->bdaddr, addr->type,
MGMT_STATUS_DISCONNECTED);
}
@@ -5121,7 +5168,8 @@ static void auth_failed_callback(uint16_t index, uint16_t length,
return;
}
- bonding_complete(adapter, &ev->addr.bdaddr, ev->addr.type, ev->status);
+ bonding_attempt_complete(adapter, &ev->addr.bdaddr, ev->addr.type,
+ ev->status);
}
static void store_link_key(struct btd_adapter *adapter,
@@ -5721,14 +5769,31 @@ static void connect_failed_callback(uint16_t index, uint16_t length,
device = adapter_find_device(adapter, &ev->addr.bdaddr);
if (device) {
+ /* If the device is in a bonding process cancel any auth request
+ * sent to the agent before proceeding, but keep the bonding
+ * request structure. */
if (device_is_bonding(device, NULL))
- device_bonding_failed(device, ev->status);
- if (device_is_temporary(device))
- adapter_remove_device(adapter, device, TRUE);
+ device_cancel_authentication(device, FALSE);
}
/* In the case of security mode 3 devices */
- bonding_complete(adapter, &ev->addr.bdaddr, ev->addr.type, ev->status);
+ bonding_attempt_complete(adapter, &ev->addr.bdaddr, ev->addr.type,
+ ev->status);
+
+ /* If the device is scheduled to retry the bonding wait until the retry
+ * happens. In other case, proceed with cancel the bondig.
+ */
+ if (device && device_is_bonding(device, NULL)
+ && !device_is_retrying(device)) {
+ device_cancel_authentication(device, TRUE);
+ device_bonding_failed(device, ev->status);
+ }
+
+ /* In the case the bonding was canceled or did exists, remove the device
+ * when it is temporary. */
+ if (device && !device_is_bonding(device, NULL)
+ && device_is_temporary(device))
+ adapter_remove_device(adapter, device, TRUE);
}
static void unpaired_callback(uint16_t index, uint16_t length,
diff --git a/src/adapter.h b/src/adapter.h
index 7392187..2f4bc5a 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -178,6 +178,9 @@ int btd_adapter_passkey_reply(struct btd_adapter *adapter,
int adapter_create_bonding(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
uint8_t addr_type, uint8_t io_cap);
+int adapter_bonding_attempt(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
+ uint8_t addr_type, uint8_t io_cap);
+
int adapter_cancel_bonding(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
uint8_t addr_type);
diff --git a/src/device.c b/src/device.c
index 291ae5f..1cd85d0 100644
--- a/src/device.c
+++ b/src/device.c
@@ -3743,6 +3743,47 @@ gboolean device_is_bonding(struct btd_device *device, const char *sender)
return g_str_equal(sender, dbus_message_get_sender(bonding->msg));
}
+static gboolean device_bonding_retry(gpointer data)
+{
+ struct btd_device *device = data;
+ struct btd_adapter *adapter = device_get_adapter(device);
+ struct bonding_req *bonding = device->bonding;
+ int err;
+
+ if (!bonding)
+ return FALSE;
+
+ DBG("retrying bonding");
+ bonding->retry_timer = 0;
+
+ err = adapter_bonding_attempt(adapter, &device->bdaddr,
+ device->bdaddr_type, bonding->capability);
+ if (err < 0)
+ device_bonding_complete(device, bonding->status);
+
+ return FALSE;
+}
+
+int device_bonding_attempt_retry(struct btd_device *device)
+{
+ struct bonding_req *bonding = device->bonding;
+
+ /* Ignore other failure events while retrying */
+ if (device_is_retrying(device))
+ return 0;
+
+ if (!bonding)
+ return -EINVAL;
+
+ if (pincb_iter_end(bonding->cb_iter))
+ return -EINVAL;
+
+ DBG("scheduling retry with io_cap %u", bonding->capability);
+ bonding->retry_timer = g_timeout_add(3000,
+ device_bonding_retry, device);
+ return 0;
+}
+
void device_bonding_failed(struct btd_device *device, uint8_t status)
{
struct bonding_req *bonding = device->bonding;
diff --git a/src/device.h b/src/device.h
index 61a294b..f81721a 100644
--- a/src/device.h
+++ b/src/device.h
@@ -76,8 +76,10 @@ gboolean device_is_connected(struct btd_device *device);
gboolean device_is_retrying(struct btd_device *device);
void device_bonding_complete(struct btd_device *device, uint8_t status);
gboolean device_is_bonding(struct btd_device *device, const char *sender);
+void device_bonding_attempt_failed(struct btd_device *device, uint8_t status);
void device_bonding_failed(struct btd_device *device, uint8_t status);
struct pincb_iter *device_bonding_iter(struct btd_device *device);
+int device_bonding_attempt_retry(struct btd_device *device);
int device_request_pincode(struct btd_device *device, gboolean secure);
int device_request_passkey(struct btd_device *device);
int device_confirm_passkey(struct btd_device *device, uint32_t passkey,
--
1.8.2.1
next prev parent reply other threads:[~2013-04-23 18:04 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-04-23 18:03 [PATCH v3 0/8] Autopair plugin Alex Deymo
2013-04-23 18:04 ` [PATCH v3 1/8] core: Convert the pincode callback to an interable list Alex Deymo
2013-04-24 11:24 ` Johan Hedberg
2013-04-24 11:42 ` Johan Hedberg
2013-04-23 18:04 ` [PATCH v3 2/8] plugins: Extend the pin code callback with the call number Alex Deymo
2013-04-23 18:04 ` [PATCH v3 3/8] core: Add support for retrying a bonding Alex Deymo
2013-04-24 11:29 ` Johan Hedberg
2013-04-23 18:04 ` Alex Deymo [this message]
2013-04-24 11:32 ` [PATCH v3 4/8] core: retry bonding attempt until the iterator reaches the end Johan Hedberg
2013-04-23 18:04 ` [PATCH v3 5/8] core: Add device_get_class to the public interface Alex Deymo
2013-04-23 18:04 ` [PATCH v3 6/8] autopair: Add the autopair plugin Alex Deymo
2013-04-23 18:04 ` [PATCH v3 7/8] core: Expose the last bonding attempt timeout on retry Alex Deymo
2013-04-24 11:37 ` Johan Hedberg
2013-04-24 14:03 ` Marcel Holtmann
2013-04-23 18:04 ` [PATCH v3 8/8] autopair: Try a fixed pincode for keyboards rejecting random codes Alex Deymo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1366740247-368-5-git-send-email-deymo@chromium.org \
--to=deymo@chromium.org \
--cc=keybuk@chromium.org \
--cc=linux-bluetooth@vger.kernel.org \
--cc=marcel@holtmann.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox