xref: /dragonfly/sys/netbt/l2cap_socket.c (revision 8a7bdfea)
1 /* $DragonFly: src/sys/netbt/l2cap_socket.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */
2 /* $OpenBSD: l2cap_socket.c,v 1.1 2007/06/01 02:46:11 uwe Exp $ */
3 /* $NetBSD: l2cap_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $ */
4 
5 /*-
6  * Copyright (c) 2005 Iain Hibbert.
7  * Copyright (c) 2006 Itronix Inc.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. The name of Itronix Inc. may not be used to endorse
19  *    or promote products derived from this software without specific
20  *    prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
26  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29  * ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <sys/cdefs.h>
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 #include <vm/vm_zone.h>
53 
54 #include <netbt/bluetooth.h>
55 #include <netbt/hci.h>		/* XXX for EPASSTHROUGH */
56 #include <netbt/l2cap.h>
57 
58 /*
59  * L2CAP Sockets
60  *
61  *	SOCK_SEQPACKET - normal L2CAP connection
62  *
63  *	SOCK_DGRAM - connectionless L2CAP - XXX not yet
64  */
65 
66 static void l2cap_connecting(void *);
67 static void l2cap_connected(void *);
68 static void l2cap_disconnected(void *, int);
69 static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
70 static void l2cap_complete(void *, int);
71 static void l2cap_linkmode(void *, int);
72 static void l2cap_input(void *, struct mbuf *);
73 
74 static const struct btproto l2cap_proto = {
75 	l2cap_connecting,
76 	l2cap_connected,
77 	l2cap_disconnected,
78 	l2cap_newconn,
79 	l2cap_complete,
80 	l2cap_linkmode,
81 	l2cap_input,
82 };
83 
84 /* sysctl variables */
85 int l2cap_sendspace = 4096;
86 int l2cap_recvspace = 4096;
87 
88 /*
89  * l2cap_ctloutput(request, socket, level, optname, opt)
90  *
91  *	Apply configuration commands to channel. This corresponds to
92  *	"Reconfigure Channel Request" in the L2CAP specification.
93  */
94 int
95 l2cap_ctloutput(struct socket *so, struct sockopt *sopt)
96 {
97 	struct l2cap_channel *pcb = (struct l2cap_channel *) so->so_pcb;
98 	struct mbuf *m;
99 	int err = 0;
100 
101 #ifdef notyet			/* XXX */
102 	DPRINTFN(2, "%s\n", prcorequests[req]);
103 #endif
104 
105 	if (pcb == NULL)
106 		return EINVAL;
107 
108 	if (sopt->sopt_level != BTPROTO_L2CAP)
109 		return ENOPROTOOPT;
110 
111 	switch(sopt->sopt_dir) {
112 	case PRCO_GETOPT:
113 		m = m_get(M_NOWAIT, MT_DATA);
114 		if (m == NULL) {
115 		    err = ENOMEM;
116 		    break;
117 		}
118 		m->m_len = l2cap_getopt(pcb, sopt->sopt_name, mtod(m, void *));
119 		if (m->m_len == 0) {
120 			m_freem(m);
121 			m = NULL;
122 			err = ENOPROTOOPT;
123 		}
124 		err = sooptcopyout(sopt, mtod(m, void *), m->m_len);
125 		break;
126 
127 	case PRCO_SETOPT:
128 		err = l2cap_setopt2(pcb, sopt->sopt_name, so, sopt);
129 		break;
130 
131 	default:
132 		err = ENOPROTOOPT;
133 		break;
134 	}
135 
136 	return err;
137 }
138 
139 /**********************************************************************
140  *
141  *	L2CAP Protocol socket callbacks
142  *
143  */
144 
145 static void
146 l2cap_connecting(void *arg)
147 {
148 	struct socket *so = arg;
149 
150 	DPRINTF("Connecting\n");
151 	soisconnecting(so);
152 }
153 
154 static void
155 l2cap_connected(void *arg)
156 {
157 	struct socket *so = arg;
158 
159 	DPRINTF("Connected\n");
160 	soisconnected(so);
161 }
162 
163 static void
164 l2cap_disconnected(void *arg, int err)
165 {
166 	struct socket *so = arg;
167 
168 	DPRINTF("Disconnected (%d)\n", err);
169 
170 	so->so_error = err;
171 	soisdisconnected(so);
172 }
173 
174 static void *
175 l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
176     struct sockaddr_bt *raddr)
177 {
178 	struct socket *so = arg;
179 
180 	DPRINTF("New Connection\n");
181 	so = sonewconn(so, 0);
182 	if (so == NULL)
183 		return NULL;
184 
185 	soisconnecting(so);
186 
187 	return so->so_pcb;
188 }
189 
190 static void
191 l2cap_complete(void *arg, int count)
192 {
193 	struct socket *so = arg;
194 
195 	while (count-- > 0)
196 		sbdroprecord(&so->so_snd.sb);
197 
198 	sowwakeup(so);
199 }
200 
201 static void
202 l2cap_linkmode(void *arg, int new)
203 {
204 	struct socket *so = arg;
205 	int mode;
206 
207 	DPRINTF("auth %s, encrypt %s, secure %s\n",
208 		(new & L2CAP_LM_AUTH ? "on" : "off"),
209 		(new & L2CAP_LM_ENCRYPT ? "on" : "off"),
210 		(new & L2CAP_LM_SECURE ? "on" : "off"));
211 
212 	(void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode);
213 	if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
214 	    || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
215 	    || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
216 		l2cap_disconnect(so->so_pcb, 0);
217 }
218 
219 static void
220 l2cap_input(void *arg, struct mbuf *m)
221 {
222 	struct socket *so = arg;
223 
224 	if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
225 		kprintf("%s: packet (%d bytes) dropped (socket buffer full)\n",
226 			__func__, m->m_pkthdr.len);
227 		m_freem(m);
228 		return;
229 	}
230 
231 	DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
232 
233 	sbappendrecord(&so->so_rcv.sb, m);
234 	sorwakeup(so);
235 }
236 
237 
238 /*
239  * Implementation of usrreqs.
240  */
241 static int
242 l2cap_sdetach(struct socket *so)
243 {
244 	return l2cap_detach((struct l2cap_channel **)&so->so_pcb);
245 }
246 
247 static int
248 l2cap_sabort (struct socket *so)
249 {
250 	struct l2cap_channel *pcb = so->so_pcb;
251 
252 	l2cap_disconnect(pcb, 0);
253 	soisdisconnected(so);
254 
255 	return l2cap_sdetach(so);
256 }
257 
258 static int
259 l2cap_sdisconnect (struct socket *so)
260 {
261 	struct l2cap_channel *pcb = so->so_pcb;
262 
263 	soisdisconnecting(so);
264 
265 	return l2cap_disconnect(pcb, so->so_linger);
266 }
267 
268 static int
269 l2cap_scontrol (struct socket *so, u_long cmd, caddr_t data,
270     struct ifnet *ifp, struct thread *td)
271 {
272 	return EPASSTHROUGH;
273 }
274 
275 static int
276 l2cap_sattach (struct socket *so, int proto,
277 			       struct pru_attach_info *ai)
278 {
279 	struct l2cap_channel *pcb = so->so_pcb;
280 	int err = 0;
281 
282 	if (pcb != NULL)
283 		return EINVAL;
284 
285 	/*
286 	 * For L2CAP socket PCB we just use an l2cap_channel structure
287 	 * since we have nothing to add..
288 	 */
289 	err = soreserve(so, l2cap_sendspace, l2cap_recvspace, NULL);
290 	if (err)
291 		return err;
292 
293 	return l2cap_attach((struct l2cap_channel **)&so->so_pcb,
294 	    &l2cap_proto, so);
295 }
296 
297 static int
298 l2cap_sbind (struct socket *so, struct sockaddr *nam,
299 				 struct thread *td)
300 {
301 	struct l2cap_channel *pcb = so->so_pcb;
302 	struct sockaddr_bt *sa;
303 
304 	KKASSERT(nam != NULL);
305 	sa = (struct sockaddr_bt *)nam;
306 
307 	if (sa->bt_len != sizeof(struct sockaddr_bt))
308 		return EINVAL;
309 
310 	if (sa->bt_family != AF_BLUETOOTH)
311 		return EAFNOSUPPORT;
312 
313 	return l2cap_bind(pcb, sa);
314 }
315 
316 static int
317 l2cap_sconnect (struct socket *so, struct sockaddr *nam,
318 				    struct thread *td)
319 {
320 	struct l2cap_channel *pcb = so->so_pcb;
321 	struct sockaddr_bt *sa;
322 
323 	KKASSERT(nam != NULL);
324 	sa = (struct sockaddr_bt *)nam;
325 
326 	if (sa->bt_len != sizeof(struct sockaddr_bt))
327 		return EINVAL;
328 
329 	if (sa->bt_family != AF_BLUETOOTH)
330 		return EAFNOSUPPORT;
331 
332 	soisconnecting(so);
333 	return l2cap_connect(pcb, sa);
334 }
335 
336 static int
337 l2cap_speeraddr (struct socket *so, struct sockaddr **nam)
338 {
339 	struct l2cap_channel *pcb = so->so_pcb;
340 	struct sockaddr_bt *sa, ssa;
341 	int e;
342 
343 	sa = &ssa;
344 	bzero(sa, sizeof *sa);
345 	sa->bt_len = sizeof(struct sockaddr_bt);
346 	sa->bt_family = AF_BLUETOOTH;
347 	e = l2cap_peeraddr(pcb, sa);
348 	*nam = dup_sockaddr((struct sockaddr *)sa);
349 
350 	return (e);
351 }
352 
353 static int
354 l2cap_ssockaddr (struct socket *so, struct sockaddr **nam)
355 {
356 	struct l2cap_channel *pcb = so->so_pcb;
357 	struct sockaddr_bt *sa, ssa;
358 	int e;
359 
360 	sa = &ssa;
361 	bzero(sa, sizeof *sa);
362 	sa->bt_len = sizeof(struct sockaddr_bt);
363 	sa->bt_family = AF_BLUETOOTH;
364 	e = l2cap_sockaddr(pcb, sa);
365 	*nam = dup_sockaddr((struct sockaddr *)sa);
366 
367 	return (e);
368 }
369 
370 static int
371 l2cap_sshutdown (struct socket *so)
372 {
373 	socantsendmore(so);
374 	return 0;
375 }
376 
377 static int
378 l2cap_ssend (struct socket *so, int flags, struct mbuf *m,
379     struct sockaddr *addr, struct mbuf *control, struct thread *td)
380 {
381 	struct l2cap_channel *pcb = so->so_pcb;
382 	struct mbuf *m0;
383 
384 	int err = 0;
385 
386 	KKASSERT(m != NULL);
387 	if (m->m_pkthdr.len == 0)
388 		goto error;
389 
390 	if (m->m_pkthdr.len > pcb->lc_omtu) {
391 		err = EMSGSIZE;
392 		goto error;
393 	}
394 
395 	m0 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT);
396 	if (m0 == NULL) {
397 		err = ENOMEM;
398 		goto error;
399 	}
400 
401 	if (control)	/* no use for that */
402 		m_freem(control);
403 
404 	sbappendrecord(&so->so_snd.sb, m);
405 	return l2cap_send(pcb, m0);
406 
407 error:
408 	if (m)
409 		m_freem(m);
410 	if (control)
411 		m_freem(control);
412 
413 	return err;
414 }
415 
416 static int
417 l2cap_saccept(struct socket *so, struct sockaddr **nam)
418 {
419 	struct l2cap_channel *pcb = so->so_pcb;
420 	struct sockaddr_bt sa;
421 	int e;
422 
423 	KKASSERT(nam != NULL);
424 
425 	bzero(&sa, sizeof (sa) );
426 	sa.bt_len = sizeof(struct sockaddr_bt);
427 	sa.bt_family = AF_BLUETOOTH;
428 
429 	e = l2cap_peeraddr(pcb, &sa);
430 	*nam = dup_sockaddr((struct sockaddr *)&sa);
431 
432 	return e;
433 }
434 
435 static int
436 l2cap_slisten(struct socket *so, struct thread *td)
437 {
438 	struct l2cap_channel *pcb = so->so_pcb;
439 	return l2cap_listen(pcb);
440 }
441 
442 
443 struct pr_usrreqs l2cap_usrreqs = {
444         .pru_abort = l2cap_sabort,
445         .pru_accept = l2cap_saccept,
446         .pru_attach = l2cap_sattach,
447         .pru_bind = l2cap_sbind,
448         .pru_connect = l2cap_sconnect,
449         .pru_connect2 = pru_connect2_notsupp,
450         .pru_control = l2cap_scontrol,
451         .pru_detach = l2cap_sdetach,
452         .pru_disconnect = l2cap_sdisconnect,
453         .pru_listen = l2cap_slisten,
454         .pru_peeraddr = l2cap_speeraddr,
455         .pru_rcvd = pru_rcvd_notsupp,
456         .pru_rcvoob = pru_rcvoob_notsupp,
457         .pru_send = l2cap_ssend,
458         .pru_sense = pru_sense_null,
459         .pru_shutdown = l2cap_sshutdown,
460         .pru_sockaddr = l2cap_ssockaddr,
461         .pru_sosend = sosend,
462         .pru_soreceive = soreceive,
463         .pru_sopoll = sopoll
464 };
465