aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2014-06-29 13:44:03 -0400
committerMarcel Holtmann <marcel@holtmann.org>2014-07-03 11:42:50 -0400
commit2faade53e65f276cf1c30a885fb64808a083714e (patch)
tree9e3a7b5ace382ab46c8515b3be69f8a39bcd4615 /net
parent037fc415bce5ac7604ac52216ec03d011f81e5b0 (diff)
Bluetooth: Add support for Add/Remove Device management commands
This allows adding or removing devices from the background scanning list the kernel maintains. Device flagged for auto-connection will be automatically connected if they are found. The passive scanning required for auto-connection will be started and stopped on demand. Signed-off-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/mgmt.c99
1 files changed, 98 insertions, 1 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 41b1aec0c5dc..64b55c7881ee 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -86,6 +86,8 @@ static const u16 mgmt_commands[] = {
86 MGMT_OP_LOAD_IRKS, 86 MGMT_OP_LOAD_IRKS,
87 MGMT_OP_GET_CONN_INFO, 87 MGMT_OP_GET_CONN_INFO,
88 MGMT_OP_GET_CLOCK_INFO, 88 MGMT_OP_GET_CLOCK_INFO,
89 MGMT_OP_ADD_DEVICE,
90 MGMT_OP_REMOVE_DEVICE,
89}; 91};
90 92
91static const u16 mgmt_events[] = { 93static const u16 mgmt_events[] = {
@@ -4966,6 +4968,100 @@ unlock:
4966 return err; 4968 return err;
4967} 4969}
4968 4970
4971static int add_device(struct sock *sk, struct hci_dev *hdev,
4972 void *data, u16 len)
4973{
4974 struct mgmt_cp_add_device *cp = data;
4975 u8 auto_conn, addr_type;
4976 int err;
4977
4978 BT_DBG("%s", hdev->name);
4979
4980 if (!bdaddr_type_is_le(cp->addr.type) ||
4981 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
4982 return cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
4983 MGMT_STATUS_INVALID_PARAMS,
4984 &cp->addr, sizeof(cp->addr));
4985
4986 if (cp->action != 0x00 && cp->action != 0x01)
4987 return cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
4988 MGMT_STATUS_INVALID_PARAMS,
4989 &cp->addr, sizeof(cp->addr));
4990
4991 hci_dev_lock(hdev);
4992
4993 if (cp->addr.type == BDADDR_LE_PUBLIC)
4994 addr_type = ADDR_LE_DEV_PUBLIC;
4995 else
4996 addr_type = ADDR_LE_DEV_RANDOM;
4997
4998 if (cp->action)
4999 auto_conn = HCI_AUTO_CONN_ALWAYS;
5000 else
5001 auto_conn = HCI_AUTO_CONN_DISABLED;
5002
5003 if (hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type, auto_conn,
5004 hdev->le_conn_min_interval,
5005 hdev->le_conn_max_interval) < 0) {
5006 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5007 MGMT_STATUS_FAILED,
5008 &cp->addr, sizeof(cp->addr));
5009 goto unlock;
5010 }
5011
5012 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5013 MGMT_STATUS_SUCCESS, &cp->addr, sizeof(cp->addr));
5014
5015unlock:
5016 hci_dev_unlock(hdev);
5017 return err;
5018}
5019
5020static int remove_device(struct sock *sk, struct hci_dev *hdev,
5021 void *data, u16 len)
5022{
5023 struct mgmt_cp_remove_device *cp = data;
5024 int err;
5025
5026 BT_DBG("%s", hdev->name);
5027
5028 hci_dev_lock(hdev);
5029
5030 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5031 u8 addr_type;
5032
5033 if (!bdaddr_type_is_le(cp->addr.type)) {
5034 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5035 MGMT_STATUS_INVALID_PARAMS,
5036 &cp->addr, sizeof(cp->addr));
5037 goto unlock;
5038 }
5039
5040 if (cp->addr.type == BDADDR_LE_PUBLIC)
5041 addr_type = ADDR_LE_DEV_PUBLIC;
5042 else
5043 addr_type = ADDR_LE_DEV_RANDOM;
5044
5045 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
5046 } else {
5047 if (cp->addr.type) {
5048 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5049 MGMT_STATUS_INVALID_PARAMS,
5050 &cp->addr, sizeof(cp->addr));
5051 goto unlock;
5052 }
5053
5054 hci_conn_params_clear(hdev);
5055 }
5056
5057 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5058 MGMT_STATUS_SUCCESS, &cp->addr, sizeof(cp->addr));
5059
5060unlock:
5061 hci_dev_unlock(hdev);
5062 return err;
5063}
5064
4969static const struct mgmt_handler { 5065static const struct mgmt_handler {
4970 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, 5066 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4971 u16 data_len); 5067 u16 data_len);
@@ -5023,9 +5119,10 @@ static const struct mgmt_handler {
5023 { load_irks, true, MGMT_LOAD_IRKS_SIZE }, 5119 { load_irks, true, MGMT_LOAD_IRKS_SIZE },
5024 { get_conn_info, false, MGMT_GET_CONN_INFO_SIZE }, 5120 { get_conn_info, false, MGMT_GET_CONN_INFO_SIZE },
5025 { get_clock_info, false, MGMT_GET_CLOCK_INFO_SIZE }, 5121 { get_clock_info, false, MGMT_GET_CLOCK_INFO_SIZE },
5122 { add_device, false, MGMT_ADD_DEVICE_SIZE },
5123 { remove_device, false, MGMT_REMOVE_DEVICE_SIZE },
5026}; 5124};
5027 5125
5028
5029int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) 5126int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
5030{ 5127{
5031 void *buf; 5128 void *buf;