Added code for LE Data length extension feature. 23/48223/6 accepted/tizen/mobile/20151207.124010 accepted/tizen/tv/20151207.124247 accepted/tizen/wearable/20151207.124359 submit/tizen_mobile/20151207.014408 submit/tizen_tv/20151207.014413 submit/tizen_wearable/20151207.014418
authorSudha Bheemanna <b.sudha@samsung.com>
Wed, 16 Sep 2015 11:04:53 +0000 (16:34 +0530)
committerPyun DoHyun <dh79.pyun@samsung.com>
Mon, 7 Dec 2015 01:41:54 +0000 (17:41 -0800)
Change-Id: I7c7cd8760935b378aa6f7e578ca27ddb1ba40176
Signed-off-by: Sudha Bheemanna <b.sudha@samsung.com>
lib/hci.c [changed mode: 0644->0755]
lib/hci.h [changed mode: 0644->0755]
lib/mgmt.h [changed mode: 0644->0755]
src/adapter.c [changed mode: 0644->0755]
src/adapter.h [changed mode: 0644->0755]
src/device.c [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
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
old mode 100644 (file)
new mode 100755 (executable)
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;
old mode 100644 (file)
new mode 100755 (executable)
index 6a8f603..6bec10e
@@ -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)
old mode 100644 (file)
new mode 100755 (executable)
index d0af889..1e55b6a
@@ -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);
old mode 100644 (file)
new mode 100755 (executable)
index 5e87c59..afa649f
@@ -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
old mode 100644 (file)
new mode 100755 (executable)
index bd89163..cf479ed
@@ -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)