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