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