summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSudha Bheemanna <b.sudha@samsung.com>2016-09-16 15:37:22 +0530
committerSeung-Woo Kim <sw0312.kim@samsung.com>2016-12-14 13:53:27 +0900
commitd4e62d53870f259cce1868920432576ee749ab51 (patch)
tree12c605a5bf060381902e1b41d89cd8e416c936b4
parent00ee9494f355d01ed48f22464ef9ce563a176422 (diff)
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: I3dbcbba83098e17f0e6da209753f8924ffb67678 Signed-off-by: Sudha Bheemanna <b.sudha@samsung.com>
-rw-r--r--include/net/bluetooth/hci_core.h14
-rw-r--r--include/net/bluetooth/mgmt_tizen.h24
-rw-r--r--net/bluetooth/hci_conn.c29
-rw-r--r--net/bluetooth/hci_event.c31
-rw-r--r--net/bluetooth/mgmt.c95
5 files changed, 193 insertions, 0 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 7843ada51bc7..f9d117c1bf14 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -465,6 +465,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;
@@ -515,6 +521,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,
@@ -1558,6 +1568,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 022e51060713..cfb9d5064789 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 */
@@ -295,4 +309,14 @@ struct mgmt_ev_6lowpan_conn_state_changed {
__u8 connected;
__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 93a97c1d99d5..1848ff8e93da 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1173,6 +1173,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 e72f98150d02..f49d81e5ba95 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1567,6 +1567,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)
@@ -5386,6 +5411,12 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_le_direct_adv_report_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 53896298e379..565b4400663b 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -7716,6 +7716,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)
@@ -9615,6 +9708,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