1 /* $NetBSD: l2cap_socket.c,v 1.1 2006/06/19 15:44:45 gdamore 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: l2cap_socket.c,v 1.1 2006/06/19 15:44:45 gdamore Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/domain.h> 38 #include <sys/kernel.h> 39 #include <sys/mbuf.h> 40 #include <sys/proc.h> 41 #include <sys/protosw.h> 42 #include <sys/socket.h> 43 #include <sys/socketvar.h> 44 #include <sys/systm.h> 45 46 #include <netbt/bluetooth.h> 47 #include <netbt/l2cap.h> 48 49 /* 50 * L2CAP Sockets 51 * 52 * SOCK_SEQPACKET - normal L2CAP connection 53 * 54 * SOCK_DGRAM - connectionless L2CAP - XXX not yet 55 */ 56 57 static void l2cap_connecting(void *); 58 static void l2cap_connected(void *); 59 static void l2cap_disconnected(void *, int); 60 static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); 61 static void l2cap_complete(void *, int); 62 static void l2cap_input(void *, struct mbuf *); 63 64 static const struct btproto l2cap_proto = { 65 l2cap_connecting, 66 l2cap_connected, 67 l2cap_disconnected, 68 l2cap_newconn, 69 l2cap_complete, 70 l2cap_input 71 }; 72 73 /* sysctl variables */ 74 int l2cap_sendspace = 4096; 75 int l2cap_recvspace = 4096; 76 77 /* 78 * User Request. 79 * up is socket 80 * m is either 81 * optional mbuf chain containing message 82 * ioctl command (PRU_CONTROL) 83 * nam is either 84 * optional mbuf chain containing an address 85 * ioctl data (PRU_CONTROL) 86 * optionally protocol number (PRU_ATTACH) 87 * message flags (PRU_RCVD) 88 * ctl is either 89 * optional mbuf chain containing socket options 90 * optional interface pointer (PRU_CONTROL, PRU_PURGEIF) 91 * l is pointer to process requesting action (if any) 92 * 93 * we are responsible for disposing of m and ctl if 94 * they are mbuf chains 95 */ 96 int 97 l2cap_usrreq(struct socket *up, int req, struct mbuf *m, 98 struct mbuf *nam, struct mbuf *ctl, struct lwp *l) 99 { 100 struct l2cap_channel *pcb = up->so_pcb; 101 struct sockaddr_bt *sa; 102 struct mbuf *m0; 103 int err = 0; 104 105 DPRINTFN(2, "%s\n", prurequests[req]); 106 107 switch (req) { 108 case PRU_CONTROL: 109 return EPASSTHROUGH; 110 111 case PRU_PURGEIF: 112 return EOPNOTSUPP; 113 114 case PRU_ATTACH: 115 if (pcb != NULL) 116 return EINVAL; 117 118 /* 119 * For L2CAP socket PCB we just use an l2cap_channel structure 120 * since we have nothing to add.. 121 */ 122 err = soreserve(up, l2cap_sendspace, l2cap_recvspace); 123 if (err) 124 return err; 125 126 return l2cap_attach((struct l2cap_channel **)&up->so_pcb, 127 &l2cap_proto, up); 128 } 129 130 if (pcb == NULL) { 131 err = EINVAL; 132 goto release; 133 } 134 135 switch(req) { 136 case PRU_DISCONNECT: 137 soisdisconnecting(up); 138 return l2cap_disconnect(pcb, up->so_linger); 139 140 case PRU_ABORT: 141 l2cap_disconnect(pcb, 0); 142 soisdisconnected(up); 143 /* fall through to */ 144 case PRU_DETACH: 145 return l2cap_detach((struct l2cap_channel **)&up->so_pcb); 146 147 case PRU_BIND: 148 KASSERT(nam); 149 sa = mtod(nam, struct sockaddr_bt *); 150 151 if (sa->bt_len != sizeof(struct sockaddr_bt)) 152 return EINVAL; 153 154 if (sa->bt_family != AF_BLUETOOTH) 155 return EAFNOSUPPORT; 156 157 return l2cap_bind(pcb, sa); 158 159 case PRU_CONNECT: 160 KASSERT(nam); 161 sa = mtod(nam, struct sockaddr_bt *); 162 163 if (sa->bt_len != sizeof(struct sockaddr_bt)) 164 return EINVAL; 165 166 if (sa->bt_family != AF_BLUETOOTH) 167 return EAFNOSUPPORT; 168 169 soisconnecting(up); 170 return l2cap_connect(pcb, sa); 171 172 case PRU_PEERADDR: 173 KASSERT(nam); 174 sa = mtod(nam, struct sockaddr_bt *); 175 nam->m_len = sizeof(struct sockaddr_bt); 176 return l2cap_peeraddr(pcb, sa); 177 178 case PRU_SOCKADDR: 179 KASSERT(nam); 180 sa = mtod(nam, struct sockaddr_bt *); 181 nam->m_len = sizeof(struct sockaddr_bt); 182 return l2cap_sockaddr(pcb, sa); 183 184 case PRU_SHUTDOWN: 185 socantsendmore(up); 186 break; 187 188 case PRU_SEND: 189 KASSERT(m); 190 if (m->m_pkthdr.len == 0) 191 break; 192 193 if (m->m_pkthdr.len > pcb->lc_omtu) { 194 err = EMSGSIZE; 195 break; 196 } 197 198 m0 = m_copypacket(m, M_DONTWAIT); 199 if (m0 == NULL) { 200 err = ENOMEM; 201 break; 202 } 203 204 if (ctl) /* no use for that */ 205 m_freem(ctl); 206 207 sbappendrecord(&up->so_snd, m); 208 return l2cap_send(pcb, m0); 209 210 case PRU_SENSE: 211 return 0; /* (no release) */ 212 213 case PRU_RCVD: 214 case PRU_RCVOOB: 215 return EOPNOTSUPP; /* (no release) */ 216 217 case PRU_LISTEN: 218 return l2cap_listen(pcb); 219 220 case PRU_ACCEPT: 221 KASSERT(nam); 222 sa = mtod(nam, struct sockaddr_bt *); 223 nam->m_len = sizeof(struct sockaddr_bt); 224 return l2cap_peeraddr(pcb, sa); 225 226 case PRU_CONNECT2: 227 case PRU_SENDOOB: 228 case PRU_FASTTIMO: 229 case PRU_SLOWTIMO: 230 case PRU_PROTORCV: 231 case PRU_PROTOSEND: 232 err = EOPNOTSUPP; 233 break; 234 235 default: 236 UNKNOWN(req); 237 err = EOPNOTSUPP; 238 break; 239 } 240 241 release: 242 if (m) m_freem(m); 243 if (ctl) m_freem(ctl); 244 return err; 245 } 246 247 /* 248 * l2cap_ctloutput(request, socket, level, optname, opt) 249 * 250 * Apply configuration commands to channel. This corresponds to 251 * "Reconfigure Channel Request" in the L2CAP specification. 252 */ 253 int 254 l2cap_ctloutput(int req, struct socket *so, int level, 255 int optname, struct mbuf **opt) 256 { 257 struct l2cap_channel *pcb = so->so_pcb; 258 struct mbuf *m; 259 int err = 0; 260 261 DPRINTFN(2, "%s\n", prcorequests[req]); 262 263 if (level != BTPROTO_L2CAP) 264 return 0; // err? 265 266 switch(req) { 267 case PRCO_GETOPT: 268 m = m_get(M_WAIT, MT_SOOPTS); 269 m->m_len = l2cap_getopt(pcb, optname, mtod(m, void *)); 270 if (m->m_len == 0) { 271 m_freem(m); 272 m = NULL; 273 err = EINVAL; 274 } 275 *opt = m; 276 break; 277 278 case PRCO_SETOPT: 279 m = *opt; 280 KASSERT(m != NULL); 281 err = l2cap_setopt(pcb, optname, mtod(m, void *)); 282 m_freem(m); 283 break; 284 285 default: 286 err = EINVAL; 287 break; 288 } 289 290 return err; 291 } 292 293 /********************************************************************** 294 * 295 * L2CAP Protocol socket callbacks 296 * 297 */ 298 299 static void 300 l2cap_connecting(void *arg) 301 { 302 struct socket *so = arg; 303 304 DPRINTF("Connecting\n"); 305 soisconnecting(so); 306 } 307 308 static void 309 l2cap_connected(void *arg) 310 { 311 struct socket *so = arg; 312 313 DPRINTF("Connected\n"); 314 soisconnected(so); 315 } 316 317 static void 318 l2cap_disconnected(void *arg, int err) 319 { 320 struct socket *so = arg; 321 322 DPRINTF("Disconnected (%d)\n", err); 323 324 so->so_error = err; 325 soisdisconnected(so); 326 } 327 328 static void * 329 l2cap_newconn(void *arg, struct sockaddr_bt *laddr, struct sockaddr_bt *raddr) 330 { 331 struct socket *so = arg; 332 333 DPRINTF("New Connection\n"); 334 so = sonewconn(so, 0); 335 if (so == NULL) 336 return NULL; 337 338 soisconnecting(so); 339 340 return so->so_pcb; 341 } 342 343 static void 344 l2cap_complete(void *arg, int count) 345 { 346 struct socket *so = arg; 347 348 while (count-- > 0) 349 sbdroprecord(&so->so_snd); 350 351 sowwakeup(so); 352 } 353 354 static void 355 l2cap_input(void *arg, struct mbuf *m) 356 { 357 struct socket *so = arg; 358 359 if (m->m_pkthdr.len > sbspace(&so->so_rcv)) { 360 printf("%s: packet (%d bytes) dropped (socket buffer full)\n", 361 __func__, m->m_pkthdr.len); 362 m_freem(m); 363 return; 364 } 365 366 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len); 367 368 sbappendrecord(&so->so_rcv, m); 369 sorwakeup(so); 370 } 371