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