xref: /netbsd-src/sys/netbt/l2cap_socket.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: l2cap_socket.c,v 1.17 2014/07/01 05:49:18 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.17 2014/07/01 05:49:18 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 *up, u_long cmd, void *nam, struct ifnet *ifp)
121 {
122 	return EPASSTHROUGH;
123 }
124 
125 /*
126  * User Request.
127  * up is socket
128  * m is optional mbuf chain containing message
129  * nam is either
130  *	optional mbuf chain containing an address
131  *	message flags (PRU_RCVD)
132  * ctl is either
133  *	optional mbuf chain containing socket options
134  *	optional interface pointer PRU_PURGEIF
135  * l is pointer to process requesting action (if any)
136  *
137  * we are responsible for disposing of m and ctl if
138  * they are mbuf chains
139  */
140 static int
141 l2cap_usrreq(struct socket *up, int req, struct mbuf *m,
142     struct mbuf *nam, struct mbuf *ctl, struct lwp *l)
143 {
144 	struct l2cap_channel *pcb = up->so_pcb;
145 	struct sockaddr_bt *sa;
146 	struct mbuf *m0;
147 	int err = 0;
148 
149 	DPRINTFN(2, "%s\n", prurequests[req]);
150 	KASSERT(req != PRU_ATTACH);
151 	KASSERT(req != PRU_DETACH);
152 	KASSERT(req != PRU_CONTROL);
153 
154 	switch (req) {
155 	case PRU_PURGEIF:
156 		return EOPNOTSUPP;
157 	}
158 
159 	if (pcb == NULL) {
160 		err = EINVAL;
161 		goto release;
162 	}
163 
164 	switch(req) {
165 	case PRU_DISCONNECT:
166 		soisdisconnecting(up);
167 		return l2cap_disconnect(pcb, up->so_linger);
168 
169 	case PRU_ABORT:
170 		l2cap_disconnect(pcb, 0);
171 		soisdisconnected(up);
172 		l2cap_detach(up);
173 		return 0;
174 
175 	case PRU_BIND:
176 		KASSERT(nam != NULL);
177 		sa = mtod(nam, struct sockaddr_bt *);
178 
179 		if (sa->bt_len != sizeof(struct sockaddr_bt))
180 			return EINVAL;
181 
182 		if (sa->bt_family != AF_BLUETOOTH)
183 			return EAFNOSUPPORT;
184 
185 		return l2cap_bind(pcb, sa);
186 
187 	case PRU_CONNECT:
188 		KASSERT(nam != NULL);
189 		sa = mtod(nam, struct sockaddr_bt *);
190 
191 		if (sa->bt_len != sizeof(struct sockaddr_bt))
192 			return EINVAL;
193 
194 		if (sa->bt_family != AF_BLUETOOTH)
195 			return EAFNOSUPPORT;
196 
197 		soisconnecting(up);
198 		return l2cap_connect(pcb, sa);
199 
200 	case PRU_PEERADDR:
201 		KASSERT(nam != NULL);
202 		sa = mtod(nam, struct sockaddr_bt *);
203 		nam->m_len = sizeof(struct sockaddr_bt);
204 		return l2cap_peeraddr(pcb, sa);
205 
206 	case PRU_SOCKADDR:
207 		KASSERT(nam != NULL);
208 		sa = mtod(nam, struct sockaddr_bt *);
209 		nam->m_len = sizeof(struct sockaddr_bt);
210 		return l2cap_sockaddr(pcb, sa);
211 
212 	case PRU_SHUTDOWN:
213 		socantsendmore(up);
214 		break;
215 
216 	case PRU_SEND:
217 		KASSERT(m != NULL);
218 		if (m->m_pkthdr.len == 0)
219 			break;
220 
221 		if (m->m_pkthdr.len > pcb->lc_omtu) {
222 			err = EMSGSIZE;
223 			break;
224 		}
225 
226 		m0 = m_copypacket(m, M_DONTWAIT);
227 		if (m0 == NULL) {
228 			err = ENOMEM;
229 			break;
230 		}
231 
232 		if (ctl)	/* no use for that */
233 			m_freem(ctl);
234 
235 		sbappendrecord(&up->so_snd, m);
236 		return l2cap_send(pcb, m0);
237 
238 	case PRU_SENSE:
239 		return 0;		/* (no release) */
240 
241 	case PRU_RCVD:
242 	case PRU_RCVOOB:
243 		return EOPNOTSUPP;	/* (no release) */
244 
245 	case PRU_LISTEN:
246 		return l2cap_listen(pcb);
247 
248 	case PRU_ACCEPT:
249 		KASSERT(nam != NULL);
250 		sa = mtod(nam, struct sockaddr_bt *);
251 		nam->m_len = sizeof(struct sockaddr_bt);
252 		return l2cap_peeraddr(pcb, sa);
253 
254 	case PRU_CONNECT2:
255 	case PRU_SENDOOB:
256 	case PRU_FASTTIMO:
257 	case PRU_SLOWTIMO:
258 	case PRU_PROTORCV:
259 	case PRU_PROTOSEND:
260 		err = EOPNOTSUPP;
261 		break;
262 
263 	default:
264 		UNKNOWN(req);
265 		err = EOPNOTSUPP;
266 		break;
267 	}
268 
269 release:
270 	if (m) m_freem(m);
271 	if (ctl) m_freem(ctl);
272 	return err;
273 }
274 
275 /*
276  * l2cap_ctloutput(req, socket, sockopt)
277  *
278  *	Apply configuration commands to channel. This corresponds to
279  *	"Reconfigure Channel Request" in the L2CAP specification.
280  */
281 int
282 l2cap_ctloutput(int req, struct socket *so, struct sockopt *sopt)
283 {
284 	struct l2cap_channel *pcb = so->so_pcb;
285 	int err = 0;
286 
287 	DPRINTFN(2, "%s\n", prcorequests[req]);
288 
289 	if (pcb == NULL)
290 		return EINVAL;
291 
292 	if (sopt->sopt_level != BTPROTO_L2CAP)
293 		return ENOPROTOOPT;
294 
295 	switch(req) {
296 	case PRCO_GETOPT:
297 		err = l2cap_getopt(pcb, sopt);
298 		break;
299 
300 	case PRCO_SETOPT:
301 		err = l2cap_setopt(pcb, sopt);
302 		break;
303 
304 	default:
305 		err = ENOPROTOOPT;
306 		break;
307 	}
308 
309 	return err;
310 }
311 
312 /**********************************************************************
313  *
314  *	L2CAP Protocol socket callbacks
315  *
316  */
317 
318 static void
319 l2cap_connecting(void *arg)
320 {
321 	struct socket *so = arg;
322 
323 	DPRINTF("Connecting\n");
324 	soisconnecting(so);
325 }
326 
327 static void
328 l2cap_connected(void *arg)
329 {
330 	struct socket *so = arg;
331 
332 	DPRINTF("Connected\n");
333 	soisconnected(so);
334 }
335 
336 static void
337 l2cap_disconnected(void *arg, int err)
338 {
339 	struct socket *so = arg;
340 
341 	DPRINTF("Disconnected (%d)\n", err);
342 
343 	so->so_error = err;
344 	soisdisconnected(so);
345 }
346 
347 static void *
348 l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
349     struct sockaddr_bt *raddr)
350 {
351 	struct socket *so = arg;
352 
353 	DPRINTF("New Connection\n");
354 	so = sonewconn(so, false);
355 	if (so == NULL)
356 		return NULL;
357 
358 	soisconnecting(so);
359 
360 	return so->so_pcb;
361 }
362 
363 static void
364 l2cap_complete(void *arg, int count)
365 {
366 	struct socket *so = arg;
367 
368 	while (count-- > 0)
369 		sbdroprecord(&so->so_snd);
370 
371 	sowwakeup(so);
372 }
373 
374 static void
375 l2cap_linkmode(void *arg, int new)
376 {
377 	struct socket *so = arg;
378 	struct sockopt sopt;
379 	int mode;
380 
381 	DPRINTF("auth %s, encrypt %s, secure %s\n",
382 		(new & L2CAP_LM_AUTH ? "on" : "off"),
383 		(new & L2CAP_LM_ENCRYPT ? "on" : "off"),
384 		(new & L2CAP_LM_SECURE ? "on" : "off"));
385 
386 	sockopt_init(&sopt, BTPROTO_L2CAP, SO_L2CAP_LM, 0);
387 	(void)l2cap_getopt(so->so_pcb, &sopt);
388 	(void)sockopt_getint(&sopt, &mode);
389 	sockopt_destroy(&sopt);
390 
391 	if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
392 	    || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
393 	    || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
394 		l2cap_disconnect(so->so_pcb, 0);
395 }
396 
397 static void
398 l2cap_input(void *arg, struct mbuf *m)
399 {
400 	struct socket *so = arg;
401 
402 	if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
403 		printf("%s: packet (%d bytes) dropped (socket buffer full)\n",
404 			__func__, m->m_pkthdr.len);
405 		m_freem(m);
406 		return;
407 	}
408 
409 	DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
410 
411 	sbappendrecord(&so->so_rcv, m);
412 	sorwakeup(so);
413 }
414 
415 PR_WRAP_USRREQS(l2cap)
416 
417 #define	l2cap_attach		l2cap_attach_wrapper
418 #define	l2cap_detach		l2cap_detach_wrapper
419 #define	l2cap_ioctl		l2cap_ioctl_wrapper
420 #define	l2cap_usrreq		l2cap_usrreq_wrapper
421 
422 const struct pr_usrreqs l2cap_usrreqs = {
423 	.pr_attach	= l2cap_attach,
424 	.pr_detach	= l2cap_detach,
425 	.pr_ioctl	= l2cap_ioctl,
426 	.pr_generic	= l2cap_usrreq,
427 };
428