Bluetooth: Connection Parameter Update Procedure

This patch adds support for LE Connection Parameters Request Link
Layer control procedure introduced in Core spec 4.1. This procedure
allows a Peripheral or Central to update the Link Layer connection
parameters of an established connection.

Regarding the acceptance of connection parameters, the LL procedure
follows the same approach of L2CAP procedure (see l2cap_conn_param_
update_req function). We accept any connection parameters values as
long as they are within the valid range.

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
Andre Guedes 2014-07-01 18:10:08 -03:00 committed by Marcel Holtmann
parent 396e04f4bb
commit 8e75b46a4f
2 changed files with 78 additions and 0 deletions

View file

@ -355,6 +355,7 @@ enum {
#define HCI_LK_AUTH_COMBINATION_P256 0x08
/* ---- HCI Error Codes ---- */
#define HCI_ERROR_UNKNOWN_CONN_ID 0x02
#define HCI_ERROR_AUTH_FAILURE 0x05
#define HCI_ERROR_MEMORY_EXCEEDED 0x07
#define HCI_ERROR_CONNECTION_TIMEOUT 0x08
@ -364,6 +365,7 @@ enum {
#define HCI_ERROR_REMOTE_POWER_OFF 0x15
#define HCI_ERROR_LOCAL_HOST_TERM 0x16
#define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18
#define HCI_ERROR_INVALID_LL_PARAMS 0x1E
#define HCI_ERROR_ADVERTISING_TIMEOUT 0x3c
/* Flow control modes */
@ -1305,6 +1307,23 @@ struct hci_rp_le_read_supported_states {
__u8 le_states[8];
} __packed;
#define HCI_OP_LE_CONN_PARAM_REQ_REPLY 0x2020
struct hci_cp_le_conn_param_req_reply {
__le16 handle;
__le16 interval_min;
__le16 interval_max;
__le16 latency;
__le16 timeout;
__le16 min_ce_len;
__le16 max_ce_len;
} __packed;
#define HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY 0x2021
struct hci_cp_le_conn_param_req_neg_reply {
__le16 handle;
__u8 reason;
} __packed;
/* ---- HCI Events ---- */
#define HCI_EV_INQUIRY_COMPLETE 0x01
@ -1700,6 +1719,15 @@ struct hci_ev_le_ltk_req {
__le16 ediv;
} __packed;
#define HCI_EV_LE_REMOTE_CONN_PARAM_REQ 0x06
struct hci_ev_le_remote_conn_param_req {
__le16 handle;
__le16 interval_min;
__le16 interval_max;
__le16 latency;
__le16 timeout;
} __packed;
/* Advertising report event types */
#define LE_ADV_IND 0x00
#define LE_ADV_DIRECT_IND 0x01

View file

@ -4382,6 +4382,52 @@ not_found:
hci_dev_unlock(hdev);
}
static void send_conn_param_neg_reply(struct hci_dev *hdev, u16 handle,
u8 reason)
{
struct hci_cp_le_conn_param_req_neg_reply cp;
cp.handle = cpu_to_le16(handle);
cp.reason = reason;
hci_send_cmd(hdev, HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY, sizeof(cp),
&cp);
}
static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_ev_le_remote_conn_param_req *ev = (void *) skb->data;
struct hci_cp_le_conn_param_req_reply cp;
struct hci_conn *hcon;
u16 handle, min, max, latency, timeout;
handle = le16_to_cpu(ev->handle);
min = le16_to_cpu(ev->interval_min);
max = le16_to_cpu(ev->interval_max);
latency = le16_to_cpu(ev->latency);
timeout = le16_to_cpu(ev->timeout);
hcon = hci_conn_hash_lookup_handle(hdev, handle);
if (!hcon || hcon->state != BT_CONNECTED)
return send_conn_param_neg_reply(hdev, handle,
HCI_ERROR_UNKNOWN_CONN_ID);
if (hci_check_conn_params(min, max, latency, timeout))
return send_conn_param_neg_reply(hdev, handle,
HCI_ERROR_INVALID_LL_PARAMS);
cp.handle = ev->handle;
cp.interval_min = ev->interval_min;
cp.interval_max = ev->interval_max;
cp.latency = ev->latency;
cp.timeout = ev->timeout;
cp.min_ce_len = 0;
cp.max_ce_len = 0;
hci_send_cmd(hdev, HCI_OP_LE_CONN_PARAM_REQ_REPLY, sizeof(cp), &cp);
}
static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_le_meta *le_ev = (void *) skb->data;
@ -4405,6 +4451,10 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_le_ltk_request_evt(hdev, skb);
break;
case HCI_EV_LE_REMOTE_CONN_PARAM_REQ:
hci_le_remote_conn_param_req_evt(hdev, skb);
break;
default:
break;
}