return -EIO;
}
+static void pincode_reply_complete(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct btd_device *device = user_data;
+
+ /* If the MGMT_OP_PIN_CODE_REPLY command is acknowledged, move the
+ * starting time to that point. This give a better sense of time
+ * evaluating the pincode. */
+ device_bonding_restart_timer(device);
+}
+
int btd_adapter_pincode_reply(struct btd_adapter *adapter,
const bdaddr_t *bdaddr,
const char *pin, size_t pin_len)
{
+ struct btd_device *device;
unsigned int id;
char addr[18];
cp.pin_len = pin_len;
memcpy(cp.pin_code, pin, pin_len);
+ /* Since a pincode was requested, update the starting time to
+ * the point where the pincode is provided. */
+ device = adapter_find_device(adapter, bdaddr);
+ device_bonding_restart_timer(device);
+
id = mgmt_reply(adapter->mgmt, MGMT_OP_PIN_CODE_REPLY,
adapter->dev_id, sizeof(cp), &cp,
- NULL, NULL, NULL);
+ pincode_reply_complete, device, NULL);
}
if (id == 0)
#include <sys/ioctl.h>
#include <errno.h>
#include <dirent.h>
+#include <time.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/sdp.h>
struct btd_adapter_pin_cb_iter *cb_iter;
uint8_t status;
guint retry_timer;
+ struct timespec attempt_start_time;
+ long last_attempt_duration_ms;
};
typedef enum {
bonding->cb_iter = btd_adapter_pin_cb_iter_new(device->adapter);
+ /* Marks the bonding start time for the first attempt on request
+ * construction. The following attempts will be updated on
+ * device_bonding_retry. */
+ clock_gettime(CLOCK_MONOTONIC, &bonding->attempt_start_time);
+
if (agent)
bonding->agent = agent_ref(agent);
return bonding;
}
+void device_bonding_restart_timer(struct btd_device *device)
+{
+ if (!device || !device->bonding)
+ return;
+
+ clock_gettime(CLOCK_MONOTONIC, &device->bonding->attempt_start_time);
+}
+
+static void bonding_request_stop_timer(struct bonding_req *bonding)
+{
+ struct timespec current;
+
+ clock_gettime(CLOCK_MONOTONIC, ¤t);
+
+ /* Compute the time difference in ms. */
+ bonding->last_attempt_duration_ms =
+ (current.tv_sec - bonding->attempt_start_time.tv_sec) * 1000L +
+ (current.tv_nsec - bonding->attempt_start_time.tv_nsec)
+ / 1000000L;
+}
+
+/* Returns the duration of the last bonding attempt in milliseconds. The
+ * duration is measured starting from the latest of the following three
+ * events and finishing when the Command complete event is received for the
+ * authentication request:
+ * - MGMT_OP_PAIR_DEVICE is sent,
+ * - MGMT_OP_PIN_CODE_REPLY is sent and
+ * - Command complete event is received for the sent MGMT_OP_PIN_CODE_REPLY.
+ */
+long device_bonding_last_duration(struct btd_device *device)
+{
+ struct bonding_req *bonding = device->bonding;
+
+ if (!bonding)
+ return 0;
+
+ return bonding->last_attempt_duration_ms;
+}
+
static void create_bond_req_exit(DBusConnection *conn, void *user_data)
{
struct btd_device *device = user_data;
DBG("retrying bonding");
bonding->retry_timer = 0;
+ /* Restart the bonding timer to the begining of the pairing. If not
+ * pincode request/reply occurs during this retry,
+ * device_bonding_last_duration() will return a consistent value from
+ * this point. */
+ device_bonding_restart_timer(device);
+
if (bonding->agent)
io_cap = agent_get_io_capability(bonding->agent);
else
if (!bonding)
return -EINVAL;
+ /* Mark the end of a bonding attempt to compute the delta for the
+ * retry. */
+ bonding_request_stop_timer(bonding);
+
if (btd_adapter_pin_cb_iter_end(bonding->cb_iter))
return -EINVAL;
void device_bonding_failed(struct btd_device *device, uint8_t status);
struct btd_adapter_pin_cb_iter *device_bonding_iter(struct btd_device *device);
int device_bonding_attempt_retry(struct btd_device *device);
+long device_bonding_last_duration(struct btd_device *device);
+void device_bonding_restart_timer(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,