From b3b4886b4ad0ad7de29a232377ff47e6316f00ef Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Fri, 16 Sep 2016 15:37:22 +0530 Subject: [PATCH] Bluetooth: Set le data length command and event Sets the data length for the le data packet with in the advised limits. MGMT command and event are added to handle the setting of data length. Change-Id: Ia5c2167743cc9a29190e5631973e9d52d41caa1d Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung --- include/net/bluetooth/hci_core.h | 14 ++++++ include/net/bluetooth/mgmt_tizen.h | 23 +++++++++ net/bluetooth/hci_conn.c | 29 ++++++++++++ net/bluetooth/hci_event.c | 32 +++++++++++++ net/bluetooth/mgmt.c | 95 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 193 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index a558e9a..79c8042 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -759,6 +759,12 @@ struct hci_conn { __u8 remote_id; unsigned int sent; +#ifdef TIZEN_BT + __u16 tx_len; + __u16 tx_time; + __u16 rx_len; + __u16 rx_time; +#endif struct sk_buff_head data_q; struct list_head chan_list; @@ -815,6 +821,10 @@ struct hci_conn_params { u16 conn_latency; u16 supervision_timeout; +#ifdef TIZEN_BT + u16 max_tx_octets; + u16 max_tx_time; +#endif enum { HCI_AUTO_CONN_DISABLED, HCI_AUTO_CONN_REPORT, @@ -2245,6 +2255,10 @@ void mgmt_le_write_host_suggested_data_length_complete(struct hci_dev *hdev, u8 status); void mgmt_le_read_host_suggested_data_length_complete(struct hci_dev *hdev, u8 status); +void mgmt_le_data_length_change_complete(struct hci_dev *hdev, + bdaddr_t *bdaddr, u16 tx_octets, u16 tx_time, + u16 rx_octets, u16 rx_time); +int hci_le_set_data_length(struct hci_conn *conn, u16 tx_octets, u16 tx_time); #endif int hci_abort_conn(struct hci_conn *conn, u8 reason); diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 2d11d5b..cfb9d50 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -208,6 +208,20 @@ struct mgmt_rp_le_read_host_suggested_data_length { } __packed; #define MGMT_LE_READ_HOST_SUGGESTED_DATA_LENGTH_SIZE 0 +#define MGMT_OP_LE_SET_DATA_LENGTH (TIZEN_OP_CODE_BASE + 0x18) +struct mgmt_cp_le_set_data_length { + bdaddr_t bdaddr; + __le16 max_tx_octets; + __le16 max_tx_time; +} __packed; +#define MGMT_LE_SET_DATA_LENGTH_SIZE 10 + +struct mgmt_rp_le_set_data_length { + __u8 status; + __le16 handle; +} __packed; +#define MGMT_LE_SET_DATA_LENGTH_RSP_SIZE 3 + /* EVENTS */ /* For device name update changes */ @@ -296,4 +310,13 @@ struct mgmt_ev_6lowpan_conn_state_changed { __u8 ifname[16]; } __packed; +#define MGMT_EV_LE_DATA_LENGTH_CHANGED (TIZEN_EV_BASE + 0x0d) +struct mgmt_ev_le_data_length_changed { + struct mgmt_addr_info addr; + __le16 max_tx_octets; + __le16 max_tx_time; + __le16 max_rx_octets; + __le16 max_rx_time; +} __packed; + #endif /* __MGMT_TIZEN_H */ diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index d9383a3..473d44a 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -2494,6 +2494,35 @@ int hci_conn_change_supervision_timeout(struct hci_conn *conn, __u16 timeout) return 0; } + +int hci_le_set_data_length(struct hci_conn *conn, u16 tx_octets, u16 tx_time) +{ + struct hci_dev *hdev = conn->hdev; + struct hci_conn_params *params; + struct hci_cp_le_set_data_len cp; + + hci_dev_lock(hdev); + + params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); + if (params) { + params->max_tx_octets = tx_octets; + params->max_tx_time = tx_time; + } + + hci_dev_unlock(hdev); + + memset(&cp, 0, sizeof(cp)); + cp.handle = cpu_to_le16(conn->handle); + cp.tx_len = cpu_to_le16(tx_octets); + cp.tx_time = cpu_to_le16(tx_time); + + hci_send_cmd(hdev, HCI_OP_LE_SET_DATA_LEN, sizeof(cp), &cp); + + if (params) + return 0x01; + + return 0x00; +} #endif /* Enter active mode */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a4ea46e..cc4c4bb 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2359,6 +2359,32 @@ static void hci_vendor_specific_evt(struct hci_dev *hdev, void *data, break; } } + +static void hci_le_data_length_changed_complete_evt(struct hci_dev *hdev, + void *data, + struct sk_buff *skb) +{ + struct hci_ev_le_data_len_change *ev = (void *)skb->data; + struct hci_conn *conn; + + BT_DBG("%s status", hdev->name); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); + if (conn) { + conn->tx_len = le16_to_cpu(ev->tx_len); + conn->tx_time = le16_to_cpu(ev->tx_time); + conn->rx_len = le16_to_cpu(ev->rx_len); + conn->rx_time = le16_to_cpu(ev->rx_time); + } + + mgmt_le_data_length_change_complete(hdev, &conn->dst, + conn->tx_len, conn->tx_time, + conn->rx_len, conn->rx_time); + + hci_dev_unlock(hdev); +} #endif static u8 hci_cc_read_rssi(struct hci_dev *hdev, void *data, @@ -7321,6 +7347,12 @@ static const struct hci_le_ev { HCI_LE_EV(HCI_EV_LE_REMOTE_CONN_PARAM_REQ, hci_le_remote_conn_param_req_evt, sizeof(struct hci_ev_le_remote_conn_param_req)), +#ifdef TIZEN_BT + /* [0x07 = HCI_EV_LE_DATA_LEN_CHANGE] */ + HCI_LE_EV(HCI_EV_LE_DATA_LEN_CHANGE, + hci_le_data_length_changed_complete_evt, + sizeof(struct hci_ev_le_data_len_change)), +#endif /* [0x0a = HCI_EV_LE_ENHANCED_CONN_COMPLETE] */ HCI_LE_EV(HCI_EV_LE_ENHANCED_CONN_COMPLETE, hci_le_enh_conn_complete_evt, diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7046be4..a674d9c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -9366,6 +9366,99 @@ unlock: return err; } + +static int set_le_data_length_params(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_cp_le_set_data_length *cp = data; + struct mgmt_rp_le_set_data_length *rp; + struct mgmt_pending_cmd *cmd; + struct hci_conn *conn; + int err = 0; + u16 max_tx_octets, max_tx_time; + size_t rp_len; + + BT_INFO("Set Data length for the device %s", hdev->name); + + hci_dev_lock(hdev); + + rp_len = sizeof(*rp); + rp = kmalloc(rp_len, GFP_KERNEL); + if (!rp) { + err = -ENOMEM; + goto unlock; + } + + if (!hdev_is_powered(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_SET_DATA_LENGTH, + MGMT_STATUS_NOT_POWERED); + goto unlock; + } + + if (!lmp_le_capable(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_SET_DATA_LENGTH, + MGMT_STATUS_NOT_SUPPORTED); + goto unlock; + } + + if (pending_find(MGMT_OP_LE_SET_DATA_LENGTH, hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_SET_DATA_LENGTH, + MGMT_STATUS_BUSY); + goto unlock; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_LE_SET_DATA_LENGTH, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto unlock; + } + + max_tx_octets = __le16_to_cpu(cp->max_tx_octets); + max_tx_time = __le16_to_cpu(cp->max_tx_time); + + BT_DBG("max_tx_octets 0x%4.4x max_tx_time 0x%4.4x latency", + max_tx_octets, max_tx_time); + + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr); + if (!conn) { + mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_SET_DATA_LENGTH, + MGMT_STATUS_NOT_CONNECTED); + goto unlock; + } + + hci_dev_unlock(hdev); + + err = hci_le_set_data_length(conn, max_tx_octets, max_tx_time); + if (err < 0) + mgmt_pending_remove(cmd); + + rp->handle = conn->handle; + rp->status = 0; + + hci_dev_lock(hdev); + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LE_SET_DATA_LENGTH, 0, + rp, rp_len); +unlock: + kfree(rp); + hci_dev_unlock(hdev); + + return err; +} + +void mgmt_le_data_length_change_complete(struct hci_dev *hdev, + bdaddr_t *bdaddr, u16 tx_octets, u16 tx_time, + u16 rx_octets, u16 rx_time) +{ + struct mgmt_ev_le_data_length_changed ev; + + bacpy(&ev.addr.bdaddr, bdaddr); + ev.max_tx_octets = tx_octets; + ev.max_tx_time = tx_time; + ev.max_rx_octets = rx_octets; + ev.max_rx_time = rx_time; + + mgmt_event(MGMT_EV_LE_DATA_LENGTH_CHANGED, hdev, &ev, sizeof(ev), NULL); +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) @@ -11710,6 +11803,8 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { MGMT_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH_SIZE }, { read_host_suggested_data_length, MGMT_LE_READ_HOST_SUGGESTED_DATA_LENGTH_SIZE }, + { set_le_data_length_params, + MGMT_LE_SET_DATA_LENGTH_SIZE }, }; #endif -- 2.7.4