Annotation of sys/netbt/l2cap_socket.c, Revision 1.1.1.1
1.1 nbrk 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: #include <sys/cdefs.h>
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/hci.h> /* XXX for EPASSTHROUGH */
54: #include <netbt/l2cap.h>
55:
56: /*
57: * L2CAP Sockets
58: *
59: * SOCK_SEQPACKET - normal L2CAP connection
60: *
61: * SOCK_DGRAM - connectionless L2CAP - XXX not yet
62: */
63:
64: static void l2cap_connecting(void *);
65: static void l2cap_connected(void *);
66: static void l2cap_disconnected(void *, int);
67: static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
68: static void l2cap_complete(void *, int);
69: static void l2cap_linkmode(void *, int);
70: static void l2cap_input(void *, struct mbuf *);
71:
72: static const struct btproto l2cap_proto = {
73: l2cap_connecting,
74: l2cap_connected,
75: l2cap_disconnected,
76: l2cap_newconn,
77: l2cap_complete,
78: l2cap_linkmode,
79: l2cap_input,
80: };
81:
82: /* sysctl variables */
83: int l2cap_sendspace = 4096;
84: int l2cap_recvspace = 4096;
85:
86: /*
87: * User Request.
88: * up is socket
89: * m is either
90: * optional mbuf chain containing message
91: * ioctl command (PRU_CONTROL)
92: * nam is either
93: * optional mbuf chain containing an address
94: * ioctl data (PRU_CONTROL)
95: * optionally protocol number (PRU_ATTACH)
96: * message flags (PRU_RCVD)
97: * ctl is either
98: * optional mbuf chain containing socket options
99: * optional interface pointer (PRU_CONTROL, PRU_PURGEIF)
100: * l is pointer to process requesting action (if any)
101: *
102: * we are responsible for disposing of m and ctl if
103: * they are mbuf chains
104: */
105: int
106: l2cap_usrreq(struct socket *up, int req, struct mbuf *m,
107: struct mbuf *nam, struct mbuf *ctl)
108: {
109: struct l2cap_channel *pcb = up->so_pcb;
110: struct sockaddr_bt *sa;
111: struct mbuf *m0;
112: int err = 0;
113:
114: #ifdef notyet /* XXX */
115: DPRINTFN(2, "%s\n", prurequests[req]);
116: #endif
117:
118: switch (req) {
119: case PRU_CONTROL:
120: return EPASSTHROUGH;
121:
122: #ifdef notyet /* XXX */
123: case PRU_PURGEIF:
124: return EOPNOTSUPP;
125: #endif
126:
127: case PRU_ATTACH:
128: if (pcb != NULL)
129: return EINVAL;
130:
131: /*
132: * For L2CAP socket PCB we just use an l2cap_channel structure
133: * since we have nothing to add..
134: */
135: err = soreserve(up, l2cap_sendspace, l2cap_recvspace);
136: if (err)
137: return err;
138:
139: return l2cap_attach((struct l2cap_channel **)&up->so_pcb,
140: &l2cap_proto, up);
141: }
142:
143: if (pcb == NULL) {
144: err = EINVAL;
145: goto release;
146: }
147:
148: switch(req) {
149: case PRU_DISCONNECT:
150: soisdisconnecting(up);
151: return l2cap_disconnect(pcb, up->so_linger);
152:
153: case PRU_ABORT:
154: l2cap_disconnect(pcb, 0);
155: soisdisconnected(up);
156: /* fall through to */
157: case PRU_DETACH:
158: return l2cap_detach((struct l2cap_channel **)&up->so_pcb);
159:
160: case PRU_BIND:
161: KASSERT(nam != NULL);
162: sa = mtod(nam, struct sockaddr_bt *);
163:
164: if (sa->bt_len != sizeof(struct sockaddr_bt))
165: return EINVAL;
166:
167: if (sa->bt_family != AF_BLUETOOTH)
168: return EAFNOSUPPORT;
169:
170: return l2cap_bind(pcb, sa);
171:
172: case PRU_CONNECT:
173: KASSERT(nam != NULL);
174: sa = mtod(nam, struct sockaddr_bt *);
175:
176: if (sa->bt_len != sizeof(struct sockaddr_bt))
177: return EINVAL;
178:
179: if (sa->bt_family != AF_BLUETOOTH)
180: return EAFNOSUPPORT;
181:
182: soisconnecting(up);
183: return l2cap_connect(pcb, sa);
184:
185: case PRU_PEERADDR:
186: KASSERT(nam != NULL);
187: sa = mtod(nam, struct sockaddr_bt *);
188: nam->m_len = sizeof(struct sockaddr_bt);
189: return l2cap_peeraddr(pcb, sa);
190:
191: case PRU_SOCKADDR:
192: KASSERT(nam != NULL);
193: sa = mtod(nam, struct sockaddr_bt *);
194: nam->m_len = sizeof(struct sockaddr_bt);
195: return l2cap_sockaddr(pcb, sa);
196:
197: case PRU_SHUTDOWN:
198: socantsendmore(up);
199: break;
200:
201: case PRU_SEND:
202: KASSERT(m != NULL);
203: if (m->m_pkthdr.len == 0)
204: break;
205:
206: if (m->m_pkthdr.len > pcb->lc_omtu) {
207: err = EMSGSIZE;
208: break;
209: }
210:
211: m0 = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
212: if (m0 == NULL) {
213: err = ENOMEM;
214: break;
215: }
216:
217: if (ctl) /* no use for that */
218: m_freem(ctl);
219:
220: sbappendrecord(&up->so_snd, m);
221: return l2cap_send(pcb, m0);
222:
223: case PRU_SENSE:
224: return 0; /* (no release) */
225:
226: case PRU_RCVD:
227: case PRU_RCVOOB:
228: return EOPNOTSUPP; /* (no release) */
229:
230: case PRU_LISTEN:
231: return l2cap_listen(pcb);
232:
233: case PRU_ACCEPT:
234: KASSERT(nam != NULL);
235: sa = mtod(nam, struct sockaddr_bt *);
236: nam->m_len = sizeof(struct sockaddr_bt);
237: return l2cap_peeraddr(pcb, sa);
238:
239: case PRU_CONNECT2:
240: case PRU_SENDOOB:
241: case PRU_FASTTIMO:
242: case PRU_SLOWTIMO:
243: case PRU_PROTORCV:
244: case PRU_PROTOSEND:
245: err = EOPNOTSUPP;
246: break;
247:
248: default:
249: UNKNOWN(req);
250: err = EOPNOTSUPP;
251: break;
252: }
253:
254: release:
255: if (m) m_freem(m);
256: if (ctl) m_freem(ctl);
257: return err;
258: }
259:
260: /*
261: * l2cap_ctloutput(request, socket, level, optname, opt)
262: *
263: * Apply configuration commands to channel. This corresponds to
264: * "Reconfigure Channel Request" in the L2CAP specification.
265: */
266: int
267: l2cap_ctloutput(int req, struct socket *so, int level,
268: int optname, struct mbuf **opt)
269: {
270: struct l2cap_channel *pcb = so->so_pcb;
271: struct mbuf *m;
272: int err = 0;
273:
274: #ifdef notyet /* XXX */
275: DPRINTFN(2, "%s\n", prcorequests[req]);
276: #endif
277:
278: if (pcb == NULL)
279: return EINVAL;
280:
281: if (level != BTPROTO_L2CAP)
282: return ENOPROTOOPT;
283:
284: switch(req) {
285: case PRCO_GETOPT:
286: m = m_get(M_WAIT, MT_SOOPTS);
287: m->m_len = l2cap_getopt(pcb, optname, mtod(m, void *));
288: if (m->m_len == 0) {
289: m_freem(m);
290: m = NULL;
291: err = ENOPROTOOPT;
292: }
293: *opt = m;
294: break;
295:
296: case PRCO_SETOPT:
297: m = *opt;
298: KASSERT(m != NULL);
299: err = l2cap_setopt(pcb, optname, mtod(m, void *));
300: m_freem(m);
301: break;
302:
303: default:
304: err = ENOPROTOOPT;
305: break;
306: }
307:
308: return err;
309: }
310:
311: /**********************************************************************
312: *
313: * L2CAP Protocol socket callbacks
314: *
315: */
316:
317: static void
318: l2cap_connecting(void *arg)
319: {
320: struct socket *so = arg;
321:
322: DPRINTF("Connecting\n");
323: soisconnecting(so);
324: }
325:
326: static void
327: l2cap_connected(void *arg)
328: {
329: struct socket *so = arg;
330:
331: DPRINTF("Connected\n");
332: soisconnected(so);
333: }
334:
335: static void
336: l2cap_disconnected(void *arg, int err)
337: {
338: struct socket *so = arg;
339:
340: DPRINTF("Disconnected (%d)\n", err);
341:
342: so->so_error = err;
343: soisdisconnected(so);
344: }
345:
346: static void *
347: l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
348: struct sockaddr_bt *raddr)
349: {
350: struct socket *so = arg;
351:
352: DPRINTF("New Connection\n");
353: so = sonewconn(so, 0);
354: if (so == NULL)
355: return NULL;
356:
357: soisconnecting(so);
358:
359: return so->so_pcb;
360: }
361:
362: static void
363: l2cap_complete(void *arg, int count)
364: {
365: struct socket *so = arg;
366:
367: while (count-- > 0)
368: sbdroprecord(&so->so_snd);
369:
370: sowwakeup(so);
371: }
372:
373: static void
374: l2cap_linkmode(void *arg, int new)
375: {
376: struct socket *so = arg;
377: int mode;
378:
379: DPRINTF("auth %s, encrypt %s, secure %s\n",
380: (new & L2CAP_LM_AUTH ? "on" : "off"),
381: (new & L2CAP_LM_ENCRYPT ? "on" : "off"),
382: (new & L2CAP_LM_SECURE ? "on" : "off"));
383:
384: (void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode);
385: if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
386: || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
387: || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
388: l2cap_disconnect(so->so_pcb, 0);
389: }
390:
391: static void
392: l2cap_input(void *arg, struct mbuf *m)
393: {
394: struct socket *so = arg;
395:
396: if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
397: printf("%s: packet (%d bytes) dropped (socket buffer full)\n",
398: __func__, m->m_pkthdr.len);
399: m_freem(m);
400: return;
401: }
402:
403: DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
404:
405: sbappendrecord(&so->so_rcv, m);
406: sorwakeup(so);
407: }
CVSweb