rfcomm_session.c revision 1.7 1 1.7 plunky /* $NetBSD: rfcomm_session.c,v 1.7 2007/03/15 19:47:51 plunky Exp $ */
2 1.1 gdamore
3 1.1 gdamore /*-
4 1.1 gdamore * Copyright (c) 2006 Itronix Inc.
5 1.1 gdamore * All rights reserved.
6 1.1 gdamore *
7 1.1 gdamore * Written by Iain Hibbert for Itronix Inc.
8 1.1 gdamore *
9 1.1 gdamore * Redistribution and use in source and binary forms, with or without
10 1.1 gdamore * modification, are permitted provided that the following conditions
11 1.1 gdamore * are met:
12 1.1 gdamore * 1. Redistributions of source code must retain the above copyright
13 1.1 gdamore * notice, this list of conditions and the following disclaimer.
14 1.1 gdamore * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 gdamore * notice, this list of conditions and the following disclaimer in the
16 1.1 gdamore * documentation and/or other materials provided with the distribution.
17 1.1 gdamore * 3. The name of Itronix Inc. may not be used to endorse
18 1.1 gdamore * or promote products derived from this software without specific
19 1.1 gdamore * prior written permission.
20 1.1 gdamore *
21 1.1 gdamore * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
22 1.1 gdamore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 1.1 gdamore * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 1.1 gdamore * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
25 1.1 gdamore * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 1.1 gdamore * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 1.1 gdamore * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 1.1 gdamore * ON ANY THEORY OF LIABILITY, WHETHER IN
29 1.1 gdamore * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 1.1 gdamore * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 1.1 gdamore * POSSIBILITY OF SUCH DAMAGE.
32 1.1 gdamore */
33 1.1 gdamore
34 1.1 gdamore #include <sys/cdefs.h>
35 1.7 plunky __KERNEL_RCSID(0, "$NetBSD: rfcomm_session.c,v 1.7 2007/03/15 19:47:51 plunky Exp $");
36 1.1 gdamore
37 1.1 gdamore #include <sys/param.h>
38 1.1 gdamore #include <sys/kernel.h>
39 1.1 gdamore #include <sys/mbuf.h>
40 1.1 gdamore #include <sys/proc.h>
41 1.1 gdamore #include <sys/systm.h>
42 1.1 gdamore #include <sys/types.h>
43 1.1 gdamore
44 1.1 gdamore #include <netbt/bluetooth.h>
45 1.1 gdamore #include <netbt/hci.h>
46 1.1 gdamore #include <netbt/l2cap.h>
47 1.1 gdamore #include <netbt/rfcomm.h>
48 1.1 gdamore
49 1.1 gdamore /******************************************************************************
50 1.1 gdamore *
51 1.1 gdamore * RFCOMM Multiplexer Sessions sit directly on L2CAP channels, and can
52 1.1 gdamore * multiplex up to 30 incoming and 30 outgoing connections.
53 1.1 gdamore * Only one Multiplexer is allowed between any two devices.
54 1.1 gdamore */
55 1.1 gdamore
56 1.1 gdamore static void rfcomm_session_timeout(void *);
57 1.1 gdamore static void rfcomm_session_recv_sabm(struct rfcomm_session *, int);
58 1.1 gdamore static void rfcomm_session_recv_disc(struct rfcomm_session *, int);
59 1.1 gdamore static void rfcomm_session_recv_ua(struct rfcomm_session *, int);
60 1.1 gdamore static void rfcomm_session_recv_dm(struct rfcomm_session *, int);
61 1.1 gdamore static void rfcomm_session_recv_uih(struct rfcomm_session *, int, int, struct mbuf *, int);
62 1.1 gdamore static void rfcomm_session_recv_mcc(struct rfcomm_session *, struct mbuf *);
63 1.1 gdamore static void rfcomm_session_recv_mcc_test(struct rfcomm_session *, int, struct mbuf *);
64 1.1 gdamore static void rfcomm_session_recv_mcc_fcon(struct rfcomm_session *, int);
65 1.1 gdamore static void rfcomm_session_recv_mcc_fcoff(struct rfcomm_session *, int);
66 1.1 gdamore static void rfcomm_session_recv_mcc_msc(struct rfcomm_session *, int, struct mbuf *);
67 1.1 gdamore static void rfcomm_session_recv_mcc_rpn(struct rfcomm_session *, int, struct mbuf *);
68 1.1 gdamore static void rfcomm_session_recv_mcc_rls(struct rfcomm_session *, int, struct mbuf *);
69 1.1 gdamore static void rfcomm_session_recv_mcc_pn(struct rfcomm_session *, int, struct mbuf *);
70 1.1 gdamore static void rfcomm_session_recv_mcc_nsc(struct rfcomm_session *, int, struct mbuf *);
71 1.1 gdamore
72 1.1 gdamore /* L2CAP callbacks */
73 1.1 gdamore static void rfcomm_session_connecting(void *);
74 1.1 gdamore static void rfcomm_session_connected(void *);
75 1.1 gdamore static void rfcomm_session_disconnected(void *, int);
76 1.1 gdamore static void *rfcomm_session_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
77 1.1 gdamore static void rfcomm_session_complete(void *, int);
78 1.1 gdamore static void rfcomm_session_input(void *, struct mbuf *);
79 1.1 gdamore
80 1.1 gdamore static const struct btproto rfcomm_session_proto = {
81 1.1 gdamore rfcomm_session_connecting,
82 1.1 gdamore rfcomm_session_connected,
83 1.1 gdamore rfcomm_session_disconnected,
84 1.1 gdamore rfcomm_session_newconn,
85 1.1 gdamore rfcomm_session_complete,
86 1.1 gdamore rfcomm_session_input
87 1.1 gdamore };
88 1.1 gdamore
89 1.1 gdamore struct rfcomm_session_list
90 1.1 gdamore rfcomm_session_active = LIST_HEAD_INITIALIZER(rfcomm_session_active);
91 1.1 gdamore
92 1.1 gdamore struct rfcomm_session_list
93 1.1 gdamore rfcomm_session_listen = LIST_HEAD_INITIALIZER(rfcomm_session_listen);
94 1.1 gdamore
95 1.1 gdamore POOL_INIT(rfcomm_credit_pool, sizeof(struct rfcomm_credit),
96 1.6 ad 0, 0, 0, "rfcomm_credit", NULL, IPL_SOFTNET);
97 1.1 gdamore
98 1.1 gdamore /*
99 1.1 gdamore * RFCOMM System Parameters (see section 5.3)
100 1.1 gdamore */
101 1.1 gdamore int rfcomm_mtu_default = 127; /* bytes */
102 1.1 gdamore int rfcomm_ack_timeout = 20; /* seconds */
103 1.1 gdamore int rfcomm_mcc_timeout = 20; /* seconds */
104 1.1 gdamore
105 1.1 gdamore /*
106 1.1 gdamore * Reversed CRC table as per TS 07.10 Annex B.3.5
107 1.1 gdamore */
108 1.1 gdamore static uint8_t crctable[256] = { /* reversed, 8-bit, poly=0x07 */
109 1.1 gdamore 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,
110 1.1 gdamore 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
111 1.1 gdamore 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,
112 1.1 gdamore 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
113 1.1 gdamore
114 1.1 gdamore 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,
115 1.1 gdamore 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
116 1.1 gdamore 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,
117 1.1 gdamore 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
118 1.1 gdamore
119 1.1 gdamore 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,
120 1.1 gdamore 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
121 1.1 gdamore 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,
122 1.1 gdamore 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
123 1.1 gdamore
124 1.1 gdamore 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,
125 1.1 gdamore 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
126 1.1 gdamore 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,
127 1.1 gdamore 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
128 1.1 gdamore
129 1.1 gdamore 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,
130 1.1 gdamore 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
131 1.1 gdamore 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,
132 1.1 gdamore 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
133 1.1 gdamore
134 1.1 gdamore 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,
135 1.1 gdamore 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
136 1.1 gdamore 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,
137 1.1 gdamore 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
138 1.1 gdamore
139 1.1 gdamore 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,
140 1.1 gdamore 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
141 1.1 gdamore 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,
142 1.1 gdamore 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
143 1.1 gdamore
144 1.1 gdamore 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,
145 1.1 gdamore 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
146 1.1 gdamore 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,
147 1.1 gdamore 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf
148 1.1 gdamore };
149 1.1 gdamore
150 1.1 gdamore #define FCS(f, d) crctable[(f) ^ (d)]
151 1.1 gdamore
152 1.1 gdamore /*
153 1.1 gdamore * rfcomm_session_alloc(list, sockaddr)
154 1.1 gdamore *
155 1.1 gdamore * allocate a new session and fill in the blanks, then
156 1.1 gdamore * attach session to front of specified list (active or listen)
157 1.1 gdamore */
158 1.1 gdamore struct rfcomm_session *
159 1.1 gdamore rfcomm_session_alloc(struct rfcomm_session_list *list,
160 1.1 gdamore struct sockaddr_bt *laddr)
161 1.1 gdamore {
162 1.1 gdamore struct rfcomm_session *rs;
163 1.1 gdamore int err;
164 1.1 gdamore
165 1.1 gdamore rs = malloc(sizeof(*rs), M_BLUETOOTH, M_NOWAIT | M_ZERO);
166 1.1 gdamore if (rs == NULL)
167 1.1 gdamore return NULL;
168 1.1 gdamore
169 1.1 gdamore rs->rs_state = RFCOMM_SESSION_CLOSED;
170 1.1 gdamore
171 1.1 gdamore callout_init(&rs->rs_timeout);
172 1.1 gdamore callout_setfunc(&rs->rs_timeout, rfcomm_session_timeout, rs);
173 1.1 gdamore
174 1.1 gdamore SIMPLEQ_INIT(&rs->rs_credits);
175 1.1 gdamore LIST_INIT(&rs->rs_dlcs);
176 1.1 gdamore
177 1.1 gdamore err = l2cap_attach(&rs->rs_l2cap, &rfcomm_session_proto, rs);
178 1.1 gdamore if (err) {
179 1.1 gdamore free(rs, M_BLUETOOTH);
180 1.1 gdamore return NULL;
181 1.1 gdamore }
182 1.1 gdamore
183 1.1 gdamore (void)l2cap_getopt(rs->rs_l2cap, SO_L2CAP_OMTU, &rs->rs_mtu);
184 1.1 gdamore
185 1.1 gdamore if (laddr->bt_psm == L2CAP_PSM_ANY)
186 1.1 gdamore laddr->bt_psm = L2CAP_PSM_RFCOMM;
187 1.1 gdamore
188 1.1 gdamore (void)l2cap_bind(rs->rs_l2cap, laddr);
189 1.1 gdamore
190 1.1 gdamore LIST_INSERT_HEAD(list, rs, rs_next);
191 1.1 gdamore
192 1.1 gdamore return rs;
193 1.1 gdamore }
194 1.1 gdamore
195 1.1 gdamore /*
196 1.1 gdamore * rfcomm_session_free(rfcomm_session)
197 1.1 gdamore *
198 1.1 gdamore * release a session, including any cleanup
199 1.1 gdamore */
200 1.1 gdamore void
201 1.1 gdamore rfcomm_session_free(struct rfcomm_session *rs)
202 1.1 gdamore {
203 1.1 gdamore struct rfcomm_credit *credit;
204 1.1 gdamore
205 1.1 gdamore KASSERT(rs != NULL);
206 1.1 gdamore KASSERT(LIST_EMPTY(&rs->rs_dlcs));
207 1.1 gdamore
208 1.1 gdamore rs->rs_state = RFCOMM_SESSION_CLOSED;
209 1.1 gdamore
210 1.1 gdamore /*
211 1.1 gdamore * If the callout is already invoked we have no way to stop it,
212 1.1 gdamore * but it will call us back right away (there are no DLC's) so
213 1.1 gdamore * not to worry.
214 1.1 gdamore */
215 1.1 gdamore callout_stop(&rs->rs_timeout);
216 1.1 gdamore if (callout_invoking(&rs->rs_timeout))
217 1.1 gdamore return;
218 1.1 gdamore
219 1.1 gdamore /*
220 1.1 gdamore * Take care that rfcomm_session_disconnected() doesnt call
221 1.1 gdamore * us back either as it will do if the l2cap_channel has not
222 1.1 gdamore * been closed when we detach it..
223 1.1 gdamore */
224 1.1 gdamore if (rs->rs_flags & RFCOMM_SESSION_FREE)
225 1.1 gdamore return;
226 1.1 gdamore
227 1.1 gdamore rs->rs_flags |= RFCOMM_SESSION_FREE;
228 1.1 gdamore
229 1.1 gdamore /* throw away any remaining credit notes */
230 1.1 gdamore while ((credit = SIMPLEQ_FIRST(&rs->rs_credits)) != NULL) {
231 1.1 gdamore SIMPLEQ_REMOVE_HEAD(&rs->rs_credits, rc_next);
232 1.1 gdamore pool_put(&rfcomm_credit_pool, credit);
233 1.1 gdamore }
234 1.1 gdamore
235 1.1 gdamore KASSERT(SIMPLEQ_EMPTY(&rs->rs_credits));
236 1.1 gdamore
237 1.1 gdamore /* Goodbye! */
238 1.1 gdamore LIST_REMOVE(rs, rs_next);
239 1.1 gdamore l2cap_detach(&rs->rs_l2cap);
240 1.1 gdamore free(rs, M_BLUETOOTH);
241 1.1 gdamore }
242 1.1 gdamore
243 1.1 gdamore /*
244 1.1 gdamore * rfcomm_session_lookup(sockaddr, sockaddr)
245 1.1 gdamore *
246 1.1 gdamore * Find active rfcomm session matching src and dest addresses
247 1.1 gdamore * when src is BDADDR_ANY match any local address
248 1.1 gdamore */
249 1.1 gdamore struct rfcomm_session *
250 1.1 gdamore rfcomm_session_lookup(struct sockaddr_bt *src, struct sockaddr_bt *dest)
251 1.1 gdamore {
252 1.1 gdamore struct rfcomm_session *rs;
253 1.1 gdamore struct sockaddr_bt addr;
254 1.1 gdamore
255 1.1 gdamore LIST_FOREACH(rs, &rfcomm_session_active, rs_next) {
256 1.1 gdamore if (rs->rs_state == RFCOMM_SESSION_CLOSED)
257 1.1 gdamore continue;
258 1.1 gdamore
259 1.1 gdamore l2cap_sockaddr(rs->rs_l2cap, &addr);
260 1.1 gdamore
261 1.1 gdamore if (bdaddr_same(&src->bt_bdaddr, &addr.bt_bdaddr) == 0)
262 1.1 gdamore if (bdaddr_any(&src->bt_bdaddr) == 0)
263 1.1 gdamore continue;
264 1.1 gdamore
265 1.1 gdamore l2cap_peeraddr(rs->rs_l2cap, &addr);
266 1.1 gdamore
267 1.1 gdamore if (addr.bt_psm != dest->bt_psm)
268 1.1 gdamore continue;
269 1.1 gdamore
270 1.1 gdamore if (bdaddr_same(&dest->bt_bdaddr, &addr.bt_bdaddr))
271 1.1 gdamore break;
272 1.1 gdamore }
273 1.1 gdamore
274 1.1 gdamore return rs;
275 1.1 gdamore }
276 1.1 gdamore
277 1.1 gdamore /*
278 1.1 gdamore * rfcomm_session_timeout(rfcomm_session)
279 1.1 gdamore *
280 1.1 gdamore * Session timeouts are scheduled when a session is left or
281 1.1 gdamore * created with no DLCs, and when SABM(0) or DISC(0) are
282 1.1 gdamore * sent.
283 1.1 gdamore *
284 1.1 gdamore * So, if it is in an open state with DLC's attached then
285 1.1 gdamore * we leave it alone, otherwise the session is lost.
286 1.1 gdamore */
287 1.1 gdamore static void
288 1.1 gdamore rfcomm_session_timeout(void *arg)
289 1.1 gdamore {
290 1.1 gdamore struct rfcomm_session *rs = arg;
291 1.1 gdamore struct rfcomm_dlc *dlc;
292 1.1 gdamore int s;
293 1.1 gdamore
294 1.1 gdamore KASSERT(rs != NULL);
295 1.1 gdamore
296 1.1 gdamore s = splsoftnet();
297 1.1 gdamore callout_ack(&rs->rs_timeout);
298 1.1 gdamore
299 1.1 gdamore if (rs->rs_state != RFCOMM_SESSION_OPEN) {
300 1.1 gdamore DPRINTF("timeout\n");
301 1.1 gdamore rs->rs_state = RFCOMM_SESSION_CLOSED;
302 1.1 gdamore
303 1.1 gdamore while (!LIST_EMPTY(&rs->rs_dlcs)) {
304 1.1 gdamore dlc = LIST_FIRST(&rs->rs_dlcs);
305 1.1 gdamore
306 1.1 gdamore rfcomm_dlc_close(dlc, ETIMEDOUT);
307 1.1 gdamore }
308 1.1 gdamore }
309 1.1 gdamore
310 1.1 gdamore if (LIST_EMPTY(&rs->rs_dlcs)) {
311 1.1 gdamore DPRINTF("expiring\n");
312 1.1 gdamore rfcomm_session_free(rs);
313 1.1 gdamore }
314 1.1 gdamore splx(s);
315 1.1 gdamore }
316 1.1 gdamore
317 1.1 gdamore /***********************************************************************
318 1.1 gdamore *
319 1.1 gdamore * RFCOMM Session L2CAP protocol callbacks
320 1.1 gdamore *
321 1.1 gdamore */
322 1.1 gdamore
323 1.1 gdamore static void
324 1.4 christos rfcomm_session_connecting(void *arg)
325 1.1 gdamore {
326 1.7 plunky /* struct rfcomm_session *rs = arg; */
327 1.1 gdamore
328 1.1 gdamore DPRINTF("Connecting\n");
329 1.1 gdamore }
330 1.1 gdamore
331 1.1 gdamore static void
332 1.1 gdamore rfcomm_session_connected(void *arg)
333 1.1 gdamore {
334 1.1 gdamore struct rfcomm_session *rs = arg;
335 1.1 gdamore
336 1.1 gdamore DPRINTF("Connected\n");
337 1.1 gdamore
338 1.1 gdamore /*
339 1.1 gdamore * L2CAP is open.
340 1.1 gdamore *
341 1.1 gdamore * If we are initiator, we can send our SABM(0)
342 1.1 gdamore * a timeout should be active?
343 1.1 gdamore *
344 1.1 gdamore * We must take note of the L2CAP MTU because currently
345 1.1 gdamore * the L2CAP implementation can only do Basic Mode.
346 1.1 gdamore */
347 1.1 gdamore l2cap_getopt(rs->rs_l2cap, SO_L2CAP_OMTU, &rs->rs_mtu);
348 1.1 gdamore
349 1.1 gdamore rs->rs_mtu -= 6; /* (RFCOMM overhead could be this big) */
350 1.1 gdamore if (rs->rs_mtu < RFCOMM_MTU_MIN) {
351 1.1 gdamore rfcomm_session_disconnected(rs, EINVAL);
352 1.1 gdamore return;
353 1.1 gdamore }
354 1.1 gdamore
355 1.1 gdamore if (IS_INITIATOR(rs)) {
356 1.1 gdamore int err;
357 1.1 gdamore
358 1.1 gdamore err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_SABM, 0);
359 1.1 gdamore if (err)
360 1.1 gdamore rfcomm_session_disconnected(rs, err);
361 1.1 gdamore
362 1.1 gdamore callout_schedule(&rs->rs_timeout, rfcomm_ack_timeout * hz);
363 1.1 gdamore }
364 1.1 gdamore }
365 1.1 gdamore
366 1.1 gdamore static void
367 1.1 gdamore rfcomm_session_disconnected(void *arg, int err)
368 1.1 gdamore {
369 1.1 gdamore struct rfcomm_session *rs = arg;
370 1.1 gdamore struct rfcomm_dlc *dlc;
371 1.1 gdamore
372 1.1 gdamore DPRINTF("Disconnected\n");
373 1.1 gdamore
374 1.1 gdamore rs->rs_state = RFCOMM_SESSION_CLOSED;
375 1.1 gdamore
376 1.1 gdamore while (!LIST_EMPTY(&rs->rs_dlcs)) {
377 1.1 gdamore dlc = LIST_FIRST(&rs->rs_dlcs);
378 1.1 gdamore
379 1.1 gdamore rfcomm_dlc_close(dlc, err);
380 1.1 gdamore }
381 1.1 gdamore
382 1.1 gdamore rfcomm_session_free(rs);
383 1.1 gdamore }
384 1.1 gdamore
385 1.1 gdamore static void *
386 1.1 gdamore rfcomm_session_newconn(void *arg, struct sockaddr_bt *laddr,
387 1.1 gdamore struct sockaddr_bt *raddr)
388 1.1 gdamore {
389 1.1 gdamore struct rfcomm_session *new, *rs = arg;
390 1.1 gdamore
391 1.1 gdamore DPRINTF("New Connection\n");
392 1.1 gdamore
393 1.1 gdamore /*
394 1.1 gdamore * Incoming session connect request. We should return a new
395 1.1 gdamore * session pointer if this is acceptable. The L2CAP layer
396 1.1 gdamore * passes local and remote addresses, which we must check as
397 1.1 gdamore * only one RFCOMM session is allowed between any two devices
398 1.1 gdamore */
399 1.1 gdamore new = rfcomm_session_lookup(laddr, raddr);
400 1.1 gdamore if (new != NULL)
401 1.1 gdamore return NULL;
402 1.1 gdamore
403 1.1 gdamore new = rfcomm_session_alloc(&rfcomm_session_active, laddr);
404 1.1 gdamore if (new == NULL)
405 1.1 gdamore return NULL;
406 1.1 gdamore
407 1.1 gdamore new->rs_mtu = rs->rs_mtu;
408 1.1 gdamore new->rs_state = RFCOMM_SESSION_WAIT_CONNECT;
409 1.1 gdamore
410 1.1 gdamore /*
411 1.1 gdamore * schedule an expiry so that if nothing comes of it we
412 1.1 gdamore * can punt.
413 1.1 gdamore */
414 1.1 gdamore callout_schedule(&new->rs_timeout, rfcomm_mcc_timeout * hz);
415 1.1 gdamore
416 1.1 gdamore return new->rs_l2cap;
417 1.1 gdamore }
418 1.1 gdamore
419 1.1 gdamore static void
420 1.1 gdamore rfcomm_session_complete(void *arg, int count)
421 1.1 gdamore {
422 1.1 gdamore struct rfcomm_session *rs = arg;
423 1.1 gdamore struct rfcomm_credit *credit;
424 1.1 gdamore struct rfcomm_dlc *dlc;
425 1.1 gdamore
426 1.1 gdamore /*
427 1.1 gdamore * count L2CAP packets are 'complete', meaning that they are cleared
428 1.1 gdamore * our buffers (for best effort) or arrived safe (for guaranteed) so
429 1.1 gdamore * we can take it off our list and pass the message on, so that
430 1.1 gdamore * eventually the data can be removed from the sockbuf
431 1.1 gdamore */
432 1.1 gdamore while (count-- > 0) {
433 1.1 gdamore credit = SIMPLEQ_FIRST(&rs->rs_credits);
434 1.1 gdamore #ifdef DIAGNOSTIC
435 1.1 gdamore if (credit == NULL) {
436 1.1 gdamore printf("%s: too many packets completed!\n", __func__);
437 1.1 gdamore break;
438 1.1 gdamore }
439 1.1 gdamore #endif
440 1.1 gdamore dlc = credit->rc_dlc;
441 1.1 gdamore if (dlc != NULL) {
442 1.1 gdamore dlc->rd_pending--;
443 1.1 gdamore (*dlc->rd_proto->complete)
444 1.1 gdamore (dlc->rd_upper, credit->rc_len);
445 1.1 gdamore
446 1.1 gdamore /*
447 1.1 gdamore * if not using credit flow control, we may push
448 1.1 gdamore * more data now
449 1.1 gdamore */
450 1.1 gdamore if ((rs->rs_flags & RFCOMM_SESSION_CFC) == 0
451 1.1 gdamore && dlc->rd_state == RFCOMM_DLC_OPEN) {
452 1.1 gdamore rfcomm_dlc_start(dlc);
453 1.1 gdamore }
454 1.1 gdamore
455 1.1 gdamore /*
456 1.1 gdamore * When shutdown is indicated, we are just waiting to
457 1.1 gdamore * clear outgoing data.
458 1.1 gdamore */
459 1.1 gdamore if ((dlc->rd_flags & RFCOMM_DLC_SHUTDOWN)
460 1.1 gdamore && dlc->rd_txbuf == NULL && dlc->rd_pending == 0) {
461 1.1 gdamore dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
462 1.1 gdamore rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
463 1.1 gdamore dlc->rd_dlci);
464 1.1 gdamore callout_schedule(&dlc->rd_timeout,
465 1.1 gdamore rfcomm_ack_timeout * hz);
466 1.1 gdamore }
467 1.1 gdamore }
468 1.1 gdamore
469 1.1 gdamore SIMPLEQ_REMOVE_HEAD(&rs->rs_credits, rc_next);
470 1.1 gdamore pool_put(&rfcomm_credit_pool, credit);
471 1.1 gdamore }
472 1.1 gdamore
473 1.1 gdamore /*
474 1.1 gdamore * If session is closed, we are just waiting to clear the queue
475 1.1 gdamore */
476 1.1 gdamore if (rs->rs_state == RFCOMM_SESSION_CLOSED) {
477 1.1 gdamore if (SIMPLEQ_EMPTY(&rs->rs_credits))
478 1.1 gdamore l2cap_disconnect(rs->rs_l2cap, 0);
479 1.1 gdamore }
480 1.1 gdamore }
481 1.1 gdamore
482 1.1 gdamore /*
483 1.1 gdamore * Receive data from L2CAP layer for session. There is always exactly one
484 1.1 gdamore * RFCOMM frame contained in each L2CAP frame.
485 1.1 gdamore */
486 1.1 gdamore static void
487 1.1 gdamore rfcomm_session_input(void *arg, struct mbuf *m)
488 1.1 gdamore {
489 1.1 gdamore struct rfcomm_session *rs = arg;
490 1.1 gdamore int dlci, len, type, pf;
491 1.1 gdamore uint8_t fcs, b;
492 1.1 gdamore
493 1.1 gdamore KASSERT(m != NULL);
494 1.1 gdamore KASSERT(rs != NULL);
495 1.1 gdamore
496 1.1 gdamore /*
497 1.1 gdamore * UIH frames: FCS is only calculated on address and control fields
498 1.1 gdamore * For other frames: FCS is calculated on address, control and length
499 1.1 gdamore * Length may extend to two octets
500 1.1 gdamore */
501 1.1 gdamore fcs = 0xff;
502 1.1 gdamore
503 1.1 gdamore if (m->m_pkthdr.len < 4) {
504 1.1 gdamore DPRINTF("short frame (%d), discarded\n", m->m_pkthdr.len);
505 1.1 gdamore goto done;
506 1.1 gdamore }
507 1.1 gdamore
508 1.1 gdamore /* address - one octet */
509 1.1 gdamore m_copydata(m, 0, 1, &b);
510 1.1 gdamore m_adj(m, 1);
511 1.1 gdamore fcs = FCS(fcs, b);
512 1.1 gdamore dlci = RFCOMM_DLCI(b);
513 1.1 gdamore
514 1.1 gdamore /* control - one octet */
515 1.1 gdamore m_copydata(m, 0, 1, &b);
516 1.1 gdamore m_adj(m, 1);
517 1.1 gdamore fcs = FCS(fcs, b);
518 1.1 gdamore type = RFCOMM_TYPE(b);
519 1.1 gdamore pf = RFCOMM_PF(b);
520 1.1 gdamore
521 1.1 gdamore /* length - may be two octets */
522 1.1 gdamore m_copydata(m, 0, 1, &b);
523 1.1 gdamore m_adj(m, 1);
524 1.1 gdamore if (type != RFCOMM_FRAME_UIH)
525 1.1 gdamore fcs = FCS(fcs, b);
526 1.1 gdamore len = (b >> 1) & 0x7f;
527 1.1 gdamore
528 1.1 gdamore if (RFCOMM_EA(b) == 0) {
529 1.1 gdamore if (m->m_pkthdr.len < 2) {
530 1.1 gdamore DPRINTF("short frame (%d, EA = 0), discarded\n",
531 1.1 gdamore m->m_pkthdr.len);
532 1.1 gdamore goto done;
533 1.1 gdamore }
534 1.1 gdamore
535 1.1 gdamore m_copydata(m, 0, 1, &b);
536 1.1 gdamore m_adj(m, 1);
537 1.1 gdamore if (type != RFCOMM_FRAME_UIH)
538 1.1 gdamore fcs = FCS(fcs, b);
539 1.1 gdamore
540 1.1 gdamore len |= (b << 7);
541 1.1 gdamore }
542 1.1 gdamore
543 1.1 gdamore /* FCS byte is last octet in frame */
544 1.1 gdamore m_copydata(m, m->m_pkthdr.len - 1, 1, &b);
545 1.1 gdamore m_adj(m, -1);
546 1.1 gdamore fcs = FCS(fcs, b);
547 1.1 gdamore
548 1.1 gdamore if (fcs != 0xcf) {
549 1.1 gdamore DPRINTF("Bad FCS value (%#2.2x), frame discarded\n", fcs);
550 1.1 gdamore goto done;
551 1.1 gdamore }
552 1.1 gdamore
553 1.1 gdamore DPRINTFN(10, "dlci %d, type %2.2x, len = %d\n", dlci, type, len);
554 1.1 gdamore
555 1.1 gdamore switch (type) {
556 1.1 gdamore case RFCOMM_FRAME_SABM:
557 1.1 gdamore if (pf)
558 1.1 gdamore rfcomm_session_recv_sabm(rs, dlci);
559 1.1 gdamore break;
560 1.1 gdamore
561 1.1 gdamore case RFCOMM_FRAME_DISC:
562 1.1 gdamore if (pf)
563 1.1 gdamore rfcomm_session_recv_disc(rs, dlci);
564 1.1 gdamore break;
565 1.1 gdamore
566 1.1 gdamore case RFCOMM_FRAME_UA:
567 1.1 gdamore if (pf)
568 1.1 gdamore rfcomm_session_recv_ua(rs, dlci);
569 1.1 gdamore break;
570 1.1 gdamore
571 1.1 gdamore case RFCOMM_FRAME_DM:
572 1.1 gdamore rfcomm_session_recv_dm(rs, dlci);
573 1.1 gdamore break;
574 1.1 gdamore
575 1.1 gdamore case RFCOMM_FRAME_UIH:
576 1.1 gdamore rfcomm_session_recv_uih(rs, dlci, pf, m, len);
577 1.1 gdamore return; /* (no release) */
578 1.1 gdamore
579 1.1 gdamore default:
580 1.1 gdamore UNKNOWN(type);
581 1.1 gdamore break;
582 1.1 gdamore }
583 1.1 gdamore
584 1.1 gdamore done:
585 1.1 gdamore m_freem(m);
586 1.1 gdamore }
587 1.1 gdamore
588 1.1 gdamore /***********************************************************************
589 1.1 gdamore *
590 1.1 gdamore * RFCOMM Session receive processing
591 1.1 gdamore */
592 1.1 gdamore
593 1.1 gdamore /*
594 1.1 gdamore * rfcomm_session_recv_sabm(rfcomm_session, dlci)
595 1.1 gdamore *
596 1.1 gdamore * Set Asyncrhonous Balanced Mode - open the channel.
597 1.1 gdamore */
598 1.1 gdamore static void
599 1.1 gdamore rfcomm_session_recv_sabm(struct rfcomm_session *rs, int dlci)
600 1.1 gdamore {
601 1.1 gdamore struct rfcomm_mcc_msc msc;
602 1.1 gdamore struct rfcomm_dlc *dlc;
603 1.1 gdamore int err;
604 1.1 gdamore
605 1.1 gdamore DPRINTFN(5, "SABM(%d)\n", dlci);
606 1.1 gdamore
607 1.1 gdamore if (dlci == 0) { /* Open Session */
608 1.1 gdamore rs->rs_state = RFCOMM_SESSION_OPEN;
609 1.1 gdamore rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, 0);
610 1.1 gdamore LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
611 1.1 gdamore if (dlc->rd_state == RFCOMM_DLC_WAIT_SESSION)
612 1.1 gdamore rfcomm_dlc_connect(dlc);
613 1.1 gdamore }
614 1.1 gdamore return;
615 1.1 gdamore }
616 1.1 gdamore
617 1.1 gdamore if (rs->rs_state != RFCOMM_SESSION_OPEN) {
618 1.1 gdamore DPRINTF("session was not even open!\n");
619 1.1 gdamore return;
620 1.1 gdamore }
621 1.1 gdamore
622 1.1 gdamore /* validate direction bit */
623 1.1 gdamore if ((IS_INITIATOR(rs) && !RFCOMM_DIRECTION(dlci))
624 1.1 gdamore || (!IS_INITIATOR(rs) && RFCOMM_DIRECTION(dlci))) {
625 1.1 gdamore DPRINTF("Invalid direction bit on DLCI\n");
626 1.1 gdamore return;
627 1.1 gdamore }
628 1.1 gdamore
629 1.1 gdamore /*
630 1.1 gdamore * look for our DLC - this may exist if we received PN
631 1.1 gdamore * already, or we may have to fabricate a new one.
632 1.1 gdamore */
633 1.1 gdamore dlc = rfcomm_dlc_lookup(rs, dlci);
634 1.1 gdamore if (dlc == NULL) {
635 1.1 gdamore dlc = rfcomm_dlc_newconn(rs, dlci);
636 1.1 gdamore if (dlc == NULL)
637 1.1 gdamore return; /* (DM is sent) */
638 1.1 gdamore }
639 1.1 gdamore
640 1.1 gdamore DPRINTFN(2, "send UA(%d) state = %d\n", dlci, dlc->rd_state);
641 1.1 gdamore
642 1.1 gdamore err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, dlci);
643 1.1 gdamore if (err) {
644 1.1 gdamore rfcomm_dlc_close(dlc, err);
645 1.1 gdamore return;
646 1.1 gdamore }
647 1.1 gdamore
648 1.1 gdamore /*
649 1.1 gdamore * If this was some kind of spurious SABM then lets
650 1.1 gdamore * not do anything, heh.
651 1.1 gdamore */
652 1.1 gdamore if (dlc->rd_state != RFCOMM_DLC_WAIT_CONNECT)
653 1.1 gdamore return;
654 1.1 gdamore
655 1.1 gdamore msc.address = RFCOMM_MKADDRESS(1, dlc->rd_dlci);
656 1.1 gdamore msc.modem = dlc->rd_lmodem & 0xfe; /* EA = 0 */
657 1.5 plunky msc.brk = 0x00 | 0x01; /* EA = 1 */
658 1.1 gdamore rfcomm_session_send_mcc(rs, 1, RFCOMM_MCC_MSC, &msc, sizeof(msc));
659 1.1 gdamore callout_schedule(&dlc->rd_timeout, rfcomm_mcc_timeout * hz);
660 1.1 gdamore
661 1.1 gdamore dlc->rd_state = RFCOMM_DLC_OPEN;
662 1.1 gdamore (*dlc->rd_proto->connected)(dlc->rd_upper);
663 1.1 gdamore }
664 1.1 gdamore
665 1.1 gdamore /*
666 1.1 gdamore * Receive Disconnect Command
667 1.1 gdamore */
668 1.1 gdamore static void
669 1.1 gdamore rfcomm_session_recv_disc(struct rfcomm_session *rs, int dlci)
670 1.1 gdamore {
671 1.1 gdamore struct rfcomm_dlc *dlc;
672 1.1 gdamore
673 1.1 gdamore DPRINTFN(5, "DISC(%d)\n", dlci);
674 1.1 gdamore
675 1.1 gdamore if (dlci == 0) {
676 1.1 gdamore /*
677 1.1 gdamore * Disconnect Session
678 1.1 gdamore *
679 1.1 gdamore * We set the session state to CLOSED so that when
680 1.1 gdamore * the UA frame is clear the session will be closed
681 1.1 gdamore * automatically. We wont bother to close any DLC's
682 1.1 gdamore * just yet as there should be none. In the unlikely
683 1.1 gdamore * event that something is left, it will get flushed
684 1.1 gdamore * out as the session goes down.
685 1.1 gdamore */
686 1.1 gdamore rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, 0);
687 1.1 gdamore rs->rs_state = RFCOMM_SESSION_CLOSED;
688 1.1 gdamore return;
689 1.1 gdamore }
690 1.1 gdamore
691 1.1 gdamore dlc = rfcomm_dlc_lookup(rs, dlci);
692 1.1 gdamore if (dlc == NULL) {
693 1.1 gdamore rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM, dlci);
694 1.1 gdamore return;
695 1.1 gdamore }
696 1.1 gdamore
697 1.1 gdamore rfcomm_dlc_close(dlc, ECONNRESET);
698 1.1 gdamore rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, dlci);
699 1.1 gdamore }
700 1.1 gdamore
701 1.1 gdamore /*
702 1.1 gdamore * Receive Unnumbered Acknowledgement Response
703 1.1 gdamore *
704 1.1 gdamore * This should be a response to a DISC or SABM frame that we
705 1.1 gdamore * have previously sent. If unexpected, ignore it.
706 1.1 gdamore */
707 1.1 gdamore static void
708 1.1 gdamore rfcomm_session_recv_ua(struct rfcomm_session *rs, int dlci)
709 1.1 gdamore {
710 1.1 gdamore struct rfcomm_mcc_msc msc;
711 1.1 gdamore struct rfcomm_dlc *dlc;
712 1.1 gdamore
713 1.1 gdamore DPRINTFN(5, "UA(%d)\n", dlci);
714 1.1 gdamore
715 1.1 gdamore if (dlci == 0) {
716 1.1 gdamore switch (rs->rs_state) {
717 1.1 gdamore case RFCOMM_SESSION_WAIT_CONNECT: /* We sent SABM */
718 1.1 gdamore callout_stop(&rs->rs_timeout);
719 1.1 gdamore rs->rs_state = RFCOMM_SESSION_OPEN;
720 1.1 gdamore LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
721 1.1 gdamore if (dlc->rd_state == RFCOMM_DLC_WAIT_SESSION)
722 1.1 gdamore rfcomm_dlc_connect(dlc);
723 1.1 gdamore }
724 1.1 gdamore break;
725 1.1 gdamore
726 1.1 gdamore case RFCOMM_SESSION_WAIT_DISCONNECT: /* We sent DISC */
727 1.1 gdamore callout_stop(&rs->rs_timeout);
728 1.1 gdamore rs->rs_state = RFCOMM_SESSION_CLOSED;
729 1.1 gdamore l2cap_disconnect(rs->rs_l2cap, 0);
730 1.1 gdamore break;
731 1.1 gdamore
732 1.1 gdamore default:
733 1.1 gdamore DPRINTF("Received spurious UA(0)!\n");
734 1.1 gdamore break;
735 1.1 gdamore }
736 1.1 gdamore
737 1.1 gdamore return;
738 1.1 gdamore }
739 1.1 gdamore
740 1.1 gdamore /*
741 1.1 gdamore * If we have no DLC on this dlci, we may have aborted
742 1.1 gdamore * without shutting down properly, so check if the session
743 1.1 gdamore * needs disconnecting.
744 1.1 gdamore */
745 1.1 gdamore dlc = rfcomm_dlc_lookup(rs, dlci);
746 1.1 gdamore if (dlc == NULL)
747 1.1 gdamore goto check;
748 1.1 gdamore
749 1.1 gdamore switch (dlc->rd_state) {
750 1.1 gdamore case RFCOMM_DLC_WAIT_CONNECT: /* We sent SABM */
751 1.1 gdamore msc.address = RFCOMM_MKADDRESS(1, dlc->rd_dlci);
752 1.1 gdamore msc.modem = dlc->rd_lmodem & 0xfe; /* EA = 0 */
753 1.1 gdamore msc.brk = 0x00 | 0x01; /* EA = 1 */
754 1.1 gdamore rfcomm_session_send_mcc(rs, 1, RFCOMM_MCC_MSC,
755 1.1 gdamore &msc, sizeof(msc));
756 1.1 gdamore callout_schedule(&dlc->rd_timeout, rfcomm_mcc_timeout * hz);
757 1.1 gdamore
758 1.1 gdamore dlc->rd_state = RFCOMM_DLC_OPEN;
759 1.1 gdamore (*dlc->rd_proto->connected)(dlc->rd_upper);
760 1.1 gdamore return;
761 1.1 gdamore
762 1.1 gdamore case RFCOMM_DLC_WAIT_DISCONNECT: /* We sent DISC */
763 1.1 gdamore rfcomm_dlc_close(dlc, 0);
764 1.1 gdamore break;
765 1.1 gdamore
766 1.1 gdamore default:
767 1.1 gdamore DPRINTF("Received spurious UA(%d)!\n", dlci);
768 1.1 gdamore return;
769 1.1 gdamore }
770 1.1 gdamore
771 1.1 gdamore check: /* last one out turns out the light */
772 1.1 gdamore if (LIST_EMPTY(&rs->rs_dlcs)) {
773 1.1 gdamore rs->rs_state = RFCOMM_SESSION_WAIT_DISCONNECT;
774 1.1 gdamore rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC, 0);
775 1.1 gdamore callout_schedule(&rs->rs_timeout, rfcomm_ack_timeout * hz);
776 1.1 gdamore }
777 1.1 gdamore }
778 1.1 gdamore
779 1.1 gdamore /*
780 1.1 gdamore * Receive Disconnected Mode Response
781 1.1 gdamore *
782 1.1 gdamore * If this does not apply to a known DLC then we may ignore it.
783 1.1 gdamore */
784 1.1 gdamore static void
785 1.1 gdamore rfcomm_session_recv_dm(struct rfcomm_session *rs, int dlci)
786 1.1 gdamore {
787 1.1 gdamore struct rfcomm_dlc *dlc;
788 1.1 gdamore
789 1.1 gdamore DPRINTFN(5, "DM(%d)\n", dlci);
790 1.1 gdamore
791 1.1 gdamore dlc = rfcomm_dlc_lookup(rs, dlci);
792 1.1 gdamore if (dlc == NULL)
793 1.1 gdamore return;
794 1.1 gdamore
795 1.1 gdamore if (dlc->rd_state == RFCOMM_DLC_WAIT_CONNECT)
796 1.1 gdamore rfcomm_dlc_close(dlc, ECONNREFUSED);
797 1.1 gdamore else
798 1.1 gdamore rfcomm_dlc_close(dlc, ECONNRESET);
799 1.1 gdamore }
800 1.1 gdamore
801 1.1 gdamore /*
802 1.1 gdamore * Receive Unnumbered Information with Header check (MCC or data packet)
803 1.1 gdamore */
804 1.1 gdamore static void
805 1.1 gdamore rfcomm_session_recv_uih(struct rfcomm_session *rs, int dlci,
806 1.1 gdamore int pf, struct mbuf *m, int len)
807 1.1 gdamore {
808 1.1 gdamore struct rfcomm_dlc *dlc;
809 1.1 gdamore uint8_t credits = 0;
810 1.1 gdamore
811 1.1 gdamore DPRINTFN(10, "UIH(%d)\n", dlci);
812 1.1 gdamore
813 1.1 gdamore if (dlci == 0) {
814 1.1 gdamore rfcomm_session_recv_mcc(rs, m);
815 1.1 gdamore return;
816 1.1 gdamore }
817 1.1 gdamore
818 1.1 gdamore if (m->m_pkthdr.len != len + pf) {
819 1.1 gdamore DPRINTF("Bad Frame Length (%d), frame discarded\n",
820 1.1 gdamore m->m_pkthdr.len);
821 1.1 gdamore
822 1.1 gdamore goto discard;
823 1.1 gdamore }
824 1.1 gdamore
825 1.1 gdamore dlc = rfcomm_dlc_lookup(rs, dlci);
826 1.1 gdamore if (dlc == NULL) {
827 1.1 gdamore DPRINTF("UIH received for non existent DLC, discarded\n");
828 1.1 gdamore rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM, dlci);
829 1.1 gdamore goto discard;
830 1.1 gdamore }
831 1.1 gdamore
832 1.1 gdamore if (dlc->rd_state != RFCOMM_DLC_OPEN) {
833 1.1 gdamore DPRINTF("non-open DLC (state = %d), discarded\n",
834 1.1 gdamore dlc->rd_state);
835 1.1 gdamore goto discard;
836 1.1 gdamore }
837 1.1 gdamore
838 1.1 gdamore /* if PF is set, credits were included */
839 1.1 gdamore if (rs->rs_flags & RFCOMM_SESSION_CFC) {
840 1.1 gdamore if (pf != 0) {
841 1.1 gdamore if (m->m_pkthdr.len < sizeof(credits)) {
842 1.1 gdamore DPRINTF("Bad PF value, UIH discarded\n");
843 1.1 gdamore goto discard;
844 1.1 gdamore }
845 1.1 gdamore
846 1.1 gdamore m_copydata(m, 0, sizeof(credits), &credits);
847 1.1 gdamore m_adj(m, sizeof(credits));
848 1.1 gdamore
849 1.1 gdamore dlc->rd_txcred += credits;
850 1.1 gdamore
851 1.1 gdamore if (credits > 0 && dlc->rd_txbuf != NULL)
852 1.1 gdamore rfcomm_dlc_start(dlc);
853 1.1 gdamore }
854 1.1 gdamore
855 1.1 gdamore if (len == 0)
856 1.1 gdamore goto discard;
857 1.1 gdamore
858 1.1 gdamore if (dlc->rd_rxcred == 0) {
859 1.1 gdamore DPRINTF("Credit limit reached, UIH discarded\n");
860 1.1 gdamore goto discard;
861 1.1 gdamore }
862 1.1 gdamore
863 1.1 gdamore if (len > dlc->rd_rxsize) {
864 1.1 gdamore DPRINTF("UIH frame exceeds rxsize, discarded\n");
865 1.1 gdamore goto discard;
866 1.1 gdamore }
867 1.1 gdamore
868 1.1 gdamore dlc->rd_rxcred--;
869 1.1 gdamore dlc->rd_rxsize -= len;
870 1.1 gdamore }
871 1.1 gdamore
872 1.1 gdamore (*dlc->rd_proto->input)(dlc->rd_upper, m);
873 1.1 gdamore return;
874 1.1 gdamore
875 1.1 gdamore discard:
876 1.1 gdamore m_freem(m);
877 1.1 gdamore }
878 1.1 gdamore
879 1.1 gdamore /*
880 1.1 gdamore * Receive Multiplexer Control Command
881 1.1 gdamore */
882 1.1 gdamore static void
883 1.1 gdamore rfcomm_session_recv_mcc(struct rfcomm_session *rs, struct mbuf *m)
884 1.1 gdamore {
885 1.1 gdamore int type, cr, len;
886 1.1 gdamore uint8_t b;
887 1.1 gdamore
888 1.1 gdamore /*
889 1.1 gdamore * Extract MCC header.
890 1.1 gdamore *
891 1.1 gdamore * Fields are variable length using extension bit = 1 to signify the
892 1.1 gdamore * last octet in the sequence.
893 1.1 gdamore *
894 1.1 gdamore * Only single octet types are defined in TS 07.10/RFCOMM spec
895 1.1 gdamore *
896 1.1 gdamore * Length can realistically only use 15 bits (max RFCOMM MTU)
897 1.1 gdamore */
898 1.1 gdamore if (m->m_pkthdr.len < sizeof(b)) {
899 1.1 gdamore DPRINTF("Short MCC header, discarded\n");
900 1.1 gdamore goto release;
901 1.1 gdamore }
902 1.1 gdamore
903 1.1 gdamore m_copydata(m, 0, sizeof(b), &b);
904 1.1 gdamore m_adj(m, sizeof(b));
905 1.1 gdamore
906 1.1 gdamore if (RFCOMM_EA(b) == 0) { /* verify no extensions */
907 1.1 gdamore DPRINTF("MCC type EA = 1, discarded\n");
908 1.1 gdamore goto release;
909 1.1 gdamore }
910 1.1 gdamore
911 1.1 gdamore type = RFCOMM_MCC_TYPE(b);
912 1.1 gdamore cr = RFCOMM_CR(b);
913 1.1 gdamore
914 1.1 gdamore len = 0;
915 1.1 gdamore do {
916 1.1 gdamore if (m->m_pkthdr.len < sizeof(b)) {
917 1.1 gdamore DPRINTF("Short MCC header, discarded\n");
918 1.1 gdamore goto release;
919 1.1 gdamore }
920 1.1 gdamore
921 1.1 gdamore m_copydata(m, 0, sizeof(b), &b);
922 1.1 gdamore m_adj(m, sizeof(b));
923 1.1 gdamore
924 1.1 gdamore len = (len << 7) | (b >> 1);
925 1.1 gdamore len = min(len, RFCOMM_MTU_MAX);
926 1.1 gdamore } while (RFCOMM_EA(b) == 0);
927 1.1 gdamore
928 1.1 gdamore if (len != m->m_pkthdr.len) {
929 1.1 gdamore DPRINTF("Incorrect MCC length, discarded\n");
930 1.1 gdamore goto release;
931 1.1 gdamore }
932 1.1 gdamore
933 1.1 gdamore DPRINTFN(2, "MCC %s type %2.2x (%d bytes)\n",
934 1.1 gdamore (cr ? "command" : "response"), type, len);
935 1.1 gdamore
936 1.1 gdamore /*
937 1.1 gdamore * pass to command handler
938 1.1 gdamore */
939 1.1 gdamore switch(type) {
940 1.1 gdamore case RFCOMM_MCC_TEST: /* Test */
941 1.1 gdamore rfcomm_session_recv_mcc_test(rs, cr, m);
942 1.1 gdamore break;
943 1.1 gdamore
944 1.1 gdamore case RFCOMM_MCC_FCON: /* Flow Control On */
945 1.1 gdamore rfcomm_session_recv_mcc_fcon(rs, cr);
946 1.1 gdamore break;
947 1.1 gdamore
948 1.1 gdamore case RFCOMM_MCC_FCOFF: /* Flow Control Off */
949 1.1 gdamore rfcomm_session_recv_mcc_fcoff(rs, cr);
950 1.1 gdamore break;
951 1.1 gdamore
952 1.1 gdamore case RFCOMM_MCC_MSC: /* Modem Status Command */
953 1.1 gdamore rfcomm_session_recv_mcc_msc(rs, cr, m);
954 1.1 gdamore break;
955 1.1 gdamore
956 1.1 gdamore case RFCOMM_MCC_RPN: /* Remote Port Negotiation */
957 1.1 gdamore rfcomm_session_recv_mcc_rpn(rs, cr, m);
958 1.1 gdamore break;
959 1.1 gdamore
960 1.1 gdamore case RFCOMM_MCC_RLS: /* Remote Line Status */
961 1.1 gdamore rfcomm_session_recv_mcc_rls(rs, cr, m);
962 1.1 gdamore break;
963 1.1 gdamore
964 1.1 gdamore case RFCOMM_MCC_PN: /* Parameter Negotiation */
965 1.1 gdamore rfcomm_session_recv_mcc_pn(rs, cr, m);
966 1.1 gdamore break;
967 1.1 gdamore
968 1.1 gdamore case RFCOMM_MCC_NSC: /* Non Supported Command */
969 1.1 gdamore rfcomm_session_recv_mcc_nsc(rs, cr, m);
970 1.1 gdamore break;
971 1.1 gdamore
972 1.1 gdamore default:
973 1.1 gdamore b = RFCOMM_MKMCC_TYPE(cr, type);
974 1.1 gdamore rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_NSC, &b, sizeof(b));
975 1.1 gdamore }
976 1.1 gdamore
977 1.1 gdamore release:
978 1.1 gdamore m_freem(m);
979 1.1 gdamore }
980 1.1 gdamore
981 1.1 gdamore /*
982 1.1 gdamore * process TEST command/response
983 1.1 gdamore */
984 1.1 gdamore static void
985 1.1 gdamore rfcomm_session_recv_mcc_test(struct rfcomm_session *rs, int cr, struct mbuf *m)
986 1.1 gdamore {
987 1.1 gdamore void *data;
988 1.1 gdamore int len;
989 1.1 gdamore
990 1.1 gdamore if (cr == 0) /* ignore ack */
991 1.1 gdamore return;
992 1.1 gdamore
993 1.1 gdamore /*
994 1.1 gdamore * we must send all the data they included back as is
995 1.1 gdamore */
996 1.1 gdamore
997 1.1 gdamore len = m->m_pkthdr.len;
998 1.1 gdamore if (len > RFCOMM_MTU_MAX)
999 1.1 gdamore return;
1000 1.1 gdamore
1001 1.1 gdamore data = malloc(len, M_BLUETOOTH, M_NOWAIT);
1002 1.1 gdamore if (data == NULL)
1003 1.1 gdamore return;
1004 1.1 gdamore
1005 1.1 gdamore m_copydata(m, 0, len, data);
1006 1.1 gdamore rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_TEST, data, len);
1007 1.1 gdamore free(data, M_BLUETOOTH);
1008 1.1 gdamore }
1009 1.1 gdamore
1010 1.1 gdamore /*
1011 1.1 gdamore * process Flow Control ON command/response
1012 1.1 gdamore */
1013 1.1 gdamore static void
1014 1.1 gdamore rfcomm_session_recv_mcc_fcon(struct rfcomm_session *rs, int cr)
1015 1.1 gdamore {
1016 1.1 gdamore
1017 1.1 gdamore if (cr == 0) /* ignore ack */
1018 1.1 gdamore return;
1019 1.1 gdamore
1020 1.1 gdamore rs->rs_flags |= RFCOMM_SESSION_RFC;
1021 1.1 gdamore rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_FCON, NULL, 0);
1022 1.1 gdamore }
1023 1.1 gdamore
1024 1.1 gdamore /*
1025 1.1 gdamore * process Flow Control OFF command/response
1026 1.1 gdamore */
1027 1.1 gdamore static void
1028 1.1 gdamore rfcomm_session_recv_mcc_fcoff(struct rfcomm_session *rs, int cr)
1029 1.1 gdamore {
1030 1.1 gdamore
1031 1.1 gdamore if (cr == 0) /* ignore ack */
1032 1.1 gdamore return;
1033 1.1 gdamore
1034 1.1 gdamore rs->rs_flags &= ~RFCOMM_SESSION_RFC;
1035 1.1 gdamore rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_FCOFF, NULL, 0);
1036 1.1 gdamore }
1037 1.1 gdamore
1038 1.1 gdamore /*
1039 1.1 gdamore * process Modem Status Command command/response
1040 1.1 gdamore */
1041 1.1 gdamore static void
1042 1.1 gdamore rfcomm_session_recv_mcc_msc(struct rfcomm_session *rs, int cr, struct mbuf *m)
1043 1.1 gdamore {
1044 1.1 gdamore struct rfcomm_mcc_msc msc; /* (3 octets) */
1045 1.1 gdamore struct rfcomm_dlc *dlc;
1046 1.1 gdamore int len = 0;
1047 1.1 gdamore
1048 1.1 gdamore /* [ADDRESS] */
1049 1.1 gdamore if (m->m_pkthdr.len < sizeof(msc.address))
1050 1.1 gdamore return;
1051 1.1 gdamore
1052 1.1 gdamore m_copydata(m, 0, sizeof(msc.address), &msc.address);
1053 1.1 gdamore m_adj(m, sizeof(msc.address));
1054 1.1 gdamore len += sizeof(msc.address);
1055 1.1 gdamore
1056 1.1 gdamore dlc = rfcomm_dlc_lookup(rs, RFCOMM_DLCI(msc.address));
1057 1.1 gdamore
1058 1.1 gdamore if (cr == 0) { /* ignore acks */
1059 1.1 gdamore if (dlc != NULL)
1060 1.1 gdamore callout_stop(&dlc->rd_timeout);
1061 1.1 gdamore
1062 1.1 gdamore return;
1063 1.1 gdamore }
1064 1.1 gdamore
1065 1.1 gdamore if (dlc == NULL) {
1066 1.1 gdamore rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM,
1067 1.1 gdamore RFCOMM_DLCI(msc.address));
1068 1.1 gdamore return;
1069 1.1 gdamore }
1070 1.1 gdamore
1071 1.1 gdamore /* [SIGNALS] */
1072 1.1 gdamore if (m->m_pkthdr.len < sizeof(msc.modem))
1073 1.1 gdamore return;
1074 1.1 gdamore
1075 1.1 gdamore m_copydata(m, 0, sizeof(msc.modem), &msc.modem);
1076 1.1 gdamore m_adj(m, sizeof(msc.modem));
1077 1.1 gdamore len += sizeof(msc.modem);
1078 1.1 gdamore
1079 1.1 gdamore dlc->rd_rmodem = msc.modem;
1080 1.7 plunky /* XXX how do we signal this upstream? */
1081 1.1 gdamore
1082 1.1 gdamore if (RFCOMM_EA(msc.modem) == 0) {
1083 1.1 gdamore if (m->m_pkthdr.len < sizeof(msc.brk))
1084 1.1 gdamore return;
1085 1.1 gdamore
1086 1.1 gdamore m_copydata(m, 0, sizeof(msc.brk), &msc.brk);
1087 1.1 gdamore m_adj(m, sizeof(msc.brk));
1088 1.1 gdamore len += sizeof(msc.brk);
1089 1.1 gdamore
1090 1.7 plunky /* XXX how do we signal this upstream? */
1091 1.1 gdamore }
1092 1.1 gdamore
1093 1.1 gdamore rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_MSC, &msc, len);
1094 1.1 gdamore }
1095 1.1 gdamore
1096 1.1 gdamore /*
1097 1.1 gdamore * process Remote Port Negotiation command/response
1098 1.1 gdamore */
1099 1.1 gdamore static void
1100 1.1 gdamore rfcomm_session_recv_mcc_rpn(struct rfcomm_session *rs, int cr, struct mbuf *m)
1101 1.1 gdamore {
1102 1.1 gdamore struct rfcomm_mcc_rpn rpn;
1103 1.1 gdamore uint16_t mask;
1104 1.1 gdamore
1105 1.1 gdamore if (cr == 0) /* ignore ack */
1106 1.1 gdamore return;
1107 1.1 gdamore
1108 1.1 gdamore /* default values */
1109 1.1 gdamore rpn.bit_rate = RFCOMM_RPN_BR_9600;
1110 1.1 gdamore rpn.line_settings = RFCOMM_RPN_8_N_1;
1111 1.1 gdamore rpn.flow_control = RFCOMM_RPN_FLOW_NONE;
1112 1.1 gdamore rpn.xon_char = RFCOMM_RPN_XON_CHAR;
1113 1.1 gdamore rpn.xoff_char = RFCOMM_RPN_XOFF_CHAR;
1114 1.1 gdamore
1115 1.1 gdamore if (m->m_pkthdr.len == sizeof(rpn)) {
1116 1.1 gdamore m_copydata(m, 0, sizeof(rpn), &rpn);
1117 1.1 gdamore rpn.param_mask = RFCOMM_RPN_PM_ALL;
1118 1.1 gdamore } else if (m->m_pkthdr.len == 1) {
1119 1.1 gdamore m_copydata(m, 0, 1, &rpn);
1120 1.1 gdamore rpn.param_mask = le16toh(rpn.param_mask);
1121 1.1 gdamore } else {
1122 1.1 gdamore DPRINTF("Bad RPN length (%d)\n", m->m_pkthdr.len);
1123 1.1 gdamore return;
1124 1.1 gdamore }
1125 1.1 gdamore
1126 1.1 gdamore mask = 0;
1127 1.1 gdamore
1128 1.1 gdamore if (rpn.param_mask & RFCOMM_RPN_PM_RATE)
1129 1.1 gdamore mask |= RFCOMM_RPN_PM_RATE;
1130 1.1 gdamore
1131 1.1 gdamore if (rpn.param_mask & RFCOMM_RPN_PM_DATA
1132 1.1 gdamore && RFCOMM_RPN_DATA_BITS(rpn.line_settings) == RFCOMM_RPN_DATA_8)
1133 1.1 gdamore mask |= RFCOMM_RPN_PM_DATA;
1134 1.1 gdamore
1135 1.1 gdamore if (rpn.param_mask & RFCOMM_RPN_PM_STOP
1136 1.1 gdamore && RFCOMM_RPN_STOP_BITS(rpn.line_settings) == RFCOMM_RPN_STOP_1)
1137 1.1 gdamore mask |= RFCOMM_RPN_PM_STOP;
1138 1.1 gdamore
1139 1.1 gdamore if (rpn.param_mask & RFCOMM_RPN_PM_PARITY
1140 1.1 gdamore && RFCOMM_RPN_PARITY(rpn.line_settings) == RFCOMM_RPN_PARITY_NONE)
1141 1.1 gdamore mask |= RFCOMM_RPN_PM_PARITY;
1142 1.1 gdamore
1143 1.1 gdamore if (rpn.param_mask & RFCOMM_RPN_PM_XON
1144 1.1 gdamore && rpn.xon_char == RFCOMM_RPN_XON_CHAR)
1145 1.1 gdamore mask |= RFCOMM_RPN_PM_XON;
1146 1.1 gdamore
1147 1.1 gdamore if (rpn.param_mask & RFCOMM_RPN_PM_XOFF
1148 1.1 gdamore && rpn.xoff_char == RFCOMM_RPN_XOFF_CHAR)
1149 1.1 gdamore mask |= RFCOMM_RPN_PM_XOFF;
1150 1.1 gdamore
1151 1.1 gdamore if (rpn.param_mask & RFCOMM_RPN_PM_FLOW
1152 1.1 gdamore && rpn.flow_control == RFCOMM_RPN_FLOW_NONE)
1153 1.1 gdamore mask |= RFCOMM_RPN_PM_FLOW;
1154 1.1 gdamore
1155 1.1 gdamore rpn.param_mask = htole16(mask);
1156 1.1 gdamore
1157 1.1 gdamore rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_RPN, &rpn, sizeof(rpn));
1158 1.1 gdamore }
1159 1.1 gdamore
1160 1.1 gdamore /*
1161 1.1 gdamore * process Remote Line Status command/response
1162 1.1 gdamore */
1163 1.1 gdamore static void
1164 1.1 gdamore rfcomm_session_recv_mcc_rls(struct rfcomm_session *rs, int cr, struct mbuf *m)
1165 1.1 gdamore {
1166 1.1 gdamore struct rfcomm_mcc_rls rls;
1167 1.1 gdamore
1168 1.1 gdamore if (cr == 0) /* ignore ack */
1169 1.1 gdamore return;
1170 1.1 gdamore
1171 1.1 gdamore if (m->m_pkthdr.len != sizeof(rls)) {
1172 1.1 gdamore DPRINTF("Bad RLS length %d\n", m->m_pkthdr.len);
1173 1.1 gdamore return;
1174 1.1 gdamore }
1175 1.1 gdamore
1176 1.1 gdamore m_copydata(m, 0, sizeof(rls), &rls);
1177 1.1 gdamore
1178 1.1 gdamore /*
1179 1.1 gdamore * So far as I can tell, we just send back what
1180 1.1 gdamore * they sent us. This signifies errors that seem
1181 1.1 gdamore * irrelevent for RFCOMM over L2CAP.
1182 1.1 gdamore */
1183 1.1 gdamore rls.address |= 0x03; /* EA = 1, CR = 1 */
1184 1.1 gdamore rls.status &= 0x0f; /* only 4 bits valid */
1185 1.1 gdamore
1186 1.1 gdamore rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_RLS, &rls, sizeof(rls));
1187 1.1 gdamore }
1188 1.1 gdamore
1189 1.1 gdamore /*
1190 1.1 gdamore * process Parameter Negotiation command/response
1191 1.1 gdamore */
1192 1.1 gdamore static void
1193 1.1 gdamore rfcomm_session_recv_mcc_pn(struct rfcomm_session *rs, int cr, struct mbuf *m)
1194 1.1 gdamore {
1195 1.1 gdamore struct rfcomm_dlc *dlc;
1196 1.1 gdamore struct rfcomm_mcc_pn pn;
1197 1.1 gdamore int err;
1198 1.1 gdamore
1199 1.1 gdamore if (m->m_pkthdr.len != sizeof(pn)) {
1200 1.1 gdamore DPRINTF("Bad PN length %d\n", m->m_pkthdr.len);
1201 1.1 gdamore return;
1202 1.1 gdamore }
1203 1.1 gdamore
1204 1.1 gdamore m_copydata(m, 0, sizeof(pn), &pn);
1205 1.1 gdamore
1206 1.1 gdamore pn.dlci &= 0x3f;
1207 1.1 gdamore pn.mtu = le16toh(pn.mtu);
1208 1.1 gdamore
1209 1.1 gdamore dlc = rfcomm_dlc_lookup(rs, pn.dlci);
1210 1.1 gdamore if (cr) { /* Command */
1211 1.1 gdamore /*
1212 1.1 gdamore * If there is no DLC present, this is a new
1213 1.1 gdamore * connection so attempt to make one
1214 1.1 gdamore */
1215 1.1 gdamore if (dlc == NULL) {
1216 1.1 gdamore dlc = rfcomm_dlc_newconn(rs, pn.dlci);
1217 1.1 gdamore if (dlc == NULL)
1218 1.1 gdamore return; /* (DM is sent) */
1219 1.1 gdamore }
1220 1.1 gdamore
1221 1.1 gdamore /* accept any valid MTU, and offer it back */
1222 1.1 gdamore pn.mtu = min(pn.mtu, RFCOMM_MTU_MAX);
1223 1.1 gdamore pn.mtu = min(pn.mtu, rs->rs_mtu);
1224 1.1 gdamore pn.mtu = max(pn.mtu, RFCOMM_MTU_MIN);
1225 1.1 gdamore dlc->rd_mtu = pn.mtu;
1226 1.1 gdamore pn.mtu = htole16(pn.mtu);
1227 1.1 gdamore
1228 1.1 gdamore /* credits are only set before DLC is open */
1229 1.1 gdamore if (dlc->rd_state == RFCOMM_DLC_WAIT_CONNECT
1230 1.1 gdamore && (pn.flow_control & 0xf0) == 0xf0) {
1231 1.1 gdamore rs->rs_flags |= RFCOMM_SESSION_CFC;
1232 1.1 gdamore dlc->rd_txcred = pn.credits & 0x07;
1233 1.1 gdamore
1234 1.1 gdamore dlc->rd_rxcred = (dlc->rd_rxsize / dlc->rd_mtu);
1235 1.1 gdamore dlc->rd_rxcred = min(dlc->rd_rxcred,
1236 1.1 gdamore RFCOMM_CREDITS_DEFAULT);
1237 1.1 gdamore
1238 1.1 gdamore pn.flow_control = 0xe0;
1239 1.1 gdamore pn.credits = dlc->rd_rxcred;
1240 1.1 gdamore } else {
1241 1.1 gdamore pn.flow_control = 0x00;
1242 1.1 gdamore pn.credits = 0x00;
1243 1.1 gdamore }
1244 1.1 gdamore
1245 1.1 gdamore /* unused fields must be ignored and set to zero */
1246 1.1 gdamore pn.ack_timer = 0;
1247 1.1 gdamore pn.max_retrans = 0;
1248 1.1 gdamore
1249 1.1 gdamore /* send our response */
1250 1.1 gdamore err = rfcomm_session_send_mcc(rs, 0,
1251 1.1 gdamore RFCOMM_MCC_PN, &pn, sizeof(pn));
1252 1.1 gdamore if (err)
1253 1.1 gdamore goto close;
1254 1.1 gdamore
1255 1.1 gdamore } else { /* Response */
1256 1.1 gdamore /* ignore responses with no matching DLC */
1257 1.1 gdamore if (dlc == NULL)
1258 1.1 gdamore return;
1259 1.1 gdamore
1260 1.1 gdamore callout_stop(&dlc->rd_timeout);
1261 1.1 gdamore
1262 1.1 gdamore if (pn.mtu > RFCOMM_MTU_MAX || pn.mtu > dlc->rd_mtu) {
1263 1.1 gdamore dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
1264 1.1 gdamore err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
1265 1.1 gdamore pn.dlci);
1266 1.1 gdamore if (err)
1267 1.1 gdamore goto close;
1268 1.1 gdamore
1269 1.1 gdamore callout_schedule(&dlc->rd_timeout,
1270 1.1 gdamore rfcomm_ack_timeout * hz);
1271 1.1 gdamore return;
1272 1.1 gdamore }
1273 1.1 gdamore dlc->rd_mtu = pn.mtu;
1274 1.1 gdamore
1275 1.1 gdamore /* initial credits can only be set before DLC is open */
1276 1.1 gdamore if (dlc->rd_state == RFCOMM_DLC_WAIT_CONNECT
1277 1.1 gdamore && (pn.flow_control & 0xf0) == 0xe0) {
1278 1.1 gdamore rs->rs_flags |= RFCOMM_SESSION_CFC;
1279 1.1 gdamore dlc->rd_txcred = (pn.credits & 0x07);
1280 1.1 gdamore }
1281 1.1 gdamore
1282 1.1 gdamore /* Ok, lets go with it */
1283 1.1 gdamore err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_SABM, pn.dlci);
1284 1.1 gdamore if (err)
1285 1.1 gdamore goto close;
1286 1.1 gdamore
1287 1.1 gdamore callout_schedule(&dlc->rd_timeout, rfcomm_ack_timeout * hz);
1288 1.1 gdamore }
1289 1.1 gdamore return;
1290 1.1 gdamore
1291 1.1 gdamore close:
1292 1.1 gdamore rfcomm_dlc_close(dlc, err);
1293 1.1 gdamore }
1294 1.1 gdamore
1295 1.1 gdamore /*
1296 1.1 gdamore * process Non Supported Command command/response
1297 1.1 gdamore */
1298 1.1 gdamore static void
1299 1.3 christos rfcomm_session_recv_mcc_nsc(struct rfcomm_session *rs,
1300 1.4 christos int cr, struct mbuf *m)
1301 1.1 gdamore {
1302 1.2 plunky struct rfcomm_dlc *dlc, *next;
1303 1.1 gdamore
1304 1.1 gdamore /*
1305 1.1 gdamore * Since we did nothing that is not mandatory,
1306 1.1 gdamore * we just abort the whole session..
1307 1.1 gdamore */
1308 1.2 plunky
1309 1.2 plunky next = LIST_FIRST(&rs->rs_dlcs);
1310 1.2 plunky while ((dlc = next) != NULL) {
1311 1.2 plunky next = LIST_NEXT(dlc, rd_next);
1312 1.1 gdamore rfcomm_dlc_close(dlc, ECONNABORTED);
1313 1.2 plunky }
1314 1.1 gdamore
1315 1.1 gdamore rfcomm_session_free(rs);
1316 1.1 gdamore }
1317 1.1 gdamore
1318 1.1 gdamore /***********************************************************************
1319 1.1 gdamore *
1320 1.1 gdamore * RFCOMM Session outward frame/uih/mcc building
1321 1.1 gdamore */
1322 1.1 gdamore
1323 1.1 gdamore /*
1324 1.1 gdamore * SABM/DISC/DM/UA frames are all minimal and mostly identical.
1325 1.1 gdamore */
1326 1.1 gdamore int
1327 1.1 gdamore rfcomm_session_send_frame(struct rfcomm_session *rs, int type, int dlci)
1328 1.1 gdamore {
1329 1.1 gdamore struct rfcomm_cmd_hdr *hdr;
1330 1.1 gdamore struct rfcomm_credit *credit;
1331 1.1 gdamore struct mbuf *m;
1332 1.1 gdamore uint8_t fcs, cr;
1333 1.1 gdamore
1334 1.1 gdamore credit = pool_get(&rfcomm_credit_pool, PR_NOWAIT);
1335 1.1 gdamore if (credit == NULL)
1336 1.1 gdamore return ENOMEM;
1337 1.1 gdamore
1338 1.1 gdamore m = m_gethdr(M_DONTWAIT, MT_DATA);
1339 1.1 gdamore if (m == NULL) {
1340 1.1 gdamore pool_put(&rfcomm_credit_pool, credit);
1341 1.1 gdamore return ENOMEM;
1342 1.1 gdamore }
1343 1.1 gdamore
1344 1.1 gdamore /*
1345 1.1 gdamore * The CR (command/response) bit identifies the frame either as a
1346 1.1 gdamore * commmand or a response and is used along with the DLCI to form
1347 1.1 gdamore * the address. Commands contain the non-initiator address, whereas
1348 1.1 gdamore * responses contain the initiator address, so the CR value is
1349 1.1 gdamore * also dependent on the session direction.
1350 1.1 gdamore */
1351 1.1 gdamore if (type == RFCOMM_FRAME_UA || type == RFCOMM_FRAME_DM)
1352 1.1 gdamore cr = IS_INITIATOR(rs) ? 0 : 1;
1353 1.1 gdamore else
1354 1.1 gdamore cr = IS_INITIATOR(rs) ? 1 : 0;
1355 1.1 gdamore
1356 1.1 gdamore hdr = mtod(m, struct rfcomm_cmd_hdr *);
1357 1.1 gdamore hdr->address = RFCOMM_MKADDRESS(cr, dlci);
1358 1.1 gdamore hdr->control = RFCOMM_MKCONTROL(type, 1); /* PF = 1 */
1359 1.1 gdamore hdr->length = (0x00 << 1) | 0x01; /* len = 0x00, EA = 1 */
1360 1.1 gdamore
1361 1.1 gdamore fcs = 0xff;
1362 1.1 gdamore fcs = FCS(fcs, hdr->address);
1363 1.1 gdamore fcs = FCS(fcs, hdr->control);
1364 1.1 gdamore fcs = FCS(fcs, hdr->length);
1365 1.1 gdamore fcs = 0xff - fcs; /* ones complement */
1366 1.1 gdamore hdr->fcs = fcs;
1367 1.1 gdamore
1368 1.1 gdamore m->m_pkthdr.len = m->m_len = sizeof(struct rfcomm_cmd_hdr);
1369 1.1 gdamore
1370 1.1 gdamore /* empty credit note */
1371 1.1 gdamore credit->rc_dlc = NULL;
1372 1.1 gdamore credit->rc_len = m->m_pkthdr.len;
1373 1.1 gdamore SIMPLEQ_INSERT_TAIL(&rs->rs_credits, credit, rc_next);
1374 1.1 gdamore
1375 1.1 gdamore DPRINTFN(5, "dlci %d type %2.2x (%d bytes, fcs=%#2.2x)\n",
1376 1.1 gdamore dlci, type, m->m_pkthdr.len, fcs);
1377 1.1 gdamore
1378 1.1 gdamore return l2cap_send(rs->rs_l2cap, m);
1379 1.1 gdamore }
1380 1.1 gdamore
1381 1.1 gdamore /*
1382 1.1 gdamore * rfcomm_session_send_uih(rfcomm_session, rfcomm_dlc, credits, mbuf)
1383 1.1 gdamore *
1384 1.1 gdamore * UIH frame is per DLC data or Multiplexer Control Commands
1385 1.1 gdamore * when no DLC is given. Data mbuf is optional (just credits
1386 1.1 gdamore * will be sent in that case)
1387 1.1 gdamore */
1388 1.1 gdamore int
1389 1.1 gdamore rfcomm_session_send_uih(struct rfcomm_session *rs, struct rfcomm_dlc *dlc,
1390 1.1 gdamore int credits, struct mbuf *m)
1391 1.1 gdamore {
1392 1.1 gdamore struct rfcomm_credit *credit;
1393 1.1 gdamore struct mbuf *m0 = NULL;
1394 1.1 gdamore int err, len;
1395 1.1 gdamore uint8_t fcs, *hdr;
1396 1.1 gdamore
1397 1.1 gdamore KASSERT(rs != NULL);
1398 1.1 gdamore
1399 1.1 gdamore len = (m == NULL) ? 0 : m->m_pkthdr.len;
1400 1.1 gdamore KASSERT(!(credits == 0 && len == 0));
1401 1.1 gdamore
1402 1.1 gdamore /*
1403 1.1 gdamore * Make a credit note for the completion notification
1404 1.1 gdamore */
1405 1.1 gdamore credit = pool_get(&rfcomm_credit_pool, PR_NOWAIT);
1406 1.1 gdamore if (credit == NULL)
1407 1.1 gdamore goto nomem;
1408 1.1 gdamore
1409 1.1 gdamore credit->rc_len = len;
1410 1.1 gdamore credit->rc_dlc = dlc;
1411 1.1 gdamore
1412 1.1 gdamore /*
1413 1.1 gdamore * Wrap UIH frame information around payload.
1414 1.1 gdamore *
1415 1.1 gdamore * [ADDRESS] [CONTROL] [LENGTH] [CREDITS] [...] [FCS]
1416 1.1 gdamore *
1417 1.1 gdamore * Address is one octet.
1418 1.1 gdamore * Control is one octet.
1419 1.1 gdamore * Length is one or two octets.
1420 1.1 gdamore * Credits may be one octet.
1421 1.1 gdamore *
1422 1.1 gdamore * FCS is one octet and calculated on address and
1423 1.1 gdamore * control octets only.
1424 1.1 gdamore *
1425 1.1 gdamore * If there are credits to be sent, we will set the PF
1426 1.1 gdamore * flag and include them in the frame.
1427 1.1 gdamore */
1428 1.1 gdamore m0 = m_gethdr(M_DONTWAIT, MT_DATA);
1429 1.1 gdamore if (m0 == NULL)
1430 1.1 gdamore goto nomem;
1431 1.1 gdamore
1432 1.1 gdamore MH_ALIGN(m0, 5); /* (max 5 header octets) */
1433 1.1 gdamore hdr = mtod(m0, uint8_t *);
1434 1.1 gdamore
1435 1.1 gdamore /* CR bit is set according to the initiator of the session */
1436 1.1 gdamore *hdr = RFCOMM_MKADDRESS((IS_INITIATOR(rs) ? 1 : 0),
1437 1.1 gdamore (dlc ? dlc->rd_dlci : 0));
1438 1.1 gdamore fcs = FCS(0xff, *hdr);
1439 1.1 gdamore hdr++;
1440 1.1 gdamore
1441 1.1 gdamore /* PF bit is set if credits are being sent */
1442 1.1 gdamore *hdr = RFCOMM_MKCONTROL(RFCOMM_FRAME_UIH, (credits > 0 ? 1 : 0));
1443 1.1 gdamore fcs = FCS(fcs, *hdr);
1444 1.1 gdamore hdr++;
1445 1.1 gdamore
1446 1.1 gdamore if (len < (1 << 7)) {
1447 1.1 gdamore *hdr++ = ((len << 1) & 0xfe) | 0x01; /* 7 bits, EA = 1 */
1448 1.1 gdamore } else {
1449 1.1 gdamore *hdr++ = ((len << 1) & 0xfe); /* 7 bits, EA = 0 */
1450 1.1 gdamore *hdr++ = ((len >> 7) & 0xff); /* 8 bits, no EA */
1451 1.1 gdamore }
1452 1.1 gdamore
1453 1.1 gdamore if (credits > 0)
1454 1.1 gdamore *hdr++ = (uint8_t)credits;
1455 1.1 gdamore
1456 1.1 gdamore m0->m_len = hdr - mtod(m0, uint8_t *);
1457 1.1 gdamore
1458 1.1 gdamore /* Append payload */
1459 1.1 gdamore m0->m_next = m;
1460 1.1 gdamore m = NULL;
1461 1.1 gdamore
1462 1.1 gdamore m0->m_pkthdr.len = m0->m_len + len;
1463 1.1 gdamore
1464 1.1 gdamore /* Append FCS */
1465 1.1 gdamore fcs = 0xff - fcs; /* ones complement */
1466 1.1 gdamore len = m0->m_pkthdr.len;
1467 1.1 gdamore m_copyback(m0, len, sizeof(fcs), &fcs);
1468 1.1 gdamore if (m0->m_pkthdr.len != len + sizeof(fcs))
1469 1.1 gdamore goto nomem;
1470 1.1 gdamore
1471 1.1 gdamore DPRINTFN(10, "dlci %d, pktlen %d (%d data, %d credits), fcs=%#2.2x\n",
1472 1.1 gdamore dlc ? dlc->rd_dlci : 0, m0->m_pkthdr.len, credit->rc_len,
1473 1.1 gdamore credits, fcs);
1474 1.1 gdamore
1475 1.1 gdamore /*
1476 1.1 gdamore * UIH frame ready to go..
1477 1.1 gdamore */
1478 1.1 gdamore err = l2cap_send(rs->rs_l2cap, m0);
1479 1.1 gdamore if (err)
1480 1.1 gdamore goto fail;
1481 1.1 gdamore
1482 1.1 gdamore SIMPLEQ_INSERT_TAIL(&rs->rs_credits, credit, rc_next);
1483 1.1 gdamore return 0;
1484 1.1 gdamore
1485 1.1 gdamore nomem:
1486 1.1 gdamore err = ENOMEM;
1487 1.1 gdamore
1488 1.1 gdamore if (m0 != NULL)
1489 1.1 gdamore m_freem(m0);
1490 1.1 gdamore
1491 1.1 gdamore if (m != NULL)
1492 1.1 gdamore m_freem(m);
1493 1.1 gdamore
1494 1.1 gdamore fail:
1495 1.1 gdamore if (credit != NULL)
1496 1.1 gdamore pool_put(&rfcomm_credit_pool, credit);
1497 1.1 gdamore
1498 1.1 gdamore return err;
1499 1.1 gdamore }
1500 1.1 gdamore
1501 1.1 gdamore /*
1502 1.1 gdamore * send Multiplexer Control Command (or Response) on session
1503 1.1 gdamore */
1504 1.1 gdamore int
1505 1.1 gdamore rfcomm_session_send_mcc(struct rfcomm_session *rs, int cr,
1506 1.1 gdamore uint8_t type, void *data, int len)
1507 1.1 gdamore {
1508 1.1 gdamore struct mbuf *m;
1509 1.1 gdamore uint8_t *hdr;
1510 1.1 gdamore int hlen;
1511 1.1 gdamore
1512 1.1 gdamore m = m_gethdr(M_DONTWAIT, MT_DATA);
1513 1.1 gdamore if (m == NULL)
1514 1.1 gdamore return ENOMEM;
1515 1.1 gdamore
1516 1.1 gdamore hdr = mtod(m, uint8_t *);
1517 1.1 gdamore
1518 1.1 gdamore /*
1519 1.1 gdamore * Technically the type field can extend past one octet, but none
1520 1.1 gdamore * currently defined will do that.
1521 1.1 gdamore */
1522 1.1 gdamore *hdr++ = RFCOMM_MKMCC_TYPE(cr, type);
1523 1.1 gdamore
1524 1.1 gdamore /*
1525 1.1 gdamore * In the frame, the max length size is 2 octets (15 bits) whereas
1526 1.1 gdamore * no max length size is specified for MCC commands. We must allow
1527 1.1 gdamore * for 3 octets since for MCC frames we use 7 bits + EA in each.
1528 1.1 gdamore *
1529 1.1 gdamore * Only test data can possibly be that big.
1530 1.1 gdamore *
1531 1.1 gdamore * XXX Should we check this against the MTU?
1532 1.1 gdamore */
1533 1.1 gdamore if (len < (1 << 7)) {
1534 1.1 gdamore *hdr++ = ((len << 1) & 0xfe) | 0x01; /* 7 bits, EA = 1 */
1535 1.1 gdamore } else if (len < (1 << 14)) {
1536 1.1 gdamore *hdr++ = ((len << 1) & 0xfe); /* 7 bits, EA = 0 */
1537 1.1 gdamore *hdr++ = ((len >> 6) & 0xfe) | 0x01; /* 7 bits, EA = 1 */
1538 1.1 gdamore } else if (len < (1 << 15)) {
1539 1.1 gdamore *hdr++ = ((len << 1) & 0xfe); /* 7 bits, EA = 0 */
1540 1.1 gdamore *hdr++ = ((len >> 6) & 0xfe); /* 7 bits, EA = 0 */
1541 1.1 gdamore *hdr++ = ((len >> 13) & 0x02) | 0x01; /* 1 bit, EA = 1 */
1542 1.1 gdamore } else {
1543 1.1 gdamore DPRINTF("incredible length! (%d)\n", len);
1544 1.1 gdamore m_freem(m);
1545 1.1 gdamore return EMSGSIZE;
1546 1.1 gdamore }
1547 1.1 gdamore
1548 1.1 gdamore /*
1549 1.1 gdamore * add command data (to same mbuf if possible)
1550 1.1 gdamore */
1551 1.1 gdamore hlen = hdr - mtod(m, uint8_t *);
1552 1.1 gdamore
1553 1.1 gdamore if (len > 0) {
1554 1.1 gdamore m->m_pkthdr.len = m->m_len = MHLEN;
1555 1.1 gdamore m_copyback(m, hlen, len, data);
1556 1.1 gdamore if (m->m_pkthdr.len != max(MHLEN, hlen + len)) {
1557 1.1 gdamore m_freem(m);
1558 1.1 gdamore return ENOMEM;
1559 1.1 gdamore }
1560 1.1 gdamore }
1561 1.1 gdamore
1562 1.1 gdamore m->m_pkthdr.len = hlen + len;
1563 1.1 gdamore m->m_len = min(MHLEN, m->m_pkthdr.len);
1564 1.1 gdamore
1565 1.1 gdamore DPRINTFN(5, "%s type %2.2x len %d\n",
1566 1.1 gdamore (cr ? "command" : "response"), type, m->m_pkthdr.len);
1567 1.1 gdamore
1568 1.1 gdamore return rfcomm_session_send_uih(rs, NULL, 0, m);
1569 1.1 gdamore }
1570