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