diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2014-07-02 10:37:29 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2014-07-03 11:42:57 -0400 |
commit | a26f3dcff2cf5890f33d883c98d90cdfa51ed460 (patch) | |
tree | f9149c17177f5e56b5fef11856c2ed51791ef509 /net/bluetooth/mgmt.c | |
parent | c71593dd34ae1fd46777662a522a32cfde86f073 (diff) |
Bluetooth: Add Load Connection Parameters command
This patch implements the new Load Connection Parameters mgmt command
that's intended to load the desired connection parameters for LE
devices.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r-- | net/bluetooth/mgmt.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 574dd9f7c39e..59bf1ac41429 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -88,6 +88,7 @@ static const u16 mgmt_commands[] = { | |||
88 | MGMT_OP_GET_CLOCK_INFO, | 88 | MGMT_OP_GET_CLOCK_INFO, |
89 | MGMT_OP_ADD_DEVICE, | 89 | MGMT_OP_ADD_DEVICE, |
90 | MGMT_OP_REMOVE_DEVICE, | 90 | MGMT_OP_REMOVE_DEVICE, |
91 | MGMT_OP_LOAD_CONN_PARAM, | ||
91 | }; | 92 | }; |
92 | 93 | ||
93 | static const u16 mgmt_events[] = { | 94 | static const u16 mgmt_events[] = { |
@@ -5134,6 +5135,83 @@ unlock: | |||
5134 | return err; | 5135 | return err; |
5135 | } | 5136 | } |
5136 | 5137 | ||
5138 | static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data, | ||
5139 | u16 len) | ||
5140 | { | ||
5141 | struct mgmt_cp_load_conn_param *cp = data; | ||
5142 | u16 param_count, expected_len; | ||
5143 | int i; | ||
5144 | |||
5145 | if (!lmp_le_capable(hdev)) | ||
5146 | return cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, | ||
5147 | MGMT_STATUS_NOT_SUPPORTED); | ||
5148 | |||
5149 | param_count = __le16_to_cpu(cp->param_count); | ||
5150 | |||
5151 | expected_len = sizeof(*cp) + param_count * | ||
5152 | sizeof(struct mgmt_conn_param); | ||
5153 | if (expected_len != len) { | ||
5154 | BT_ERR("load_conn_param: expected %u bytes, got %u bytes", | ||
5155 | expected_len, len); | ||
5156 | return cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, | ||
5157 | MGMT_STATUS_INVALID_PARAMS); | ||
5158 | } | ||
5159 | |||
5160 | BT_DBG("%s param_count %u", hdev->name, param_count); | ||
5161 | |||
5162 | hci_dev_lock(hdev); | ||
5163 | |||
5164 | hci_conn_params_clear_disabled(hdev); | ||
5165 | |||
5166 | for (i = 0; i < param_count; i++) { | ||
5167 | struct mgmt_conn_param *param = &cp->params[i]; | ||
5168 | struct hci_conn_params *hci_param; | ||
5169 | u16 min, max, latency, timeout; | ||
5170 | u8 addr_type; | ||
5171 | |||
5172 | BT_DBG("Adding %pMR (type %u)", ¶m->addr.bdaddr, | ||
5173 | param->addr.type); | ||
5174 | |||
5175 | if (param->addr.type == BDADDR_LE_PUBLIC) { | ||
5176 | addr_type = ADDR_LE_DEV_PUBLIC; | ||
5177 | } else if (param->addr.type == BDADDR_LE_RANDOM) { | ||
5178 | addr_type = ADDR_LE_DEV_RANDOM; | ||
5179 | } else { | ||
5180 | BT_ERR("Ignoring invalid connection parameters"); | ||
5181 | continue; | ||
5182 | } | ||
5183 | |||
5184 | min = le16_to_cpu(param->min_interval); | ||
5185 | max = le16_to_cpu(param->max_interval); | ||
5186 | latency = le16_to_cpu(param->latency); | ||
5187 | timeout = le16_to_cpu(param->timeout); | ||
5188 | |||
5189 | BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x", | ||
5190 | min, max, latency, timeout); | ||
5191 | |||
5192 | if (hci_check_conn_params(min, max, latency, timeout) < 0) { | ||
5193 | BT_ERR("Ignoring invalid connection parameters"); | ||
5194 | continue; | ||
5195 | } | ||
5196 | |||
5197 | hci_param = hci_conn_params_add(hdev, ¶m->addr.bdaddr, | ||
5198 | addr_type); | ||
5199 | if (!hci_param) { | ||
5200 | BT_ERR("Failed to add connection parameters"); | ||
5201 | continue; | ||
5202 | } | ||
5203 | |||
5204 | hci_param->conn_min_interval = min; | ||
5205 | hci_param->conn_max_interval = max; | ||
5206 | hci_param->conn_latency = latency; | ||
5207 | hci_param->supervision_timeout = timeout; | ||
5208 | } | ||
5209 | |||
5210 | hci_dev_unlock(hdev); | ||
5211 | |||
5212 | return cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0, NULL, 0); | ||
5213 | } | ||
5214 | |||
5137 | static const struct mgmt_handler { | 5215 | static const struct mgmt_handler { |
5138 | int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, | 5216 | int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, |
5139 | u16 data_len); | 5217 | u16 data_len); |
@@ -5193,6 +5271,7 @@ static const struct mgmt_handler { | |||
5193 | { get_clock_info, false, MGMT_GET_CLOCK_INFO_SIZE }, | 5271 | { get_clock_info, false, MGMT_GET_CLOCK_INFO_SIZE }, |
5194 | { add_device, false, MGMT_ADD_DEVICE_SIZE }, | 5272 | { add_device, false, MGMT_ADD_DEVICE_SIZE }, |
5195 | { remove_device, false, MGMT_REMOVE_DEVICE_SIZE }, | 5273 | { remove_device, false, MGMT_REMOVE_DEVICE_SIZE }, |
5274 | { load_conn_param, true, MGMT_LOAD_CONN_PARAM_SIZE }, | ||
5196 | }; | 5275 | }; |
5197 | 5276 | ||
5198 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | 5277 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) |