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