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