xref: /netbsd-src/sys/netbt/rfcomm_socket.c (revision b7ae68fde0d8ef1c03714e8bbb1ee7c6118ea93b)
1 /*	$NetBSD: rfcomm_socket.c,v 1.1 2006/06/19 15:44:45 gdamore Exp $	*/
2 
3 /*-
4  * Copyright (c) 2006 Itronix Inc.
5  * All rights reserved.
6  *
7  * Written by Iain Hibbert for Itronix Inc.
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 __KERNEL_RCSID(0, "$NetBSD: rfcomm_socket.c,v 1.1 2006/06/19 15:44:45 gdamore Exp $");
36 
37 #include <sys/param.h>
38 #include <sys/domain.h>
39 #include <sys/kernel.h>
40 #include <sys/mbuf.h>
41 #include <sys/proc.h>
42 #include <sys/protosw.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <sys/systm.h>
46 
47 #include <netbt/bluetooth.h>
48 #include <netbt/rfcomm.h>
49 
50 /****************************************************************************
51  *
52  *	RFCOMM SOCK_STREAM Sockets - serial line emulation
53  *
54  */
55 
56 static void rfcomm_connecting(void *);
57 static void rfcomm_connected(void *);
58 static void rfcomm_disconnected(void *, int);
59 static void *rfcomm_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
60 static void rfcomm_complete(void *, int);
61 static void rfcomm_input(void *, struct mbuf *);
62 
63 static const struct btproto rfcomm_proto = {
64 	rfcomm_connecting,
65 	rfcomm_connected,
66 	rfcomm_disconnected,
67 	rfcomm_newconn,
68 	rfcomm_complete,
69 	rfcomm_input,
70 };
71 
72 /* sysctl variables */
73 int rfcomm_sendspace = 4096;
74 int rfcomm_recvspace = 4096;
75 
76 /*
77  * User Request.
78  * up is socket
79  * m is either
80  *	optional mbuf chain containing message
81  *	ioctl command (PRU_CONTROL)
82  * nam is either
83  *	optional mbuf chain containing an address
84  *	ioctl data (PRU_CONTROL)
85  *	optionally protocol number (PRU_ATTACH)
86  *	message flags (PRU_RCVD)
87  * ctl is either
88  *	optional mbuf chain containing socket options
89  *	optional interface pointer (PRU_CONTROL, PRU_PURGEIF)
90  * l is pointer to process requesting action (if any)
91  *
92  * we are responsible for disposing of m and ctl if
93  * they are mbuf chains
94  */
95 int
96 rfcomm_usrreq(struct socket *up, int req, struct mbuf *m,
97 		struct mbuf *nam, struct mbuf *ctl, struct lwp *l)
98 {
99 	struct rfcomm_dlc *pcb = up->so_pcb;
100 	struct sockaddr_bt *sa;
101 	struct mbuf *m0;
102 	int err = 0;
103 
104 	DPRINTFN(2, "%s\n", prurequests[req]);
105 
106 	switch (req) {
107 	case PRU_CONTROL:
108 		return EPASSTHROUGH;
109 
110 	case PRU_PURGEIF:
111 		return EOPNOTSUPP;
112 
113 	case PRU_ATTACH:
114 		if (pcb != NULL)
115 			return EINVAL;
116 
117 		/*
118 		 * Since we have nothing to add, we attach the DLC
119 		 * structure directly to our PCB pointer.
120 		 */
121 		err = rfcomm_attach((struct rfcomm_dlc **)&up->so_pcb,
122 					&rfcomm_proto, up);
123 		if (err)
124 			return err;
125 
126 		err = soreserve(up, rfcomm_sendspace, rfcomm_recvspace);
127 		if (err)
128 			return err;
129 
130 		err = rfcomm_rcvd(up->so_pcb, sbspace(&up->so_rcv));
131 		if (err)
132 			return err;
133 
134 		return 0;
135 	}
136 
137 	if (pcb == NULL) {
138 		err = EINVAL;
139 		goto release;
140 	}
141 
142 	switch(req) {
143 	case PRU_DISCONNECT:
144 		soisdisconnecting(up);
145 		return rfcomm_disconnect(pcb, up->so_linger);
146 
147 	case PRU_ABORT:
148 		rfcomm_disconnect(pcb, 0);
149 		soisdisconnected(up);
150 		/* fall through to */
151 	case PRU_DETACH:
152 		return rfcomm_detach((struct rfcomm_dlc **)&up->so_pcb);
153 
154 	case PRU_BIND:
155 		KASSERT(nam);
156 		sa = mtod(nam, struct sockaddr_bt *);
157 
158 		if (sa->bt_len != sizeof(struct sockaddr_bt))
159 			return EINVAL;
160 
161 		if (sa->bt_family != AF_BLUETOOTH)
162 			return EAFNOSUPPORT;
163 
164 		return rfcomm_bind(pcb, sa);
165 
166 	case PRU_CONNECT:
167 		KASSERT(nam);
168 		sa = mtod(nam, struct sockaddr_bt *);
169 
170 		if (sa->bt_len != sizeof(struct sockaddr_bt))
171 			return EINVAL;
172 
173 		if (sa->bt_family != AF_BLUETOOTH)
174 			return EAFNOSUPPORT;
175 
176 		soisconnecting(up);
177 		return rfcomm_connect(pcb, sa);
178 
179 	case PRU_PEERADDR:
180 		KASSERT(nam);
181 		sa = mtod(nam, struct sockaddr_bt *);
182 		nam->m_len = sizeof(struct sockaddr_bt);
183 		return rfcomm_peeraddr(pcb, sa);
184 
185 	case PRU_SOCKADDR:
186 		KASSERT(nam);
187 		sa = mtod(nam, struct sockaddr_bt *);
188 		nam->m_len = sizeof(struct sockaddr_bt);
189 		return rfcomm_sockaddr(pcb, sa);
190 
191 	case PRU_SHUTDOWN:
192 		socantsendmore(up);
193 		break;
194 
195 	case PRU_SEND:
196 		KASSERT(m);
197 
198 		if (ctl)	/* no use for that */
199 			m_freem(ctl);
200 
201 		m0 = m_copypacket(m, M_DONTWAIT);
202 		if (m0 == NULL)
203 			return ENOMEM;
204 
205 		sbappendstream(&up->so_snd, m);
206 
207 		return rfcomm_send(pcb, m0);
208 
209 	case PRU_SENSE:
210 		return 0;		/* (no release) */
211 
212 	case PRU_RCVD:
213 		return rfcomm_rcvd(pcb, sbspace(&up->so_rcv));
214 
215 	case PRU_RCVOOB:
216 		return EOPNOTSUPP;	/* (no release) */
217 
218 	case PRU_LISTEN:
219 		return rfcomm_listen(pcb);
220 
221 	case PRU_ACCEPT:
222 		KASSERT(nam);
223 		sa = mtod(nam, struct sockaddr_bt *);
224 		nam->m_len = sizeof(struct sockaddr_bt);
225 		return rfcomm_peeraddr(pcb, sa);
226 
227 	case PRU_CONNECT2:
228 	case PRU_SENDOOB:
229 	case PRU_FASTTIMO:
230 	case PRU_SLOWTIMO:
231 	case PRU_PROTORCV:
232 	case PRU_PROTOSEND:
233 		err = EOPNOTSUPP;
234 		break;
235 
236 	default:
237 		UNKNOWN(req);
238 		err = EOPNOTSUPP;
239 		break;
240 	}
241 
242 release:
243 	if (m) m_freem(m);
244 	if (ctl) m_freem(ctl);
245 	return err;
246 }
247 
248 /*
249  * rfcomm_ctloutput(request, socket, level, optname, opt)
250  *
251  */
252 int
253 rfcomm_ctloutput(int req, struct socket *so, int level,
254 		int optname, struct mbuf **opt)
255 {
256 	struct rfcomm_dlc *pcb = so->so_pcb;
257 	struct mbuf *m;
258 	int err = 0;
259 
260 	DPRINTFN(2, "%s\n", prcorequests[req]);
261 
262 	if (level != BTPROTO_RFCOMM)
263 		return 0;	// err?
264 
265 	switch(req) {
266 	case PRCO_GETOPT:
267 		m = m_get(M_WAIT, MT_SOOPTS);
268 		m->m_len = rfcomm_getopt(pcb, optname, mtod(m, void *));
269 		if (m->m_len == 0) {
270 			m_freem(m);
271 			m = NULL;
272 			err = EINVAL;
273 		}
274 		*opt = m;
275 		break;
276 
277 	case PRCO_SETOPT:
278 		m = *opt;
279 		KASSERT(m != NULL);
280 		err = rfcomm_setopt(pcb, optname, mtod(m, void *));
281 		m_freem(m);
282 		break;
283 
284 	default:
285 		err = EINVAL;
286 		break;
287 	}
288 
289 	return err;
290 }
291 
292 /**********************************************************************
293  *
294  * RFCOMM callbacks
295  */
296 
297 static void
298 rfcomm_connecting(void *arg)
299 {
300 	/* struct socket *so = arg; */
301 
302 	KASSERT(arg);
303 	DPRINTF("Connecting\n");
304 }
305 
306 static void
307 rfcomm_connected(void *arg)
308 {
309 	struct socket *so = arg;
310 
311 	KASSERT(so);
312 	DPRINTF("Connected\n");
313 	soisconnected(so);
314 }
315 
316 static void
317 rfcomm_disconnected(void *arg, int err)
318 {
319 	struct socket *so = arg;
320 
321 	KASSERT(so);
322 	DPRINTF("Disconnected\n");
323 
324 	so->so_error = err;
325 	soisdisconnected(so);
326 }
327 
328 static void *
329 rfcomm_newconn(void *arg, struct sockaddr_bt *laddr, struct sockaddr_bt *raddr)
330 {
331 	struct socket *so = arg;
332 
333 	DPRINTF("New Connection\n");
334 	so = sonewconn(so, 0);
335 	if (so == NULL)
336 		return NULL;
337 
338 	soisconnecting(so);
339 
340 	return so->so_pcb;
341 }
342 
343 /*
344  * rfcomm_complete(rfcomm_dlc, length)
345  *
346  * length bytes are sent and may be removed from socket buffer
347  */
348 static void
349 rfcomm_complete(void *arg, int length)
350 {
351 	struct socket *so = arg;
352 
353 	sbdrop(&so->so_snd, length);
354 	sowwakeup(so);
355 }
356 
357 /*
358  * rfcomm_input(rfcomm_dlc, mbuf)
359  */
360 static void
361 rfcomm_input(void *arg, struct mbuf *m)
362 {
363 	struct socket *so = arg;
364 
365 	KASSERT(so);
366 
367 	if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
368 		printf("%s: %d bytes dropped (socket buffer full)\n",
369 			__func__, m->m_pkthdr.len);
370 		m_freem(m);
371 		return;
372 	}
373 
374 	DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
375 
376 	sbappendstream(&so->so_rcv, m);
377 	sorwakeup(so);
378 }
379