1*83aacedeSHasso Tepper /* $OpenBSD: src/sys/netbt/hci_misc.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */
2*83aacedeSHasso Tepper /* $NetBSD: hci_misc.c,v 1.3 2007/09/16 19:59:30 plunky Exp $ */
30a9108ebSHasso Tepper
40a9108ebSHasso Tepper /*-
50a9108ebSHasso Tepper * Copyright (c) 2005 Iain Hibbert.
60a9108ebSHasso Tepper * Copyright (c) 2006 Itronix Inc.
70a9108ebSHasso Tepper * All rights reserved.
80a9108ebSHasso Tepper *
90a9108ebSHasso Tepper * Redistribution and use in source and binary forms, with or without
100a9108ebSHasso Tepper * modification, are permitted provided that the following conditions
110a9108ebSHasso Tepper * are met:
120a9108ebSHasso Tepper * 1. Redistributions of source code must retain the above copyright
130a9108ebSHasso Tepper * notice, this list of conditions and the following disclaimer.
140a9108ebSHasso Tepper * 2. Redistributions in binary form must reproduce the above copyright
150a9108ebSHasso Tepper * notice, this list of conditions and the following disclaimer in the
160a9108ebSHasso Tepper * documentation and/or other materials provided with the distribution.
170a9108ebSHasso Tepper * 3. The name of Itronix Inc. may not be used to endorse
180a9108ebSHasso Tepper * or promote products derived from this software without specific
190a9108ebSHasso Tepper * prior written permission.
200a9108ebSHasso Tepper *
210a9108ebSHasso Tepper * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
220a9108ebSHasso Tepper * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
230a9108ebSHasso Tepper * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
240a9108ebSHasso Tepper * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
250a9108ebSHasso Tepper * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
260a9108ebSHasso Tepper * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
270a9108ebSHasso Tepper * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
280a9108ebSHasso Tepper * ON ANY THEORY OF LIABILITY, WHETHER IN
290a9108ebSHasso Tepper * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
300a9108ebSHasso Tepper * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
310a9108ebSHasso Tepper * POSSIBILITY OF SUCH DAMAGE.
320a9108ebSHasso Tepper */
330a9108ebSHasso Tepper
340a9108ebSHasso Tepper #include <sys/param.h>
350a9108ebSHasso Tepper #include <sys/kernel.h>
360a9108ebSHasso Tepper #include <sys/malloc.h>
370a9108ebSHasso Tepper #include <sys/mbuf.h>
380a9108ebSHasso Tepper #include <sys/proc.h>
390a9108ebSHasso Tepper #include <sys/queue.h>
400a9108ebSHasso Tepper #include <sys/systm.h>
410a9108ebSHasso Tepper
420a9108ebSHasso Tepper #include <netbt/bluetooth.h>
430a9108ebSHasso Tepper #include <netbt/hci.h>
440a9108ebSHasso Tepper
450a9108ebSHasso Tepper /*
460a9108ebSHasso Tepper * cache Inquiry Responses for this number of seconds for routing
470a9108ebSHasso Tepper * purposes [sysctl]
480a9108ebSHasso Tepper */
490a9108ebSHasso Tepper int hci_memo_expiry = 600;
500a9108ebSHasso Tepper
510a9108ebSHasso Tepper /*
520a9108ebSHasso Tepper * set 'src' address for routing to 'dest'
530a9108ebSHasso Tepper */
540a9108ebSHasso Tepper int
hci_route_lookup(bdaddr_t * src,bdaddr_t * dest)550a9108ebSHasso Tepper hci_route_lookup(bdaddr_t *src, bdaddr_t *dest)
560a9108ebSHasso Tepper {
570a9108ebSHasso Tepper struct hci_unit *unit;
580a9108ebSHasso Tepper struct hci_link *link;
590a9108ebSHasso Tepper struct hci_memo *memo;
600a9108ebSHasso Tepper
610a9108ebSHasso Tepper /*
620a9108ebSHasso Tepper * Walk the ACL connections, if we have a connection
630a9108ebSHasso Tepper * to 'dest' already then thats best..
640a9108ebSHasso Tepper */
650a9108ebSHasso Tepper TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
660a9108ebSHasso Tepper if ((unit->hci_flags & BTF_UP) == 0)
670a9108ebSHasso Tepper continue;
680a9108ebSHasso Tepper
690a9108ebSHasso Tepper TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
700a9108ebSHasso Tepper if (link->hl_type != HCI_LINK_ACL)
710a9108ebSHasso Tepper continue;
720a9108ebSHasso Tepper
730a9108ebSHasso Tepper if (bdaddr_same(&link->hl_bdaddr, dest))
740a9108ebSHasso Tepper goto found;
750a9108ebSHasso Tepper }
760a9108ebSHasso Tepper }
770a9108ebSHasso Tepper
780a9108ebSHasso Tepper /*
790a9108ebSHasso Tepper * Now check all the memos to see if there has been an
800a9108ebSHasso Tepper * inquiry repsonse..
810a9108ebSHasso Tepper */
820a9108ebSHasso Tepper TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
830a9108ebSHasso Tepper if ((unit->hci_flags & BTF_UP) == 0)
840a9108ebSHasso Tepper continue;
850a9108ebSHasso Tepper
860a9108ebSHasso Tepper memo = hci_memo_find(unit, dest);
870a9108ebSHasso Tepper if (memo)
880a9108ebSHasso Tepper goto found;
890a9108ebSHasso Tepper }
900a9108ebSHasso Tepper
910a9108ebSHasso Tepper /*
920a9108ebSHasso Tepper * Last ditch effort, lets use the first unit we find
930a9108ebSHasso Tepper * thats up and running. (XXX settable default route?)
940a9108ebSHasso Tepper */
950a9108ebSHasso Tepper TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
960a9108ebSHasso Tepper if ((unit->hci_flags & BTF_UP) == 0)
970a9108ebSHasso Tepper continue;
980a9108ebSHasso Tepper
990a9108ebSHasso Tepper goto found;
1000a9108ebSHasso Tepper }
1010a9108ebSHasso Tepper
1020a9108ebSHasso Tepper return EHOSTUNREACH;
1030a9108ebSHasso Tepper
1040a9108ebSHasso Tepper found:
1050a9108ebSHasso Tepper bdaddr_copy(src, &unit->hci_bdaddr);
1060a9108ebSHasso Tepper return 0;
1070a9108ebSHasso Tepper }
1080a9108ebSHasso Tepper
1090a9108ebSHasso Tepper /*
1100a9108ebSHasso Tepper * find unit memo from bdaddr
1110a9108ebSHasso Tepper */
1120a9108ebSHasso Tepper struct hci_memo *
hci_memo_find(struct hci_unit * unit,bdaddr_t * bdaddr)1130a9108ebSHasso Tepper hci_memo_find(struct hci_unit *unit, bdaddr_t *bdaddr)
1140a9108ebSHasso Tepper {
1150a9108ebSHasso Tepper struct hci_memo *memo, *m0;
1160a9108ebSHasso Tepper struct timeval now;
1170a9108ebSHasso Tepper
1180a9108ebSHasso Tepper microtime(&now);
1190a9108ebSHasso Tepper
1200a9108ebSHasso Tepper m0 = LIST_FIRST(&unit->hci_memos);
1210a9108ebSHasso Tepper while ((memo = m0) != NULL) {
1220a9108ebSHasso Tepper m0 = LIST_NEXT(memo, next);
1230a9108ebSHasso Tepper
1240a9108ebSHasso Tepper if (now.tv_sec > memo->time.tv_sec + hci_memo_expiry) {
1250a9108ebSHasso Tepper DPRINTF("memo %p too old (expiring)\n", memo);
1260a9108ebSHasso Tepper hci_memo_free(memo);
1270a9108ebSHasso Tepper continue;
1280a9108ebSHasso Tepper }
1290a9108ebSHasso Tepper
130*83aacedeSHasso Tepper if (bdaddr_same(bdaddr, &memo->bdaddr)) {
1310a9108ebSHasso Tepper DPRINTF("memo %p found\n", memo);
1320a9108ebSHasso Tepper return memo;
1330a9108ebSHasso Tepper }
1340a9108ebSHasso Tepper }
1350a9108ebSHasso Tepper
1360a9108ebSHasso Tepper DPRINTF("no memo found\n");
1370a9108ebSHasso Tepper return NULL;
1380a9108ebSHasso Tepper }
1390a9108ebSHasso Tepper
140*83aacedeSHasso Tepper /*
141*83aacedeSHasso Tepper * Make a new memo on unit for bdaddr. If a memo exists, just
142*83aacedeSHasso Tepper * update the timestamp.
143*83aacedeSHasso Tepper */
144*83aacedeSHasso Tepper struct hci_memo *
hci_memo_new(struct hci_unit * unit,bdaddr_t * bdaddr)145*83aacedeSHasso Tepper hci_memo_new(struct hci_unit *unit, bdaddr_t *bdaddr)
146*83aacedeSHasso Tepper {
147*83aacedeSHasso Tepper struct hci_memo *memo;
148*83aacedeSHasso Tepper
149*83aacedeSHasso Tepper memo = hci_memo_find(unit, bdaddr);
150*83aacedeSHasso Tepper if (memo == NULL) {
151*83aacedeSHasso Tepper memo = kmalloc(sizeof(struct hci_memo),
152*83aacedeSHasso Tepper M_BLUETOOTH, M_NOWAIT | M_ZERO);
153*83aacedeSHasso Tepper
154*83aacedeSHasso Tepper if (memo == NULL) {
155*83aacedeSHasso Tepper DPRINTFN(0, "no memory for memo!\n");
156*83aacedeSHasso Tepper return NULL;
157*83aacedeSHasso Tepper }
158*83aacedeSHasso Tepper
159*83aacedeSHasso Tepper DPRINTF("memo created for %02x:%02x:%02x:%02x:%02x:%02x\n",
160*83aacedeSHasso Tepper bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
161*83aacedeSHasso Tepper bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
162*83aacedeSHasso Tepper
163*83aacedeSHasso Tepper bdaddr_copy(&memo->bdaddr, bdaddr);
164*83aacedeSHasso Tepper LIST_INSERT_HEAD(&unit->hci_memos, memo, next);
165*83aacedeSHasso Tepper }
166*83aacedeSHasso Tepper else
167*83aacedeSHasso Tepper DPRINTF("memo updated for %02x:%02x:%02x:%02x:%02x:%02x\n",
168*83aacedeSHasso Tepper bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
169*83aacedeSHasso Tepper bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
170*83aacedeSHasso Tepper
171*83aacedeSHasso Tepper microtime(&memo->time);
172*83aacedeSHasso Tepper return memo;
173*83aacedeSHasso Tepper }
174*83aacedeSHasso Tepper
1750a9108ebSHasso Tepper void
hci_memo_free(struct hci_memo * memo)1760a9108ebSHasso Tepper hci_memo_free(struct hci_memo *memo)
1770a9108ebSHasso Tepper {
1780a9108ebSHasso Tepper
1790a9108ebSHasso Tepper LIST_REMOVE(memo, next);
1800a9108ebSHasso Tepper kfree(memo, M_BLUETOOTH);
1810a9108ebSHasso Tepper }
182