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