2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
23 /* Bluetooth HCI Management interface */
25 #include <asm/uaccess.h>
26 #include <asm/unaligned.h>
28 #include <net/bluetooth/bluetooth.h>
29 #include <net/bluetooth/hci_core.h>
30 #include <net/bluetooth/mgmt.h>
32 #define MGMT_VERSION 0
33 #define MGMT_REVISION 1
35 static int cmd_status(struct sock
*sk
, u16 cmd
, u8 status
)
39 struct mgmt_ev_cmd_status
*ev
;
41 BT_DBG("sock %p", sk
);
43 skb
= alloc_skb(sizeof(*hdr
) + sizeof(*ev
), GFP_ATOMIC
);
47 hdr
= (void *) skb_put(skb
, sizeof(*hdr
));
49 hdr
->opcode
= cpu_to_le16(MGMT_EV_CMD_STATUS
);
50 hdr
->len
= cpu_to_le16(sizeof(*ev
));
52 ev
= (void *) skb_put(skb
, sizeof(*ev
));
54 put_unaligned_le16(cmd
, &ev
->opcode
);
56 if (sock_queue_rcv_skb(sk
, skb
) < 0)
62 static int read_version(struct sock
*sk
)
66 struct mgmt_ev_cmd_complete
*ev
;
67 struct mgmt_rp_read_version
*rp
;
69 BT_DBG("sock %p", sk
);
71 skb
= alloc_skb(sizeof(*hdr
) + sizeof(*ev
) + sizeof(*rp
), GFP_ATOMIC
);
75 hdr
= (void *) skb_put(skb
, sizeof(*hdr
));
76 hdr
->opcode
= cpu_to_le16(MGMT_EV_CMD_COMPLETE
);
77 hdr
->len
= cpu_to_le16(sizeof(*ev
) + sizeof(*rp
));
79 ev
= (void *) skb_put(skb
, sizeof(*ev
));
80 put_unaligned_le16(MGMT_OP_READ_VERSION
, &ev
->opcode
);
82 rp
= (void *) skb_put(skb
, sizeof(*rp
));
83 rp
->version
= MGMT_VERSION
;
84 put_unaligned_le16(MGMT_REVISION
, &rp
->revision
);
86 if (sock_queue_rcv_skb(sk
, skb
) < 0)
92 static int read_index_list(struct sock
*sk
)
96 struct mgmt_ev_cmd_complete
*ev
;
97 struct mgmt_rp_read_index_list
*rp
;
103 BT_DBG("sock %p", sk
);
105 read_lock(&hci_dev_list_lock
);
108 list_for_each(p
, &hci_dev_list
) {
112 body_len
= sizeof(*ev
) + sizeof(*rp
) + (2 * count
);
113 skb
= alloc_skb(sizeof(*hdr
) + body_len
, GFP_ATOMIC
);
117 hdr
= (void *) skb_put(skb
, sizeof(*hdr
));
118 hdr
->opcode
= cpu_to_le16(MGMT_EV_CMD_COMPLETE
);
119 hdr
->len
= cpu_to_le16(body_len
);
121 ev
= (void *) skb_put(skb
, sizeof(*ev
));
122 put_unaligned_le16(MGMT_OP_READ_INDEX_LIST
, &ev
->opcode
);
124 rp
= (void *) skb_put(skb
, sizeof(*rp
) + (2 * count
));
125 put_unaligned_le16(count
, &rp
->num_controllers
);
128 list_for_each(p
, &hci_dev_list
) {
129 struct hci_dev
*d
= list_entry(p
, struct hci_dev
, list
);
130 put_unaligned_le16(d
->id
, &rp
->index
[i
++]);
131 BT_DBG("Added hci%u", d
->id
);
134 read_unlock(&hci_dev_list_lock
);
136 if (sock_queue_rcv_skb(sk
, skb
) < 0)
142 static int read_controller_info(struct sock
*sk
, unsigned char *data
, u16 len
)
145 struct mgmt_hdr
*hdr
;
146 struct mgmt_ev_cmd_complete
*ev
;
147 struct mgmt_rp_read_info
*rp
;
148 struct mgmt_cp_read_info
*cp
;
149 struct hci_dev
*hdev
;
152 BT_DBG("sock %p", sk
);
155 return cmd_status(sk
, MGMT_OP_READ_INFO
, EINVAL
);
157 skb
= alloc_skb(sizeof(*hdr
) + sizeof(*ev
) + sizeof(*rp
), GFP_ATOMIC
);
161 hdr
= (void *) skb_put(skb
, sizeof(*hdr
));
162 hdr
->opcode
= cpu_to_le16(MGMT_EV_CMD_COMPLETE
);
163 hdr
->len
= cpu_to_le16(sizeof(*ev
) + sizeof(*rp
));
165 ev
= (void *) skb_put(skb
, sizeof(*ev
));
166 put_unaligned_le16(MGMT_OP_READ_INFO
, &ev
->opcode
);
168 rp
= (void *) skb_put(skb
, sizeof(*rp
));
171 dev_id
= get_unaligned_le16(&cp
->index
);
173 BT_DBG("request for hci%u", dev_id
);
175 hdev
= hci_dev_get(dev_id
);
178 return cmd_status(sk
, MGMT_OP_READ_INFO
, ENODEV
);
181 hci_dev_lock_bh(hdev
);
183 put_unaligned_le16(hdev
->id
, &rp
->index
);
184 rp
->type
= hdev
->dev_type
;
186 rp
->powered
= test_bit(HCI_UP
, &hdev
->flags
);
187 rp
->discoverable
= test_bit(HCI_ISCAN
, &hdev
->flags
);
188 rp
->pairable
= test_bit(HCI_PSCAN
, &hdev
->flags
);
190 if (test_bit(HCI_AUTH
, &hdev
->flags
))
192 else if (hdev
->ssp_mode
> 0)
197 bacpy(&rp
->bdaddr
, &hdev
->bdaddr
);
198 memcpy(rp
->features
, hdev
->features
, 8);
199 memcpy(rp
->dev_class
, hdev
->dev_class
, 3);
200 put_unaligned_le16(hdev
->manufacturer
, &rp
->manufacturer
);
201 rp
->hci_ver
= hdev
->hci_ver
;
202 put_unaligned_le16(hdev
->hci_rev
, &rp
->hci_rev
);
204 hci_dev_unlock_bh(hdev
);
207 if (sock_queue_rcv_skb(sk
, skb
) < 0)
213 int mgmt_control(struct sock
*sk
, struct msghdr
*msg
, size_t msglen
)
216 struct mgmt_hdr
*hdr
;
220 BT_DBG("got %zu bytes", msglen
);
222 if (msglen
< sizeof(*hdr
))
225 buf
= kmalloc(msglen
, GFP_ATOMIC
);
229 if (memcpy_fromiovec(buf
, msg
->msg_iov
, msglen
)) {
234 hdr
= (struct mgmt_hdr
*) buf
;
235 opcode
= get_unaligned_le16(&hdr
->opcode
);
236 len
= get_unaligned_le16(&hdr
->len
);
238 if (len
!= msglen
- sizeof(*hdr
)) {
244 case MGMT_OP_READ_VERSION
:
245 err
= read_version(sk
);
247 case MGMT_OP_READ_INDEX_LIST
:
248 err
= read_index_list(sk
);
250 case MGMT_OP_READ_INFO
:
251 err
= read_controller_info(sk
, buf
+ sizeof(*hdr
), len
);
254 BT_DBG("Unknown op %u", opcode
);
255 err
= cmd_status(sk
, opcode
, 0x01);
269 static int mgmt_event(u16 event
, void *data
, u16 data_len
)
272 struct mgmt_hdr
*hdr
;
274 skb
= alloc_skb(sizeof(*hdr
) + data_len
, GFP_ATOMIC
);
278 bt_cb(skb
)->channel
= HCI_CHANNEL_CONTROL
;
280 hdr
= (void *) skb_put(skb
, sizeof(*hdr
));
281 hdr
->opcode
= cpu_to_le16(event
);
282 hdr
->len
= cpu_to_le16(data_len
);
284 memcpy(skb_put(skb
, data_len
), data
, data_len
);
286 hci_send_to_sock(NULL
, skb
);
292 int mgmt_index_added(u16 index
)
294 struct mgmt_ev_index_added ev
;
296 put_unaligned_le16(index
, &ev
.index
);
298 return mgmt_event(MGMT_EV_INDEX_ADDED
, &ev
, sizeof(ev
));
301 int mgmt_index_removed(u16 index
)
303 struct mgmt_ev_index_added ev
;
305 put_unaligned_le16(index
, &ev
.index
);
307 return mgmt_event(MGMT_EV_INDEX_REMOVED
, &ev
, sizeof(ev
));