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