xref: /dflybsd-src/sys/netbt/l2cap_socket.c (revision 6cef7136f04e2b24a6db289e78720d6d8c60274e)
1 /* $OpenBSD: l2cap_socket.c,v 1.1 2007/06/01 02:46:11 uwe Exp $ */
2 /* $NetBSD: l2cap_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $ */
3 
4 /*-
5  * Copyright (c) 2005 Iain Hibbert.
6  * Copyright (c) 2006 Itronix Inc.
7  * All rights reserved.
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 /* load symbolic names */
35 #ifdef BLUETOOTH_DEBUG
36 #define PRUREQUESTS
37 #define PRCOREQUESTS
38 #endif
39 
40 #include <sys/param.h>
41 #include <sys/domain.h>
42 #include <sys/kernel.h>
43 #include <sys/mbuf.h>
44 #include <sys/proc.h>
45 #include <sys/protosw.h>
46 #include <sys/socket.h>
47 #include <sys/socketvar.h>
48 #include <sys/systm.h>
49 #include <vm/vm_zone.h>
50 
51 #include <netbt/bluetooth.h>
52 #include <netbt/hci.h>		/* XXX for EPASSTHROUGH */
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 /*
86  * l2cap_ctloutput(request, socket, level, optname, opt)
87  *
88  *	Apply configuration commands to channel. This corresponds to
89  *	"Reconfigure Channel Request" in the L2CAP specification.
90  */
91 int
92 l2cap_ctloutput(struct socket *so, struct sockopt *sopt)
93 {
94 	struct l2cap_channel *pcb = (struct l2cap_channel *) so->so_pcb;
95 	struct mbuf *m;
96 	int err = 0;
97 
98 #ifdef notyet			/* XXX */
99 	DPRINTFN(2, "%s\n", prcorequests[req]);
100 #endif
101 
102 	if (pcb == NULL)
103 		return EINVAL;
104 
105 	if (sopt->sopt_level != BTPROTO_L2CAP)
106 		return ENOPROTOOPT;
107 
108 	switch(sopt->sopt_dir) {
109 	case PRCO_GETOPT:
110 		m = m_get(M_NOWAIT, MT_DATA);
111 		if (m == NULL) {
112 		    err = ENOMEM;
113 		    break;
114 		}
115 		m->m_len = l2cap_getopt(pcb, sopt->sopt_name, mtod(m, void *));
116 		if (m->m_len == 0) {
117 			m_freem(m);
118 			m = NULL;
119 			err = ENOPROTOOPT;
120 		}
121 		soopt_from_kbuf(sopt, mtod(m, void *), m->m_len);
122 		break;
123 
124 	case PRCO_SETOPT:
125 		err = l2cap_setopt2(pcb, sopt->sopt_name, so, sopt);
126 		break;
127 
128 	default:
129 		err = ENOPROTOOPT;
130 		break;
131 	}
132 
133 	return err;
134 }
135 
136 /**********************************************************************
137  *
138  *	L2CAP Protocol socket callbacks
139  *
140  */
141 
142 static void
143 l2cap_connecting(void *arg)
144 {
145 	struct socket *so = arg;
146 
147 	DPRINTF("Connecting\n");
148 	soisconnecting(so);
149 }
150 
151 static void
152 l2cap_connected(void *arg)
153 {
154 	struct socket *so = arg;
155 
156 	DPRINTF("Connected\n");
157 	soisconnected(so);
158 }
159 
160 static void
161 l2cap_disconnected(void *arg, int err)
162 {
163 	struct socket *so = arg;
164 
165 	DPRINTF("Disconnected (%d)\n", err);
166 
167 	so->so_error = err;
168 	soisdisconnected(so);
169 }
170 
171 static void *
172 l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
173     struct sockaddr_bt *raddr)
174 {
175 	struct socket *so = arg;
176 
177 	DPRINTF("New Connection\n");
178 	so = sonewconn(so, 0);
179 	if (so == NULL)
180 		return NULL;
181 
182 	soisconnecting(so);
183 
184 	return so->so_pcb;
185 }
186 
187 static void
188 l2cap_complete(void *arg, int count)
189 {
190 	struct socket *so = arg;
191 
192 	while (count-- > 0)
193 		sbdroprecord(&so->so_snd.sb);
194 
195 	sowwakeup(so);
196 }
197 
198 static void
199 l2cap_linkmode(void *arg, int new)
200 {
201 	struct socket *so = arg;
202 	int mode;
203 
204 	DPRINTF("auth %s, encrypt %s, secure %s\n",
205 		(new & L2CAP_LM_AUTH ? "on" : "off"),
206 		(new & L2CAP_LM_ENCRYPT ? "on" : "off"),
207 		(new & L2CAP_LM_SECURE ? "on" : "off"));
208 
209 	(void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode);
210 	if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
211 	    || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
212 	    || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
213 		l2cap_disconnect(so->so_pcb, 0);
214 }
215 
216 static void
217 l2cap_input(void *arg, struct mbuf *m)
218 {
219 	struct socket *so = arg;
220 
221 	if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
222 		kprintf("%s: packet (%d bytes) dropped (socket buffer full)\n",
223 			__func__, m->m_pkthdr.len);
224 		m_freem(m);
225 		return;
226 	}
227 
228 	DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
229 
230 	sbappendrecord(&so->so_rcv.sb, m);
231 	sorwakeup(so);
232 }
233 
234 
235 /*
236  * Implementation of usrreqs.
237  */
238 static int
239 l2cap_sdetach(struct socket *so)
240 {
241 	return l2cap_detach((struct l2cap_channel **)&so->so_pcb);
242 }
243 
244 /*
245  * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
246  *	 will sofree() it when we return.
247  */
248 static int
249 l2cap_sabort (struct socket *so)
250 {
251 	struct l2cap_channel *pcb = so->so_pcb;
252 	int error;
253 
254 	l2cap_disconnect(pcb, 0);
255 	soisdisconnected(so);
256 
257 	error = l2cap_sdetach(so);
258 	return error;
259 }
260 
261 static int
262 l2cap_sdisconnect (struct socket *so)
263 {
264 	struct l2cap_channel *pcb = so->so_pcb;
265 
266 	soisdisconnecting(so);
267 
268 	return l2cap_disconnect(pcb, so->so_linger);
269 }
270 
271 static int
272 l2cap_scontrol (struct socket *so, u_long cmd, caddr_t data,
273     struct ifnet *ifp, struct thread *td)
274 {
275 	return EPASSTHROUGH;
276 }
277 
278 static int
279 l2cap_sattach (struct socket *so, int proto,
280 			       struct pru_attach_info *ai)
281 {
282 	struct l2cap_channel *pcb = so->so_pcb;
283 	int err = 0;
284 
285 	if (pcb != NULL)
286 		return EINVAL;
287 
288 	/*
289 	 * For L2CAP socket PCB we just use an l2cap_channel structure
290 	 * since we have nothing to add..
291 	 */
292 	err = soreserve(so, l2cap_sendspace, l2cap_recvspace, NULL);
293 	if (err)
294 		return err;
295 
296 	return l2cap_attach((struct l2cap_channel **)&so->so_pcb,
297 	    &l2cap_proto, so);
298 }
299 
300 static int
301 l2cap_sbind (struct socket *so, struct sockaddr *nam,
302 				 struct thread *td)
303 {
304 	struct l2cap_channel *pcb = so->so_pcb;
305 	struct sockaddr_bt *sa;
306 
307 	KKASSERT(nam != NULL);
308 	sa = (struct sockaddr_bt *)nam;
309 
310 	if (sa->bt_len != sizeof(struct sockaddr_bt))
311 		return EINVAL;
312 
313 	if (sa->bt_family != AF_BLUETOOTH)
314 		return EAFNOSUPPORT;
315 
316 	return l2cap_bind(pcb, sa);
317 }
318 
319 static int
320 l2cap_sconnect (struct socket *so, struct sockaddr *nam,
321 				    struct thread *td)
322 {
323 	struct l2cap_channel *pcb = so->so_pcb;
324 	struct sockaddr_bt *sa;
325 
326 	KKASSERT(nam != NULL);
327 	sa = (struct sockaddr_bt *)nam;
328 
329 	if (sa->bt_len != sizeof(struct sockaddr_bt))
330 		return EINVAL;
331 
332 	if (sa->bt_family != AF_BLUETOOTH)
333 		return EAFNOSUPPORT;
334 
335 	soisconnecting(so);
336 	return l2cap_connect(pcb, sa);
337 }
338 
339 static int
340 l2cap_speeraddr (struct socket *so, struct sockaddr **nam)
341 {
342 	struct l2cap_channel *pcb = so->so_pcb;
343 	struct sockaddr_bt *sa, ssa;
344 	int e;
345 
346 	sa = &ssa;
347 	bzero(sa, sizeof *sa);
348 	sa->bt_len = sizeof(struct sockaddr_bt);
349 	sa->bt_family = AF_BLUETOOTH;
350 	e = l2cap_peeraddr(pcb, sa);
351 	*nam = dup_sockaddr((struct sockaddr *)sa);
352 
353 	return (e);
354 }
355 
356 static int
357 l2cap_ssockaddr (struct socket *so, struct sockaddr **nam)
358 {
359 	struct l2cap_channel *pcb = so->so_pcb;
360 	struct sockaddr_bt *sa, ssa;
361 	int e;
362 
363 	sa = &ssa;
364 	bzero(sa, sizeof *sa);
365 	sa->bt_len = sizeof(struct sockaddr_bt);
366 	sa->bt_family = AF_BLUETOOTH;
367 	e = l2cap_sockaddr(pcb, sa);
368 	*nam = dup_sockaddr((struct sockaddr *)sa);
369 
370 	return (e);
371 }
372 
373 static int
374 l2cap_sshutdown (struct socket *so)
375 {
376 	socantsendmore(so);
377 	return 0;
378 }
379 
380 static int
381 l2cap_ssend (struct socket *so, int flags, struct mbuf *m,
382     struct sockaddr *addr, struct mbuf *control, struct thread *td)
383 {
384 	struct l2cap_channel *pcb = so->so_pcb;
385 	struct mbuf *m0;
386 
387 	int err = 0;
388 
389 	KKASSERT(m != NULL);
390 	if (m->m_pkthdr.len == 0)
391 		goto error;
392 
393 	if (m->m_pkthdr.len > pcb->lc_omtu) {
394 		err = EMSGSIZE;
395 		goto error;
396 	}
397 
398 	m0 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT);
399 	if (m0 == NULL) {
400 		err = ENOMEM;
401 		goto error;
402 	}
403 
404 	if (control)	/* no use for that */
405 		m_freem(control);
406 
407 	sbappendrecord(&so->so_snd.sb, m);
408 	return l2cap_send(pcb, m0);
409 
410 error:
411 	if (m)
412 		m_freem(m);
413 	if (control)
414 		m_freem(control);
415 
416 	return err;
417 }
418 
419 static int
420 l2cap_saccept(struct socket *so, struct sockaddr **nam)
421 {
422 	struct l2cap_channel *pcb = so->so_pcb;
423 	struct sockaddr_bt sa;
424 	int e;
425 
426 	KKASSERT(nam != NULL);
427 
428 	bzero(&sa, sizeof (sa) );
429 	sa.bt_len = sizeof(struct sockaddr_bt);
430 	sa.bt_family = AF_BLUETOOTH;
431 
432 	e = l2cap_peeraddr(pcb, &sa);
433 	*nam = dup_sockaddr((struct sockaddr *)&sa);
434 
435 	return e;
436 }
437 
438 static int
439 l2cap_slisten(struct socket *so, struct thread *td)
440 {
441 	struct l2cap_channel *pcb = so->so_pcb;
442 	return l2cap_listen(pcb);
443 }
444 
445 
446 struct pr_usrreqs l2cap_usrreqs = {
447         .pru_abort = l2cap_sabort,
448         .pru_accept = l2cap_saccept,
449         .pru_attach = l2cap_sattach,
450         .pru_bind = l2cap_sbind,
451         .pru_connect = l2cap_sconnect,
452         .pru_connect2 = pru_connect2_notsupp,
453         .pru_control = l2cap_scontrol,
454         .pru_detach = l2cap_sdetach,
455         .pru_disconnect = l2cap_sdisconnect,
456         .pru_listen = l2cap_slisten,
457         .pru_peeraddr = l2cap_speeraddr,
458         .pru_rcvd = pru_rcvd_notsupp,
459         .pru_rcvoob = pru_rcvoob_notsupp,
460         .pru_send = l2cap_ssend,
461         .pru_sense = pru_sense_null,
462         .pru_shutdown = l2cap_sshutdown,
463         .pru_sockaddr = l2cap_ssockaddr,
464         .pru_sosend = sosend,
465         .pru_soreceive = soreceive
466 };
467