diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2011-11-10 08:54:38 -0500 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-11-10 15:05:37 -0500 |
commit | a8a1d19e9d00e2ec6f28b89133137390b1d293bd (patch) | |
tree | f0a9b29406b632ed0d1dc1ff23cd397c707cd305 /net/bluetooth/mgmt.c | |
parent | c3f06755ca4279597cd58befd6c076ae2e3db480 (diff) |
Bluetooth: Add proper response to mgmt_remove_keys command
Since the command can fail we need to have a proper response with the
remote address and a failure status for it. This also updates it to
conform to the latest mgmt API spec.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r-- | net/bluetooth/mgmt.c | 61 |
1 files changed, 50 insertions, 11 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c3d7852baa1f..dddb19057d11 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -961,6 +961,9 @@ static int remove_keys(struct sock *sk, u16 index, unsigned char *data, | |||
961 | { | 961 | { |
962 | struct hci_dev *hdev; | 962 | struct hci_dev *hdev; |
963 | struct mgmt_cp_remove_keys *cp; | 963 | struct mgmt_cp_remove_keys *cp; |
964 | struct mgmt_rp_remove_keys rp; | ||
965 | struct hci_cp_disconnect dc; | ||
966 | struct pending_cmd *cmd; | ||
964 | struct hci_conn *conn; | 967 | struct hci_conn *conn; |
965 | int err; | 968 | int err; |
966 | 969 | ||
@@ -975,27 +978,44 @@ static int remove_keys(struct sock *sk, u16 index, unsigned char *data, | |||
975 | 978 | ||
976 | hci_dev_lock_bh(hdev); | 979 | hci_dev_lock_bh(hdev); |
977 | 980 | ||
981 | memset(&rp, 0, sizeof(rp)); | ||
982 | bacpy(&rp.bdaddr, &cp->bdaddr); | ||
983 | |||
978 | err = hci_remove_link_key(hdev, &cp->bdaddr); | 984 | err = hci_remove_link_key(hdev, &cp->bdaddr); |
979 | if (err < 0) { | 985 | if (err < 0) |
980 | err = cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, -err); | ||
981 | goto unlock; | 986 | goto unlock; |
982 | } | ||
983 | |||
984 | err = 0; | ||
985 | 987 | ||
986 | if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) | 988 | if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) { |
989 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, | ||
990 | sizeof(rp)); | ||
987 | goto unlock; | 991 | goto unlock; |
992 | } | ||
988 | 993 | ||
989 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); | 994 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); |
990 | if (conn) { | 995 | if (!conn) { |
991 | struct hci_cp_disconnect dc; | 996 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, |
997 | sizeof(rp)); | ||
998 | goto unlock; | ||
999 | } | ||
992 | 1000 | ||
993 | put_unaligned_le16(conn->handle, &dc.handle); | 1001 | cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp)); |
994 | dc.reason = 0x13; /* Remote User Terminated Connection */ | 1002 | if (!cmd) { |
995 | err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc); | 1003 | err = -ENOMEM; |
1004 | goto unlock; | ||
996 | } | 1005 | } |
997 | 1006 | ||
1007 | put_unaligned_le16(conn->handle, &dc.handle); | ||
1008 | dc.reason = 0x13; /* Remote User Terminated Connection */ | ||
1009 | err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc); | ||
1010 | if (err < 0) | ||
1011 | mgmt_pending_remove(cmd); | ||
1012 | |||
998 | unlock: | 1013 | unlock: |
1014 | if (err < 0) { | ||
1015 | rp.status = -err; | ||
1016 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, | ||
1017 | sizeof(rp)); | ||
1018 | } | ||
999 | hci_dev_unlock_bh(hdev); | 1019 | hci_dev_unlock_bh(hdev); |
1000 | hci_dev_put(hdev); | 1020 | hci_dev_put(hdev); |
1001 | 1021 | ||
@@ -2117,6 +2137,23 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data) | |||
2117 | mgmt_pending_remove(cmd); | 2137 | mgmt_pending_remove(cmd); |
2118 | } | 2138 | } |
2119 | 2139 | ||
2140 | static void remove_keys_rsp(struct pending_cmd *cmd, void *data) | ||
2141 | { | ||
2142 | u8 *status = data; | ||
2143 | struct mgmt_cp_remove_keys *cp = cmd->param; | ||
2144 | struct mgmt_rp_remove_keys rp; | ||
2145 | |||
2146 | memset(&rp, 0, sizeof(rp)); | ||
2147 | bacpy(&rp.bdaddr, &cp->bdaddr); | ||
2148 | if (status != NULL) | ||
2149 | rp.status = *status; | ||
2150 | |||
2151 | cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp, | ||
2152 | sizeof(rp)); | ||
2153 | |||
2154 | mgmt_pending_remove(cmd); | ||
2155 | } | ||
2156 | |||
2120 | int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | 2157 | int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, |
2121 | u8 addr_type) | 2158 | u8 addr_type) |
2122 | { | 2159 | { |
@@ -2134,6 +2171,8 @@ int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | |||
2134 | if (sk) | 2171 | if (sk) |
2135 | sock_put(sk); | 2172 | sock_put(sk); |
2136 | 2173 | ||
2174 | mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL); | ||
2175 | |||
2137 | return err; | 2176 | return err; |
2138 | } | 2177 | } |
2139 | 2178 | ||