Re: [PATCH] core: Add btd_adapter_recreate_bonding()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Please note that this patch depends on a previously submitted kernel
patch [1] to ensure that connection parameters are not lost when
rebonding.


[1] [PATCH] Bluetooth: Defer connection-parameter removal when
unpairing without disconnecting

On Sat, Oct 11, 2014 at 1:53 AM, Alfonso Acosta <fons@xxxxxxxxxxx> wrote:
> This patch adds btd_adapter_recreate_bonding() which rebonds a device,
> i.e. it performs an unbonding operation inmediately followed by a
> bonding operation.
>
> Although there is no internal use for btd_adapter_recreate_bonding()
> yet, it is useful for plugins dealing with devices which require
> renegotiaing their keys. For instance, when dealing with devices
> without persistent storage which lose their keys on reset.
>
> Certain caveats have been taken into account when rebonding with a LE
> device:
>
>  * If the device to rebond is already connected, the rebonding is done
>    without disconnecting to avoid the extra latency of reestablishing
>    the connection.
>
>  * If no connection exists, we connect before unbonding anyways to
>    avoid losing the device's autoconnection and connection parameters,
>    which are removed by the kernel when unpairing if no connection
>    exists.
>
>  * Not closing the connection requires defering attribute discovery
>    until the rebonding is done. Otherwise, the security level could be
>    elavated with the old LTK, which may be invalid since we are
>    rebonding. When rebonding, attribute discovery is suspended and the
>    ATT socket is saved to allow resuming it once bonding is finished.
> ---
>  src/adapter.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
>  src/adapter.h |  7 ++++++-
>  src/device.c  | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
>  src/device.h  |  4 ++++
>  4 files changed, 119 insertions(+), 7 deletions(-)
>
> diff --git a/src/adapter.c b/src/adapter.c
> index 92ee1a0..81e8f22 100644
> --- a/src/adapter.c
> +++ b/src/adapter.c
> @@ -5195,14 +5195,15 @@ int btd_adapter_read_clock(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
>  }
>
>  int btd_adapter_remove_bonding(struct btd_adapter *adapter,
> -                               const bdaddr_t *bdaddr, uint8_t bdaddr_type)
> +                               const bdaddr_t *bdaddr, uint8_t bdaddr_type,
> +                               uint8_t disconnect)
>  {
>         struct mgmt_cp_unpair_device cp;
>
>         memset(&cp, 0, sizeof(cp));
>         bacpy(&cp.addr.bdaddr, bdaddr);
>         cp.addr.type = bdaddr_type;
> -       cp.disconnect = 1;
> +       cp.disconnect = disconnect;
>
>         if (mgmt_send(adapter->mgmt, MGMT_OP_UNPAIR_DEVICE,
>                                 adapter->dev_id, sizeof(cp), &cp,
> @@ -5212,6 +5213,53 @@ int btd_adapter_remove_bonding(struct btd_adapter *adapter,
>         return -EIO;
>  }
>
> +int btd_adapter_recreate_bonding(struct btd_adapter *adapter,
> +                                       const bdaddr_t *bdaddr,
> +                                       uint8_t bdaddr_type,
> +                                       uint8_t io_cap)
> +{
> +       struct btd_device *device;
> +       int err;
> +
> +       device = btd_adapter_get_device(adapter, bdaddr, bdaddr_type);
> +
> +       if (!device || !device_is_bonded(device, bdaddr_type))
> +               return -EINVAL;
> +
> +       device_set_rebonding(device, bdaddr_type, true);
> +
> +       /* Make sure the device is connected before unbonding to avoid
> +        * losing the device's autoconnection and connection
> +        * parameters, which are removed by the kernel when unpairing
> +        * if no connection exists. We would had anyways implicitly
> +        * connected when bonding later on, so we might as well just
> +        * do it explicitly now.
> +        */
> +       if (bdaddr_type != BDADDR_BREDR && !btd_device_is_connected(device)) {
> +               err = device_connect_le(device);
> +               if (err < 0)
> +                       goto failed;
> +       }
> +
> +       /* Unbond without disconnecting to avoid the connection
> +        * re-establishment latency
> +        */
> +       err = btd_adapter_remove_bonding(adapter, bdaddr, bdaddr_type, 0);
> +       if (err < 0)
> +               goto failed;
> +
> +       err = adapter_create_bonding(adapter, bdaddr, bdaddr_type, io_cap);
> +       if (err < 0)
> +               goto failed;
> +
> +       return 0;
> +
> +failed:
> +       error("failed: %s", strerror(-err));
> +       device_set_rebonding(device, bdaddr_type, false);
> +       return err;
> +}
> +
>  static void pincode_reply_complete(uint8_t status, uint16_t length,
>                                         const void *param, void *user_data)
>  {
> @@ -5594,8 +5642,11 @@ static void bonding_complete(struct btd_adapter *adapter,
>         else
>                 device = btd_adapter_find_device(adapter, bdaddr, addr_type);
>
> -       if (device != NULL)
> +       if (device != NULL) {
>                 device_bonding_complete(device, addr_type, status);
> +               if (device_is_rebonding(device, addr_type))
> +                       device_rebonding_complete(device, addr_type);
> +       }
>
>         resume_discovery(adapter);
>
> diff --git a/src/adapter.h b/src/adapter.h
> index 6801fee..bd00d3e 100644
> --- a/src/adapter.h
> +++ b/src/adapter.h
> @@ -158,7 +158,12 @@ int btd_adapter_disconnect_device(struct btd_adapter *adapter,
>                                                         uint8_t bdaddr_type);
>
>  int btd_adapter_remove_bonding(struct btd_adapter *adapter,
> -                               const bdaddr_t *bdaddr, uint8_t bdaddr_type);
> +                               const bdaddr_t *bdaddr, uint8_t bdaddr_type,
> +                               uint8_t disconnect);
> +int btd_adapter_recreate_bonding(struct btd_adapter *adapter,
> +                                       const bdaddr_t *bdaddr,
> +                                       uint8_t bdaddr_type,
> +                                       uint8_t io_cap);
>
>  int btd_adapter_pincode_reply(struct btd_adapter *adapter,
>                                         const  bdaddr_t *bdaddr,
> diff --git a/src/device.c b/src/device.c
> index 875a5c5..4aab349 100644
> --- a/src/device.c
> +++ b/src/device.c
> @@ -158,6 +158,7 @@ struct att_callbacks {
>  struct bearer_state {
>         bool paired;
>         bool bonded;
> +       bool rebonding;
>         bool connected;
>         bool svc_resolved;
>  };
> @@ -221,6 +222,8 @@ struct btd_device {
>         int8_t          rssi;
>
>         GIOChannel      *att_io;
> +       GIOChannel      *att_rebond_io;
> +
>         guint           cleanup_id;
>         guint           store_id;
>  };
> @@ -522,6 +525,9 @@ static void device_free(gpointer user_data)
>
>         attio_cleanup(device);
>
> +       if (device->att_rebond_io)
> +               g_io_channel_unref(device->att_rebond_io);
> +
>         if (device->tmp_records)
>                 sdp_list_free(device->tmp_records,
>                                         (sdp_free_func_t) sdp_record_free);
> @@ -1739,6 +1745,23 @@ long device_bonding_last_duration(struct btd_device *device)
>         return bonding->last_attempt_duration_ms;
>  }
>
> +bool device_is_rebonding(struct btd_device *device, uint8_t bdaddr_type)
> +{
> +       struct bearer_state *state = get_state(device, bdaddr_type);
> +
> +       return state->rebonding;
> +}
> +
> +void device_set_rebonding(struct btd_device *device, uint8_t bdaddr_type,
> +                               bool rebonding)
> +{
> +       struct bearer_state *state = get_state(device, bdaddr_type);
> +
> +       state->rebonding = rebonding;
> +
> +       DBG("rebonding = %d", rebonding);
> +}
> +
>  static void create_bond_req_exit(DBusConnection *conn, void *user_data)
>  {
>         struct btd_device *device = user_data;
> @@ -2029,7 +2052,7 @@ void device_remove_connection(struct btd_device *device, uint8_t bdaddr_type)
>
>         if (state->paired && !state->bonded)
>                 btd_adapter_remove_bonding(device->adapter, &device->bdaddr,
> -                                                               bdaddr_type);
> +                                                               bdaddr_type, 1);
>
>         if (device->bredr_state.connected || device->le_state.connected)
>                 return;
> @@ -2639,13 +2662,13 @@ static void device_remove_stored(struct btd_device *device)
>         if (device->bredr_state.bonded) {
>                 device->bredr_state.bonded = false;
>                 btd_adapter_remove_bonding(device->adapter, &device->bdaddr,
> -                                                               BDADDR_BREDR);
> +                                                       BDADDR_BREDR, 1);
>         }
>
>         if (device->le_state.bonded) {
>                 device->le_state.bonded = false;
>                 btd_adapter_remove_bonding(device->adapter, &device->bdaddr,
> -                                                       device->bdaddr_type);
> +                                                       device->bdaddr_type, 1);
>         }
>
>         device->bredr_state.paired = false;
> @@ -3628,6 +3651,18 @@ bool device_attach_attrib(struct btd_device *dev, GIOChannel *io)
>         GAttrib *attrib;
>         BtIOSecLevel sec_level;
>
> +       DBG("");
> +
> +       if (dev->le_state.rebonding) {
> +               DBG("postponing due to rebonding");
> +               /* Keep the att socket, and defer attaching the attributes
> +                * until rebonding is done.
> +                */
> +               if (!dev->att_rebond_io)
> +                       dev->att_rebond_io = g_io_channel_ref(io);
> +               return false;
> +       }
> +
>         bt_io_get(io, &gerr, BT_IO_OPT_SEC_LEVEL, &sec_level,
>                                                 BT_IO_OPT_INVALID);
>         if (gerr) {
> @@ -4269,6 +4304,23 @@ void device_bonding_complete(struct btd_device *device, uint8_t bdaddr_type,
>         }
>  }
>
> +bool device_rebonding_complete(struct btd_device *device, uint8_t bdaddr_type)
> +{
> +       bool ret = true;
> +
> +       DBG("");
> +
> +       device_set_rebonding(device, bdaddr_type, false);
> +
> +       if (bdaddr_type != BDADDR_BREDR && device->att_rebond_io) {
> +               ret = device_attach_attrib(device, device->att_rebond_io);
> +               g_io_channel_unref(device->att_rebond_io);
> +               device->att_rebond_io = NULL;
> +       }
> +
> +       return ret;
> +}
> +
>  static gboolean svc_idle_cb(gpointer user_data)
>  {
>         struct svc_callback *cb = user_data;
> diff --git a/src/device.h b/src/device.h
> index 2e0473e..65b1018 100644
> --- a/src/device.h
> +++ b/src/device.h
> @@ -94,6 +94,10 @@ bool device_is_retrying(struct btd_device *device);
>  void device_bonding_complete(struct btd_device *device, uint8_t bdaddr_type,
>                                                         uint8_t status);
>  gboolean device_is_bonding(struct btd_device *device, const char *sender);
> +bool device_is_rebonding(struct btd_device *device, uint8_t bdaddr_type);
> +void device_set_rebonding(struct btd_device *device, uint8_t bdaddr_type,
> +                               bool rebonding);
> +bool device_complete_rebonding(struct btd_device *device, uint8_t bdaddr_type);
>  void device_bonding_attempt_failed(struct btd_device *device, uint8_t status);
>  void device_bonding_failed(struct btd_device *device, uint8_t status);
>  struct btd_adapter_pin_cb_iter *device_bonding_iter(struct btd_device *device);
> --
> 1.9.1
>



-- 
Alfonso Acosta

Embedded Systems Engineer at Spotify
Birger Jarlsgatan 61, Stockholm, Sweden
http://www.spotify.com
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux