]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netgraph/bluetooth/socket/ng_btsocket_rfcomm.c
MFV r357608: Limit memory usage in xz(1) instead of in tuklib.
[FreeBSD/FreeBSD.git] / sys / netgraph / bluetooth / socket / ng_btsocket_rfcomm.c
1 /*
2  * ng_btsocket_rfcomm.c
3  */
4
5 /*-
6  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
7  *
8  * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Id: ng_btsocket_rfcomm.c,v 1.28 2003/09/14 23:29:06 max Exp $
33  * $FreeBSD$
34  */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/bitstring.h>
39 #include <sys/domain.h>
40 #include <sys/endian.h>
41 #include <sys/errno.h>
42 #include <sys/filedesc.h>
43 #include <sys/ioccom.h>
44 #include <sys/kernel.h>
45 #include <sys/lock.h>
46 #include <sys/malloc.h>
47 #include <sys/mbuf.h>
48 #include <sys/mutex.h>
49 #include <sys/proc.h>
50 #include <sys/protosw.h>
51 #include <sys/queue.h>
52 #include <sys/socket.h>
53 #include <sys/socketvar.h>
54 #include <sys/sysctl.h>
55 #include <sys/taskqueue.h>
56 #include <sys/uio.h>
57
58 #include <net/vnet.h>
59
60 #include <netgraph/ng_message.h>
61 #include <netgraph/netgraph.h>
62 #include <netgraph/bluetooth/include/ng_bluetooth.h>
63 #include <netgraph/bluetooth/include/ng_hci.h>
64 #include <netgraph/bluetooth/include/ng_l2cap.h>
65 #include <netgraph/bluetooth/include/ng_btsocket.h>
66 #include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>
67 #include <netgraph/bluetooth/include/ng_btsocket_rfcomm.h>
68
69 /* MALLOC define */
70 #ifdef NG_SEPARATE_MALLOC
71 static MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_RFCOMM, "netgraph_btsocks_rfcomm",
72                 "Netgraph Bluetooth RFCOMM sockets");
73 #else
74 #define M_NETGRAPH_BTSOCKET_RFCOMM M_NETGRAPH
75 #endif /* NG_SEPARATE_MALLOC */
76
77 /* Debug */
78 #define NG_BTSOCKET_RFCOMM_INFO \
79         if (ng_btsocket_rfcomm_debug_level >= NG_BTSOCKET_INFO_LEVEL && \
80             ppsratecheck(&ng_btsocket_rfcomm_lasttime, &ng_btsocket_rfcomm_curpps, 1)) \
81                 printf
82
83 #define NG_BTSOCKET_RFCOMM_WARN \
84         if (ng_btsocket_rfcomm_debug_level >= NG_BTSOCKET_WARN_LEVEL && \
85             ppsratecheck(&ng_btsocket_rfcomm_lasttime, &ng_btsocket_rfcomm_curpps, 1)) \
86                 printf
87
88 #define NG_BTSOCKET_RFCOMM_ERR \
89         if (ng_btsocket_rfcomm_debug_level >= NG_BTSOCKET_ERR_LEVEL && \
90             ppsratecheck(&ng_btsocket_rfcomm_lasttime, &ng_btsocket_rfcomm_curpps, 1)) \
91                 printf
92
93 #define NG_BTSOCKET_RFCOMM_ALERT \
94         if (ng_btsocket_rfcomm_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \
95             ppsratecheck(&ng_btsocket_rfcomm_lasttime, &ng_btsocket_rfcomm_curpps, 1)) \
96                 printf
97
98 #define ALOT    0x7fff
99
100 /* Local prototypes */
101 static int ng_btsocket_rfcomm_upcall
102         (struct socket *so, void *arg, int waitflag);
103 static void ng_btsocket_rfcomm_sessions_task
104         (void *ctx, int pending);
105 static void ng_btsocket_rfcomm_session_task
106         (ng_btsocket_rfcomm_session_p s);
107 #define ng_btsocket_rfcomm_task_wakeup() \
108         taskqueue_enqueue(taskqueue_swi_giant, &ng_btsocket_rfcomm_task)
109
110 static ng_btsocket_rfcomm_pcb_p ng_btsocket_rfcomm_connect_ind
111         (ng_btsocket_rfcomm_session_p s, int channel);
112 static void ng_btsocket_rfcomm_connect_cfm
113         (ng_btsocket_rfcomm_session_p s);
114
115 static int ng_btsocket_rfcomm_session_create
116         (ng_btsocket_rfcomm_session_p *sp, struct socket *l2so,
117          bdaddr_p src, bdaddr_p dst, struct thread *td);
118 static int ng_btsocket_rfcomm_session_accept
119         (ng_btsocket_rfcomm_session_p s0);
120 static int ng_btsocket_rfcomm_session_connect
121         (ng_btsocket_rfcomm_session_p s);
122 static int ng_btsocket_rfcomm_session_receive
123         (ng_btsocket_rfcomm_session_p s);
124 static int ng_btsocket_rfcomm_session_send
125         (ng_btsocket_rfcomm_session_p s);
126 static void ng_btsocket_rfcomm_session_clean
127         (ng_btsocket_rfcomm_session_p s);
128 static void ng_btsocket_rfcomm_session_process_pcb
129         (ng_btsocket_rfcomm_session_p s);
130 static ng_btsocket_rfcomm_session_p ng_btsocket_rfcomm_session_by_addr
131         (bdaddr_p src, bdaddr_p dst);
132
133 static int ng_btsocket_rfcomm_receive_frame
134         (ng_btsocket_rfcomm_session_p s, struct mbuf *m0);
135 static int ng_btsocket_rfcomm_receive_sabm
136         (ng_btsocket_rfcomm_session_p s, int dlci);
137 static int ng_btsocket_rfcomm_receive_disc
138         (ng_btsocket_rfcomm_session_p s, int dlci);
139 static int ng_btsocket_rfcomm_receive_ua
140         (ng_btsocket_rfcomm_session_p s, int dlci);
141 static int ng_btsocket_rfcomm_receive_dm
142         (ng_btsocket_rfcomm_session_p s, int dlci);
143 static int ng_btsocket_rfcomm_receive_uih
144         (ng_btsocket_rfcomm_session_p s, int dlci, int pf, struct mbuf *m0);
145 static int ng_btsocket_rfcomm_receive_mcc
146         (ng_btsocket_rfcomm_session_p s, struct mbuf *m0);
147 static int ng_btsocket_rfcomm_receive_test
148         (ng_btsocket_rfcomm_session_p s, struct mbuf *m0);
149 static int ng_btsocket_rfcomm_receive_fc
150         (ng_btsocket_rfcomm_session_p s, struct mbuf *m0);
151 static int ng_btsocket_rfcomm_receive_msc
152         (ng_btsocket_rfcomm_session_p s, struct mbuf *m0);
153 static int ng_btsocket_rfcomm_receive_rpn
154         (ng_btsocket_rfcomm_session_p s, struct mbuf *m0);
155 static int ng_btsocket_rfcomm_receive_rls
156         (ng_btsocket_rfcomm_session_p s, struct mbuf *m0);
157 static int ng_btsocket_rfcomm_receive_pn
158         (ng_btsocket_rfcomm_session_p s, struct mbuf *m0);
159 static void ng_btsocket_rfcomm_set_pn
160         (ng_btsocket_rfcomm_pcb_p pcb, u_int8_t cr, u_int8_t flow_control, 
161          u_int8_t credits, u_int16_t mtu);
162
163 static int ng_btsocket_rfcomm_send_command
164         (ng_btsocket_rfcomm_session_p s, u_int8_t type, u_int8_t dlci);
165 static int ng_btsocket_rfcomm_send_uih
166         (ng_btsocket_rfcomm_session_p s, u_int8_t address, u_int8_t pf, 
167          u_int8_t credits, struct mbuf *data);
168 static int ng_btsocket_rfcomm_send_msc
169         (ng_btsocket_rfcomm_pcb_p pcb);
170 static int ng_btsocket_rfcomm_send_pn
171         (ng_btsocket_rfcomm_pcb_p pcb);
172 static int ng_btsocket_rfcomm_send_credits
173         (ng_btsocket_rfcomm_pcb_p pcb);
174
175 static int ng_btsocket_rfcomm_pcb_send
176         (ng_btsocket_rfcomm_pcb_p pcb, int limit);
177 static void ng_btsocket_rfcomm_pcb_kill
178         (ng_btsocket_rfcomm_pcb_p pcb, int error);
179 static ng_btsocket_rfcomm_pcb_p ng_btsocket_rfcomm_pcb_by_dlci
180         (ng_btsocket_rfcomm_session_p s, int dlci);
181 static ng_btsocket_rfcomm_pcb_p ng_btsocket_rfcomm_pcb_listener
182         (bdaddr_p src, int channel);
183
184 static void ng_btsocket_rfcomm_timeout
185         (ng_btsocket_rfcomm_pcb_p pcb);
186 static void ng_btsocket_rfcomm_untimeout
187         (ng_btsocket_rfcomm_pcb_p pcb);
188 static void ng_btsocket_rfcomm_process_timeout
189         (void *xpcb);
190
191 static struct mbuf * ng_btsocket_rfcomm_prepare_packet
192         (struct sockbuf *sb, int length);
193
194 /* Globals */
195 extern int                                      ifqmaxlen;
196 static u_int32_t                                ng_btsocket_rfcomm_debug_level;
197 static u_int32_t                                ng_btsocket_rfcomm_timo;
198 struct task                                     ng_btsocket_rfcomm_task;
199 static LIST_HEAD(, ng_btsocket_rfcomm_session)  ng_btsocket_rfcomm_sessions;
200 static struct mtx                               ng_btsocket_rfcomm_sessions_mtx;
201 static LIST_HEAD(, ng_btsocket_rfcomm_pcb)      ng_btsocket_rfcomm_sockets;
202 static struct mtx                               ng_btsocket_rfcomm_sockets_mtx;
203 static struct timeval                           ng_btsocket_rfcomm_lasttime;
204 static int                                      ng_btsocket_rfcomm_curpps;
205
206 /* Sysctl tree */
207 SYSCTL_DECL(_net_bluetooth_rfcomm_sockets);
208 static SYSCTL_NODE(_net_bluetooth_rfcomm_sockets, OID_AUTO, stream, CTLFLAG_RW,
209         0, "Bluetooth STREAM RFCOMM sockets family");
210 SYSCTL_UINT(_net_bluetooth_rfcomm_sockets_stream, OID_AUTO, debug_level,
211         CTLFLAG_RW,
212         &ng_btsocket_rfcomm_debug_level, NG_BTSOCKET_INFO_LEVEL,
213         "Bluetooth STREAM RFCOMM sockets debug level");
214 SYSCTL_UINT(_net_bluetooth_rfcomm_sockets_stream, OID_AUTO, timeout,
215         CTLFLAG_RW,
216         &ng_btsocket_rfcomm_timo, 60,
217         "Bluetooth STREAM RFCOMM sockets timeout");
218
219 /*****************************************************************************
220  *****************************************************************************
221  **                              RFCOMM CRC
222  *****************************************************************************
223  *****************************************************************************/
224
225 static u_int8_t ng_btsocket_rfcomm_crc_table[256] = {
226         0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,
227         0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
228         0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,
229         0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
230
231         0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,
232         0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
233         0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,
234         0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
235
236         0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,
237         0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
238         0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,
239         0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
240
241         0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,
242         0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
243         0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,
244         0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
245
246         0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,
247         0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
248         0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,
249         0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
250
251         0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,
252         0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
253         0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,
254         0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
255
256         0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,
257         0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
258         0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,
259         0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
260
261         0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,
262         0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
263         0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,
264         0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf
265 };
266
267 /* CRC */
268 static u_int8_t
269 ng_btsocket_rfcomm_crc(u_int8_t *data, int length)
270 {
271         u_int8_t        crc = 0xff;
272
273         while (length --)
274                 crc = ng_btsocket_rfcomm_crc_table[crc ^ *data++];
275
276         return (crc);
277 } /* ng_btsocket_rfcomm_crc */
278
279 /* FCS on 2 bytes */
280 static u_int8_t
281 ng_btsocket_rfcomm_fcs2(u_int8_t *data)
282 {
283         return (0xff - ng_btsocket_rfcomm_crc(data, 2));
284 } /* ng_btsocket_rfcomm_fcs2 */
285   
286 /* FCS on 3 bytes */
287 static u_int8_t
288 ng_btsocket_rfcomm_fcs3(u_int8_t *data)
289 {
290         return (0xff - ng_btsocket_rfcomm_crc(data, 3));
291 } /* ng_btsocket_rfcomm_fcs3 */
292
293 /* 
294  * Check FCS
295  *
296  * From Bluetooth spec
297  *
298  * "... In 07.10, the frame check sequence (FCS) is calculated on different 
299  * sets of fields for different frame types. These are the fields that the 
300  * FCS are calculated on:
301  *
302  * For SABM, DISC, UA, DM frames: on Address, Control and length field.
303  * For UIH frames: on Address and Control field.
304  *
305  * (This is stated here for clarification, and to set the standard for RFCOMM;
306  * the fields included in FCS calculation have actually changed in version
307  * 7.0.0 of TS 07.10, but RFCOMM will not change the FCS calculation scheme
308  * from the one above.) ..."
309  */
310
311 static int
312 ng_btsocket_rfcomm_check_fcs(u_int8_t *data, int type, u_int8_t fcs)
313 {
314         if (type != RFCOMM_FRAME_UIH)
315                 return (ng_btsocket_rfcomm_fcs3(data) != fcs);
316
317         return (ng_btsocket_rfcomm_fcs2(data) != fcs);
318 } /* ng_btsocket_rfcomm_check_fcs */
319
320 /*****************************************************************************
321  *****************************************************************************
322  **                              Socket interface
323  *****************************************************************************
324  *****************************************************************************/
325
326 /* 
327  * Initialize everything
328  */
329
330 void
331 ng_btsocket_rfcomm_init(void)
332 {
333
334         /* Skip initialization of globals for non-default instances. */
335         if (!IS_DEFAULT_VNET(curvnet))
336                 return;
337
338         ng_btsocket_rfcomm_debug_level = NG_BTSOCKET_WARN_LEVEL;
339         ng_btsocket_rfcomm_timo = 60;
340
341         /* RFCOMM task */
342         TASK_INIT(&ng_btsocket_rfcomm_task, 0,
343                 ng_btsocket_rfcomm_sessions_task, NULL);
344
345         /* RFCOMM sessions list */
346         LIST_INIT(&ng_btsocket_rfcomm_sessions);
347         mtx_init(&ng_btsocket_rfcomm_sessions_mtx,
348                 "btsocks_rfcomm_sessions_mtx", NULL, MTX_DEF);
349
350         /* RFCOMM sockets list */
351         LIST_INIT(&ng_btsocket_rfcomm_sockets);
352         mtx_init(&ng_btsocket_rfcomm_sockets_mtx,
353                 "btsocks_rfcomm_sockets_mtx", NULL, MTX_DEF);
354 } /* ng_btsocket_rfcomm_init */
355
356 /*
357  * Abort connection on socket
358  */
359
360 void
361 ng_btsocket_rfcomm_abort(struct socket *so)
362 {
363
364         so->so_error = ECONNABORTED;
365         (void)ng_btsocket_rfcomm_disconnect(so);
366 } /* ng_btsocket_rfcomm_abort */
367
368 void
369 ng_btsocket_rfcomm_close(struct socket *so)
370 {
371
372         (void)ng_btsocket_rfcomm_disconnect(so);
373 } /* ng_btsocket_rfcomm_close */
374
375 /*
376  * Accept connection on socket. Nothing to do here, socket must be connected
377  * and ready, so just return peer address and be done with it.
378  */
379
380 int
381 ng_btsocket_rfcomm_accept(struct socket *so, struct sockaddr **nam)
382 {
383         return (ng_btsocket_rfcomm_peeraddr(so, nam));
384 } /* ng_btsocket_rfcomm_accept */
385
386 /*
387  * Create and attach new socket
388  */
389
390 int
391 ng_btsocket_rfcomm_attach(struct socket *so, int proto, struct thread *td)
392 {
393         ng_btsocket_rfcomm_pcb_p        pcb = so2rfcomm_pcb(so);
394         int                             error;
395
396         /* Check socket and protocol */
397         if (so->so_type != SOCK_STREAM)
398                 return (ESOCKTNOSUPPORT);
399
400 #if 0 /* XXX sonewconn() calls "pru_attach" with proto == 0 */
401         if (proto != 0) 
402                 if (proto != BLUETOOTH_PROTO_RFCOMM)
403                         return (EPROTONOSUPPORT);
404 #endif /* XXX */
405
406         if (pcb != NULL)
407                 return (EISCONN);
408
409         /* Reserve send and receive space if it is not reserved yet */
410         if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) {
411                 error = soreserve(so, NG_BTSOCKET_RFCOMM_SENDSPACE,
412                                         NG_BTSOCKET_RFCOMM_RECVSPACE);
413                 if (error != 0)
414                         return (error);
415         }
416
417         /* Allocate the PCB */
418         pcb = malloc(sizeof(*pcb),
419                 M_NETGRAPH_BTSOCKET_RFCOMM, M_NOWAIT | M_ZERO);
420         if (pcb == NULL)
421                 return (ENOMEM);
422
423         /* Link the PCB and the socket */
424         so->so_pcb = (caddr_t) pcb;
425         pcb->so = so;
426
427         /* Initialize PCB */
428         pcb->state = NG_BTSOCKET_RFCOMM_DLC_CLOSED;
429         pcb->flags = NG_BTSOCKET_RFCOMM_DLC_CFC;
430
431         pcb->lmodem =
432         pcb->rmodem = (RFCOMM_MODEM_RTC | RFCOMM_MODEM_RTR | RFCOMM_MODEM_DV);
433
434         pcb->mtu = RFCOMM_DEFAULT_MTU;
435         pcb->tx_cred = 0;
436         pcb->rx_cred = RFCOMM_DEFAULT_CREDITS;
437
438         mtx_init(&pcb->pcb_mtx, "btsocks_rfcomm_pcb_mtx", NULL, MTX_DEF);
439         callout_init_mtx(&pcb->timo, &pcb->pcb_mtx, 0);
440
441         /* Add the PCB to the list */
442         mtx_lock(&ng_btsocket_rfcomm_sockets_mtx);
443         LIST_INSERT_HEAD(&ng_btsocket_rfcomm_sockets, pcb, next);
444         mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);
445
446         return (0);
447 } /* ng_btsocket_rfcomm_attach */
448
449 /*
450  * Bind socket
451  */
452
453 int
454 ng_btsocket_rfcomm_bind(struct socket *so, struct sockaddr *nam, 
455                 struct thread *td)
456 {
457         ng_btsocket_rfcomm_pcb_t        *pcb = so2rfcomm_pcb(so), *pcb1;
458         struct sockaddr_rfcomm          *sa = (struct sockaddr_rfcomm *) nam;
459
460         if (pcb == NULL)
461                 return (EINVAL);
462
463         /* Verify address */
464         if (sa == NULL)
465                 return (EINVAL);
466         if (sa->rfcomm_family != AF_BLUETOOTH)
467                 return (EAFNOSUPPORT);
468         if (sa->rfcomm_len != sizeof(*sa))
469                 return (EINVAL);
470         if (sa->rfcomm_channel > 30)
471                 return (EINVAL);
472
473         mtx_lock(&pcb->pcb_mtx);
474
475         if (sa->rfcomm_channel != 0) {
476                 mtx_lock(&ng_btsocket_rfcomm_sockets_mtx);
477
478                 LIST_FOREACH(pcb1, &ng_btsocket_rfcomm_sockets, next) {
479                         if (pcb1->channel == sa->rfcomm_channel &&
480                             bcmp(&pcb1->src, &sa->rfcomm_bdaddr,
481                                         sizeof(pcb1->src)) == 0) {
482                                 mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);
483                                 mtx_unlock(&pcb->pcb_mtx);
484
485                                 return (EADDRINUSE);
486                         }
487                 }
488
489                 mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);
490         }
491
492         bcopy(&sa->rfcomm_bdaddr, &pcb->src, sizeof(pcb->src));
493         pcb->channel = sa->rfcomm_channel;
494
495         mtx_unlock(&pcb->pcb_mtx);
496
497         return (0);
498 } /* ng_btsocket_rfcomm_bind */
499
500 /*
501  * Connect socket
502  */
503
504 int
505 ng_btsocket_rfcomm_connect(struct socket *so, struct sockaddr *nam, 
506                 struct thread *td)
507 {
508         ng_btsocket_rfcomm_pcb_t        *pcb = so2rfcomm_pcb(so);
509         struct sockaddr_rfcomm          *sa = (struct sockaddr_rfcomm *) nam;
510         ng_btsocket_rfcomm_session_t    *s = NULL;
511         struct socket                   *l2so = NULL;
512         int                              dlci, error = 0;
513
514         if (pcb == NULL)
515                 return (EINVAL);
516
517         /* Verify address */
518         if (sa == NULL)
519                 return (EINVAL);
520         if (sa->rfcomm_family != AF_BLUETOOTH)
521                 return (EAFNOSUPPORT);
522         if (sa->rfcomm_len != sizeof(*sa))
523                 return (EINVAL);
524         if (sa->rfcomm_channel > 30)
525                 return (EINVAL);
526         if (sa->rfcomm_channel == 0 ||
527             bcmp(&sa->rfcomm_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
528                 return (EDESTADDRREQ);
529
530         /*
531          * Note that we will not check for errors in socreate() because
532          * if we failed to create L2CAP socket at this point we still
533          * might have already open session.
534          */
535
536         error = socreate(PF_BLUETOOTH, &l2so, SOCK_SEQPACKET,
537                         BLUETOOTH_PROTO_L2CAP, td->td_ucred, td);
538
539         /* 
540          * Look for session between "pcb->src" and "sa->rfcomm_bdaddr" (dst)
541          */
542
543         mtx_lock(&ng_btsocket_rfcomm_sessions_mtx);
544
545         s = ng_btsocket_rfcomm_session_by_addr(&pcb->src, &sa->rfcomm_bdaddr);
546         if (s == NULL) {
547                 /*
548                  * We need to create new RFCOMM session. Check if we have L2CAP
549                  * socket. If l2so == NULL then error has the error code from
550                  * socreate()
551                  */
552
553                 if (l2so == NULL) {
554                         mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx);
555                         return (error);
556                 }
557
558                 error = ng_btsocket_rfcomm_session_create(&s, l2so,
559                                 &pcb->src, &sa->rfcomm_bdaddr, td);
560                 if (error != 0) {
561                         mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx);
562                         soclose(l2so);
563
564                         return (error);
565                 }
566         } else if (l2so != NULL)
567                 soclose(l2so); /* we don't need new L2CAP socket */
568
569         /*
570          * Check if we already have the same DLCI the same session
571          */
572
573         mtx_lock(&s->session_mtx);
574         mtx_lock(&pcb->pcb_mtx);
575
576         dlci = RFCOMM_MKDLCI(!INITIATOR(s), sa->rfcomm_channel);
577
578         if (ng_btsocket_rfcomm_pcb_by_dlci(s, dlci) != NULL) {
579                 mtx_unlock(&pcb->pcb_mtx);
580                 mtx_unlock(&s->session_mtx);
581                 mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx);
582
583                 return (EBUSY);
584         }
585
586         /*
587          * Check session state and if its not acceptable then refuse connection
588          */
589
590         switch (s->state) {
591         case NG_BTSOCKET_RFCOMM_SESSION_CONNECTING:
592         case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED:
593         case NG_BTSOCKET_RFCOMM_SESSION_OPEN:
594                 /*
595                  * Update destination address and channel and attach 
596                  * DLC to the session
597                  */
598
599                 bcopy(&sa->rfcomm_bdaddr, &pcb->dst, sizeof(pcb->dst));
600                 pcb->channel = sa->rfcomm_channel;
601                 pcb->dlci = dlci;
602
603                 LIST_INSERT_HEAD(&s->dlcs, pcb, session_next);
604                 pcb->session = s;
605
606                 ng_btsocket_rfcomm_timeout(pcb);
607                 soisconnecting(pcb->so);
608
609                 if (s->state == NG_BTSOCKET_RFCOMM_SESSION_OPEN) {
610                         pcb->mtu = s->mtu;
611                         bcopy(&so2l2cap_pcb(s->l2so)->src, &pcb->src,
612                                 sizeof(pcb->src));
613
614                         pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONFIGURING;
615
616                         error = ng_btsocket_rfcomm_send_pn(pcb);
617                         if (error == 0)
618                                 error = ng_btsocket_rfcomm_task_wakeup();
619                 } else
620                         pcb->state = NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT;
621                 break;
622
623         default:
624                 error = ECONNRESET;
625                 break;
626         }
627
628         mtx_unlock(&pcb->pcb_mtx);
629         mtx_unlock(&s->session_mtx);
630         mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx);
631
632         return (error);
633 } /* ng_btsocket_rfcomm_connect */
634
635 /*
636  * Process ioctl's calls on socket.
637  * XXX FIXME this should provide interface to the RFCOMM multiplexor channel
638  */
639
640 int
641 ng_btsocket_rfcomm_control(struct socket *so, u_long cmd, caddr_t data,
642                 struct ifnet *ifp, struct thread *td)
643 {
644         return (EINVAL);
645 } /* ng_btsocket_rfcomm_control */
646
647 /*
648  * Process getsockopt/setsockopt system calls
649  */
650
651 int
652 ng_btsocket_rfcomm_ctloutput(struct socket *so, struct sockopt *sopt)
653 {
654         ng_btsocket_rfcomm_pcb_p                pcb = so2rfcomm_pcb(so);
655         struct ng_btsocket_rfcomm_fc_info       fcinfo;
656         int                                     error = 0;
657
658         if (pcb == NULL)
659                 return (EINVAL);
660         if (sopt->sopt_level != SOL_RFCOMM)
661                 return (0);
662
663         mtx_lock(&pcb->pcb_mtx);
664
665         switch (sopt->sopt_dir) {
666         case SOPT_GET:
667                 switch (sopt->sopt_name) {
668                 case SO_RFCOMM_MTU:
669                         error = sooptcopyout(sopt, &pcb->mtu, sizeof(pcb->mtu));
670                         break;
671
672                 case SO_RFCOMM_FC_INFO:
673                         fcinfo.lmodem = pcb->lmodem;
674                         fcinfo.rmodem = pcb->rmodem;
675                         fcinfo.tx_cred = pcb->tx_cred;
676                         fcinfo.rx_cred = pcb->rx_cred;
677                         fcinfo.cfc = (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC)?
678                                 1 : 0;
679                         fcinfo.reserved = 0;
680
681                         error = sooptcopyout(sopt, &fcinfo, sizeof(fcinfo));
682                         break;
683
684                 default:
685                         error = ENOPROTOOPT;
686                         break;
687                 }
688                 break;
689
690         case SOPT_SET:
691                 switch (sopt->sopt_name) {
692                 default:
693                         error = ENOPROTOOPT;
694                         break;
695                 }
696                 break;
697
698         default:
699                 error = EINVAL;
700                 break;
701         }
702
703         mtx_unlock(&pcb->pcb_mtx);
704
705         return (error);
706 } /* ng_btsocket_rfcomm_ctloutput */
707
708 /*
709  * Detach and destroy socket
710  */
711
712 void
713 ng_btsocket_rfcomm_detach(struct socket *so)
714 {
715         ng_btsocket_rfcomm_pcb_p        pcb = so2rfcomm_pcb(so);
716
717         KASSERT(pcb != NULL, ("ng_btsocket_rfcomm_detach: pcb == NULL"));
718
719         mtx_lock(&pcb->pcb_mtx);
720
721         switch (pcb->state) {
722         case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT:
723         case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING:
724         case NG_BTSOCKET_RFCOMM_DLC_CONNECTING:
725         case NG_BTSOCKET_RFCOMM_DLC_CONNECTED:
726                 /* XXX What to do with pending request? */
727                 if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)
728                         ng_btsocket_rfcomm_untimeout(pcb);
729
730                 if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT)
731                         pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_DETACHED;
732                 else
733                         pcb->state = NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING;
734
735                 ng_btsocket_rfcomm_task_wakeup();
736                 break;
737
738         case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING:
739                 ng_btsocket_rfcomm_task_wakeup();
740                 break;
741         }
742         
743         while (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CLOSED)
744                 msleep(&pcb->state, &pcb->pcb_mtx, PZERO, "rf_det", 0);
745
746         if (pcb->session != NULL)
747                 panic("%s: pcb->session != NULL\n", __func__);
748         if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)
749                 panic("%s: timeout on closed DLC, flags=%#x\n",
750                         __func__, pcb->flags);
751
752         mtx_lock(&ng_btsocket_rfcomm_sockets_mtx);
753         LIST_REMOVE(pcb, next);
754         mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);
755
756         mtx_unlock(&pcb->pcb_mtx);
757
758         mtx_destroy(&pcb->pcb_mtx);
759         bzero(pcb, sizeof(*pcb));
760         free(pcb, M_NETGRAPH_BTSOCKET_RFCOMM);
761
762         soisdisconnected(so);
763         so->so_pcb = NULL;
764 } /* ng_btsocket_rfcomm_detach */
765
766 /*
767  * Disconnect socket
768  */
769
770 int
771 ng_btsocket_rfcomm_disconnect(struct socket *so)
772 {
773         ng_btsocket_rfcomm_pcb_p        pcb = so2rfcomm_pcb(so);
774
775         if (pcb == NULL)
776                 return (EINVAL);
777
778         mtx_lock(&pcb->pcb_mtx);
779
780         if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING) {
781                 mtx_unlock(&pcb->pcb_mtx);
782                 return (EINPROGRESS);
783         }
784
785         /* XXX What to do with pending request? */
786         if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)
787                 ng_btsocket_rfcomm_untimeout(pcb);
788
789         switch (pcb->state) {
790         case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING: /* XXX can we get here? */
791         case NG_BTSOCKET_RFCOMM_DLC_CONNECTING: /* XXX can we get here? */
792         case NG_BTSOCKET_RFCOMM_DLC_CONNECTED:
793
794                 /*
795                  * Just change DLC state and enqueue RFCOMM task. It will
796                  * queue and send DISC on the DLC.
797                  */ 
798
799                 pcb->state = NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING;
800                 soisdisconnecting(so);
801
802                 ng_btsocket_rfcomm_task_wakeup();
803                 break;
804
805         case NG_BTSOCKET_RFCOMM_DLC_CLOSED:
806         case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT:
807                 break;
808
809         default:
810                 panic("%s: Invalid DLC state=%d, flags=%#x\n",
811                         __func__, pcb->state, pcb->flags);
812                 break;
813         }
814
815         mtx_unlock(&pcb->pcb_mtx);
816
817         return (0);
818 } /* ng_btsocket_rfcomm_disconnect */
819
820 /*
821  * Listen on socket. First call to listen() will create listening RFCOMM session
822  */
823
824 int
825 ng_btsocket_rfcomm_listen(struct socket *so, int backlog, struct thread *td)
826 {
827         ng_btsocket_rfcomm_pcb_p         pcb = so2rfcomm_pcb(so), pcb1;
828         ng_btsocket_rfcomm_session_p     s = NULL;
829         struct socket                   *l2so = NULL;
830         int                              error, socreate_error, usedchannels;
831
832         if (pcb == NULL)
833                 return (EINVAL);
834         if (pcb->channel > 30)
835                 return (EADDRNOTAVAIL);
836
837         usedchannels = 0;
838
839         mtx_lock(&pcb->pcb_mtx);
840
841         if (pcb->channel == 0) {
842                 mtx_lock(&ng_btsocket_rfcomm_sockets_mtx);
843
844                 LIST_FOREACH(pcb1, &ng_btsocket_rfcomm_sockets, next)
845                         if (pcb1->channel != 0 &&
846                             bcmp(&pcb1->src, &pcb->src, sizeof(pcb->src)) == 0)
847                                 usedchannels |= (1 << (pcb1->channel - 1));
848
849                 for (pcb->channel = 30; pcb->channel > 0; pcb->channel --)
850                         if (!(usedchannels & (1 << (pcb->channel - 1))))
851                                 break;
852
853                 if (pcb->channel == 0) {
854                         mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);
855                         mtx_unlock(&pcb->pcb_mtx);
856
857                         return (EADDRNOTAVAIL);
858                 }
859
860                 mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);
861         }
862
863         mtx_unlock(&pcb->pcb_mtx);
864
865         /*
866          * Note that we will not check for errors in socreate() because
867          * if we failed to create L2CAP socket at this point we still
868          * might have already open session.
869          */
870
871         socreate_error = socreate(PF_BLUETOOTH, &l2so, SOCK_SEQPACKET,
872                         BLUETOOTH_PROTO_L2CAP, td->td_ucred, td);
873
874         /*
875          * Transition the socket and session into the LISTENING state.  Check
876          * for collisions first, as there can only be one.
877          */
878         mtx_lock(&ng_btsocket_rfcomm_sessions_mtx);
879         SOCK_LOCK(so);
880         error = solisten_proto_check(so);
881         SOCK_UNLOCK(so);
882         if (error != 0)
883                 goto out;
884
885         LIST_FOREACH(s, &ng_btsocket_rfcomm_sessions, next)
886                 if (s->state == NG_BTSOCKET_RFCOMM_SESSION_LISTENING)
887                         break;
888
889         if (s == NULL) {
890                 /*
891                  * We need to create default RFCOMM session. Check if we have 
892                  * L2CAP socket. If l2so == NULL then error has the error code 
893                  * from socreate()
894                  */
895                 if (l2so == NULL) {
896                         error = socreate_error;
897                         goto out;
898                 }
899
900                 /* 
901                  * Create default listen RFCOMM session. The default RFCOMM 
902                  * session will listen on ANY address.
903                  *
904                  * XXX FIXME Note that currently there is no way to adjust MTU
905                  * for the default session.
906                  */
907                 error = ng_btsocket_rfcomm_session_create(&s, l2so,
908                                         NG_HCI_BDADDR_ANY, NULL, td);
909                 if (error != 0)
910                         goto out;
911                 l2so = NULL;
912         }
913         SOCK_LOCK(so);
914         solisten_proto(so, backlog);
915         SOCK_UNLOCK(so);
916 out:
917         mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx);
918         /*
919          * If we still have an l2so reference here, it's unneeded, so release
920          * it.
921          */
922         if (l2so != NULL)
923                 soclose(l2so);
924         return (error);
925 } /* ng_btsocket_listen */
926
927 /*
928  * Get peer address
929  */
930
931 int
932 ng_btsocket_rfcomm_peeraddr(struct socket *so, struct sockaddr **nam)
933 {
934         ng_btsocket_rfcomm_pcb_p        pcb = so2rfcomm_pcb(so);
935         struct sockaddr_rfcomm          sa;
936
937         if (pcb == NULL)
938                 return (EINVAL);
939
940         bcopy(&pcb->dst, &sa.rfcomm_bdaddr, sizeof(sa.rfcomm_bdaddr));
941         sa.rfcomm_channel = pcb->channel;
942         sa.rfcomm_len = sizeof(sa);
943         sa.rfcomm_family = AF_BLUETOOTH;
944
945         *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
946
947         return ((*nam == NULL)? ENOMEM : 0);
948 } /* ng_btsocket_rfcomm_peeraddr */
949
950 /*
951  * Send data to socket
952  */
953
954 int
955 ng_btsocket_rfcomm_send(struct socket *so, int flags, struct mbuf *m,
956                 struct sockaddr *nam, struct mbuf *control, struct thread *td)
957 {
958         ng_btsocket_rfcomm_pcb_t        *pcb = so2rfcomm_pcb(so);
959         int                              error = 0;
960
961         /* Check socket and input */
962         if (pcb == NULL || m == NULL || control != NULL) {
963                 error = EINVAL;
964                 goto drop;
965         }
966
967         mtx_lock(&pcb->pcb_mtx);
968
969         /* Make sure DLC is connected */
970         if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTED) {
971                 mtx_unlock(&pcb->pcb_mtx);
972                 error = ENOTCONN;
973                 goto drop;
974         }
975
976         /* Put the packet on the socket's send queue and wakeup RFCOMM task */
977         sbappend(&pcb->so->so_snd, m, flags);
978         m = NULL;
979         
980         if (!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_SENDING)) {
981                 pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_SENDING;
982                 error = ng_btsocket_rfcomm_task_wakeup();
983         }
984
985         mtx_unlock(&pcb->pcb_mtx);
986 drop:
987         NG_FREE_M(m); /* checks for != NULL */
988         NG_FREE_M(control);
989
990         return (error);
991 } /* ng_btsocket_rfcomm_send */
992
993 /*
994  * Get socket address
995  */
996
997 int
998 ng_btsocket_rfcomm_sockaddr(struct socket *so, struct sockaddr **nam)
999 {
1000         ng_btsocket_rfcomm_pcb_p        pcb = so2rfcomm_pcb(so);
1001         struct sockaddr_rfcomm          sa;
1002
1003         if (pcb == NULL)
1004                 return (EINVAL);
1005
1006         bcopy(&pcb->src, &sa.rfcomm_bdaddr, sizeof(sa.rfcomm_bdaddr));
1007         sa.rfcomm_channel = pcb->channel;
1008         sa.rfcomm_len = sizeof(sa);
1009         sa.rfcomm_family = AF_BLUETOOTH;
1010
1011         *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1012
1013         return ((*nam == NULL)? ENOMEM : 0);
1014 } /* ng_btsocket_rfcomm_sockaddr */
1015
1016 /*
1017  * Upcall function for L2CAP sockets. Enqueue RFCOMM task.
1018  */
1019
1020 static int
1021 ng_btsocket_rfcomm_upcall(struct socket *so, void *arg, int waitflag)
1022 {
1023         int     error;
1024
1025         if (so == NULL)
1026                 panic("%s: so == NULL\n", __func__);
1027
1028         if ((error = ng_btsocket_rfcomm_task_wakeup()) != 0)
1029                 NG_BTSOCKET_RFCOMM_ALERT(
1030 "%s: Could not enqueue RFCOMM task, error=%d\n", __func__, error);
1031         return (SU_OK);
1032 } /* ng_btsocket_rfcomm_upcall */
1033
1034 /*
1035  * RFCOMM task. Will handle all RFCOMM sessions in one pass.
1036  * XXX FIXME does not scale very well
1037  */
1038
1039 static void
1040 ng_btsocket_rfcomm_sessions_task(void *ctx, int pending)
1041 {
1042         ng_btsocket_rfcomm_session_p    s = NULL, s_next = NULL;
1043
1044         mtx_lock(&ng_btsocket_rfcomm_sessions_mtx);
1045
1046         for (s = LIST_FIRST(&ng_btsocket_rfcomm_sessions); s != NULL; ) {
1047                 mtx_lock(&s->session_mtx);
1048                 s_next = LIST_NEXT(s, next);
1049
1050                 ng_btsocket_rfcomm_session_task(s);
1051
1052                 if (s->state == NG_BTSOCKET_RFCOMM_SESSION_CLOSED) {
1053                         /* Unlink and clean the session */
1054                         LIST_REMOVE(s, next);
1055
1056                         NG_BT_MBUFQ_DRAIN(&s->outq);
1057                         if (!LIST_EMPTY(&s->dlcs))
1058                                 panic("%s: DLC list is not empty\n", __func__);
1059
1060                         /* Close L2CAP socket */
1061                         SOCKBUF_LOCK(&s->l2so->so_rcv);
1062                         soupcall_clear(s->l2so, SO_RCV);
1063                         SOCKBUF_UNLOCK(&s->l2so->so_rcv);
1064                         SOCKBUF_LOCK(&s->l2so->so_snd);
1065                         soupcall_clear(s->l2so, SO_SND);
1066                         SOCKBUF_UNLOCK(&s->l2so->so_snd);
1067                         soclose(s->l2so);
1068
1069                         mtx_unlock(&s->session_mtx);
1070
1071                         mtx_destroy(&s->session_mtx);
1072                         bzero(s, sizeof(*s));
1073                         free(s, M_NETGRAPH_BTSOCKET_RFCOMM);
1074                 } else
1075                         mtx_unlock(&s->session_mtx);
1076
1077                 s = s_next;
1078         }
1079
1080         mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx);
1081 } /* ng_btsocket_rfcomm_sessions_task */
1082
1083 /*
1084  * Process RFCOMM session. Will handle all RFCOMM sockets in one pass.
1085  */
1086
1087 static void
1088 ng_btsocket_rfcomm_session_task(ng_btsocket_rfcomm_session_p s)
1089 {
1090         mtx_assert(&s->session_mtx, MA_OWNED);
1091
1092         if (s->l2so->so_rcv.sb_state & SBS_CANTRCVMORE) {
1093                 NG_BTSOCKET_RFCOMM_INFO(
1094 "%s: L2CAP connection has been terminated, so=%p, so_state=%#x, so_count=%d, " \
1095 "state=%d, flags=%#x\n", __func__, s->l2so, s->l2so->so_state, 
1096                         s->l2so->so_count, s->state, s->flags);
1097
1098                 s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;
1099                 ng_btsocket_rfcomm_session_clean(s);
1100         }
1101
1102         /* Now process upcall */
1103         switch (s->state) {
1104         /* Try to accept new L2CAP connection(s) */
1105         case NG_BTSOCKET_RFCOMM_SESSION_LISTENING:
1106                 while (ng_btsocket_rfcomm_session_accept(s) == 0)
1107                         ;
1108                 break;
1109
1110         /* Process the results of the L2CAP connect */
1111         case NG_BTSOCKET_RFCOMM_SESSION_CONNECTING:
1112                 ng_btsocket_rfcomm_session_process_pcb(s);
1113
1114                 if (ng_btsocket_rfcomm_session_connect(s) != 0) {
1115                         s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;
1116                         ng_btsocket_rfcomm_session_clean(s);
1117                 } 
1118                 break;
1119
1120         /* Try to receive/send more data */
1121         case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED:
1122         case NG_BTSOCKET_RFCOMM_SESSION_OPEN:
1123         case NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING:
1124                 ng_btsocket_rfcomm_session_process_pcb(s);
1125
1126                 if (ng_btsocket_rfcomm_session_receive(s) != 0) {
1127                         s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;
1128                         ng_btsocket_rfcomm_session_clean(s);
1129                 } else if (ng_btsocket_rfcomm_session_send(s) != 0) {
1130                         s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;
1131                         ng_btsocket_rfcomm_session_clean(s);
1132                 }
1133                 break;
1134
1135         case NG_BTSOCKET_RFCOMM_SESSION_CLOSED:
1136                 break;
1137
1138         default:
1139                 panic("%s: Invalid session state=%d, flags=%#x\n",
1140                         __func__, s->state, s->flags);
1141                 break;
1142         }
1143 } /* ng_btsocket_rfcomm_session_task */
1144
1145 /*
1146  * Process RFCOMM connection indicator. Caller must hold s->session_mtx
1147  */
1148
1149 static ng_btsocket_rfcomm_pcb_p
1150 ng_btsocket_rfcomm_connect_ind(ng_btsocket_rfcomm_session_p s, int channel)
1151 {
1152         ng_btsocket_rfcomm_pcb_p         pcb = NULL, pcb1 = NULL;
1153         ng_btsocket_l2cap_pcb_p          l2pcb = NULL;
1154         struct socket                   *so1;
1155
1156         mtx_assert(&s->session_mtx, MA_OWNED);
1157
1158         /*
1159          * Try to find RFCOMM socket that listens on given source address 
1160          * and channel. This will return the best possible match.
1161          */
1162
1163         l2pcb = so2l2cap_pcb(s->l2so);
1164         pcb = ng_btsocket_rfcomm_pcb_listener(&l2pcb->src, channel);
1165         if (pcb == NULL)
1166                 return (NULL);
1167
1168         /*
1169          * Check the pending connections queue and if we have space then 
1170          * create new socket and set proper source and destination address,
1171          * and channel.
1172          */
1173
1174         mtx_lock(&pcb->pcb_mtx);
1175
1176         CURVNET_SET(pcb->so->so_vnet);
1177         so1 = sonewconn(pcb->so, 0);
1178         CURVNET_RESTORE();
1179
1180         mtx_unlock(&pcb->pcb_mtx);
1181
1182         if (so1 == NULL)
1183                 return (NULL);
1184
1185         /*
1186          * If we got here than we have created new socket. So complete the 
1187          * connection. Set source and destination address from the session.
1188          */
1189
1190         pcb1 = so2rfcomm_pcb(so1);
1191         if (pcb1 == NULL)
1192                 panic("%s: pcb1 == NULL\n", __func__);
1193
1194         mtx_lock(&pcb1->pcb_mtx);
1195
1196         bcopy(&l2pcb->src, &pcb1->src, sizeof(pcb1->src));
1197         bcopy(&l2pcb->dst, &pcb1->dst, sizeof(pcb1->dst));
1198         pcb1->channel = channel;
1199
1200         /* Link new DLC to the session. We already hold s->session_mtx */
1201         LIST_INSERT_HEAD(&s->dlcs, pcb1, session_next);
1202         pcb1->session = s;
1203                         
1204         mtx_unlock(&pcb1->pcb_mtx);
1205
1206         return (pcb1);
1207 } /* ng_btsocket_rfcomm_connect_ind */
1208
1209 /*
1210  * Process RFCOMM connect confirmation. Caller must hold s->session_mtx.
1211  */
1212
1213 static void
1214 ng_btsocket_rfcomm_connect_cfm(ng_btsocket_rfcomm_session_p s)
1215 {
1216         ng_btsocket_rfcomm_pcb_p        pcb = NULL, pcb_next = NULL;
1217         int                             error;
1218
1219         mtx_assert(&s->session_mtx, MA_OWNED);
1220
1221         /*
1222          * Wake up all waiting sockets and send PN request for each of them. 
1223          * Note that timeout already been set in ng_btsocket_rfcomm_connect()
1224          *
1225          * Note: cannot use LIST_FOREACH because ng_btsocket_rfcomm_pcb_kill
1226          * will unlink DLC from the session
1227          */
1228
1229         for (pcb = LIST_FIRST(&s->dlcs); pcb != NULL; ) {
1230                 mtx_lock(&pcb->pcb_mtx);
1231                 pcb_next = LIST_NEXT(pcb, session_next);
1232
1233                 if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT) {
1234                         pcb->mtu = s->mtu;
1235                         bcopy(&so2l2cap_pcb(s->l2so)->src, &pcb->src,
1236                                 sizeof(pcb->src));
1237
1238                         error = ng_btsocket_rfcomm_send_pn(pcb);
1239                         if (error == 0)
1240                                 pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONFIGURING;
1241                         else
1242                                 ng_btsocket_rfcomm_pcb_kill(pcb, error);
1243                 }
1244
1245                 mtx_unlock(&pcb->pcb_mtx);
1246                 pcb = pcb_next;
1247         }
1248 } /* ng_btsocket_rfcomm_connect_cfm */
1249
1250 /*****************************************************************************
1251  *****************************************************************************
1252  **                              RFCOMM sessions
1253  *****************************************************************************
1254  *****************************************************************************/
1255
1256 /*
1257  * Create new RFCOMM session. That function WILL NOT take ownership over l2so.
1258  * Caller MUST free l2so if function failed.
1259  */
1260
1261 static int
1262 ng_btsocket_rfcomm_session_create(ng_btsocket_rfcomm_session_p *sp,
1263                 struct socket *l2so, bdaddr_p src, bdaddr_p dst,
1264                 struct thread *td)
1265 {
1266         ng_btsocket_rfcomm_session_p    s = NULL;
1267         struct sockaddr_l2cap           l2sa;
1268         struct sockopt                  l2sopt;
1269         int                             error;
1270         u_int16_t                       mtu;
1271
1272         mtx_assert(&ng_btsocket_rfcomm_sessions_mtx, MA_OWNED);
1273
1274         /* Allocate the RFCOMM session */
1275         s = malloc(sizeof(*s),
1276                 M_NETGRAPH_BTSOCKET_RFCOMM, M_NOWAIT | M_ZERO);
1277         if (s == NULL)
1278                 return (ENOMEM);
1279
1280         /* Set defaults */
1281         s->mtu = RFCOMM_DEFAULT_MTU;
1282         s->flags = 0;
1283         s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;
1284         NG_BT_MBUFQ_INIT(&s->outq, ifqmaxlen);
1285
1286         /*
1287          * XXX Mark session mutex as DUPOK to prevent "duplicated lock of 
1288          * the same type" message. When accepting new L2CAP connection
1289          * ng_btsocket_rfcomm_session_accept() holds both session mutexes 
1290          * for "old" (accepting) session and "new" (created) session.
1291          */
1292
1293         mtx_init(&s->session_mtx, "btsocks_rfcomm_session_mtx", NULL,
1294                 MTX_DEF|MTX_DUPOK);
1295
1296         LIST_INIT(&s->dlcs);
1297
1298         /* Prepare L2CAP socket */
1299         SOCKBUF_LOCK(&l2so->so_rcv);
1300         soupcall_set(l2so, SO_RCV, ng_btsocket_rfcomm_upcall, NULL);
1301         SOCKBUF_UNLOCK(&l2so->so_rcv);
1302         SOCKBUF_LOCK(&l2so->so_snd);
1303         soupcall_set(l2so, SO_SND, ng_btsocket_rfcomm_upcall, NULL);
1304         SOCKBUF_UNLOCK(&l2so->so_snd);
1305         l2so->so_state |= SS_NBIO;
1306         s->l2so = l2so;
1307
1308         mtx_lock(&s->session_mtx);
1309
1310         /*
1311          * "src" == NULL and "dst" == NULL means just create session.
1312          * caller must do the rest
1313          */
1314
1315         if (src == NULL && dst == NULL)
1316                 goto done;
1317
1318         /*
1319          * Set incoming MTU on L2CAP socket. It is RFCOMM session default MTU 
1320          * plus 5 bytes: RFCOMM frame header, one extra byte for length and one
1321          * extra byte for credits.
1322          */
1323
1324         mtu = s->mtu + sizeof(struct rfcomm_frame_hdr) + 1 + 1;
1325
1326         l2sopt.sopt_dir = SOPT_SET;
1327         l2sopt.sopt_level = SOL_L2CAP;
1328         l2sopt.sopt_name = SO_L2CAP_IMTU;
1329         l2sopt.sopt_val = (void *) &mtu;
1330         l2sopt.sopt_valsize = sizeof(mtu);
1331         l2sopt.sopt_td = NULL;
1332
1333         error = sosetopt(s->l2so, &l2sopt);
1334         if (error != 0)
1335                 goto bad;
1336
1337         /* Bind socket to "src" address */
1338         l2sa.l2cap_len = sizeof(l2sa);
1339         l2sa.l2cap_family = AF_BLUETOOTH;
1340         l2sa.l2cap_psm = (dst == NULL)? htole16(NG_L2CAP_PSM_RFCOMM) : 0;
1341         bcopy(src, &l2sa.l2cap_bdaddr, sizeof(l2sa.l2cap_bdaddr));
1342         l2sa.l2cap_cid = 0;
1343         l2sa.l2cap_bdaddr_type = BDADDR_BREDR;
1344
1345         error = sobind(s->l2so, (struct sockaddr *) &l2sa, td);
1346         if (error != 0)
1347                 goto bad;
1348
1349         /* If "dst" is not NULL then initiate connect(), otherwise listen() */
1350         if (dst == NULL) {
1351                 s->flags = 0;
1352                 s->state = NG_BTSOCKET_RFCOMM_SESSION_LISTENING;
1353
1354                 error = solisten(s->l2so, 10, td);
1355                 if (error != 0)
1356                         goto bad;
1357         } else {
1358                 s->flags = NG_BTSOCKET_RFCOMM_SESSION_INITIATOR;
1359                 s->state = NG_BTSOCKET_RFCOMM_SESSION_CONNECTING;
1360
1361                 l2sa.l2cap_len = sizeof(l2sa);   
1362                 l2sa.l2cap_family = AF_BLUETOOTH;
1363                 l2sa.l2cap_psm = htole16(NG_L2CAP_PSM_RFCOMM);
1364                 bcopy(dst, &l2sa.l2cap_bdaddr, sizeof(l2sa.l2cap_bdaddr));
1365                 l2sa.l2cap_cid = 0;
1366                 l2sa.l2cap_bdaddr_type = BDADDR_BREDR;
1367
1368                 error = soconnect(s->l2so, (struct sockaddr *) &l2sa, td);
1369                 if (error != 0)
1370                         goto bad;
1371         }
1372
1373 done:
1374         LIST_INSERT_HEAD(&ng_btsocket_rfcomm_sessions, s, next);
1375         *sp = s;
1376
1377         mtx_unlock(&s->session_mtx);
1378
1379         return (0);
1380
1381 bad:
1382         mtx_unlock(&s->session_mtx);
1383
1384         /* Return L2CAP socket back to its original state */
1385         SOCKBUF_LOCK(&l2so->so_rcv);
1386         soupcall_clear(s->l2so, SO_RCV);
1387         SOCKBUF_UNLOCK(&l2so->so_rcv);
1388         SOCKBUF_LOCK(&l2so->so_snd);
1389         soupcall_clear(s->l2so, SO_SND);
1390         SOCKBUF_UNLOCK(&l2so->so_snd);
1391         l2so->so_state &= ~SS_NBIO;
1392
1393         mtx_destroy(&s->session_mtx);
1394         bzero(s, sizeof(*s));
1395         free(s, M_NETGRAPH_BTSOCKET_RFCOMM);
1396
1397         return (error);
1398 } /* ng_btsocket_rfcomm_session_create */
1399
1400 /*
1401  * Process accept() on RFCOMM session
1402  * XXX FIXME locking for "l2so"?
1403  */
1404
1405 static int
1406 ng_btsocket_rfcomm_session_accept(ng_btsocket_rfcomm_session_p s0)
1407 {
1408         struct socket                   *l2so;
1409         struct sockaddr_l2cap           *l2sa = NULL;
1410         ng_btsocket_l2cap_pcb_t         *l2pcb = NULL;
1411         ng_btsocket_rfcomm_session_p     s = NULL;
1412         int                              error;
1413
1414         mtx_assert(&ng_btsocket_rfcomm_sessions_mtx, MA_OWNED);
1415         mtx_assert(&s0->session_mtx, MA_OWNED);
1416
1417         SOLISTEN_LOCK(s0->l2so);
1418         error = solisten_dequeue(s0->l2so, &l2so, 0);
1419         if (error == EWOULDBLOCK)
1420                 return (error);
1421         if (error) {
1422                 NG_BTSOCKET_RFCOMM_ERR(
1423 "%s: Could not accept connection on L2CAP socket, error=%d\n", __func__, error);
1424                 return (error);
1425         }
1426
1427         error = soaccept(l2so, (struct sockaddr **) &l2sa);
1428         if (error != 0) {
1429                 NG_BTSOCKET_RFCOMM_ERR(
1430 "%s: soaccept() on L2CAP socket failed, error=%d\n", __func__, error);
1431                 soclose(l2so);
1432
1433                 return (error);
1434         }
1435
1436         /*
1437          * Check if there is already active RFCOMM session between two devices.
1438          * If so then close L2CAP connection. We only support one RFCOMM session
1439          * between each pair of devices. Note that here we assume session in any
1440          * state. The session even could be in the middle of disconnecting.
1441          */
1442
1443         l2pcb = so2l2cap_pcb(l2so);
1444         s = ng_btsocket_rfcomm_session_by_addr(&l2pcb->src, &l2pcb->dst);
1445         if (s == NULL) {
1446                 /* Create a new RFCOMM session */
1447                 error = ng_btsocket_rfcomm_session_create(&s, l2so, NULL, NULL,
1448                                 curthread /* XXX */);
1449                 if (error == 0) {
1450                         mtx_lock(&s->session_mtx);
1451
1452                         s->flags = 0;
1453                         s->state = NG_BTSOCKET_RFCOMM_SESSION_CONNECTED;
1454
1455                         /*
1456                          * Adjust MTU on incoming connection. Reserve 5 bytes:
1457                          * RFCOMM frame header, one extra byte for length and 
1458                          * one extra byte for credits.
1459                          */
1460
1461                         s->mtu = min(l2pcb->imtu, l2pcb->omtu) -
1462                                         sizeof(struct rfcomm_frame_hdr) - 1 - 1;
1463
1464                         mtx_unlock(&s->session_mtx);
1465                 } else {
1466                         NG_BTSOCKET_RFCOMM_ALERT(
1467 "%s: Failed to create new RFCOMM session, error=%d\n", __func__, error);
1468
1469                         soclose(l2so);
1470                 }
1471         } else {
1472                 NG_BTSOCKET_RFCOMM_WARN(
1473 "%s: Rejecting duplicating RFCOMM session between src=%x:%x:%x:%x:%x:%x and " \
1474 "dst=%x:%x:%x:%x:%x:%x, state=%d, flags=%#x\n", __func__,
1475                         l2pcb->src.b[5], l2pcb->src.b[4], l2pcb->src.b[3],
1476                         l2pcb->src.b[2], l2pcb->src.b[1], l2pcb->src.b[0],
1477                         l2pcb->dst.b[5], l2pcb->dst.b[4], l2pcb->dst.b[3],
1478                         l2pcb->dst.b[2], l2pcb->dst.b[1], l2pcb->dst.b[0],
1479                         s->state, s->flags);
1480
1481                 error = EBUSY;
1482                 soclose(l2so);
1483         }
1484
1485         return (error);
1486 } /* ng_btsocket_rfcomm_session_accept */
1487
1488 /*
1489  * Process connect() on RFCOMM session
1490  * XXX FIXME locking for "l2so"?
1491  */
1492
1493 static int
1494 ng_btsocket_rfcomm_session_connect(ng_btsocket_rfcomm_session_p s)
1495 {
1496         ng_btsocket_l2cap_pcb_p l2pcb = so2l2cap_pcb(s->l2so);
1497         int                     error;
1498
1499         mtx_assert(&s->session_mtx, MA_OWNED);
1500
1501         /* First check if connection has failed */
1502         if ((error = s->l2so->so_error) != 0) {
1503                 s->l2so->so_error = 0;
1504
1505                 NG_BTSOCKET_RFCOMM_ERR(
1506 "%s: Could not connect RFCOMM session, error=%d, state=%d, flags=%#x\n",
1507                         __func__, error, s->state, s->flags);
1508
1509                 return (error);
1510         }
1511
1512         /* Is connection still in progress? */
1513         if (s->l2so->so_state & SS_ISCONNECTING)
1514                 return (0); 
1515
1516         /* 
1517          * If we got here then we are connected. Send SABM on DLCI 0 to 
1518          * open multiplexor channel.
1519          */
1520
1521         if (error == 0) {
1522                 s->state = NG_BTSOCKET_RFCOMM_SESSION_CONNECTED;
1523
1524                 /*
1525                  * Adjust MTU on outgoing connection. Reserve 5 bytes: RFCOMM 
1526                  * frame header, one extra byte for length and one extra byte 
1527                  * for credits.
1528                  */
1529
1530                 s->mtu = min(l2pcb->imtu, l2pcb->omtu) -
1531                                 sizeof(struct rfcomm_frame_hdr) - 1 - 1;
1532
1533                 error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_SABM,0);
1534                 if (error == 0)
1535                         error = ng_btsocket_rfcomm_task_wakeup();
1536         }
1537
1538         return (error);
1539 }/* ng_btsocket_rfcomm_session_connect */
1540
1541 /*
1542  * Receive data on RFCOMM session
1543  * XXX FIXME locking for "l2so"?
1544  */
1545
1546 static int
1547 ng_btsocket_rfcomm_session_receive(ng_btsocket_rfcomm_session_p s)
1548 {
1549         struct mbuf     *m = NULL;
1550         struct uio       uio;
1551         int              more, flags, error;
1552
1553         mtx_assert(&s->session_mtx, MA_OWNED);
1554
1555         /* Can we read from the L2CAP socket? */
1556         if (!soreadable(s->l2so))
1557                 return (0);
1558
1559         /* First check for error on L2CAP socket */
1560         if ((error = s->l2so->so_error) != 0) {
1561                 s->l2so->so_error = 0;
1562
1563                 NG_BTSOCKET_RFCOMM_ERR(
1564 "%s: Could not receive data from L2CAP socket, error=%d, state=%d, flags=%#x\n",
1565                         __func__, error, s->state, s->flags);
1566
1567                 return (error);
1568         }
1569
1570         /*
1571          * Read all packets from the L2CAP socket. 
1572          * XXX FIXME/VERIFY is that correct? For now use m->m_nextpkt as
1573          * indication that there is more packets on the socket's buffer.
1574          * Also what should we use in uio.uio_resid?
1575          * May be s->mtu + sizeof(struct rfcomm_frame_hdr) + 1 + 1?
1576          */
1577
1578         for (more = 1; more; ) {
1579                 /* Try to get next packet from socket */
1580                 bzero(&uio, sizeof(uio));
1581 /*              uio.uio_td = NULL; */
1582                 uio.uio_resid = 1000000000;
1583                 flags = MSG_DONTWAIT;
1584
1585                 m = NULL;
1586                 error = soreceive(s->l2so, NULL, &uio, &m,
1587                     (struct mbuf **) NULL, &flags);
1588                 if (error != 0) {
1589                         if (error == EWOULDBLOCK)
1590                                 return (0); /* XXX can happen? */
1591
1592                         NG_BTSOCKET_RFCOMM_ERR(
1593 "%s: Could not receive data from L2CAP socket, error=%d\n", __func__, error);
1594
1595                         return (error);
1596                 }
1597         
1598                 more = (m->m_nextpkt != NULL);
1599                 m->m_nextpkt = NULL;
1600
1601                 ng_btsocket_rfcomm_receive_frame(s, m);
1602         }
1603
1604         return (0);
1605 } /* ng_btsocket_rfcomm_session_receive */
1606
1607 /*
1608  * Send data on RFCOMM session
1609  * XXX FIXME locking for "l2so"?
1610  */
1611
1612 static int
1613 ng_btsocket_rfcomm_session_send(ng_btsocket_rfcomm_session_p s)
1614 {
1615         struct mbuf     *m = NULL;
1616         int              error;
1617
1618         mtx_assert(&s->session_mtx, MA_OWNED);
1619
1620         /* Send as much as we can from the session queue */
1621         while (sowriteable(s->l2so)) {
1622                 /* Check if socket still OK */
1623                 if ((error = s->l2so->so_error) != 0) {
1624                         s->l2so->so_error = 0;
1625
1626                         NG_BTSOCKET_RFCOMM_ERR(
1627 "%s: Detected error=%d on L2CAP socket, state=%d, flags=%#x\n",
1628                                 __func__, error, s->state, s->flags);
1629
1630                         return (error);
1631                 }
1632
1633                 NG_BT_MBUFQ_DEQUEUE(&s->outq, m);
1634                 if (m == NULL)
1635                         return (0); /* we are done */
1636
1637                 /* Call send function on the L2CAP socket */
1638                 error = (*s->l2so->so_proto->pr_usrreqs->pru_send)(s->l2so,
1639                                 0, m, NULL, NULL, curthread /* XXX */);
1640                 if (error != 0) {
1641                         NG_BTSOCKET_RFCOMM_ERR(
1642 "%s: Could not send data to L2CAP socket, error=%d\n", __func__, error);
1643
1644                         return (error);
1645                 }
1646         }
1647
1648         return (0);
1649 } /* ng_btsocket_rfcomm_session_send */
1650
1651 /*
1652  * Close and disconnect all DLCs for the given session. Caller must hold 
1653  * s->sesson_mtx. Will wakeup session.
1654  */
1655
1656 static void
1657 ng_btsocket_rfcomm_session_clean(ng_btsocket_rfcomm_session_p s)
1658 {
1659         ng_btsocket_rfcomm_pcb_p        pcb = NULL, pcb_next = NULL;
1660         int                             error;
1661
1662         mtx_assert(&s->session_mtx, MA_OWNED);
1663
1664         /*
1665          * Note: cannot use LIST_FOREACH because ng_btsocket_rfcomm_pcb_kill
1666          * will unlink DLC from the session
1667          */
1668
1669         for (pcb = LIST_FIRST(&s->dlcs); pcb != NULL; ) {
1670                 mtx_lock(&pcb->pcb_mtx);
1671                 pcb_next = LIST_NEXT(pcb, session_next);
1672
1673                 NG_BTSOCKET_RFCOMM_INFO(
1674 "%s: Disconnecting dlci=%d, state=%d, flags=%#x\n",
1675                         __func__, pcb->dlci, pcb->state, pcb->flags);
1676
1677                 if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONNECTED)
1678                         error = ECONNRESET;
1679                 else
1680                         error = ECONNREFUSED;
1681
1682                 ng_btsocket_rfcomm_pcb_kill(pcb, error);
1683
1684                 mtx_unlock(&pcb->pcb_mtx);
1685                 pcb = pcb_next;
1686         }
1687 } /* ng_btsocket_rfcomm_session_clean */
1688
1689 /*
1690  * Process all DLCs on the session. Caller MUST hold s->session_mtx.
1691  */
1692
1693 static void
1694 ng_btsocket_rfcomm_session_process_pcb(ng_btsocket_rfcomm_session_p s)
1695 {
1696         ng_btsocket_rfcomm_pcb_p        pcb = NULL, pcb_next = NULL;
1697         int                             error;
1698
1699         mtx_assert(&s->session_mtx, MA_OWNED);
1700
1701         /*
1702          * Note: cannot use LIST_FOREACH because ng_btsocket_rfcomm_pcb_kill
1703          * will unlink DLC from the session
1704          */
1705
1706         for (pcb = LIST_FIRST(&s->dlcs); pcb != NULL; ) {
1707                 mtx_lock(&pcb->pcb_mtx);
1708                 pcb_next = LIST_NEXT(pcb, session_next);
1709
1710                 switch (pcb->state) {
1711
1712                 /*
1713                  * If DLC in W4_CONNECT state then we should check for both
1714                  * timeout and detach.
1715                  */
1716
1717                 case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT:
1718                         if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_DETACHED)
1719                                 ng_btsocket_rfcomm_pcb_kill(pcb, 0);
1720                         else if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT)
1721                                 ng_btsocket_rfcomm_pcb_kill(pcb, ETIMEDOUT);
1722                         break;
1723
1724                 /*
1725                  * If DLC in CONFIGURING or CONNECTING state then we only
1726                  * should check for timeout. If detach() was called then
1727                  * DLC will be moved into DISCONNECTING state.
1728                  */
1729
1730                 case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING:
1731                 case NG_BTSOCKET_RFCOMM_DLC_CONNECTING:
1732                         if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT)
1733                                 ng_btsocket_rfcomm_pcb_kill(pcb, ETIMEDOUT);
1734                         break;
1735
1736                 /*
1737                  * If DLC in CONNECTED state then we need to send data (if any)
1738                  * from the socket's send queue. Note that we will send data
1739                  * from either all sockets or none. This may overload session's
1740                  * outgoing queue (but we do not check for that).
1741                  *
1742                  * XXX FIXME need scheduler for RFCOMM sockets
1743                  */
1744
1745                 case NG_BTSOCKET_RFCOMM_DLC_CONNECTED:
1746                         error = ng_btsocket_rfcomm_pcb_send(pcb, ALOT);
1747                         if (error != 0)
1748                                 ng_btsocket_rfcomm_pcb_kill(pcb, error);
1749                         break;
1750
1751                 /*
1752                  * If DLC in DISCONNECTING state then we must send DISC frame.
1753                  * Note that if DLC has timeout set then we do not need to 
1754                  * resend DISC frame.
1755                  *
1756                  * XXX FIXME need to drain all data from the socket's queue
1757                  * if LINGER option was set
1758                  */
1759
1760                 case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING:
1761                         if (!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)) {
1762                                 error = ng_btsocket_rfcomm_send_command(
1763                                                 pcb->session, RFCOMM_FRAME_DISC,
1764                                                 pcb->dlci);
1765                                 if (error == 0)
1766                                         ng_btsocket_rfcomm_timeout(pcb);
1767                                 else
1768                                         ng_btsocket_rfcomm_pcb_kill(pcb, error);
1769                         } else if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT)
1770                                 ng_btsocket_rfcomm_pcb_kill(pcb, ETIMEDOUT);
1771                         break;
1772                 
1773 /*              case NG_BTSOCKET_RFCOMM_DLC_CLOSED: */
1774                 default:
1775                         panic("%s: Invalid DLC state=%d, flags=%#x\n",
1776                                 __func__, pcb->state, pcb->flags);
1777                         break;
1778                 }
1779
1780                 mtx_unlock(&pcb->pcb_mtx);
1781                 pcb = pcb_next;
1782         }
1783 } /* ng_btsocket_rfcomm_session_process_pcb */
1784
1785 /*
1786  * Find RFCOMM session between "src" and "dst".
1787  * Caller MUST hold ng_btsocket_rfcomm_sessions_mtx.
1788  */
1789
1790 static ng_btsocket_rfcomm_session_p
1791 ng_btsocket_rfcomm_session_by_addr(bdaddr_p src, bdaddr_p dst)
1792 {
1793         ng_btsocket_rfcomm_session_p    s = NULL;
1794         ng_btsocket_l2cap_pcb_p         l2pcb = NULL;
1795         int                             any_src;
1796
1797         mtx_assert(&ng_btsocket_rfcomm_sessions_mtx, MA_OWNED);
1798
1799         any_src = (bcmp(src, NG_HCI_BDADDR_ANY, sizeof(*src)) == 0);
1800
1801         LIST_FOREACH(s, &ng_btsocket_rfcomm_sessions, next) {
1802                 l2pcb = so2l2cap_pcb(s->l2so);
1803
1804                 if ((any_src || bcmp(&l2pcb->src, src, sizeof(*src)) == 0) &&
1805                     bcmp(&l2pcb->dst, dst, sizeof(*dst)) == 0)
1806                         break;
1807         }
1808
1809         return (s);
1810 } /* ng_btsocket_rfcomm_session_by_addr */
1811
1812 /*****************************************************************************
1813  *****************************************************************************
1814  **                                  RFCOMM 
1815  *****************************************************************************
1816  *****************************************************************************/
1817
1818 /*
1819  * Process incoming RFCOMM frame. Caller must hold s->session_mtx.
1820  * XXX FIXME check frame length
1821  */
1822
1823 static int
1824 ng_btsocket_rfcomm_receive_frame(ng_btsocket_rfcomm_session_p s,
1825                 struct mbuf *m0)
1826 {
1827         struct rfcomm_frame_hdr *hdr = NULL;
1828         struct mbuf             *m = NULL;
1829         u_int16_t                length;
1830         u_int8_t                 dlci, type;
1831         int                      error = 0;
1832
1833         mtx_assert(&s->session_mtx, MA_OWNED);
1834
1835         /* Pullup as much as we can into first mbuf (for direct access) */
1836         length = min(m0->m_pkthdr.len, MHLEN);
1837         if (m0->m_len < length) {
1838                 if ((m0 = m_pullup(m0, length)) == NULL) {
1839                         NG_BTSOCKET_RFCOMM_ALERT(
1840 "%s: m_pullup(%d) failed\n", __func__, length);
1841
1842                         return (ENOBUFS);
1843                 }
1844         }
1845
1846         hdr = mtod(m0, struct rfcomm_frame_hdr *);
1847         dlci = RFCOMM_DLCI(hdr->address);
1848         type = RFCOMM_TYPE(hdr->control);
1849
1850         /* Test EA bit in length. If not set then we have 2 bytes of length */
1851         if (!RFCOMM_EA(hdr->length)) {
1852                 bcopy(&hdr->length, &length, sizeof(length));
1853                 length = le16toh(length) >> 1;
1854                 m_adj(m0, sizeof(*hdr) + 1);
1855         } else {
1856                 length = hdr->length >> 1;
1857                 m_adj(m0, sizeof(*hdr));
1858         }
1859
1860         NG_BTSOCKET_RFCOMM_INFO(
1861 "%s: Got frame type=%#x, dlci=%d, length=%d, cr=%d, pf=%d, len=%d\n",
1862                 __func__, type, dlci, length, RFCOMM_CR(hdr->address),
1863                 RFCOMM_PF(hdr->control), m0->m_pkthdr.len);
1864
1865         /*
1866          * Get FCS (the last byte in the frame)
1867          * XXX this will not work if mbuf chain ends with empty mbuf.
1868          * XXX let's hope it never happens :)
1869          */
1870
1871         for (m = m0; m->m_next != NULL; m = m->m_next)
1872                 ;
1873         if (m->m_len <= 0)
1874                 panic("%s: Empty mbuf at the end of the chain, len=%d\n",
1875                         __func__, m->m_len);
1876
1877         /*
1878          * Check FCS. We only need to calculate FCS on first 2 or 3 bytes
1879          * and already m_pullup'ed mbuf chain, so it should be safe.
1880          */
1881
1882         if (ng_btsocket_rfcomm_check_fcs((u_int8_t *) hdr, type, m->m_data[m->m_len - 1])) {
1883                 NG_BTSOCKET_RFCOMM_ERR(
1884 "%s: Invalid RFCOMM packet. Bad checksum\n", __func__);
1885                 NG_FREE_M(m0);
1886
1887                 return (EINVAL);
1888         }
1889
1890         m_adj(m0, -1); /* Trim FCS byte */
1891
1892         /*
1893          * Process RFCOMM frame.
1894          *
1895          * From TS 07.10 spec
1896          * 
1897          * "... In the case where a SABM or DISC command with the P bit set
1898          * to 0 is received then the received frame shall be discarded..."
1899          *
1900          * "... If a unsolicited DM response is received then the frame shall
1901          * be processed irrespective of the P/F setting... "
1902          *
1903          * "... The station may transmit response frames with the F bit set 
1904          * to 0 at any opportunity on an asynchronous basis. However, in the 
1905          * case where a UA response is received with the F bit set to 0 then 
1906          * the received frame shall be discarded..."
1907          *
1908          * From Bluetooth spec
1909          *
1910          * "... When credit based flow control is being used, the meaning of
1911          * the P/F bit in the control field of the RFCOMM header is redefined
1912          * for UIH frames..."
1913          */
1914
1915         switch (type) {
1916         case RFCOMM_FRAME_SABM:
1917                 if (RFCOMM_PF(hdr->control))
1918                         error = ng_btsocket_rfcomm_receive_sabm(s, dlci);
1919                 break;
1920
1921         case RFCOMM_FRAME_DISC:
1922                 if (RFCOMM_PF(hdr->control))
1923                         error = ng_btsocket_rfcomm_receive_disc(s, dlci);
1924                 break;
1925
1926         case RFCOMM_FRAME_UA:
1927                 if (RFCOMM_PF(hdr->control))
1928                         error = ng_btsocket_rfcomm_receive_ua(s, dlci);
1929                 break;
1930
1931         case RFCOMM_FRAME_DM:
1932                 error = ng_btsocket_rfcomm_receive_dm(s, dlci);
1933                 break;
1934
1935         case RFCOMM_FRAME_UIH:
1936                 if (dlci == 0)
1937                         error = ng_btsocket_rfcomm_receive_mcc(s, m0);
1938                 else
1939                         error = ng_btsocket_rfcomm_receive_uih(s, dlci,
1940                                         RFCOMM_PF(hdr->control), m0);
1941
1942                 return (error);
1943                 /* NOT REACHED */
1944
1945         default:
1946                 NG_BTSOCKET_RFCOMM_ERR(
1947 "%s: Invalid RFCOMM packet. Unknown type=%#x\n", __func__, type);
1948                 error = EINVAL;
1949                 break;
1950         }
1951
1952         NG_FREE_M(m0);
1953
1954         return (error);
1955 } /* ng_btsocket_rfcomm_receive_frame */
1956
1957 /*
1958  * Process RFCOMM SABM frame
1959  */
1960
1961 static int
1962 ng_btsocket_rfcomm_receive_sabm(ng_btsocket_rfcomm_session_p s, int dlci)
1963 {
1964         ng_btsocket_rfcomm_pcb_p        pcb = NULL;
1965         int                             error = 0;
1966
1967         mtx_assert(&s->session_mtx, MA_OWNED);
1968
1969         NG_BTSOCKET_RFCOMM_INFO(
1970 "%s: Got SABM, session state=%d, flags=%#x, mtu=%d, dlci=%d\n",
1971                 __func__, s->state, s->flags, s->mtu, dlci);
1972
1973         /* DLCI == 0 means open multiplexor channel */
1974         if (dlci == 0) {
1975                 switch (s->state) {
1976                 case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED:
1977                 case NG_BTSOCKET_RFCOMM_SESSION_OPEN:
1978                         error = ng_btsocket_rfcomm_send_command(s,
1979                                         RFCOMM_FRAME_UA, dlci);
1980                         if (error == 0) {
1981                                 s->state = NG_BTSOCKET_RFCOMM_SESSION_OPEN;
1982                                 ng_btsocket_rfcomm_connect_cfm(s);
1983                         } else {
1984                                 s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;
1985                                 ng_btsocket_rfcomm_session_clean(s);
1986                         }
1987                         break;
1988
1989                 default:
1990                         NG_BTSOCKET_RFCOMM_WARN(
1991 "%s: Got SABM for session in invalid state state=%d, flags=%#x\n",
1992                                 __func__, s->state, s->flags);
1993                         error = EINVAL;
1994                         break;
1995                 }
1996
1997                 return (error);
1998         }
1999
2000         /* Make sure multiplexor channel is open */
2001         if (s->state != NG_BTSOCKET_RFCOMM_SESSION_OPEN) {
2002                 NG_BTSOCKET_RFCOMM_ERR(
2003 "%s: Got SABM for dlci=%d with mulitplexor channel closed, state=%d, " \
2004 "flags=%#x\n",          __func__, dlci, s->state, s->flags);
2005
2006                 return (EINVAL);
2007         }
2008
2009         /*
2010          * Check if we have this DLCI. This might happen when remote
2011          * peer uses PN command before actual open (SABM) happens.
2012          */
2013
2014         pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci);
2015         if (pcb != NULL) {
2016                 mtx_lock(&pcb->pcb_mtx);
2017
2018                 if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTING) {
2019                         NG_BTSOCKET_RFCOMM_ERR(
2020 "%s: Got SABM for dlci=%d in invalid state=%d, flags=%#x\n",
2021                                 __func__, dlci, pcb->state, pcb->flags);
2022                         mtx_unlock(&pcb->pcb_mtx);
2023
2024                         return (ENOENT);
2025                 }
2026
2027                 ng_btsocket_rfcomm_untimeout(pcb);
2028
2029                 error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_UA,dlci);
2030                 if (error == 0)
2031                         error = ng_btsocket_rfcomm_send_msc(pcb);
2032
2033                 if (error == 0) {
2034                         pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTED;
2035                         soisconnected(pcb->so);
2036                 } else
2037                         ng_btsocket_rfcomm_pcb_kill(pcb, error);
2038
2039                 mtx_unlock(&pcb->pcb_mtx);
2040
2041                 return (error);
2042         }
2043
2044         /*
2045          * We do not have requested DLCI, so it must be an incoming connection
2046          * with default parameters. Try to accept it.
2047          */ 
2048
2049         pcb = ng_btsocket_rfcomm_connect_ind(s, RFCOMM_SRVCHANNEL(dlci));
2050         if (pcb != NULL) {
2051                 mtx_lock(&pcb->pcb_mtx);
2052
2053                 pcb->dlci = dlci;
2054
2055                 error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_UA,dlci);
2056                 if (error == 0)
2057                         error = ng_btsocket_rfcomm_send_msc(pcb);
2058
2059                 if (error == 0) {
2060                         pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTED;
2061                         soisconnected(pcb->so);
2062                 } else
2063                         ng_btsocket_rfcomm_pcb_kill(pcb, error);
2064
2065                 mtx_unlock(&pcb->pcb_mtx);
2066         } else
2067                 /* Nobody is listen()ing on the requested DLCI */
2068                 error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_DM,dlci);
2069
2070         return (error);
2071 } /* ng_btsocket_rfcomm_receive_sabm */
2072
2073 /*
2074  * Process RFCOMM DISC frame
2075  */
2076
2077 static int
2078 ng_btsocket_rfcomm_receive_disc(ng_btsocket_rfcomm_session_p s, int dlci)
2079 {
2080         ng_btsocket_rfcomm_pcb_p        pcb = NULL;
2081         int                             error = 0;
2082
2083         mtx_assert(&s->session_mtx, MA_OWNED);
2084
2085         NG_BTSOCKET_RFCOMM_INFO(
2086 "%s: Got DISC, session state=%d, flags=%#x, mtu=%d, dlci=%d\n",
2087                 __func__, s->state, s->flags, s->mtu, dlci);
2088
2089         /* DLCI == 0 means close multiplexor channel */
2090         if (dlci == 0) {
2091                 /* XXX FIXME assume that remote side will close the socket */
2092                 error = ng_btsocket_rfcomm_send_command(s, RFCOMM_FRAME_UA, 0);
2093                 if (error == 0) {
2094                         if (s->state == NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING)
2095                                 s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; /* XXX */
2096                         else
2097                                 s->state = NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING;
2098                 } else
2099                         s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; /* XXX */
2100
2101                 ng_btsocket_rfcomm_session_clean(s);
2102         } else {
2103                 pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci);
2104                 if (pcb != NULL) {
2105                         int     err;
2106
2107                         mtx_lock(&pcb->pcb_mtx);
2108
2109                         NG_BTSOCKET_RFCOMM_INFO(
2110 "%s: Got DISC for dlci=%d, state=%d, flags=%#x\n",
2111                                 __func__, dlci, pcb->state, pcb->flags);
2112
2113                         error = ng_btsocket_rfcomm_send_command(s,
2114                                         RFCOMM_FRAME_UA, dlci);
2115
2116                         if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONNECTED)
2117                                 err = 0;
2118                         else
2119                                 err = ECONNREFUSED;
2120
2121                         ng_btsocket_rfcomm_pcb_kill(pcb, err);
2122
2123                         mtx_unlock(&pcb->pcb_mtx);
2124                 } else {
2125                         NG_BTSOCKET_RFCOMM_WARN(
2126 "%s: Got DISC for non-existing dlci=%d\n", __func__, dlci);
2127
2128                         error = ng_btsocket_rfcomm_send_command(s,
2129                                         RFCOMM_FRAME_DM, dlci);
2130                 }
2131         }
2132
2133         return (error);
2134 } /* ng_btsocket_rfcomm_receive_disc */
2135
2136 /*
2137  * Process RFCOMM UA frame
2138  */
2139
2140 static int
2141 ng_btsocket_rfcomm_receive_ua(ng_btsocket_rfcomm_session_p s, int dlci)
2142 {
2143         ng_btsocket_rfcomm_pcb_p        pcb = NULL;
2144         int                             error = 0;
2145
2146         mtx_assert(&s->session_mtx, MA_OWNED);
2147
2148         NG_BTSOCKET_RFCOMM_INFO(
2149 "%s: Got UA, session state=%d, flags=%#x, mtu=%d, dlci=%d\n",
2150                 __func__, s->state, s->flags, s->mtu, dlci);
2151
2152         /* dlci == 0 means multiplexor channel */
2153         if (dlci == 0) {
2154                 switch (s->state) {
2155                 case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED:
2156                         s->state = NG_BTSOCKET_RFCOMM_SESSION_OPEN;
2157                         ng_btsocket_rfcomm_connect_cfm(s);
2158                         break;
2159
2160                 case NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING:
2161                         s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;
2162                         ng_btsocket_rfcomm_session_clean(s);
2163                         break;
2164
2165                 default:
2166                         NG_BTSOCKET_RFCOMM_WARN(
2167 "%s: Got UA for session in invalid state=%d(%d), flags=%#x, mtu=%d\n",
2168                                 __func__, s->state, INITIATOR(s), s->flags,
2169                                 s->mtu);
2170                         error = ENOENT;
2171                         break;
2172                 }
2173
2174                 return (error);
2175         }
2176
2177         /* Check if we have this DLCI */
2178         pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci);
2179         if (pcb != NULL) {
2180                 mtx_lock(&pcb->pcb_mtx);
2181
2182                 NG_BTSOCKET_RFCOMM_INFO(
2183 "%s: Got UA for dlci=%d, state=%d, flags=%#x\n",
2184                         __func__, dlci, pcb->state, pcb->flags);
2185
2186                 switch (pcb->state) {
2187                 case NG_BTSOCKET_RFCOMM_DLC_CONNECTING:
2188                         ng_btsocket_rfcomm_untimeout(pcb);
2189
2190                         error = ng_btsocket_rfcomm_send_msc(pcb);
2191                         if (error == 0) {
2192                                 pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTED;
2193                                 soisconnected(pcb->so);
2194                         }
2195                         break;
2196
2197                 case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING:
2198                         ng_btsocket_rfcomm_pcb_kill(pcb, 0);
2199                         break;
2200
2201                 default:
2202                         NG_BTSOCKET_RFCOMM_WARN(
2203 "%s: Got UA for dlci=%d in invalid state=%d, flags=%#x\n",
2204                                 __func__, dlci, pcb->state, pcb->flags);
2205                         error = ENOENT;
2206                         break;
2207                 }
2208
2209                 mtx_unlock(&pcb->pcb_mtx);
2210         } else {
2211                 NG_BTSOCKET_RFCOMM_WARN(
2212 "%s: Got UA for non-existing dlci=%d\n", __func__, dlci);
2213
2214                 error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_DM,dlci);
2215         }
2216
2217         return (error);
2218 } /* ng_btsocket_rfcomm_receive_ua */
2219
2220 /*
2221  * Process RFCOMM DM frame
2222  */
2223
2224 static int
2225 ng_btsocket_rfcomm_receive_dm(ng_btsocket_rfcomm_session_p s, int dlci)
2226 {
2227         ng_btsocket_rfcomm_pcb_p        pcb = NULL;
2228         int                             error;
2229
2230         mtx_assert(&s->session_mtx, MA_OWNED);
2231
2232         NG_BTSOCKET_RFCOMM_INFO(
2233 "%s: Got DM, session state=%d, flags=%#x, mtu=%d, dlci=%d\n",
2234                 __func__, s->state, s->flags, s->mtu, dlci);
2235
2236         /* DLCI == 0 means multiplexor channel */
2237         if (dlci == 0) {
2238                 /* Disconnect all dlc's on the session */
2239                 s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;
2240                 ng_btsocket_rfcomm_session_clean(s);
2241         } else {
2242                 pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci);
2243                 if (pcb != NULL) {
2244                         mtx_lock(&pcb->pcb_mtx);
2245
2246                         NG_BTSOCKET_RFCOMM_INFO(
2247 "%s: Got DM for dlci=%d, state=%d, flags=%#x\n",
2248                                 __func__, dlci, pcb->state, pcb->flags);
2249
2250                         if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONNECTED)
2251                                 error = ECONNRESET;
2252                         else
2253                                 error = ECONNREFUSED;
2254
2255                         ng_btsocket_rfcomm_pcb_kill(pcb, error);
2256
2257                         mtx_unlock(&pcb->pcb_mtx);
2258                 } else
2259                         NG_BTSOCKET_RFCOMM_WARN(
2260 "%s: Got DM for non-existing dlci=%d\n", __func__, dlci);
2261         }
2262
2263         return (0);
2264 } /* ng_btsocket_rfcomm_receive_dm */
2265
2266 /*
2267  * Process RFCOMM UIH frame (data)
2268  */
2269
2270 static int
2271 ng_btsocket_rfcomm_receive_uih(ng_btsocket_rfcomm_session_p s, int dlci,
2272                 int pf, struct mbuf *m0)
2273 {
2274         ng_btsocket_rfcomm_pcb_p        pcb = NULL;
2275         int                             error = 0;
2276
2277         mtx_assert(&s->session_mtx, MA_OWNED);
2278
2279         NG_BTSOCKET_RFCOMM_INFO(
2280 "%s: Got UIH, session state=%d, flags=%#x, mtu=%d, dlci=%d, pf=%d, len=%d\n",
2281                 __func__, s->state, s->flags, s->mtu, dlci, pf,
2282                 m0->m_pkthdr.len);
2283
2284         /* XXX should we do it here? Check for session flow control */
2285         if (s->flags & NG_BTSOCKET_RFCOMM_SESSION_LFC) {
2286                 NG_BTSOCKET_RFCOMM_WARN(
2287 "%s: Got UIH with session flow control asserted, state=%d, flags=%#x\n",
2288                         __func__, s->state, s->flags);
2289                 goto drop;
2290         }
2291
2292         /* Check if we have this dlci */
2293         pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci);
2294         if (pcb == NULL) {
2295                 NG_BTSOCKET_RFCOMM_WARN(
2296 "%s: Got UIH for non-existing dlci=%d\n", __func__, dlci);
2297                 error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_DM,dlci);
2298                 goto drop;
2299         }
2300
2301         mtx_lock(&pcb->pcb_mtx);
2302
2303         /* Check dlci state */  
2304         if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTED) {
2305                 NG_BTSOCKET_RFCOMM_WARN(
2306 "%s: Got UIH for dlci=%d in invalid state=%d, flags=%#x\n",
2307                         __func__, dlci, pcb->state, pcb->flags);
2308                 error = EINVAL;
2309                 goto drop1;
2310         }
2311
2312         /* Check dlci flow control */
2313         if (((pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) && pcb->rx_cred <= 0) ||
2314              (pcb->lmodem & RFCOMM_MODEM_FC)) {
2315                 NG_BTSOCKET_RFCOMM_ERR(
2316 "%s: Got UIH for dlci=%d with asserted flow control, state=%d, " \
2317 "flags=%#x, rx_cred=%d, lmodem=%#x\n",
2318                         __func__, dlci, pcb->state, pcb->flags,
2319                         pcb->rx_cred, pcb->lmodem);
2320                 goto drop1;
2321         }
2322
2323         /* Did we get any credits? */
2324         if ((pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) && pf) {
2325                 NG_BTSOCKET_RFCOMM_INFO(
2326 "%s: Got %d more credits for dlci=%d, state=%d, flags=%#x, " \
2327 "rx_cred=%d, tx_cred=%d\n",
2328                         __func__, *mtod(m0, u_int8_t *), dlci, pcb->state, 
2329                         pcb->flags, pcb->rx_cred, pcb->tx_cred);
2330
2331                 pcb->tx_cred += *mtod(m0, u_int8_t *);
2332                 m_adj(m0, 1);
2333
2334                 /* Send more from the DLC. XXX check for errors? */
2335                 ng_btsocket_rfcomm_pcb_send(pcb, ALOT);
2336         } 
2337
2338         /* OK the of the rest of the mbuf is the data */
2339         if (m0->m_pkthdr.len > 0) {
2340                 /* If we are using credit flow control decrease rx_cred here */
2341                 if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) {
2342                         /* Give remote peer more credits (if needed) */
2343                         if (-- pcb->rx_cred <= RFCOMM_MAX_CREDITS / 2)
2344                                 ng_btsocket_rfcomm_send_credits(pcb);
2345                         else
2346                                 NG_BTSOCKET_RFCOMM_INFO(
2347 "%s: Remote side still has credits, dlci=%d, state=%d, flags=%#x, " \
2348 "rx_cred=%d, tx_cred=%d\n",             __func__, dlci, pcb->state, pcb->flags,
2349                                         pcb->rx_cred, pcb->tx_cred);
2350                 }
2351                 
2352                 /* Check packet against mtu on dlci */
2353                 if (m0->m_pkthdr.len > pcb->mtu) {
2354                         NG_BTSOCKET_RFCOMM_ERR(
2355 "%s: Got oversized UIH for dlci=%d, state=%d, flags=%#x, mtu=%d, len=%d\n",
2356                                 __func__, dlci, pcb->state, pcb->flags,
2357                                 pcb->mtu, m0->m_pkthdr.len);
2358
2359                         error = EMSGSIZE;
2360                 } else if (m0->m_pkthdr.len > sbspace(&pcb->so->so_rcv)) {
2361  
2362                         /*
2363                          * This is really bad. Receive queue on socket does
2364                          * not have enough space for the packet. We do not
2365                          * have any other choice but drop the packet. 
2366                          */
2367  
2368                         NG_BTSOCKET_RFCOMM_ERR(
2369 "%s: Not enough space in socket receive queue. Dropping UIH for dlci=%d, " \
2370 "state=%d, flags=%#x, len=%d, space=%ld\n",
2371                                 __func__, dlci, pcb->state, pcb->flags,
2372                                 m0->m_pkthdr.len, sbspace(&pcb->so->so_rcv));
2373
2374                         error = ENOBUFS;
2375                 } else {
2376                         /* Append packet to the socket receive queue */
2377                         sbappend(&pcb->so->so_rcv, m0, 0);
2378                         m0 = NULL;
2379
2380                         sorwakeup(pcb->so);
2381                 }
2382         }
2383 drop1:
2384         mtx_unlock(&pcb->pcb_mtx);
2385 drop:
2386         NG_FREE_M(m0); /* checks for != NULL */
2387
2388         return (error);
2389 } /* ng_btsocket_rfcomm_receive_uih */
2390
2391 /*
2392  * Process RFCOMM MCC command (Multiplexor)
2393  * 
2394  * From TS 07.10 spec
2395  *
2396  * "5.4.3.1 Information Data
2397  * 
2398  *  ...The frames (UIH) sent by the initiating station have the C/R bit set 
2399  *  to 1 and those sent by the responding station have the C/R bit set to 0..."
2400  *
2401  * "5.4.6.2 Operating procedures
2402  *
2403  *  Messages always exist in pairs; a command message and a corresponding 
2404  *  response message. If the C/R bit is set to 1 the message is a command, 
2405  *  if it is set to 0 the message is a response...
2406  *
2407  *  ...
2408  * 
2409  *  NOTE: Notice that when UIH frames are used to convey information on DLCI 0
2410  *  there are at least two different fields that contain a C/R bit, and the 
2411  *  bits are set of different form. The C/R bit in the Type field shall be set
2412  *  as it is stated above, while the C/R bit in the Address field (see subclause
2413  *  5.2.1.2) shall be set as it is described in subclause 5.4.3.1."
2414  */
2415
2416 static int
2417 ng_btsocket_rfcomm_receive_mcc(ng_btsocket_rfcomm_session_p s, struct mbuf *m0)
2418 {
2419         struct rfcomm_mcc_hdr   *hdr = NULL;
2420         u_int8_t                 cr, type, length;
2421
2422         mtx_assert(&s->session_mtx, MA_OWNED);
2423
2424         /*
2425          * We can access data directly in the first mbuf, because we have
2426          * m_pullup()'ed mbuf chain in ng_btsocket_rfcomm_receive_frame().
2427          * All MCC commands should fit into single mbuf (except probably TEST).
2428          */
2429
2430         hdr = mtod(m0, struct rfcomm_mcc_hdr *);
2431         cr = RFCOMM_CR(hdr->type);
2432         type = RFCOMM_MCC_TYPE(hdr->type);
2433         length = RFCOMM_MCC_LENGTH(hdr->length);
2434
2435         /* Check MCC frame length */
2436         if (sizeof(*hdr) + length != m0->m_pkthdr.len) {
2437                 NG_BTSOCKET_RFCOMM_ERR(
2438 "%s: Invalid MCC frame length=%d, len=%d\n",
2439                         __func__, length, m0->m_pkthdr.len);
2440                 NG_FREE_M(m0);
2441
2442                 return (EMSGSIZE);
2443         }
2444
2445         switch (type) {
2446         case RFCOMM_MCC_TEST:
2447                 return (ng_btsocket_rfcomm_receive_test(s, m0));
2448                 /* NOT REACHED */
2449
2450         case RFCOMM_MCC_FCON:
2451         case RFCOMM_MCC_FCOFF:
2452                 return (ng_btsocket_rfcomm_receive_fc(s, m0));
2453                 /* NOT REACHED */
2454
2455         case RFCOMM_MCC_MSC:
2456                 return (ng_btsocket_rfcomm_receive_msc(s, m0));
2457                 /* NOT REACHED */
2458
2459         case RFCOMM_MCC_RPN:
2460                 return (ng_btsocket_rfcomm_receive_rpn(s, m0));
2461                 /* NOT REACHED */
2462
2463         case RFCOMM_MCC_RLS:
2464                 return (ng_btsocket_rfcomm_receive_rls(s, m0));
2465                 /* NOT REACHED */
2466
2467         case RFCOMM_MCC_PN:
2468                 return (ng_btsocket_rfcomm_receive_pn(s, m0));
2469                 /* NOT REACHED */
2470
2471         case RFCOMM_MCC_NSC:
2472                 NG_BTSOCKET_RFCOMM_ERR(
2473 "%s: Got MCC NSC, type=%#x, cr=%d, length=%d, session state=%d, flags=%#x, " \
2474 "mtu=%d, len=%d\n",     __func__, RFCOMM_MCC_TYPE(*((u_int8_t *)(hdr + 1))), cr,
2475                          length, s->state, s->flags, s->mtu, m0->m_pkthdr.len);
2476                 NG_FREE_M(m0);
2477                 break;
2478
2479         default:
2480                 NG_BTSOCKET_RFCOMM_ERR(
2481 "%s: Got unknown MCC, type=%#x, cr=%d, length=%d, session state=%d, " \
2482 "flags=%#x, mtu=%d, len=%d\n",
2483                         __func__, type, cr, length, s->state, s->flags,
2484                         s->mtu, m0->m_pkthdr.len);
2485
2486                 /* Reuse mbuf to send NSC */
2487                 hdr = mtod(m0, struct rfcomm_mcc_hdr *);
2488                 m0->m_pkthdr.len = m0->m_len = sizeof(*hdr);
2489
2490                 /* Create MCC NSC header */
2491                 hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_NSC);
2492                 hdr->length = RFCOMM_MKLEN8(1);
2493
2494                 /* Put back MCC command type we did not like */
2495                 m0->m_data[m0->m_len] = RFCOMM_MKMCC_TYPE(cr, type);
2496                 m0->m_pkthdr.len ++;
2497                 m0->m_len ++;
2498
2499                 /* Send UIH frame */
2500                 return (ng_btsocket_rfcomm_send_uih(s,
2501                                 RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0));
2502                 /* NOT REACHED */
2503         }
2504
2505         return (0);
2506 } /* ng_btsocket_rfcomm_receive_mcc */
2507
2508 /*
2509  * Receive RFCOMM TEST MCC command
2510  */
2511
2512 static int
2513 ng_btsocket_rfcomm_receive_test(ng_btsocket_rfcomm_session_p s, struct mbuf *m0)
2514 {
2515         struct rfcomm_mcc_hdr   *hdr = mtod(m0, struct rfcomm_mcc_hdr *);
2516         int                      error = 0;
2517
2518         mtx_assert(&s->session_mtx, MA_OWNED);
2519
2520         NG_BTSOCKET_RFCOMM_INFO(
2521 "%s: Got MCC TEST, cr=%d, length=%d, session state=%d, flags=%#x, mtu=%d, " \
2522 "len=%d\n",     __func__, RFCOMM_CR(hdr->type), RFCOMM_MCC_LENGTH(hdr->length),
2523                 s->state, s->flags, s->mtu, m0->m_pkthdr.len);
2524
2525         if (RFCOMM_CR(hdr->type)) {
2526                 hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_TEST);
2527                 error = ng_btsocket_rfcomm_send_uih(s,
2528                                 RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0);
2529         } else
2530                 NG_FREE_M(m0); /* XXX ignore response */
2531
2532         return (error);
2533 } /* ng_btsocket_rfcomm_receive_test */
2534
2535 /*
2536  * Receive RFCOMM FCON/FCOFF MCC command
2537  */
2538
2539 static int
2540 ng_btsocket_rfcomm_receive_fc(ng_btsocket_rfcomm_session_p s, struct mbuf *m0)
2541 {
2542         struct rfcomm_mcc_hdr   *hdr = mtod(m0, struct rfcomm_mcc_hdr *);
2543         u_int8_t                 type = RFCOMM_MCC_TYPE(hdr->type);
2544         int                      error = 0;
2545
2546         mtx_assert(&s->session_mtx, MA_OWNED);
2547
2548         /*
2549          * Turn ON/OFF aggregate flow on the entire session. When remote peer 
2550          * asserted flow control no transmission shall occur except on dlci 0
2551          * (control channel).
2552          */
2553
2554         NG_BTSOCKET_RFCOMM_INFO(
2555 "%s: Got MCC FC%s, cr=%d, length=%d, session state=%d, flags=%#x, mtu=%d, " \
2556 "len=%d\n",     __func__, (type == RFCOMM_MCC_FCON)? "ON" : "OFF",
2557                 RFCOMM_CR(hdr->type), RFCOMM_MCC_LENGTH(hdr->length),
2558                 s->state, s->flags, s->mtu, m0->m_pkthdr.len);
2559
2560         if (RFCOMM_CR(hdr->type)) {
2561                 if (type == RFCOMM_MCC_FCON)
2562                         s->flags &= ~NG_BTSOCKET_RFCOMM_SESSION_RFC;
2563                 else
2564                         s->flags |= NG_BTSOCKET_RFCOMM_SESSION_RFC;
2565
2566                 hdr->type = RFCOMM_MKMCC_TYPE(0, type);
2567                 error = ng_btsocket_rfcomm_send_uih(s,
2568                                 RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0);
2569         } else
2570                 NG_FREE_M(m0); /* XXX ignore response */
2571
2572         return (error);
2573 } /* ng_btsocket_rfcomm_receive_fc  */
2574
2575 /*
2576  * Receive RFCOMM MSC MCC command
2577  */
2578
2579 static int
2580 ng_btsocket_rfcomm_receive_msc(ng_btsocket_rfcomm_session_p s, struct mbuf *m0)
2581 {
2582         struct rfcomm_mcc_hdr           *hdr = mtod(m0, struct rfcomm_mcc_hdr*);
2583         struct rfcomm_mcc_msc           *msc = (struct rfcomm_mcc_msc *)(hdr+1);
2584         ng_btsocket_rfcomm_pcb_t        *pcb = NULL;
2585         int                              error = 0;
2586
2587         mtx_assert(&s->session_mtx, MA_OWNED);
2588
2589         NG_BTSOCKET_RFCOMM_INFO(
2590 "%s: Got MCC MSC, dlci=%d, cr=%d, length=%d, session state=%d, flags=%#x, " \
2591 "mtu=%d, len=%d\n",
2592                 __func__,  RFCOMM_DLCI(msc->address), RFCOMM_CR(hdr->type),
2593                 RFCOMM_MCC_LENGTH(hdr->length), s->state, s->flags,
2594                 s->mtu, m0->m_pkthdr.len);
2595
2596         if (RFCOMM_CR(hdr->type)) {
2597                 pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, RFCOMM_DLCI(msc->address));
2598                 if (pcb == NULL) {
2599                         NG_BTSOCKET_RFCOMM_WARN(
2600 "%s: Got MSC command for non-existing dlci=%d\n",
2601                                 __func__, RFCOMM_DLCI(msc->address));
2602                         NG_FREE_M(m0);
2603
2604                         return (ENOENT);
2605                 }
2606
2607                 mtx_lock(&pcb->pcb_mtx);
2608
2609                 if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTING &&
2610                     pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTED) {
2611                         NG_BTSOCKET_RFCOMM_WARN(
2612 "%s: Got MSC on dlci=%d in invalid state=%d\n",
2613                                 __func__, RFCOMM_DLCI(msc->address),
2614                                 pcb->state);
2615
2616                         mtx_unlock(&pcb->pcb_mtx);
2617                         NG_FREE_M(m0);
2618
2619                         return (EINVAL);
2620                 }
2621
2622                 pcb->rmodem = msc->modem; /* Update remote port signals */
2623
2624                 hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_MSC);
2625                 error = ng_btsocket_rfcomm_send_uih(s,
2626                                 RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0);
2627
2628 #if 0 /* YYY */
2629                 /* Send more data from DLC. XXX check for errors? */
2630                 if (!(pcb->rmodem & RFCOMM_MODEM_FC) &&
2631                     !(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC))
2632                         ng_btsocket_rfcomm_pcb_send(pcb, ALOT);
2633 #endif /* YYY */
2634
2635                 mtx_unlock(&pcb->pcb_mtx);
2636         } else
2637                 NG_FREE_M(m0); /* XXX ignore response */
2638
2639         return (error);
2640 } /* ng_btsocket_rfcomm_receive_msc */
2641
2642 /*
2643  * Receive RFCOMM RPN MCC command
2644  * XXX FIXME do we need htole16/le16toh for RPN param_mask?
2645  */
2646
2647 static int
2648 ng_btsocket_rfcomm_receive_rpn(ng_btsocket_rfcomm_session_p s, struct mbuf *m0)
2649 {
2650         struct rfcomm_mcc_hdr   *hdr = mtod(m0, struct rfcomm_mcc_hdr *);
2651         struct rfcomm_mcc_rpn   *rpn = (struct rfcomm_mcc_rpn *)(hdr + 1);
2652         int                      error = 0;
2653         u_int16_t                param_mask;
2654         u_int8_t                 bit_rate, data_bits, stop_bits, parity,
2655                                  flow_control, xon_char, xoff_char;
2656
2657         mtx_assert(&s->session_mtx, MA_OWNED);
2658
2659         NG_BTSOCKET_RFCOMM_INFO(
2660 "%s: Got MCC RPN, dlci=%d, cr=%d, length=%d, session state=%d, flags=%#x, " \
2661 "mtu=%d, len=%d\n",
2662                 __func__, RFCOMM_DLCI(rpn->dlci), RFCOMM_CR(hdr->type),
2663                 RFCOMM_MCC_LENGTH(hdr->length), s->state, s->flags,
2664                 s->mtu, m0->m_pkthdr.len);
2665
2666         if (RFCOMM_CR(hdr->type)) {
2667                 param_mask = RFCOMM_RPN_PM_ALL;
2668
2669                 if (RFCOMM_MCC_LENGTH(hdr->length) == 1) {
2670                         /* Request - return default setting */
2671                         bit_rate = RFCOMM_RPN_BR_115200;
2672                         data_bits = RFCOMM_RPN_DATA_8;
2673                         stop_bits = RFCOMM_RPN_STOP_1;
2674                         parity = RFCOMM_RPN_PARITY_NONE;
2675                         flow_control = RFCOMM_RPN_FLOW_NONE;
2676                         xon_char = RFCOMM_RPN_XON_CHAR;
2677                         xoff_char = RFCOMM_RPN_XOFF_CHAR;
2678                 } else {
2679                         /*
2680                          * Ignore/accept bit_rate, 8 bits, 1 stop bit, no 
2681                          * parity, no flow control lines, default XON/XOFF 
2682                          * chars.
2683                          */
2684
2685                         bit_rate = rpn->bit_rate;
2686                         rpn->param_mask = le16toh(rpn->param_mask); /* XXX */
2687
2688                         data_bits = RFCOMM_RPN_DATA_BITS(rpn->line_settings);
2689                         if (rpn->param_mask & RFCOMM_RPN_PM_DATA &&
2690                             data_bits != RFCOMM_RPN_DATA_8) {
2691                                 data_bits = RFCOMM_RPN_DATA_8;
2692                                 param_mask ^= RFCOMM_RPN_PM_DATA;
2693                         }
2694
2695                         stop_bits = RFCOMM_RPN_STOP_BITS(rpn->line_settings);
2696                         if (rpn->param_mask & RFCOMM_RPN_PM_STOP &&
2697                             stop_bits != RFCOMM_RPN_STOP_1) {
2698                                 stop_bits = RFCOMM_RPN_STOP_1;
2699                                 param_mask ^= RFCOMM_RPN_PM_STOP;
2700                         }
2701
2702                         parity = RFCOMM_RPN_PARITY(rpn->line_settings);
2703                         if (rpn->param_mask & RFCOMM_RPN_PM_PARITY &&
2704                             parity != RFCOMM_RPN_PARITY_NONE) {
2705                                 parity = RFCOMM_RPN_PARITY_NONE;
2706                                 param_mask ^= RFCOMM_RPN_PM_PARITY;
2707                         }
2708
2709                         flow_control = rpn->flow_control;
2710                         if (rpn->param_mask & RFCOMM_RPN_PM_FLOW &&
2711                             flow_control != RFCOMM_RPN_FLOW_NONE) {
2712                                 flow_control = RFCOMM_RPN_FLOW_NONE;
2713                                 param_mask ^= RFCOMM_RPN_PM_FLOW;
2714                         }
2715
2716                         xon_char = rpn->xon_char;
2717                         if (rpn->param_mask & RFCOMM_RPN_PM_XON &&
2718                             xon_char != RFCOMM_RPN_XON_CHAR) {
2719                                 xon_char = RFCOMM_RPN_XON_CHAR;
2720                                 param_mask ^= RFCOMM_RPN_PM_XON;
2721                         }
2722
2723                         xoff_char = rpn->xoff_char;
2724                         if (rpn->param_mask & RFCOMM_RPN_PM_XOFF &&
2725                             xoff_char != RFCOMM_RPN_XOFF_CHAR) {
2726                                 xoff_char = RFCOMM_RPN_XOFF_CHAR;
2727                                 param_mask ^= RFCOMM_RPN_PM_XOFF;
2728                         }
2729                 }
2730
2731                 rpn->bit_rate = bit_rate;
2732                 rpn->line_settings = RFCOMM_MKRPN_LINE_SETTINGS(data_bits, 
2733                                                 stop_bits, parity);
2734                 rpn->flow_control = flow_control;
2735                 rpn->xon_char = xon_char;
2736                 rpn->xoff_char = xoff_char;
2737                 rpn->param_mask = htole16(param_mask); /* XXX */
2738
2739                 m0->m_pkthdr.len = m0->m_len = sizeof(*hdr) + sizeof(*rpn);
2740
2741                 hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_RPN);
2742                 error = ng_btsocket_rfcomm_send_uih(s,
2743                                 RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0);
2744         } else
2745                 NG_FREE_M(m0); /* XXX ignore response */
2746
2747         return (error);
2748 } /* ng_btsocket_rfcomm_receive_rpn */
2749
2750 /*
2751  * Receive RFCOMM RLS MCC command
2752  */
2753
2754 static int
2755 ng_btsocket_rfcomm_receive_rls(ng_btsocket_rfcomm_session_p s, struct mbuf *m0)
2756 {
2757         struct rfcomm_mcc_hdr   *hdr = mtod(m0, struct rfcomm_mcc_hdr *);
2758         struct rfcomm_mcc_rls   *rls = (struct rfcomm_mcc_rls *)(hdr + 1);
2759         int                      error = 0;
2760
2761         mtx_assert(&s->session_mtx, MA_OWNED);
2762
2763         /*
2764          * XXX FIXME Do we have to do anything else here? Remote peer tries to 
2765          * tell us something about DLCI. Just report what we have received and
2766          * return back received values as required by TS 07.10 spec.
2767          */
2768
2769         NG_BTSOCKET_RFCOMM_INFO(
2770 "%s: Got MCC RLS, dlci=%d, status=%#x, cr=%d, length=%d, session state=%d, " \
2771 "flags=%#x, mtu=%d, len=%d\n",
2772                 __func__, RFCOMM_DLCI(rls->address), rls->status,
2773                 RFCOMM_CR(hdr->type), RFCOMM_MCC_LENGTH(hdr->length),
2774                 s->state, s->flags, s->mtu, m0->m_pkthdr.len);
2775
2776         if (RFCOMM_CR(hdr->type)) {
2777                 if (rls->status & 0x1)
2778                         NG_BTSOCKET_RFCOMM_ERR(
2779 "%s: Got RLS dlci=%d, error=%#x\n", __func__, RFCOMM_DLCI(rls->address),
2780                                 rls->status >> 1);
2781
2782                 hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_RLS);
2783                 error = ng_btsocket_rfcomm_send_uih(s,
2784                                 RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0);
2785         } else
2786                 NG_FREE_M(m0); /* XXX ignore responses */
2787
2788         return (error);
2789 } /* ng_btsocket_rfcomm_receive_rls */
2790
2791 /*
2792  * Receive RFCOMM PN MCC command
2793  */
2794
2795 static int
2796 ng_btsocket_rfcomm_receive_pn(ng_btsocket_rfcomm_session_p s, struct mbuf *m0)
2797 {
2798         struct rfcomm_mcc_hdr           *hdr = mtod(m0, struct rfcomm_mcc_hdr*);
2799         struct rfcomm_mcc_pn            *pn = (struct rfcomm_mcc_pn *)(hdr+1);
2800         ng_btsocket_rfcomm_pcb_t        *pcb = NULL;
2801         int                              error = 0;
2802
2803         mtx_assert(&s->session_mtx, MA_OWNED);
2804
2805         NG_BTSOCKET_RFCOMM_INFO(
2806 "%s: Got MCC PN, dlci=%d, cr=%d, length=%d, flow_control=%#x, priority=%d, " \
2807 "ack_timer=%d, mtu=%d, max_retrans=%d, credits=%d, session state=%d, " \
2808 "flags=%#x, session mtu=%d, len=%d\n",
2809                 __func__, pn->dlci, RFCOMM_CR(hdr->type),
2810                 RFCOMM_MCC_LENGTH(hdr->length), pn->flow_control, pn->priority,
2811                 pn->ack_timer, le16toh(pn->mtu), pn->max_retrans, pn->credits,
2812                 s->state, s->flags, s->mtu, m0->m_pkthdr.len);
2813
2814         if (pn->dlci == 0) {
2815                 NG_BTSOCKET_RFCOMM_ERR("%s: Zero dlci in MCC PN\n", __func__);
2816                 NG_FREE_M(m0);
2817
2818                 return (EINVAL);
2819         }
2820
2821         /* Check if we have this dlci */
2822         pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, pn->dlci);
2823         if (pcb != NULL) {
2824                 mtx_lock(&pcb->pcb_mtx);
2825
2826                 if (RFCOMM_CR(hdr->type)) {
2827                         /* PN Request */
2828                         ng_btsocket_rfcomm_set_pn(pcb, 1, pn->flow_control,
2829                                 pn->credits, pn->mtu);
2830
2831                         if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) {
2832                                 pn->flow_control = 0xe0;
2833                                 pn->credits = RFCOMM_DEFAULT_CREDITS;
2834                         } else {
2835                                 pn->flow_control = 0;
2836                                 pn->credits = 0;
2837                         }
2838
2839                         hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_PN);
2840                         error = ng_btsocket_rfcomm_send_uih(s, 
2841                                         RFCOMM_MKADDRESS(INITIATOR(s), 0),
2842                                         0, 0, m0);
2843                 } else {
2844                         /* PN Response - proceed with SABM. Timeout still set */
2845                         if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONFIGURING) {
2846                                 ng_btsocket_rfcomm_set_pn(pcb, 0,
2847                                         pn->flow_control, pn->credits, pn->mtu);
2848
2849                                 pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTING;
2850                                 error = ng_btsocket_rfcomm_send_command(s,
2851                                                 RFCOMM_FRAME_SABM, pn->dlci);
2852                         } else
2853                                 NG_BTSOCKET_RFCOMM_WARN(
2854 "%s: Got PN response for dlci=%d in invalid state=%d\n",
2855                                         __func__, pn->dlci, pcb->state);
2856
2857                         NG_FREE_M(m0);
2858                 }
2859
2860                 mtx_unlock(&pcb->pcb_mtx);
2861         } else if (RFCOMM_CR(hdr->type)) {
2862                 /* PN request to non-existing dlci - incoming connection */
2863                 pcb = ng_btsocket_rfcomm_connect_ind(s,
2864                                 RFCOMM_SRVCHANNEL(pn->dlci));
2865                 if (pcb != NULL) {
2866                         mtx_lock(&pcb->pcb_mtx);
2867
2868                         pcb->dlci = pn->dlci;
2869
2870                         ng_btsocket_rfcomm_set_pn(pcb, 1, pn->flow_control,
2871                                 pn->credits, pn->mtu);
2872
2873                         if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) {
2874                                 pn->flow_control = 0xe0;
2875                                 pn->credits = RFCOMM_DEFAULT_CREDITS;
2876                         } else {
2877                                 pn->flow_control = 0;
2878                                 pn->credits = 0;
2879                         }
2880
2881                         hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_PN);
2882                         error = ng_btsocket_rfcomm_send_uih(s, 
2883                                         RFCOMM_MKADDRESS(INITIATOR(s), 0),
2884                                         0, 0, m0);
2885
2886                         if (error == 0) {
2887                                 ng_btsocket_rfcomm_timeout(pcb);
2888                                 pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTING;
2889                                 soisconnecting(pcb->so);
2890                         } else
2891                                 ng_btsocket_rfcomm_pcb_kill(pcb, error);
2892
2893                         mtx_unlock(&pcb->pcb_mtx);
2894                 } else {
2895                         /* Nobody is listen()ing on this channel */
2896                         error = ng_btsocket_rfcomm_send_command(s,
2897                                         RFCOMM_FRAME_DM, pn->dlci);
2898                         NG_FREE_M(m0);
2899                 }
2900         } else
2901                 NG_FREE_M(m0); /* XXX ignore response to non-existing dlci */
2902
2903         return (error);
2904 } /* ng_btsocket_rfcomm_receive_pn */
2905
2906 /*
2907  * Set PN parameters for dlci. Caller must hold pcb->pcb_mtx.
2908  * 
2909  * From Bluetooth spec.
2910  * 
2911  * "... The CL1 - CL4 field is completely redefined. (In TS07.10 this defines 
2912  *  the convergence layer to use, which is not applicable to RFCOMM. In RFCOMM,
2913  *  in Bluetooth versions up to 1.0B, this field was forced to 0).
2914  *
2915  *  In the PN request sent prior to a DLC establishment, this field must contain
2916  *  the value 15 (0xF), indicating support of credit based flow control in the 
2917  *  sender. See Table 5.3 below. If the PN response contains any other value 
2918  *  than 14 (0xE) in this field, it is inferred that the peer RFCOMM entity is 
2919  *  not supporting the credit based flow control feature. (This is only possible
2920  *  if the peer RFCOMM implementation is only conforming to Bluetooth version 
2921  *  1.0B.) If a PN request is sent on an already open DLC, then this field must
2922  *  contain the value zero; it is not possible to set initial credits  more 
2923  *  than once per DLC activation. A responding implementation must set this 
2924  *  field in the PN response to 14 (0xE), if (and only if) the value in the PN 
2925  *  request was 15..."
2926  */
2927
2928 static void
2929 ng_btsocket_rfcomm_set_pn(ng_btsocket_rfcomm_pcb_p pcb, u_int8_t cr,
2930                 u_int8_t flow_control, u_int8_t credits, u_int16_t mtu)
2931 {
2932         mtx_assert(&pcb->pcb_mtx, MA_OWNED);
2933
2934         pcb->mtu = le16toh(mtu);
2935
2936         if (cr) {
2937                 if (flow_control == 0xf0) {
2938                         pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_CFC;
2939                         pcb->tx_cred = credits;
2940                 } else {
2941                         pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_CFC;
2942                         pcb->tx_cred = 0;
2943                 }
2944         } else {
2945                 if (flow_control == 0xe0) {
2946                         pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_CFC;
2947                         pcb->tx_cred = credits;
2948                 } else {
2949                         pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_CFC;
2950                         pcb->tx_cred = 0;
2951                 }
2952         }
2953
2954         NG_BTSOCKET_RFCOMM_INFO(
2955 "%s: cr=%d, dlci=%d, state=%d, flags=%#x, mtu=%d, rx_cred=%d, tx_cred=%d\n",
2956                 __func__, cr, pcb->dlci, pcb->state, pcb->flags, pcb->mtu,
2957                 pcb->rx_cred, pcb->tx_cred);
2958 } /* ng_btsocket_rfcomm_set_pn */
2959
2960 /*
2961  * Send RFCOMM SABM/DISC/UA/DM frames. Caller must hold s->session_mtx
2962  */
2963
2964 static int
2965 ng_btsocket_rfcomm_send_command(ng_btsocket_rfcomm_session_p s,
2966                 u_int8_t type, u_int8_t dlci)
2967 {
2968         struct rfcomm_cmd_hdr   *hdr = NULL;
2969         struct mbuf             *m = NULL;
2970         int                      cr;
2971
2972         mtx_assert(&s->session_mtx, MA_OWNED);
2973
2974         NG_BTSOCKET_RFCOMM_INFO(
2975 "%s: Sending command type %#x, session state=%d, flags=%#x, mtu=%d, dlci=%d\n",
2976                 __func__, type, s->state, s->flags, s->mtu, dlci);
2977
2978         switch (type) {
2979         case RFCOMM_FRAME_SABM:
2980         case RFCOMM_FRAME_DISC:
2981                 cr = INITIATOR(s);
2982                 break;
2983
2984         case RFCOMM_FRAME_UA:
2985         case RFCOMM_FRAME_DM:
2986                 cr = !INITIATOR(s);
2987                 break;
2988
2989         default:
2990                 panic("%s: Invalid frame type=%#x\n", __func__, type);
2991                 return (EINVAL);
2992                 /* NOT REACHED */
2993         }
2994
2995         MGETHDR(m, M_NOWAIT, MT_DATA);
2996         if (m == NULL)
2997                 return (ENOBUFS);
2998
2999         m->m_pkthdr.len = m->m_len = sizeof(*hdr);
3000
3001         hdr = mtod(m, struct rfcomm_cmd_hdr *);
3002         hdr->address = RFCOMM_MKADDRESS(cr, dlci);
3003         hdr->control = RFCOMM_MKCONTROL(type, 1);
3004         hdr->length = RFCOMM_MKLEN8(0);
3005         hdr->fcs = ng_btsocket_rfcomm_fcs3((u_int8_t *) hdr);
3006
3007         NG_BT_MBUFQ_ENQUEUE(&s->outq, m);
3008
3009         return (0);
3010 } /* ng_btsocket_rfcomm_send_command */
3011
3012 /*
3013  * Send RFCOMM UIH frame. Caller must hold s->session_mtx
3014  */
3015
3016 static int
3017 ng_btsocket_rfcomm_send_uih(ng_btsocket_rfcomm_session_p s, u_int8_t address,
3018                 u_int8_t pf, u_int8_t credits, struct mbuf *data)
3019 {
3020         struct rfcomm_frame_hdr *hdr = NULL;
3021         struct mbuf             *m = NULL, *mcrc = NULL;
3022         u_int16_t                length;
3023
3024         mtx_assert(&s->session_mtx, MA_OWNED);
3025
3026         MGETHDR(m, M_NOWAIT, MT_DATA);
3027         if (m == NULL) {
3028                 NG_FREE_M(data);
3029                 return (ENOBUFS);
3030         }
3031         m->m_pkthdr.len = m->m_len = sizeof(*hdr);
3032
3033         MGET(mcrc, M_NOWAIT, MT_DATA);
3034         if (mcrc == NULL) {
3035                 NG_FREE_M(data);
3036                 return (ENOBUFS);
3037         }
3038         mcrc->m_len = 1;
3039
3040         /* Fill UIH frame header */
3041         hdr = mtod(m, struct rfcomm_frame_hdr *);
3042         hdr->address = address;
3043         hdr->control = RFCOMM_MKCONTROL(RFCOMM_FRAME_UIH, pf);
3044
3045         /* Calculate FCS */
3046         mcrc->m_data[0] = ng_btsocket_rfcomm_fcs2((u_int8_t *) hdr);
3047
3048         /* Put length back */
3049         length = (data != NULL)? data->m_pkthdr.len : 0;
3050         if (length > 127) {
3051                 u_int16_t       l = htole16(RFCOMM_MKLEN16(length));
3052
3053                 bcopy(&l, &hdr->length, sizeof(l));
3054                 m->m_pkthdr.len ++;
3055                 m->m_len ++;
3056         } else
3057                 hdr->length = RFCOMM_MKLEN8(length);
3058
3059         if (pf) {
3060                 m->m_data[m->m_len] = credits;
3061                 m->m_pkthdr.len ++;
3062                 m->m_len ++;
3063         }
3064
3065         /* Add payload */
3066         if (data != NULL) {
3067                 m_cat(m, data);
3068                 m->m_pkthdr.len += length;
3069         }
3070
3071         /* Put FCS back */
3072         m_cat(m, mcrc);
3073         m->m_pkthdr.len ++;
3074
3075         NG_BTSOCKET_RFCOMM_INFO(
3076 "%s: Sending UIH state=%d, flags=%#x, address=%d, length=%d, pf=%d, " \
3077 "credits=%d, len=%d\n",
3078                 __func__, s->state, s->flags, address, length, pf, credits,
3079                 m->m_pkthdr.len);
3080
3081         NG_BT_MBUFQ_ENQUEUE(&s->outq, m);
3082
3083         return (0);
3084 } /* ng_btsocket_rfcomm_send_uih */
3085
3086 /*
3087  * Send MSC request. Caller must hold pcb->pcb_mtx and pcb->session->session_mtx
3088  */
3089
3090 static int
3091 ng_btsocket_rfcomm_send_msc(ng_btsocket_rfcomm_pcb_p pcb)
3092 {
3093         struct mbuf             *m = NULL;
3094         struct rfcomm_mcc_hdr   *hdr = NULL;
3095         struct rfcomm_mcc_msc   *msc = NULL;
3096
3097         mtx_assert(&pcb->session->session_mtx, MA_OWNED);
3098         mtx_assert(&pcb->pcb_mtx, MA_OWNED);
3099
3100         MGETHDR(m, M_NOWAIT, MT_DATA);
3101         if (m == NULL)
3102                 return (ENOBUFS);
3103
3104         m->m_pkthdr.len = m->m_len = sizeof(*hdr) + sizeof(*msc);
3105
3106         hdr = mtod(m, struct rfcomm_mcc_hdr *);
3107         msc = (struct rfcomm_mcc_msc *)(hdr + 1);
3108
3109         hdr->type = RFCOMM_MKMCC_TYPE(1, RFCOMM_MCC_MSC);
3110         hdr->length = RFCOMM_MKLEN8(sizeof(*msc));
3111
3112         msc->address = RFCOMM_MKADDRESS(1, pcb->dlci);
3113         msc->modem = pcb->lmodem;
3114
3115         NG_BTSOCKET_RFCOMM_INFO(
3116 "%s: Sending MSC dlci=%d, state=%d, flags=%#x, address=%d, modem=%#x\n",
3117                 __func__, pcb->dlci, pcb->state, pcb->flags, msc->address,
3118                 msc->modem);
3119
3120         return (ng_btsocket_rfcomm_send_uih(pcb->session,
3121                         RFCOMM_MKADDRESS(INITIATOR(pcb->session), 0), 0, 0, m));
3122 } /* ng_btsocket_rfcomm_send_msc */
3123
3124 /*
3125  * Send PN request. Caller must hold pcb->pcb_mtx and pcb->session->session_mtx
3126  */
3127
3128 static int
3129 ng_btsocket_rfcomm_send_pn(ng_btsocket_rfcomm_pcb_p pcb)
3130 {
3131         struct mbuf             *m = NULL;
3132         struct rfcomm_mcc_hdr   *hdr = NULL;
3133         struct rfcomm_mcc_pn    *pn = NULL;
3134
3135         mtx_assert(&pcb->session->session_mtx, MA_OWNED);
3136         mtx_assert(&pcb->pcb_mtx, MA_OWNED);
3137
3138         MGETHDR(m, M_NOWAIT, MT_DATA);
3139         if (m == NULL)
3140                 return (ENOBUFS);
3141
3142         m->m_pkthdr.len = m->m_len = sizeof(*hdr) + sizeof(*pn);
3143
3144         hdr = mtod(m, struct rfcomm_mcc_hdr *);
3145         pn = (struct rfcomm_mcc_pn *)(hdr + 1);
3146
3147         hdr->type = RFCOMM_MKMCC_TYPE(1, RFCOMM_MCC_PN);
3148         hdr->length = RFCOMM_MKLEN8(sizeof(*pn));
3149
3150         pn->dlci = pcb->dlci;
3151
3152         /*
3153          * Set default DLCI priority as described in GSM 07.10
3154          * (ETSI TS 101 369) clause 5.6 page 42
3155          */
3156
3157         pn->priority = (pcb->dlci < 56)? (((pcb->dlci >> 3) << 3) + 7) : 61;
3158         pn->ack_timer = 0;
3159         pn->mtu = htole16(pcb->mtu);
3160         pn->max_retrans = 0;
3161
3162         if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) {
3163                 pn->flow_control = 0xf0;
3164                 pn->credits = pcb->rx_cred;
3165         } else {
3166                 pn->flow_control = 0;
3167                 pn->credits = 0;
3168         }
3169
3170         NG_BTSOCKET_RFCOMM_INFO(
3171 "%s: Sending PN dlci=%d, state=%d, flags=%#x, mtu=%d, flow_control=%#x, " \
3172 "credits=%d\n", __func__, pcb->dlci, pcb->state, pcb->flags, pcb->mtu,
3173                 pn->flow_control, pn->credits);
3174
3175         return (ng_btsocket_rfcomm_send_uih(pcb->session,
3176                         RFCOMM_MKADDRESS(INITIATOR(pcb->session), 0), 0, 0, m));
3177 } /* ng_btsocket_rfcomm_send_pn */
3178
3179 /*
3180  * Calculate and send credits based on available space in receive buffer
3181  */
3182
3183 static int
3184 ng_btsocket_rfcomm_send_credits(ng_btsocket_rfcomm_pcb_p pcb)
3185 {
3186         int             error = 0;
3187         u_int8_t        credits;
3188
3189         mtx_assert(&pcb->pcb_mtx, MA_OWNED);
3190         mtx_assert(&pcb->session->session_mtx, MA_OWNED);
3191
3192         NG_BTSOCKET_RFCOMM_INFO(
3193 "%s: Sending more credits, dlci=%d, state=%d, flags=%#x, mtu=%d, " \
3194 "space=%ld, tx_cred=%d, rx_cred=%d\n",
3195                 __func__, pcb->dlci, pcb->state, pcb->flags, pcb->mtu,
3196                 sbspace(&pcb->so->so_rcv), pcb->tx_cred, pcb->rx_cred);
3197
3198         credits = sbspace(&pcb->so->so_rcv) / pcb->mtu;
3199         if (credits > 0) {
3200                 if (pcb->rx_cred + credits > RFCOMM_MAX_CREDITS)
3201                         credits = RFCOMM_MAX_CREDITS - pcb->rx_cred;
3202
3203                 error = ng_btsocket_rfcomm_send_uih(
3204                                 pcb->session,
3205                                 RFCOMM_MKADDRESS(INITIATOR(pcb->session),
3206                                         pcb->dlci), 1, credits, NULL);
3207                 if (error == 0) {
3208                         pcb->rx_cred += credits;
3209
3210                         NG_BTSOCKET_RFCOMM_INFO(
3211 "%s: Gave remote side %d more credits, dlci=%d, state=%d, flags=%#x, " \
3212 "rx_cred=%d, tx_cred=%d\n",     __func__, credits, pcb->dlci, pcb->state,
3213                                 pcb->flags, pcb->rx_cred, pcb->tx_cred);
3214                 } else
3215                         NG_BTSOCKET_RFCOMM_ERR(
3216 "%s: Could not send credits, error=%d, dlci=%d, state=%d, flags=%#x, " \
3217 "mtu=%d, space=%ld, tx_cred=%d, rx_cred=%d\n",
3218                                 __func__, error, pcb->dlci, pcb->state,
3219                                 pcb->flags, pcb->mtu, sbspace(&pcb->so->so_rcv),
3220                                 pcb->tx_cred, pcb->rx_cred);
3221         }
3222
3223         return (error);
3224 } /* ng_btsocket_rfcomm_send_credits */
3225
3226 /*****************************************************************************
3227  *****************************************************************************
3228  **                              RFCOMM DLCs
3229  *****************************************************************************
3230  *****************************************************************************/
3231
3232 /*
3233  * Send data from socket send buffer
3234  * Caller must hold pcb->pcb_mtx and pcb->session->session_mtx
3235  */
3236
3237 static int
3238 ng_btsocket_rfcomm_pcb_send(ng_btsocket_rfcomm_pcb_p pcb, int limit)
3239 {
3240         struct mbuf     *m = NULL;
3241         int              sent, length, error;
3242
3243         mtx_assert(&pcb->session->session_mtx, MA_OWNED);
3244         mtx_assert(&pcb->pcb_mtx, MA_OWNED);
3245
3246         if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC)
3247                 limit = min(limit, pcb->tx_cred);
3248         else if (!(pcb->rmodem & RFCOMM_MODEM_FC))
3249                 limit = min(limit, RFCOMM_MAX_CREDITS); /* XXX ??? */
3250         else
3251                 limit = 0;
3252
3253         if (limit == 0) {
3254                 NG_BTSOCKET_RFCOMM_INFO(
3255 "%s: Could not send - remote flow control asserted, dlci=%d, flags=%#x, " \
3256 "rmodem=%#x, tx_cred=%d\n",
3257                         __func__, pcb->dlci, pcb->flags, pcb->rmodem,
3258                         pcb->tx_cred);
3259
3260                 return (0);
3261         }
3262
3263         for (error = 0, sent = 0; sent < limit; sent ++) { 
3264                 length = min(pcb->mtu, sbavail(&pcb->so->so_snd));
3265                 if (length == 0)
3266                         break;
3267
3268                 /* Get the chunk from the socket's send buffer */
3269                 m = ng_btsocket_rfcomm_prepare_packet(&pcb->so->so_snd, length);
3270                 if (m == NULL) {
3271                         error = ENOBUFS;
3272                         break;
3273                 }
3274
3275                 sbdrop(&pcb->so->so_snd, length);
3276
3277                 error = ng_btsocket_rfcomm_send_uih(pcb->session,
3278                                 RFCOMM_MKADDRESS(INITIATOR(pcb->session),
3279                                         pcb->dlci), 0, 0, m);
3280                 if (error != 0)
3281                         break;
3282         }
3283
3284         if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC)
3285                 pcb->tx_cred -= sent;
3286
3287         if (error == 0 && sent > 0) {
3288                 pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_SENDING;
3289                 sowwakeup(pcb->so);
3290         }
3291
3292         return (error);
3293 } /* ng_btsocket_rfcomm_pcb_send */
3294
3295 /*
3296  * Unlink and disconnect DLC. If ng_btsocket_rfcomm_pcb_kill() returns
3297  * non zero value than socket has no reference and has to be detached.
3298  * Caller must hold pcb->pcb_mtx and pcb->session->session_mtx
3299  */
3300
3301 static void
3302 ng_btsocket_rfcomm_pcb_kill(ng_btsocket_rfcomm_pcb_p pcb, int error)
3303 {
3304         ng_btsocket_rfcomm_session_p    s = pcb->session;
3305
3306         NG_BTSOCKET_RFCOMM_INFO(
3307 "%s: Killing DLC, so=%p, dlci=%d, state=%d, flags=%#x, error=%d\n",
3308                 __func__, pcb->so, pcb->dlci, pcb->state, pcb->flags, error);
3309
3310         if (pcb->session == NULL)
3311                 panic("%s: DLC without session, pcb=%p, state=%d, flags=%#x\n",
3312                         __func__, pcb, pcb->state, pcb->flags);
3313
3314         mtx_assert(&pcb->session->session_mtx, MA_OWNED);
3315         mtx_assert(&pcb->pcb_mtx, MA_OWNED);
3316
3317         if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)
3318                 ng_btsocket_rfcomm_untimeout(pcb);
3319
3320         /* Detach DLC from the session. Does not matter which state DLC in */
3321         LIST_REMOVE(pcb, session_next);
3322         pcb->session = NULL;
3323
3324         /* Change DLC state and wakeup all sleepers */
3325         pcb->state = NG_BTSOCKET_RFCOMM_DLC_CLOSED;
3326         pcb->so->so_error = error;
3327         soisdisconnected(pcb->so);
3328         wakeup(&pcb->state);
3329
3330         /* Check if we have any DLCs left on the session */
3331         if (LIST_EMPTY(&s->dlcs) && INITIATOR(s)) {
3332                 NG_BTSOCKET_RFCOMM_INFO(
3333 "%s: Disconnecting session, state=%d, flags=%#x, mtu=%d\n",
3334                         __func__, s->state, s->flags, s->mtu);
3335
3336                 switch (s->state) {
3337                 case NG_BTSOCKET_RFCOMM_SESSION_CLOSED:
3338                 case NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING:
3339                         /*
3340                          * Do not have to do anything here. We can get here
3341                          * when L2CAP connection was terminated or we have 
3342                          * received DISC on multiplexor channel
3343                          */
3344                         break;
3345
3346                 case NG_BTSOCKET_RFCOMM_SESSION_OPEN:
3347                         /* Send DISC on multiplexor channel */
3348                         error = ng_btsocket_rfcomm_send_command(s,
3349                                         RFCOMM_FRAME_DISC, 0);
3350                         if (error == 0) {
3351                                 s->state = NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING;
3352                                 break;
3353                         }
3354                         /* FALL THROUGH */
3355
3356                 case NG_BTSOCKET_RFCOMM_SESSION_CONNECTING:
3357                 case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED:
3358                         s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;
3359                         break;
3360
3361 /*              case NG_BTSOCKET_RFCOMM_SESSION_LISTENING: */
3362                 default:
3363                         panic("%s: Invalid session state=%d, flags=%#x\n",
3364                                 __func__, s->state, s->flags);
3365                         break;
3366                 }
3367
3368                 ng_btsocket_rfcomm_task_wakeup();
3369         }
3370 } /* ng_btsocket_rfcomm_pcb_kill */
3371
3372 /*
3373  * Look for given dlci for given RFCOMM session. Caller must hold s->session_mtx
3374  */
3375
3376 static ng_btsocket_rfcomm_pcb_p
3377 ng_btsocket_rfcomm_pcb_by_dlci(ng_btsocket_rfcomm_session_p s, int dlci)
3378 {
3379         ng_btsocket_rfcomm_pcb_p        pcb = NULL;
3380
3381         mtx_assert(&s->session_mtx, MA_OWNED);
3382
3383         LIST_FOREACH(pcb, &s->dlcs, session_next)
3384                 if (pcb->dlci == dlci)
3385                         break;
3386
3387         return (pcb);
3388 } /* ng_btsocket_rfcomm_pcb_by_dlci */
3389
3390 /*
3391  * Look for socket that listens on given src address and given channel
3392  */
3393
3394 static ng_btsocket_rfcomm_pcb_p
3395 ng_btsocket_rfcomm_pcb_listener(bdaddr_p src, int channel)
3396 {
3397         ng_btsocket_rfcomm_pcb_p        pcb = NULL, pcb1 = NULL;
3398
3399         mtx_lock(&ng_btsocket_rfcomm_sockets_mtx);
3400
3401         LIST_FOREACH(pcb, &ng_btsocket_rfcomm_sockets, next) {
3402                 if (pcb->channel != channel ||
3403                     !(pcb->so->so_options & SO_ACCEPTCONN))
3404                         continue;
3405
3406                 if (bcmp(&pcb->src, src, sizeof(*src)) == 0)
3407                         break;
3408
3409                 if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
3410                         pcb1 = pcb;
3411         }
3412
3413         mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);
3414
3415         return ((pcb != NULL)? pcb : pcb1);
3416 } /* ng_btsocket_rfcomm_pcb_listener */
3417
3418 /*****************************************************************************
3419  *****************************************************************************
3420  **                              Misc. functions 
3421  *****************************************************************************
3422  *****************************************************************************/
3423
3424 /*
3425  *  Set timeout. Caller MUST hold pcb_mtx
3426  */
3427
3428 static void
3429 ng_btsocket_rfcomm_timeout(ng_btsocket_rfcomm_pcb_p pcb)
3430 {
3431         mtx_assert(&pcb->pcb_mtx, MA_OWNED);
3432
3433         if (!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)) {
3434                 pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_TIMO;
3435                 pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT;
3436                 callout_reset(&pcb->timo, ng_btsocket_rfcomm_timo * hz,
3437                     ng_btsocket_rfcomm_process_timeout, pcb);
3438         } else
3439                 panic("%s: Duplicated socket timeout?!\n", __func__);
3440 } /* ng_btsocket_rfcomm_timeout */
3441
3442 /*
3443  *  Unset pcb timeout. Caller MUST hold pcb_mtx
3444  */
3445
3446 static void
3447 ng_btsocket_rfcomm_untimeout(ng_btsocket_rfcomm_pcb_p pcb)
3448 {
3449         mtx_assert(&pcb->pcb_mtx, MA_OWNED);
3450
3451         if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO) {
3452                 callout_stop(&pcb->timo);
3453                 pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMO;
3454                 pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT;
3455         } else
3456                 panic("%s: No socket timeout?!\n", __func__);
3457 } /* ng_btsocket_rfcomm_timeout */
3458
3459 /*
3460  * Process pcb timeout
3461  */
3462
3463 static void
3464 ng_btsocket_rfcomm_process_timeout(void *xpcb)
3465 {
3466         ng_btsocket_rfcomm_pcb_p        pcb = (ng_btsocket_rfcomm_pcb_p) xpcb;
3467
3468         mtx_assert(&pcb->pcb_mtx, MA_OWNED);
3469
3470         NG_BTSOCKET_RFCOMM_INFO(
3471 "%s: Timeout, so=%p, dlci=%d, state=%d, flags=%#x\n",
3472                 __func__, pcb->so, pcb->dlci, pcb->state, pcb->flags);
3473
3474         pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMO;
3475         pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT;
3476
3477         switch (pcb->state) {
3478         case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING:
3479         case NG_BTSOCKET_RFCOMM_DLC_CONNECTING:
3480                 pcb->state = NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING;
3481                 break;
3482
3483         case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT:
3484         case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING:
3485                 break;
3486
3487         default:
3488                 panic(
3489 "%s: DLC timeout in invalid state, dlci=%d, state=%d, flags=%#x\n",
3490                         __func__, pcb->dlci, pcb->state, pcb->flags);
3491                 break;
3492         }
3493
3494         ng_btsocket_rfcomm_task_wakeup();
3495 } /* ng_btsocket_rfcomm_process_timeout */
3496
3497 /*
3498  * Get up to length bytes from the socket buffer
3499  */
3500
3501 static struct mbuf *
3502 ng_btsocket_rfcomm_prepare_packet(struct sockbuf *sb, int length)
3503 {
3504         struct mbuf     *top = NULL, *m = NULL, *n = NULL, *nextpkt = NULL;
3505         int              mlen, noff, len;
3506
3507         MGETHDR(top, M_NOWAIT, MT_DATA);
3508         if (top == NULL)
3509                 return (NULL);
3510
3511         top->m_pkthdr.len = length;
3512         top->m_len = 0;
3513         mlen = MHLEN;
3514
3515         m = top;
3516         n = sb->sb_mb;
3517         nextpkt = n->m_nextpkt;
3518         noff = 0;
3519
3520         while (length > 0 && n != NULL) {
3521                 len = min(mlen - m->m_len, n->m_len - noff);
3522                 if (len > length)
3523                         len = length;
3524
3525                 bcopy(mtod(n, caddr_t)+noff, mtod(m, caddr_t)+m->m_len, len);
3526                 m->m_len += len;
3527                 noff += len;
3528                 length -= len;
3529
3530                 if (length > 0 && m->m_len == mlen) {
3531                         MGET(m->m_next, M_NOWAIT, MT_DATA);
3532                         if (m->m_next == NULL) {
3533                                 NG_FREE_M(top);
3534                                 return (NULL);
3535                         }
3536
3537                         m = m->m_next;
3538                         m->m_len = 0;
3539                         mlen = MLEN;
3540                 }
3541
3542                 if (noff == n->m_len) {
3543                         noff = 0;
3544                         n = n->m_next;
3545
3546                         if (n == NULL)
3547                                 n = nextpkt;
3548
3549                         nextpkt = (n != NULL)? n->m_nextpkt : NULL;
3550                 }
3551         }
3552
3553         if (length < 0)
3554                 panic("%s: length=%d\n", __func__, length);
3555         if (length > 0 && n == NULL)
3556                 panic("%s: bogus length=%d, n=%p\n", __func__, length, n);
3557
3558         return (top);
3559 } /* ng_btsocket_rfcomm_prepare_packet */
3560