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