xref: /dragonfly/sys/netbt/hci_misc.c (revision 63e03116)
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
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 *
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 *
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
176 hci_memo_free(struct hci_memo *memo)
177 {
178 
179 	LIST_REMOVE(memo, next);
180 	kfree(memo, M_BLUETOOTH);
181 }
182