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 | |
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>
-rw-r--r-- | include/net/bluetooth/mgmt.h | 15 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 79 |
2 files changed, 94 insertions, 0 deletions
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 3c0f29614d1b..5b3e8009eddd 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h | |||
@@ -449,6 +449,21 @@ struct mgmt_cp_remove_device { | |||
449 | } __packed; | 449 | } __packed; |
450 | #define MGMT_REMOVE_DEVICE_SIZE MGMT_ADDR_INFO_SIZE | 450 | #define MGMT_REMOVE_DEVICE_SIZE MGMT_ADDR_INFO_SIZE |
451 | 451 | ||
452 | struct mgmt_conn_param { | ||
453 | struct mgmt_addr_info addr; | ||
454 | __le16 min_interval; | ||
455 | __le16 max_interval; | ||
456 | __le16 latency; | ||
457 | __le16 timeout; | ||
458 | } __packed; | ||
459 | |||
460 | #define MGMT_OP_LOAD_CONN_PARAM 0x0035 | ||
461 | struct mgmt_cp_load_conn_param { | ||
462 | __le16 param_count; | ||
463 | struct mgmt_conn_param params[0]; | ||
464 | } __packed; | ||
465 | #define MGMT_LOAD_CONN_PARAM_SIZE 2 | ||
466 | |||
452 | #define MGMT_EV_CMD_COMPLETE 0x0001 | 467 | #define MGMT_EV_CMD_COMPLETE 0x0001 |
453 | struct mgmt_ev_cmd_complete { | 468 | struct mgmt_ev_cmd_complete { |
454 | __le16 opcode; | 469 | __le16 opcode; |
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) |