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