From a399864284077d907d9a6e67e796a12e11798b73 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Wed, 16 Sep 2015 16:34:53 +0530 Subject: [PATCH] Added code for LE Data length extension feature. Change-Id: I7c7cd8760935b378aa6f7e578ca27ddb1ba40176 Signed-off-by: Sudha Bheemanna --- lib/hci.c | 133 +++++++++++++++++- lib/hci.h | 46 ++++++ lib/mgmt.h | 39 ++++++ src/adapter.c | 439 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/adapter.h | 30 ++++ src/device.c | 77 ++++++++++ 6 files changed, 762 insertions(+), 2 deletions(-) mode change 100644 => 100755 lib/hci.c mode change 100644 => 100755 lib/hci.h mode change 100644 => 100755 lib/mgmt.h mode change 100644 => 100755 src/adapter.c mode change 100644 => 100755 src/adapter.h mode change 100644 => 100755 src/device.c diff --git a/lib/hci.c b/lib/hci.c old mode 100644 new mode 100755 index bc453f7..7fd251f --- a/lib/hci.c +++ b/lib/hci.c @@ -592,7 +592,8 @@ static hci_map commands_map[] = { { "LE Receiver Test", 228 }, { "LE Transmitter Test", 229 }, { "LE Test End", 230 }, - { "Reserved", 231 }, + { "LE Read Maximum Data Length", 231 }, + { "Reserved", 232 }, { NULL } }; @@ -3117,3 +3118,133 @@ int hci_le_read_remote_features(int dd, uint16_t handle, uint8_t *features, int return 0; } + +#ifdef __TIZEN_PATCH__ +int hci_le_read_maximum_data_length( + int dd, uint8_t *status, uint16_t *tx_octets, + uint16_t *tx_time, uint16_t *rx_octets, + uint16_t *rx_time, int to) +{ + le_read_maximum_data_length_rp rp; + struct hci_request rq; + + memset(&rq, 0, sizeof(rq)); + memset(&rp, 0, sizeof(rp)); + + rq.ogf = OGF_LE_CTL; + rq.ocf = OCF_LE_READ_MAXIMUM_DATA_LENGTH; + rq.rparam = &rp; + rq.rlen = LE_READ_MAXIMUM_DATA_LENGTH_SIZE; + + if (hci_send_req(dd, &rq, to) < 0) + return -1; + + if (rp.status) { + errno = EIO; + return -1; + } + + *tx_octets = rp.max_tx_octets; + *tx_time = rp.max_tx_time; + *rx_octets = rp.max_rx_octets; + *rx_time = rp.max_rx_time; + *status = rp.status; + return 0; +} + +int hci_le_write_host_suggested_data_length( + int dd, uint16_t *def_tx_octets, + uint16_t *def_tx_time, int to) +{ + le_write_host_suggested_data_length_cp cp; + struct hci_request rq; + uint8_t status; + + memset(&cp, 0, sizeof(cp)); + cp.def_tx_octets = def_tx_octets; + cp.def_tx_time = def_tx_time; + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_LE_CTL; + rq.ocf = OCF_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH; + rq.cparam = &cp; + rq.clen = LE_WRITE_HOST_SUGGESTED_DATA_LENGTH_CP_SIZE; + rq.rparam = &status; + rq.rlen = 1; + + if (hci_send_req(dd, &rq, to) < 0) + return -1; + + if (status) { + errno = EIO; + return -1; + } + + return 0; +} + +int hci_le_read_host_suggested_data_length( + int dd, uint8_t *status, uint16_t *def_tx_octets, + uint16_t *def_tx_time, int to) +{ + le_read_host_suggested_data_length_rp rp; + struct hci_request rq; + + memset(&rp, 0, sizeof(rp)); + memset(&rq, 0, sizeof(rq)); + + rq.ogf = OGF_LE_CTL; + rq.ocf = OCF_LE_READ_HOST_SUGGESTED_DATA_LENGTH; + rq.rparam = &rp; + rq.rlen = LE_READ_HOST_SUGGESTED_DATA_LENGTH_SIZE; + + if (hci_send_req(dd, &rq, to) < 0) + return -1; + + if (rp.status) { + errno = EIO; + return -1; + } + + *def_tx_octets = rp.def_tx_octets; + *def_tx_time = rp.def_tx_time; + *status = rp.status; + return 0; +} + +int hci_le_set_data_length( + int dd, const bdaddr_t *bdaddr, uint16_t *max_tx_octets, + uint16_t *max_tx_time, int to) +{ + le_set_data_length_cp cp; + le_set_data_length_rp rp; + struct hci_request rq; + uint8_t status; + + memset(&cp, 0, sizeof(cp)); + memset(&rp, 0, sizeof(rp)); + + bacpy(&cp.bdaddr, bdaddr); + cp.max_tx_octets = max_tx_octets; + cp.max_tx_time = max_tx_time; + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_LE_CTL; + rq.ocf = OCF_LE_SET_DATA_LENGTH; + rq.cparam = &cp; + rq.clen = LE_SET_DATA_LENGTH_CP_SIZE; + rq.rparam = &rp; + rq.rlen = LE_SET_DATA_LENGTH_RP_SIZE; + + if (hci_send_req(dd, &rq, to) < 0) + return -1; + + if (rp.status) { + errno = EIO; + return -1; + } + + return 0; +} + +#endif diff --git a/lib/hci.h b/lib/hci.h old mode 100644 new mode 100755 index 8f524ff..ae7be46 --- a/lib/hci.h +++ b/lib/hci.h @@ -1710,6 +1710,52 @@ typedef struct { } __attribute__ ((packed)) le_test_end_rp; #define LE_TEST_END_RP_SIZE 3 +#ifdef __TIZEN_PATCH__ +#define OCF_LE_READ_MAXIMUM_DATA_LENGTH 0x002F +typedef struct { + uint8_t status; + uint16_t max_tx_octets; + uint16_t max_tx_time; + uint16_t max_rx_octets; + uint16_t max_rx_time; +} __attribute__ ((packed)) +le_read_maximum_data_length_rp; +#define LE_READ_MAXIMUM_DATA_LENGTH_SIZE 9 + +#define OCF_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH 0x0030 +typedef struct { + uint16_t def_tx_octets; + uint16_t def_tx_time; +} __attribute__ ((packed)) +le_write_host_suggested_data_length_cp; +#define LE_WRITE_HOST_SUGGESTED_DATA_LENGTH_CP_SIZE 4 + +#define OCF_LE_READ_HOST_SUGGESTED_DATA_LENGTH 0x0024 +typedef struct { + uint8_t status; + uint16_t def_tx_octets; + uint16_t def_tx_time; +} __attribute__ ((packed)) +le_read_host_suggested_data_length_rp; +#define LE_READ_HOST_SUGGESTED_DATA_LENGTH_SIZE 5 + +#define OCF_LE_SET_DATA_LENGTH 0x0022 +typedef struct { + bdaddr_t bdaddr; + uint16_t max_tx_octets; + uint16_t max_tx_time; +} __attribute__ ((packed)) +le_set_data_length_cp; +#define LE_SET_DATA_LENGTH_CP_SIZE 10 + +typedef struct { + uint16_t handle; + uint8_t status; +} __attribute__ ((packed)) +le_set_data_length_rp; +#define LE_SET_DATA_LENGTH_RP_SIZE 3 +#endif + #define OCF_LE_ADD_DEVICE_TO_RESOLV_LIST 0x0027 typedef struct { uint8_t bdaddr_type; diff --git a/lib/mgmt.h b/lib/mgmt.h old mode 100644 new mode 100755 index 6a8f603..6bec10e --- a/lib/mgmt.h +++ b/lib/mgmt.h @@ -908,6 +908,36 @@ struct mgmt_cp_disconnect_6lowpan { struct mgmt_addr_info addr; } __packed; +#define MGMT_OP_LE_READ_MAXIMUM_DATA_LENGTH (TIZEN_OP_CODE_BASE + 0x15) +struct mgmt_rp_le_read_maximum_data_length { + uint8_t status; + uint16_t max_tx_octets; + uint16_t max_tx_time; + uint16_t max_rx_octets; + uint16_t max_rx_time; +} __packed; + +#define MGMT_OP_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH (TIZEN_OP_CODE_BASE + 0x16) +struct mgmt_cp_le_write_host_suggested_data_length { + uint16_t def_tx_octets; + uint16_t def_tx_time; +} __packed; + +#define MGMT_OP_LE_READ_HOST_SUGGESTED_DATA_LENGTH (TIZEN_OP_CODE_BASE + 0x17) +struct mgmt_rp_le_read_host_suggested_data_length { + uint8_t status; + uint16_t def_tx_octets; + uint16_t def_tx_time; +} __packed; + +#define MGMT_OP_LE_SET_DATA_LENGTH (TIZEN_OP_CODE_BASE + 0x18) +struct mgmt_cp_le_set_data_length { + bdaddr_t bdaddr; + uint16_t max_tx_octets; + uint16_t max_tx_time; +} __packed; +#define MGMT_LE_SET_DATA_LENGTH_SIZE 10 + /* Currently there is no support in kernel for below MGMT cmd opcodes. */ #if 0 // Not defined in kernel #define MGMT_OP_READ_RSSI (TIZEN_OP_CODE_BASE + 0x11) @@ -1039,6 +1069,15 @@ struct mgmt_ev_6lowpan_conn_state_changed { uint8_t connected; } __packed; +#define MGMT_EV_LE_DATA_LENGTH_CHANGED (TIZEN_EV_BASE + 0x0d) +struct mgmt_ev_le_data_length_changed { + struct mgmt_addr_info addr; + int16_t max_tx_octets; + int16_t max_tx_time; + int16_t max_rx_octets; + int16_t max_rx_time; +} __packed; + /* Currently there is no support in kernel for below MGMT events. */ #if 0 // Not defined in kernel #define MGMT_EV_NEW_LOCAL_IRK (TIZEN_EV_BASE + 0x0b) diff --git a/src/adapter.c b/src/adapter.c old mode 100644 new mode 100755 index d0af889..1e55b6a --- a/src/adapter.c +++ b/src/adapter.c @@ -194,6 +194,16 @@ struct adv_info { int slot_id; /* Reservied slot id is 0 (Single adv) */ bool status; /* Advertising status */ }; + +static GSList *read_requests = NULL; + +struct le_data_length_read_request { + struct btd_adapter *adapter; + DBusMessage *msg; +}; + +static GSList *read_host_requests = NULL; + #endif struct btd_adapter { @@ -230,6 +240,8 @@ struct btd_adapter { #ifdef IPSP_SUPPORT bool ipsp_intialized; /* Ipsp Initialization state */ #endif + struct le_data_length_read_handler *read_handler; + struct le_data_length_read_default_data_length_handler *def_read_handler; #endif bool discovering; /* discovering property state */ @@ -3666,6 +3678,384 @@ static DBusMessage *set_nb_parameters(DBusConnection *conn, return dbus_message_new_method_return(msg); } +#endif /* __BROADCOM_PATCH__ */ + +#ifdef __TIZEN_PATCH__ +void btd_adapter_set_read_le_data_length_handler( + struct btd_adapter *adapter, + struct le_data_length_read_handler *handler) +{ + adapter->read_handler = handler; +} + +static void le_read_maximum_data_length_return_param_complete( + uint8_t status, uint16_t length, + const void *param, void *user_data) +{ + struct btd_adapter *adapter = user_data; + const struct mgmt_rp_le_read_maximum_data_length *rp = param; + uint16_t max_tx_octects, max_tx_time; + uint16_t max_rx_octects, max_rx_time; + int32_t err; + + if (status != MGMT_STATUS_SUCCESS) { + error("le read maximum data length failed: %s (0x%02x)", + mgmt_errstr(status), status); + max_tx_octects = 0; + max_tx_time =0; + max_rx_octects = 0; + max_rx_time = 0; + err = -EIO; + } + + if (length < sizeof(*rp)) { + error("Too small le read maximum data length response"); + max_tx_octects = 0; + max_tx_time =0; + max_rx_octects = 0; + max_rx_time = 0; + err = -EIO; + } else { + max_tx_octects = rp->max_tx_octets; + max_tx_time =rp->max_tx_time; + max_rx_octects = rp->max_rx_octets; + max_rx_time = rp->max_rx_time; + err = 0; + } + + if (!adapter->read_handler || + !adapter->read_handler->read_callback) { + g_free(adapter->read_handler); + return; + } + + adapter->read_handler->read_callback(adapter, + max_tx_octects, max_tx_time, + max_rx_octects, max_rx_time, + err, adapter->read_handler->user_data); + + g_free(adapter->read_handler); + adapter->read_handler = NULL; +} + +int btd_adapter_le_read_maximum_data_length( + struct btd_adapter *adapter) +{ + if (mgmt_send(adapter->mgmt, + MGMT_OP_LE_READ_MAXIMUM_DATA_LENGTH, + adapter->dev_id, 0, NULL, + le_read_maximum_data_length_return_param_complete, + adapter, NULL) > 0) + return 0; + + return -EIO; +} + +static gint read_request_cmp(gconstpointer a, gconstpointer b) +{ + const struct le_data_length_read_request *data = a; + const struct btd_adapter *adapter = b; + + return data->adapter != adapter; +} + +static struct le_data_length_read_request *find_read_le_data_length_request( + struct btd_adapter *adapter) +{ + GSList *match; + + match = g_slist_find_custom(read_requests, adapter, read_request_cmp); + + if (match) + return match->data; + + return NULL; +} + +static void le_read_data_length_complete( + struct btd_adapter *adapter, + uint16_t max_tx_octects, uint16_t max_tx_time, + uint16_t max_rx_octects, uint16_t max_rx_time, + int32_t err, void *user_data) +{ + DBusMessage *reply; + struct le_data_length_read_request *read_request; + + DBG("inside le_read_data_length_complete"); + + read_request = find_read_le_data_length_request(adapter); + if (!read_request) + return; + + reply = g_dbus_create_reply(read_request->msg, + DBUS_TYPE_UINT16, &max_tx_octects, + DBUS_TYPE_UINT16, &max_tx_time, + DBUS_TYPE_UINT16, &max_rx_octects, + DBUS_TYPE_UINT16, &max_rx_time, + DBUS_TYPE_INT32, &err, + DBUS_TYPE_INVALID); + + if (!reply) { + btd_error_failed(read_request->msg, + "Failed to read max data length."); + return; + } + + read_requests = g_slist_remove(read_requests, read_request); + dbus_message_unref(read_request->msg); + g_free(read_request); + + if (!g_dbus_send_message(dbus_conn, reply)) + error("D-Bus send failed"); +} + +static DBusMessage *le_read_maximum_data_length( + DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + struct btd_adapter *adapter = user_data; + struct le_data_length_read_request *read_request; + struct le_data_length_read_handler *handler; + + if (find_read_le_data_length_request(adapter)) + return btd_error_in_progress(msg); + + if (btd_adapter_le_read_maximum_data_length(adapter)) + return btd_error_failed(msg, "Unable to read maximum le data length"); + + read_request = g_new(struct le_data_length_read_request, 1); + + read_request->msg = dbus_message_ref(msg); + read_request->adapter = adapter; + + read_requests = g_slist_append(read_requests, read_request); + + handler = g_new0(struct le_data_length_read_handler, 1); + + handler->read_callback = + (read_max_data_length_cb_t)le_read_data_length_complete; + + btd_adapter_set_read_le_data_length_handler( + read_request->adapter, handler); + + return NULL; + +} + +void le_write_host_suggested_data_length_return_param_complete( + uint8_t status, uint16_t length, + const void *param, void *user_data) +{ + if (status != MGMT_STATUS_SUCCESS) { + error("le write host suggested data length failed: %s (0x%02x)", + mgmt_errstr(status), status); + } + + return; +} + +static DBusMessage *le_write_host_suggested_default_data_length( + DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + struct btd_adapter *adapter = user_data; + struct mgmt_cp_le_write_host_suggested_data_length cp; + dbus_uint16_t def_tx_Octets; + dbus_uint16_t def_tx_time; + + if (!(adapter->current_settings & MGMT_SETTING_POWERED)) + return btd_error_not_ready(msg); + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_UINT16, &def_tx_Octets, + DBUS_TYPE_UINT16, &def_tx_time, + DBUS_TYPE_INVALID)) + return btd_error_invalid_args(msg); + + memset(&cp, 0, sizeof(cp)); + cp.def_tx_octets = def_tx_Octets; + cp.def_tx_time = def_tx_time; + + if (mgmt_send(adapter->mgmt, + MGMT_OP_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH, + adapter->dev_id, sizeof(cp), &cp, + le_write_host_suggested_data_length_return_param_complete, + adapter, NULL) > 0) + return dbus_message_new_method_return(msg); + + return btd_error_failed(msg, "Unable to write host suggested le data length values"); +} + +static void le_read_suggested_default_data_length_return_param_complete( + uint8_t status, uint16_t length, + const void *param, void *user_data) +{ + struct btd_adapter *adapter = user_data; + const struct mgmt_rp_le_read_host_suggested_data_length *rp = param; + uint16_t def_tx_octects, def_tx_time; + int32_t err; + + if (status != MGMT_STATUS_SUCCESS) { + error("Read host suggested def le data length values failed: %s (0x%02x)", + mgmt_errstr(status), status); + def_tx_octects = 0; + def_tx_time =0; + err = -EIO; + } + + if (length < sizeof(*rp)) { + DBG("Too small le read host data length response"); + err = -EIO; + } else { + def_tx_octects = rp->def_tx_octets; + def_tx_time =rp->def_tx_time; + err = 0; + DBG("retrieving host suggested data length values %d %d", def_tx_octects, def_tx_time); + } + + if (!adapter->def_read_handler) + return; + + if(!adapter->def_read_handler->read_callback) { + goto done; + } + + adapter->def_read_handler->read_callback(adapter, + def_tx_octects, def_tx_time, + err, adapter->def_read_handler->user_data); +done: + if (adapter->def_read_handler) + g_free(adapter->def_read_handler->user_data); + + g_free(adapter->def_read_handler); + adapter->def_read_handler = NULL; +} + +int btd_adapter_le_read_suggested_default_data_length( + struct btd_adapter *adapter) +{ + if (mgmt_send(adapter->mgmt, + MGMT_OP_LE_READ_HOST_SUGGESTED_DATA_LENGTH, + adapter->dev_id, 0, NULL, + le_read_suggested_default_data_length_return_param_complete, + adapter, NULL) > 0) { + return 0; + } + + return -EIO; +} + +static struct le_data_length_read_request *find_read_le_host_data_length_request( + struct btd_adapter *adapter) +{ + GSList *match; + + match = g_slist_find_custom(read_host_requests, adapter, read_request_cmp); + + if (match) + return match->data; + + return NULL; +} + +static void le_read_host_suggested_default_length_complete( + struct btd_adapter *adapter, + uint16_t def_tx_octects, uint16_t def_tx_time, + int32_t err, void *user_data) +{ + DBusMessage *reply; + struct le_data_length_read_request *read_request; + + read_request = find_read_le_host_data_length_request(adapter); + if (!read_request) + return; + + reply = g_dbus_create_reply(read_request->msg, + DBUS_TYPE_UINT16, &def_tx_octects, + DBUS_TYPE_UINT16, &def_tx_time, + DBUS_TYPE_INT32, &err, + DBUS_TYPE_INVALID); + + if (!reply) { + btd_error_failed(read_request->msg, + "Failed to read host suggested def data length values"); + return; + } + + read_host_requests = g_slist_remove(read_host_requests, read_request); + dbus_message_unref(read_request->msg); + g_free(read_request); + + if (!g_dbus_send_message(dbus_conn, reply)) + error("D-Bus send failed"); +} + +static DBusMessage *le_read_host_suggested_default_data_length( + DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + struct btd_adapter *adapter = user_data; + struct le_data_length_read_request *read_request; + struct le_data_length_read_default_data_length_handler *handler; + + if (find_read_le_host_data_length_request(adapter)) + return btd_error_in_progress(msg); + + if (btd_adapter_le_read_suggested_default_data_length(adapter)) + return btd_error_failed(msg, "Unable to read host suggested def data length"); + + read_request = g_new(struct le_data_length_read_request, 1); + + read_request->msg = dbus_message_ref(msg); + read_request->adapter = adapter; + + read_host_requests = g_slist_append(read_host_requests, read_request); + + handler = g_new0(struct le_data_length_read_default_data_length_handler, 1); + + handler->read_callback = + (read_host_suggested_default_data_length_cb_t)le_read_host_suggested_default_length_complete; + + read_request->adapter->def_read_handler = handler; + + return NULL; +} + +void le_set_data_length_return_param_complete( + uint8_t status, uint16_t length, + const void *param, void *user_data) +{ + if (status != MGMT_STATUS_SUCCESS) { + error("le_set_data_length failed: %s (0x%02x)", + mgmt_errstr(status), status); + } + + return; +} + +int btd_adapter_le_set_data_length(struct btd_adapter *adapter, bdaddr_t *bdaddr, + uint16_t max_tx_octets, uint16_t max_tx_time) +{ + struct mgmt_cp_le_set_data_length cp; + + memset(&cp, 0, sizeof(cp)); + + bacpy(&cp.bdaddr, bdaddr); + + cp.max_tx_octets = max_tx_octets; + cp.max_tx_time = max_tx_time; + + if (mgmt_send(adapter->mgmt, MGMT_OP_LE_SET_DATA_LENGTH, + adapter->dev_id, sizeof(cp), &cp, + le_set_data_length_return_param_complete, + adapter, NULL) > 0) + return 0; + + return -EIO; +} + +#endif + static DBusMessage *adapter_set_manufacturer_data(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -3696,7 +4086,6 @@ static DBusMessage *adapter_set_manufacturer_data(DBusConnection *conn, return btd_error_failed(msg, "Set manufacturer data failed"); } -#endif /* __BROADCOM_PATCH__ */ #endif /* __TIZEN_PATCH__ */ static DBusMessage *stop_discovery(DBusConnection *conn, @@ -4787,6 +5176,20 @@ static const GDBusMethodTable adapter_methods[] = { #endif { GDBUS_ASYNC_METHOD("RemoveDevice", GDBUS_ARGS({ "device", "o" }), NULL, remove_device) }, +#ifdef __TIZEN_PATCH__ + { GDBUS_ASYNC_METHOD("LEReadMaximumDataLength", NULL, + GDBUS_ARGS({"maxTxOctets", "q" }, { "maxTxTime", "q" }, + {"maxRxOctets", "q" }, { "maxRxTime", "q" }, + { "read_error", "i" }), + le_read_maximum_data_length)}, + { GDBUS_ASYNC_METHOD("LEWriteHostSuggestedDataLength", + GDBUS_ARGS({"def_tx_octets", "q" }, { "def_tx_time", "q" }), NULL, + le_write_host_suggested_default_data_length)}, + { GDBUS_ASYNC_METHOD("LEReadHostSuggestedDataLength", NULL, + GDBUS_ARGS({"def_tx_octets", "q" }, { "def_tx_time", "q" }, + { "read_error", "i" }), + le_read_host_suggested_default_data_length)}, +#endif { } }; @@ -8530,6 +8933,35 @@ static void bt_6lowpan_conn_state_change_callback(uint16_t index, uint16_t lengt device_set_ipsp_connected(device, connected); #endif } + +static void bt_le_data_length_changed_callback(uint16_t index, uint16_t length, + const void *param, void *user_data) +{ + const struct mgmt_ev_le_data_length_changed *ev = param; + struct btd_adapter *adapter = user_data; + struct btd_device *device; + char addr[18]; + + if (length < sizeof(*ev)) { + error("Too small data length changed event"); + return; + } + + ba2str(&ev->addr.bdaddr, addr); + + DBG("hci%u device %s", index, addr); + + device = btd_adapter_find_device(adapter, &ev->addr.bdaddr, + ev->addr.type); + if (!device) { + error("Unable to get device object for %s", addr); + return; + } + + device_le_data_length_changed(device, ev->max_tx_octets, ev->max_tx_time, + ev->max_rx_octets, ev->max_rx_time); +} + #endif struct btd_adapter_pin_cb_iter *btd_adapter_pin_cb_iter_new( @@ -10404,6 +10836,11 @@ static void read_info_complete(uint8_t status, uint16_t length, adapter->dev_id, bt_6lowpan_conn_state_change_callback, adapter, NULL); + + mgmt_register(adapter->mgmt, MGMT_EV_LE_DATA_LENGTH_CHANGED, + adapter->dev_id, + bt_le_data_length_changed_callback, + adapter, NULL); #endif set_dev_class(adapter); diff --git a/src/adapter.h b/src/adapter.h old mode 100644 new mode 100755 index 5e87c59..afa649f --- a/src/adapter.h +++ b/src/adapter.h @@ -275,4 +275,34 @@ int btd_adapter_disconnect_ipsp(struct btd_adapter *adapter, const bdaddr_t *bdaddr, uint8_t bdaddr_type); #endif + +typedef void (*read_max_data_length_cb_t) (struct btd_adapter *adapter, + uint16_t max_txOctects, + uint16_t max_txTime, + uint16_t max_rxOctects, + uint16_t max_rxTime, + int32_t read_error, + void *user_data); + +struct le_data_length_read_handler { + read_max_data_length_cb_t read_callback; + void *user_data; +}; + +typedef void (*read_host_suggested_default_data_length_cb_t) (struct btd_adapter *adapter, + uint16_t def_txOctects, + uint16_t def_txTime, + int32_t read_error, + void *user_data); + +struct le_data_length_read_default_data_length_handler { + read_host_suggested_default_data_length_cb_t read_callback; + void *user_data; +}; + +int btd_adapter_le_set_data_length(struct btd_adapter *adapter, bdaddr_t *bdaddr, + uint16_t max_tx_octets, uint16_t max_tx_time); +void device_le_data_length_changed(struct btd_device *device, uint16_t max_tx_octets, + uint16_t max_tx_time, uint16_t max_rx_octets, uint16_t max_rx_time); + #endif diff --git a/src/device.c b/src/device.c old mode 100644 new mode 100755 index bd89163..cf479ed --- a/src/device.c +++ b/src/device.c @@ -313,6 +313,10 @@ struct btd_device { #ifdef IPSP_SUPPORT gboolean ipsp_connected; /* IPSP Connection state */ #endif + uint16_t max_tx_octets; + uint16_t max_tx_time; + uint16_t max_rx_octets; + uint16_t max_rx_time; #endif }; @@ -3010,6 +3014,45 @@ static DBusMessage *disconnect_ipsp(DBusConnection *conn, DBusMessage *msg, } #endif +#ifdef __TIZEN_PATCH__ +static DBusMessage *le_set_data_length( + DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + dbus_uint16_t max_tx_octets; + dbus_uint16_t max_tx_time; + struct btd_device *device = user_data; + int status; + char addr[BT_ADDRESS_STRING_SIZE]; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_UINT16, &max_tx_octets, + DBUS_TYPE_UINT16, &max_tx_time, + DBUS_TYPE_INVALID)) { + DBG("error in retrieving values"); + return btd_error_invalid_args(msg); + } + + if (device->bdaddr_type == BDADDR_BREDR) + return btd_error_not_supported(msg); + + ba2str(&device->bdaddr, addr); + + DBG("Remote device address: %s", addr); + DBG("Max tx octets: %u, Max tx time: %u", + max_tx_octets, max_tx_time); + + status = btd_adapter_le_set_data_length(device->adapter, + &device->bdaddr, max_tx_octets, + max_tx_time); + + if (status != 0) + return btd_error_failed(msg, "Unable to set le data length values"); + else + return dbus_message_new_method_return(msg); +} +#endif + static DBusMessage *is_connected_profile(DBusConnection *conn, DBusMessage *msg, void *user_data) { @@ -3142,6 +3185,10 @@ static const GDBusMethodTable device_methods[] = { { GDBUS_ASYNC_METHOD("ConnectIpsp", NULL, NULL, connect_ipsp) }, { GDBUS_ASYNC_METHOD("DisconnectIpsp", NULL, NULL, disconnect_ipsp) }, #endif + { GDBUS_ASYNC_METHOD("LESetDataLength", + GDBUS_ARGS({"max_tx_octets", "q" }, + { "max_tx_time", "q" }), NULL, + le_set_data_length)}, #endif { } }; @@ -3206,6 +3253,11 @@ static const GDBusSignalTable device_signals[] = { { "RSSI", "i"}, { "AdvDataLen", "i"}, { "AdvData", "ay"})) }, + { GDBUS_SIGNAL("LEDataLengthChanged", + GDBUS_ARGS({"max_tx_octets","q"}, + { "max_tx_time", "q" }, + { "max_rx_octets", "q"}, + { "max_rx_time", "q"})) }, }; #endif @@ -5742,6 +5794,31 @@ void device_set_ipsp_connected(struct btd_device *device, gboolean connected) DEVICE_INTERFACE, "IpspConnected"); } #endif + +void device_le_data_length_changed(struct btd_device *device, uint16_t max_tx_octets, + uint16_t max_tx_time, uint16_t max_rx_octets, uint16_t max_rx_time) +{ + if (device == NULL) { + error("device is NULL"); + return; + } + + device->max_tx_octets = max_tx_octets; + device->max_tx_time = max_tx_time; + device->max_rx_octets = max_rx_octets; + device->max_rx_time = max_rx_time; + + DBG("data length changed values :max_tx_octets: %d max_tx_time: %d max_rx_octets: %d max_rx_time: %d", + max_tx_octets, max_tx_time, max_rx_octets, max_rx_time); + + g_dbus_emit_signal(dbus_conn, device->path, + DEVICE_INTERFACE, "LEDataLengthChanged", + DBUS_TYPE_UINT16, &max_tx_octets, + DBUS_TYPE_UINT16, &max_tx_time, + DBUS_TYPE_UINT16, &max_rx_octets, + DBUS_TYPE_UINT16, &max_rx_time, + DBUS_TYPE_INVALID); +} #endif int device_discover_services(struct btd_device *device) -- 2.7.4