1114878Sjulian/* 2114878Sjulian * ng_btsocket_rfcomm.c 3139823Simp */ 4139823Simp 5139823Simp/*- 6114878Sjulian * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> 7114878Sjulian * All rights reserved. 8114878Sjulian * 9114878Sjulian * Redistribution and use in source and binary forms, with or without 10114878Sjulian * modification, are permitted provided that the following conditions 11114878Sjulian * are met: 12114878Sjulian * 1. Redistributions of source code must retain the above copyright 13114878Sjulian * notice, this list of conditions and the following disclaimer. 14114878Sjulian * 2. Redistributions in binary form must reproduce the above copyright 15114878Sjulian * notice, this list of conditions and the following disclaimer in the 16114878Sjulian * documentation and/or other materials provided with the distribution. 17114878Sjulian * 18114878Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19114878Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20114878Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21114878Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22114878Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23114878Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24114878Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25114878Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26114878Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27114878Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28114878Sjulian * SUCH DAMAGE. 29114878Sjulian * 30121054Semax * $Id: ng_btsocket_rfcomm.c,v 1.28 2003/09/14 23:29:06 max Exp $ 31114878Sjulian * $FreeBSD$ 32114878Sjulian */ 33114878Sjulian 34114878Sjulian#include <sys/param.h> 35114878Sjulian#include <sys/systm.h> 36121054Semax#include <sys/bitstring.h> 37114878Sjulian#include <sys/domain.h> 38114878Sjulian#include <sys/endian.h> 39114878Sjulian#include <sys/errno.h> 40114878Sjulian#include <sys/filedesc.h> 41114878Sjulian#include <sys/ioccom.h> 42114878Sjulian#include <sys/kernel.h> 43114878Sjulian#include <sys/lock.h> 44114878Sjulian#include <sys/malloc.h> 45114878Sjulian#include <sys/mbuf.h> 46114878Sjulian#include <sys/mutex.h> 47114878Sjulian#include <sys/proc.h> 48114878Sjulian#include <sys/protosw.h> 49114878Sjulian#include <sys/queue.h> 50114878Sjulian#include <sys/socket.h> 51114878Sjulian#include <sys/socketvar.h> 52114878Sjulian#include <sys/sysctl.h> 53114878Sjulian#include <sys/taskqueue.h> 54114878Sjulian#include <sys/uio.h> 55218757Sbz 56218757Sbz#include <net/vnet.h> 57218757Sbz 58114878Sjulian#include <netgraph/ng_message.h> 59114878Sjulian#include <netgraph/netgraph.h> 60128688Semax#include <netgraph/bluetooth/include/ng_bluetooth.h> 61128688Semax#include <netgraph/bluetooth/include/ng_hci.h> 62128688Semax#include <netgraph/bluetooth/include/ng_l2cap.h> 63128688Semax#include <netgraph/bluetooth/include/ng_btsocket.h> 64128688Semax#include <netgraph/bluetooth/include/ng_btsocket_l2cap.h> 65128688Semax#include <netgraph/bluetooth/include/ng_btsocket_rfcomm.h> 66114878Sjulian 67114878Sjulian/* MALLOC define */ 68114878Sjulian#ifdef NG_SEPARATE_MALLOC 69249132Smavstatic MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_RFCOMM, "netgraph_btsocks_rfcomm", 70114878Sjulian "Netgraph Bluetooth RFCOMM sockets"); 71114878Sjulian#else 72114878Sjulian#define M_NETGRAPH_BTSOCKET_RFCOMM M_NETGRAPH 73114878Sjulian#endif /* NG_SEPARATE_MALLOC */ 74114878Sjulian 75114878Sjulian/* Debug */ 76114878Sjulian#define NG_BTSOCKET_RFCOMM_INFO \ 77181093Semax if (ng_btsocket_rfcomm_debug_level >= NG_BTSOCKET_INFO_LEVEL && \ 78181093Semax ppsratecheck(&ng_btsocket_rfcomm_lasttime, &ng_btsocket_rfcomm_curpps, 1)) \ 79114878Sjulian printf 80114878Sjulian 81114878Sjulian#define NG_BTSOCKET_RFCOMM_WARN \ 82181093Semax if (ng_btsocket_rfcomm_debug_level >= NG_BTSOCKET_WARN_LEVEL && \ 83181093Semax ppsratecheck(&ng_btsocket_rfcomm_lasttime, &ng_btsocket_rfcomm_curpps, 1)) \ 84114878Sjulian printf 85114878Sjulian 86114878Sjulian#define NG_BTSOCKET_RFCOMM_ERR \ 87181093Semax if (ng_btsocket_rfcomm_debug_level >= NG_BTSOCKET_ERR_LEVEL && \ 88181093Semax ppsratecheck(&ng_btsocket_rfcomm_lasttime, &ng_btsocket_rfcomm_curpps, 1)) \ 89114878Sjulian printf 90114878Sjulian 91114878Sjulian#define NG_BTSOCKET_RFCOMM_ALERT \ 92181093Semax if (ng_btsocket_rfcomm_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \ 93181093Semax ppsratecheck(&ng_btsocket_rfcomm_lasttime, &ng_btsocket_rfcomm_curpps, 1)) \ 94114878Sjulian printf 95114878Sjulian 96114878Sjulian#define ALOT 0x7fff 97114878Sjulian 98114878Sjulian/* Local prototypes */ 99193272Sjhbstatic int ng_btsocket_rfcomm_upcall 100114878Sjulian (struct socket *so, void *arg, int waitflag); 101114878Sjulianstatic void ng_btsocket_rfcomm_sessions_task 102114878Sjulian (void *ctx, int pending); 103114878Sjulianstatic void ng_btsocket_rfcomm_session_task 104114878Sjulian (ng_btsocket_rfcomm_session_p s); 105114878Sjulian#define ng_btsocket_rfcomm_task_wakeup() \ 106114878Sjulian taskqueue_enqueue(taskqueue_swi_giant, &ng_btsocket_rfcomm_task) 107114878Sjulian 108114878Sjulianstatic ng_btsocket_rfcomm_pcb_p ng_btsocket_rfcomm_connect_ind 109114878Sjulian (ng_btsocket_rfcomm_session_p s, int channel); 110114878Sjulianstatic void ng_btsocket_rfcomm_connect_cfm 111114878Sjulian (ng_btsocket_rfcomm_session_p s); 112114878Sjulian 113114878Sjulianstatic int ng_btsocket_rfcomm_session_create 114114878Sjulian (ng_btsocket_rfcomm_session_p *sp, struct socket *l2so, 115114878Sjulian bdaddr_p src, bdaddr_p dst, struct thread *td); 116114878Sjulianstatic int ng_btsocket_rfcomm_session_accept 117114878Sjulian (ng_btsocket_rfcomm_session_p s0); 118114878Sjulianstatic int ng_btsocket_rfcomm_session_connect 119114878Sjulian (ng_btsocket_rfcomm_session_p s); 120114878Sjulianstatic int ng_btsocket_rfcomm_session_receive 121114878Sjulian (ng_btsocket_rfcomm_session_p s); 122114878Sjulianstatic int ng_btsocket_rfcomm_session_send 123114878Sjulian (ng_btsocket_rfcomm_session_p s); 124114878Sjulianstatic void ng_btsocket_rfcomm_session_clean 125114878Sjulian (ng_btsocket_rfcomm_session_p s); 126114878Sjulianstatic void ng_btsocket_rfcomm_session_process_pcb 127114878Sjulian (ng_btsocket_rfcomm_session_p s); 128114878Sjulianstatic ng_btsocket_rfcomm_session_p ng_btsocket_rfcomm_session_by_addr 129114878Sjulian (bdaddr_p src, bdaddr_p dst); 130114878Sjulian 131114878Sjulianstatic int ng_btsocket_rfcomm_receive_frame 132114878Sjulian (ng_btsocket_rfcomm_session_p s, struct mbuf *m0); 133114878Sjulianstatic int ng_btsocket_rfcomm_receive_sabm 134114878Sjulian (ng_btsocket_rfcomm_session_p s, int dlci); 135114878Sjulianstatic int ng_btsocket_rfcomm_receive_disc 136114878Sjulian (ng_btsocket_rfcomm_session_p s, int dlci); 137114878Sjulianstatic int ng_btsocket_rfcomm_receive_ua 138114878Sjulian (ng_btsocket_rfcomm_session_p s, int dlci); 139114878Sjulianstatic int ng_btsocket_rfcomm_receive_dm 140114878Sjulian (ng_btsocket_rfcomm_session_p s, int dlci); 141114878Sjulianstatic int ng_btsocket_rfcomm_receive_uih 142114878Sjulian (ng_btsocket_rfcomm_session_p s, int dlci, int pf, struct mbuf *m0); 143114878Sjulianstatic int ng_btsocket_rfcomm_receive_mcc 144114878Sjulian (ng_btsocket_rfcomm_session_p s, struct mbuf *m0); 145114878Sjulianstatic int ng_btsocket_rfcomm_receive_test 146114878Sjulian (ng_btsocket_rfcomm_session_p s, struct mbuf *m0); 147114878Sjulianstatic int ng_btsocket_rfcomm_receive_fc 148114878Sjulian (ng_btsocket_rfcomm_session_p s, struct mbuf *m0); 149114878Sjulianstatic int ng_btsocket_rfcomm_receive_msc 150114878Sjulian (ng_btsocket_rfcomm_session_p s, struct mbuf *m0); 151114878Sjulianstatic int ng_btsocket_rfcomm_receive_rpn 152114878Sjulian (ng_btsocket_rfcomm_session_p s, struct mbuf *m0); 153114878Sjulianstatic int ng_btsocket_rfcomm_receive_rls 154114878Sjulian (ng_btsocket_rfcomm_session_p s, struct mbuf *m0); 155114878Sjulianstatic int ng_btsocket_rfcomm_receive_pn 156114878Sjulian (ng_btsocket_rfcomm_session_p s, struct mbuf *m0); 157114878Sjulianstatic void ng_btsocket_rfcomm_set_pn 158114878Sjulian (ng_btsocket_rfcomm_pcb_p pcb, u_int8_t cr, u_int8_t flow_control, 159114878Sjulian u_int8_t credits, u_int16_t mtu); 160114878Sjulian 161114878Sjulianstatic int ng_btsocket_rfcomm_send_command 162114878Sjulian (ng_btsocket_rfcomm_session_p s, u_int8_t type, u_int8_t dlci); 163114878Sjulianstatic int ng_btsocket_rfcomm_send_uih 164114878Sjulian (ng_btsocket_rfcomm_session_p s, u_int8_t address, u_int8_t pf, 165114878Sjulian u_int8_t credits, struct mbuf *data); 166114878Sjulianstatic int ng_btsocket_rfcomm_send_msc 167114878Sjulian (ng_btsocket_rfcomm_pcb_p pcb); 168114878Sjulianstatic int ng_btsocket_rfcomm_send_pn 169114878Sjulian (ng_btsocket_rfcomm_pcb_p pcb); 170114878Sjulianstatic int ng_btsocket_rfcomm_send_credits 171114878Sjulian (ng_btsocket_rfcomm_pcb_p pcb); 172114878Sjulian 173114878Sjulianstatic int ng_btsocket_rfcomm_pcb_send 174114878Sjulian (ng_btsocket_rfcomm_pcb_p pcb, int limit); 175161623Semaxstatic void ng_btsocket_rfcomm_pcb_kill 176114878Sjulian (ng_btsocket_rfcomm_pcb_p pcb, int error); 177114878Sjulianstatic ng_btsocket_rfcomm_pcb_p ng_btsocket_rfcomm_pcb_by_dlci 178114878Sjulian (ng_btsocket_rfcomm_session_p s, int dlci); 179114878Sjulianstatic ng_btsocket_rfcomm_pcb_p ng_btsocket_rfcomm_pcb_listener 180114878Sjulian (bdaddr_p src, int channel); 181114878Sjulian 182114878Sjulianstatic void ng_btsocket_rfcomm_timeout 183114878Sjulian (ng_btsocket_rfcomm_pcb_p pcb); 184114878Sjulianstatic void ng_btsocket_rfcomm_untimeout 185114878Sjulian (ng_btsocket_rfcomm_pcb_p pcb); 186114878Sjulianstatic void ng_btsocket_rfcomm_process_timeout 187114878Sjulian (void *xpcb); 188114878Sjulian 189114878Sjulianstatic struct mbuf * ng_btsocket_rfcomm_prepare_packet 190114878Sjulian (struct sockbuf *sb, int length); 191114878Sjulian 192114878Sjulian/* Globals */ 193114878Sjulianextern int ifqmaxlen; 194114878Sjulianstatic u_int32_t ng_btsocket_rfcomm_debug_level; 195114878Sjulianstatic u_int32_t ng_btsocket_rfcomm_timo; 196114878Sjulianstruct task ng_btsocket_rfcomm_task; 197114878Sjulianstatic LIST_HEAD(, ng_btsocket_rfcomm_session) ng_btsocket_rfcomm_sessions; 198114878Sjulianstatic struct mtx ng_btsocket_rfcomm_sessions_mtx; 199114878Sjulianstatic LIST_HEAD(, ng_btsocket_rfcomm_pcb) ng_btsocket_rfcomm_sockets; 200114878Sjulianstatic struct mtx ng_btsocket_rfcomm_sockets_mtx; 201181093Semaxstatic struct timeval ng_btsocket_rfcomm_lasttime; 202181093Semaxstatic int ng_btsocket_rfcomm_curpps; 203114878Sjulian 204114878Sjulian/* Sysctl tree */ 205114878SjulianSYSCTL_DECL(_net_bluetooth_rfcomm_sockets); 206248085Smariusstatic SYSCTL_NODE(_net_bluetooth_rfcomm_sockets, OID_AUTO, stream, CTLFLAG_RW, 207114878Sjulian 0, "Bluetooth STREAM RFCOMM sockets family"); 208217320SmdfSYSCTL_UINT(_net_bluetooth_rfcomm_sockets_stream, OID_AUTO, debug_level, 209114878Sjulian CTLFLAG_RW, 210114878Sjulian &ng_btsocket_rfcomm_debug_level, NG_BTSOCKET_INFO_LEVEL, 211114878Sjulian "Bluetooth STREAM RFCOMM sockets debug level"); 212217320SmdfSYSCTL_UINT(_net_bluetooth_rfcomm_sockets_stream, OID_AUTO, timeout, 213114878Sjulian CTLFLAG_RW, 214114878Sjulian &ng_btsocket_rfcomm_timo, 60, 215114878Sjulian "Bluetooth STREAM RFCOMM sockets timeout"); 216114878Sjulian 217114878Sjulian/***************************************************************************** 218114878Sjulian ***************************************************************************** 219114878Sjulian ** RFCOMM CRC 220114878Sjulian ***************************************************************************** 221114878Sjulian *****************************************************************************/ 222114878Sjulian 223114878Sjulianstatic u_int8_t ng_btsocket_rfcomm_crc_table[256] = { 224114878Sjulian 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75, 225114878Sjulian 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b, 226114878Sjulian 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69, 227114878Sjulian 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67, 228114878Sjulian 229114878Sjulian 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d, 230114878Sjulian 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43, 231114878Sjulian 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51, 232114878Sjulian 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f, 233114878Sjulian 234114878Sjulian 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05, 235114878Sjulian 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b, 236114878Sjulian 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19, 237114878Sjulian 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17, 238114878Sjulian 239114878Sjulian 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d, 240114878Sjulian 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33, 241114878Sjulian 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21, 242114878Sjulian 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f, 243114878Sjulian 244114878Sjulian 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95, 245114878Sjulian 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b, 246114878Sjulian 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89, 247114878Sjulian 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87, 248114878Sjulian 249114878Sjulian 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad, 250114878Sjulian 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3, 251114878Sjulian 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1, 252114878Sjulian 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf, 253114878Sjulian 254114878Sjulian 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5, 255114878Sjulian 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb, 256114878Sjulian 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9, 257114878Sjulian 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7, 258114878Sjulian 259114878Sjulian 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd, 260114878Sjulian 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3, 261114878Sjulian 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1, 262114878Sjulian 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf 263114878Sjulian}; 264114878Sjulian 265114878Sjulian/* CRC */ 266114878Sjulianstatic u_int8_t 267114878Sjulianng_btsocket_rfcomm_crc(u_int8_t *data, int length) 268114878Sjulian{ 269114878Sjulian u_int8_t crc = 0xff; 270114878Sjulian 271114878Sjulian while (length --) 272114878Sjulian crc = ng_btsocket_rfcomm_crc_table[crc ^ *data++]; 273114878Sjulian 274114878Sjulian return (crc); 275114878Sjulian} /* ng_btsocket_rfcomm_crc */ 276114878Sjulian 277114878Sjulian/* FCS on 2 bytes */ 278114878Sjulianstatic u_int8_t 279114878Sjulianng_btsocket_rfcomm_fcs2(u_int8_t *data) 280114878Sjulian{ 281114878Sjulian return (0xff - ng_btsocket_rfcomm_crc(data, 2)); 282114878Sjulian} /* ng_btsocket_rfcomm_fcs2 */ 283114878Sjulian 284114878Sjulian/* FCS on 3 bytes */ 285114878Sjulianstatic u_int8_t 286114878Sjulianng_btsocket_rfcomm_fcs3(u_int8_t *data) 287114878Sjulian{ 288114878Sjulian return (0xff - ng_btsocket_rfcomm_crc(data, 3)); 289114878Sjulian} /* ng_btsocket_rfcomm_fcs3 */ 290114878Sjulian 291114878Sjulian/* 292114878Sjulian * Check FCS 293114878Sjulian * 294114878Sjulian * From Bluetooth spec 295114878Sjulian * 296114878Sjulian * "... In 07.10, the frame check sequence (FCS) is calculated on different 297114878Sjulian * sets of fields for different frame types. These are the fields that the 298114878Sjulian * FCS are calculated on: 299114878Sjulian * 300114878Sjulian * For SABM, DISC, UA, DM frames: on Address, Control and length field. 301114878Sjulian * For UIH frames: on Address and Control field. 302114878Sjulian * 303114878Sjulian * (This is stated here for clarification, and to set the standard for RFCOMM; 304114878Sjulian * the fields included in FCS calculation have actually changed in version 305114878Sjulian * 7.0.0 of TS 07.10, but RFCOMM will not change the FCS calculation scheme 306114878Sjulian * from the one above.) ..." 307114878Sjulian */ 308114878Sjulian 309114878Sjulianstatic int 310114878Sjulianng_btsocket_rfcomm_check_fcs(u_int8_t *data, int type, u_int8_t fcs) 311114878Sjulian{ 312114878Sjulian if (type != RFCOMM_FRAME_UIH) 313114878Sjulian return (ng_btsocket_rfcomm_fcs3(data) != fcs); 314114878Sjulian 315114878Sjulian return (ng_btsocket_rfcomm_fcs2(data) != fcs); 316114878Sjulian} /* ng_btsocket_rfcomm_check_fcs */ 317114878Sjulian 318114878Sjulian/***************************************************************************** 319114878Sjulian ***************************************************************************** 320114878Sjulian ** Socket interface 321114878Sjulian ***************************************************************************** 322114878Sjulian *****************************************************************************/ 323114878Sjulian 324114878Sjulian/* 325114878Sjulian * Initialize everything 326114878Sjulian */ 327114878Sjulian 328114878Sjulianvoid 329114878Sjulianng_btsocket_rfcomm_init(void) 330114878Sjulian{ 331114878Sjulian ng_btsocket_rfcomm_debug_level = NG_BTSOCKET_WARN_LEVEL; 332114878Sjulian ng_btsocket_rfcomm_timo = 60; 333114878Sjulian 334114878Sjulian /* RFCOMM task */ 335114878Sjulian TASK_INIT(&ng_btsocket_rfcomm_task, 0, 336114878Sjulian ng_btsocket_rfcomm_sessions_task, NULL); 337114878Sjulian 338114878Sjulian /* RFCOMM sessions list */ 339114878Sjulian LIST_INIT(&ng_btsocket_rfcomm_sessions); 340114878Sjulian mtx_init(&ng_btsocket_rfcomm_sessions_mtx, 341114878Sjulian "btsocks_rfcomm_sessions_mtx", NULL, MTX_DEF); 342114878Sjulian 343114878Sjulian /* RFCOMM sockets list */ 344114878Sjulian LIST_INIT(&ng_btsocket_rfcomm_sockets); 345114878Sjulian mtx_init(&ng_btsocket_rfcomm_sockets_mtx, 346114878Sjulian "btsocks_rfcomm_sockets_mtx", NULL, MTX_DEF); 347114878Sjulian} /* ng_btsocket_rfcomm_init */ 348114878Sjulian 349114878Sjulian/* 350114878Sjulian * Abort connection on socket 351114878Sjulian */ 352114878Sjulian 353157366Srwatsonvoid 354114878Sjulianng_btsocket_rfcomm_abort(struct socket *so) 355114878Sjulian{ 356160549Srwatson 357114878Sjulian so->so_error = ECONNABORTED; 358160549Srwatson (void)ng_btsocket_rfcomm_disconnect(so); 359114878Sjulian} /* ng_btsocket_rfcomm_abort */ 360114878Sjulian 361160549Srwatsonvoid 362160549Srwatsonng_btsocket_rfcomm_close(struct socket *so) 363160549Srwatson{ 364160549Srwatson 365160549Srwatson (void)ng_btsocket_rfcomm_disconnect(so); 366160549Srwatson} /* ng_btsocket_rfcomm_close */ 367160549Srwatson 368114878Sjulian/* 369114878Sjulian * Accept connection on socket. Nothing to do here, socket must be connected 370114878Sjulian * and ready, so just return peer address and be done with it. 371114878Sjulian */ 372114878Sjulian 373114878Sjulianint 374114878Sjulianng_btsocket_rfcomm_accept(struct socket *so, struct sockaddr **nam) 375114878Sjulian{ 376114878Sjulian return (ng_btsocket_rfcomm_peeraddr(so, nam)); 377114878Sjulian} /* ng_btsocket_rfcomm_accept */ 378114878Sjulian 379114878Sjulian/* 380114878Sjulian * Create and attach new socket 381114878Sjulian */ 382114878Sjulian 383114878Sjulianint 384114878Sjulianng_btsocket_rfcomm_attach(struct socket *so, int proto, struct thread *td) 385114878Sjulian{ 386114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 387114878Sjulian int error; 388114878Sjulian 389114878Sjulian /* Check socket and protocol */ 390114878Sjulian if (so->so_type != SOCK_STREAM) 391114878Sjulian return (ESOCKTNOSUPPORT); 392114878Sjulian 393114878Sjulian#if 0 /* XXX sonewconn() calls "pru_attach" with proto == 0 */ 394114878Sjulian if (proto != 0) 395114878Sjulian if (proto != BLUETOOTH_PROTO_RFCOMM) 396114878Sjulian return (EPROTONOSUPPORT); 397114878Sjulian#endif /* XXX */ 398114878Sjulian 399114878Sjulian if (pcb != NULL) 400114878Sjulian return (EISCONN); 401114878Sjulian 402114878Sjulian /* Reserve send and receive space if it is not reserved yet */ 403114878Sjulian if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) { 404114878Sjulian error = soreserve(so, NG_BTSOCKET_RFCOMM_SENDSPACE, 405114878Sjulian NG_BTSOCKET_RFCOMM_RECVSPACE); 406114878Sjulian if (error != 0) 407114878Sjulian return (error); 408114878Sjulian } 409114878Sjulian 410114878Sjulian /* Allocate the PCB */ 411184205Sdes pcb = malloc(sizeof(*pcb), 412114878Sjulian M_NETGRAPH_BTSOCKET_RFCOMM, M_NOWAIT | M_ZERO); 413114878Sjulian if (pcb == NULL) 414114878Sjulian return (ENOMEM); 415114878Sjulian 416114878Sjulian /* Link the PCB and the socket */ 417114878Sjulian so->so_pcb = (caddr_t) pcb; 418114878Sjulian pcb->so = so; 419114878Sjulian 420114878Sjulian /* Initialize PCB */ 421114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CLOSED; 422114878Sjulian pcb->flags = NG_BTSOCKET_RFCOMM_DLC_CFC; 423114878Sjulian 424114878Sjulian pcb->lmodem = 425114878Sjulian pcb->rmodem = (RFCOMM_MODEM_RTC | RFCOMM_MODEM_RTR | RFCOMM_MODEM_DV); 426114878Sjulian 427114878Sjulian pcb->mtu = RFCOMM_DEFAULT_MTU; 428114878Sjulian pcb->tx_cred = 0; 429114878Sjulian pcb->rx_cred = RFCOMM_DEFAULT_CREDITS; 430114878Sjulian 431114878Sjulian mtx_init(&pcb->pcb_mtx, "btsocks_rfcomm_pcb_mtx", NULL, MTX_DEF); 432114878Sjulian callout_handle_init(&pcb->timo); 433114878Sjulian 434114878Sjulian /* Add the PCB to the list */ 435114878Sjulian mtx_lock(&ng_btsocket_rfcomm_sockets_mtx); 436114878Sjulian LIST_INSERT_HEAD(&ng_btsocket_rfcomm_sockets, pcb, next); 437114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 438114878Sjulian 439114878Sjulian return (0); 440114878Sjulian} /* ng_btsocket_rfcomm_attach */ 441114878Sjulian 442114878Sjulian/* 443114878Sjulian * Bind socket 444114878Sjulian */ 445114878Sjulian 446114878Sjulianint 447114878Sjulianng_btsocket_rfcomm_bind(struct socket *so, struct sockaddr *nam, 448114878Sjulian struct thread *td) 449114878Sjulian{ 450173151Semax ng_btsocket_rfcomm_pcb_t *pcb = so2rfcomm_pcb(so), *pcb1; 451114878Sjulian struct sockaddr_rfcomm *sa = (struct sockaddr_rfcomm *) nam; 452114878Sjulian 453114878Sjulian if (pcb == NULL) 454114878Sjulian return (EINVAL); 455114878Sjulian 456114878Sjulian /* Verify address */ 457114878Sjulian if (sa == NULL) 458114878Sjulian return (EINVAL); 459114878Sjulian if (sa->rfcomm_family != AF_BLUETOOTH) 460114878Sjulian return (EAFNOSUPPORT); 461114878Sjulian if (sa->rfcomm_len != sizeof(*sa)) 462114878Sjulian return (EINVAL); 463114878Sjulian if (sa->rfcomm_channel > 30) 464114878Sjulian return (EINVAL); 465114878Sjulian 466173151Semax mtx_lock(&pcb->pcb_mtx); 467173151Semax 468173151Semax if (sa->rfcomm_channel != 0) { 469173151Semax mtx_lock(&ng_btsocket_rfcomm_sockets_mtx); 470173151Semax 471173151Semax LIST_FOREACH(pcb1, &ng_btsocket_rfcomm_sockets, next) { 472173151Semax if (pcb1->channel == sa->rfcomm_channel && 473173151Semax bcmp(&pcb1->src, &sa->rfcomm_bdaddr, 474173151Semax sizeof(pcb1->src)) == 0) { 475173151Semax mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 476173151Semax mtx_unlock(&pcb->pcb_mtx); 477173151Semax 478173151Semax return (EADDRINUSE); 479173151Semax } 480173151Semax } 481173151Semax 482173151Semax mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 483173151Semax } 484173151Semax 485114878Sjulian bcopy(&sa->rfcomm_bdaddr, &pcb->src, sizeof(pcb->src)); 486114878Sjulian pcb->channel = sa->rfcomm_channel; 487114878Sjulian 488173151Semax mtx_unlock(&pcb->pcb_mtx); 489173151Semax 490114878Sjulian return (0); 491114878Sjulian} /* ng_btsocket_rfcomm_bind */ 492114878Sjulian 493114878Sjulian/* 494114878Sjulian * Connect socket 495114878Sjulian */ 496114878Sjulian 497114878Sjulianint 498114878Sjulianng_btsocket_rfcomm_connect(struct socket *so, struct sockaddr *nam, 499114878Sjulian struct thread *td) 500114878Sjulian{ 501114878Sjulian ng_btsocket_rfcomm_pcb_t *pcb = so2rfcomm_pcb(so); 502114878Sjulian struct sockaddr_rfcomm *sa = (struct sockaddr_rfcomm *) nam; 503114878Sjulian ng_btsocket_rfcomm_session_t *s = NULL; 504114878Sjulian struct socket *l2so = NULL; 505114878Sjulian int dlci, error = 0; 506114878Sjulian 507114878Sjulian if (pcb == NULL) 508114878Sjulian return (EINVAL); 509114878Sjulian 510114878Sjulian /* Verify address */ 511114878Sjulian if (sa == NULL) 512114878Sjulian return (EINVAL); 513114878Sjulian if (sa->rfcomm_family != AF_BLUETOOTH) 514114878Sjulian return (EAFNOSUPPORT); 515114878Sjulian if (sa->rfcomm_len != sizeof(*sa)) 516114878Sjulian return (EINVAL); 517114878Sjulian if (sa->rfcomm_channel > 30) 518114878Sjulian return (EINVAL); 519114878Sjulian if (sa->rfcomm_channel == 0 || 520114878Sjulian bcmp(&sa->rfcomm_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) 521114878Sjulian return (EDESTADDRREQ); 522114878Sjulian 523114878Sjulian /* 524188452Semax * Note that we will not check for errors in socreate() because 525188452Semax * if we failed to create L2CAP socket at this point we still 526188452Semax * might have already open session. 527114878Sjulian */ 528114878Sjulian 529114878Sjulian error = socreate(PF_BLUETOOTH, &l2so, SOCK_SEQPACKET, 530114878Sjulian BLUETOOTH_PROTO_L2CAP, td->td_ucred, td); 531114878Sjulian 532114878Sjulian /* 533114878Sjulian * Look for session between "pcb->src" and "sa->rfcomm_bdaddr" (dst) 534114878Sjulian */ 535114878Sjulian 536114878Sjulian mtx_lock(&ng_btsocket_rfcomm_sessions_mtx); 537114878Sjulian 538114878Sjulian s = ng_btsocket_rfcomm_session_by_addr(&pcb->src, &sa->rfcomm_bdaddr); 539114878Sjulian if (s == NULL) { 540114878Sjulian /* 541114878Sjulian * We need to create new RFCOMM session. Check if we have L2CAP 542114878Sjulian * socket. If l2so == NULL then error has the error code from 543114878Sjulian * socreate() 544114878Sjulian */ 545114878Sjulian 546114878Sjulian if (l2so == NULL) { 547114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 548114878Sjulian return (error); 549114878Sjulian } 550114878Sjulian 551114878Sjulian error = ng_btsocket_rfcomm_session_create(&s, l2so, 552114878Sjulian &pcb->src, &sa->rfcomm_bdaddr, td); 553114878Sjulian if (error != 0) { 554114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 555114878Sjulian soclose(l2so); 556114878Sjulian 557114878Sjulian return (error); 558114878Sjulian } 559114878Sjulian } else if (l2so != NULL) 560114878Sjulian soclose(l2so); /* we don't need new L2CAP socket */ 561114878Sjulian 562114878Sjulian /* 563218909Sbrucec * Check if we already have the same DLCI the same session 564114878Sjulian */ 565114878Sjulian 566114878Sjulian mtx_lock(&s->session_mtx); 567114878Sjulian mtx_lock(&pcb->pcb_mtx); 568114878Sjulian 569114878Sjulian dlci = RFCOMM_MKDLCI(!INITIATOR(s), sa->rfcomm_channel); 570114878Sjulian 571114878Sjulian if (ng_btsocket_rfcomm_pcb_by_dlci(s, dlci) != NULL) { 572114878Sjulian mtx_unlock(&pcb->pcb_mtx); 573114878Sjulian mtx_unlock(&s->session_mtx); 574114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 575114878Sjulian 576114878Sjulian return (EBUSY); 577114878Sjulian } 578114878Sjulian 579114878Sjulian /* 580114878Sjulian * Check session state and if its not acceptable then refuse connection 581114878Sjulian */ 582114878Sjulian 583114878Sjulian switch (s->state) { 584114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CONNECTING: 585114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED: 586114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_OPEN: 587114878Sjulian /* 588114878Sjulian * Update destination address and channel and attach 589114878Sjulian * DLC to the session 590114878Sjulian */ 591114878Sjulian 592114878Sjulian bcopy(&sa->rfcomm_bdaddr, &pcb->dst, sizeof(pcb->dst)); 593114878Sjulian pcb->channel = sa->rfcomm_channel; 594114878Sjulian pcb->dlci = dlci; 595114878Sjulian 596114878Sjulian LIST_INSERT_HEAD(&s->dlcs, pcb, session_next); 597114878Sjulian pcb->session = s; 598114878Sjulian 599114878Sjulian ng_btsocket_rfcomm_timeout(pcb); 600114878Sjulian soisconnecting(pcb->so); 601114878Sjulian 602114878Sjulian if (s->state == NG_BTSOCKET_RFCOMM_SESSION_OPEN) { 603114878Sjulian pcb->mtu = s->mtu; 604114878Sjulian bcopy(&so2l2cap_pcb(s->l2so)->src, &pcb->src, 605114878Sjulian sizeof(pcb->src)); 606114878Sjulian 607114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONFIGURING; 608114878Sjulian 609114878Sjulian error = ng_btsocket_rfcomm_send_pn(pcb); 610114878Sjulian if (error == 0) 611114878Sjulian error = ng_btsocket_rfcomm_task_wakeup(); 612114878Sjulian } else 613114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT; 614114878Sjulian break; 615114878Sjulian 616114878Sjulian default: 617114878Sjulian error = ECONNRESET; 618114878Sjulian break; 619114878Sjulian } 620114878Sjulian 621114878Sjulian mtx_unlock(&pcb->pcb_mtx); 622114878Sjulian mtx_unlock(&s->session_mtx); 623114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 624114878Sjulian 625114878Sjulian return (error); 626114878Sjulian} /* ng_btsocket_rfcomm_connect */ 627114878Sjulian 628114878Sjulian/* 629114878Sjulian * Process ioctl's calls on socket. 630114878Sjulian * XXX FIXME this should provide interface to the RFCOMM multiplexor channel 631114878Sjulian */ 632114878Sjulian 633114878Sjulianint 634114878Sjulianng_btsocket_rfcomm_control(struct socket *so, u_long cmd, caddr_t data, 635114878Sjulian struct ifnet *ifp, struct thread *td) 636114878Sjulian{ 637114878Sjulian return (EINVAL); 638114878Sjulian} /* ng_btsocket_rfcomm_control */ 639114878Sjulian 640114878Sjulian/* 641114878Sjulian * Process getsockopt/setsockopt system calls 642114878Sjulian */ 643114878Sjulian 644114878Sjulianint 645114878Sjulianng_btsocket_rfcomm_ctloutput(struct socket *so, struct sockopt *sopt) 646114878Sjulian{ 647114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 648114878Sjulian struct ng_btsocket_rfcomm_fc_info fcinfo; 649114878Sjulian int error = 0; 650114878Sjulian 651114878Sjulian if (pcb == NULL) 652114878Sjulian return (EINVAL); 653114878Sjulian if (sopt->sopt_level != SOL_RFCOMM) 654114878Sjulian return (0); 655114878Sjulian 656114878Sjulian mtx_lock(&pcb->pcb_mtx); 657114878Sjulian 658114878Sjulian switch (sopt->sopt_dir) { 659114878Sjulian case SOPT_GET: 660114878Sjulian switch (sopt->sopt_name) { 661114878Sjulian case SO_RFCOMM_MTU: 662114878Sjulian error = sooptcopyout(sopt, &pcb->mtu, sizeof(pcb->mtu)); 663114878Sjulian break; 664114878Sjulian 665114878Sjulian case SO_RFCOMM_FC_INFO: 666114878Sjulian fcinfo.lmodem = pcb->lmodem; 667114878Sjulian fcinfo.rmodem = pcb->rmodem; 668114878Sjulian fcinfo.tx_cred = pcb->tx_cred; 669114878Sjulian fcinfo.rx_cred = pcb->rx_cred; 670114878Sjulian fcinfo.cfc = (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC)? 671114878Sjulian 1 : 0; 672114878Sjulian fcinfo.reserved = 0; 673114878Sjulian 674114878Sjulian error = sooptcopyout(sopt, &fcinfo, sizeof(fcinfo)); 675114878Sjulian break; 676114878Sjulian 677114878Sjulian default: 678114878Sjulian error = ENOPROTOOPT; 679114878Sjulian break; 680114878Sjulian } 681114878Sjulian break; 682114878Sjulian 683114878Sjulian case SOPT_SET: 684114878Sjulian switch (sopt->sopt_name) { 685114878Sjulian default: 686114878Sjulian error = ENOPROTOOPT; 687114878Sjulian break; 688114878Sjulian } 689114878Sjulian break; 690114878Sjulian 691114878Sjulian default: 692114878Sjulian error = EINVAL; 693114878Sjulian break; 694114878Sjulian } 695114878Sjulian 696114878Sjulian mtx_unlock(&pcb->pcb_mtx); 697114878Sjulian 698114878Sjulian return (error); 699114878Sjulian} /* ng_btsocket_rfcomm_ctloutput */ 700114878Sjulian 701114878Sjulian/* 702114878Sjulian * Detach and destroy socket 703114878Sjulian */ 704114878Sjulian 705157370Srwatsonvoid 706114878Sjulianng_btsocket_rfcomm_detach(struct socket *so) 707114878Sjulian{ 708114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 709114878Sjulian 710157370Srwatson KASSERT(pcb != NULL, ("ng_btsocket_rfcomm_detach: pcb == NULL")); 711114878Sjulian 712114878Sjulian mtx_lock(&pcb->pcb_mtx); 713114878Sjulian 714114878Sjulian switch (pcb->state) { 715114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT: 716114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING: 717114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONNECTING: 718114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONNECTED: 719114878Sjulian /* XXX What to do with pending request? */ 720114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO) 721114878Sjulian ng_btsocket_rfcomm_untimeout(pcb); 722114878Sjulian 723114878Sjulian if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT) 724114878Sjulian pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_DETACHED; 725114878Sjulian else 726114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING; 727114878Sjulian 728114878Sjulian ng_btsocket_rfcomm_task_wakeup(); 729114878Sjulian break; 730114878Sjulian 731114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING: 732114878Sjulian ng_btsocket_rfcomm_task_wakeup(); 733114878Sjulian break; 734114878Sjulian } 735114878Sjulian 736114878Sjulian while (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CLOSED) 737114878Sjulian msleep(&pcb->state, &pcb->pcb_mtx, PZERO, "rf_det", 0); 738114878Sjulian 739114878Sjulian if (pcb->session != NULL) 740114878Sjulian panic("%s: pcb->session != NULL\n", __func__); 741114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO) 742114878Sjulian panic("%s: timeout on closed DLC, flags=%#x\n", 743114878Sjulian __func__, pcb->flags); 744114878Sjulian 745114878Sjulian mtx_lock(&ng_btsocket_rfcomm_sockets_mtx); 746114878Sjulian LIST_REMOVE(pcb, next); 747114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 748114878Sjulian 749114878Sjulian mtx_unlock(&pcb->pcb_mtx); 750114878Sjulian 751114878Sjulian mtx_destroy(&pcb->pcb_mtx); 752114878Sjulian bzero(pcb, sizeof(*pcb)); 753184205Sdes free(pcb, M_NETGRAPH_BTSOCKET_RFCOMM); 754114878Sjulian 755114878Sjulian soisdisconnected(so); 756114878Sjulian so->so_pcb = NULL; 757114878Sjulian} /* ng_btsocket_rfcomm_detach */ 758114878Sjulian 759114878Sjulian/* 760114878Sjulian * Disconnect socket 761114878Sjulian */ 762114878Sjulian 763114878Sjulianint 764114878Sjulianng_btsocket_rfcomm_disconnect(struct socket *so) 765114878Sjulian{ 766114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 767114878Sjulian 768114878Sjulian if (pcb == NULL) 769114878Sjulian return (EINVAL); 770114878Sjulian 771114878Sjulian mtx_lock(&pcb->pcb_mtx); 772114878Sjulian 773114878Sjulian if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING) { 774114878Sjulian mtx_unlock(&pcb->pcb_mtx); 775114878Sjulian return (EINPROGRESS); 776114878Sjulian } 777114878Sjulian 778114878Sjulian /* XXX What to do with pending request? */ 779114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO) 780114878Sjulian ng_btsocket_rfcomm_untimeout(pcb); 781114878Sjulian 782114878Sjulian switch (pcb->state) { 783114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING: /* XXX can we get here? */ 784114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONNECTING: /* XXX can we get here? */ 785114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONNECTED: 786114878Sjulian 787114878Sjulian /* 788114878Sjulian * Just change DLC state and enqueue RFCOMM task. It will 789114878Sjulian * queue and send DISC on the DLC. 790114878Sjulian */ 791114878Sjulian 792114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING; 793114878Sjulian soisdisconnecting(so); 794114878Sjulian 795114878Sjulian ng_btsocket_rfcomm_task_wakeup(); 796114878Sjulian break; 797114878Sjulian 798161623Semax case NG_BTSOCKET_RFCOMM_DLC_CLOSED: 799161623Semax case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT: 800161623Semax break; 801161623Semax 802114878Sjulian default: 803114878Sjulian panic("%s: Invalid DLC state=%d, flags=%#x\n", 804114878Sjulian __func__, pcb->state, pcb->flags); 805114878Sjulian break; 806114878Sjulian } 807114878Sjulian 808114878Sjulian mtx_unlock(&pcb->pcb_mtx); 809114878Sjulian 810114878Sjulian return (0); 811114878Sjulian} /* ng_btsocket_rfcomm_disconnect */ 812114878Sjulian 813114878Sjulian/* 814114878Sjulian * Listen on socket. First call to listen() will create listening RFCOMM session 815114878Sjulian */ 816114878Sjulian 817114878Sjulianint 818151888Srwatsonng_btsocket_rfcomm_listen(struct socket *so, int backlog, struct thread *td) 819114878Sjulian{ 820173151Semax ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so), pcb1; 821114878Sjulian ng_btsocket_rfcomm_session_p s = NULL; 822114878Sjulian struct socket *l2so = NULL; 823173151Semax int error, socreate_error, usedchannels; 824114878Sjulian 825114878Sjulian if (pcb == NULL) 826114878Sjulian return (EINVAL); 827173151Semax if (pcb->channel > 30) 828171937Semax return (EADDRNOTAVAIL); 829114878Sjulian 830173151Semax usedchannels = 0; 831173151Semax 832173151Semax mtx_lock(&pcb->pcb_mtx); 833173151Semax 834173151Semax if (pcb->channel == 0) { 835173151Semax mtx_lock(&ng_btsocket_rfcomm_sockets_mtx); 836173151Semax 837173151Semax LIST_FOREACH(pcb1, &ng_btsocket_rfcomm_sockets, next) 838173151Semax if (pcb1->channel != 0 && 839173151Semax bcmp(&pcb1->src, &pcb->src, sizeof(pcb->src)) == 0) 840173151Semax usedchannels |= (1 << (pcb1->channel - 1)); 841173151Semax 842173151Semax for (pcb->channel = 30; pcb->channel > 0; pcb->channel --) 843173151Semax if (!(usedchannels & (1 << (pcb->channel - 1)))) 844173151Semax break; 845173151Semax 846173151Semax if (pcb->channel == 0) { 847173151Semax mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 848173151Semax mtx_unlock(&pcb->pcb_mtx); 849173151Semax 850173151Semax return (EADDRNOTAVAIL); 851173151Semax } 852173151Semax 853173151Semax mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 854173151Semax } 855173151Semax 856173151Semax mtx_unlock(&pcb->pcb_mtx); 857173151Semax 858114878Sjulian /* 859188452Semax * Note that we will not check for errors in socreate() because 860188452Semax * if we failed to create L2CAP socket at this point we still 861188452Semax * might have already open session. 862114878Sjulian */ 863114878Sjulian 864142190Srwatson socreate_error = socreate(PF_BLUETOOTH, &l2so, SOCK_SEQPACKET, 865114878Sjulian BLUETOOTH_PROTO_L2CAP, td->td_ucred, td); 866114878Sjulian 867142190Srwatson /* 868142190Srwatson * Transition the socket and session into the LISTENING state. Check 869142190Srwatson * for collisions first, as there can only be one. 870114878Sjulian */ 871114878Sjulian mtx_lock(&ng_btsocket_rfcomm_sessions_mtx); 872142190Srwatson SOCK_LOCK(so); 873142190Srwatson error = solisten_proto_check(so); 874161623Semax SOCK_UNLOCK(so); 875142190Srwatson if (error != 0) 876142190Srwatson goto out; 877114878Sjulian 878114878Sjulian LIST_FOREACH(s, &ng_btsocket_rfcomm_sessions, next) 879114878Sjulian if (s->state == NG_BTSOCKET_RFCOMM_SESSION_LISTENING) 880114878Sjulian break; 881114878Sjulian 882114878Sjulian if (s == NULL) { 883114878Sjulian /* 884114878Sjulian * We need to create default RFCOMM session. Check if we have 885114878Sjulian * L2CAP socket. If l2so == NULL then error has the error code 886114878Sjulian * from socreate() 887114878Sjulian */ 888114878Sjulian if (l2so == NULL) { 889142190Srwatson error = socreate_error; 890142190Srwatson goto out; 891114878Sjulian } 892114878Sjulian 893114878Sjulian /* 894114878Sjulian * Create default listen RFCOMM session. The default RFCOMM 895114878Sjulian * session will listen on ANY address. 896114878Sjulian * 897114878Sjulian * XXX FIXME Note that currently there is no way to adjust MTU 898114878Sjulian * for the default session. 899114878Sjulian */ 900114878Sjulian error = ng_btsocket_rfcomm_session_create(&s, l2so, 901114878Sjulian NG_HCI_BDADDR_ANY, NULL, td); 902142190Srwatson if (error != 0) 903142190Srwatson goto out; 904142190Srwatson l2so = NULL; 905142190Srwatson } 906161623Semax SOCK_LOCK(so); 907151888Srwatson solisten_proto(so, backlog); 908161623Semax SOCK_UNLOCK(so); 909142190Srwatsonout: 910114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 911142190Srwatson /* 912142190Srwatson * If we still have an l2so reference here, it's unneeded, so release 913142190Srwatson * it. 914142190Srwatson */ 915142190Srwatson if (l2so != NULL) 916142190Srwatson soclose(l2so); 917142190Srwatson return (error); 918114878Sjulian} /* ng_btsocket_listen */ 919114878Sjulian 920114878Sjulian/* 921114878Sjulian * Get peer address 922114878Sjulian */ 923114878Sjulian 924114878Sjulianint 925114878Sjulianng_btsocket_rfcomm_peeraddr(struct socket *so, struct sockaddr **nam) 926114878Sjulian{ 927114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 928114878Sjulian struct sockaddr_rfcomm sa; 929114878Sjulian 930114878Sjulian if (pcb == NULL) 931114878Sjulian return (EINVAL); 932114878Sjulian 933114878Sjulian bcopy(&pcb->dst, &sa.rfcomm_bdaddr, sizeof(sa.rfcomm_bdaddr)); 934114878Sjulian sa.rfcomm_channel = pcb->channel; 935114878Sjulian sa.rfcomm_len = sizeof(sa); 936114878Sjulian sa.rfcomm_family = AF_BLUETOOTH; 937114878Sjulian 938126425Srwatson *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 939114878Sjulian 940114878Sjulian return ((*nam == NULL)? ENOMEM : 0); 941114878Sjulian} /* ng_btsocket_rfcomm_peeraddr */ 942114878Sjulian 943114878Sjulian/* 944114878Sjulian * Send data to socket 945114878Sjulian */ 946114878Sjulian 947114878Sjulianint 948114878Sjulianng_btsocket_rfcomm_send(struct socket *so, int flags, struct mbuf *m, 949114878Sjulian struct sockaddr *nam, struct mbuf *control, struct thread *td) 950114878Sjulian{ 951114878Sjulian ng_btsocket_rfcomm_pcb_t *pcb = so2rfcomm_pcb(so); 952114878Sjulian int error = 0; 953114878Sjulian 954114878Sjulian /* Check socket and input */ 955114878Sjulian if (pcb == NULL || m == NULL || control != NULL) { 956114878Sjulian error = EINVAL; 957114878Sjulian goto drop; 958114878Sjulian } 959114878Sjulian 960114878Sjulian mtx_lock(&pcb->pcb_mtx); 961114878Sjulian 962114878Sjulian /* Make sure DLC is connected */ 963114878Sjulian if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTED) { 964114878Sjulian mtx_unlock(&pcb->pcb_mtx); 965114878Sjulian error = ENOTCONN; 966114878Sjulian goto drop; 967114878Sjulian } 968114878Sjulian 969114878Sjulian /* Put the packet on the socket's send queue and wakeup RFCOMM task */ 970114878Sjulian sbappend(&pcb->so->so_snd, m); 971114878Sjulian m = NULL; 972114878Sjulian 973114878Sjulian if (!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_SENDING)) { 974114878Sjulian pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_SENDING; 975114878Sjulian error = ng_btsocket_rfcomm_task_wakeup(); 976114878Sjulian } 977114878Sjulian 978114878Sjulian mtx_unlock(&pcb->pcb_mtx); 979114878Sjuliandrop: 980114878Sjulian NG_FREE_M(m); /* checks for != NULL */ 981114878Sjulian NG_FREE_M(control); 982114878Sjulian 983114878Sjulian return (error); 984114878Sjulian} /* ng_btsocket_rfcomm_send */ 985114878Sjulian 986114878Sjulian/* 987114878Sjulian * Get socket address 988114878Sjulian */ 989114878Sjulian 990114878Sjulianint 991114878Sjulianng_btsocket_rfcomm_sockaddr(struct socket *so, struct sockaddr **nam) 992114878Sjulian{ 993114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 994114878Sjulian struct sockaddr_rfcomm sa; 995114878Sjulian 996114878Sjulian if (pcb == NULL) 997114878Sjulian return (EINVAL); 998114878Sjulian 999114878Sjulian bcopy(&pcb->src, &sa.rfcomm_bdaddr, sizeof(sa.rfcomm_bdaddr)); 1000114878Sjulian sa.rfcomm_channel = pcb->channel; 1001114878Sjulian sa.rfcomm_len = sizeof(sa); 1002114878Sjulian sa.rfcomm_family = AF_BLUETOOTH; 1003114878Sjulian 1004126425Srwatson *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 1005114878Sjulian 1006114878Sjulian return ((*nam == NULL)? ENOMEM : 0); 1007114878Sjulian} /* ng_btsocket_rfcomm_sockaddr */ 1008114878Sjulian 1009114878Sjulian/* 1010114878Sjulian * Upcall function for L2CAP sockets. Enqueue RFCOMM task. 1011114878Sjulian */ 1012114878Sjulian 1013193272Sjhbstatic int 1014114878Sjulianng_btsocket_rfcomm_upcall(struct socket *so, void *arg, int waitflag) 1015114878Sjulian{ 1016114878Sjulian int error; 1017114878Sjulian 1018114878Sjulian if (so == NULL) 1019114878Sjulian panic("%s: so == NULL\n", __func__); 1020114878Sjulian 1021114878Sjulian if ((error = ng_btsocket_rfcomm_task_wakeup()) != 0) 1022114878Sjulian NG_BTSOCKET_RFCOMM_ALERT( 1023114878Sjulian"%s: Could not enqueue RFCOMM task, error=%d\n", __func__, error); 1024193272Sjhb return (SU_OK); 1025114878Sjulian} /* ng_btsocket_rfcomm_upcall */ 1026114878Sjulian 1027114878Sjulian/* 1028114878Sjulian * RFCOMM task. Will handle all RFCOMM sessions in one pass. 1029114878Sjulian * XXX FIXME does not scale very well 1030114878Sjulian */ 1031114878Sjulian 1032114878Sjulianstatic void 1033114878Sjulianng_btsocket_rfcomm_sessions_task(void *ctx, int pending) 1034114878Sjulian{ 1035114878Sjulian ng_btsocket_rfcomm_session_p s = NULL, s_next = NULL; 1036114878Sjulian 1037114878Sjulian mtx_lock(&ng_btsocket_rfcomm_sessions_mtx); 1038114878Sjulian 1039114878Sjulian for (s = LIST_FIRST(&ng_btsocket_rfcomm_sessions); s != NULL; ) { 1040114878Sjulian mtx_lock(&s->session_mtx); 1041114878Sjulian s_next = LIST_NEXT(s, next); 1042114878Sjulian 1043114878Sjulian ng_btsocket_rfcomm_session_task(s); 1044114878Sjulian 1045114878Sjulian if (s->state == NG_BTSOCKET_RFCOMM_SESSION_CLOSED) { 1046114878Sjulian /* Unlink and clean the session */ 1047114878Sjulian LIST_REMOVE(s, next); 1048114878Sjulian 1049114878Sjulian NG_BT_MBUFQ_DRAIN(&s->outq); 1050114878Sjulian if (!LIST_EMPTY(&s->dlcs)) 1051114878Sjulian panic("%s: DLC list is not empty\n", __func__); 1052114878Sjulian 1053114878Sjulian /* Close L2CAP socket */ 1054130653Srwatson SOCKBUF_LOCK(&s->l2so->so_rcv); 1055193272Sjhb soupcall_clear(s->l2so, SO_RCV); 1056130653Srwatson SOCKBUF_UNLOCK(&s->l2so->so_rcv); 1057130653Srwatson SOCKBUF_LOCK(&s->l2so->so_snd); 1058193272Sjhb soupcall_clear(s->l2so, SO_SND); 1059130653Srwatson SOCKBUF_UNLOCK(&s->l2so->so_snd); 1060114878Sjulian soclose(s->l2so); 1061114878Sjulian 1062114878Sjulian mtx_unlock(&s->session_mtx); 1063114878Sjulian 1064114878Sjulian mtx_destroy(&s->session_mtx); 1065114878Sjulian bzero(s, sizeof(*s)); 1066184205Sdes free(s, M_NETGRAPH_BTSOCKET_RFCOMM); 1067114878Sjulian } else 1068114878Sjulian mtx_unlock(&s->session_mtx); 1069114878Sjulian 1070114878Sjulian s = s_next; 1071114878Sjulian } 1072114878Sjulian 1073114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 1074114878Sjulian} /* ng_btsocket_rfcomm_sessions_task */ 1075114878Sjulian 1076114878Sjulian/* 1077114878Sjulian * Process RFCOMM session. Will handle all RFCOMM sockets in one pass. 1078114878Sjulian */ 1079114878Sjulian 1080114878Sjulianstatic void 1081114878Sjulianng_btsocket_rfcomm_session_task(ng_btsocket_rfcomm_session_p s) 1082114878Sjulian{ 1083114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1084114878Sjulian 1085130480Srwatson if (s->l2so->so_rcv.sb_state & SBS_CANTRCVMORE) { 1086114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 1087114878Sjulian"%s: L2CAP connection has been terminated, so=%p, so_state=%#x, so_count=%d, " \ 1088114878Sjulian"state=%d, flags=%#x\n", __func__, s->l2so, s->l2so->so_state, 1089114878Sjulian s->l2so->so_count, s->state, s->flags); 1090114878Sjulian 1091114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 1092114878Sjulian ng_btsocket_rfcomm_session_clean(s); 1093114878Sjulian } 1094114878Sjulian 1095114878Sjulian /* Now process upcall */ 1096114878Sjulian switch (s->state) { 1097114878Sjulian /* Try to accept new L2CAP connection(s) */ 1098114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_LISTENING: 1099114878Sjulian while (ng_btsocket_rfcomm_session_accept(s) == 0) 1100114878Sjulian ; 1101114878Sjulian break; 1102114878Sjulian 1103114878Sjulian /* Process the results of the L2CAP connect */ 1104114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CONNECTING: 1105114878Sjulian ng_btsocket_rfcomm_session_process_pcb(s); 1106114878Sjulian 1107114878Sjulian if (ng_btsocket_rfcomm_session_connect(s) != 0) { 1108114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 1109114878Sjulian ng_btsocket_rfcomm_session_clean(s); 1110114878Sjulian } 1111114878Sjulian break; 1112114878Sjulian 1113114878Sjulian /* Try to receive/send more data */ 1114114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED: 1115114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_OPEN: 1116114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING: 1117114878Sjulian ng_btsocket_rfcomm_session_process_pcb(s); 1118114878Sjulian 1119114878Sjulian if (ng_btsocket_rfcomm_session_receive(s) != 0) { 1120114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 1121114878Sjulian ng_btsocket_rfcomm_session_clean(s); 1122114878Sjulian } else if (ng_btsocket_rfcomm_session_send(s) != 0) { 1123114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 1124114878Sjulian ng_btsocket_rfcomm_session_clean(s); 1125114878Sjulian } 1126114878Sjulian break; 1127114878Sjulian 1128114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CLOSED: 1129114878Sjulian break; 1130114878Sjulian 1131114878Sjulian default: 1132114878Sjulian panic("%s: Invalid session state=%d, flags=%#x\n", 1133114878Sjulian __func__, s->state, s->flags); 1134114878Sjulian break; 1135114878Sjulian } 1136114878Sjulian} /* ng_btsocket_rfcomm_session_task */ 1137114878Sjulian 1138114878Sjulian/* 1139114878Sjulian * Process RFCOMM connection indicator. Caller must hold s->session_mtx 1140114878Sjulian */ 1141114878Sjulian 1142114878Sjulianstatic ng_btsocket_rfcomm_pcb_p 1143114878Sjulianng_btsocket_rfcomm_connect_ind(ng_btsocket_rfcomm_session_p s, int channel) 1144114878Sjulian{ 1145114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb1 = NULL; 1146114878Sjulian ng_btsocket_l2cap_pcb_p l2pcb = NULL; 1147114878Sjulian struct socket *so1 = NULL; 1148114878Sjulian 1149114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1150114878Sjulian 1151114878Sjulian /* 1152114878Sjulian * Try to find RFCOMM socket that listens on given source address 1153114878Sjulian * and channel. This will return the best possible match. 1154114878Sjulian */ 1155114878Sjulian 1156114878Sjulian l2pcb = so2l2cap_pcb(s->l2so); 1157114878Sjulian pcb = ng_btsocket_rfcomm_pcb_listener(&l2pcb->src, channel); 1158114878Sjulian if (pcb == NULL) 1159114878Sjulian return (NULL); 1160114878Sjulian 1161114878Sjulian /* 1162114878Sjulian * Check the pending connections queue and if we have space then 1163114878Sjulian * create new socket and set proper source and destination address, 1164114878Sjulian * and channel. 1165114878Sjulian */ 1166114878Sjulian 1167114878Sjulian mtx_lock(&pcb->pcb_mtx); 1168114878Sjulian 1169218757Sbz if (pcb->so->so_qlen <= pcb->so->so_qlimit) { 1170218757Sbz CURVNET_SET(pcb->so->so_vnet); 1171114878Sjulian so1 = sonewconn(pcb->so, 0); 1172218757Sbz CURVNET_RESTORE(); 1173218757Sbz } 1174114878Sjulian 1175114878Sjulian mtx_unlock(&pcb->pcb_mtx); 1176114878Sjulian 1177114878Sjulian if (so1 == NULL) 1178114878Sjulian return (NULL); 1179114878Sjulian 1180114878Sjulian /* 1181114878Sjulian * If we got here than we have created new socket. So complete the 1182114878Sjulian * connection. Set source and destination address from the session. 1183114878Sjulian */ 1184114878Sjulian 1185114878Sjulian pcb1 = so2rfcomm_pcb(so1); 1186114878Sjulian if (pcb1 == NULL) 1187114878Sjulian panic("%s: pcb1 == NULL\n", __func__); 1188114878Sjulian 1189114878Sjulian mtx_lock(&pcb1->pcb_mtx); 1190114878Sjulian 1191114878Sjulian bcopy(&l2pcb->src, &pcb1->src, sizeof(pcb1->src)); 1192114878Sjulian bcopy(&l2pcb->dst, &pcb1->dst, sizeof(pcb1->dst)); 1193114878Sjulian pcb1->channel = channel; 1194114878Sjulian 1195114878Sjulian /* Link new DLC to the session. We already hold s->session_mtx */ 1196114878Sjulian LIST_INSERT_HEAD(&s->dlcs, pcb1, session_next); 1197114878Sjulian pcb1->session = s; 1198114878Sjulian 1199114878Sjulian mtx_unlock(&pcb1->pcb_mtx); 1200114878Sjulian 1201114878Sjulian return (pcb1); 1202114878Sjulian} /* ng_btsocket_rfcomm_connect_ind */ 1203114878Sjulian 1204114878Sjulian/* 1205114878Sjulian * Process RFCOMM connect confirmation. Caller must hold s->session_mtx. 1206114878Sjulian */ 1207114878Sjulian 1208114878Sjulianstatic void 1209114878Sjulianng_btsocket_rfcomm_connect_cfm(ng_btsocket_rfcomm_session_p s) 1210114878Sjulian{ 1211161623Semax ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb_next = NULL; 1212161623Semax int error; 1213114878Sjulian 1214114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1215114878Sjulian 1216114878Sjulian /* 1217114878Sjulian * Wake up all waiting sockets and send PN request for each of them. 1218114878Sjulian * Note that timeout already been set in ng_btsocket_rfcomm_connect() 1219114878Sjulian * 1220114878Sjulian * Note: cannot use LIST_FOREACH because ng_btsocket_rfcomm_pcb_kill 1221114878Sjulian * will unlink DLC from the session 1222114878Sjulian */ 1223114878Sjulian 1224114878Sjulian for (pcb = LIST_FIRST(&s->dlcs); pcb != NULL; ) { 1225114878Sjulian mtx_lock(&pcb->pcb_mtx); 1226114878Sjulian pcb_next = LIST_NEXT(pcb, session_next); 1227114878Sjulian 1228114878Sjulian if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT) { 1229114878Sjulian pcb->mtu = s->mtu; 1230114878Sjulian bcopy(&so2l2cap_pcb(s->l2so)->src, &pcb->src, 1231114878Sjulian sizeof(pcb->src)); 1232114878Sjulian 1233114878Sjulian error = ng_btsocket_rfcomm_send_pn(pcb); 1234114878Sjulian if (error == 0) 1235114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONFIGURING; 1236161623Semax else 1237161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, error); 1238114878Sjulian } 1239114878Sjulian 1240114878Sjulian mtx_unlock(&pcb->pcb_mtx); 1241114878Sjulian pcb = pcb_next; 1242114878Sjulian } 1243114878Sjulian} /* ng_btsocket_rfcomm_connect_cfm */ 1244114878Sjulian 1245114878Sjulian/***************************************************************************** 1246114878Sjulian ***************************************************************************** 1247114878Sjulian ** RFCOMM sessions 1248114878Sjulian ***************************************************************************** 1249114878Sjulian *****************************************************************************/ 1250114878Sjulian 1251114878Sjulian/* 1252114878Sjulian * Create new RFCOMM session. That function WILL NOT take ownership over l2so. 1253114878Sjulian * Caller MUST free l2so if function failed. 1254114878Sjulian */ 1255114878Sjulian 1256114878Sjulianstatic int 1257114878Sjulianng_btsocket_rfcomm_session_create(ng_btsocket_rfcomm_session_p *sp, 1258114878Sjulian struct socket *l2so, bdaddr_p src, bdaddr_p dst, 1259114878Sjulian struct thread *td) 1260114878Sjulian{ 1261114878Sjulian ng_btsocket_rfcomm_session_p s = NULL; 1262114878Sjulian struct sockaddr_l2cap l2sa; 1263114878Sjulian struct sockopt l2sopt; 1264161579Semax int error; 1265161579Semax u_int16_t mtu; 1266114878Sjulian 1267114878Sjulian mtx_assert(&ng_btsocket_rfcomm_sessions_mtx, MA_OWNED); 1268114878Sjulian 1269114878Sjulian /* Allocate the RFCOMM session */ 1270184205Sdes s = malloc(sizeof(*s), 1271114878Sjulian M_NETGRAPH_BTSOCKET_RFCOMM, M_NOWAIT | M_ZERO); 1272114878Sjulian if (s == NULL) 1273114878Sjulian return (ENOMEM); 1274114878Sjulian 1275114878Sjulian /* Set defaults */ 1276114878Sjulian s->mtu = RFCOMM_DEFAULT_MTU; 1277114878Sjulian s->flags = 0; 1278114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 1279114878Sjulian NG_BT_MBUFQ_INIT(&s->outq, ifqmaxlen); 1280114878Sjulian 1281114878Sjulian /* 1282114878Sjulian * XXX Mark session mutex as DUPOK to prevent "duplicated lock of 1283114878Sjulian * the same type" message. When accepting new L2CAP connection 1284114878Sjulian * ng_btsocket_rfcomm_session_accept() holds both session mutexes 1285114878Sjulian * for "old" (accepting) session and "new" (created) session. 1286114878Sjulian */ 1287114878Sjulian 1288114878Sjulian mtx_init(&s->session_mtx, "btsocks_rfcomm_session_mtx", NULL, 1289114878Sjulian MTX_DEF|MTX_DUPOK); 1290114878Sjulian 1291114878Sjulian LIST_INIT(&s->dlcs); 1292114878Sjulian 1293114878Sjulian /* Prepare L2CAP socket */ 1294130653Srwatson SOCKBUF_LOCK(&l2so->so_rcv); 1295193272Sjhb soupcall_set(l2so, SO_RCV, ng_btsocket_rfcomm_upcall, NULL); 1296130653Srwatson SOCKBUF_UNLOCK(&l2so->so_rcv); 1297130653Srwatson SOCKBUF_LOCK(&l2so->so_snd); 1298193272Sjhb soupcall_set(l2so, SO_SND, ng_btsocket_rfcomm_upcall, NULL); 1299130653Srwatson SOCKBUF_UNLOCK(&l2so->so_snd); 1300114878Sjulian l2so->so_state |= SS_NBIO; 1301114878Sjulian s->l2so = l2so; 1302114878Sjulian 1303114878Sjulian mtx_lock(&s->session_mtx); 1304114878Sjulian 1305114878Sjulian /* 1306114878Sjulian * "src" == NULL and "dst" == NULL means just create session. 1307114878Sjulian * caller must do the rest 1308114878Sjulian */ 1309114878Sjulian 1310114878Sjulian if (src == NULL && dst == NULL) 1311114878Sjulian goto done; 1312114878Sjulian 1313114878Sjulian /* 1314114878Sjulian * Set incoming MTU on L2CAP socket. It is RFCOMM session default MTU 1315114878Sjulian * plus 5 bytes: RFCOMM frame header, one extra byte for length and one 1316114878Sjulian * extra byte for credits. 1317114878Sjulian */ 1318114878Sjulian 1319114878Sjulian mtu = s->mtu + sizeof(struct rfcomm_frame_hdr) + 1 + 1; 1320114878Sjulian 1321114878Sjulian l2sopt.sopt_dir = SOPT_SET; 1322114878Sjulian l2sopt.sopt_level = SOL_L2CAP; 1323114878Sjulian l2sopt.sopt_name = SO_L2CAP_IMTU; 1324114878Sjulian l2sopt.sopt_val = (void *) &mtu; 1325114878Sjulian l2sopt.sopt_valsize = sizeof(mtu); 1326114878Sjulian l2sopt.sopt_td = NULL; 1327114878Sjulian 1328114878Sjulian error = sosetopt(s->l2so, &l2sopt); 1329114878Sjulian if (error != 0) 1330114878Sjulian goto bad; 1331114878Sjulian 1332114878Sjulian /* Bind socket to "src" address */ 1333114878Sjulian l2sa.l2cap_len = sizeof(l2sa); 1334114878Sjulian l2sa.l2cap_family = AF_BLUETOOTH; 1335114878Sjulian l2sa.l2cap_psm = (dst == NULL)? htole16(NG_L2CAP_PSM_RFCOMM) : 0; 1336114878Sjulian bcopy(src, &l2sa.l2cap_bdaddr, sizeof(l2sa.l2cap_bdaddr)); 1337114878Sjulian 1338114878Sjulian error = sobind(s->l2so, (struct sockaddr *) &l2sa, td); 1339114878Sjulian if (error != 0) 1340114878Sjulian goto bad; 1341114878Sjulian 1342114878Sjulian /* If "dst" is not NULL then initiate connect(), otherwise listen() */ 1343114878Sjulian if (dst == NULL) { 1344114878Sjulian s->flags = 0; 1345114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_LISTENING; 1346114878Sjulian 1347114878Sjulian error = solisten(s->l2so, 10, td); 1348114878Sjulian if (error != 0) 1349114878Sjulian goto bad; 1350114878Sjulian } else { 1351114878Sjulian s->flags = NG_BTSOCKET_RFCOMM_SESSION_INITIATOR; 1352114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CONNECTING; 1353114878Sjulian 1354114878Sjulian l2sa.l2cap_len = sizeof(l2sa); 1355114878Sjulian l2sa.l2cap_family = AF_BLUETOOTH; 1356114878Sjulian l2sa.l2cap_psm = htole16(NG_L2CAP_PSM_RFCOMM); 1357114878Sjulian bcopy(dst, &l2sa.l2cap_bdaddr, sizeof(l2sa.l2cap_bdaddr)); 1358114878Sjulian 1359114878Sjulian error = soconnect(s->l2so, (struct sockaddr *) &l2sa, td); 1360114878Sjulian if (error != 0) 1361114878Sjulian goto bad; 1362114878Sjulian } 1363114878Sjulian 1364114878Sjuliandone: 1365114878Sjulian LIST_INSERT_HEAD(&ng_btsocket_rfcomm_sessions, s, next); 1366114878Sjulian *sp = s; 1367114878Sjulian 1368114878Sjulian mtx_unlock(&s->session_mtx); 1369114878Sjulian 1370114878Sjulian return (0); 1371114878Sjulian 1372114878Sjulianbad: 1373114878Sjulian mtx_unlock(&s->session_mtx); 1374114878Sjulian 1375114878Sjulian /* Return L2CAP socket back to its original state */ 1376130653Srwatson SOCKBUF_LOCK(&l2so->so_rcv); 1377193272Sjhb soupcall_clear(s->l2so, SO_RCV); 1378130670Srwatson SOCKBUF_UNLOCK(&l2so->so_rcv); 1379130653Srwatson SOCKBUF_LOCK(&l2so->so_snd); 1380193272Sjhb soupcall_clear(s->l2so, SO_SND); 1381130670Srwatson SOCKBUF_UNLOCK(&l2so->so_snd); 1382114878Sjulian l2so->so_state &= ~SS_NBIO; 1383114878Sjulian 1384114878Sjulian mtx_destroy(&s->session_mtx); 1385114878Sjulian bzero(s, sizeof(*s)); 1386184205Sdes free(s, M_NETGRAPH_BTSOCKET_RFCOMM); 1387114878Sjulian 1388114878Sjulian return (error); 1389114878Sjulian} /* ng_btsocket_rfcomm_session_create */ 1390114878Sjulian 1391114878Sjulian/* 1392114878Sjulian * Process accept() on RFCOMM session 1393114878Sjulian * XXX FIXME locking for "l2so"? 1394114878Sjulian */ 1395114878Sjulian 1396114878Sjulianstatic int 1397114878Sjulianng_btsocket_rfcomm_session_accept(ng_btsocket_rfcomm_session_p s0) 1398114878Sjulian{ 1399114878Sjulian struct socket *l2so = NULL; 1400114878Sjulian struct sockaddr_l2cap *l2sa = NULL; 1401114878Sjulian ng_btsocket_l2cap_pcb_t *l2pcb = NULL; 1402114878Sjulian ng_btsocket_rfcomm_session_p s = NULL; 1403114878Sjulian int error = 0; 1404114878Sjulian 1405114878Sjulian mtx_assert(&ng_btsocket_rfcomm_sessions_mtx, MA_OWNED); 1406114878Sjulian mtx_assert(&s0->session_mtx, MA_OWNED); 1407114878Sjulian 1408114878Sjulian /* Check if there is a complete L2CAP connection in the queue */ 1409114878Sjulian if ((error = s0->l2so->so_error) != 0) { 1410114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1411114878Sjulian"%s: Could not accept connection on L2CAP socket, error=%d\n", __func__, error); 1412114878Sjulian s0->l2so->so_error = 0; 1413114878Sjulian 1414114878Sjulian return (error); 1415114878Sjulian } 1416114878Sjulian 1417129979Srwatson ACCEPT_LOCK(); 1418114878Sjulian if (TAILQ_EMPTY(&s0->l2so->so_comp)) { 1419129979Srwatson ACCEPT_UNLOCK(); 1420130480Srwatson if (s0->l2so->so_rcv.sb_state & SBS_CANTRCVMORE) 1421114878Sjulian return (ECONNABORTED); 1422114878Sjulian return (EWOULDBLOCK); 1423114878Sjulian } 1424114878Sjulian 1425114878Sjulian /* Accept incoming L2CAP connection */ 1426114878Sjulian l2so = TAILQ_FIRST(&s0->l2so->so_comp); 1427114878Sjulian if (l2so == NULL) 1428114878Sjulian panic("%s: l2so == NULL\n", __func__); 1429114878Sjulian 1430114878Sjulian TAILQ_REMOVE(&s0->l2so->so_comp, l2so, so_list); 1431114878Sjulian s0->l2so->so_qlen --; 1432129979Srwatson l2so->so_qstate &= ~SQ_COMP; 1433129979Srwatson l2so->so_head = NULL; 1434130387Srwatson SOCK_LOCK(l2so); 1435114878Sjulian soref(l2so); 1436114878Sjulian l2so->so_state |= SS_NBIO; 1437130387Srwatson SOCK_UNLOCK(l2so); 1438129979Srwatson ACCEPT_UNLOCK(); 1439114878Sjulian 1440114878Sjulian error = soaccept(l2so, (struct sockaddr **) &l2sa); 1441114878Sjulian if (error != 0) { 1442114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1443114878Sjulian"%s: soaccept() on L2CAP socket failed, error=%d\n", __func__, error); 1444114878Sjulian soclose(l2so); 1445114878Sjulian 1446114878Sjulian return (error); 1447114878Sjulian } 1448114878Sjulian 1449114878Sjulian /* 1450114878Sjulian * Check if there is already active RFCOMM session between two devices. 1451114878Sjulian * If so then close L2CAP connection. We only support one RFCOMM session 1452114878Sjulian * between each pair of devices. Note that here we assume session in any 1453114878Sjulian * state. The session even could be in the middle of disconnecting. 1454114878Sjulian */ 1455114878Sjulian 1456114878Sjulian l2pcb = so2l2cap_pcb(l2so); 1457114878Sjulian s = ng_btsocket_rfcomm_session_by_addr(&l2pcb->src, &l2pcb->dst); 1458114878Sjulian if (s == NULL) { 1459114878Sjulian /* Create a new RFCOMM session */ 1460114878Sjulian error = ng_btsocket_rfcomm_session_create(&s, l2so, NULL, NULL, 1461114878Sjulian curthread /* XXX */); 1462114878Sjulian if (error == 0) { 1463114878Sjulian mtx_lock(&s->session_mtx); 1464114878Sjulian 1465114878Sjulian s->flags = 0; 1466114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CONNECTED; 1467114878Sjulian 1468114878Sjulian /* 1469114878Sjulian * Adjust MTU on incomming connection. Reserve 5 bytes: 1470114878Sjulian * RFCOMM frame header, one extra byte for length and 1471114878Sjulian * one extra byte for credits. 1472114878Sjulian */ 1473114878Sjulian 1474114878Sjulian s->mtu = min(l2pcb->imtu, l2pcb->omtu) - 1475114878Sjulian sizeof(struct rfcomm_frame_hdr) - 1 - 1; 1476114878Sjulian 1477114878Sjulian mtx_unlock(&s->session_mtx); 1478114878Sjulian } else { 1479114878Sjulian NG_BTSOCKET_RFCOMM_ALERT( 1480114878Sjulian"%s: Failed to create new RFCOMM session, error=%d\n", __func__, error); 1481114878Sjulian 1482114878Sjulian soclose(l2so); 1483114878Sjulian } 1484114878Sjulian } else { 1485114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 1486114878Sjulian"%s: Rejecting duplicating RFCOMM session between src=%x:%x:%x:%x:%x:%x and " \ 1487114878Sjulian"dst=%x:%x:%x:%x:%x:%x, state=%d, flags=%#x\n", __func__, 1488114878Sjulian l2pcb->src.b[5], l2pcb->src.b[4], l2pcb->src.b[3], 1489114878Sjulian l2pcb->src.b[2], l2pcb->src.b[1], l2pcb->src.b[0], 1490114878Sjulian l2pcb->dst.b[5], l2pcb->dst.b[4], l2pcb->dst.b[3], 1491114878Sjulian l2pcb->dst.b[2], l2pcb->dst.b[1], l2pcb->dst.b[0], 1492114878Sjulian s->state, s->flags); 1493114878Sjulian 1494114878Sjulian error = EBUSY; 1495114878Sjulian soclose(l2so); 1496114878Sjulian } 1497114878Sjulian 1498114878Sjulian return (error); 1499114878Sjulian} /* ng_btsocket_rfcomm_session_accept */ 1500114878Sjulian 1501114878Sjulian/* 1502114878Sjulian * Process connect() on RFCOMM session 1503114878Sjulian * XXX FIXME locking for "l2so"? 1504114878Sjulian */ 1505114878Sjulian 1506114878Sjulianstatic int 1507114878Sjulianng_btsocket_rfcomm_session_connect(ng_btsocket_rfcomm_session_p s) 1508114878Sjulian{ 1509114878Sjulian ng_btsocket_l2cap_pcb_p l2pcb = so2l2cap_pcb(s->l2so); 1510114878Sjulian int error; 1511114878Sjulian 1512114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1513114878Sjulian 1514114878Sjulian /* First check if connection has failed */ 1515114878Sjulian if ((error = s->l2so->so_error) != 0) { 1516114878Sjulian s->l2so->so_error = 0; 1517114878Sjulian 1518114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1519114878Sjulian"%s: Could not connect RFCOMM session, error=%d, state=%d, flags=%#x\n", 1520114878Sjulian __func__, error, s->state, s->flags); 1521114878Sjulian 1522114878Sjulian return (error); 1523114878Sjulian } 1524114878Sjulian 1525114878Sjulian /* Is connection still in progress? */ 1526114878Sjulian if (s->l2so->so_state & SS_ISCONNECTING) 1527114878Sjulian return (0); 1528114878Sjulian 1529114878Sjulian /* 1530114878Sjulian * If we got here then we are connected. Send SABM on DLCI 0 to 1531114878Sjulian * open multiplexor channel. 1532114878Sjulian */ 1533114878Sjulian 1534114878Sjulian if (error == 0) { 1535114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CONNECTED; 1536114878Sjulian 1537114878Sjulian /* 1538114878Sjulian * Adjust MTU on outgoing connection. Reserve 5 bytes: RFCOMM 1539114878Sjulian * frame header, one extra byte for length and one extra byte 1540114878Sjulian * for credits. 1541114878Sjulian */ 1542114878Sjulian 1543114878Sjulian s->mtu = min(l2pcb->imtu, l2pcb->omtu) - 1544114878Sjulian sizeof(struct rfcomm_frame_hdr) - 1 - 1; 1545114878Sjulian 1546114878Sjulian error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_SABM,0); 1547114878Sjulian if (error == 0) 1548114878Sjulian error = ng_btsocket_rfcomm_task_wakeup(); 1549114878Sjulian } 1550114878Sjulian 1551114878Sjulian return (error); 1552114878Sjulian}/* ng_btsocket_rfcomm_session_connect */ 1553114878Sjulian 1554114878Sjulian/* 1555114878Sjulian * Receive data on RFCOMM session 1556114878Sjulian * XXX FIXME locking for "l2so"? 1557114878Sjulian */ 1558114878Sjulian 1559114878Sjulianstatic int 1560114878Sjulianng_btsocket_rfcomm_session_receive(ng_btsocket_rfcomm_session_p s) 1561114878Sjulian{ 1562114878Sjulian struct mbuf *m = NULL; 1563114878Sjulian struct uio uio; 1564114878Sjulian int more, flags, error; 1565114878Sjulian 1566114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1567114878Sjulian 1568114878Sjulian /* Can we read from the L2CAP socket? */ 1569114878Sjulian if (!soreadable(s->l2so)) 1570114878Sjulian return (0); 1571114878Sjulian 1572114878Sjulian /* First check for error on L2CAP socket */ 1573114878Sjulian if ((error = s->l2so->so_error) != 0) { 1574114878Sjulian s->l2so->so_error = 0; 1575114878Sjulian 1576114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1577114878Sjulian"%s: Could not receive data from L2CAP socket, error=%d, state=%d, flags=%#x\n", 1578114878Sjulian __func__, error, s->state, s->flags); 1579114878Sjulian 1580114878Sjulian return (error); 1581114878Sjulian } 1582114878Sjulian 1583114878Sjulian /* 1584114878Sjulian * Read all packets from the L2CAP socket. 1585114878Sjulian * XXX FIXME/VERIFY is that correct? For now use m->m_nextpkt as 1586114878Sjulian * indication that there is more packets on the socket's buffer. 1587114878Sjulian * Also what should we use in uio.uio_resid? 1588114878Sjulian * May be s->mtu + sizeof(struct rfcomm_frame_hdr) + 1 + 1? 1589114878Sjulian */ 1590114878Sjulian 1591114878Sjulian for (more = 1; more; ) { 1592114878Sjulian /* Try to get next packet from socket */ 1593114878Sjulian bzero(&uio, sizeof(uio)); 1594114878Sjulian/* uio.uio_td = NULL; */ 1595114878Sjulian uio.uio_resid = 1000000000; 1596114878Sjulian flags = MSG_DONTWAIT; 1597114878Sjulian 1598114878Sjulian m = NULL; 1599160619Srwatson error = soreceive(s->l2so, NULL, &uio, &m, 1600160619Srwatson (struct mbuf **) NULL, &flags); 1601114878Sjulian if (error != 0) { 1602114878Sjulian if (error == EWOULDBLOCK) 1603114878Sjulian return (0); /* XXX can happen? */ 1604114878Sjulian 1605114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1606114878Sjulian"%s: Could not receive data from L2CAP socket, error=%d\n", __func__, error); 1607114878Sjulian 1608114878Sjulian return (error); 1609114878Sjulian } 1610114878Sjulian 1611114878Sjulian more = (m->m_nextpkt != NULL); 1612114878Sjulian m->m_nextpkt = NULL; 1613114878Sjulian 1614114878Sjulian ng_btsocket_rfcomm_receive_frame(s, m); 1615114878Sjulian } 1616114878Sjulian 1617114878Sjulian return (0); 1618114878Sjulian} /* ng_btsocket_rfcomm_session_receive */ 1619114878Sjulian 1620114878Sjulian/* 1621114878Sjulian * Send data on RFCOMM session 1622114878Sjulian * XXX FIXME locking for "l2so"? 1623114878Sjulian */ 1624114878Sjulian 1625114878Sjulianstatic int 1626114878Sjulianng_btsocket_rfcomm_session_send(ng_btsocket_rfcomm_session_p s) 1627114878Sjulian{ 1628114878Sjulian struct mbuf *m = NULL; 1629114878Sjulian int error; 1630114878Sjulian 1631114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1632114878Sjulian 1633114878Sjulian /* Send as much as we can from the session queue */ 1634114878Sjulian while (sowriteable(s->l2so)) { 1635114878Sjulian /* Check if socket still OK */ 1636114878Sjulian if ((error = s->l2so->so_error) != 0) { 1637114878Sjulian s->l2so->so_error = 0; 1638114878Sjulian 1639114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1640114878Sjulian"%s: Detected error=%d on L2CAP socket, state=%d, flags=%#x\n", 1641114878Sjulian __func__, error, s->state, s->flags); 1642114878Sjulian 1643114878Sjulian return (error); 1644114878Sjulian } 1645114878Sjulian 1646114878Sjulian NG_BT_MBUFQ_DEQUEUE(&s->outq, m); 1647114878Sjulian if (m == NULL) 1648114878Sjulian return (0); /* we are done */ 1649114878Sjulian 1650114878Sjulian /* Call send function on the L2CAP socket */ 1651170972Semax error = (*s->l2so->so_proto->pr_usrreqs->pru_send)(s->l2so, 1652170972Semax 0, m, NULL, NULL, curthread /* XXX */); 1653114878Sjulian if (error != 0) { 1654114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1655114878Sjulian"%s: Could not send data to L2CAP socket, error=%d\n", __func__, error); 1656114878Sjulian 1657114878Sjulian return (error); 1658114878Sjulian } 1659114878Sjulian } 1660114878Sjulian 1661114878Sjulian return (0); 1662114878Sjulian} /* ng_btsocket_rfcomm_session_send */ 1663114878Sjulian 1664114878Sjulian/* 1665114878Sjulian * Close and disconnect all DLCs for the given session. Caller must hold 1666114878Sjulian * s->sesson_mtx. Will wakeup session. 1667114878Sjulian */ 1668114878Sjulian 1669114878Sjulianstatic void 1670114878Sjulianng_btsocket_rfcomm_session_clean(ng_btsocket_rfcomm_session_p s) 1671114878Sjulian{ 1672161623Semax ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb_next = NULL; 1673161623Semax int error; 1674114878Sjulian 1675114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1676114878Sjulian 1677114878Sjulian /* 1678114878Sjulian * Note: cannot use LIST_FOREACH because ng_btsocket_rfcomm_pcb_kill 1679114878Sjulian * will unlink DLC from the session 1680114878Sjulian */ 1681114878Sjulian 1682114878Sjulian for (pcb = LIST_FIRST(&s->dlcs); pcb != NULL; ) { 1683114878Sjulian mtx_lock(&pcb->pcb_mtx); 1684114878Sjulian pcb_next = LIST_NEXT(pcb, session_next); 1685114878Sjulian 1686114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 1687114878Sjulian"%s: Disconnecting dlci=%d, state=%d, flags=%#x\n", 1688114878Sjulian __func__, pcb->dlci, pcb->state, pcb->flags); 1689114878Sjulian 1690114878Sjulian if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONNECTED) 1691114878Sjulian error = ECONNRESET; 1692114878Sjulian else 1693114878Sjulian error = ECONNREFUSED; 1694114878Sjulian 1695161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, error); 1696114878Sjulian 1697114878Sjulian mtx_unlock(&pcb->pcb_mtx); 1698114878Sjulian pcb = pcb_next; 1699114878Sjulian } 1700114878Sjulian} /* ng_btsocket_rfcomm_session_clean */ 1701114878Sjulian 1702114878Sjulian/* 1703114878Sjulian * Process all DLCs on the session. Caller MUST hold s->session_mtx. 1704114878Sjulian */ 1705114878Sjulian 1706114878Sjulianstatic void 1707114878Sjulianng_btsocket_rfcomm_session_process_pcb(ng_btsocket_rfcomm_session_p s) 1708114878Sjulian{ 1709161623Semax ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb_next = NULL; 1710161623Semax int error; 1711114878Sjulian 1712114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1713114878Sjulian 1714114878Sjulian /* 1715114878Sjulian * Note: cannot use LIST_FOREACH because ng_btsocket_rfcomm_pcb_kill 1716114878Sjulian * will unlink DLC from the session 1717114878Sjulian */ 1718114878Sjulian 1719114878Sjulian for (pcb = LIST_FIRST(&s->dlcs); pcb != NULL; ) { 1720114878Sjulian mtx_lock(&pcb->pcb_mtx); 1721114878Sjulian pcb_next = LIST_NEXT(pcb, session_next); 1722114878Sjulian 1723114878Sjulian switch (pcb->state) { 1724114878Sjulian 1725114878Sjulian /* 1726114878Sjulian * If DLC in W4_CONNECT state then we should check for both 1727114878Sjulian * timeout and detach. 1728114878Sjulian */ 1729114878Sjulian 1730114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT: 1731161623Semax if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_DETACHED) 1732161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, 0); 1733161623Semax else if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT) 1734161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, ETIMEDOUT); 1735114878Sjulian break; 1736114878Sjulian 1737114878Sjulian /* 1738114878Sjulian * If DLC in CONFIGURING or CONNECTING state then we only 1739114878Sjulian * should check for timeout. If detach() was called then 1740114878Sjulian * DLC will be moved into DISCONNECTING state. 1741114878Sjulian */ 1742114878Sjulian 1743114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING: 1744114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONNECTING: 1745114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT) 1746161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, ETIMEDOUT); 1747114878Sjulian break; 1748114878Sjulian 1749114878Sjulian /* 1750114878Sjulian * If DLC in CONNECTED state then we need to send data (if any) 1751114878Sjulian * from the socket's send queue. Note that we will send data 1752114878Sjulian * from either all sockets or none. This may overload session's 1753114878Sjulian * outgoing queue (but we do not check for that). 1754114878Sjulian * 1755114878Sjulian * XXX FIXME need scheduler for RFCOMM sockets 1756114878Sjulian */ 1757114878Sjulian 1758114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONNECTED: 1759114878Sjulian error = ng_btsocket_rfcomm_pcb_send(pcb, ALOT); 1760114878Sjulian if (error != 0) 1761161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, error); 1762114878Sjulian break; 1763114878Sjulian 1764114878Sjulian /* 1765114878Sjulian * If DLC in DISCONNECTING state then we must send DISC frame. 1766114878Sjulian * Note that if DLC has timeout set then we do not need to 1767114878Sjulian * resend DISC frame. 1768114878Sjulian * 1769114878Sjulian * XXX FIXME need to drain all data from the socket's queue 1770114878Sjulian * if LINGER option was set 1771114878Sjulian */ 1772114878Sjulian 1773114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING: 1774114878Sjulian if (!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)) { 1775114878Sjulian error = ng_btsocket_rfcomm_send_command( 1776114878Sjulian pcb->session, RFCOMM_FRAME_DISC, 1777114878Sjulian pcb->dlci); 1778114878Sjulian if (error == 0) 1779114878Sjulian ng_btsocket_rfcomm_timeout(pcb); 1780161623Semax else 1781161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, error); 1782114878Sjulian } else if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT) 1783161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, ETIMEDOUT); 1784114878Sjulian break; 1785114878Sjulian 1786114878Sjulian/* case NG_BTSOCKET_RFCOMM_DLC_CLOSED: */ 1787114878Sjulian default: 1788114878Sjulian panic("%s: Invalid DLC state=%d, flags=%#x\n", 1789114878Sjulian __func__, pcb->state, pcb->flags); 1790114878Sjulian break; 1791114878Sjulian } 1792114878Sjulian 1793114878Sjulian mtx_unlock(&pcb->pcb_mtx); 1794114878Sjulian pcb = pcb_next; 1795114878Sjulian } 1796114878Sjulian} /* ng_btsocket_rfcomm_session_process_pcb */ 1797114878Sjulian 1798114878Sjulian/* 1799114878Sjulian * Find RFCOMM session between "src" and "dst". 1800114878Sjulian * Caller MUST hold ng_btsocket_rfcomm_sessions_mtx. 1801114878Sjulian */ 1802114878Sjulian 1803114878Sjulianstatic ng_btsocket_rfcomm_session_p 1804114878Sjulianng_btsocket_rfcomm_session_by_addr(bdaddr_p src, bdaddr_p dst) 1805114878Sjulian{ 1806114878Sjulian ng_btsocket_rfcomm_session_p s = NULL; 1807114878Sjulian ng_btsocket_l2cap_pcb_p l2pcb = NULL; 1808114878Sjulian int any_src; 1809114878Sjulian 1810114878Sjulian mtx_assert(&ng_btsocket_rfcomm_sessions_mtx, MA_OWNED); 1811114878Sjulian 1812114878Sjulian any_src = (bcmp(src, NG_HCI_BDADDR_ANY, sizeof(*src)) == 0); 1813114878Sjulian 1814114878Sjulian LIST_FOREACH(s, &ng_btsocket_rfcomm_sessions, next) { 1815114878Sjulian l2pcb = so2l2cap_pcb(s->l2so); 1816114878Sjulian 1817114878Sjulian if ((any_src || bcmp(&l2pcb->src, src, sizeof(*src)) == 0) && 1818114878Sjulian bcmp(&l2pcb->dst, dst, sizeof(*dst)) == 0) 1819114878Sjulian break; 1820114878Sjulian } 1821114878Sjulian 1822114878Sjulian return (s); 1823114878Sjulian} /* ng_btsocket_rfcomm_session_by_addr */ 1824114878Sjulian 1825114878Sjulian/***************************************************************************** 1826114878Sjulian ***************************************************************************** 1827114878Sjulian ** RFCOMM 1828114878Sjulian ***************************************************************************** 1829114878Sjulian *****************************************************************************/ 1830114878Sjulian 1831114878Sjulian/* 1832114878Sjulian * Process incoming RFCOMM frame. Caller must hold s->session_mtx. 1833114878Sjulian * XXX FIXME check frame length 1834114878Sjulian */ 1835114878Sjulian 1836114878Sjulianstatic int 1837114878Sjulianng_btsocket_rfcomm_receive_frame(ng_btsocket_rfcomm_session_p s, 1838114878Sjulian struct mbuf *m0) 1839114878Sjulian{ 1840114878Sjulian struct rfcomm_frame_hdr *hdr = NULL; 1841114878Sjulian struct mbuf *m = NULL; 1842114878Sjulian u_int16_t length; 1843114878Sjulian u_int8_t dlci, type; 1844114878Sjulian int error = 0; 1845114878Sjulian 1846114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1847114878Sjulian 1848114878Sjulian /* Pullup as much as we can into first mbuf (for direct access) */ 1849114878Sjulian length = min(m0->m_pkthdr.len, MHLEN); 1850114878Sjulian if (m0->m_len < length) { 1851114878Sjulian if ((m0 = m_pullup(m0, length)) == NULL) { 1852114878Sjulian NG_BTSOCKET_RFCOMM_ALERT( 1853114878Sjulian"%s: m_pullup(%d) failed\n", __func__, length); 1854114878Sjulian 1855114878Sjulian return (ENOBUFS); 1856114878Sjulian } 1857114878Sjulian } 1858114878Sjulian 1859114878Sjulian hdr = mtod(m0, struct rfcomm_frame_hdr *); 1860114878Sjulian dlci = RFCOMM_DLCI(hdr->address); 1861114878Sjulian type = RFCOMM_TYPE(hdr->control); 1862114878Sjulian 1863114878Sjulian /* Test EA bit in length. If not set then we have 2 bytes of length */ 1864114878Sjulian if (!RFCOMM_EA(hdr->length)) { 1865114878Sjulian bcopy(&hdr->length, &length, sizeof(length)); 1866144721Semax length = le16toh(length) >> 1; 1867114878Sjulian m_adj(m0, sizeof(*hdr) + 1); 1868114878Sjulian } else { 1869114878Sjulian length = hdr->length >> 1; 1870114878Sjulian m_adj(m0, sizeof(*hdr)); 1871114878Sjulian } 1872114878Sjulian 1873114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 1874114878Sjulian"%s: Got frame type=%#x, dlci=%d, length=%d, cr=%d, pf=%d, len=%d\n", 1875114878Sjulian __func__, type, dlci, length, RFCOMM_CR(hdr->address), 1876114878Sjulian RFCOMM_PF(hdr->control), m0->m_pkthdr.len); 1877114878Sjulian 1878114878Sjulian /* 1879114878Sjulian * Get FCS (the last byte in the frame) 1880114878Sjulian * XXX this will not work if mbuf chain ends with empty mbuf. 1881114878Sjulian * XXX let's hope it never happens :) 1882114878Sjulian */ 1883114878Sjulian 1884114878Sjulian for (m = m0; m->m_next != NULL; m = m->m_next) 1885114878Sjulian ; 1886114878Sjulian if (m->m_len <= 0) 1887114878Sjulian panic("%s: Empty mbuf at the end of the chain, len=%d\n", 1888114878Sjulian __func__, m->m_len); 1889114878Sjulian 1890114878Sjulian /* 1891114878Sjulian * Check FCS. We only need to calculate FCS on first 2 or 3 bytes 1892114878Sjulian * and already m_pullup'ed mbuf chain, so it should be safe. 1893114878Sjulian */ 1894114878Sjulian 1895114878Sjulian if (ng_btsocket_rfcomm_check_fcs((u_int8_t *) hdr, type, m->m_data[m->m_len - 1])) { 1896114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1897114878Sjulian"%s: Invalid RFCOMM packet. Bad checksum\n", __func__); 1898114878Sjulian NG_FREE_M(m0); 1899114878Sjulian 1900114878Sjulian return (EINVAL); 1901114878Sjulian } 1902114878Sjulian 1903114878Sjulian m_adj(m0, -1); /* Trim FCS byte */ 1904114878Sjulian 1905114878Sjulian /* 1906114878Sjulian * Process RFCOMM frame. 1907114878Sjulian * 1908114878Sjulian * From TS 07.10 spec 1909114878Sjulian * 1910114878Sjulian * "... In the case where a SABM or DISC command with the P bit set 1911114878Sjulian * to 0 is received then the received frame shall be discarded..." 1912114878Sjulian * 1913114878Sjulian * "... If a unsolicited DM response is received then the frame shall 1914114878Sjulian * be processed irrespective of the P/F setting... " 1915114878Sjulian * 1916114878Sjulian * "... The station may transmit response frames with the F bit set 1917114878Sjulian * to 0 at any opportunity on an asynchronous basis. However, in the 1918114878Sjulian * case where a UA response is received with the F bit set to 0 then 1919114878Sjulian * the received frame shall be discarded..." 1920114878Sjulian * 1921114878Sjulian * From Bluetooth spec 1922114878Sjulian * 1923114878Sjulian * "... When credit based flow control is being used, the meaning of 1924114878Sjulian * the P/F bit in the control field of the RFCOMM header is redefined 1925114878Sjulian * for UIH frames..." 1926114878Sjulian */ 1927114878Sjulian 1928114878Sjulian switch (type) { 1929114878Sjulian case RFCOMM_FRAME_SABM: 1930114878Sjulian if (RFCOMM_PF(hdr->control)) 1931114878Sjulian error = ng_btsocket_rfcomm_receive_sabm(s, dlci); 1932114878Sjulian break; 1933114878Sjulian 1934114878Sjulian case RFCOMM_FRAME_DISC: 1935114878Sjulian if (RFCOMM_PF(hdr->control)) 1936114878Sjulian error = ng_btsocket_rfcomm_receive_disc(s, dlci); 1937114878Sjulian break; 1938114878Sjulian 1939114878Sjulian case RFCOMM_FRAME_UA: 1940114878Sjulian if (RFCOMM_PF(hdr->control)) 1941114878Sjulian error = ng_btsocket_rfcomm_receive_ua(s, dlci); 1942114878Sjulian break; 1943114878Sjulian 1944114878Sjulian case RFCOMM_FRAME_DM: 1945114878Sjulian error = ng_btsocket_rfcomm_receive_dm(s, dlci); 1946114878Sjulian break; 1947114878Sjulian 1948114878Sjulian case RFCOMM_FRAME_UIH: 1949114878Sjulian if (dlci == 0) 1950114878Sjulian error = ng_btsocket_rfcomm_receive_mcc(s, m0); 1951114878Sjulian else 1952114878Sjulian error = ng_btsocket_rfcomm_receive_uih(s, dlci, 1953114878Sjulian RFCOMM_PF(hdr->control), m0); 1954114878Sjulian 1955114878Sjulian return (error); 1956114878Sjulian /* NOT REACHED */ 1957114878Sjulian 1958114878Sjulian default: 1959114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1960114878Sjulian"%s: Invalid RFCOMM packet. Unknown type=%#x\n", __func__, type); 1961114878Sjulian error = EINVAL; 1962114878Sjulian break; 1963114878Sjulian } 1964114878Sjulian 1965114878Sjulian NG_FREE_M(m0); 1966114878Sjulian 1967114878Sjulian return (error); 1968114878Sjulian} /* ng_btsocket_rfcomm_receive_frame */ 1969114878Sjulian 1970114878Sjulian/* 1971114878Sjulian * Process RFCOMM SABM frame 1972114878Sjulian */ 1973114878Sjulian 1974114878Sjulianstatic int 1975114878Sjulianng_btsocket_rfcomm_receive_sabm(ng_btsocket_rfcomm_session_p s, int dlci) 1976114878Sjulian{ 1977161623Semax ng_btsocket_rfcomm_pcb_p pcb = NULL; 1978161623Semax int error = 0; 1979114878Sjulian 1980114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1981114878Sjulian 1982114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 1983114878Sjulian"%s: Got SABM, session state=%d, flags=%#x, mtu=%d, dlci=%d\n", 1984114878Sjulian __func__, s->state, s->flags, s->mtu, dlci); 1985114878Sjulian 1986114878Sjulian /* DLCI == 0 means open multiplexor channel */ 1987114878Sjulian if (dlci == 0) { 1988114878Sjulian switch (s->state) { 1989114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED: 1990114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_OPEN: 1991114878Sjulian error = ng_btsocket_rfcomm_send_command(s, 1992114878Sjulian RFCOMM_FRAME_UA, dlci); 1993114878Sjulian if (error == 0) { 1994114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_OPEN; 1995114878Sjulian ng_btsocket_rfcomm_connect_cfm(s); 1996114878Sjulian } else { 1997114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 1998114878Sjulian ng_btsocket_rfcomm_session_clean(s); 1999114878Sjulian } 2000114878Sjulian break; 2001114878Sjulian 2002114878Sjulian default: 2003114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2004114878Sjulian"%s: Got SABM for session in invalid state state=%d, flags=%#x\n", 2005114878Sjulian __func__, s->state, s->flags); 2006114878Sjulian error = EINVAL; 2007114878Sjulian break; 2008114878Sjulian } 2009114878Sjulian 2010114878Sjulian return (error); 2011114878Sjulian } 2012114878Sjulian 2013114878Sjulian /* Make sure multiplexor channel is open */ 2014114878Sjulian if (s->state != NG_BTSOCKET_RFCOMM_SESSION_OPEN) { 2015114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2016114878Sjulian"%s: Got SABM for dlci=%d with mulitplexor channel closed, state=%d, " \ 2017114878Sjulian"flags=%#x\n", __func__, dlci, s->state, s->flags); 2018114878Sjulian 2019114878Sjulian return (EINVAL); 2020114878Sjulian } 2021114878Sjulian 2022114878Sjulian /* 2023114878Sjulian * Check if we have this DLCI. This might happen when remote 2024114878Sjulian * peer uses PN command before actual open (SABM) happens. 2025114878Sjulian */ 2026114878Sjulian 2027114878Sjulian pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci); 2028114878Sjulian if (pcb != NULL) { 2029114878Sjulian mtx_lock(&pcb->pcb_mtx); 2030114878Sjulian 2031114878Sjulian if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTING) { 2032114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2033114878Sjulian"%s: Got SABM for dlci=%d in invalid state=%d, flags=%#x\n", 2034114878Sjulian __func__, dlci, pcb->state, pcb->flags); 2035114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2036114878Sjulian 2037114878Sjulian return (ENOENT); 2038114878Sjulian } 2039114878Sjulian 2040114878Sjulian ng_btsocket_rfcomm_untimeout(pcb); 2041114878Sjulian 2042114878Sjulian error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_UA,dlci); 2043114878Sjulian if (error == 0) 2044114878Sjulian error = ng_btsocket_rfcomm_send_msc(pcb); 2045114878Sjulian 2046114878Sjulian if (error == 0) { 2047114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTED; 2048114878Sjulian soisconnected(pcb->so); 2049161623Semax } else 2050161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, error); 2051114878Sjulian 2052114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2053114878Sjulian 2054114878Sjulian return (error); 2055114878Sjulian } 2056114878Sjulian 2057114878Sjulian /* 2058114878Sjulian * We do not have requested DLCI, so it must be an incoming connection 2059114878Sjulian * with default parameters. Try to accept it. 2060114878Sjulian */ 2061114878Sjulian 2062114878Sjulian pcb = ng_btsocket_rfcomm_connect_ind(s, RFCOMM_SRVCHANNEL(dlci)); 2063114878Sjulian if (pcb != NULL) { 2064114878Sjulian mtx_lock(&pcb->pcb_mtx); 2065114878Sjulian 2066114878Sjulian pcb->dlci = dlci; 2067114878Sjulian 2068114878Sjulian error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_UA,dlci); 2069121054Semax if (error == 0) 2070121054Semax error = ng_btsocket_rfcomm_send_msc(pcb); 2071121054Semax 2072114878Sjulian if (error == 0) { 2073114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTED; 2074114878Sjulian soisconnected(pcb->so); 2075161623Semax } else 2076161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, error); 2077114878Sjulian 2078114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2079114878Sjulian } else 2080114878Sjulian /* Nobody is listen()ing on the requested DLCI */ 2081114878Sjulian error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_DM,dlci); 2082114878Sjulian 2083114878Sjulian return (error); 2084114878Sjulian} /* ng_btsocket_rfcomm_receive_sabm */ 2085114878Sjulian 2086114878Sjulian/* 2087114878Sjulian * Process RFCOMM DISC frame 2088114878Sjulian */ 2089114878Sjulian 2090114878Sjulianstatic int 2091114878Sjulianng_btsocket_rfcomm_receive_disc(ng_btsocket_rfcomm_session_p s, int dlci) 2092114878Sjulian{ 2093114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = NULL; 2094114878Sjulian int error = 0; 2095114878Sjulian 2096114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2097114878Sjulian 2098114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2099114878Sjulian"%s: Got DISC, session state=%d, flags=%#x, mtu=%d, dlci=%d\n", 2100114878Sjulian __func__, s->state, s->flags, s->mtu, dlci); 2101114878Sjulian 2102114878Sjulian /* DLCI == 0 means close multiplexor channel */ 2103114878Sjulian if (dlci == 0) { 2104114878Sjulian /* XXX FIXME assume that remote side will close the socket */ 2105114878Sjulian error = ng_btsocket_rfcomm_send_command(s, RFCOMM_FRAME_UA, 0); 2106128591Semax if (error == 0) { 2107128591Semax if (s->state == NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING) 2108128591Semax s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; /* XXX */ 2109128591Semax else 2110128591Semax s->state = NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING; 2111128591Semax } else 2112114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; /* XXX */ 2113114878Sjulian 2114114878Sjulian ng_btsocket_rfcomm_session_clean(s); 2115114878Sjulian } else { 2116114878Sjulian pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci); 2117114878Sjulian if (pcb != NULL) { 2118161623Semax int err; 2119114878Sjulian 2120114878Sjulian mtx_lock(&pcb->pcb_mtx); 2121114878Sjulian 2122114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2123114878Sjulian"%s: Got DISC for dlci=%d, state=%d, flags=%#x\n", 2124114878Sjulian __func__, dlci, pcb->state, pcb->flags); 2125114878Sjulian 2126114878Sjulian error = ng_btsocket_rfcomm_send_command(s, 2127114878Sjulian RFCOMM_FRAME_UA, dlci); 2128114878Sjulian 2129114878Sjulian if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONNECTED) 2130114878Sjulian err = 0; 2131114878Sjulian else 2132114878Sjulian err = ECONNREFUSED; 2133114878Sjulian 2134161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, err); 2135114878Sjulian 2136114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2137114878Sjulian } else { 2138114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2139114878Sjulian"%s: Got DISC for non-existing dlci=%d\n", __func__, dlci); 2140114878Sjulian 2141114878Sjulian error = ng_btsocket_rfcomm_send_command(s, 2142114878Sjulian RFCOMM_FRAME_DM, dlci); 2143114878Sjulian } 2144114878Sjulian } 2145114878Sjulian 2146114878Sjulian return (error); 2147114878Sjulian} /* ng_btsocket_rfcomm_receive_disc */ 2148114878Sjulian 2149114878Sjulian/* 2150114878Sjulian * Process RFCOMM UA frame 2151114878Sjulian */ 2152114878Sjulian 2153114878Sjulianstatic int 2154114878Sjulianng_btsocket_rfcomm_receive_ua(ng_btsocket_rfcomm_session_p s, int dlci) 2155114878Sjulian{ 2156114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = NULL; 2157114878Sjulian int error = 0; 2158114878Sjulian 2159114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2160114878Sjulian 2161114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2162114878Sjulian"%s: Got UA, session state=%d, flags=%#x, mtu=%d, dlci=%d\n", 2163114878Sjulian __func__, s->state, s->flags, s->mtu, dlci); 2164114878Sjulian 2165114878Sjulian /* dlci == 0 means multiplexor channel */ 2166114878Sjulian if (dlci == 0) { 2167114878Sjulian switch (s->state) { 2168114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED: 2169114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_OPEN; 2170114878Sjulian ng_btsocket_rfcomm_connect_cfm(s); 2171114878Sjulian break; 2172114878Sjulian 2173114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING: 2174114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 2175114878Sjulian ng_btsocket_rfcomm_session_clean(s); 2176114878Sjulian break; 2177114878Sjulian 2178114878Sjulian default: 2179114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2180114878Sjulian"%s: Got UA for session in invalid state=%d(%d), flags=%#x, mtu=%d\n", 2181114878Sjulian __func__, s->state, INITIATOR(s), s->flags, 2182114878Sjulian s->mtu); 2183114878Sjulian error = ENOENT; 2184114878Sjulian break; 2185114878Sjulian } 2186114878Sjulian 2187114878Sjulian return (error); 2188114878Sjulian } 2189114878Sjulian 2190114878Sjulian /* Check if we have this DLCI */ 2191114878Sjulian pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci); 2192114878Sjulian if (pcb != NULL) { 2193114878Sjulian mtx_lock(&pcb->pcb_mtx); 2194114878Sjulian 2195114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2196114878Sjulian"%s: Got UA for dlci=%d, state=%d, flags=%#x\n", 2197114878Sjulian __func__, dlci, pcb->state, pcb->flags); 2198114878Sjulian 2199114878Sjulian switch (pcb->state) { 2200114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONNECTING: 2201114878Sjulian ng_btsocket_rfcomm_untimeout(pcb); 2202114878Sjulian 2203114878Sjulian error = ng_btsocket_rfcomm_send_msc(pcb); 2204114878Sjulian if (error == 0) { 2205114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTED; 2206114878Sjulian soisconnected(pcb->so); 2207114878Sjulian } 2208114878Sjulian break; 2209114878Sjulian 2210114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING: 2211161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, 0); 2212114878Sjulian break; 2213114878Sjulian 2214114878Sjulian default: 2215114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2216114878Sjulian"%s: Got UA for dlci=%d in invalid state=%d, flags=%#x\n", 2217114878Sjulian __func__, dlci, pcb->state, pcb->flags); 2218114878Sjulian error = ENOENT; 2219114878Sjulian break; 2220114878Sjulian } 2221114878Sjulian 2222114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2223114878Sjulian } else { 2224114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2225114878Sjulian"%s: Got UA for non-existing dlci=%d\n", __func__, dlci); 2226114878Sjulian 2227114878Sjulian error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_DM,dlci); 2228114878Sjulian } 2229114878Sjulian 2230114878Sjulian return (error); 2231114878Sjulian} /* ng_btsocket_rfcomm_receive_ua */ 2232114878Sjulian 2233114878Sjulian/* 2234114878Sjulian * Process RFCOMM DM frame 2235114878Sjulian */ 2236114878Sjulian 2237114878Sjulianstatic int 2238114878Sjulianng_btsocket_rfcomm_receive_dm(ng_btsocket_rfcomm_session_p s, int dlci) 2239114878Sjulian{ 2240114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = NULL; 2241114878Sjulian int error; 2242114878Sjulian 2243114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2244114878Sjulian 2245114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2246114878Sjulian"%s: Got DM, session state=%d, flags=%#x, mtu=%d, dlci=%d\n", 2247114878Sjulian __func__, s->state, s->flags, s->mtu, dlci); 2248114878Sjulian 2249114878Sjulian /* DLCI == 0 means multiplexor channel */ 2250114878Sjulian if (dlci == 0) { 2251114878Sjulian /* Disconnect all dlc's on the session */ 2252114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 2253114878Sjulian ng_btsocket_rfcomm_session_clean(s); 2254114878Sjulian } else { 2255114878Sjulian pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci); 2256114878Sjulian if (pcb != NULL) { 2257114878Sjulian mtx_lock(&pcb->pcb_mtx); 2258114878Sjulian 2259114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2260114878Sjulian"%s: Got DM for dlci=%d, state=%d, flags=%#x\n", 2261114878Sjulian __func__, dlci, pcb->state, pcb->flags); 2262114878Sjulian 2263114878Sjulian if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONNECTED) 2264114878Sjulian error = ECONNRESET; 2265114878Sjulian else 2266114878Sjulian error = ECONNREFUSED; 2267114878Sjulian 2268161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, error); 2269114878Sjulian 2270114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2271114878Sjulian } else 2272114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2273114878Sjulian"%s: Got DM for non-existing dlci=%d\n", __func__, dlci); 2274114878Sjulian } 2275114878Sjulian 2276114878Sjulian return (0); 2277114878Sjulian} /* ng_btsocket_rfcomm_receive_dm */ 2278114878Sjulian 2279114878Sjulian/* 2280114878Sjulian * Process RFCOMM UIH frame (data) 2281114878Sjulian */ 2282114878Sjulian 2283114878Sjulianstatic int 2284114878Sjulianng_btsocket_rfcomm_receive_uih(ng_btsocket_rfcomm_session_p s, int dlci, 2285114878Sjulian int pf, struct mbuf *m0) 2286114878Sjulian{ 2287114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = NULL; 2288114878Sjulian int error = 0; 2289114878Sjulian 2290114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2291114878Sjulian 2292114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2293114878Sjulian"%s: Got UIH, session state=%d, flags=%#x, mtu=%d, dlci=%d, pf=%d, len=%d\n", 2294114878Sjulian __func__, s->state, s->flags, s->mtu, dlci, pf, 2295114878Sjulian m0->m_pkthdr.len); 2296114878Sjulian 2297114878Sjulian /* XXX should we do it here? Check for session flow control */ 2298114878Sjulian if (s->flags & NG_BTSOCKET_RFCOMM_SESSION_LFC) { 2299114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2300114878Sjulian"%s: Got UIH with session flow control asserted, state=%d, flags=%#x\n", 2301114878Sjulian __func__, s->state, s->flags); 2302114878Sjulian goto drop; 2303114878Sjulian } 2304114878Sjulian 2305114878Sjulian /* Check if we have this dlci */ 2306114878Sjulian pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci); 2307114878Sjulian if (pcb == NULL) { 2308114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2309114878Sjulian"%s: Got UIH for non-existing dlci=%d\n", __func__, dlci); 2310114878Sjulian error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_DM,dlci); 2311114878Sjulian goto drop; 2312114878Sjulian } 2313114878Sjulian 2314114878Sjulian mtx_lock(&pcb->pcb_mtx); 2315114878Sjulian 2316114878Sjulian /* Check dlci state */ 2317114878Sjulian if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTED) { 2318114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2319114878Sjulian"%s: Got UIH for dlci=%d in invalid state=%d, flags=%#x\n", 2320114878Sjulian __func__, dlci, pcb->state, pcb->flags); 2321114878Sjulian error = EINVAL; 2322114878Sjulian goto drop1; 2323114878Sjulian } 2324114878Sjulian 2325114878Sjulian /* Check dlci flow control */ 2326114878Sjulian if (((pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) && pcb->rx_cred <= 0) || 2327114878Sjulian (pcb->lmodem & RFCOMM_MODEM_FC)) { 2328114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2329114878Sjulian"%s: Got UIH for dlci=%d with asserted flow control, state=%d, " \ 2330114878Sjulian"flags=%#x, rx_cred=%d, lmodem=%#x\n", 2331114878Sjulian __func__, dlci, pcb->state, pcb->flags, 2332114878Sjulian pcb->rx_cred, pcb->lmodem); 2333114878Sjulian goto drop1; 2334114878Sjulian } 2335114878Sjulian 2336114878Sjulian /* Did we get any credits? */ 2337114878Sjulian if ((pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) && pf) { 2338114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2339114878Sjulian"%s: Got %d more credits for dlci=%d, state=%d, flags=%#x, " \ 2340114878Sjulian"rx_cred=%d, tx_cred=%d\n", 2341114878Sjulian __func__, *mtod(m0, u_int8_t *), dlci, pcb->state, 2342114878Sjulian pcb->flags, pcb->rx_cred, pcb->tx_cred); 2343114878Sjulian 2344114878Sjulian pcb->tx_cred += *mtod(m0, u_int8_t *); 2345114878Sjulian m_adj(m0, 1); 2346114878Sjulian 2347114878Sjulian /* Send more from the DLC. XXX check for errors? */ 2348114878Sjulian ng_btsocket_rfcomm_pcb_send(pcb, ALOT); 2349114878Sjulian } 2350114878Sjulian 2351114878Sjulian /* OK the of the rest of the mbuf is the data */ 2352114878Sjulian if (m0->m_pkthdr.len > 0) { 2353114878Sjulian /* If we are using credit flow control decrease rx_cred here */ 2354114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) { 2355114878Sjulian /* Give remote peer more credits (if needed) */ 2356114878Sjulian if (-- pcb->rx_cred <= RFCOMM_MAX_CREDITS / 2) 2357114878Sjulian ng_btsocket_rfcomm_send_credits(pcb); 2358114878Sjulian else 2359114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2360114878Sjulian"%s: Remote side still has credits, dlci=%d, state=%d, flags=%#x, " \ 2361114878Sjulian"rx_cred=%d, tx_cred=%d\n", __func__, dlci, pcb->state, pcb->flags, 2362114878Sjulian pcb->rx_cred, pcb->tx_cred); 2363114878Sjulian } 2364114878Sjulian 2365114878Sjulian /* Check packet against mtu on dlci */ 2366114878Sjulian if (m0->m_pkthdr.len > pcb->mtu) { 2367114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2368114878Sjulian"%s: Got oversized UIH for dlci=%d, state=%d, flags=%#x, mtu=%d, len=%d\n", 2369114878Sjulian __func__, dlci, pcb->state, pcb->flags, 2370114878Sjulian pcb->mtu, m0->m_pkthdr.len); 2371114878Sjulian 2372114878Sjulian error = EMSGSIZE; 2373114878Sjulian } else if (m0->m_pkthdr.len > sbspace(&pcb->so->so_rcv)) { 2374114878Sjulian 2375114878Sjulian /* 2376114878Sjulian * This is really bad. Receive queue on socket does 2377114878Sjulian * not have enough space for the packet. We do not 2378114878Sjulian * have any other choice but drop the packet. 2379114878Sjulian */ 2380114878Sjulian 2381114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2382114878Sjulian"%s: Not enough space in socket receive queue. Dropping UIH for dlci=%d, " \ 2383114878Sjulian"state=%d, flags=%#x, len=%d, space=%ld\n", 2384114878Sjulian __func__, dlci, pcb->state, pcb->flags, 2385114878Sjulian m0->m_pkthdr.len, sbspace(&pcb->so->so_rcv)); 2386114878Sjulian 2387114878Sjulian error = ENOBUFS; 2388114878Sjulian } else { 2389114878Sjulian /* Append packet to the socket receive queue */ 2390114878Sjulian sbappend(&pcb->so->so_rcv, m0); 2391114878Sjulian m0 = NULL; 2392114878Sjulian 2393114878Sjulian sorwakeup(pcb->so); 2394114878Sjulian } 2395114878Sjulian } 2396114878Sjuliandrop1: 2397114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2398114878Sjuliandrop: 2399114878Sjulian NG_FREE_M(m0); /* checks for != NULL */ 2400114878Sjulian 2401114878Sjulian return (error); 2402114878Sjulian} /* ng_btsocket_rfcomm_receive_uih */ 2403114878Sjulian 2404114878Sjulian/* 2405114878Sjulian * Process RFCOMM MCC command (Multiplexor) 2406114878Sjulian * 2407114878Sjulian * From TS 07.10 spec 2408114878Sjulian * 2409114878Sjulian * "5.4.3.1 Information Data 2410114878Sjulian * 2411114878Sjulian * ...The frames (UIH) sent by the initiating station have the C/R bit set 2412114878Sjulian * to 1 and those sent by the responding station have the C/R bit set to 0..." 2413114878Sjulian * 2414114878Sjulian * "5.4.6.2 Operating procedures 2415114878Sjulian * 2416114878Sjulian * Messages always exist in pairs; a command message and a corresponding 2417114878Sjulian * response message. If the C/R bit is set to 1 the message is a command, 2418114878Sjulian * if it is set to 0 the message is a response... 2419114878Sjulian * 2420114878Sjulian * ... 2421114878Sjulian * 2422114878Sjulian * NOTE: Notice that when UIH frames are used to convey information on DLCI 0 2423114878Sjulian * there are at least two different fields that contain a C/R bit, and the 2424114878Sjulian * bits are set of different form. The C/R bit in the Type field shall be set 2425114878Sjulian * as it is stated above, while the C/R bit in the Address field (see subclause 2426114878Sjulian * 5.2.1.2) shall be set as it is described in subclause 5.4.3.1." 2427114878Sjulian */ 2428114878Sjulian 2429114878Sjulianstatic int 2430114878Sjulianng_btsocket_rfcomm_receive_mcc(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2431114878Sjulian{ 2432114878Sjulian struct rfcomm_mcc_hdr *hdr = NULL; 2433114878Sjulian u_int8_t cr, type, length; 2434114878Sjulian 2435114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2436114878Sjulian 2437114878Sjulian /* 2438114878Sjulian * We can access data directly in the first mbuf, because we have 2439114878Sjulian * m_pullup()'ed mbuf chain in ng_btsocket_rfcomm_receive_frame(). 2440114878Sjulian * All MCC commands should fit into single mbuf (except probably TEST). 2441114878Sjulian */ 2442114878Sjulian 2443114878Sjulian hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2444114878Sjulian cr = RFCOMM_CR(hdr->type); 2445114878Sjulian type = RFCOMM_MCC_TYPE(hdr->type); 2446114878Sjulian length = RFCOMM_MCC_LENGTH(hdr->length); 2447114878Sjulian 2448114878Sjulian /* Check MCC frame length */ 2449114878Sjulian if (sizeof(*hdr) + length != m0->m_pkthdr.len) { 2450114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2451114878Sjulian"%s: Invalid MCC frame length=%d, len=%d\n", 2452114878Sjulian __func__, length, m0->m_pkthdr.len); 2453114878Sjulian NG_FREE_M(m0); 2454114878Sjulian 2455114878Sjulian return (EMSGSIZE); 2456114878Sjulian } 2457114878Sjulian 2458114878Sjulian switch (type) { 2459114878Sjulian case RFCOMM_MCC_TEST: 2460114878Sjulian return (ng_btsocket_rfcomm_receive_test(s, m0)); 2461114878Sjulian /* NOT REACHED */ 2462114878Sjulian 2463114878Sjulian case RFCOMM_MCC_FCON: 2464114878Sjulian case RFCOMM_MCC_FCOFF: 2465114878Sjulian return (ng_btsocket_rfcomm_receive_fc(s, m0)); 2466114878Sjulian /* NOT REACHED */ 2467114878Sjulian 2468114878Sjulian case RFCOMM_MCC_MSC: 2469114878Sjulian return (ng_btsocket_rfcomm_receive_msc(s, m0)); 2470114878Sjulian /* NOT REACHED */ 2471114878Sjulian 2472114878Sjulian case RFCOMM_MCC_RPN: 2473114878Sjulian return (ng_btsocket_rfcomm_receive_rpn(s, m0)); 2474114878Sjulian /* NOT REACHED */ 2475114878Sjulian 2476114878Sjulian case RFCOMM_MCC_RLS: 2477114878Sjulian return (ng_btsocket_rfcomm_receive_rls(s, m0)); 2478114878Sjulian /* NOT REACHED */ 2479114878Sjulian 2480114878Sjulian case RFCOMM_MCC_PN: 2481114878Sjulian return (ng_btsocket_rfcomm_receive_pn(s, m0)); 2482114878Sjulian /* NOT REACHED */ 2483114878Sjulian 2484114878Sjulian case RFCOMM_MCC_NSC: 2485114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2486114878Sjulian"%s: Got MCC NSC, type=%#x, cr=%d, length=%d, session state=%d, flags=%#x, " \ 2487114878Sjulian"mtu=%d, len=%d\n", __func__, RFCOMM_MCC_TYPE(*((u_int8_t *)(hdr + 1))), cr, 2488114878Sjulian length, s->state, s->flags, s->mtu, m0->m_pkthdr.len); 2489114878Sjulian NG_FREE_M(m0); 2490114878Sjulian break; 2491114878Sjulian 2492114878Sjulian default: 2493114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2494114878Sjulian"%s: Got unknown MCC, type=%#x, cr=%d, length=%d, session state=%d, " \ 2495114878Sjulian"flags=%#x, mtu=%d, len=%d\n", 2496114878Sjulian __func__, type, cr, length, s->state, s->flags, 2497114878Sjulian s->mtu, m0->m_pkthdr.len); 2498114878Sjulian 2499114878Sjulian /* Reuse mbuf to send NSC */ 2500114878Sjulian hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2501114878Sjulian m0->m_pkthdr.len = m0->m_len = sizeof(*hdr); 2502114878Sjulian 2503114878Sjulian /* Create MCC NSC header */ 2504114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_NSC); 2505114878Sjulian hdr->length = RFCOMM_MKLEN8(1); 2506114878Sjulian 2507114878Sjulian /* Put back MCC command type we did not like */ 2508114878Sjulian m0->m_data[m0->m_len] = RFCOMM_MKMCC_TYPE(cr, type); 2509114878Sjulian m0->m_pkthdr.len ++; 2510114878Sjulian m0->m_len ++; 2511114878Sjulian 2512114878Sjulian /* Send UIH frame */ 2513114878Sjulian return (ng_btsocket_rfcomm_send_uih(s, 2514114878Sjulian RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0)); 2515114878Sjulian /* NOT REACHED */ 2516114878Sjulian } 2517114878Sjulian 2518114878Sjulian return (0); 2519114878Sjulian} /* ng_btsocket_rfcomm_receive_mcc */ 2520114878Sjulian 2521114878Sjulian/* 2522114878Sjulian * Receive RFCOMM TEST MCC command 2523114878Sjulian */ 2524114878Sjulian 2525114878Sjulianstatic int 2526114878Sjulianng_btsocket_rfcomm_receive_test(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2527114878Sjulian{ 2528114878Sjulian struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2529114878Sjulian int error = 0; 2530114878Sjulian 2531114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2532114878Sjulian 2533114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2534114878Sjulian"%s: Got MCC TEST, cr=%d, length=%d, session state=%d, flags=%#x, mtu=%d, " \ 2535114878Sjulian"len=%d\n", __func__, RFCOMM_CR(hdr->type), RFCOMM_MCC_LENGTH(hdr->length), 2536114878Sjulian s->state, s->flags, s->mtu, m0->m_pkthdr.len); 2537114878Sjulian 2538114878Sjulian if (RFCOMM_CR(hdr->type)) { 2539114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_TEST); 2540114878Sjulian error = ng_btsocket_rfcomm_send_uih(s, 2541114878Sjulian RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0); 2542114878Sjulian } else 2543114878Sjulian NG_FREE_M(m0); /* XXX ignore response */ 2544114878Sjulian 2545114878Sjulian return (error); 2546114878Sjulian} /* ng_btsocket_rfcomm_receive_test */ 2547114878Sjulian 2548114878Sjulian/* 2549114878Sjulian * Receive RFCOMM FCON/FCOFF MCC command 2550114878Sjulian */ 2551114878Sjulian 2552114878Sjulianstatic int 2553114878Sjulianng_btsocket_rfcomm_receive_fc(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2554114878Sjulian{ 2555114878Sjulian struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2556114878Sjulian u_int8_t type = RFCOMM_MCC_TYPE(hdr->type); 2557114878Sjulian int error = 0; 2558114878Sjulian 2559114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2560114878Sjulian 2561114878Sjulian /* 2562114878Sjulian * Turn ON/OFF aggregate flow on the entire session. When remote peer 2563114878Sjulian * asserted flow control no transmission shall occur except on dlci 0 2564114878Sjulian * (control channel). 2565114878Sjulian */ 2566114878Sjulian 2567114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2568114878Sjulian"%s: Got MCC FC%s, cr=%d, length=%d, session state=%d, flags=%#x, mtu=%d, " \ 2569114878Sjulian"len=%d\n", __func__, (type == RFCOMM_MCC_FCON)? "ON" : "OFF", 2570114878Sjulian RFCOMM_CR(hdr->type), RFCOMM_MCC_LENGTH(hdr->length), 2571114878Sjulian s->state, s->flags, s->mtu, m0->m_pkthdr.len); 2572114878Sjulian 2573114878Sjulian if (RFCOMM_CR(hdr->type)) { 2574114878Sjulian if (type == RFCOMM_MCC_FCON) 2575114878Sjulian s->flags &= ~NG_BTSOCKET_RFCOMM_SESSION_RFC; 2576114878Sjulian else 2577114878Sjulian s->flags |= NG_BTSOCKET_RFCOMM_SESSION_RFC; 2578114878Sjulian 2579114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(0, type); 2580114878Sjulian error = ng_btsocket_rfcomm_send_uih(s, 2581114878Sjulian RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0); 2582114878Sjulian } else 2583114878Sjulian NG_FREE_M(m0); /* XXX ignore response */ 2584114878Sjulian 2585114878Sjulian return (error); 2586114878Sjulian} /* ng_btsocket_rfcomm_receive_fc */ 2587114878Sjulian 2588114878Sjulian/* 2589114878Sjulian * Receive RFCOMM MSC MCC command 2590114878Sjulian */ 2591114878Sjulian 2592114878Sjulianstatic int 2593114878Sjulianng_btsocket_rfcomm_receive_msc(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2594114878Sjulian{ 2595114878Sjulian struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr*); 2596114878Sjulian struct rfcomm_mcc_msc *msc = (struct rfcomm_mcc_msc *)(hdr+1); 2597114878Sjulian ng_btsocket_rfcomm_pcb_t *pcb = NULL; 2598114878Sjulian int error = 0; 2599114878Sjulian 2600114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2601114878Sjulian 2602114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2603114878Sjulian"%s: Got MCC MSC, dlci=%d, cr=%d, length=%d, session state=%d, flags=%#x, " \ 2604114878Sjulian"mtu=%d, len=%d\n", 2605114878Sjulian __func__, RFCOMM_DLCI(msc->address), RFCOMM_CR(hdr->type), 2606114878Sjulian RFCOMM_MCC_LENGTH(hdr->length), s->state, s->flags, 2607114878Sjulian s->mtu, m0->m_pkthdr.len); 2608114878Sjulian 2609114878Sjulian if (RFCOMM_CR(hdr->type)) { 2610114878Sjulian pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, RFCOMM_DLCI(msc->address)); 2611114878Sjulian if (pcb == NULL) { 2612114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2613114878Sjulian"%s: Got MSC command for non-existing dlci=%d\n", 2614114878Sjulian __func__, RFCOMM_DLCI(msc->address)); 2615114878Sjulian NG_FREE_M(m0); 2616114878Sjulian 2617114878Sjulian return (ENOENT); 2618114878Sjulian } 2619114878Sjulian 2620114878Sjulian mtx_lock(&pcb->pcb_mtx); 2621114878Sjulian 2622114878Sjulian if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTING && 2623114878Sjulian pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTED) { 2624114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2625114878Sjulian"%s: Got MSC on dlci=%d in invalid state=%d\n", 2626114878Sjulian __func__, RFCOMM_DLCI(msc->address), 2627114878Sjulian pcb->state); 2628114878Sjulian 2629114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2630114878Sjulian NG_FREE_M(m0); 2631114878Sjulian 2632114878Sjulian return (EINVAL); 2633114878Sjulian } 2634114878Sjulian 2635114878Sjulian pcb->rmodem = msc->modem; /* Update remote port signals */ 2636114878Sjulian 2637114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_MSC); 2638114878Sjulian error = ng_btsocket_rfcomm_send_uih(s, 2639114878Sjulian RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0); 2640114878Sjulian 2641114878Sjulian#if 0 /* YYY */ 2642114878Sjulian /* Send more data from DLC. XXX check for errors? */ 2643114878Sjulian if (!(pcb->rmodem & RFCOMM_MODEM_FC) && 2644114878Sjulian !(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC)) 2645114878Sjulian ng_btsocket_rfcomm_pcb_send(pcb, ALOT); 2646114878Sjulian#endif /* YYY */ 2647114878Sjulian 2648114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2649114878Sjulian } else 2650114878Sjulian NG_FREE_M(m0); /* XXX ignore response */ 2651114878Sjulian 2652114878Sjulian return (error); 2653114878Sjulian} /* ng_btsocket_rfcomm_receive_msc */ 2654114878Sjulian 2655114878Sjulian/* 2656114878Sjulian * Receive RFCOMM RPN MCC command 2657114878Sjulian * XXX FIXME do we need htole16/le16toh for RPN param_mask? 2658114878Sjulian */ 2659114878Sjulian 2660114878Sjulianstatic int 2661114878Sjulianng_btsocket_rfcomm_receive_rpn(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2662114878Sjulian{ 2663114878Sjulian struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2664114878Sjulian struct rfcomm_mcc_rpn *rpn = (struct rfcomm_mcc_rpn *)(hdr + 1); 2665114878Sjulian int error = 0; 2666114878Sjulian u_int16_t param_mask; 2667114878Sjulian u_int8_t bit_rate, data_bits, stop_bits, parity, 2668114878Sjulian flow_control, xon_char, xoff_char; 2669114878Sjulian 2670114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2671114878Sjulian 2672114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2673114878Sjulian"%s: Got MCC RPN, dlci=%d, cr=%d, length=%d, session state=%d, flags=%#x, " \ 2674114878Sjulian"mtu=%d, len=%d\n", 2675114878Sjulian __func__, RFCOMM_DLCI(rpn->dlci), RFCOMM_CR(hdr->type), 2676114878Sjulian RFCOMM_MCC_LENGTH(hdr->length), s->state, s->flags, 2677114878Sjulian s->mtu, m0->m_pkthdr.len); 2678114878Sjulian 2679114878Sjulian if (RFCOMM_CR(hdr->type)) { 2680114878Sjulian param_mask = RFCOMM_RPN_PM_ALL; 2681114878Sjulian 2682114878Sjulian if (RFCOMM_MCC_LENGTH(hdr->length) == 1) { 2683114878Sjulian /* Request - return default setting */ 2684114878Sjulian bit_rate = RFCOMM_RPN_BR_115200; 2685114878Sjulian data_bits = RFCOMM_RPN_DATA_8; 2686114878Sjulian stop_bits = RFCOMM_RPN_STOP_1; 2687114878Sjulian parity = RFCOMM_RPN_PARITY_NONE; 2688114878Sjulian flow_control = RFCOMM_RPN_FLOW_NONE; 2689114878Sjulian xon_char = RFCOMM_RPN_XON_CHAR; 2690114878Sjulian xoff_char = RFCOMM_RPN_XOFF_CHAR; 2691114878Sjulian } else { 2692114878Sjulian /* 2693114878Sjulian * Ignore/accept bit_rate, 8 bits, 1 stop bit, no 2694114878Sjulian * parity, no flow control lines, default XON/XOFF 2695114878Sjulian * chars. 2696114878Sjulian */ 2697114878Sjulian 2698114878Sjulian bit_rate = rpn->bit_rate; 2699114878Sjulian rpn->param_mask = le16toh(rpn->param_mask); /* XXX */ 2700114878Sjulian 2701114878Sjulian data_bits = RFCOMM_RPN_DATA_BITS(rpn->line_settings); 2702114878Sjulian if (rpn->param_mask & RFCOMM_RPN_PM_DATA && 2703114878Sjulian data_bits != RFCOMM_RPN_DATA_8) { 2704114878Sjulian data_bits = RFCOMM_RPN_DATA_8; 2705114878Sjulian param_mask ^= RFCOMM_RPN_PM_DATA; 2706114878Sjulian } 2707114878Sjulian 2708114878Sjulian stop_bits = RFCOMM_RPN_STOP_BITS(rpn->line_settings); 2709114878Sjulian if (rpn->param_mask & RFCOMM_RPN_PM_STOP && 2710114878Sjulian stop_bits != RFCOMM_RPN_STOP_1) { 2711114878Sjulian stop_bits = RFCOMM_RPN_STOP_1; 2712114878Sjulian param_mask ^= RFCOMM_RPN_PM_STOP; 2713114878Sjulian } 2714114878Sjulian 2715114878Sjulian parity = RFCOMM_RPN_PARITY(rpn->line_settings); 2716114878Sjulian if (rpn->param_mask & RFCOMM_RPN_PM_PARITY && 2717114878Sjulian parity != RFCOMM_RPN_PARITY_NONE) { 2718114878Sjulian parity = RFCOMM_RPN_PARITY_NONE; 2719114878Sjulian param_mask ^= RFCOMM_RPN_PM_PARITY; 2720114878Sjulian } 2721114878Sjulian 2722114878Sjulian flow_control = rpn->flow_control; 2723114878Sjulian if (rpn->param_mask & RFCOMM_RPN_PM_FLOW && 2724114878Sjulian flow_control != RFCOMM_RPN_FLOW_NONE) { 2725114878Sjulian flow_control = RFCOMM_RPN_FLOW_NONE; 2726114878Sjulian param_mask ^= RFCOMM_RPN_PM_FLOW; 2727114878Sjulian } 2728114878Sjulian 2729114878Sjulian xon_char = rpn->xon_char; 2730114878Sjulian if (rpn->param_mask & RFCOMM_RPN_PM_XON && 2731114878Sjulian xon_char != RFCOMM_RPN_XON_CHAR) { 2732114878Sjulian xon_char = RFCOMM_RPN_XON_CHAR; 2733114878Sjulian param_mask ^= RFCOMM_RPN_PM_XON; 2734114878Sjulian } 2735114878Sjulian 2736114878Sjulian xoff_char = rpn->xoff_char; 2737114878Sjulian if (rpn->param_mask & RFCOMM_RPN_PM_XOFF && 2738114878Sjulian xoff_char != RFCOMM_RPN_XOFF_CHAR) { 2739114878Sjulian xoff_char = RFCOMM_RPN_XOFF_CHAR; 2740114878Sjulian param_mask ^= RFCOMM_RPN_PM_XOFF; 2741114878Sjulian } 2742114878Sjulian } 2743114878Sjulian 2744114878Sjulian rpn->bit_rate = bit_rate; 2745114878Sjulian rpn->line_settings = RFCOMM_MKRPN_LINE_SETTINGS(data_bits, 2746114878Sjulian stop_bits, parity); 2747114878Sjulian rpn->flow_control = flow_control; 2748114878Sjulian rpn->xon_char = xon_char; 2749114878Sjulian rpn->xoff_char = xoff_char; 2750114878Sjulian rpn->param_mask = htole16(param_mask); /* XXX */ 2751114878Sjulian 2752114878Sjulian m0->m_pkthdr.len = m0->m_len = sizeof(*hdr) + sizeof(*rpn); 2753114878Sjulian 2754114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_RPN); 2755114878Sjulian error = ng_btsocket_rfcomm_send_uih(s, 2756114878Sjulian RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0); 2757114878Sjulian } else 2758114878Sjulian NG_FREE_M(m0); /* XXX ignore response */ 2759114878Sjulian 2760114878Sjulian return (error); 2761114878Sjulian} /* ng_btsocket_rfcomm_receive_rpn */ 2762114878Sjulian 2763114878Sjulian/* 2764114878Sjulian * Receive RFCOMM RLS MCC command 2765114878Sjulian */ 2766114878Sjulian 2767114878Sjulianstatic int 2768114878Sjulianng_btsocket_rfcomm_receive_rls(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2769114878Sjulian{ 2770114878Sjulian struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2771114878Sjulian struct rfcomm_mcc_rls *rls = (struct rfcomm_mcc_rls *)(hdr + 1); 2772114878Sjulian int error = 0; 2773114878Sjulian 2774114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2775114878Sjulian 2776114878Sjulian /* 2777114878Sjulian * XXX FIXME Do we have to do anything else here? Remote peer tries to 2778114878Sjulian * tell us something about DLCI. Just report what we have received and 2779114878Sjulian * return back received values as required by TS 07.10 spec. 2780114878Sjulian */ 2781114878Sjulian 2782114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2783114878Sjulian"%s: Got MCC RLS, dlci=%d, status=%#x, cr=%d, length=%d, session state=%d, " \ 2784114878Sjulian"flags=%#x, mtu=%d, len=%d\n", 2785114878Sjulian __func__, RFCOMM_DLCI(rls->address), rls->status, 2786114878Sjulian RFCOMM_CR(hdr->type), RFCOMM_MCC_LENGTH(hdr->length), 2787114878Sjulian s->state, s->flags, s->mtu, m0->m_pkthdr.len); 2788114878Sjulian 2789114878Sjulian if (RFCOMM_CR(hdr->type)) { 2790114878Sjulian if (rls->status & 0x1) 2791114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2792114878Sjulian"%s: Got RLS dlci=%d, error=%#x\n", __func__, RFCOMM_DLCI(rls->address), 2793114878Sjulian rls->status >> 1); 2794114878Sjulian 2795114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_RLS); 2796114878Sjulian error = ng_btsocket_rfcomm_send_uih(s, 2797114878Sjulian RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0); 2798114878Sjulian } else 2799114878Sjulian NG_FREE_M(m0); /* XXX ignore responses */ 2800114878Sjulian 2801114878Sjulian return (error); 2802114878Sjulian} /* ng_btsocket_rfcomm_receive_rls */ 2803114878Sjulian 2804114878Sjulian/* 2805114878Sjulian * Receive RFCOMM PN MCC command 2806114878Sjulian */ 2807114878Sjulian 2808114878Sjulianstatic int 2809114878Sjulianng_btsocket_rfcomm_receive_pn(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2810114878Sjulian{ 2811114878Sjulian struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr*); 2812114878Sjulian struct rfcomm_mcc_pn *pn = (struct rfcomm_mcc_pn *)(hdr+1); 2813114878Sjulian ng_btsocket_rfcomm_pcb_t *pcb = NULL; 2814114878Sjulian int error = 0; 2815114878Sjulian 2816114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2817114878Sjulian 2818114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2819114878Sjulian"%s: Got MCC PN, dlci=%d, cr=%d, length=%d, flow_control=%#x, priority=%d, " \ 2820114878Sjulian"ack_timer=%d, mtu=%d, max_retrans=%d, credits=%d, session state=%d, " \ 2821114878Sjulian"flags=%#x, session mtu=%d, len=%d\n", 2822114878Sjulian __func__, pn->dlci, RFCOMM_CR(hdr->type), 2823114878Sjulian RFCOMM_MCC_LENGTH(hdr->length), pn->flow_control, pn->priority, 2824114878Sjulian pn->ack_timer, le16toh(pn->mtu), pn->max_retrans, pn->credits, 2825114878Sjulian s->state, s->flags, s->mtu, m0->m_pkthdr.len); 2826114878Sjulian 2827114878Sjulian if (pn->dlci == 0) { 2828114878Sjulian NG_BTSOCKET_RFCOMM_ERR("%s: Zero dlci in MCC PN\n", __func__); 2829114878Sjulian NG_FREE_M(m0); 2830114878Sjulian 2831114878Sjulian return (EINVAL); 2832114878Sjulian } 2833114878Sjulian 2834114878Sjulian /* Check if we have this dlci */ 2835114878Sjulian pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, pn->dlci); 2836114878Sjulian if (pcb != NULL) { 2837114878Sjulian mtx_lock(&pcb->pcb_mtx); 2838114878Sjulian 2839114878Sjulian if (RFCOMM_CR(hdr->type)) { 2840114878Sjulian /* PN Request */ 2841114878Sjulian ng_btsocket_rfcomm_set_pn(pcb, 1, pn->flow_control, 2842114878Sjulian pn->credits, pn->mtu); 2843114878Sjulian 2844114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) { 2845114878Sjulian pn->flow_control = 0xe0; 2846114878Sjulian pn->credits = RFCOMM_DEFAULT_CREDITS; 2847114878Sjulian } else { 2848114878Sjulian pn->flow_control = 0; 2849114878Sjulian pn->credits = 0; 2850114878Sjulian } 2851114878Sjulian 2852114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_PN); 2853114878Sjulian error = ng_btsocket_rfcomm_send_uih(s, 2854114878Sjulian RFCOMM_MKADDRESS(INITIATOR(s), 0), 2855114878Sjulian 0, 0, m0); 2856114878Sjulian } else { 2857114878Sjulian /* PN Response - proceed with SABM. Timeout still set */ 2858114878Sjulian if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONFIGURING) { 2859114878Sjulian ng_btsocket_rfcomm_set_pn(pcb, 0, 2860114878Sjulian pn->flow_control, pn->credits, pn->mtu); 2861114878Sjulian 2862114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTING; 2863114878Sjulian error = ng_btsocket_rfcomm_send_command(s, 2864114878Sjulian RFCOMM_FRAME_SABM, pn->dlci); 2865114878Sjulian } else 2866114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2867114878Sjulian"%s: Got PN response for dlci=%d in invalid state=%d\n", 2868114878Sjulian __func__, pn->dlci, pcb->state); 2869114878Sjulian 2870114878Sjulian NG_FREE_M(m0); 2871114878Sjulian } 2872114878Sjulian 2873114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2874114878Sjulian } else if (RFCOMM_CR(hdr->type)) { 2875114878Sjulian /* PN request to non-existing dlci - incomming connection */ 2876114878Sjulian pcb = ng_btsocket_rfcomm_connect_ind(s, 2877114878Sjulian RFCOMM_SRVCHANNEL(pn->dlci)); 2878114878Sjulian if (pcb != NULL) { 2879114878Sjulian mtx_lock(&pcb->pcb_mtx); 2880114878Sjulian 2881114878Sjulian pcb->dlci = pn->dlci; 2882114878Sjulian 2883114878Sjulian ng_btsocket_rfcomm_set_pn(pcb, 1, pn->flow_control, 2884114878Sjulian pn->credits, pn->mtu); 2885114878Sjulian 2886114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) { 2887114878Sjulian pn->flow_control = 0xe0; 2888114878Sjulian pn->credits = RFCOMM_DEFAULT_CREDITS; 2889114878Sjulian } else { 2890114878Sjulian pn->flow_control = 0; 2891114878Sjulian pn->credits = 0; 2892114878Sjulian } 2893114878Sjulian 2894114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_PN); 2895114878Sjulian error = ng_btsocket_rfcomm_send_uih(s, 2896114878Sjulian RFCOMM_MKADDRESS(INITIATOR(s), 0), 2897114878Sjulian 0, 0, m0); 2898114878Sjulian 2899114878Sjulian if (error == 0) { 2900114878Sjulian ng_btsocket_rfcomm_timeout(pcb); 2901114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTING; 2902114878Sjulian soisconnecting(pcb->so); 2903161623Semax } else 2904161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, error); 2905114878Sjulian 2906114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2907114878Sjulian } else { 2908114878Sjulian /* Nobody is listen()ing on this channel */ 2909114878Sjulian error = ng_btsocket_rfcomm_send_command(s, 2910114878Sjulian RFCOMM_FRAME_DM, pn->dlci); 2911114878Sjulian NG_FREE_M(m0); 2912114878Sjulian } 2913114878Sjulian } else 2914114878Sjulian NG_FREE_M(m0); /* XXX ignore response to non-existing dlci */ 2915114878Sjulian 2916114878Sjulian return (error); 2917114878Sjulian} /* ng_btsocket_rfcomm_receive_pn */ 2918114878Sjulian 2919114878Sjulian/* 2920114878Sjulian * Set PN parameters for dlci. Caller must hold pcb->pcb_mtx. 2921114878Sjulian * 2922114878Sjulian * From Bluetooth spec. 2923114878Sjulian * 2924114878Sjulian * "... The CL1 - CL4 field is completely redefined. (In TS07.10 this defines 2925114878Sjulian * the convergence layer to use, which is not applicable to RFCOMM. In RFCOMM, 2926114878Sjulian * in Bluetooth versions up to 1.0B, this field was forced to 0). 2927114878Sjulian * 2928114878Sjulian * In the PN request sent prior to a DLC establishment, this field must contain 2929114878Sjulian * the value 15 (0xF), indicating support of credit based flow control in the 2930114878Sjulian * sender. See Table 5.3 below. If the PN response contains any other value 2931114878Sjulian * than 14 (0xE) in this field, it is inferred that the peer RFCOMM entity is 2932114878Sjulian * not supporting the credit based flow control feature. (This is only possible 2933114878Sjulian * if the peer RFCOMM implementation is only conforming to Bluetooth version 2934114878Sjulian * 1.0B.) If a PN request is sent on an already open DLC, then this field must 2935114878Sjulian * contain the value zero; it is not possible to set initial credits more 2936114878Sjulian * than once per DLC activation. A responding implementation must set this 2937114878Sjulian * field in the PN response to 14 (0xE), if (and only if) the value in the PN 2938114878Sjulian * request was 15..." 2939114878Sjulian */ 2940114878Sjulian 2941114878Sjulianstatic void 2942114878Sjulianng_btsocket_rfcomm_set_pn(ng_btsocket_rfcomm_pcb_p pcb, u_int8_t cr, 2943114878Sjulian u_int8_t flow_control, u_int8_t credits, u_int16_t mtu) 2944114878Sjulian{ 2945114878Sjulian mtx_assert(&pcb->pcb_mtx, MA_OWNED); 2946114878Sjulian 2947114878Sjulian pcb->mtu = le16toh(mtu); 2948114878Sjulian 2949114878Sjulian if (cr) { 2950114878Sjulian if (flow_control == 0xf0) { 2951114878Sjulian pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_CFC; 2952114878Sjulian pcb->tx_cred = credits; 2953114878Sjulian } else { 2954114878Sjulian pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_CFC; 2955114878Sjulian pcb->tx_cred = 0; 2956114878Sjulian } 2957114878Sjulian } else { 2958114878Sjulian if (flow_control == 0xe0) { 2959114878Sjulian pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_CFC; 2960114878Sjulian pcb->tx_cred = credits; 2961114878Sjulian } else { 2962114878Sjulian pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_CFC; 2963114878Sjulian pcb->tx_cred = 0; 2964114878Sjulian } 2965114878Sjulian } 2966114878Sjulian 2967114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2968114878Sjulian"%s: cr=%d, dlci=%d, state=%d, flags=%#x, mtu=%d, rx_cred=%d, tx_cred=%d\n", 2969114878Sjulian __func__, cr, pcb->dlci, pcb->state, pcb->flags, pcb->mtu, 2970114878Sjulian pcb->rx_cred, pcb->tx_cred); 2971114878Sjulian} /* ng_btsocket_rfcomm_set_pn */ 2972114878Sjulian 2973114878Sjulian/* 2974114878Sjulian * Send RFCOMM SABM/DISC/UA/DM frames. Caller must hold s->session_mtx 2975114878Sjulian */ 2976114878Sjulian 2977114878Sjulianstatic int 2978114878Sjulianng_btsocket_rfcomm_send_command(ng_btsocket_rfcomm_session_p s, 2979114878Sjulian u_int8_t type, u_int8_t dlci) 2980114878Sjulian{ 2981114878Sjulian struct rfcomm_cmd_hdr *hdr = NULL; 2982114878Sjulian struct mbuf *m = NULL; 2983114878Sjulian int cr; 2984114878Sjulian 2985114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2986114878Sjulian 2987114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2988114878Sjulian"%s: Sending command type %#x, session state=%d, flags=%#x, mtu=%d, dlci=%d\n", 2989114878Sjulian __func__, type, s->state, s->flags, s->mtu, dlci); 2990114878Sjulian 2991114878Sjulian switch (type) { 2992114878Sjulian case RFCOMM_FRAME_SABM: 2993114878Sjulian case RFCOMM_FRAME_DISC: 2994114878Sjulian cr = INITIATOR(s); 2995114878Sjulian break; 2996114878Sjulian 2997114878Sjulian case RFCOMM_FRAME_UA: 2998114878Sjulian case RFCOMM_FRAME_DM: 2999114878Sjulian cr = !INITIATOR(s); 3000114878Sjulian break; 3001114878Sjulian 3002114878Sjulian default: 3003114878Sjulian panic("%s: Invalid frame type=%#x\n", __func__, type); 3004114878Sjulian return (EINVAL); 3005114878Sjulian /* NOT REACHED */ 3006114878Sjulian } 3007114878Sjulian 3008114878Sjulian MGETHDR(m, M_DONTWAIT, MT_DATA); 3009114878Sjulian if (m == NULL) 3010114878Sjulian return (ENOBUFS); 3011114878Sjulian 3012114878Sjulian m->m_pkthdr.len = m->m_len = sizeof(*hdr); 3013114878Sjulian 3014114878Sjulian hdr = mtod(m, struct rfcomm_cmd_hdr *); 3015114878Sjulian hdr->address = RFCOMM_MKADDRESS(cr, dlci); 3016114878Sjulian hdr->control = RFCOMM_MKCONTROL(type, 1); 3017114878Sjulian hdr->length = RFCOMM_MKLEN8(0); 3018114878Sjulian hdr->fcs = ng_btsocket_rfcomm_fcs3((u_int8_t *) hdr); 3019114878Sjulian 3020114878Sjulian NG_BT_MBUFQ_ENQUEUE(&s->outq, m); 3021114878Sjulian 3022114878Sjulian return (0); 3023114878Sjulian} /* ng_btsocket_rfcomm_send_command */ 3024114878Sjulian 3025114878Sjulian/* 3026114878Sjulian * Send RFCOMM UIH frame. Caller must hold s->session_mtx 3027114878Sjulian */ 3028114878Sjulian 3029114878Sjulianstatic int 3030114878Sjulianng_btsocket_rfcomm_send_uih(ng_btsocket_rfcomm_session_p s, u_int8_t address, 3031114878Sjulian u_int8_t pf, u_int8_t credits, struct mbuf *data) 3032114878Sjulian{ 3033114878Sjulian struct rfcomm_frame_hdr *hdr = NULL; 3034114878Sjulian struct mbuf *m = NULL, *mcrc = NULL; 3035114878Sjulian u_int16_t length; 3036114878Sjulian 3037114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 3038114878Sjulian 3039114878Sjulian MGETHDR(m, M_DONTWAIT, MT_DATA); 3040114878Sjulian if (m == NULL) { 3041114878Sjulian NG_FREE_M(data); 3042114878Sjulian return (ENOBUFS); 3043114878Sjulian } 3044114878Sjulian m->m_pkthdr.len = m->m_len = sizeof(*hdr); 3045114878Sjulian 3046114878Sjulian MGET(mcrc, M_DONTWAIT, MT_DATA); 3047114878Sjulian if (mcrc == NULL) { 3048114878Sjulian NG_FREE_M(data); 3049114878Sjulian return (ENOBUFS); 3050114878Sjulian } 3051114878Sjulian mcrc->m_len = 1; 3052114878Sjulian 3053114878Sjulian /* Fill UIH frame header */ 3054114878Sjulian hdr = mtod(m, struct rfcomm_frame_hdr *); 3055114878Sjulian hdr->address = address; 3056114878Sjulian hdr->control = RFCOMM_MKCONTROL(RFCOMM_FRAME_UIH, pf); 3057114878Sjulian 3058114878Sjulian /* Calculate FCS */ 3059114878Sjulian mcrc->m_data[0] = ng_btsocket_rfcomm_fcs2((u_int8_t *) hdr); 3060114878Sjulian 3061114878Sjulian /* Put length back */ 3062114878Sjulian length = (data != NULL)? data->m_pkthdr.len : 0; 3063114878Sjulian if (length > 127) { 3064114878Sjulian u_int16_t l = htole16(RFCOMM_MKLEN16(length)); 3065114878Sjulian 3066114878Sjulian bcopy(&l, &hdr->length, sizeof(l)); 3067114878Sjulian m->m_pkthdr.len ++; 3068114878Sjulian m->m_len ++; 3069114878Sjulian } else 3070114878Sjulian hdr->length = RFCOMM_MKLEN8(length); 3071114878Sjulian 3072114878Sjulian if (pf) { 3073114878Sjulian m->m_data[m->m_len] = credits; 3074114878Sjulian m->m_pkthdr.len ++; 3075114878Sjulian m->m_len ++; 3076114878Sjulian } 3077114878Sjulian 3078114878Sjulian /* Add payload */ 3079114878Sjulian if (data != NULL) { 3080114878Sjulian m_cat(m, data); 3081114878Sjulian m->m_pkthdr.len += length; 3082114878Sjulian } 3083114878Sjulian 3084114878Sjulian /* Put FCS back */ 3085114878Sjulian m_cat(m, mcrc); 3086114878Sjulian m->m_pkthdr.len ++; 3087114878Sjulian 3088114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3089114878Sjulian"%s: Sending UIH state=%d, flags=%#x, address=%d, length=%d, pf=%d, " \ 3090114878Sjulian"credits=%d, len=%d\n", 3091114878Sjulian __func__, s->state, s->flags, address, length, pf, credits, 3092114878Sjulian m->m_pkthdr.len); 3093114878Sjulian 3094114878Sjulian NG_BT_MBUFQ_ENQUEUE(&s->outq, m); 3095114878Sjulian 3096114878Sjulian return (0); 3097114878Sjulian} /* ng_btsocket_rfcomm_send_uih */ 3098114878Sjulian 3099114878Sjulian/* 3100114878Sjulian * Send MSC request. Caller must hold pcb->pcb_mtx and pcb->session->session_mtx 3101114878Sjulian */ 3102114878Sjulian 3103114878Sjulianstatic int 3104114878Sjulianng_btsocket_rfcomm_send_msc(ng_btsocket_rfcomm_pcb_p pcb) 3105114878Sjulian{ 3106114878Sjulian struct mbuf *m = NULL; 3107114878Sjulian struct rfcomm_mcc_hdr *hdr = NULL; 3108114878Sjulian struct rfcomm_mcc_msc *msc = NULL; 3109114878Sjulian 3110114878Sjulian mtx_assert(&pcb->session->session_mtx, MA_OWNED); 3111114878Sjulian mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3112114878Sjulian 3113114878Sjulian MGETHDR(m, M_DONTWAIT, MT_DATA); 3114114878Sjulian if (m == NULL) 3115114878Sjulian return (ENOBUFS); 3116114878Sjulian 3117114878Sjulian m->m_pkthdr.len = m->m_len = sizeof(*hdr) + sizeof(*msc); 3118114878Sjulian 3119114878Sjulian hdr = mtod(m, struct rfcomm_mcc_hdr *); 3120114878Sjulian msc = (struct rfcomm_mcc_msc *)(hdr + 1); 3121114878Sjulian 3122114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(1, RFCOMM_MCC_MSC); 3123114878Sjulian hdr->length = RFCOMM_MKLEN8(sizeof(*msc)); 3124114878Sjulian 3125114878Sjulian msc->address = RFCOMM_MKADDRESS(1, pcb->dlci); 3126114878Sjulian msc->modem = pcb->lmodem; 3127114878Sjulian 3128114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3129114878Sjulian"%s: Sending MSC dlci=%d, state=%d, flags=%#x, address=%d, modem=%#x\n", 3130114878Sjulian __func__, pcb->dlci, pcb->state, pcb->flags, msc->address, 3131114878Sjulian msc->modem); 3132114878Sjulian 3133114878Sjulian return (ng_btsocket_rfcomm_send_uih(pcb->session, 3134114878Sjulian RFCOMM_MKADDRESS(INITIATOR(pcb->session), 0), 0, 0, m)); 3135114878Sjulian} /* ng_btsocket_rfcomm_send_msc */ 3136114878Sjulian 3137114878Sjulian/* 3138114878Sjulian * Send PN request. Caller must hold pcb->pcb_mtx and pcb->session->session_mtx 3139114878Sjulian */ 3140114878Sjulian 3141114878Sjulianstatic int 3142114878Sjulianng_btsocket_rfcomm_send_pn(ng_btsocket_rfcomm_pcb_p pcb) 3143114878Sjulian{ 3144114878Sjulian struct mbuf *m = NULL; 3145114878Sjulian struct rfcomm_mcc_hdr *hdr = NULL; 3146114878Sjulian struct rfcomm_mcc_pn *pn = NULL; 3147114878Sjulian 3148114878Sjulian mtx_assert(&pcb->session->session_mtx, MA_OWNED); 3149114878Sjulian mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3150114878Sjulian 3151114878Sjulian MGETHDR(m, M_DONTWAIT, MT_DATA); 3152114878Sjulian if (m == NULL) 3153114878Sjulian return (ENOBUFS); 3154114878Sjulian 3155114878Sjulian m->m_pkthdr.len = m->m_len = sizeof(*hdr) + sizeof(*pn); 3156114878Sjulian 3157114878Sjulian hdr = mtod(m, struct rfcomm_mcc_hdr *); 3158114878Sjulian pn = (struct rfcomm_mcc_pn *)(hdr + 1); 3159114878Sjulian 3160114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(1, RFCOMM_MCC_PN); 3161114878Sjulian hdr->length = RFCOMM_MKLEN8(sizeof(*pn)); 3162114878Sjulian 3163114878Sjulian pn->dlci = pcb->dlci; 3164121054Semax 3165121054Semax /* 3166121054Semax * Set default DLCI priority as described in GSM 07.10 3167121054Semax * (ETSI TS 101 369) clause 5.6 page 42 3168121054Semax */ 3169121054Semax 3170121054Semax pn->priority = (pcb->dlci < 56)? (((pcb->dlci >> 3) << 3) + 7) : 61; 3171114878Sjulian pn->ack_timer = 0; 3172114878Sjulian pn->mtu = htole16(pcb->mtu); 3173114878Sjulian pn->max_retrans = 0; 3174114878Sjulian 3175114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) { 3176114878Sjulian pn->flow_control = 0xf0; 3177114878Sjulian pn->credits = pcb->rx_cred; 3178114878Sjulian } else { 3179114878Sjulian pn->flow_control = 0; 3180114878Sjulian pn->credits = 0; 3181114878Sjulian } 3182114878Sjulian 3183114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3184114878Sjulian"%s: Sending PN dlci=%d, state=%d, flags=%#x, mtu=%d, flow_control=%#x, " \ 3185114878Sjulian"credits=%d\n", __func__, pcb->dlci, pcb->state, pcb->flags, pcb->mtu, 3186114878Sjulian pn->flow_control, pn->credits); 3187114878Sjulian 3188114878Sjulian return (ng_btsocket_rfcomm_send_uih(pcb->session, 3189114878Sjulian RFCOMM_MKADDRESS(INITIATOR(pcb->session), 0), 0, 0, m)); 3190114878Sjulian} /* ng_btsocket_rfcomm_send_pn */ 3191114878Sjulian 3192114878Sjulian/* 3193114878Sjulian * Calculate and send credits based on available space in receive buffer 3194114878Sjulian */ 3195114878Sjulian 3196114878Sjulianstatic int 3197114878Sjulianng_btsocket_rfcomm_send_credits(ng_btsocket_rfcomm_pcb_p pcb) 3198114878Sjulian{ 3199114878Sjulian int error = 0; 3200114878Sjulian u_int8_t credits; 3201114878Sjulian 3202114878Sjulian mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3203114878Sjulian mtx_assert(&pcb->session->session_mtx, MA_OWNED); 3204114878Sjulian 3205114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3206114878Sjulian"%s: Sending more credits, dlci=%d, state=%d, flags=%#x, mtu=%d, " \ 3207114878Sjulian"space=%ld, tx_cred=%d, rx_cred=%d\n", 3208114878Sjulian __func__, pcb->dlci, pcb->state, pcb->flags, pcb->mtu, 3209114878Sjulian sbspace(&pcb->so->so_rcv), pcb->tx_cred, pcb->rx_cred); 3210114878Sjulian 3211114878Sjulian credits = sbspace(&pcb->so->so_rcv) / pcb->mtu; 3212114878Sjulian if (credits > 0) { 3213114878Sjulian if (pcb->rx_cred + credits > RFCOMM_MAX_CREDITS) 3214114878Sjulian credits = RFCOMM_MAX_CREDITS - pcb->rx_cred; 3215114878Sjulian 3216114878Sjulian error = ng_btsocket_rfcomm_send_uih( 3217114878Sjulian pcb->session, 3218114878Sjulian RFCOMM_MKADDRESS(INITIATOR(pcb->session), 3219114878Sjulian pcb->dlci), 1, credits, NULL); 3220114878Sjulian if (error == 0) { 3221114878Sjulian pcb->rx_cred += credits; 3222114878Sjulian 3223114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3224114878Sjulian"%s: Gave remote side %d more credits, dlci=%d, state=%d, flags=%#x, " \ 3225114878Sjulian"rx_cred=%d, tx_cred=%d\n", __func__, credits, pcb->dlci, pcb->state, 3226114878Sjulian pcb->flags, pcb->rx_cred, pcb->tx_cred); 3227114878Sjulian } else 3228114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 3229114878Sjulian"%s: Could not send credits, error=%d, dlci=%d, state=%d, flags=%#x, " \ 3230114878Sjulian"mtu=%d, space=%ld, tx_cred=%d, rx_cred=%d\n", 3231114878Sjulian __func__, error, pcb->dlci, pcb->state, 3232114878Sjulian pcb->flags, pcb->mtu, sbspace(&pcb->so->so_rcv), 3233114878Sjulian pcb->tx_cred, pcb->rx_cred); 3234114878Sjulian } 3235114878Sjulian 3236114878Sjulian return (error); 3237114878Sjulian} /* ng_btsocket_rfcomm_send_credits */ 3238114878Sjulian 3239114878Sjulian/***************************************************************************** 3240114878Sjulian ***************************************************************************** 3241114878Sjulian ** RFCOMM DLCs 3242114878Sjulian ***************************************************************************** 3243114878Sjulian *****************************************************************************/ 3244114878Sjulian 3245114878Sjulian/* 3246114878Sjulian * Send data from socket send buffer 3247114878Sjulian * Caller must hold pcb->pcb_mtx and pcb->session->session_mtx 3248114878Sjulian */ 3249114878Sjulian 3250114878Sjulianstatic int 3251114878Sjulianng_btsocket_rfcomm_pcb_send(ng_btsocket_rfcomm_pcb_p pcb, int limit) 3252114878Sjulian{ 3253114878Sjulian struct mbuf *m = NULL; 3254114878Sjulian int sent, length, error; 3255114878Sjulian 3256114878Sjulian mtx_assert(&pcb->session->session_mtx, MA_OWNED); 3257114878Sjulian mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3258114878Sjulian 3259114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) 3260114878Sjulian limit = min(limit, pcb->tx_cred); 3261114878Sjulian else if (!(pcb->rmodem & RFCOMM_MODEM_FC)) 3262114878Sjulian limit = min(limit, RFCOMM_MAX_CREDITS); /* XXX ??? */ 3263114878Sjulian else 3264114878Sjulian limit = 0; 3265114878Sjulian 3266114878Sjulian if (limit == 0) { 3267114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3268114878Sjulian"%s: Could not send - remote flow control asserted, dlci=%d, flags=%#x, " \ 3269114878Sjulian"rmodem=%#x, tx_cred=%d\n", 3270114878Sjulian __func__, pcb->dlci, pcb->flags, pcb->rmodem, 3271114878Sjulian pcb->tx_cred); 3272114878Sjulian 3273114878Sjulian return (0); 3274114878Sjulian } 3275114878Sjulian 3276114878Sjulian for (error = 0, sent = 0; sent < limit; sent ++) { 3277114878Sjulian length = min(pcb->mtu, pcb->so->so_snd.sb_cc); 3278114878Sjulian if (length == 0) 3279114878Sjulian break; 3280114878Sjulian 3281114878Sjulian /* Get the chunk from the socket's send buffer */ 3282114878Sjulian m = ng_btsocket_rfcomm_prepare_packet(&pcb->so->so_snd, length); 3283114878Sjulian if (m == NULL) { 3284114878Sjulian error = ENOBUFS; 3285114878Sjulian break; 3286114878Sjulian } 3287114878Sjulian 3288114878Sjulian sbdrop(&pcb->so->so_snd, length); 3289114878Sjulian 3290114878Sjulian error = ng_btsocket_rfcomm_send_uih(pcb->session, 3291114878Sjulian RFCOMM_MKADDRESS(INITIATOR(pcb->session), 3292114878Sjulian pcb->dlci), 0, 0, m); 3293114878Sjulian if (error != 0) 3294114878Sjulian break; 3295114878Sjulian } 3296114878Sjulian 3297114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) 3298114878Sjulian pcb->tx_cred -= sent; 3299114878Sjulian 3300114878Sjulian if (error == 0 && sent > 0) { 3301114878Sjulian pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_SENDING; 3302114878Sjulian sowwakeup(pcb->so); 3303114878Sjulian } 3304114878Sjulian 3305114878Sjulian return (error); 3306114878Sjulian} /* ng_btsocket_rfcomm_pcb_send */ 3307114878Sjulian 3308114878Sjulian/* 3309114878Sjulian * Unlink and disconnect DLC. If ng_btsocket_rfcomm_pcb_kill() returns 3310114878Sjulian * non zero value than socket has no reference and has to be detached. 3311114878Sjulian * Caller must hold pcb->pcb_mtx and pcb->session->session_mtx 3312114878Sjulian */ 3313114878Sjulian 3314161623Semaxstatic void 3315114878Sjulianng_btsocket_rfcomm_pcb_kill(ng_btsocket_rfcomm_pcb_p pcb, int error) 3316114878Sjulian{ 3317114878Sjulian ng_btsocket_rfcomm_session_p s = pcb->session; 3318114878Sjulian 3319114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3320114878Sjulian"%s: Killing DLC, so=%p, dlci=%d, state=%d, flags=%#x, error=%d\n", 3321114878Sjulian __func__, pcb->so, pcb->dlci, pcb->state, pcb->flags, error); 3322114878Sjulian 3323114878Sjulian if (pcb->session == NULL) 3324114878Sjulian panic("%s: DLC without session, pcb=%p, state=%d, flags=%#x\n", 3325114878Sjulian __func__, pcb, pcb->state, pcb->flags); 3326114878Sjulian 3327142542Ssam mtx_assert(&pcb->session->session_mtx, MA_OWNED); 3328142542Ssam mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3329142542Ssam 3330114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO) 3331114878Sjulian ng_btsocket_rfcomm_untimeout(pcb); 3332114878Sjulian 3333114878Sjulian /* Detach DLC from the session. Does not matter which state DLC in */ 3334114878Sjulian LIST_REMOVE(pcb, session_next); 3335114878Sjulian pcb->session = NULL; 3336114878Sjulian 3337114878Sjulian /* Change DLC state and wakeup all sleepers */ 3338114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CLOSED; 3339114878Sjulian pcb->so->so_error = error; 3340114878Sjulian soisdisconnected(pcb->so); 3341114878Sjulian wakeup(&pcb->state); 3342114878Sjulian 3343114878Sjulian /* Check if we have any DLCs left on the session */ 3344114878Sjulian if (LIST_EMPTY(&s->dlcs) && INITIATOR(s)) { 3345114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3346114878Sjulian"%s: Disconnecting session, state=%d, flags=%#x, mtu=%d\n", 3347114878Sjulian __func__, s->state, s->flags, s->mtu); 3348114878Sjulian 3349114878Sjulian switch (s->state) { 3350114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CLOSED: 3351114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING: 3352114878Sjulian /* 3353114878Sjulian * Do not have to do anything here. We can get here 3354114878Sjulian * when L2CAP connection was terminated or we have 3355114878Sjulian * received DISC on multiplexor channel 3356114878Sjulian */ 3357114878Sjulian break; 3358114878Sjulian 3359114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_OPEN: 3360114878Sjulian /* Send DISC on multiplexor channel */ 3361114878Sjulian error = ng_btsocket_rfcomm_send_command(s, 3362114878Sjulian RFCOMM_FRAME_DISC, 0); 3363114878Sjulian if (error == 0) { 3364114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING; 3365114878Sjulian break; 3366114878Sjulian } 3367114878Sjulian /* FALL THROUGH */ 3368114878Sjulian 3369114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CONNECTING: 3370114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED: 3371114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 3372114878Sjulian break; 3373114878Sjulian 3374114878Sjulian/* case NG_BTSOCKET_RFCOMM_SESSION_LISTENING: */ 3375114878Sjulian default: 3376114878Sjulian panic("%s: Invalid session state=%d, flags=%#x\n", 3377114878Sjulian __func__, s->state, s->flags); 3378114878Sjulian break; 3379114878Sjulian } 3380114878Sjulian 3381114878Sjulian ng_btsocket_rfcomm_task_wakeup(); 3382114878Sjulian } 3383114878Sjulian} /* ng_btsocket_rfcomm_pcb_kill */ 3384114878Sjulian 3385114878Sjulian/* 3386114878Sjulian * Look for given dlci for given RFCOMM session. Caller must hold s->session_mtx 3387114878Sjulian */ 3388114878Sjulian 3389114878Sjulianstatic ng_btsocket_rfcomm_pcb_p 3390114878Sjulianng_btsocket_rfcomm_pcb_by_dlci(ng_btsocket_rfcomm_session_p s, int dlci) 3391114878Sjulian{ 3392114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = NULL; 3393114878Sjulian 3394114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 3395114878Sjulian 3396114878Sjulian LIST_FOREACH(pcb, &s->dlcs, session_next) 3397114878Sjulian if (pcb->dlci == dlci) 3398114878Sjulian break; 3399114878Sjulian 3400114878Sjulian return (pcb); 3401114878Sjulian} /* ng_btsocket_rfcomm_pcb_by_dlci */ 3402114878Sjulian 3403114878Sjulian/* 3404114878Sjulian * Look for socket that listens on given src address and given channel 3405114878Sjulian */ 3406114878Sjulian 3407114878Sjulianstatic ng_btsocket_rfcomm_pcb_p 3408114878Sjulianng_btsocket_rfcomm_pcb_listener(bdaddr_p src, int channel) 3409114878Sjulian{ 3410114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb1 = NULL; 3411114878Sjulian 3412114878Sjulian mtx_lock(&ng_btsocket_rfcomm_sockets_mtx); 3413114878Sjulian 3414114878Sjulian LIST_FOREACH(pcb, &ng_btsocket_rfcomm_sockets, next) { 3415114878Sjulian if (pcb->channel != channel || 3416114878Sjulian !(pcb->so->so_options & SO_ACCEPTCONN)) 3417114878Sjulian continue; 3418114878Sjulian 3419114878Sjulian if (bcmp(&pcb->src, src, sizeof(*src)) == 0) 3420114878Sjulian break; 3421114878Sjulian 3422114878Sjulian if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) 3423114878Sjulian pcb1 = pcb; 3424114878Sjulian } 3425114878Sjulian 3426114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 3427114878Sjulian 3428114878Sjulian return ((pcb != NULL)? pcb : pcb1); 3429114878Sjulian} /* ng_btsocket_rfcomm_pcb_listener */ 3430114878Sjulian 3431114878Sjulian/***************************************************************************** 3432114878Sjulian ***************************************************************************** 3433114878Sjulian ** Misc. functions 3434114878Sjulian ***************************************************************************** 3435114878Sjulian *****************************************************************************/ 3436114878Sjulian 3437114878Sjulian/* 3438114878Sjulian * Set timeout. Caller MUST hold pcb_mtx 3439114878Sjulian */ 3440114878Sjulian 3441114878Sjulianstatic void 3442114878Sjulianng_btsocket_rfcomm_timeout(ng_btsocket_rfcomm_pcb_p pcb) 3443114878Sjulian{ 3444114878Sjulian mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3445114878Sjulian 3446114878Sjulian if (!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)) { 3447114878Sjulian pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_TIMO; 3448114878Sjulian pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT; 3449114878Sjulian pcb->timo = timeout(ng_btsocket_rfcomm_process_timeout, pcb, 3450114878Sjulian ng_btsocket_rfcomm_timo * hz); 3451114878Sjulian } else 3452114878Sjulian panic("%s: Duplicated socket timeout?!\n", __func__); 3453114878Sjulian} /* ng_btsocket_rfcomm_timeout */ 3454114878Sjulian 3455114878Sjulian/* 3456114878Sjulian * Unset pcb timeout. Caller MUST hold pcb_mtx 3457114878Sjulian */ 3458114878Sjulian 3459114878Sjulianstatic void 3460114878Sjulianng_btsocket_rfcomm_untimeout(ng_btsocket_rfcomm_pcb_p pcb) 3461114878Sjulian{ 3462114878Sjulian mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3463114878Sjulian 3464114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO) { 3465114878Sjulian untimeout(ng_btsocket_rfcomm_process_timeout, pcb, pcb->timo); 3466114878Sjulian pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMO; 3467114878Sjulian pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT; 3468114878Sjulian } else 3469114878Sjulian panic("%s: No socket timeout?!\n", __func__); 3470114878Sjulian} /* ng_btsocket_rfcomm_timeout */ 3471114878Sjulian 3472114878Sjulian/* 3473114878Sjulian * Process pcb timeout 3474114878Sjulian */ 3475114878Sjulian 3476114878Sjulianstatic void 3477114878Sjulianng_btsocket_rfcomm_process_timeout(void *xpcb) 3478114878Sjulian{ 3479114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = (ng_btsocket_rfcomm_pcb_p) xpcb; 3480114878Sjulian 3481114878Sjulian mtx_lock(&pcb->pcb_mtx); 3482114878Sjulian 3483114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3484114878Sjulian"%s: Timeout, so=%p, dlci=%d, state=%d, flags=%#x\n", 3485114878Sjulian __func__, pcb->so, pcb->dlci, pcb->state, pcb->flags); 3486114878Sjulian 3487114878Sjulian pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMO; 3488114878Sjulian pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT; 3489114878Sjulian 3490114878Sjulian switch (pcb->state) { 3491114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING: 3492114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONNECTING: 3493114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING; 3494114878Sjulian break; 3495114878Sjulian 3496114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT: 3497114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING: 3498114878Sjulian break; 3499114878Sjulian 3500114878Sjulian default: 3501114878Sjulian panic( 3502114878Sjulian"%s: DLC timeout in invalid state, dlci=%d, state=%d, flags=%#x\n", 3503114878Sjulian __func__, pcb->dlci, pcb->state, pcb->flags); 3504114878Sjulian break; 3505114878Sjulian } 3506114878Sjulian 3507114878Sjulian ng_btsocket_rfcomm_task_wakeup(); 3508114878Sjulian 3509114878Sjulian mtx_unlock(&pcb->pcb_mtx); 3510114878Sjulian} /* ng_btsocket_rfcomm_process_timeout */ 3511114878Sjulian 3512114878Sjulian/* 3513114878Sjulian * Get up to length bytes from the socket buffer 3514114878Sjulian */ 3515114878Sjulian 3516114878Sjulianstatic struct mbuf * 3517114878Sjulianng_btsocket_rfcomm_prepare_packet(struct sockbuf *sb, int length) 3518114878Sjulian{ 3519114878Sjulian struct mbuf *top = NULL, *m = NULL, *n = NULL, *nextpkt = NULL; 3520114878Sjulian int mlen, noff, len; 3521114878Sjulian 3522114878Sjulian MGETHDR(top, M_DONTWAIT, MT_DATA); 3523114878Sjulian if (top == NULL) 3524114878Sjulian return (NULL); 3525114878Sjulian 3526114878Sjulian top->m_pkthdr.len = length; 3527114878Sjulian top->m_len = 0; 3528114878Sjulian mlen = MHLEN; 3529114878Sjulian 3530114878Sjulian m = top; 3531114878Sjulian n = sb->sb_mb; 3532114878Sjulian nextpkt = n->m_nextpkt; 3533114878Sjulian noff = 0; 3534114878Sjulian 3535114878Sjulian while (length > 0 && n != NULL) { 3536114878Sjulian len = min(mlen - m->m_len, n->m_len - noff); 3537114878Sjulian if (len > length) 3538114878Sjulian len = length; 3539114878Sjulian 3540114878Sjulian bcopy(mtod(n, caddr_t)+noff, mtod(m, caddr_t)+m->m_len, len); 3541114878Sjulian m->m_len += len; 3542114878Sjulian noff += len; 3543114878Sjulian length -= len; 3544114878Sjulian 3545114878Sjulian if (length > 0 && m->m_len == mlen) { 3546114878Sjulian MGET(m->m_next, M_DONTWAIT, MT_DATA); 3547114878Sjulian if (m->m_next == NULL) { 3548114878Sjulian NG_FREE_M(top); 3549114878Sjulian return (NULL); 3550114878Sjulian } 3551114878Sjulian 3552114878Sjulian m = m->m_next; 3553114878Sjulian m->m_len = 0; 3554114878Sjulian mlen = MLEN; 3555114878Sjulian } 3556114878Sjulian 3557114878Sjulian if (noff == n->m_len) { 3558114878Sjulian noff = 0; 3559114878Sjulian n = n->m_next; 3560114878Sjulian 3561114878Sjulian if (n == NULL) 3562114878Sjulian n = nextpkt; 3563114878Sjulian 3564114878Sjulian nextpkt = (n != NULL)? n->m_nextpkt : NULL; 3565114878Sjulian } 3566114878Sjulian } 3567114878Sjulian 3568114878Sjulian if (length < 0) 3569114878Sjulian panic("%s: length=%d\n", __func__, length); 3570114878Sjulian if (length > 0 && n == NULL) 3571114878Sjulian panic("%s: bogus length=%d, n=%p\n", __func__, length, n); 3572114878Sjulian 3573114878Sjulian return (top); 3574114878Sjulian} /* ng_btsocket_rfcomm_prepare_packet */ 3575114878Sjulian 3576