diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2012-02-13 09:59:33 -0500 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@intel.com> | 2012-02-15 07:28:07 -0500 |
commit | e70bb2e89959983aebcfce28f645a1104ffa9ab2 (patch) | |
tree | 721c67618b45cce0d6adc610f59589d5ef9bc816 /net/bluetooth/mgmt.c | |
parent | 9ab875affbe61b2c88685c342461c9a367ab7a3e (diff) |
Bluetooth: Implement Read Supported Commands commands for mgmt
This patch implements the Read Supported Commands mgmt command which was
recently added to the API specification. It returns a list of supported
commands and events to user space.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r-- | net/bluetooth/mgmt.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a2c2e12516c6..8efbd8eaa1b3 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -35,6 +35,69 @@ | |||
35 | #define MGMT_VERSION 0 | 35 | #define MGMT_VERSION 0 |
36 | #define MGMT_REVISION 1 | 36 | #define MGMT_REVISION 1 |
37 | 37 | ||
38 | static const u16 mgmt_commands[] = { | ||
39 | MGMT_OP_READ_INDEX_LIST, | ||
40 | MGMT_OP_READ_INFO, | ||
41 | MGMT_OP_SET_POWERED, | ||
42 | MGMT_OP_SET_DISCOVERABLE, | ||
43 | MGMT_OP_SET_CONNECTABLE, | ||
44 | MGMT_OP_SET_FAST_CONNECTABLE, | ||
45 | MGMT_OP_SET_PAIRABLE, | ||
46 | MGMT_OP_SET_LINK_SECURITY, | ||
47 | MGMT_OP_SET_SSP, | ||
48 | MGMT_OP_SET_HS, | ||
49 | MGMT_OP_SET_LE, | ||
50 | MGMT_OP_SET_DEV_CLASS, | ||
51 | MGMT_OP_SET_LOCAL_NAME, | ||
52 | MGMT_OP_ADD_UUID, | ||
53 | MGMT_OP_REMOVE_UUID, | ||
54 | MGMT_OP_LOAD_LINK_KEYS, | ||
55 | MGMT_OP_LOAD_LONG_TERM_KEYS, | ||
56 | MGMT_OP_DISCONNECT, | ||
57 | MGMT_OP_GET_CONNECTIONS, | ||
58 | MGMT_OP_PIN_CODE_REPLY, | ||
59 | MGMT_OP_PIN_CODE_NEG_REPLY, | ||
60 | MGMT_OP_SET_IO_CAPABILITY, | ||
61 | MGMT_OP_PAIR_DEVICE, | ||
62 | MGMT_OP_CANCEL_PAIR_DEVICE, | ||
63 | MGMT_OP_UNPAIR_DEVICE, | ||
64 | MGMT_OP_USER_CONFIRM_REPLY, | ||
65 | MGMT_OP_USER_CONFIRM_NEG_REPLY, | ||
66 | MGMT_OP_USER_PASSKEY_REPLY, | ||
67 | MGMT_OP_USER_PASSKEY_NEG_REPLY, | ||
68 | MGMT_OP_READ_LOCAL_OOB_DATA, | ||
69 | MGMT_OP_ADD_REMOTE_OOB_DATA, | ||
70 | MGMT_OP_REMOVE_REMOTE_OOB_DATA, | ||
71 | MGMT_OP_START_DISCOVERY, | ||
72 | MGMT_OP_STOP_DISCOVERY, | ||
73 | MGMT_OP_CONFIRM_NAME, | ||
74 | MGMT_OP_BLOCK_DEVICE, | ||
75 | MGMT_OP_UNBLOCK_DEVICE, | ||
76 | }; | ||
77 | |||
78 | static const u16 mgmt_events[] = { | ||
79 | MGMT_EV_CONTROLLER_ERROR, | ||
80 | MGMT_EV_INDEX_ADDED, | ||
81 | MGMT_EV_INDEX_REMOVED, | ||
82 | MGMT_EV_NEW_SETTINGS, | ||
83 | MGMT_EV_CLASS_OF_DEV_CHANGED, | ||
84 | MGMT_EV_LOCAL_NAME_CHANGED, | ||
85 | MGMT_EV_NEW_LINK_KEY, | ||
86 | MGMT_EV_NEW_LONG_TERM_KEY, | ||
87 | MGMT_EV_DEVICE_CONNECTED, | ||
88 | MGMT_EV_DEVICE_DISCONNECTED, | ||
89 | MGMT_EV_CONNECT_FAILED, | ||
90 | MGMT_EV_PIN_CODE_REQUEST, | ||
91 | MGMT_EV_USER_CONFIRM_REQUEST, | ||
92 | MGMT_EV_USER_PASSKEY_REQUEST, | ||
93 | MGMT_EV_AUTH_FAILED, | ||
94 | MGMT_EV_DEVICE_FOUND, | ||
95 | MGMT_EV_DISCOVERING, | ||
96 | MGMT_EV_DEVICE_BLOCKED, | ||
97 | MGMT_EV_DEVICE_UNBLOCKED, | ||
98 | MGMT_EV_DEVICE_UNPAIRED, | ||
99 | }; | ||
100 | |||
38 | /* | 101 | /* |
39 | * These LE scan and inquiry parameters were chosen according to LE General | 102 | * These LE scan and inquiry parameters were chosen according to LE General |
40 | * Discovery Procedure specification. | 103 | * Discovery Procedure specification. |
@@ -206,6 +269,39 @@ static int read_version(struct sock *sk) | |||
206 | sizeof(rp)); | 269 | sizeof(rp)); |
207 | } | 270 | } |
208 | 271 | ||
272 | static int read_commands(struct sock *sk) | ||
273 | { | ||
274 | struct mgmt_rp_read_commands *rp; | ||
275 | u16 num_commands = ARRAY_SIZE(mgmt_commands); | ||
276 | u16 num_events = ARRAY_SIZE(mgmt_events); | ||
277 | u16 *opcode; | ||
278 | size_t rp_size; | ||
279 | int i, err; | ||
280 | |||
281 | BT_DBG("sock %p", sk); | ||
282 | |||
283 | rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16)); | ||
284 | |||
285 | rp = kmalloc(rp_size, GFP_KERNEL); | ||
286 | if (!rp) | ||
287 | return -ENOMEM; | ||
288 | |||
289 | put_unaligned_le16(num_commands, &rp->num_commands); | ||
290 | put_unaligned_le16(num_events, &rp->num_events); | ||
291 | |||
292 | for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++) | ||
293 | put_unaligned_le16(mgmt_commands[i], opcode); | ||
294 | |||
295 | for (i = 0; i < num_events; i++, opcode++) | ||
296 | put_unaligned_le16(mgmt_events[i], opcode); | ||
297 | |||
298 | err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, rp, | ||
299 | rp_size); | ||
300 | kfree(rp); | ||
301 | |||
302 | return err; | ||
303 | } | ||
304 | |||
209 | static int read_index_list(struct sock *sk) | 305 | static int read_index_list(struct sock *sk) |
210 | { | 306 | { |
211 | struct mgmt_rp_read_index_list *rp; | 307 | struct mgmt_rp_read_index_list *rp; |
@@ -2323,6 +2419,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
2323 | case MGMT_OP_READ_VERSION: | 2419 | case MGMT_OP_READ_VERSION: |
2324 | err = read_version(sk); | 2420 | err = read_version(sk); |
2325 | break; | 2421 | break; |
2422 | case MGMT_OP_READ_COMMANDS: | ||
2423 | err = read_commands(sk); | ||
2424 | break; | ||
2326 | case MGMT_OP_READ_INDEX_LIST: | 2425 | case MGMT_OP_READ_INDEX_LIST: |
2327 | err = read_index_list(sk); | 2426 | err = read_index_list(sk); |
2328 | break; | 2427 | break; |