1 1.48 rin /* $NetBSD: hci_socket.c,v 1.48 2024/07/05 04:31:53 rin Exp $ */ 2 1.1 gdamore 3 1.1 gdamore /*- 4 1.1 gdamore * Copyright (c) 2005 Iain Hibbert. 5 1.1 gdamore * Copyright (c) 2006 Itronix Inc. 6 1.1 gdamore * All rights reserved. 7 1.1 gdamore * 8 1.1 gdamore * Redistribution and use in source and binary forms, with or without 9 1.1 gdamore * modification, are permitted provided that the following conditions 10 1.1 gdamore * are met: 11 1.1 gdamore * 1. Redistributions of source code must retain the above copyright 12 1.1 gdamore * notice, this list of conditions and the following disclaimer. 13 1.1 gdamore * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 gdamore * notice, this list of conditions and the following disclaimer in the 15 1.1 gdamore * documentation and/or other materials provided with the distribution. 16 1.1 gdamore * 3. The name of Itronix Inc. may not be used to endorse 17 1.1 gdamore * or promote products derived from this software without specific 18 1.1 gdamore * prior written permission. 19 1.1 gdamore * 20 1.1 gdamore * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 21 1.1 gdamore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.1 gdamore * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.1 gdamore * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 24 1.1 gdamore * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 1.1 gdamore * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 1.1 gdamore * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 1.1 gdamore * ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.1 gdamore * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.1 gdamore * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.1 gdamore * POSSIBILITY OF SUCH DAMAGE. 31 1.1 gdamore */ 32 1.1 gdamore 33 1.1 gdamore #include <sys/cdefs.h> 34 1.48 rin __KERNEL_RCSID(0, "$NetBSD: hci_socket.c,v 1.48 2024/07/05 04:31:53 rin Exp $"); 35 1.1 gdamore 36 1.10 plunky /* load symbolic names */ 37 1.1 gdamore #ifdef BLUETOOTH_DEBUG 38 1.10 plunky #define PRUREQUESTS 39 1.1 gdamore #define PRCOREQUESTS 40 1.1 gdamore #endif 41 1.1 gdamore 42 1.1 gdamore #include <sys/param.h> 43 1.1 gdamore #include <sys/domain.h> 44 1.1 gdamore #include <sys/kauth.h> 45 1.1 gdamore #include <sys/kernel.h> 46 1.22 rmind #include <sys/kmem.h> 47 1.1 gdamore #include <sys/mbuf.h> 48 1.1 gdamore #include <sys/proc.h> 49 1.1 gdamore #include <sys/protosw.h> 50 1.1 gdamore #include <sys/socket.h> 51 1.1 gdamore #include <sys/socketvar.h> 52 1.1 gdamore #include <sys/systm.h> 53 1.1 gdamore 54 1.1 gdamore #include <netbt/bluetooth.h> 55 1.1 gdamore #include <netbt/hci.h> 56 1.1 gdamore 57 1.1 gdamore /******************************************************************************* 58 1.1 gdamore * 59 1.1 gdamore * HCI SOCK_RAW Sockets - for control of Bluetooth Devices 60 1.1 gdamore * 61 1.1 gdamore */ 62 1.1 gdamore 63 1.1 gdamore /* 64 1.1 gdamore * the raw HCI protocol control block 65 1.1 gdamore */ 66 1.1 gdamore struct hci_pcb { 67 1.1 gdamore struct socket *hp_socket; /* socket */ 68 1.18 plunky kauth_cred_t hp_cred; /* owner credential */ 69 1.1 gdamore unsigned int hp_flags; /* flags */ 70 1.1 gdamore bdaddr_t hp_laddr; /* local address */ 71 1.1 gdamore bdaddr_t hp_raddr; /* remote address */ 72 1.1 gdamore struct hci_filter hp_efilter; /* user event filter */ 73 1.1 gdamore struct hci_filter hp_pfilter; /* user packet filter */ 74 1.1 gdamore LIST_ENTRY(hci_pcb) hp_next; /* next HCI pcb */ 75 1.1 gdamore }; 76 1.1 gdamore 77 1.1 gdamore /* hp_flags */ 78 1.1 gdamore #define HCI_DIRECTION (1<<1) /* direction control messages */ 79 1.1 gdamore #define HCI_PROMISCUOUS (1<<2) /* listen to all units */ 80 1.1 gdamore 81 1.1 gdamore LIST_HEAD(hci_pcb_list, hci_pcb) hci_pcb = LIST_HEAD_INITIALIZER(hci_pcb); 82 1.1 gdamore 83 1.1 gdamore /* sysctl defaults */ 84 1.1 gdamore int hci_sendspace = HCI_CMD_PKT_SIZE; 85 1.1 gdamore int hci_recvspace = 4096; 86 1.1 gdamore 87 1.18 plunky /* unprivileged commands opcode table */ 88 1.13 plunky static const struct { 89 1.13 plunky uint16_t opcode; 90 1.13 plunky uint8_t offs; /* 0 - 63 */ 91 1.13 plunky uint8_t mask; /* bit 0 - 7 */ 92 1.18 plunky uint8_t length; /* approved length */ 93 1.13 plunky } hci_cmds[] = { 94 1.13 plunky { HCI_CMD_INQUIRY, 95 1.13 plunky 0, 0x01, sizeof(hci_inquiry_cp) }, 96 1.13 plunky { HCI_CMD_REMOTE_NAME_REQ, 97 1.13 plunky 2, 0x08, sizeof(hci_remote_name_req_cp) }, 98 1.13 plunky { HCI_CMD_READ_REMOTE_FEATURES, 99 1.13 plunky 2, 0x20, sizeof(hci_read_remote_features_cp) }, 100 1.13 plunky { HCI_CMD_READ_REMOTE_EXTENDED_FEATURES, 101 1.13 plunky 2, 0x40, sizeof(hci_read_remote_extended_features_cp) }, 102 1.13 plunky { HCI_CMD_READ_REMOTE_VER_INFO, 103 1.13 plunky 2, 0x80, sizeof(hci_read_remote_ver_info_cp) }, 104 1.13 plunky { HCI_CMD_READ_CLOCK_OFFSET, 105 1.13 plunky 3, 0x01, sizeof(hci_read_clock_offset_cp) }, 106 1.13 plunky { HCI_CMD_READ_LMP_HANDLE, 107 1.13 plunky 3, 0x02, sizeof(hci_read_lmp_handle_cp) }, 108 1.13 plunky { HCI_CMD_ROLE_DISCOVERY, 109 1.13 plunky 4, 0x80, sizeof(hci_role_discovery_cp) }, 110 1.13 plunky { HCI_CMD_READ_LINK_POLICY_SETTINGS, 111 1.13 plunky 5, 0x02, sizeof(hci_read_link_policy_settings_cp) }, 112 1.13 plunky { HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS, 113 1.13 plunky 5, 0x08, 0 }, 114 1.13 plunky { HCI_CMD_READ_PIN_TYPE, 115 1.13 plunky 6, 0x04, 0 }, 116 1.13 plunky { HCI_CMD_READ_LOCAL_NAME, 117 1.13 plunky 7, 0x02, 0 }, 118 1.13 plunky { HCI_CMD_READ_CON_ACCEPT_TIMEOUT, 119 1.13 plunky 7, 0x04, 0 }, 120 1.13 plunky { HCI_CMD_READ_PAGE_TIMEOUT, 121 1.13 plunky 7, 0x10, 0 }, 122 1.13 plunky { HCI_CMD_READ_SCAN_ENABLE, 123 1.13 plunky 7, 0x40, 0 }, 124 1.13 plunky { HCI_CMD_READ_PAGE_SCAN_ACTIVITY, 125 1.13 plunky 8, 0x01, 0 }, 126 1.13 plunky { HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY, 127 1.13 plunky 8, 0x04, 0 }, 128 1.13 plunky { HCI_CMD_READ_AUTH_ENABLE, 129 1.13 plunky 8, 0x10, 0 }, 130 1.13 plunky { HCI_CMD_READ_ENCRYPTION_MODE, 131 1.13 plunky 8, 0x40, 0 }, 132 1.13 plunky { HCI_CMD_READ_UNIT_CLASS, 133 1.13 plunky 9, 0x01, 0 }, 134 1.13 plunky { HCI_CMD_READ_VOICE_SETTING, 135 1.13 plunky 9, 0x04, 0 }, 136 1.13 plunky { HCI_CMD_READ_AUTO_FLUSH_TIMEOUT, 137 1.13 plunky 9, 0x10, sizeof(hci_read_auto_flush_timeout_cp) }, 138 1.13 plunky { HCI_CMD_READ_NUM_BROADCAST_RETRANS, 139 1.13 plunky 9, 0x40, 0 }, 140 1.13 plunky { HCI_CMD_READ_HOLD_MODE_ACTIVITY, 141 1.13 plunky 10, 0x01, 0 }, 142 1.13 plunky { HCI_CMD_READ_XMIT_LEVEL, 143 1.13 plunky 10, 0x04, sizeof(hci_read_xmit_level_cp) }, 144 1.13 plunky { HCI_CMD_READ_SCO_FLOW_CONTROL, 145 1.13 plunky 10, 0x08, 0 }, 146 1.13 plunky { HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT, 147 1.13 plunky 11, 0x01, sizeof(hci_read_link_supervision_timeout_cp) }, 148 1.13 plunky { HCI_CMD_READ_NUM_SUPPORTED_IAC, 149 1.13 plunky 11, 0x04, 0 }, 150 1.13 plunky { HCI_CMD_READ_IAC_LAP, 151 1.13 plunky 11, 0x08, 0 }, 152 1.13 plunky { HCI_CMD_READ_PAGE_SCAN_PERIOD, 153 1.13 plunky 11, 0x20, 0 }, 154 1.13 plunky { HCI_CMD_READ_PAGE_SCAN, 155 1.13 plunky 11, 0x80, 0 }, 156 1.13 plunky { HCI_CMD_READ_INQUIRY_SCAN_TYPE, 157 1.13 plunky 12, 0x10, 0 }, 158 1.13 plunky { HCI_CMD_READ_INQUIRY_MODE, 159 1.13 plunky 12, 0x40, 0 }, 160 1.13 plunky { HCI_CMD_READ_PAGE_SCAN_TYPE, 161 1.13 plunky 13, 0x01, 0 }, 162 1.13 plunky { HCI_CMD_READ_AFH_ASSESSMENT, 163 1.13 plunky 13, 0x04, 0 }, 164 1.13 plunky { HCI_CMD_READ_LOCAL_VER, 165 1.13 plunky 14, 0x08, 0 }, 166 1.13 plunky { HCI_CMD_READ_LOCAL_COMMANDS, 167 1.13 plunky 14, 0x10, 0 }, 168 1.13 plunky { HCI_CMD_READ_LOCAL_FEATURES, 169 1.13 plunky 14, 0x20, 0 }, 170 1.13 plunky { HCI_CMD_READ_LOCAL_EXTENDED_FEATURES, 171 1.13 plunky 14, 0x40, sizeof(hci_read_local_extended_features_cp) }, 172 1.13 plunky { HCI_CMD_READ_BUFFER_SIZE, 173 1.13 plunky 14, 0x80, 0 }, 174 1.13 plunky { HCI_CMD_READ_COUNTRY_CODE, 175 1.13 plunky 15, 0x01, 0 }, 176 1.13 plunky { HCI_CMD_READ_BDADDR, 177 1.13 plunky 15, 0x02, 0 }, 178 1.13 plunky { HCI_CMD_READ_FAILED_CONTACT_CNTR, 179 1.13 plunky 15, 0x04, sizeof(hci_read_failed_contact_cntr_cp) }, 180 1.13 plunky { HCI_CMD_READ_LINK_QUALITY, 181 1.13 plunky 15, 0x10, sizeof(hci_read_link_quality_cp) }, 182 1.13 plunky { HCI_CMD_READ_RSSI, 183 1.13 plunky 15, 0x20, sizeof(hci_read_rssi_cp) }, 184 1.13 plunky { HCI_CMD_READ_AFH_CHANNEL_MAP, 185 1.13 plunky 15, 0x40, sizeof(hci_read_afh_channel_map_cp) }, 186 1.13 plunky { HCI_CMD_READ_CLOCK, 187 1.13 plunky 15, 0x80, sizeof(hci_read_clock_cp) }, 188 1.13 plunky { HCI_CMD_READ_LOOPBACK_MODE, 189 1.13 plunky 16, 0x01, 0 }, 190 1.14 plunky { HCI_CMD_READ_EXTENDED_INQUIRY_RSP, 191 1.14 plunky 17, 0x01, 0 }, 192 1.14 plunky { HCI_CMD_READ_SIMPLE_PAIRING_MODE, 193 1.14 plunky 17, 0x20, 0 }, 194 1.14 plunky { HCI_CMD_READ_INQUIRY_RSP_XMIT_POWER, 195 1.14 plunky 18, 0x01, 0 }, 196 1.14 plunky { HCI_CMD_READ_DEFAULT_ERRDATA_REPORTING, 197 1.14 plunky 18, 0x04, 0 }, 198 1.47 plunky { HCI_CMD_READ_ENCRYPTION_KEY_SIZE, 199 1.47 plunky 20, 0x10, sizeof(hci_read_encryption_key_size_cp) }, 200 1.13 plunky }; 201 1.13 plunky 202 1.1 gdamore /* 203 1.18 plunky * supply a basic device send/recv policy 204 1.1 gdamore */ 205 1.4 plunky static int 206 1.18 plunky hci_device_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, 207 1.18 plunky void *arg0, void *arg1, void *arg2, void *arg3) 208 1.1 gdamore { 209 1.18 plunky int i, result; 210 1.18 plunky 211 1.18 plunky result = KAUTH_RESULT_DEFER; 212 1.18 plunky 213 1.18 plunky switch (action) { 214 1.19 plunky case KAUTH_DEVICE_BLUETOOTH_SEND: { 215 1.18 plunky struct hci_unit *unit = (struct hci_unit *)arg0; 216 1.18 plunky hci_cmd_hdr_t *hdr = (hci_cmd_hdr_t *)arg1; 217 1.18 plunky 218 1.18 plunky /* 219 1.18 plunky * Allow sending unprivileged commands if the packet size 220 1.18 plunky * is correct and the unit claims to support it 221 1.18 plunky */ 222 1.18 plunky 223 1.19 plunky if (hdr->type != HCI_CMD_PKT) 224 1.19 plunky break; 225 1.19 plunky 226 1.18 plunky for (i = 0; i < __arraycount(hci_cmds); i++) { 227 1.18 plunky if (hdr->opcode == hci_cmds[i].opcode 228 1.18 plunky && hdr->length == hci_cmds[i].length 229 1.18 plunky && (unit->hci_cmds[hci_cmds[i].offs] & hci_cmds[i].mask)) { 230 1.18 plunky result = KAUTH_RESULT_ALLOW; 231 1.18 plunky break; 232 1.18 plunky } 233 1.18 plunky } 234 1.18 plunky 235 1.18 plunky break; 236 1.18 plunky } 237 1.18 plunky 238 1.19 plunky case KAUTH_DEVICE_BLUETOOTH_RECV: 239 1.19 plunky switch((uint8_t)(uintptr_t)arg0) { 240 1.19 plunky case HCI_CMD_PKT: { 241 1.19 plunky uint16_t opcode = (uint16_t)(uintptr_t)arg1; 242 1.19 plunky 243 1.19 plunky /* 244 1.19 plunky * Allow to see any unprivileged command packet 245 1.19 plunky */ 246 1.19 plunky 247 1.19 plunky for (i = 0; i < __arraycount(hci_cmds); i++) { 248 1.19 plunky if (opcode == hci_cmds[i].opcode) { 249 1.19 plunky result = KAUTH_RESULT_ALLOW; 250 1.19 plunky break; 251 1.19 plunky } 252 1.19 plunky } 253 1.19 plunky 254 1.19 plunky break; 255 1.19 plunky } 256 1.19 plunky 257 1.19 plunky case HCI_EVENT_PKT: { 258 1.19 plunky uint8_t event = (uint8_t)(uintptr_t)arg1; 259 1.18 plunky 260 1.19 plunky /* 261 1.19 plunky * Allow to receive most events 262 1.19 plunky */ 263 1.19 plunky 264 1.19 plunky switch (event) { 265 1.19 plunky case HCI_EVENT_RETURN_LINK_KEYS: 266 1.19 plunky case HCI_EVENT_LINK_KEY_NOTIFICATION: 267 1.19 plunky case HCI_EVENT_USER_CONFIRM_REQ: 268 1.19 plunky case HCI_EVENT_USER_PASSKEY_NOTIFICATION: 269 1.19 plunky case HCI_EVENT_VENDOR: 270 1.19 plunky break; 271 1.18 plunky 272 1.19 plunky default: 273 1.18 plunky result = KAUTH_RESULT_ALLOW; 274 1.18 plunky break; 275 1.18 plunky } 276 1.18 plunky 277 1.19 plunky break; 278 1.19 plunky } 279 1.18 plunky 280 1.19 plunky case HCI_ACL_DATA_PKT: 281 1.19 plunky case HCI_SCO_DATA_PKT: { 282 1.19 plunky /* uint16_t handle = (uint16_t)(uintptr_t)arg1; */ 283 1.19 plunky /* 284 1.19 plunky * don't normally allow receiving data packets 285 1.19 plunky */ 286 1.18 plunky break; 287 1.19 plunky } 288 1.18 plunky 289 1.18 plunky default: 290 1.18 plunky break; 291 1.18 plunky } 292 1.13 plunky 293 1.18 plunky break; 294 1.18 plunky 295 1.18 plunky default: 296 1.13 plunky break; 297 1.4 plunky } 298 1.1 gdamore 299 1.18 plunky return result; 300 1.1 gdamore } 301 1.1 gdamore 302 1.18 plunky /* 303 1.18 plunky * HCI protocol init routine, 304 1.18 plunky * - set up a kauth listener to provide basic packet access policy 305 1.18 plunky */ 306 1.18 plunky void 307 1.18 plunky hci_init(void) 308 1.1 gdamore { 309 1.1 gdamore 310 1.18 plunky if (kauth_listen_scope(KAUTH_SCOPE_DEVICE, hci_device_cb, NULL) == NULL) 311 1.18 plunky panic("Bluetooth HCI: cannot listen on device scope"); 312 1.1 gdamore } 313 1.1 gdamore 314 1.1 gdamore /* 315 1.1 gdamore * When command packet reaches the device, we can drop 316 1.1 gdamore * it from the socket buffer (called from hci_output_acl) 317 1.1 gdamore */ 318 1.1 gdamore void 319 1.1 gdamore hci_drop(void *arg) 320 1.1 gdamore { 321 1.1 gdamore struct socket *so = arg; 322 1.1 gdamore 323 1.1 gdamore sbdroprecord(&so->so_snd); 324 1.1 gdamore sowwakeup(so); 325 1.1 gdamore } 326 1.1 gdamore 327 1.1 gdamore /* 328 1.1 gdamore * HCI socket is going away and has some pending packets. We let them 329 1.1 gdamore * go by design, but remove the context pointer as it will be invalid 330 1.1 gdamore * and we no longer need to be notified. 331 1.1 gdamore */ 332 1.1 gdamore static void 333 1.1 gdamore hci_cmdwait_flush(struct socket *so) 334 1.1 gdamore { 335 1.1 gdamore struct hci_unit *unit; 336 1.1 gdamore struct socket *ctx; 337 1.1 gdamore struct mbuf *m; 338 1.1 gdamore 339 1.1 gdamore DPRINTF("flushing %p\n", so); 340 1.1 gdamore 341 1.1 gdamore SIMPLEQ_FOREACH(unit, &hci_unit_list, hci_next) { 342 1.1 gdamore m = MBUFQ_FIRST(&unit->hci_cmdwait); 343 1.1 gdamore while (m != NULL) { 344 1.1 gdamore ctx = M_GETCTX(m, struct socket *); 345 1.1 gdamore if (ctx == so) 346 1.1 gdamore M_SETCTX(m, NULL); 347 1.1 gdamore 348 1.1 gdamore m = MBUFQ_NEXT(m); 349 1.1 gdamore } 350 1.1 gdamore } 351 1.1 gdamore } 352 1.1 gdamore 353 1.22 rmind static int 354 1.23 rmind hci_attach(struct socket *so, int proto) 355 1.22 rmind { 356 1.22 rmind struct hci_pcb *pcb; 357 1.22 rmind int error; 358 1.22 rmind 359 1.22 rmind KASSERT(so->so_pcb == NULL); 360 1.22 rmind 361 1.22 rmind if (so->so_lock == NULL) { 362 1.22 rmind mutex_obj_hold(bt_lock); 363 1.22 rmind so->so_lock = bt_lock; 364 1.22 rmind solock(so); 365 1.22 rmind } 366 1.22 rmind KASSERT(solocked(so)); 367 1.22 rmind 368 1.22 rmind error = soreserve(so, hci_sendspace, hci_recvspace); 369 1.22 rmind if (error) { 370 1.22 rmind return error; 371 1.22 rmind } 372 1.22 rmind 373 1.22 rmind pcb = kmem_zalloc(sizeof(struct hci_pcb), KM_SLEEP); 374 1.22 rmind pcb->hp_cred = kauth_cred_dup(curlwp->l_cred); 375 1.22 rmind pcb->hp_socket = so; 376 1.22 rmind 377 1.22 rmind /* 378 1.22 rmind * Set default user filter. By default, socket only passes 379 1.22 rmind * Command_Complete and Command_Status Events. 380 1.22 rmind */ 381 1.22 rmind hci_filter_set(HCI_EVENT_COMMAND_COMPL, &pcb->hp_efilter); 382 1.22 rmind hci_filter_set(HCI_EVENT_COMMAND_STATUS, &pcb->hp_efilter); 383 1.22 rmind hci_filter_set(HCI_EVENT_PKT, &pcb->hp_pfilter); 384 1.22 rmind 385 1.22 rmind LIST_INSERT_HEAD(&hci_pcb, pcb, hp_next); 386 1.22 rmind so->so_pcb = pcb; 387 1.22 rmind 388 1.22 rmind return 0; 389 1.22 rmind } 390 1.22 rmind 391 1.22 rmind static void 392 1.23 rmind hci_detach(struct socket *so) 393 1.22 rmind { 394 1.22 rmind struct hci_pcb *pcb; 395 1.22 rmind 396 1.22 rmind pcb = (struct hci_pcb *)so->so_pcb; 397 1.22 rmind KASSERT(pcb != NULL); 398 1.22 rmind 399 1.22 rmind if (so->so_snd.sb_mb != NULL) 400 1.22 rmind hci_cmdwait_flush(so); 401 1.22 rmind 402 1.22 rmind if (pcb->hp_cred != NULL) 403 1.22 rmind kauth_cred_free(pcb->hp_cred); 404 1.22 rmind 405 1.22 rmind so->so_pcb = NULL; 406 1.22 rmind LIST_REMOVE(pcb, hp_next); 407 1.22 rmind kmem_free(pcb, sizeof(*pcb)); 408 1.22 rmind } 409 1.22 rmind 410 1.25 rtr static int 411 1.42 rtr hci_accept(struct socket *so, struct sockaddr *nam) 412 1.32 rtr { 413 1.32 rtr KASSERT(solocked(so)); 414 1.32 rtr 415 1.32 rtr return EOPNOTSUPP; 416 1.32 rtr } 417 1.32 rtr 418 1.32 rtr static int 419 1.41 rtr hci_bind(struct socket *so, struct sockaddr *nam, struct lwp *l) 420 1.34 rtr { 421 1.34 rtr struct hci_pcb *pcb = so->so_pcb; 422 1.41 rtr struct sockaddr_bt *sa = (struct sockaddr_bt *)nam; 423 1.34 rtr 424 1.34 rtr KASSERT(solocked(so)); 425 1.34 rtr KASSERT(pcb != NULL); 426 1.34 rtr KASSERT(nam != NULL); 427 1.34 rtr 428 1.34 rtr if (sa->bt_len != sizeof(struct sockaddr_bt)) 429 1.34 rtr return EINVAL; 430 1.34 rtr 431 1.34 rtr if (sa->bt_family != AF_BLUETOOTH) 432 1.34 rtr return EAFNOSUPPORT; 433 1.34 rtr 434 1.34 rtr bdaddr_copy(&pcb->hp_laddr, &sa->bt_bdaddr); 435 1.34 rtr 436 1.34 rtr if (bdaddr_any(&sa->bt_bdaddr)) 437 1.34 rtr pcb->hp_flags |= HCI_PROMISCUOUS; 438 1.34 rtr else 439 1.34 rtr pcb->hp_flags &= ~HCI_PROMISCUOUS; 440 1.34 rtr 441 1.34 rtr return 0; 442 1.34 rtr } 443 1.34 rtr 444 1.34 rtr static int 445 1.37 rtr hci_listen(struct socket *so, struct lwp *l) 446 1.34 rtr { 447 1.34 rtr KASSERT(solocked(so)); 448 1.34 rtr 449 1.34 rtr return EOPNOTSUPP; 450 1.34 rtr } 451 1.34 rtr 452 1.34 rtr static int 453 1.44 rtr hci_connect(struct socket *so, struct sockaddr *nam, struct lwp *l) 454 1.35 rtr { 455 1.35 rtr struct hci_pcb *pcb = so->so_pcb; 456 1.44 rtr struct sockaddr_bt *sa = (struct sockaddr_bt *)nam; 457 1.35 rtr 458 1.35 rtr KASSERT(solocked(so)); 459 1.35 rtr KASSERT(pcb != NULL); 460 1.35 rtr KASSERT(nam != NULL); 461 1.35 rtr 462 1.35 rtr if (sa->bt_len != sizeof(struct sockaddr_bt)) 463 1.35 rtr return EINVAL; 464 1.35 rtr 465 1.35 rtr if (sa->bt_family != AF_BLUETOOTH) 466 1.35 rtr return EAFNOSUPPORT; 467 1.35 rtr 468 1.35 rtr if (hci_unit_lookup(&sa->bt_bdaddr) == NULL) 469 1.35 rtr return EADDRNOTAVAIL; 470 1.35 rtr 471 1.35 rtr bdaddr_copy(&pcb->hp_raddr, &sa->bt_bdaddr); 472 1.35 rtr soisconnected(so); 473 1.35 rtr return 0; 474 1.35 rtr } 475 1.35 rtr 476 1.35 rtr static int 477 1.40 rtr hci_connect2(struct socket *so, struct socket *so2) 478 1.40 rtr { 479 1.40 rtr KASSERT(solocked(so)); 480 1.40 rtr 481 1.40 rtr return EOPNOTSUPP; 482 1.40 rtr } 483 1.40 rtr 484 1.40 rtr static int 485 1.36 rtr hci_disconnect(struct socket *so) 486 1.36 rtr { 487 1.36 rtr struct hci_pcb *pcb = so->so_pcb; 488 1.36 rtr 489 1.36 rtr KASSERT(solocked(so)); 490 1.36 rtr KASSERT(pcb != NULL); 491 1.36 rtr 492 1.36 rtr bdaddr_copy(&pcb->hp_raddr, BDADDR_ANY); 493 1.36 rtr 494 1.36 rtr /* XXX we cannot call soisdisconnected() here, as it sets 495 1.36 rtr * SS_CANTRCVMORE and SS_CANTSENDMORE. The problem being, 496 1.36 rtr * that soisconnected() does not clear these and if you 497 1.36 rtr * try to reconnect this socket (which is permitted) you 498 1.36 rtr * get a broken pipe when you try to write any data. 499 1.36 rtr */ 500 1.36 rtr so->so_state &= ~SS_ISCONNECTED; 501 1.36 rtr return 0; 502 1.36 rtr } 503 1.36 rtr 504 1.36 rtr static int 505 1.36 rtr hci_shutdown(struct socket *so) 506 1.36 rtr { 507 1.36 rtr KASSERT(solocked(so)); 508 1.36 rtr 509 1.36 rtr socantsendmore(so); 510 1.36 rtr return 0; 511 1.36 rtr } 512 1.36 rtr 513 1.36 rtr static int 514 1.36 rtr hci_abort(struct socket *so) 515 1.36 rtr { 516 1.36 rtr KASSERT(solocked(so)); 517 1.36 rtr 518 1.36 rtr soisdisconnected(so); 519 1.36 rtr hci_detach(so); 520 1.36 rtr return 0; 521 1.36 rtr } 522 1.36 rtr 523 1.36 rtr static int 524 1.30 rtr hci_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp) 525 1.25 rtr { 526 1.25 rtr int err; 527 1.25 rtr mutex_enter(bt_lock); 528 1.26 rtr err = hci_ioctl_pcb(cmd, nam); 529 1.25 rtr mutex_exit(bt_lock); 530 1.25 rtr return err; 531 1.25 rtr } 532 1.25 rtr 533 1.27 rtr static int 534 1.27 rtr hci_stat(struct socket *so, struct stat *ub) 535 1.27 rtr { 536 1.30 rtr KASSERT(solocked(so)); 537 1.30 rtr 538 1.29 rtr return 0; 539 1.27 rtr } 540 1.27 rtr 541 1.31 rtr static int 542 1.42 rtr hci_peeraddr(struct socket *so, struct sockaddr *nam) 543 1.31 rtr { 544 1.31 rtr struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb; 545 1.42 rtr struct sockaddr_bt *sa = (struct sockaddr_bt *)nam; 546 1.31 rtr 547 1.31 rtr KASSERT(solocked(so)); 548 1.31 rtr KASSERT(pcb != NULL); 549 1.31 rtr KASSERT(nam != NULL); 550 1.31 rtr 551 1.31 rtr memset(sa, 0, sizeof(struct sockaddr_bt)); 552 1.31 rtr sa->bt_len = sizeof(struct sockaddr_bt); 553 1.31 rtr sa->bt_family = AF_BLUETOOTH; 554 1.31 rtr bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_raddr); 555 1.31 rtr return 0; 556 1.31 rtr } 557 1.31 rtr 558 1.31 rtr static int 559 1.42 rtr hci_sockaddr(struct socket *so, struct sockaddr *nam) 560 1.31 rtr { 561 1.31 rtr struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb; 562 1.42 rtr struct sockaddr_bt *sa = (struct sockaddr_bt *)nam; 563 1.31 rtr 564 1.31 rtr KASSERT(solocked(so)); 565 1.31 rtr KASSERT(pcb != NULL); 566 1.31 rtr KASSERT(nam != NULL); 567 1.31 rtr 568 1.31 rtr memset(sa, 0, sizeof(struct sockaddr_bt)); 569 1.31 rtr sa->bt_len = sizeof(struct sockaddr_bt); 570 1.31 rtr sa->bt_family = AF_BLUETOOTH; 571 1.31 rtr bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_laddr); 572 1.31 rtr return 0; 573 1.31 rtr } 574 1.31 rtr 575 1.33 rtr static int 576 1.39 rtr hci_rcvd(struct socket *so, int flags, struct lwp *l) 577 1.39 rtr { 578 1.39 rtr KASSERT(solocked(so)); 579 1.39 rtr 580 1.39 rtr return EOPNOTSUPP; 581 1.39 rtr } 582 1.39 rtr 583 1.39 rtr static int 584 1.33 rtr hci_recvoob(struct socket *so, struct mbuf *m, int flags) 585 1.33 rtr { 586 1.33 rtr KASSERT(solocked(so)); 587 1.33 rtr 588 1.33 rtr return EOPNOTSUPP; 589 1.33 rtr } 590 1.33 rtr 591 1.33 rtr static int 592 1.44 rtr hci_send(struct socket *so, struct mbuf *m, struct sockaddr *nam, 593 1.38 rtr struct mbuf *control, struct lwp *l) 594 1.38 rtr { 595 1.38 rtr struct hci_pcb *pcb = so->so_pcb; 596 1.45 plunky struct sockaddr_bt *sa = (struct sockaddr_bt *)nam; 597 1.45 plunky struct hci_unit *unit; 598 1.45 plunky struct mbuf *m0; 599 1.45 plunky hci_cmd_hdr_t hdr; 600 1.38 rtr int err = 0; 601 1.38 rtr 602 1.38 rtr KASSERT(solocked(so)); 603 1.38 rtr KASSERT(pcb != NULL); 604 1.45 plunky KASSERT(m != NULL); 605 1.38 rtr 606 1.48 rin m_freem(control); /* have no use for this */ 607 1.38 rtr 608 1.45 plunky if (sa) { 609 1.38 rtr if (sa->bt_len != sizeof(struct sockaddr_bt)) { 610 1.38 rtr err = EINVAL; 611 1.45 plunky goto bad; 612 1.38 rtr } 613 1.38 rtr 614 1.38 rtr if (sa->bt_family != AF_BLUETOOTH) { 615 1.38 rtr err = EAFNOSUPPORT; 616 1.45 plunky goto bad; 617 1.38 rtr } 618 1.38 rtr } 619 1.38 rtr 620 1.45 plunky /* 621 1.45 plunky * this came from userland, so we check it out first 622 1.45 plunky */ 623 1.45 plunky 624 1.45 plunky /* wants at least a header to start with */ 625 1.45 plunky if (m->m_pkthdr.len < sizeof(hdr)) { 626 1.45 plunky err = EMSGSIZE; 627 1.45 plunky goto bad; 628 1.45 plunky } 629 1.45 plunky m_copydata(m, 0, sizeof(hdr), &hdr); 630 1.45 plunky hdr.opcode = le16toh(hdr.opcode); 631 1.45 plunky 632 1.45 plunky /* only allows CMD packets to be sent */ 633 1.45 plunky if (hdr.type != HCI_CMD_PKT) { 634 1.45 plunky err = EINVAL; 635 1.45 plunky goto bad; 636 1.45 plunky } 637 1.45 plunky 638 1.45 plunky /* validates packet length */ 639 1.45 plunky if (m->m_pkthdr.len != sizeof(hdr) + hdr.length) { 640 1.45 plunky err = EMSGSIZE; 641 1.45 plunky goto bad; 642 1.45 plunky } 643 1.45 plunky 644 1.45 plunky /* finds destination */ 645 1.45 plunky unit = hci_unit_lookup((sa ? &sa->bt_bdaddr : &pcb->hp_raddr)); 646 1.45 plunky if (unit == NULL) { 647 1.45 plunky err = ENETDOWN; 648 1.45 plunky goto bad; 649 1.45 plunky } 650 1.45 plunky 651 1.45 plunky /* security checks for unprivileged users */ 652 1.45 plunky if (pcb->hp_cred != NULL 653 1.45 plunky && kauth_authorize_device(pcb->hp_cred, 654 1.45 plunky KAUTH_DEVICE_BLUETOOTH_SEND, 655 1.45 plunky unit, &hdr, NULL, NULL) != 0) { 656 1.45 plunky err = EPERM; 657 1.45 plunky goto bad; 658 1.45 plunky } 659 1.45 plunky 660 1.45 plunky /* makess a copy for precious to keep */ 661 1.45 plunky m0 = m_copypacket(m, M_DONTWAIT); 662 1.45 plunky if (m0 == NULL) { 663 1.45 plunky err = ENOMEM; 664 1.45 plunky goto bad; 665 1.45 plunky } 666 1.45 plunky sbappendrecord(&pcb->hp_socket->so_snd, m0); 667 1.45 plunky M_SETCTX(m, pcb->hp_socket); /* enable drop callback */ 668 1.45 plunky 669 1.45 plunky DPRINTFN(2, "(%s) opcode (%03x|%04x)\n", device_xname(unit->hci_dev), 670 1.45 plunky HCI_OGF(hdr.opcode), HCI_OCF(hdr.opcode)); 671 1.38 rtr 672 1.45 plunky /* Sendss it */ 673 1.45 plunky if (unit->hci_num_cmd_pkts == 0) 674 1.45 plunky MBUFQ_ENQUEUE(&unit->hci_cmdwait, m); 675 1.45 plunky else 676 1.45 plunky hci_output_cmd(unit, m); 677 1.45 plunky 678 1.45 plunky return 0; 679 1.45 plunky 680 1.45 plunky bad: 681 1.45 plunky DPRINTF("packet (%d bytes) not sent (error %d)\n", 682 1.45 plunky m->m_pkthdr.len, err); 683 1.48 rin m_freem(m); 684 1.38 rtr 685 1.38 rtr return err; 686 1.38 rtr } 687 1.38 rtr 688 1.38 rtr static int 689 1.33 rtr hci_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control) 690 1.33 rtr { 691 1.33 rtr KASSERT(solocked(so)); 692 1.33 rtr 693 1.46 martin m_freem(m); 694 1.46 martin m_freem(control); 695 1.33 rtr 696 1.33 rtr return EOPNOTSUPP; 697 1.33 rtr } 698 1.33 rtr 699 1.40 rtr static int 700 1.40 rtr hci_purgeif(struct socket *so, struct ifnet *ifp) 701 1.40 rtr { 702 1.40 rtr 703 1.40 rtr return EOPNOTSUPP; 704 1.40 rtr } 705 1.40 rtr 706 1.1 gdamore /* 707 1.1 gdamore * get/set socket options 708 1.1 gdamore */ 709 1.1 gdamore int 710 1.17 plunky hci_ctloutput(int req, struct socket *so, struct sockopt *sopt) 711 1.1 gdamore { 712 1.1 gdamore struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb; 713 1.17 plunky int optval, err = 0; 714 1.1 gdamore 715 1.1 gdamore DPRINTFN(2, "req %s\n", prcorequests[req]); 716 1.1 gdamore 717 1.1 gdamore if (pcb == NULL) 718 1.1 gdamore return EINVAL; 719 1.1 gdamore 720 1.17 plunky if (sopt->sopt_level != BTPROTO_HCI) 721 1.7 plunky return ENOPROTOOPT; 722 1.1 gdamore 723 1.1 gdamore switch(req) { 724 1.1 gdamore case PRCO_GETOPT: 725 1.17 plunky switch (sopt->sopt_name) { 726 1.1 gdamore case SO_HCI_EVT_FILTER: 727 1.17 plunky err = sockopt_set(sopt, &pcb->hp_efilter, 728 1.17 plunky sizeof(struct hci_filter)); 729 1.17 plunky 730 1.1 gdamore break; 731 1.1 gdamore 732 1.1 gdamore case SO_HCI_PKT_FILTER: 733 1.17 plunky err = sockopt_set(sopt, &pcb->hp_pfilter, 734 1.17 plunky sizeof(struct hci_filter)); 735 1.17 plunky 736 1.1 gdamore break; 737 1.1 gdamore 738 1.1 gdamore case SO_HCI_DIRECTION: 739 1.17 plunky err = sockopt_setint(sopt, 740 1.17 plunky (pcb->hp_flags & HCI_DIRECTION ? 1 : 0)); 741 1.17 plunky 742 1.1 gdamore break; 743 1.1 gdamore 744 1.1 gdamore default: 745 1.7 plunky err = ENOPROTOOPT; 746 1.1 gdamore break; 747 1.1 gdamore } 748 1.1 gdamore break; 749 1.1 gdamore 750 1.1 gdamore case PRCO_SETOPT: 751 1.17 plunky switch (sopt->sopt_name) { 752 1.1 gdamore case SO_HCI_EVT_FILTER: /* set event filter */ 753 1.17 plunky err = sockopt_get(sopt, &pcb->hp_efilter, 754 1.17 plunky sizeof(pcb->hp_efilter)); 755 1.17 plunky 756 1.1 gdamore break; 757 1.1 gdamore 758 1.1 gdamore case SO_HCI_PKT_FILTER: /* set packet filter */ 759 1.17 plunky err = sockopt_get(sopt, &pcb->hp_pfilter, 760 1.17 plunky sizeof(pcb->hp_pfilter)); 761 1.17 plunky 762 1.1 gdamore break; 763 1.1 gdamore 764 1.1 gdamore case SO_HCI_DIRECTION: /* request direction ctl messages */ 765 1.17 plunky err = sockopt_getint(sopt, &optval); 766 1.17 plunky if (err) 767 1.17 plunky break; 768 1.17 plunky 769 1.17 plunky if (optval) 770 1.1 gdamore pcb->hp_flags |= HCI_DIRECTION; 771 1.1 gdamore else 772 1.1 gdamore pcb->hp_flags &= ~HCI_DIRECTION; 773 1.1 gdamore break; 774 1.1 gdamore 775 1.1 gdamore default: 776 1.7 plunky err = ENOPROTOOPT; 777 1.1 gdamore break; 778 1.1 gdamore } 779 1.1 gdamore break; 780 1.1 gdamore 781 1.1 gdamore default: 782 1.7 plunky err = ENOPROTOOPT; 783 1.1 gdamore break; 784 1.1 gdamore } 785 1.1 gdamore 786 1.1 gdamore return err; 787 1.1 gdamore } 788 1.1 gdamore 789 1.1 gdamore /* 790 1.1 gdamore * HCI mbuf tap routine 791 1.1 gdamore * 792 1.1 gdamore * copy packets to any raw HCI sockets that wish (and are 793 1.1 gdamore * permitted) to see them 794 1.1 gdamore */ 795 1.1 gdamore void 796 1.1 gdamore hci_mtap(struct mbuf *m, struct hci_unit *unit) 797 1.1 gdamore { 798 1.1 gdamore struct hci_pcb *pcb; 799 1.1 gdamore struct mbuf *m0, *ctlmsg, **ctl; 800 1.1 gdamore struct sockaddr_bt sa; 801 1.1 gdamore uint8_t type; 802 1.1 gdamore uint8_t event; 803 1.19 plunky uint16_t arg1; 804 1.1 gdamore 805 1.1 gdamore KASSERT(m->m_len >= sizeof(type)); 806 1.1 gdamore 807 1.1 gdamore type = *mtod(m, uint8_t *); 808 1.1 gdamore 809 1.1 gdamore memset(&sa, 0, sizeof(sa)); 810 1.1 gdamore sa.bt_len = sizeof(struct sockaddr_bt); 811 1.1 gdamore sa.bt_family = AF_BLUETOOTH; 812 1.1 gdamore bdaddr_copy(&sa.bt_bdaddr, &unit->hci_bdaddr); 813 1.1 gdamore 814 1.1 gdamore LIST_FOREACH(pcb, &hci_pcb, hp_next) { 815 1.1 gdamore /* 816 1.1 gdamore * filter according to source address 817 1.1 gdamore */ 818 1.1 gdamore if ((pcb->hp_flags & HCI_PROMISCUOUS) == 0 819 1.1 gdamore && bdaddr_same(&pcb->hp_laddr, &sa.bt_bdaddr) == 0) 820 1.1 gdamore continue; 821 1.1 gdamore 822 1.1 gdamore /* 823 1.1 gdamore * filter according to packet type filter 824 1.1 gdamore */ 825 1.1 gdamore if (hci_filter_test(type, &pcb->hp_pfilter) == 0) 826 1.1 gdamore continue; 827 1.1 gdamore 828 1.1 gdamore /* 829 1.1 gdamore * filter according to event/security filters 830 1.1 gdamore */ 831 1.1 gdamore switch(type) { 832 1.1 gdamore case HCI_EVENT_PKT: 833 1.1 gdamore KASSERT(m->m_len >= sizeof(hci_event_hdr_t)); 834 1.1 gdamore 835 1.1 gdamore event = mtod(m, hci_event_hdr_t *)->event; 836 1.1 gdamore 837 1.1 gdamore if (hci_filter_test(event, &pcb->hp_efilter) == 0) 838 1.1 gdamore continue; 839 1.1 gdamore 840 1.19 plunky arg1 = event; 841 1.1 gdamore break; 842 1.1 gdamore 843 1.1 gdamore case HCI_CMD_PKT: 844 1.1 gdamore KASSERT(m->m_len >= sizeof(hci_cmd_hdr_t)); 845 1.19 plunky arg1 = le16toh(mtod(m, hci_cmd_hdr_t *)->opcode); 846 1.19 plunky break; 847 1.1 gdamore 848 1.19 plunky case HCI_ACL_DATA_PKT: 849 1.19 plunky KASSERT(m->m_len >= sizeof(hci_acldata_hdr_t)); 850 1.19 plunky arg1 = le16toh(mtod(m, hci_acldata_hdr_t *)->con_handle); 851 1.19 plunky arg1 = HCI_CON_HANDLE(arg1); 852 1.19 plunky break; 853 1.18 plunky 854 1.19 plunky case HCI_SCO_DATA_PKT: 855 1.19 plunky KASSERT(m->m_len >= sizeof(hci_scodata_hdr_t)); 856 1.19 plunky arg1 = le16toh(mtod(m, hci_scodata_hdr_t *)->con_handle); 857 1.19 plunky arg1 = HCI_CON_HANDLE(arg1); 858 1.1 gdamore break; 859 1.1 gdamore 860 1.1 gdamore default: 861 1.19 plunky arg1 = 0; 862 1.1 gdamore break; 863 1.1 gdamore } 864 1.1 gdamore 865 1.19 plunky if (pcb->hp_cred != NULL 866 1.19 plunky && kauth_authorize_device(pcb->hp_cred, 867 1.19 plunky KAUTH_DEVICE_BLUETOOTH_RECV, 868 1.19 plunky KAUTH_ARG(type), KAUTH_ARG(arg1), NULL, NULL) != 0) 869 1.19 plunky continue; 870 1.19 plunky 871 1.1 gdamore /* 872 1.1 gdamore * create control messages 873 1.1 gdamore */ 874 1.1 gdamore ctlmsg = NULL; 875 1.1 gdamore ctl = &ctlmsg; 876 1.1 gdamore if (pcb->hp_flags & HCI_DIRECTION) { 877 1.1 gdamore int dir = m->m_flags & M_LINK0 ? 1 : 0; 878 1.1 gdamore 879 1.11 plunky *ctl = sbcreatecontrol(&dir, sizeof(dir), 880 1.1 gdamore SCM_HCI_DIRECTION, BTPROTO_HCI); 881 1.1 gdamore 882 1.1 gdamore if (*ctl != NULL) 883 1.1 gdamore ctl = &((*ctl)->m_next); 884 1.1 gdamore } 885 1.20 plunky if (pcb->hp_socket->so_options & SO_TIMESTAMP) { 886 1.20 plunky struct timeval tv; 887 1.20 plunky 888 1.20 plunky microtime(&tv); 889 1.20 plunky *ctl = sbcreatecontrol(&tv, sizeof(tv), 890 1.20 plunky SCM_TIMESTAMP, SOL_SOCKET); 891 1.20 plunky 892 1.20 plunky if (*ctl != NULL) 893 1.20 plunky ctl = &((*ctl)->m_next); 894 1.20 plunky } 895 1.1 gdamore 896 1.1 gdamore /* 897 1.1 gdamore * copy to socket 898 1.1 gdamore */ 899 1.1 gdamore m0 = m_copypacket(m, M_DONTWAIT); 900 1.1 gdamore if (m0 && sbappendaddr(&pcb->hp_socket->so_rcv, 901 1.1 gdamore (struct sockaddr *)&sa, m0, ctlmsg)) { 902 1.1 gdamore sorwakeup(pcb->hp_socket); 903 1.1 gdamore } else { 904 1.1 gdamore m_freem(ctlmsg); 905 1.1 gdamore m_freem(m0); 906 1.1 gdamore } 907 1.1 gdamore } 908 1.1 gdamore } 909 1.21 rmind 910 1.24 rmind PR_WRAP_USRREQS(hci) 911 1.21 rmind 912 1.24 rmind #define hci_attach hci_attach_wrapper 913 1.24 rmind #define hci_detach hci_detach_wrapper 914 1.32 rtr #define hci_accept hci_accept_wrapper 915 1.34 rtr #define hci_bind hci_bind_wrapper 916 1.34 rtr #define hci_listen hci_listen_wrapper 917 1.35 rtr #define hci_connect hci_connect_wrapper 918 1.40 rtr #define hci_connect2 hci_connect2_wrapper 919 1.36 rtr #define hci_disconnect hci_disconnect_wrapper 920 1.36 rtr #define hci_shutdown hci_shutdown_wrapper 921 1.36 rtr #define hci_abort hci_abort_wrapper 922 1.25 rtr #define hci_ioctl hci_ioctl_wrapper 923 1.27 rtr #define hci_stat hci_stat_wrapper 924 1.31 rtr #define hci_peeraddr hci_peeraddr_wrapper 925 1.31 rtr #define hci_sockaddr hci_sockaddr_wrapper 926 1.39 rtr #define hci_rcvd hci_rcvd_wrapper 927 1.33 rtr #define hci_recvoob hci_recvoob_wrapper 928 1.38 rtr #define hci_send hci_send_wrapper 929 1.33 rtr #define hci_sendoob hci_sendoob_wrapper 930 1.40 rtr #define hci_purgeif hci_purgeif_wrapper 931 1.21 rmind 932 1.21 rmind const struct pr_usrreqs hci_usrreqs = { 933 1.23 rmind .pr_attach = hci_attach, 934 1.23 rmind .pr_detach = hci_detach, 935 1.32 rtr .pr_accept = hci_accept, 936 1.34 rtr .pr_bind = hci_bind, 937 1.34 rtr .pr_listen = hci_listen, 938 1.35 rtr .pr_connect = hci_connect, 939 1.40 rtr .pr_connect2 = hci_connect2, 940 1.36 rtr .pr_disconnect = hci_disconnect, 941 1.36 rtr .pr_shutdown = hci_shutdown, 942 1.36 rtr .pr_abort = hci_abort, 943 1.25 rtr .pr_ioctl = hci_ioctl, 944 1.27 rtr .pr_stat = hci_stat, 945 1.31 rtr .pr_peeraddr = hci_peeraddr, 946 1.31 rtr .pr_sockaddr = hci_sockaddr, 947 1.39 rtr .pr_rcvd = hci_rcvd, 948 1.33 rtr .pr_recvoob = hci_recvoob, 949 1.38 rtr .pr_send = hci_send, 950 1.33 rtr .pr_sendoob = hci_sendoob, 951 1.40 rtr .pr_purgeif = hci_purgeif, 952 1.21 rmind }; 953