xref: /dragonfly/sys/netbt/hci_misc.c (revision febebf837b1267101987c1c8945f3e9e9e1df7c8)
1 /* $OpenBSD: src/sys/netbt/hci_misc.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */
2 /* $NetBSD: hci_misc.c,v 1.3 2007/09/16 19:59:30 plunky Exp $ */
3 
4 /*-
5  * Copyright (c) 2005 Iain Hibbert.
6  * Copyright (c) 2006 Itronix Inc.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The name of Itronix Inc. may not be used to endorse
18  *    or promote products derived from this software without specific
19  *    prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28  * ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/mbuf.h>
38 #include <sys/proc.h>
39 #include <sys/queue.h>
40 #include <sys/systm.h>
41 
42 #include <netbt/bluetooth.h>
43 #include <netbt/hci.h>
44 
45 /*
46  * cache Inquiry Responses for this number of seconds for routing
47  * purposes [sysctl]
48  */
49 int hci_memo_expiry = 600;
50 
51 /*
52  * set 'src' address for routing to 'dest'
53  */
54 int
hci_route_lookup(bdaddr_t * src,bdaddr_t * dest)55 hci_route_lookup(bdaddr_t *src, bdaddr_t *dest)
56 {
57           struct hci_unit *unit;
58           struct hci_link *link;
59           struct hci_memo *memo;
60 
61           /*
62            * Walk the ACL connections, if we have a connection
63            * to 'dest' already then thats best..
64            */
65           TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
66                     if ((unit->hci_flags & BTF_UP) == 0)
67                               continue;
68 
69                     TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
70                               if (link->hl_type != HCI_LINK_ACL)
71                                         continue;
72 
73                               if (bdaddr_same(&link->hl_bdaddr, dest))
74                                         goto found;
75                     }
76           }
77 
78           /*
79            * Now check all the memos to see if there has been an
80            * inquiry repsonse..
81            */
82           TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
83                     if ((unit->hci_flags & BTF_UP) == 0)
84                               continue;
85 
86                     memo = hci_memo_find(unit, dest);
87                     if (memo)
88                               goto found;
89           }
90 
91           /*
92            * Last ditch effort, lets use the first unit we find
93            * thats up and running. (XXX settable default route?)
94            */
95           TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
96                     if ((unit->hci_flags & BTF_UP) == 0)
97                               continue;
98 
99                     goto found;
100           }
101 
102           return EHOSTUNREACH;
103 
104 found:
105           bdaddr_copy(src, &unit->hci_bdaddr);
106           return 0;
107 }
108 
109 /*
110  * find unit memo from bdaddr
111  */
112 struct hci_memo *
hci_memo_find(struct hci_unit * unit,bdaddr_t * bdaddr)113 hci_memo_find(struct hci_unit *unit, bdaddr_t *bdaddr)
114 {
115           struct hci_memo *memo, *m0;
116           struct timeval now;
117 
118           microtime(&now);
119 
120           m0 = LIST_FIRST(&unit->hci_memos);
121           while ((memo = m0) != NULL) {
122                     m0 = LIST_NEXT(memo, next);
123 
124                     if (now.tv_sec > memo->time.tv_sec + hci_memo_expiry) {
125                               DPRINTF("memo %p too old (expiring)\n", memo);
126                               hci_memo_free(memo);
127                               continue;
128                     }
129 
130                     if (bdaddr_same(bdaddr, &memo->bdaddr)) {
131                               DPRINTF("memo %p found\n", memo);
132                               return memo;
133                     }
134           }
135 
136           DPRINTF("no memo found\n");
137           return NULL;
138 }
139 
140 /*
141  * Make a new memo on unit for bdaddr. If a memo exists, just
142  * update the timestamp.
143  */
144 struct hci_memo *
hci_memo_new(struct hci_unit * unit,bdaddr_t * bdaddr)145 hci_memo_new(struct hci_unit *unit, bdaddr_t *bdaddr)
146 {
147           struct hci_memo *memo;
148 
149           memo = hci_memo_find(unit, bdaddr);
150           if (memo == NULL) {
151                     memo = kmalloc(sizeof(struct hci_memo),
152                               M_BLUETOOTH, M_NOWAIT | M_ZERO);
153 
154                     if (memo == NULL) {
155                               DPRINTFN(0, "no memory for memo!\n");
156                               return NULL;
157                     }
158 
159                     DPRINTF("memo created for %02x:%02x:%02x:%02x:%02x:%02x\n",
160                               bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
161                               bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
162 
163                     bdaddr_copy(&memo->bdaddr, bdaddr);
164                     LIST_INSERT_HEAD(&unit->hci_memos, memo, next);
165           }
166           else
167                     DPRINTF("memo updated for %02x:%02x:%02x:%02x:%02x:%02x\n",
168                               bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
169                               bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
170 
171           microtime(&memo->time);
172           return memo;
173 }
174 
175 void
hci_memo_free(struct hci_memo * memo)176 hci_memo_free(struct hci_memo *memo)
177 {
178 
179           LIST_REMOVE(memo, next);
180           kfree(memo, M_BLUETOOTH);
181 }
182