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