~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/bluetooth/hci_conn.c

Version: ~ [ linux-5.15-rc6 ] ~ [ linux-5.14.14 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.75 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.155 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.213 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.252 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.287 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.289 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* 
  2    BlueZ - Bluetooth protocol stack for Linux
  3    Copyright (C) 2000-2001 Qualcomm Incorporated
  4 
  5    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
  6 
  7    This program is free software; you can redistribute it and/or modify
  8    it under the terms of the GNU General Public License version 2 as
  9    published by the Free Software Foundation;
 10 
 11    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 12    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 13    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
 14    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
 15    CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
 16    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
 17    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
 18    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 19 
 20    ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
 21    COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
 22    SOFTWARE IS DISCLAIMED.
 23 */
 24 
 25 /*
 26  * HCI Connection handling.
 27  *
 28  * $Id: hci_conn.c,v 1.5 2002/07/17 18:46:25 maxk Exp $
 29  */
 30 
 31 #include <linux/config.h>
 32 #include <linux/module.h>
 33 
 34 #include <linux/types.h>
 35 #include <linux/errno.h>
 36 #include <linux/kernel.h>
 37 #include <linux/major.h>
 38 #include <linux/sched.h>
 39 #include <linux/slab.h>
 40 #include <linux/poll.h>
 41 #include <linux/fcntl.h>
 42 #include <linux/init.h>
 43 #include <linux/skbuff.h>
 44 #include <linux/interrupt.h>
 45 #include <linux/notifier.h>
 46 #include <net/sock.h>
 47 
 48 #include <asm/system.h>
 49 #include <asm/uaccess.h>
 50 #include <asm/unaligned.h>
 51 
 52 #include <net/bluetooth/bluetooth.h>
 53 #include <net/bluetooth/hci_core.h>
 54 
 55 #ifndef HCI_CORE_DEBUG
 56 #undef  BT_DBG
 57 #define BT_DBG( A... )
 58 #endif
 59 
 60 void hci_acl_connect(struct hci_conn *conn)
 61 {
 62         struct hci_dev *hdev = conn->hdev;
 63         struct inquiry_entry *ie;
 64         create_conn_cp cp;
 65 
 66         BT_DBG("%p", conn);
 67 
 68         conn->state = BT_CONNECT;
 69         conn->out   = 1;
 70         conn->link_mode = HCI_LM_MASTER;
 71 
 72         memset(&cp, 0, sizeof(cp));
 73         bacpy(&cp.bdaddr, &conn->dst);
 74         cp.pscan_rep_mode = 0x02;
 75 
 76         if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) &&
 77                         inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
 78                 cp.pscan_rep_mode = ie->info.pscan_rep_mode;
 79                 cp.pscan_mode     = ie->info.pscan_mode;
 80                 cp.clock_offset   = ie->info.clock_offset | __cpu_to_le16(0x8000);
 81         }
 82 
 83         cp.pkt_type = __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK);
 84         if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
 85                 cp.role_switch  = 0x01;
 86         else
 87                 cp.role_switch  = 0x00;
 88                 
 89         hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN,
 90                                 CREATE_CONN_CP_SIZE, &cp);
 91 }
 92 
 93 void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
 94 {
 95         disconnect_cp cp;
 96 
 97         BT_DBG("%p", conn);
 98 
 99         conn->state = BT_DISCONN;
100 
101         cp.handle = __cpu_to_le16(conn->handle);
102         cp.reason = reason;
103         hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT,
104                                 DISCONNECT_CP_SIZE, &cp);
105 }
106 
107 void hci_add_sco(struct hci_conn *conn, __u16 handle)
108 {
109         struct hci_dev *hdev = conn->hdev;
110         add_sco_cp cp;
111 
112         BT_DBG("%p", conn);
113 
114         conn->state = BT_CONNECT;
115         conn->out = 1;
116 
117         cp.pkt_type = __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
118         cp.handle   = __cpu_to_le16(handle);
119 
120         hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, ADD_SCO_CP_SIZE, &cp);
121 }
122 
123 static void hci_conn_timeout(unsigned long arg)
124 {
125         struct hci_conn *conn = (void *)arg;
126         struct hci_dev  *hdev = conn->hdev;
127 
128         BT_DBG("conn %p state %d", conn, conn->state);
129 
130         if (atomic_read(&conn->refcnt))
131                 return;
132 
133         hci_dev_lock(hdev);
134         if (conn->state == BT_CONNECTED)
135                 hci_acl_disconn(conn, 0x13);
136         else
137                 conn->state = BT_CLOSED;
138         hci_dev_unlock(hdev);
139         return;
140 }
141 
142 static void hci_conn_init_timer(struct hci_conn *conn)
143 {
144         init_timer(&conn->timer);
145         conn->timer.function = hci_conn_timeout;
146         conn->timer.data = (unsigned long)conn;
147 }
148 
149 struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
150 {
151         struct hci_conn *conn;
152 
153         BT_DBG("%s dst %s", hdev->name, batostr(dst));
154 
155         if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
156                 return NULL;
157         memset(conn, 0, sizeof(struct hci_conn));
158 
159         bacpy(&conn->dst, dst);
160         conn->type   = type;
161         conn->hdev   = hdev;
162         conn->state  = BT_OPEN;
163 
164         skb_queue_head_init(&conn->data_q);
165         hci_conn_init_timer(conn);
166 
167         atomic_set(&conn->refcnt, 0);
168 
169         hci_dev_hold(hdev);
170 
171         tasklet_disable(&hdev->tx_task);
172         conn_hash_add(hdev, conn);
173         tasklet_enable(&hdev->tx_task);
174 
175         return conn;
176 }
177 
178 int hci_conn_del(struct hci_conn *conn)
179 {
180         struct hci_dev  *hdev = conn->hdev;
181 
182         BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
183         
184         hci_conn_del_timer(conn);
185 
186         if (conn->type == SCO_LINK) {
187                 struct hci_conn *acl = conn->link;
188                 if (acl) {
189                         acl->link = NULL;
190                         hci_conn_put(acl);
191                 }
192         } else {
193                 struct hci_conn *sco = conn->link;
194                 if (sco)
195                         sco->link = NULL;
196 
197                 /* Unacked frames */
198                 hdev->acl_cnt += conn->sent;
199         }
200 
201         tasklet_disable(&hdev->tx_task);
202         conn_hash_del(hdev, conn);
203         tasklet_enable(&hdev->tx_task);
204 
205         skb_queue_purge(&conn->data_q);
206 
207         hci_dev_put(hdev);
208 
209         kfree(conn);
210         return 0;
211 }
212 
213 struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
214 {
215         int use_src = bacmp(src, BDADDR_ANY);
216         struct hci_dev *hdev = NULL;
217         struct list_head *p;
218 
219         BT_DBG("%s -> %s", batostr(src), batostr(dst));
220 
221         read_lock_bh(&hdev_list_lock);
222 
223         list_for_each(p, &hdev_list) {
224                 struct hci_dev *d;
225                 d = list_entry(p, struct hci_dev, list);
226                 
227                 if (!test_bit(HCI_UP, &d->flags))
228                         continue;
229 
230                 /* Simple routing: 
231                  *      No source address - find interface with bdaddr != dst 
232                  *      Source address    - find interface with bdaddr == src 
233                  */
234 
235                 if (use_src) {
236                         if (!bacmp(&d->bdaddr, src)) {
237                                 hdev = d; break;
238                         }
239                 } else {
240                         if (bacmp(&d->bdaddr, dst)) {
241                                 hdev = d; break;
242                         }
243                 }
244         }
245 
246         if (hdev)
247                 hci_dev_hold(hdev);
248 
249         read_unlock_bh(&hdev_list_lock);
250         return hdev;
251 }
252 
253 /* Create SCO or ACL connection.
254  * Device _must_ be locked */
255 struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
256 {
257         struct hci_conn *acl;
258 
259         BT_DBG("%s dst %s", hdev->name, batostr(dst));
260 
261         if (!(acl = conn_hash_lookup_ba(hdev, ACL_LINK, dst))) {
262                 if (!(acl = hci_conn_add(hdev, ACL_LINK, dst)))
263                         return NULL;
264         }
265 
266         hci_conn_hold(acl);
267 
268         if (acl->state == BT_OPEN || acl->state == BT_CLOSED)
269                 hci_acl_connect(acl);
270 
271         if (type == SCO_LINK) {
272                 struct hci_conn *sco;
273 
274                 if (!(sco = conn_hash_lookup_ba(hdev, SCO_LINK, dst))) {
275                         if (!(sco = hci_conn_add(hdev, SCO_LINK, dst))) {
276                                 hci_conn_put(acl);
277                                 return NULL;
278                         }
279                 }
280                 acl->link = sco;
281                 sco->link = acl;
282 
283                 hci_conn_hold(sco);
284 
285                 if (acl->state == BT_CONNECTED && 
286                                 (sco->state == BT_OPEN || sco->state == BT_CLOSED))
287                         hci_add_sco(sco, acl->handle);
288 
289                 return sco;
290         } else {
291                 return acl;
292         }
293 }
294 
295 /* Authenticate remote device */
296 int hci_conn_auth(struct hci_conn *conn)
297 {
298         BT_DBG("conn %p", conn);
299         
300         if (conn->link_mode & HCI_LM_AUTH)
301                 return 1;
302         
303         if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
304                 auth_requested_cp ar;
305                 ar.handle = __cpu_to_le16(conn->handle);
306                 hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED,
307                                 AUTH_REQUESTED_CP_SIZE, &ar);
308         }
309         return 0;
310 }
311 
312 /* Enable encryption */
313 int hci_conn_encrypt(struct hci_conn *conn)
314 {
315         BT_DBG("conn %p", conn);
316         
317         if (conn->link_mode & HCI_LM_ENCRYPT)
318                 return 1;
319         
320         if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
321                 return 0;
322 
323         if (hci_conn_auth(conn)) {
324                 set_conn_encrypt_cp ce;
325                 ce.handle  = __cpu_to_le16(conn->handle);
326                 ce.encrypt = 1; 
327                 hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT,
328                                 SET_CONN_ENCRYPT_CP_SIZE, &ce);
329         }
330         return 0;
331 }
332 
333 /* Drop all connection on the device */
334 void hci_conn_hash_flush(struct hci_dev *hdev)
335 {
336         struct conn_hash *h = &hdev->conn_hash;
337         struct list_head *p;
338 
339         BT_DBG("hdev %s", hdev->name);
340 
341         p = h->list.next;
342         while (p != &h->list) {
343                 struct hci_conn *c;
344 
345                 c = list_entry(p, struct hci_conn, list);
346                 p = p->next;
347 
348                 c->state = BT_CLOSED;
349 
350                 hci_proto_disconn_ind(c, 0x16);
351                 hci_conn_del(c);
352         }
353 }
354 
355 int hci_get_conn_list(unsigned long arg)
356 {
357         struct hci_conn_list_req req, *cl;
358         struct hci_conn_info *ci;
359         struct hci_dev *hdev;
360         struct list_head *p;
361         int n = 0, size, err;
362 
363         if (copy_from_user(&req, (void *) arg, sizeof(req)))
364                 return -EFAULT;
365 
366         if (!req.conn_num || req.conn_num > (PAGE_SIZE * 2) / sizeof(*ci))
367                 return -EINVAL;
368 
369         size = sizeof(req) + req.conn_num * sizeof(*ci);
370 
371         if (!(cl = (void *) kmalloc(size, GFP_KERNEL)))
372                 return -ENOMEM;
373 
374         if (!(hdev = hci_dev_get(req.dev_id))) {
375                 kfree(cl);
376                 return -ENODEV;
377         }
378 
379         ci = cl->conn_info;
380 
381         hci_dev_lock_bh(hdev);
382         list_for_each(p, &hdev->conn_hash.list) {
383                 register struct hci_conn *c;
384                 c = list_entry(p, struct hci_conn, list);
385 
386                 bacpy(&(ci + n)->bdaddr, &c->dst);
387                 (ci + n)->handle = c->handle;
388                 (ci + n)->type  = c->type;
389                 (ci + n)->out   = c->out;
390                 (ci + n)->state = c->state;
391                 (ci + n)->link_mode = c->link_mode;
392                 if (++n >= req.conn_num)
393                         break;
394         }
395         hci_dev_unlock_bh(hdev);
396 
397         cl->dev_id = hdev->id;
398         cl->conn_num = n;
399         size = sizeof(req) + n * sizeof(*ci);
400 
401         hci_dev_put(hdev);
402 
403         err = copy_to_user((void *) arg, cl, size);
404         kfree(cl);
405 
406         return err ? -EFAULT : 0;
407 }
408 
409 int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg)
410 {
411         struct hci_conn_info_req req;
412         struct hci_conn_info ci;
413         struct hci_conn *conn;
414         char *ptr = (void *) arg + sizeof(req);
415 
416         if (copy_from_user(&req, (void *) arg, sizeof(req)))
417                 return -EFAULT;
418 
419         hci_dev_lock_bh(hdev);
420         conn = conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
421         if (conn) {
422                 bacpy(&ci.bdaddr, &conn->dst);
423                 ci.handle = conn->handle;
424                 ci.type  = conn->type;
425                 ci.out   = conn->out;
426                 ci.state = conn->state;
427                 ci.link_mode = conn->link_mode;
428         }
429         hci_dev_unlock_bh(hdev);
430 
431         if (!conn)
432                 return -ENOENT;
433 
434         return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0;
435 }
436 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp