summaryrefslogtreecommitdiff
path: root/net
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 /net
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>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/hci_conn.c29
-rw-r--r--net/bluetooth/hci_event.c31
-rw-r--r--net/bluetooth/mgmt.c95
3 files changed, 155 insertions, 0 deletions
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