aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2010-12-13 14:07:06 -0500
committerGustavo F. Padovan <padovan@profusion.mobi>2010-12-22 19:57:51 -0500
commitf7b64e69c7c75c8e9f2d5e23edec8de1ce883bcc (patch)
treef13810db736718264f08717e9f0ba04fc2ac9da5 /net
parentfaba42eb2a8cf905ed26d540c3c93d429e327224 (diff)
Bluetooth: Add read_info management command
This patch implements the read_info command which is used to fetch basic info about an adapter. Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com> Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/mgmt.c90
1 files changed, 82 insertions, 8 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 7a8e321875c9..d6c5a32de0b6 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -32,6 +32,33 @@
32#define MGMT_VERSION 0 32#define MGMT_VERSION 0
33#define MGMT_REVISION 1 33#define MGMT_REVISION 1
34 34
35static int cmd_status(struct sock *sk, u16 cmd, u8 status)
36{
37 struct sk_buff *skb;
38 struct mgmt_hdr *hdr;
39 struct mgmt_ev_cmd_status *ev;
40
41 BT_DBG("sock %p", sk);
42
43 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
44 if (!skb)
45 return -ENOMEM;
46
47 hdr = (void *) skb_put(skb, sizeof(*hdr));
48
49 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
50 hdr->len = cpu_to_le16(sizeof(*ev));
51
52 ev = (void *) skb_put(skb, sizeof(*ev));
53 ev->status = status;
54 put_unaligned_le16(cmd, &ev->opcode);
55
56 if (sock_queue_rcv_skb(sk, skb) < 0)
57 kfree_skb(skb);
58
59 return 0;
60}
61
35static int read_version(struct sock *sk) 62static int read_version(struct sock *sk)
36{ 63{
37 struct sk_buff *skb; 64 struct sk_buff *skb;
@@ -112,26 +139,70 @@ static int read_index_list(struct sock *sk)
112 return 0; 139 return 0;
113} 140}
114 141
115static int cmd_status(struct sock *sk, u16 cmd, u8 status) 142static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
116{ 143{
117 struct sk_buff *skb; 144 struct sk_buff *skb;
118 struct mgmt_hdr *hdr; 145 struct mgmt_hdr *hdr;
119 struct mgmt_ev_cmd_status *ev; 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;
150 u16 dev_id;
120 151
121 BT_DBG("sock %p", sk); 152 BT_DBG("sock %p", sk);
122 153
123 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC); 154 if (len != 2)
155 return cmd_status(sk, MGMT_OP_READ_INFO, EINVAL);
156
157 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
124 if (!skb) 158 if (!skb)
125 return -ENOMEM; 159 return -ENOMEM;
126 160
127 hdr = (void *) skb_put(skb, sizeof(*hdr)); 161 hdr = (void *) skb_put(skb, sizeof(*hdr));
128 162 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
129 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS); 163 hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
130 hdr->len = cpu_to_le16(sizeof(*ev));
131 164
132 ev = (void *) skb_put(skb, sizeof(*ev)); 165 ev = (void *) skb_put(skb, sizeof(*ev));
133 ev->status = status; 166 put_unaligned_le16(MGMT_OP_READ_INFO, &ev->opcode);
134 put_unaligned_le16(cmd, &ev->opcode); 167
168 rp = (void *) skb_put(skb, sizeof(*rp));
169
170 cp = (void *) data;
171 dev_id = get_unaligned_le16(&cp->index);
172
173 BT_DBG("request for hci%u", dev_id);
174
175 hdev = hci_dev_get(dev_id);
176 if (!hdev) {
177 kfree_skb(skb);
178 return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV);
179 }
180
181 hci_dev_lock_bh(hdev);
182
183 put_unaligned_le16(hdev->id, &rp->index);
184 rp->type = hdev->dev_type;
185
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);
189
190 if (test_bit(HCI_AUTH, &hdev->flags))
191 rp->sec_mode = 3;
192 else if (hdev->ssp_mode > 0)
193 rp->sec_mode = 4;
194 else
195 rp->sec_mode = 2;
196
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);
203
204 hci_dev_unlock_bh(hdev);
205 hci_dev_put(hdev);
135 206
136 if (sock_queue_rcv_skb(sk, skb) < 0) 207 if (sock_queue_rcv_skb(sk, skb) < 0)
137 kfree_skb(skb); 208 kfree_skb(skb);
@@ -176,6 +247,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
176 case MGMT_OP_READ_INDEX_LIST: 247 case MGMT_OP_READ_INDEX_LIST:
177 err = read_index_list(sk); 248 err = read_index_list(sk);
178 break; 249 break;
250 case MGMT_OP_READ_INFO:
251 err = read_controller_info(sk, buf + sizeof(*hdr), len);
252 break;
179 default: 253 default:
180 BT_DBG("Unknown op %u", opcode); 254 BT_DBG("Unknown op %u", opcode);
181 err = cmd_status(sk, opcode, 0x01); 255 err = cmd_status(sk, opcode, 0x01);