From 457b81b8f4f13d06a7dd900825a0eb56b47e7f8d 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 --- 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 | 30 ++++++++++++ net/bluetooth/mgmt.c | 95 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 191 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9afbf0e..e92ded2 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -522,6 +522,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; @@ -573,6 +579,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, @@ -1743,6 +1753,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 u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, 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 51a9b30..2ed7bae 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1517,6 +1517,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 2fd3bfa..5f28cf9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1832,6 +1832,31 @@ static void hci_vendor_specific_evt(struct hci_dev *hdev, struct sk_buff *skb) break; } } + +static void hci_le_data_length_changed_complete_evt(struct hci_dev *hdev, + 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 void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb) @@ -6038,6 +6063,11 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) case HCI_EV_LE_EXT_ADV_SET_TERM: hci_le_ext_adv_term_evt(hdev, skb); break; +#ifdef TIZEN_BT + case HCI_EV_LE_DATA_LEN_CHANGE: + hci_le_data_length_changed_complete_evt(hdev, skb); + break; +#endif default: break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d2e8827..718d63e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -7282,6 +7282,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) @@ -9261,6 +9354,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