diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2014-06-29 13:44:03 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2014-07-03 11:42:50 -0400 |
commit | 2faade53e65f276cf1c30a885fb64808a083714e (patch) | |
tree | 9e3a7b5ace382ab46c8515b3be69f8a39bcd4615 /net | |
parent | 037fc415bce5ac7604ac52216ec03d011f81e5b0 (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.c | 99 |
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 | ||
91 | static const u16 mgmt_events[] = { | 93 | static const u16 mgmt_events[] = { |
@@ -4966,6 +4968,100 @@ unlock: | |||
4966 | return err; | 4968 | return err; |
4967 | } | 4969 | } |
4968 | 4970 | ||
4971 | static 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 | |||
5015 | unlock: | ||
5016 | hci_dev_unlock(hdev); | ||
5017 | return err; | ||
5018 | } | ||
5019 | |||
5020 | static 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 | |||
5060 | unlock: | ||
5061 | hci_dev_unlock(hdev); | ||
5062 | return err; | ||
5063 | } | ||
5064 | |||
4969 | static const struct mgmt_handler { | 5065 | static 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 | |||
5029 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | 5126 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) |
5030 | { | 5127 | { |
5031 | void *buf; | 5128 | void *buf; |