1 /* $DragonFly: src/sys/netbt/sco_upper.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ 2 /* $OpenBSD: sco_upper.c,v 1.2 2007/10/01 16:39:30 krw Exp $ */ 3 /* $NetBSD: sco_upper.c,v 1.6 2007/03/30 20:47:03 plunky Exp $ */ 4 5 /*- 6 * Copyright (c) 2006 Itronix Inc. 7 * All rights reserved. 8 * 9 * Written by Iain Hibbert for Itronix Inc. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. The name of Itronix Inc. may not be used to endorse 20 * or promote products derived from this software without specific 21 * prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 27 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 * ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 38 #include <sys/param.h> 39 #include <sys/kernel.h> 40 #include <sys/mbuf.h> 41 #include <sys/proc.h> 42 #include <sys/systm.h> 43 #include <sys/endian.h> 44 #include <sys/bus.h> 45 46 #include <netbt/bluetooth.h> 47 #include <netbt/hci.h> 48 #include <netbt/sco.h> 49 50 /**************************************************************************** 51 * 52 * SCO - Upper Protocol API 53 */ 54 55 struct sco_pcb_list sco_pcb = LIST_HEAD_INITIALIZER(sco_pcb); 56 57 /* 58 * sco_attach(handle, proto, upper) 59 * 60 * Attach a new instance of SCO pcb to handle 61 */ 62 int 63 sco_attach(struct sco_pcb **handle, 64 const struct btproto *proto, void *upper) 65 { 66 struct sco_pcb *pcb; 67 68 KKASSERT(handle != NULL); 69 KKASSERT(proto != NULL); 70 KKASSERT(upper != NULL); 71 72 pcb = kmalloc(sizeof(*pcb), M_BLUETOOTH, M_NOWAIT | M_ZERO); 73 if (pcb == NULL) 74 return ENOMEM; 75 76 pcb->sp_proto = proto; 77 pcb->sp_upper = upper; 78 79 LIST_INSERT_HEAD(&sco_pcb, pcb, sp_next); 80 81 *handle = pcb; 82 return 0; 83 } 84 85 /* 86 * sco_bind(pcb, sockaddr) 87 * 88 * Bind SCO pcb to local address 89 */ 90 int 91 sco_bind(struct sco_pcb *pcb, struct sockaddr_bt *addr) 92 { 93 94 bdaddr_copy(&pcb->sp_laddr, &addr->bt_bdaddr); 95 return 0; 96 } 97 98 /* 99 * sco_sockaddr(pcb, sockaddr) 100 * 101 * Copy local address of PCB to sockaddr 102 */ 103 int 104 sco_sockaddr(struct sco_pcb *pcb, struct sockaddr_bt *addr) 105 { 106 107 memset(addr, 0, sizeof(struct sockaddr_bt)); 108 addr->bt_len = sizeof(struct sockaddr_bt); 109 addr->bt_family = AF_BLUETOOTH; 110 bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_laddr); 111 return 0; 112 } 113 114 /* 115 * sco_connect(pcb, sockaddr) 116 * 117 * Initiate a SCO connection to the destination address. 118 */ 119 int 120 sco_connect(struct sco_pcb *pcb, struct sockaddr_bt *dest) 121 { 122 hci_add_sco_con_cp cp; 123 struct hci_unit *unit; 124 struct hci_link *acl, *sco; 125 int err; 126 127 if (pcb->sp_flags & SP_LISTENING) 128 return EINVAL; 129 130 bdaddr_copy(&pcb->sp_raddr, &dest->bt_bdaddr); 131 132 if (bdaddr_any(&pcb->sp_raddr)) 133 return EDESTADDRREQ; 134 135 if (bdaddr_any(&pcb->sp_laddr)) { 136 err = hci_route_lookup(&pcb->sp_laddr, &pcb->sp_raddr); 137 if (err) 138 return err; 139 } 140 141 unit = hci_unit_lookup(&pcb->sp_laddr); 142 if (unit == NULL) 143 return ENETDOWN; 144 145 /* 146 * We must have an already open ACL connection before we open the SCO 147 * connection, and since SCO connections dont happen on their own we 148 * will not open one, the application wanting this should have opened 149 * it previously. 150 */ 151 acl = hci_link_lookup_bdaddr(unit, &pcb->sp_raddr, HCI_LINK_ACL); 152 if (acl == NULL || acl->hl_state != HCI_LINK_OPEN) 153 return EHOSTUNREACH; 154 155 sco = hci_link_alloc(unit); 156 if (sco == NULL) 157 return ENOMEM; 158 159 sco->hl_type = HCI_LINK_SCO; 160 bdaddr_copy(&sco->hl_bdaddr, &pcb->sp_raddr); 161 162 sco->hl_link = hci_acl_open(unit, &pcb->sp_raddr); 163 KKASSERT(sco->hl_link == acl); 164 165 cp.con_handle = htole16(acl->hl_handle); 166 cp.pkt_type = htole16(0x00e0); /* HV1, HV2, HV3 */ 167 err = hci_send_cmd(unit, HCI_CMD_ADD_SCO_CON, &cp, sizeof(cp)); 168 if (err) { 169 hci_link_free(sco, err); 170 return err; 171 } 172 173 sco->hl_sco = pcb; 174 pcb->sp_link = sco; 175 176 pcb->sp_mtu = unit->hci_max_sco_size; 177 return 0; 178 } 179 180 /* 181 * sco_peeraddr(pcb, sockaddr) 182 * 183 * Copy remote address of SCO pcb to sockaddr 184 */ 185 int 186 sco_peeraddr(struct sco_pcb *pcb, struct sockaddr_bt *addr) 187 { 188 189 memset(addr, 0, sizeof(struct sockaddr_bt)); 190 addr->bt_len = sizeof(struct sockaddr_bt); 191 addr->bt_family = AF_BLUETOOTH; 192 bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_raddr); 193 return 0; 194 } 195 196 /* 197 * sco_disconnect(pcb, linger) 198 * 199 * Initiate disconnection of connected SCO pcb 200 */ 201 int 202 sco_disconnect(struct sco_pcb *pcb, int linger) 203 { 204 hci_discon_cp cp; 205 struct hci_link *sco; 206 int err; 207 208 sco = pcb->sp_link; 209 if (sco == NULL) 210 return EINVAL; 211 212 cp.con_handle = htole16(sco->hl_handle); 213 cp.reason = 0x13; /* "Remote User Terminated Connection" */ 214 215 err = hci_send_cmd(sco->hl_unit, HCI_CMD_DISCONNECT, &cp, sizeof(cp)); 216 if (err || linger == 0) { 217 sco->hl_sco = NULL; 218 pcb->sp_link = NULL; 219 hci_link_free(sco, err); 220 } 221 222 return err; 223 } 224 225 /* 226 * sco_detach(handle) 227 * 228 * Detach SCO pcb from handle and clear up 229 */ 230 int 231 sco_detach(struct sco_pcb **handle) 232 { 233 struct sco_pcb *pcb; 234 235 KKASSERT(handle != NULL); 236 pcb = *handle; 237 *handle = NULL; 238 239 if (pcb == NULL) 240 return EINVAL; 241 242 if (pcb->sp_link != NULL) { 243 sco_disconnect(pcb, 0); 244 pcb->sp_link = NULL; 245 } 246 247 LIST_REMOVE(pcb, sp_next); 248 kfree(pcb, M_BLUETOOTH); 249 return 0; 250 } 251 252 /* 253 * sco_listen(pcb) 254 * 255 * Mark pcb as a listener. 256 */ 257 int 258 sco_listen(struct sco_pcb *pcb) 259 { 260 261 if (pcb->sp_link != NULL) 262 return EINVAL; 263 264 pcb->sp_flags |= SP_LISTENING; 265 return 0; 266 } 267 268 /* 269 * sco_send(pcb, mbuf) 270 * 271 * Send data on SCO pcb. 272 * 273 * Gross hackage, we just output the packet directly onto the unit queue. 274 * This will work fine for one channel per unit, but for more channels it 275 * really needs fixing. We set the context so that when the packet is sent, 276 * we can drop a record from the socket buffer. 277 */ 278 int 279 sco_send(struct sco_pcb *pcb, struct mbuf *m) 280 { 281 hci_scodata_hdr_t *hdr; 282 int plen; 283 284 if (pcb->sp_link == NULL) { 285 m_freem(m); 286 return EINVAL; 287 } 288 289 plen = m->m_pkthdr.len; 290 DPRINTFN(10, "%d bytes\n", plen); 291 292 /* 293 * This is a temporary limitation, as USB devices cannot 294 * handle SCO packet sizes that are not an integer number 295 * of Isochronous frames. See ubt(4) 296 */ 297 if (plen != pcb->sp_mtu) { 298 m_freem(m); 299 return EMSGSIZE; 300 } 301 302 M_PREPEND(m, sizeof(hci_scodata_hdr_t), MB_DONTWAIT); 303 if (m == NULL) 304 return ENOMEM; 305 306 hdr = mtod(m, hci_scodata_hdr_t *); 307 hdr->type = HCI_SCO_DATA_PKT; 308 hdr->con_handle = htole16(pcb->sp_link->hl_handle); 309 hdr->length = plen; 310 311 pcb->sp_pending++; 312 M_SETCTX(m, pcb->sp_link); 313 hci_output_sco(pcb->sp_link->hl_unit, m); 314 315 return 0; 316 } 317 318 /* 319 * sco_setopt(pcb, option, addr) 320 * 321 * Set SCO pcb options 322 */ 323 int 324 sco_setopt(struct sco_pcb *pcb, int opt, void *addr) 325 { 326 int err = 0; 327 328 switch (opt) { 329 default: 330 err = ENOPROTOOPT; 331 break; 332 } 333 334 return err; 335 } 336 337 /* 338 * sco_getopt(pcb, option, addr) 339 * 340 * Get SCO pcb options 341 */ 342 int 343 sco_getopt(struct sco_pcb *pcb, int opt, void *addr) 344 { 345 346 switch (opt) { 347 case SO_SCO_MTU: 348 *(uint16_t *)addr = pcb->sp_mtu; 349 return sizeof(uint16_t); 350 351 case SO_SCO_HANDLE: 352 if (pcb->sp_link) { 353 *(uint16_t *)addr = pcb->sp_link->hl_handle; 354 return sizeof(uint16_t); 355 } 356 break; 357 358 default: 359 break; 360 } 361 return 0; 362 } 363