diff --git a/bluez/gattlib_connect.c b/bluez/gattlib_connect.c index 679d9c6..f2b57f6 100644 --- a/bluez/gattlib_connect.c +++ b/bluez/gattlib_connect.c @@ -308,31 +308,56 @@ static gatt_connection_t *initialize_gattlib_connection(const gchar *src, const } } -static BtIOSecLevel get_bt_io_sec_level(gattlib_bt_sec_level_t sec_level) { - switch(sec_level) { - case BT_SEC_SDP: - return BT_IO_SEC_SDP; - case BT_SEC_LOW: - return BT_IO_SEC_LOW; - case BT_SEC_MEDIUM: - return BT_IO_SEC_MEDIUM; - case BT_SEC_HIGH: - return BT_IO_SEC_HIGH; - default: - return BT_IO_SEC_SDP; +static void get_connection_options(unsigned long options, BtIOSecLevel *bt_io_sec_level, int *psm, int *mtu) { + if (options & GATTLIB_CONNECTION_OPTIONS_LEGACY_BT_SEC_LOW) { + *bt_io_sec_level = BT_IO_SEC_LOW; + } else if (options & GATTLIB_CONNECTION_OPTIONS_LEGACY_BT_SEC_MEDIUM) { + *bt_io_sec_level = BT_IO_SEC_MEDIUM; + } else if (options & GATTLIB_CONNECTION_OPTIONS_LEGACY_BT_SEC_HIGH) { + *bt_io_sec_level = BT_IO_SEC_HIGH; + } else { + *bt_io_sec_level = BT_IO_SEC_SDP; } + + *psm = GATTLIB_CONNECTION_OPTIONS_LEGACY_GET_PSM(options); + *mtu = GATTLIB_CONNECTION_OPTIONS_LEGACY_GET_MTU(options); } gatt_connection_t *gattlib_connect_async(const char *src, const char *dst, - uint8_t dest_type, gattlib_bt_sec_level_t sec_level, int psm, int mtu, + unsigned long options, gatt_connect_cb_t connect_cb, void* data) { + gatt_connection_t *conn; + BtIOSecLevel bt_io_sec_level; + int psm, mtu; + + // Check parameters + if ((options & (GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_PUBLIC | GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_RANDOM)) == 0) { + // Please, set GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_PUBLIC or + // GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_RANDMON + fprintf(stderr, "gattlib_connect_async() expects address type.\n"); + return NULL; + } + + get_connection_options(options, &bt_io_sec_level, &psm, &mtu); + io_connect_arg_t* io_connect_arg = malloc(sizeof(io_connect_arg_t)); io_connect_arg->user_data = data; - BtIOSecLevel bt_io_sec_level = get_bt_io_sec_level(sec_level); - return initialize_gattlib_connection(src, dst, dest_type, bt_io_sec_level, - psm, mtu, connect_cb, io_connect_arg); + if (options & GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_PUBLIC) { + conn = initialize_gattlib_connection(src, dst, BDADDR_LE_PUBLIC, bt_io_sec_level, + psm, mtu, connect_cb, io_connect_arg); + if (conn != NULL) { + return conn; + } + } + + if (options & GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_RANDOM) { + conn = initialize_gattlib_connection(src, dst, BDADDR_LE_RANDOM, bt_io_sec_level, + psm, mtu, connect_cb, io_connect_arg); + } + + return conn; } static gboolean connection_timeout(gpointer user_data) { @@ -344,20 +369,23 @@ static gboolean connection_timeout(gpointer user_data) { } /** - * @param src Local Adaptater interface - * @param dst Remote Bluetooth address - * @param dst_type Set LE address type (either BDADDR_LE_PUBLIC or BDADDR_LE_RANDOM) - * @param sec_level Set security level (either BT_IO_SEC_LOW, BT_IO_SEC_MEDIUM, BT_IO_SEC_HIGH) - * @param psm Specify the PSM for GATT/ATT over BR/EDR - * @param mtu Specify the MTU size + * @brief Function to connect to a BLE device + * + * @param src Local Adaptater interface + * @param dst Remote Bluetooth address + * @param dst_type Set LE address type (either BDADDR_LE_PUBLIC or BDADDR_LE_RANDOM) + * @param sec_level Set security level (either BT_IO_SEC_LOW, BT_IO_SEC_MEDIUM, BT_IO_SEC_HIGH) + * @param psm Specify the PSM for GATT/ATT over BR/EDR + * @param mtu Specify the MTU size */ -gatt_connection_t *gattlib_connect(const char *src, const char *dst, - uint8_t dest_type, gattlib_bt_sec_level_t sec_level, int psm, int mtu) +static gatt_connection_t *gattlib_connect_with_options(const char *src, const char *dst, + uint8_t dest_type, BtIOSecLevel bt_io_sec_level, int psm, int mtu) { - BtIOSecLevel bt_io_sec_level = get_bt_io_sec_level(sec_level); - io_connect_arg_t io_connect_arg; GSource* timeout; - gatt_connection_t *conn = initialize_gattlib_connection(src, dst, dest_type, bt_io_sec_level, + gatt_connection_t *conn; + io_connect_arg_t io_connect_arg; + + conn = initialize_gattlib_connection(src, dst, dest_type, bt_io_sec_level, psm, mtu, NULL, &io_connect_arg); if (conn == NULL) { if (io_connect_arg.error) { @@ -390,6 +418,44 @@ gatt_connection_t *gattlib_connect(const char *src, const char *dst, } } + +/** + * @brief Function to connect to a BLE device + * + * @param src Local Adaptater interface + * @param dst Remote Bluetooth address + * @param options Options to connect to BLE device. See `GATTLIB_CONNECTION_OPTIONS_*` + */ +gatt_connection_t *gattlib_connect(const char *src, const char *dst, unsigned long options) +{ + gatt_connection_t *conn; + BtIOSecLevel bt_io_sec_level; + int psm, mtu; + + // Check parameters + if ((options & (GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_PUBLIC | GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_RANDOM)) == 0) { + // Please, set GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_PUBLIC or + // GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_RANDMON + fprintf(stderr, "gattlib_connect() expects address type.\n"); + return NULL; + } + + get_connection_options(options, &bt_io_sec_level, &psm, &mtu); + + if (options & GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_PUBLIC) { + conn = gattlib_connect_with_options(src, dst, BDADDR_LE_PUBLIC, bt_io_sec_level, psm, mtu); + if (conn != NULL) { + return conn; + } + } + + if (options & GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_RANDOM) { + conn = gattlib_connect_with_options(src, dst, BDADDR_LE_RANDOM, bt_io_sec_level, psm, mtu); + } + + return conn; +} + int gattlib_disconnect(gatt_connection_t* connection) { gattlib_context_t* conn_context = connection->context; diff --git a/dbus/gattlib.c b/dbus/gattlib.c index cc07bab..f533339 100644 --- a/dbus/gattlib.c +++ b/dbus/gattlib.c @@ -230,8 +230,7 @@ gboolean on_handle_device_property_change( * @param psm Specify the PSM for GATT/ATT over BR/EDR * @param mtu Specify the MTU size */ -gatt_connection_t *gattlib_connect(const char *src, const char *dst, - uint8_t dest_type, gattlib_bt_sec_level_t sec_level, int psm, int mtu) +gatt_connection_t *gattlib_connect(const char *src, const char *dst, unsigned long options) { GError *error = NULL; const char* adapter_name; @@ -326,12 +325,12 @@ FREE_CONNECTION: } gatt_connection_t *gattlib_connect_async(const char *src, const char *dst, - uint8_t dest_type, gattlib_bt_sec_level_t sec_level, int psm, int mtu, + unsigned long options, gatt_connect_cb_t connect_cb, void* data) { gatt_connection_t *connection; - connection = gattlib_connect(src, dst, dest_type, sec_level, psm, mtu); + connection = gattlib_connect(src, dst, options); if ((connection != NULL) && (connect_cb != NULL)) { connect_cb(connection, data); } diff --git a/examples/ble_scan/ble_scan.c b/examples/ble_scan/ble_scan.c index 31aefaf..9f350b5 100644 --- a/examples/ble_scan/ble_scan.c +++ b/examples/ble_scan/ble_scan.c @@ -34,15 +34,10 @@ static void *ble_connect_device(void *arg) { printf("------------START %s ---------------\n", addr); - gatt_connection = gattlib_connect(NULL, addr, BDADDR_LE_PUBLIC, BT_SEC_LOW, 0, 0); + gatt_connection = gattlib_connect(NULL, addr, GATTLIB_CONNECTION_OPTIONS_LEGACY_DEFAULT); if (gatt_connection == NULL) { - gatt_connection = gattlib_connect(NULL, addr, BDADDR_LE_RANDOM, BT_SEC_LOW, 0, 0); - if (gatt_connection == NULL) { - fprintf(stderr, "Fail to connect to the bluetooth device.\n"); - goto connection_exit; - } else { - puts("Succeeded to connect to the bluetooth device with random address."); - } + fprintf(stderr, "Fail to connect to the bluetooth device.\n"); + goto connection_exit; } else { puts("Succeeded to connect to the bluetooth device."); } diff --git a/examples/discover/discover.c b/examples/discover/discover.c index a08e01b..b610bc8 100644 --- a/examples/discover/discover.c +++ b/examples/discover/discover.c @@ -40,7 +40,7 @@ int main(int argc, char *argv[]) return 1; } - connection = gattlib_connect(NULL, argv[1], BDADDR_LE_PUBLIC, BT_SEC_LOW, 0, 0); + connection = gattlib_connect(NULL, argv[1], GATTLIB_CONNECTION_OPTIONS_LEGACY_DEFAULT); if (connection == NULL) { fprintf(stderr, "Fail to connect to the bluetooth device.\n"); return 1; diff --git a/examples/gatttool/gatttool.c b/examples/gatttool/gatttool.c index b03d272..57eab4e 100644 --- a/examples/gatttool/gatttool.c +++ b/examples/gatttool/gatttool.c @@ -484,6 +484,7 @@ int main(int argc, char *argv[]) GOptionGroup *gatt_group, *params_group, *char_rw_group; GError *gerr = NULL; gatt_connection_t *connection; + unsigned long conn_options = 0; BtIOSecLevel sec_level; uint8_t dest_type; @@ -547,9 +548,25 @@ int main(int argc, char *argv[]) } dest_type = get_dest_type_from_str(opt_dst_type); + if (dest_type == BDADDR_LE_PUBLIC) { + conn_options |= GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_PUBLIC; + } else if (dest_type == BDADDR_LE_RANDOM) { + conn_options |= GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_RANDOM; + } + sec_level = get_sec_level_from_str(opt_sec_level); - connection = gattlib_connect_async(opt_src, opt_dst, dest_type, sec_level, - opt_psm, opt_mtu, connect_cb, NULL); + if (sec_level == BT_IO_SEC_LOW) { + conn_options |= GATTLIB_CONNECTION_OPTIONS_LEGACY_BT_SEC_LOW; + } else if (sec_level == BT_IO_SEC_MEDIUM) { + conn_options |= GATTLIB_CONNECTION_OPTIONS_LEGACY_BT_SEC_MEDIUM; + } else if (sec_level == BT_IO_SEC_HIGH) { + conn_options |= GATTLIB_CONNECTION_OPTIONS_LEGACY_BT_SEC_HIGH; + } + + conn_options |= GATTLIB_CONNECTION_OPTIONS_LEGACY_PSM(opt_psm); + conn_options |= GATTLIB_CONNECTION_OPTIONS_LEGACY_PSM(opt_mtu); + + connection = gattlib_connect_async(opt_src, opt_dst, conn_options, connect_cb, NULL); if (connection == NULL) { got_error = TRUE; goto done; diff --git a/examples/gatttool/interactive.c b/examples/gatttool/interactive.c index 49d697d..aefcf1c 100644 --- a/examples/gatttool/interactive.c +++ b/examples/gatttool/interactive.c @@ -277,6 +277,7 @@ static gboolean channel_watcher(GIOChannel *chan, GIOCondition cond, static void cmd_connect(int argcp, char **argvp) { gatt_connection_t *connection; + unsigned long conn_options = 0; BtIOSecLevel sec_level; uint8_t dst_type; @@ -302,9 +303,25 @@ static void cmd_connect(int argcp, char **argvp) set_state(STATE_CONNECTING); dst_type = get_dest_type_from_str(opt_dst_type); + if (dst_type == BDADDR_LE_PUBLIC) { + conn_options |= GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_PUBLIC; + } else if (dst_type == BDADDR_LE_RANDOM) { + conn_options |= GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_RANDOM; + } + sec_level = get_sec_level_from_str(opt_sec_level); - connection = gattlib_connect_async(opt_src, opt_dst, dst_type, sec_level, - opt_psm, opt_mtu, connect_cb, NULL); + if (sec_level == BT_IO_SEC_LOW) { + conn_options |= GATTLIB_CONNECTION_OPTIONS_LEGACY_BT_SEC_LOW; + } else if (sec_level == BT_IO_SEC_MEDIUM) { + conn_options |= GATTLIB_CONNECTION_OPTIONS_LEGACY_BT_SEC_MEDIUM; + } else if (sec_level == BT_IO_SEC_HIGH) { + conn_options |= GATTLIB_CONNECTION_OPTIONS_LEGACY_BT_SEC_HIGH; + } + + conn_options |= GATTLIB_CONNECTION_OPTIONS_LEGACY_PSM(opt_psm); + conn_options |= GATTLIB_CONNECTION_OPTIONS_LEGACY_PSM(opt_mtu); + + connection = gattlib_connect_async(opt_src, opt_dst, conn_options, connect_cb, NULL); if (connection == NULL) { set_state(STATE_DISCONNECTED); } else { diff --git a/examples/nordic_uart/nordic_uart.c b/examples/nordic_uart/nordic_uart.c index 9702b62..2fc4a00 100644 --- a/examples/nordic_uart/nordic_uart.c +++ b/examples/nordic_uart/nordic_uart.c @@ -63,7 +63,9 @@ int main(int argc, char *argv[]) { return 1; } - m_connection = gattlib_connect(NULL, argv[1], BDADDR_LE_RANDOM, BT_SEC_LOW, 0, 0); + m_connection = gattlib_connect(NULL, argv[1], + GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_RANDOM | + GATTLIB_CONNECTION_OPTIONS_LEGACY_BT_SEC_LOW); if (m_connection == NULL) { fprintf(stderr, "Fail to connect to the bluetooth device.\n"); return 1; diff --git a/examples/notification/notification.c b/examples/notification/notification.c index 9c6307a..c68b49a 100644 --- a/examples/notification/notification.c +++ b/examples/notification/notification.c @@ -62,7 +62,7 @@ int main(int argc, char *argv[]) { return 1; } - connection = gattlib_connect(NULL, argv[1], BDADDR_LE_PUBLIC, BT_SEC_LOW, 0, 0); + connection = gattlib_connect(NULL, argv[1], GATTLIB_CONNECTION_OPTIONS_LEGACY_DEFAULT); if (connection == NULL) { fprintf(stderr, "Fail to connect to the bluetooth device.\n"); return 1; diff --git a/examples/read_write/read_write.c b/examples/read_write/read_write.c index 8e4f21e..cdaf659 100644 --- a/examples/read_write/read_write.c +++ b/examples/read_write/read_write.c @@ -69,7 +69,7 @@ int main(int argc, char *argv[]) { return 1; } - connection = gattlib_connect(NULL, argv[1], BDADDR_LE_PUBLIC, BT_SEC_LOW, 0, 0); + connection = gattlib_connect(NULL, argv[1], GATTLIB_CONNECTION_OPTIONS_LEGACY_DEFAULT); if (connection == NULL) { fprintf(stderr, "Fail to connect to the bluetooth device.\n"); return 1; diff --git a/include/gattlib.h b/include/gattlib.h index fdb9478..a85af66 100644 --- a/include/gattlib.h +++ b/include/gattlib.h @@ -58,12 +58,27 @@ extern "C" { #define CREATE_UUID16(value16) { .type=SDP_UUID16, .value.uuid16=(value16) } -typedef enum { - BT_SEC_SDP = 0, - BT_SEC_LOW, - BT_SEC_MEDIUM, - BT_SEC_HIGH, -} gattlib_bt_sec_level_t; +// +// @brief Options for gattlib_connect() +// +// @note Options with the prefix `GATTLIB_CONNECTION_OPTIONS_LEGACY_` +// is for Bluez prior to v5.42 (before Bluez) support +// +#define GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_PUBLIC (1 << 0) +#define GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_RANDOM (1 << 1) +#define GATTLIB_CONNECTION_OPTIONS_LEGACY_BT_SEC_LOW (1 << 2) +#define GATTLIB_CONNECTION_OPTIONS_LEGACY_BT_SEC_MEDIUM (1 << 3) +#define GATTLIB_CONNECTION_OPTIONS_LEGACY_BT_SEC_HIGH (1 << 4) +#define GATTLIB_CONNECTION_OPTIONS_LEGACY_PSM(value) (((value) & 0x3FF) << 11) //< We encode PSM on 10 bits (up to 1023) +#define GATTLIB_CONNECTION_OPTIONS_LEGACY_MTU(value) (((value) & 0x3FF) << 21) //< We encode MTU on 10 bits (up to 1023) + +#define GATTLIB_CONNECTION_OPTIONS_LEGACY_GET_PSM(options) (((options) >> 11) && 0x3FF) +#define GATTLIB_CONNECTION_OPTIONS_LEGACY_GET_MTU(options) (((options) >> 21) && 0x3FF) + +#define GATTLIB_CONNECTION_OPTIONS_LEGACY_DEFAULT \ + GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_PUBLIC | \ + GATTLIB_CONNECTION_OPTIONS_LEGACY_BDADDR_LE_RANDOM | \ + GATTLIB_CONNECTION_OPTIONS_LEGACY_BT_SEC_LOW typedef struct _GAttrib GAttrib; @@ -105,18 +120,25 @@ int gattlib_adapter_scan_disable(void* adapter); int gattlib_adapter_close(void* adapter); /** + * @brief Function to connect to a BLE device + * * @param src Local Adaptater interface * @param dst Remote Bluetooth address - * @param dst_type Set LE address type (either BDADDR_LE_PUBLIC or BDADDR_LE_RANDOM) - * @param sec_level Set security level (either BT_IO_SEC_LOW, BT_IO_SEC_MEDIUM, BT_IO_SEC_HIGH) - * @param psm Specify the PSM for GATT/ATT over BR/EDR - * @param mtu Specify the MTU size + * @param options Options to connect to BLE device. See `GATTLIB_CONNECTION_OPTIONS_*` */ -gatt_connection_t *gattlib_connect(const char *src, const char *dst, - uint8_t dest_type, gattlib_bt_sec_level_t sec_level, int psm, int mtu); +gatt_connection_t *gattlib_connect(const char *src, const char *dst, unsigned long options); +/** + * @brief Function to asynchronously connect to a BLE device + * + * @note This function is mainly used before Bluez v5.42 (prior to D-BUS support) + * + * @param src Local Adaptater interface + * @param dst Remote Bluetooth address + * @param options Options to connect to BLE device. See `GATTLIB_CONNECTION_OPTIONS_*` + */ gatt_connection_t *gattlib_connect_async(const char *src, const char *dst, - uint8_t dest_type, gattlib_bt_sec_level_t sec_level, int psm, int mtu, + unsigned long options, gatt_connect_cb_t connect_cb, void* data); int gattlib_disconnect(gatt_connection_t* connection);