l2cap_socket.c revision 1.22 1 /* $NetBSD: l2cap_socket.c,v 1.22 2014/07/09 04:54:03 rtr 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.22 2014/07/09 04:54:03 rtr Exp $");
35
36 /* load symbolic names */
37 #ifdef BLUETOOTH_DEBUG
38 #define PRUREQUESTS
39 #define PRCOREQUESTS
40 #endif
41
42 #include <sys/param.h>
43 #include <sys/domain.h>
44 #include <sys/kernel.h>
45 #include <sys/mbuf.h>
46 #include <sys/proc.h>
47 #include <sys/protosw.h>
48 #include <sys/socket.h>
49 #include <sys/socketvar.h>
50 #include <sys/systm.h>
51
52 #include <netbt/bluetooth.h>
53 #include <netbt/l2cap.h>
54
55 /*
56 * L2CAP Sockets
57 *
58 * SOCK_SEQPACKET - normal L2CAP connection
59 *
60 * SOCK_DGRAM - connectionless L2CAP - XXX not yet
61 */
62
63 static void l2cap_connecting(void *);
64 static void l2cap_connected(void *);
65 static void l2cap_disconnected(void *, int);
66 static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
67 static void l2cap_complete(void *, int);
68 static void l2cap_linkmode(void *, int);
69 static void l2cap_input(void *, struct mbuf *);
70
71 static const struct btproto l2cap_proto = {
72 l2cap_connecting,
73 l2cap_connected,
74 l2cap_disconnected,
75 l2cap_newconn,
76 l2cap_complete,
77 l2cap_linkmode,
78 l2cap_input,
79 };
80
81 /* sysctl variables */
82 int l2cap_sendspace = 4096;
83 int l2cap_recvspace = 4096;
84
85 static int
86 l2cap_attach(struct socket *so, int proto)
87 {
88 int error;
89
90 KASSERT(so->so_pcb == NULL);
91
92 if (so->so_lock == NULL) {
93 mutex_obj_hold(bt_lock);
94 so->so_lock = bt_lock;
95 solock(so);
96 }
97 KASSERT(solocked(so));
98
99 /*
100 * For L2CAP socket PCB we just use an l2cap_channel structure
101 * since we have nothing to add..
102 */
103 error = soreserve(so, l2cap_sendspace, l2cap_recvspace);
104 if (error)
105 return error;
106
107 return l2cap_attach_pcb((struct l2cap_channel **)&so->so_pcb,
108 &l2cap_proto, so);
109 }
110
111 static void
112 l2cap_detach(struct socket *so)
113 {
114 KASSERT(so->so_pcb != NULL);
115 l2cap_detach_pcb((struct l2cap_channel **)&so->so_pcb);
116 KASSERT(so->so_pcb == NULL);
117 }
118
119 static int
120 l2cap_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
121 {
122 return EPASSTHROUGH;
123 }
124
125 static int
126 l2cap_stat(struct socket *so, struct stat *ub)
127 {
128 KASSERT(solocked(so));
129
130 return 0;
131 }
132
133 static int
134 l2cap_peeraddr(struct socket *so, struct mbuf *nam)
135 {
136 struct l2cap_channel *pcb = so->so_pcb;
137 struct sockaddr_bt *sa;
138
139 KASSERT(solocked(so));
140 KASSERT(pcb != NULL);
141 KASSERT(nam != NULL);
142
143 sa = mtod(nam, struct sockaddr_bt *);
144 nam->m_len = sizeof(struct sockaddr_bt);
145 return l2cap_peeraddr_pcb(pcb, sa);
146 }
147
148 static int
149 l2cap_sockaddr(struct socket *so, struct mbuf *nam)
150 {
151 struct l2cap_channel *pcb = so->so_pcb;
152 struct sockaddr_bt *sa;
153
154 KASSERT(solocked(so));
155 KASSERT(pcb != NULL);
156 KASSERT(nam != NULL);
157
158 sa = mtod(nam, struct sockaddr_bt *);
159 nam->m_len = sizeof(struct sockaddr_bt);
160 return l2cap_sockaddr_pcb(pcb, sa);
161 }
162
163 /*
164 * User Request.
165 * up is socket
166 * m is optional mbuf chain containing message
167 * nam is either
168 * optional mbuf chain containing an address
169 * message flags (PRU_RCVD)
170 * ctl is either
171 * optional mbuf chain containing socket options
172 * optional interface pointer PRU_PURGEIF
173 * l is pointer to process requesting action (if any)
174 *
175 * we are responsible for disposing of m and ctl if
176 * they are mbuf chains
177 */
178 static int
179 l2cap_usrreq(struct socket *up, int req, struct mbuf *m,
180 struct mbuf *nam, struct mbuf *ctl, struct lwp *l)
181 {
182 struct l2cap_channel *pcb = up->so_pcb;
183 struct sockaddr_bt *sa;
184 struct mbuf *m0;
185 int err = 0;
186
187 DPRINTFN(2, "%s\n", prurequests[req]);
188 KASSERT(req != PRU_ATTACH);
189 KASSERT(req != PRU_DETACH);
190 KASSERT(req != PRU_CONTROL);
191 KASSERT(req != PRU_SENSE);
192 KASSERT(req != PRU_PEERADDR);
193 KASSERT(req != PRU_SOCKADDR);
194
195 switch (req) {
196 case PRU_PURGEIF:
197 return EOPNOTSUPP;
198 }
199
200 if (pcb == NULL) {
201 err = EINVAL;
202 goto release;
203 }
204
205 switch(req) {
206 case PRU_DISCONNECT:
207 soisdisconnecting(up);
208 return l2cap_disconnect(pcb, up->so_linger);
209
210 case PRU_ABORT:
211 l2cap_disconnect(pcb, 0);
212 soisdisconnected(up);
213 l2cap_detach(up);
214 return 0;
215
216 case PRU_BIND:
217 KASSERT(nam != NULL);
218 sa = mtod(nam, struct sockaddr_bt *);
219
220 if (sa->bt_len != sizeof(struct sockaddr_bt))
221 return EINVAL;
222
223 if (sa->bt_family != AF_BLUETOOTH)
224 return EAFNOSUPPORT;
225
226 return l2cap_bind(pcb, sa);
227
228 case PRU_CONNECT:
229 KASSERT(nam != NULL);
230 sa = mtod(nam, struct sockaddr_bt *);
231
232 if (sa->bt_len != sizeof(struct sockaddr_bt))
233 return EINVAL;
234
235 if (sa->bt_family != AF_BLUETOOTH)
236 return EAFNOSUPPORT;
237
238 soisconnecting(up);
239 return l2cap_connect(pcb, sa);
240
241 case PRU_SHUTDOWN:
242 socantsendmore(up);
243 break;
244
245 case PRU_SEND:
246 KASSERT(m != NULL);
247 if (m->m_pkthdr.len == 0)
248 break;
249
250 if (m->m_pkthdr.len > pcb->lc_omtu) {
251 err = EMSGSIZE;
252 break;
253 }
254
255 m0 = m_copypacket(m, M_DONTWAIT);
256 if (m0 == NULL) {
257 err = ENOMEM;
258 break;
259 }
260
261 if (ctl) /* no use for that */
262 m_freem(ctl);
263
264 sbappendrecord(&up->so_snd, m);
265 return l2cap_send(pcb, m0);
266
267 case PRU_RCVD:
268 case PRU_RCVOOB:
269 return EOPNOTSUPP; /* (no release) */
270
271 case PRU_LISTEN:
272 return l2cap_listen(pcb);
273
274 case PRU_ACCEPT:
275 KASSERT(nam != NULL);
276 sa = mtod(nam, struct sockaddr_bt *);
277 nam->m_len = sizeof(struct sockaddr_bt);
278 return l2cap_peeraddr_pcb(pcb, sa);
279
280 case PRU_CONNECT2:
281 case PRU_SENDOOB:
282 case PRU_FASTTIMO:
283 case PRU_SLOWTIMO:
284 case PRU_PROTORCV:
285 case PRU_PROTOSEND:
286 err = EOPNOTSUPP;
287 break;
288
289 default:
290 UNKNOWN(req);
291 err = EOPNOTSUPP;
292 break;
293 }
294
295 release:
296 if (m) m_freem(m);
297 if (ctl) m_freem(ctl);
298 return err;
299 }
300
301 /*
302 * l2cap_ctloutput(req, socket, sockopt)
303 *
304 * Apply configuration commands to channel. This corresponds to
305 * "Reconfigure Channel Request" in the L2CAP specification.
306 */
307 int
308 l2cap_ctloutput(int req, struct socket *so, struct sockopt *sopt)
309 {
310 struct l2cap_channel *pcb = so->so_pcb;
311 int err = 0;
312
313 DPRINTFN(2, "%s\n", prcorequests[req]);
314
315 if (pcb == NULL)
316 return EINVAL;
317
318 if (sopt->sopt_level != BTPROTO_L2CAP)
319 return ENOPROTOOPT;
320
321 switch(req) {
322 case PRCO_GETOPT:
323 err = l2cap_getopt(pcb, sopt);
324 break;
325
326 case PRCO_SETOPT:
327 err = l2cap_setopt(pcb, sopt);
328 break;
329
330 default:
331 err = ENOPROTOOPT;
332 break;
333 }
334
335 return err;
336 }
337
338 /**********************************************************************
339 *
340 * L2CAP Protocol socket callbacks
341 *
342 */
343
344 static void
345 l2cap_connecting(void *arg)
346 {
347 struct socket *so = arg;
348
349 DPRINTF("Connecting\n");
350 soisconnecting(so);
351 }
352
353 static void
354 l2cap_connected(void *arg)
355 {
356 struct socket *so = arg;
357
358 DPRINTF("Connected\n");
359 soisconnected(so);
360 }
361
362 static void
363 l2cap_disconnected(void *arg, int err)
364 {
365 struct socket *so = arg;
366
367 DPRINTF("Disconnected (%d)\n", err);
368
369 so->so_error = err;
370 soisdisconnected(so);
371 }
372
373 static void *
374 l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
375 struct sockaddr_bt *raddr)
376 {
377 struct socket *so = arg;
378
379 DPRINTF("New Connection\n");
380 so = sonewconn(so, false);
381 if (so == NULL)
382 return NULL;
383
384 soisconnecting(so);
385
386 return so->so_pcb;
387 }
388
389 static void
390 l2cap_complete(void *arg, int count)
391 {
392 struct socket *so = arg;
393
394 while (count-- > 0)
395 sbdroprecord(&so->so_snd);
396
397 sowwakeup(so);
398 }
399
400 static void
401 l2cap_linkmode(void *arg, int new)
402 {
403 struct socket *so = arg;
404 struct sockopt sopt;
405 int mode;
406
407 DPRINTF("auth %s, encrypt %s, secure %s\n",
408 (new & L2CAP_LM_AUTH ? "on" : "off"),
409 (new & L2CAP_LM_ENCRYPT ? "on" : "off"),
410 (new & L2CAP_LM_SECURE ? "on" : "off"));
411
412 sockopt_init(&sopt, BTPROTO_L2CAP, SO_L2CAP_LM, 0);
413 (void)l2cap_getopt(so->so_pcb, &sopt);
414 (void)sockopt_getint(&sopt, &mode);
415 sockopt_destroy(&sopt);
416
417 if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
418 || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
419 || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
420 l2cap_disconnect(so->so_pcb, 0);
421 }
422
423 static void
424 l2cap_input(void *arg, struct mbuf *m)
425 {
426 struct socket *so = arg;
427
428 if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
429 printf("%s: packet (%d bytes) dropped (socket buffer full)\n",
430 __func__, m->m_pkthdr.len);
431 m_freem(m);
432 return;
433 }
434
435 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
436
437 sbappendrecord(&so->so_rcv, m);
438 sorwakeup(so);
439 }
440
441 PR_WRAP_USRREQS(l2cap)
442
443 #define l2cap_attach l2cap_attach_wrapper
444 #define l2cap_detach l2cap_detach_wrapper
445 #define l2cap_ioctl l2cap_ioctl_wrapper
446 #define l2cap_stat l2cap_stat_wrapper
447 #define l2cap_peeraddr l2cap_peeraddr_wrapper
448 #define l2cap_sockaddr l2cap_sockaddr_wrapper
449 #define l2cap_usrreq l2cap_usrreq_wrapper
450
451 const struct pr_usrreqs l2cap_usrreqs = {
452 .pr_attach = l2cap_attach,
453 .pr_detach = l2cap_detach,
454 .pr_ioctl = l2cap_ioctl,
455 .pr_stat = l2cap_stat,
456 .pr_peeraddr = l2cap_peeraddr,
457 .pr_sockaddr = l2cap_sockaddr,
458 .pr_generic = l2cap_usrreq,
459 };
460