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 69227293Sedstatic 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); 206227309Sedstatic 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{ 331268061Strociny 332268061Strociny /* Skip initialization of globals for non-default instances. */ 333268061Strociny if (!IS_DEFAULT_VNET(curvnet)) 334268061Strociny return; 335268061Strociny 336114878Sjulian ng_btsocket_rfcomm_debug_level = NG_BTSOCKET_WARN_LEVEL; 337114878Sjulian ng_btsocket_rfcomm_timo = 60; 338114878Sjulian 339114878Sjulian /* RFCOMM task */ 340114878Sjulian TASK_INIT(&ng_btsocket_rfcomm_task, 0, 341114878Sjulian ng_btsocket_rfcomm_sessions_task, NULL); 342114878Sjulian 343114878Sjulian /* RFCOMM sessions list */ 344114878Sjulian LIST_INIT(&ng_btsocket_rfcomm_sessions); 345114878Sjulian mtx_init(&ng_btsocket_rfcomm_sessions_mtx, 346114878Sjulian "btsocks_rfcomm_sessions_mtx", NULL, MTX_DEF); 347114878Sjulian 348114878Sjulian /* RFCOMM sockets list */ 349114878Sjulian LIST_INIT(&ng_btsocket_rfcomm_sockets); 350114878Sjulian mtx_init(&ng_btsocket_rfcomm_sockets_mtx, 351114878Sjulian "btsocks_rfcomm_sockets_mtx", NULL, MTX_DEF); 352114878Sjulian} /* ng_btsocket_rfcomm_init */ 353114878Sjulian 354114878Sjulian/* 355114878Sjulian * Abort connection on socket 356114878Sjulian */ 357114878Sjulian 358157366Srwatsonvoid 359114878Sjulianng_btsocket_rfcomm_abort(struct socket *so) 360114878Sjulian{ 361160549Srwatson 362114878Sjulian so->so_error = ECONNABORTED; 363160549Srwatson (void)ng_btsocket_rfcomm_disconnect(so); 364114878Sjulian} /* ng_btsocket_rfcomm_abort */ 365114878Sjulian 366160549Srwatsonvoid 367160549Srwatsonng_btsocket_rfcomm_close(struct socket *so) 368160549Srwatson{ 369160549Srwatson 370160549Srwatson (void)ng_btsocket_rfcomm_disconnect(so); 371160549Srwatson} /* ng_btsocket_rfcomm_close */ 372160549Srwatson 373114878Sjulian/* 374114878Sjulian * Accept connection on socket. Nothing to do here, socket must be connected 375114878Sjulian * and ready, so just return peer address and be done with it. 376114878Sjulian */ 377114878Sjulian 378114878Sjulianint 379114878Sjulianng_btsocket_rfcomm_accept(struct socket *so, struct sockaddr **nam) 380114878Sjulian{ 381114878Sjulian return (ng_btsocket_rfcomm_peeraddr(so, nam)); 382114878Sjulian} /* ng_btsocket_rfcomm_accept */ 383114878Sjulian 384114878Sjulian/* 385114878Sjulian * Create and attach new socket 386114878Sjulian */ 387114878Sjulian 388114878Sjulianint 389114878Sjulianng_btsocket_rfcomm_attach(struct socket *so, int proto, struct thread *td) 390114878Sjulian{ 391114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 392114878Sjulian int error; 393114878Sjulian 394114878Sjulian /* Check socket and protocol */ 395114878Sjulian if (so->so_type != SOCK_STREAM) 396114878Sjulian return (ESOCKTNOSUPPORT); 397114878Sjulian 398114878Sjulian#if 0 /* XXX sonewconn() calls "pru_attach" with proto == 0 */ 399114878Sjulian if (proto != 0) 400114878Sjulian if (proto != BLUETOOTH_PROTO_RFCOMM) 401114878Sjulian return (EPROTONOSUPPORT); 402114878Sjulian#endif /* XXX */ 403114878Sjulian 404114878Sjulian if (pcb != NULL) 405114878Sjulian return (EISCONN); 406114878Sjulian 407114878Sjulian /* Reserve send and receive space if it is not reserved yet */ 408114878Sjulian if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) { 409114878Sjulian error = soreserve(so, NG_BTSOCKET_RFCOMM_SENDSPACE, 410114878Sjulian NG_BTSOCKET_RFCOMM_RECVSPACE); 411114878Sjulian if (error != 0) 412114878Sjulian return (error); 413114878Sjulian } 414114878Sjulian 415114878Sjulian /* Allocate the PCB */ 416184205Sdes pcb = malloc(sizeof(*pcb), 417114878Sjulian M_NETGRAPH_BTSOCKET_RFCOMM, M_NOWAIT | M_ZERO); 418114878Sjulian if (pcb == NULL) 419114878Sjulian return (ENOMEM); 420114878Sjulian 421114878Sjulian /* Link the PCB and the socket */ 422114878Sjulian so->so_pcb = (caddr_t) pcb; 423114878Sjulian pcb->so = so; 424114878Sjulian 425114878Sjulian /* Initialize PCB */ 426114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CLOSED; 427114878Sjulian pcb->flags = NG_BTSOCKET_RFCOMM_DLC_CFC; 428114878Sjulian 429114878Sjulian pcb->lmodem = 430114878Sjulian pcb->rmodem = (RFCOMM_MODEM_RTC | RFCOMM_MODEM_RTR | RFCOMM_MODEM_DV); 431114878Sjulian 432114878Sjulian pcb->mtu = RFCOMM_DEFAULT_MTU; 433114878Sjulian pcb->tx_cred = 0; 434114878Sjulian pcb->rx_cred = RFCOMM_DEFAULT_CREDITS; 435114878Sjulian 436114878Sjulian mtx_init(&pcb->pcb_mtx, "btsocks_rfcomm_pcb_mtx", NULL, MTX_DEF); 437114878Sjulian callout_handle_init(&pcb->timo); 438114878Sjulian 439114878Sjulian /* Add the PCB to the list */ 440114878Sjulian mtx_lock(&ng_btsocket_rfcomm_sockets_mtx); 441114878Sjulian LIST_INSERT_HEAD(&ng_btsocket_rfcomm_sockets, pcb, next); 442114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 443114878Sjulian 444114878Sjulian return (0); 445114878Sjulian} /* ng_btsocket_rfcomm_attach */ 446114878Sjulian 447114878Sjulian/* 448114878Sjulian * Bind socket 449114878Sjulian */ 450114878Sjulian 451114878Sjulianint 452114878Sjulianng_btsocket_rfcomm_bind(struct socket *so, struct sockaddr *nam, 453114878Sjulian struct thread *td) 454114878Sjulian{ 455173151Semax ng_btsocket_rfcomm_pcb_t *pcb = so2rfcomm_pcb(so), *pcb1; 456114878Sjulian struct sockaddr_rfcomm *sa = (struct sockaddr_rfcomm *) nam; 457114878Sjulian 458114878Sjulian if (pcb == NULL) 459114878Sjulian return (EINVAL); 460114878Sjulian 461114878Sjulian /* Verify address */ 462114878Sjulian if (sa == NULL) 463114878Sjulian return (EINVAL); 464114878Sjulian if (sa->rfcomm_family != AF_BLUETOOTH) 465114878Sjulian return (EAFNOSUPPORT); 466114878Sjulian if (sa->rfcomm_len != sizeof(*sa)) 467114878Sjulian return (EINVAL); 468114878Sjulian if (sa->rfcomm_channel > 30) 469114878Sjulian return (EINVAL); 470114878Sjulian 471173151Semax mtx_lock(&pcb->pcb_mtx); 472173151Semax 473173151Semax if (sa->rfcomm_channel != 0) { 474173151Semax mtx_lock(&ng_btsocket_rfcomm_sockets_mtx); 475173151Semax 476173151Semax LIST_FOREACH(pcb1, &ng_btsocket_rfcomm_sockets, next) { 477173151Semax if (pcb1->channel == sa->rfcomm_channel && 478173151Semax bcmp(&pcb1->src, &sa->rfcomm_bdaddr, 479173151Semax sizeof(pcb1->src)) == 0) { 480173151Semax mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 481173151Semax mtx_unlock(&pcb->pcb_mtx); 482173151Semax 483173151Semax return (EADDRINUSE); 484173151Semax } 485173151Semax } 486173151Semax 487173151Semax mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 488173151Semax } 489173151Semax 490114878Sjulian bcopy(&sa->rfcomm_bdaddr, &pcb->src, sizeof(pcb->src)); 491114878Sjulian pcb->channel = sa->rfcomm_channel; 492114878Sjulian 493173151Semax mtx_unlock(&pcb->pcb_mtx); 494173151Semax 495114878Sjulian return (0); 496114878Sjulian} /* ng_btsocket_rfcomm_bind */ 497114878Sjulian 498114878Sjulian/* 499114878Sjulian * Connect socket 500114878Sjulian */ 501114878Sjulian 502114878Sjulianint 503114878Sjulianng_btsocket_rfcomm_connect(struct socket *so, struct sockaddr *nam, 504114878Sjulian struct thread *td) 505114878Sjulian{ 506114878Sjulian ng_btsocket_rfcomm_pcb_t *pcb = so2rfcomm_pcb(so); 507114878Sjulian struct sockaddr_rfcomm *sa = (struct sockaddr_rfcomm *) nam; 508114878Sjulian ng_btsocket_rfcomm_session_t *s = NULL; 509114878Sjulian struct socket *l2so = NULL; 510114878Sjulian int dlci, error = 0; 511114878Sjulian 512114878Sjulian if (pcb == NULL) 513114878Sjulian return (EINVAL); 514114878Sjulian 515114878Sjulian /* Verify address */ 516114878Sjulian if (sa == NULL) 517114878Sjulian return (EINVAL); 518114878Sjulian if (sa->rfcomm_family != AF_BLUETOOTH) 519114878Sjulian return (EAFNOSUPPORT); 520114878Sjulian if (sa->rfcomm_len != sizeof(*sa)) 521114878Sjulian return (EINVAL); 522114878Sjulian if (sa->rfcomm_channel > 30) 523114878Sjulian return (EINVAL); 524114878Sjulian if (sa->rfcomm_channel == 0 || 525114878Sjulian bcmp(&sa->rfcomm_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) 526114878Sjulian return (EDESTADDRREQ); 527114878Sjulian 528114878Sjulian /* 529188452Semax * Note that we will not check for errors in socreate() because 530188452Semax * if we failed to create L2CAP socket at this point we still 531188452Semax * might have already open session. 532114878Sjulian */ 533114878Sjulian 534114878Sjulian error = socreate(PF_BLUETOOTH, &l2so, SOCK_SEQPACKET, 535114878Sjulian BLUETOOTH_PROTO_L2CAP, td->td_ucred, td); 536114878Sjulian 537114878Sjulian /* 538114878Sjulian * Look for session between "pcb->src" and "sa->rfcomm_bdaddr" (dst) 539114878Sjulian */ 540114878Sjulian 541114878Sjulian mtx_lock(&ng_btsocket_rfcomm_sessions_mtx); 542114878Sjulian 543114878Sjulian s = ng_btsocket_rfcomm_session_by_addr(&pcb->src, &sa->rfcomm_bdaddr); 544114878Sjulian if (s == NULL) { 545114878Sjulian /* 546114878Sjulian * We need to create new RFCOMM session. Check if we have L2CAP 547114878Sjulian * socket. If l2so == NULL then error has the error code from 548114878Sjulian * socreate() 549114878Sjulian */ 550114878Sjulian 551114878Sjulian if (l2so == NULL) { 552114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 553114878Sjulian return (error); 554114878Sjulian } 555114878Sjulian 556114878Sjulian error = ng_btsocket_rfcomm_session_create(&s, l2so, 557114878Sjulian &pcb->src, &sa->rfcomm_bdaddr, td); 558114878Sjulian if (error != 0) { 559114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 560114878Sjulian soclose(l2so); 561114878Sjulian 562114878Sjulian return (error); 563114878Sjulian } 564114878Sjulian } else if (l2so != NULL) 565114878Sjulian soclose(l2so); /* we don't need new L2CAP socket */ 566114878Sjulian 567114878Sjulian /* 568218909Sbrucec * Check if we already have the same DLCI the same session 569114878Sjulian */ 570114878Sjulian 571114878Sjulian mtx_lock(&s->session_mtx); 572114878Sjulian mtx_lock(&pcb->pcb_mtx); 573114878Sjulian 574114878Sjulian dlci = RFCOMM_MKDLCI(!INITIATOR(s), sa->rfcomm_channel); 575114878Sjulian 576114878Sjulian if (ng_btsocket_rfcomm_pcb_by_dlci(s, dlci) != NULL) { 577114878Sjulian mtx_unlock(&pcb->pcb_mtx); 578114878Sjulian mtx_unlock(&s->session_mtx); 579114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 580114878Sjulian 581114878Sjulian return (EBUSY); 582114878Sjulian } 583114878Sjulian 584114878Sjulian /* 585114878Sjulian * Check session state and if its not acceptable then refuse connection 586114878Sjulian */ 587114878Sjulian 588114878Sjulian switch (s->state) { 589114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CONNECTING: 590114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED: 591114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_OPEN: 592114878Sjulian /* 593114878Sjulian * Update destination address and channel and attach 594114878Sjulian * DLC to the session 595114878Sjulian */ 596114878Sjulian 597114878Sjulian bcopy(&sa->rfcomm_bdaddr, &pcb->dst, sizeof(pcb->dst)); 598114878Sjulian pcb->channel = sa->rfcomm_channel; 599114878Sjulian pcb->dlci = dlci; 600114878Sjulian 601114878Sjulian LIST_INSERT_HEAD(&s->dlcs, pcb, session_next); 602114878Sjulian pcb->session = s; 603114878Sjulian 604114878Sjulian ng_btsocket_rfcomm_timeout(pcb); 605114878Sjulian soisconnecting(pcb->so); 606114878Sjulian 607114878Sjulian if (s->state == NG_BTSOCKET_RFCOMM_SESSION_OPEN) { 608114878Sjulian pcb->mtu = s->mtu; 609114878Sjulian bcopy(&so2l2cap_pcb(s->l2so)->src, &pcb->src, 610114878Sjulian sizeof(pcb->src)); 611114878Sjulian 612114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONFIGURING; 613114878Sjulian 614114878Sjulian error = ng_btsocket_rfcomm_send_pn(pcb); 615114878Sjulian if (error == 0) 616114878Sjulian error = ng_btsocket_rfcomm_task_wakeup(); 617114878Sjulian } else 618114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT; 619114878Sjulian break; 620114878Sjulian 621114878Sjulian default: 622114878Sjulian error = ECONNRESET; 623114878Sjulian break; 624114878Sjulian } 625114878Sjulian 626114878Sjulian mtx_unlock(&pcb->pcb_mtx); 627114878Sjulian mtx_unlock(&s->session_mtx); 628114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 629114878Sjulian 630114878Sjulian return (error); 631114878Sjulian} /* ng_btsocket_rfcomm_connect */ 632114878Sjulian 633114878Sjulian/* 634114878Sjulian * Process ioctl's calls on socket. 635114878Sjulian * XXX FIXME this should provide interface to the RFCOMM multiplexor channel 636114878Sjulian */ 637114878Sjulian 638114878Sjulianint 639114878Sjulianng_btsocket_rfcomm_control(struct socket *so, u_long cmd, caddr_t data, 640114878Sjulian struct ifnet *ifp, struct thread *td) 641114878Sjulian{ 642114878Sjulian return (EINVAL); 643114878Sjulian} /* ng_btsocket_rfcomm_control */ 644114878Sjulian 645114878Sjulian/* 646114878Sjulian * Process getsockopt/setsockopt system calls 647114878Sjulian */ 648114878Sjulian 649114878Sjulianint 650114878Sjulianng_btsocket_rfcomm_ctloutput(struct socket *so, struct sockopt *sopt) 651114878Sjulian{ 652114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 653114878Sjulian struct ng_btsocket_rfcomm_fc_info fcinfo; 654114878Sjulian int error = 0; 655114878Sjulian 656114878Sjulian if (pcb == NULL) 657114878Sjulian return (EINVAL); 658114878Sjulian if (sopt->sopt_level != SOL_RFCOMM) 659114878Sjulian return (0); 660114878Sjulian 661114878Sjulian mtx_lock(&pcb->pcb_mtx); 662114878Sjulian 663114878Sjulian switch (sopt->sopt_dir) { 664114878Sjulian case SOPT_GET: 665114878Sjulian switch (sopt->sopt_name) { 666114878Sjulian case SO_RFCOMM_MTU: 667114878Sjulian error = sooptcopyout(sopt, &pcb->mtu, sizeof(pcb->mtu)); 668114878Sjulian break; 669114878Sjulian 670114878Sjulian case SO_RFCOMM_FC_INFO: 671114878Sjulian fcinfo.lmodem = pcb->lmodem; 672114878Sjulian fcinfo.rmodem = pcb->rmodem; 673114878Sjulian fcinfo.tx_cred = pcb->tx_cred; 674114878Sjulian fcinfo.rx_cred = pcb->rx_cred; 675114878Sjulian fcinfo.cfc = (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC)? 676114878Sjulian 1 : 0; 677114878Sjulian fcinfo.reserved = 0; 678114878Sjulian 679114878Sjulian error = sooptcopyout(sopt, &fcinfo, sizeof(fcinfo)); 680114878Sjulian break; 681114878Sjulian 682114878Sjulian default: 683114878Sjulian error = ENOPROTOOPT; 684114878Sjulian break; 685114878Sjulian } 686114878Sjulian break; 687114878Sjulian 688114878Sjulian case SOPT_SET: 689114878Sjulian switch (sopt->sopt_name) { 690114878Sjulian default: 691114878Sjulian error = ENOPROTOOPT; 692114878Sjulian break; 693114878Sjulian } 694114878Sjulian break; 695114878Sjulian 696114878Sjulian default: 697114878Sjulian error = EINVAL; 698114878Sjulian break; 699114878Sjulian } 700114878Sjulian 701114878Sjulian mtx_unlock(&pcb->pcb_mtx); 702114878Sjulian 703114878Sjulian return (error); 704114878Sjulian} /* ng_btsocket_rfcomm_ctloutput */ 705114878Sjulian 706114878Sjulian/* 707114878Sjulian * Detach and destroy socket 708114878Sjulian */ 709114878Sjulian 710157370Srwatsonvoid 711114878Sjulianng_btsocket_rfcomm_detach(struct socket *so) 712114878Sjulian{ 713114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 714114878Sjulian 715157370Srwatson KASSERT(pcb != NULL, ("ng_btsocket_rfcomm_detach: pcb == NULL")); 716114878Sjulian 717114878Sjulian mtx_lock(&pcb->pcb_mtx); 718114878Sjulian 719114878Sjulian switch (pcb->state) { 720114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT: 721114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING: 722114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONNECTING: 723114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONNECTED: 724114878Sjulian /* XXX What to do with pending request? */ 725114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO) 726114878Sjulian ng_btsocket_rfcomm_untimeout(pcb); 727114878Sjulian 728114878Sjulian if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT) 729114878Sjulian pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_DETACHED; 730114878Sjulian else 731114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING; 732114878Sjulian 733114878Sjulian ng_btsocket_rfcomm_task_wakeup(); 734114878Sjulian break; 735114878Sjulian 736114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING: 737114878Sjulian ng_btsocket_rfcomm_task_wakeup(); 738114878Sjulian break; 739114878Sjulian } 740114878Sjulian 741114878Sjulian while (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CLOSED) 742114878Sjulian msleep(&pcb->state, &pcb->pcb_mtx, PZERO, "rf_det", 0); 743114878Sjulian 744114878Sjulian if (pcb->session != NULL) 745114878Sjulian panic("%s: pcb->session != NULL\n", __func__); 746114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO) 747114878Sjulian panic("%s: timeout on closed DLC, flags=%#x\n", 748114878Sjulian __func__, pcb->flags); 749114878Sjulian 750114878Sjulian mtx_lock(&ng_btsocket_rfcomm_sockets_mtx); 751114878Sjulian LIST_REMOVE(pcb, next); 752114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 753114878Sjulian 754114878Sjulian mtx_unlock(&pcb->pcb_mtx); 755114878Sjulian 756114878Sjulian mtx_destroy(&pcb->pcb_mtx); 757114878Sjulian bzero(pcb, sizeof(*pcb)); 758184205Sdes free(pcb, M_NETGRAPH_BTSOCKET_RFCOMM); 759114878Sjulian 760114878Sjulian soisdisconnected(so); 761114878Sjulian so->so_pcb = NULL; 762114878Sjulian} /* ng_btsocket_rfcomm_detach */ 763114878Sjulian 764114878Sjulian/* 765114878Sjulian * Disconnect socket 766114878Sjulian */ 767114878Sjulian 768114878Sjulianint 769114878Sjulianng_btsocket_rfcomm_disconnect(struct socket *so) 770114878Sjulian{ 771114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 772114878Sjulian 773114878Sjulian if (pcb == NULL) 774114878Sjulian return (EINVAL); 775114878Sjulian 776114878Sjulian mtx_lock(&pcb->pcb_mtx); 777114878Sjulian 778114878Sjulian if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING) { 779114878Sjulian mtx_unlock(&pcb->pcb_mtx); 780114878Sjulian return (EINPROGRESS); 781114878Sjulian } 782114878Sjulian 783114878Sjulian /* XXX What to do with pending request? */ 784114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO) 785114878Sjulian ng_btsocket_rfcomm_untimeout(pcb); 786114878Sjulian 787114878Sjulian switch (pcb->state) { 788114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING: /* XXX can we get here? */ 789114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONNECTING: /* XXX can we get here? */ 790114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONNECTED: 791114878Sjulian 792114878Sjulian /* 793114878Sjulian * Just change DLC state and enqueue RFCOMM task. It will 794114878Sjulian * queue and send DISC on the DLC. 795114878Sjulian */ 796114878Sjulian 797114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING; 798114878Sjulian soisdisconnecting(so); 799114878Sjulian 800114878Sjulian ng_btsocket_rfcomm_task_wakeup(); 801114878Sjulian break; 802114878Sjulian 803161623Semax case NG_BTSOCKET_RFCOMM_DLC_CLOSED: 804161623Semax case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT: 805161623Semax break; 806161623Semax 807114878Sjulian default: 808114878Sjulian panic("%s: Invalid DLC state=%d, flags=%#x\n", 809114878Sjulian __func__, pcb->state, pcb->flags); 810114878Sjulian break; 811114878Sjulian } 812114878Sjulian 813114878Sjulian mtx_unlock(&pcb->pcb_mtx); 814114878Sjulian 815114878Sjulian return (0); 816114878Sjulian} /* ng_btsocket_rfcomm_disconnect */ 817114878Sjulian 818114878Sjulian/* 819114878Sjulian * Listen on socket. First call to listen() will create listening RFCOMM session 820114878Sjulian */ 821114878Sjulian 822114878Sjulianint 823151888Srwatsonng_btsocket_rfcomm_listen(struct socket *so, int backlog, struct thread *td) 824114878Sjulian{ 825173151Semax ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so), pcb1; 826114878Sjulian ng_btsocket_rfcomm_session_p s = NULL; 827114878Sjulian struct socket *l2so = NULL; 828173151Semax int error, socreate_error, usedchannels; 829114878Sjulian 830114878Sjulian if (pcb == NULL) 831114878Sjulian return (EINVAL); 832173151Semax if (pcb->channel > 30) 833171937Semax return (EADDRNOTAVAIL); 834114878Sjulian 835173151Semax usedchannels = 0; 836173151Semax 837173151Semax mtx_lock(&pcb->pcb_mtx); 838173151Semax 839173151Semax if (pcb->channel == 0) { 840173151Semax mtx_lock(&ng_btsocket_rfcomm_sockets_mtx); 841173151Semax 842173151Semax LIST_FOREACH(pcb1, &ng_btsocket_rfcomm_sockets, next) 843173151Semax if (pcb1->channel != 0 && 844173151Semax bcmp(&pcb1->src, &pcb->src, sizeof(pcb->src)) == 0) 845173151Semax usedchannels |= (1 << (pcb1->channel - 1)); 846173151Semax 847173151Semax for (pcb->channel = 30; pcb->channel > 0; pcb->channel --) 848173151Semax if (!(usedchannels & (1 << (pcb->channel - 1)))) 849173151Semax break; 850173151Semax 851173151Semax if (pcb->channel == 0) { 852173151Semax mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 853173151Semax mtx_unlock(&pcb->pcb_mtx); 854173151Semax 855173151Semax return (EADDRNOTAVAIL); 856173151Semax } 857173151Semax 858173151Semax mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 859173151Semax } 860173151Semax 861173151Semax mtx_unlock(&pcb->pcb_mtx); 862173151Semax 863114878Sjulian /* 864188452Semax * Note that we will not check for errors in socreate() because 865188452Semax * if we failed to create L2CAP socket at this point we still 866188452Semax * might have already open session. 867114878Sjulian */ 868114878Sjulian 869142190Srwatson socreate_error = socreate(PF_BLUETOOTH, &l2so, SOCK_SEQPACKET, 870114878Sjulian BLUETOOTH_PROTO_L2CAP, td->td_ucred, td); 871114878Sjulian 872142190Srwatson /* 873142190Srwatson * Transition the socket and session into the LISTENING state. Check 874142190Srwatson * for collisions first, as there can only be one. 875114878Sjulian */ 876114878Sjulian mtx_lock(&ng_btsocket_rfcomm_sessions_mtx); 877142190Srwatson SOCK_LOCK(so); 878142190Srwatson error = solisten_proto_check(so); 879161623Semax SOCK_UNLOCK(so); 880142190Srwatson if (error != 0) 881142190Srwatson goto out; 882114878Sjulian 883114878Sjulian LIST_FOREACH(s, &ng_btsocket_rfcomm_sessions, next) 884114878Sjulian if (s->state == NG_BTSOCKET_RFCOMM_SESSION_LISTENING) 885114878Sjulian break; 886114878Sjulian 887114878Sjulian if (s == NULL) { 888114878Sjulian /* 889114878Sjulian * We need to create default RFCOMM session. Check if we have 890114878Sjulian * L2CAP socket. If l2so == NULL then error has the error code 891114878Sjulian * from socreate() 892114878Sjulian */ 893114878Sjulian if (l2so == NULL) { 894142190Srwatson error = socreate_error; 895142190Srwatson goto out; 896114878Sjulian } 897114878Sjulian 898114878Sjulian /* 899114878Sjulian * Create default listen RFCOMM session. The default RFCOMM 900114878Sjulian * session will listen on ANY address. 901114878Sjulian * 902114878Sjulian * XXX FIXME Note that currently there is no way to adjust MTU 903114878Sjulian * for the default session. 904114878Sjulian */ 905114878Sjulian error = ng_btsocket_rfcomm_session_create(&s, l2so, 906114878Sjulian NG_HCI_BDADDR_ANY, NULL, td); 907142190Srwatson if (error != 0) 908142190Srwatson goto out; 909142190Srwatson l2so = NULL; 910142190Srwatson } 911161623Semax SOCK_LOCK(so); 912151888Srwatson solisten_proto(so, backlog); 913161623Semax SOCK_UNLOCK(so); 914142190Srwatsonout: 915114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 916142190Srwatson /* 917142190Srwatson * If we still have an l2so reference here, it's unneeded, so release 918142190Srwatson * it. 919142190Srwatson */ 920142190Srwatson if (l2so != NULL) 921142190Srwatson soclose(l2so); 922142190Srwatson return (error); 923114878Sjulian} /* ng_btsocket_listen */ 924114878Sjulian 925114878Sjulian/* 926114878Sjulian * Get peer address 927114878Sjulian */ 928114878Sjulian 929114878Sjulianint 930114878Sjulianng_btsocket_rfcomm_peeraddr(struct socket *so, struct sockaddr **nam) 931114878Sjulian{ 932114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 933114878Sjulian struct sockaddr_rfcomm sa; 934114878Sjulian 935114878Sjulian if (pcb == NULL) 936114878Sjulian return (EINVAL); 937114878Sjulian 938114878Sjulian bcopy(&pcb->dst, &sa.rfcomm_bdaddr, sizeof(sa.rfcomm_bdaddr)); 939114878Sjulian sa.rfcomm_channel = pcb->channel; 940114878Sjulian sa.rfcomm_len = sizeof(sa); 941114878Sjulian sa.rfcomm_family = AF_BLUETOOTH; 942114878Sjulian 943126425Srwatson *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 944114878Sjulian 945114878Sjulian return ((*nam == NULL)? ENOMEM : 0); 946114878Sjulian} /* ng_btsocket_rfcomm_peeraddr */ 947114878Sjulian 948114878Sjulian/* 949114878Sjulian * Send data to socket 950114878Sjulian */ 951114878Sjulian 952114878Sjulianint 953114878Sjulianng_btsocket_rfcomm_send(struct socket *so, int flags, struct mbuf *m, 954114878Sjulian struct sockaddr *nam, struct mbuf *control, struct thread *td) 955114878Sjulian{ 956114878Sjulian ng_btsocket_rfcomm_pcb_t *pcb = so2rfcomm_pcb(so); 957114878Sjulian int error = 0; 958114878Sjulian 959114878Sjulian /* Check socket and input */ 960114878Sjulian if (pcb == NULL || m == NULL || control != NULL) { 961114878Sjulian error = EINVAL; 962114878Sjulian goto drop; 963114878Sjulian } 964114878Sjulian 965114878Sjulian mtx_lock(&pcb->pcb_mtx); 966114878Sjulian 967114878Sjulian /* Make sure DLC is connected */ 968114878Sjulian if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTED) { 969114878Sjulian mtx_unlock(&pcb->pcb_mtx); 970114878Sjulian error = ENOTCONN; 971114878Sjulian goto drop; 972114878Sjulian } 973114878Sjulian 974114878Sjulian /* Put the packet on the socket's send queue and wakeup RFCOMM task */ 975114878Sjulian sbappend(&pcb->so->so_snd, m); 976114878Sjulian m = NULL; 977114878Sjulian 978114878Sjulian if (!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_SENDING)) { 979114878Sjulian pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_SENDING; 980114878Sjulian error = ng_btsocket_rfcomm_task_wakeup(); 981114878Sjulian } 982114878Sjulian 983114878Sjulian mtx_unlock(&pcb->pcb_mtx); 984114878Sjuliandrop: 985114878Sjulian NG_FREE_M(m); /* checks for != NULL */ 986114878Sjulian NG_FREE_M(control); 987114878Sjulian 988114878Sjulian return (error); 989114878Sjulian} /* ng_btsocket_rfcomm_send */ 990114878Sjulian 991114878Sjulian/* 992114878Sjulian * Get socket address 993114878Sjulian */ 994114878Sjulian 995114878Sjulianint 996114878Sjulianng_btsocket_rfcomm_sockaddr(struct socket *so, struct sockaddr **nam) 997114878Sjulian{ 998114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 999114878Sjulian struct sockaddr_rfcomm sa; 1000114878Sjulian 1001114878Sjulian if (pcb == NULL) 1002114878Sjulian return (EINVAL); 1003114878Sjulian 1004114878Sjulian bcopy(&pcb->src, &sa.rfcomm_bdaddr, sizeof(sa.rfcomm_bdaddr)); 1005114878Sjulian sa.rfcomm_channel = pcb->channel; 1006114878Sjulian sa.rfcomm_len = sizeof(sa); 1007114878Sjulian sa.rfcomm_family = AF_BLUETOOTH; 1008114878Sjulian 1009126425Srwatson *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 1010114878Sjulian 1011114878Sjulian return ((*nam == NULL)? ENOMEM : 0); 1012114878Sjulian} /* ng_btsocket_rfcomm_sockaddr */ 1013114878Sjulian 1014114878Sjulian/* 1015114878Sjulian * Upcall function for L2CAP sockets. Enqueue RFCOMM task. 1016114878Sjulian */ 1017114878Sjulian 1018193272Sjhbstatic int 1019114878Sjulianng_btsocket_rfcomm_upcall(struct socket *so, void *arg, int waitflag) 1020114878Sjulian{ 1021114878Sjulian int error; 1022114878Sjulian 1023114878Sjulian if (so == NULL) 1024114878Sjulian panic("%s: so == NULL\n", __func__); 1025114878Sjulian 1026114878Sjulian if ((error = ng_btsocket_rfcomm_task_wakeup()) != 0) 1027114878Sjulian NG_BTSOCKET_RFCOMM_ALERT( 1028114878Sjulian"%s: Could not enqueue RFCOMM task, error=%d\n", __func__, error); 1029193272Sjhb return (SU_OK); 1030114878Sjulian} /* ng_btsocket_rfcomm_upcall */ 1031114878Sjulian 1032114878Sjulian/* 1033114878Sjulian * RFCOMM task. Will handle all RFCOMM sessions in one pass. 1034114878Sjulian * XXX FIXME does not scale very well 1035114878Sjulian */ 1036114878Sjulian 1037114878Sjulianstatic void 1038114878Sjulianng_btsocket_rfcomm_sessions_task(void *ctx, int pending) 1039114878Sjulian{ 1040114878Sjulian ng_btsocket_rfcomm_session_p s = NULL, s_next = NULL; 1041114878Sjulian 1042114878Sjulian mtx_lock(&ng_btsocket_rfcomm_sessions_mtx); 1043114878Sjulian 1044114878Sjulian for (s = LIST_FIRST(&ng_btsocket_rfcomm_sessions); s != NULL; ) { 1045114878Sjulian mtx_lock(&s->session_mtx); 1046114878Sjulian s_next = LIST_NEXT(s, next); 1047114878Sjulian 1048114878Sjulian ng_btsocket_rfcomm_session_task(s); 1049114878Sjulian 1050114878Sjulian if (s->state == NG_BTSOCKET_RFCOMM_SESSION_CLOSED) { 1051114878Sjulian /* Unlink and clean the session */ 1052114878Sjulian LIST_REMOVE(s, next); 1053114878Sjulian 1054114878Sjulian NG_BT_MBUFQ_DRAIN(&s->outq); 1055114878Sjulian if (!LIST_EMPTY(&s->dlcs)) 1056114878Sjulian panic("%s: DLC list is not empty\n", __func__); 1057114878Sjulian 1058114878Sjulian /* Close L2CAP socket */ 1059130653Srwatson SOCKBUF_LOCK(&s->l2so->so_rcv); 1060193272Sjhb soupcall_clear(s->l2so, SO_RCV); 1061130653Srwatson SOCKBUF_UNLOCK(&s->l2so->so_rcv); 1062130653Srwatson SOCKBUF_LOCK(&s->l2so->so_snd); 1063193272Sjhb soupcall_clear(s->l2so, SO_SND); 1064130653Srwatson SOCKBUF_UNLOCK(&s->l2so->so_snd); 1065114878Sjulian soclose(s->l2so); 1066114878Sjulian 1067114878Sjulian mtx_unlock(&s->session_mtx); 1068114878Sjulian 1069114878Sjulian mtx_destroy(&s->session_mtx); 1070114878Sjulian bzero(s, sizeof(*s)); 1071184205Sdes free(s, M_NETGRAPH_BTSOCKET_RFCOMM); 1072114878Sjulian } else 1073114878Sjulian mtx_unlock(&s->session_mtx); 1074114878Sjulian 1075114878Sjulian s = s_next; 1076114878Sjulian } 1077114878Sjulian 1078114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 1079114878Sjulian} /* ng_btsocket_rfcomm_sessions_task */ 1080114878Sjulian 1081114878Sjulian/* 1082114878Sjulian * Process RFCOMM session. Will handle all RFCOMM sockets in one pass. 1083114878Sjulian */ 1084114878Sjulian 1085114878Sjulianstatic void 1086114878Sjulianng_btsocket_rfcomm_session_task(ng_btsocket_rfcomm_session_p s) 1087114878Sjulian{ 1088114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1089114878Sjulian 1090130480Srwatson if (s->l2so->so_rcv.sb_state & SBS_CANTRCVMORE) { 1091114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 1092114878Sjulian"%s: L2CAP connection has been terminated, so=%p, so_state=%#x, so_count=%d, " \ 1093114878Sjulian"state=%d, flags=%#x\n", __func__, s->l2so, s->l2so->so_state, 1094114878Sjulian s->l2so->so_count, s->state, s->flags); 1095114878Sjulian 1096114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 1097114878Sjulian ng_btsocket_rfcomm_session_clean(s); 1098114878Sjulian } 1099114878Sjulian 1100114878Sjulian /* Now process upcall */ 1101114878Sjulian switch (s->state) { 1102114878Sjulian /* Try to accept new L2CAP connection(s) */ 1103114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_LISTENING: 1104114878Sjulian while (ng_btsocket_rfcomm_session_accept(s) == 0) 1105114878Sjulian ; 1106114878Sjulian break; 1107114878Sjulian 1108114878Sjulian /* Process the results of the L2CAP connect */ 1109114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CONNECTING: 1110114878Sjulian ng_btsocket_rfcomm_session_process_pcb(s); 1111114878Sjulian 1112114878Sjulian if (ng_btsocket_rfcomm_session_connect(s) != 0) { 1113114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 1114114878Sjulian ng_btsocket_rfcomm_session_clean(s); 1115114878Sjulian } 1116114878Sjulian break; 1117114878Sjulian 1118114878Sjulian /* Try to receive/send more data */ 1119114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED: 1120114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_OPEN: 1121114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING: 1122114878Sjulian ng_btsocket_rfcomm_session_process_pcb(s); 1123114878Sjulian 1124114878Sjulian if (ng_btsocket_rfcomm_session_receive(s) != 0) { 1125114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 1126114878Sjulian ng_btsocket_rfcomm_session_clean(s); 1127114878Sjulian } else if (ng_btsocket_rfcomm_session_send(s) != 0) { 1128114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 1129114878Sjulian ng_btsocket_rfcomm_session_clean(s); 1130114878Sjulian } 1131114878Sjulian break; 1132114878Sjulian 1133114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CLOSED: 1134114878Sjulian break; 1135114878Sjulian 1136114878Sjulian default: 1137114878Sjulian panic("%s: Invalid session state=%d, flags=%#x\n", 1138114878Sjulian __func__, s->state, s->flags); 1139114878Sjulian break; 1140114878Sjulian } 1141114878Sjulian} /* ng_btsocket_rfcomm_session_task */ 1142114878Sjulian 1143114878Sjulian/* 1144114878Sjulian * Process RFCOMM connection indicator. Caller must hold s->session_mtx 1145114878Sjulian */ 1146114878Sjulian 1147114878Sjulianstatic ng_btsocket_rfcomm_pcb_p 1148114878Sjulianng_btsocket_rfcomm_connect_ind(ng_btsocket_rfcomm_session_p s, int channel) 1149114878Sjulian{ 1150114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb1 = NULL; 1151114878Sjulian ng_btsocket_l2cap_pcb_p l2pcb = NULL; 1152114878Sjulian struct socket *so1 = NULL; 1153114878Sjulian 1154114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1155114878Sjulian 1156114878Sjulian /* 1157114878Sjulian * Try to find RFCOMM socket that listens on given source address 1158114878Sjulian * and channel. This will return the best possible match. 1159114878Sjulian */ 1160114878Sjulian 1161114878Sjulian l2pcb = so2l2cap_pcb(s->l2so); 1162114878Sjulian pcb = ng_btsocket_rfcomm_pcb_listener(&l2pcb->src, channel); 1163114878Sjulian if (pcb == NULL) 1164114878Sjulian return (NULL); 1165114878Sjulian 1166114878Sjulian /* 1167114878Sjulian * Check the pending connections queue and if we have space then 1168114878Sjulian * create new socket and set proper source and destination address, 1169114878Sjulian * and channel. 1170114878Sjulian */ 1171114878Sjulian 1172114878Sjulian mtx_lock(&pcb->pcb_mtx); 1173114878Sjulian 1174218757Sbz if (pcb->so->so_qlen <= pcb->so->so_qlimit) { 1175218757Sbz CURVNET_SET(pcb->so->so_vnet); 1176114878Sjulian so1 = sonewconn(pcb->so, 0); 1177218757Sbz CURVNET_RESTORE(); 1178218757Sbz } 1179114878Sjulian 1180114878Sjulian mtx_unlock(&pcb->pcb_mtx); 1181114878Sjulian 1182114878Sjulian if (so1 == NULL) 1183114878Sjulian return (NULL); 1184114878Sjulian 1185114878Sjulian /* 1186114878Sjulian * If we got here than we have created new socket. So complete the 1187114878Sjulian * connection. Set source and destination address from the session. 1188114878Sjulian */ 1189114878Sjulian 1190114878Sjulian pcb1 = so2rfcomm_pcb(so1); 1191114878Sjulian if (pcb1 == NULL) 1192114878Sjulian panic("%s: pcb1 == NULL\n", __func__); 1193114878Sjulian 1194114878Sjulian mtx_lock(&pcb1->pcb_mtx); 1195114878Sjulian 1196114878Sjulian bcopy(&l2pcb->src, &pcb1->src, sizeof(pcb1->src)); 1197114878Sjulian bcopy(&l2pcb->dst, &pcb1->dst, sizeof(pcb1->dst)); 1198114878Sjulian pcb1->channel = channel; 1199114878Sjulian 1200114878Sjulian /* Link new DLC to the session. We already hold s->session_mtx */ 1201114878Sjulian LIST_INSERT_HEAD(&s->dlcs, pcb1, session_next); 1202114878Sjulian pcb1->session = s; 1203114878Sjulian 1204114878Sjulian mtx_unlock(&pcb1->pcb_mtx); 1205114878Sjulian 1206114878Sjulian return (pcb1); 1207114878Sjulian} /* ng_btsocket_rfcomm_connect_ind */ 1208114878Sjulian 1209114878Sjulian/* 1210114878Sjulian * Process RFCOMM connect confirmation. Caller must hold s->session_mtx. 1211114878Sjulian */ 1212114878Sjulian 1213114878Sjulianstatic void 1214114878Sjulianng_btsocket_rfcomm_connect_cfm(ng_btsocket_rfcomm_session_p s) 1215114878Sjulian{ 1216161623Semax ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb_next = NULL; 1217161623Semax int error; 1218114878Sjulian 1219114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1220114878Sjulian 1221114878Sjulian /* 1222114878Sjulian * Wake up all waiting sockets and send PN request for each of them. 1223114878Sjulian * Note that timeout already been set in ng_btsocket_rfcomm_connect() 1224114878Sjulian * 1225114878Sjulian * Note: cannot use LIST_FOREACH because ng_btsocket_rfcomm_pcb_kill 1226114878Sjulian * will unlink DLC from the session 1227114878Sjulian */ 1228114878Sjulian 1229114878Sjulian for (pcb = LIST_FIRST(&s->dlcs); pcb != NULL; ) { 1230114878Sjulian mtx_lock(&pcb->pcb_mtx); 1231114878Sjulian pcb_next = LIST_NEXT(pcb, session_next); 1232114878Sjulian 1233114878Sjulian if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT) { 1234114878Sjulian pcb->mtu = s->mtu; 1235114878Sjulian bcopy(&so2l2cap_pcb(s->l2so)->src, &pcb->src, 1236114878Sjulian sizeof(pcb->src)); 1237114878Sjulian 1238114878Sjulian error = ng_btsocket_rfcomm_send_pn(pcb); 1239114878Sjulian if (error == 0) 1240114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONFIGURING; 1241161623Semax else 1242161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, error); 1243114878Sjulian } 1244114878Sjulian 1245114878Sjulian mtx_unlock(&pcb->pcb_mtx); 1246114878Sjulian pcb = pcb_next; 1247114878Sjulian } 1248114878Sjulian} /* ng_btsocket_rfcomm_connect_cfm */ 1249114878Sjulian 1250114878Sjulian/***************************************************************************** 1251114878Sjulian ***************************************************************************** 1252114878Sjulian ** RFCOMM sessions 1253114878Sjulian ***************************************************************************** 1254114878Sjulian *****************************************************************************/ 1255114878Sjulian 1256114878Sjulian/* 1257114878Sjulian * Create new RFCOMM session. That function WILL NOT take ownership over l2so. 1258114878Sjulian * Caller MUST free l2so if function failed. 1259114878Sjulian */ 1260114878Sjulian 1261114878Sjulianstatic int 1262114878Sjulianng_btsocket_rfcomm_session_create(ng_btsocket_rfcomm_session_p *sp, 1263114878Sjulian struct socket *l2so, bdaddr_p src, bdaddr_p dst, 1264114878Sjulian struct thread *td) 1265114878Sjulian{ 1266114878Sjulian ng_btsocket_rfcomm_session_p s = NULL; 1267114878Sjulian struct sockaddr_l2cap l2sa; 1268114878Sjulian struct sockopt l2sopt; 1269161579Semax int error; 1270161579Semax u_int16_t mtu; 1271114878Sjulian 1272114878Sjulian mtx_assert(&ng_btsocket_rfcomm_sessions_mtx, MA_OWNED); 1273114878Sjulian 1274114878Sjulian /* Allocate the RFCOMM session */ 1275184205Sdes s = malloc(sizeof(*s), 1276114878Sjulian M_NETGRAPH_BTSOCKET_RFCOMM, M_NOWAIT | M_ZERO); 1277114878Sjulian if (s == NULL) 1278114878Sjulian return (ENOMEM); 1279114878Sjulian 1280114878Sjulian /* Set defaults */ 1281114878Sjulian s->mtu = RFCOMM_DEFAULT_MTU; 1282114878Sjulian s->flags = 0; 1283114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 1284114878Sjulian NG_BT_MBUFQ_INIT(&s->outq, ifqmaxlen); 1285114878Sjulian 1286114878Sjulian /* 1287114878Sjulian * XXX Mark session mutex as DUPOK to prevent "duplicated lock of 1288114878Sjulian * the same type" message. When accepting new L2CAP connection 1289114878Sjulian * ng_btsocket_rfcomm_session_accept() holds both session mutexes 1290114878Sjulian * for "old" (accepting) session and "new" (created) session. 1291114878Sjulian */ 1292114878Sjulian 1293114878Sjulian mtx_init(&s->session_mtx, "btsocks_rfcomm_session_mtx", NULL, 1294114878Sjulian MTX_DEF|MTX_DUPOK); 1295114878Sjulian 1296114878Sjulian LIST_INIT(&s->dlcs); 1297114878Sjulian 1298114878Sjulian /* Prepare L2CAP socket */ 1299130653Srwatson SOCKBUF_LOCK(&l2so->so_rcv); 1300193272Sjhb soupcall_set(l2so, SO_RCV, ng_btsocket_rfcomm_upcall, NULL); 1301130653Srwatson SOCKBUF_UNLOCK(&l2so->so_rcv); 1302130653Srwatson SOCKBUF_LOCK(&l2so->so_snd); 1303193272Sjhb soupcall_set(l2so, SO_SND, ng_btsocket_rfcomm_upcall, NULL); 1304130653Srwatson SOCKBUF_UNLOCK(&l2so->so_snd); 1305114878Sjulian l2so->so_state |= SS_NBIO; 1306114878Sjulian s->l2so = l2so; 1307114878Sjulian 1308114878Sjulian mtx_lock(&s->session_mtx); 1309114878Sjulian 1310114878Sjulian /* 1311114878Sjulian * "src" == NULL and "dst" == NULL means just create session. 1312114878Sjulian * caller must do the rest 1313114878Sjulian */ 1314114878Sjulian 1315114878Sjulian if (src == NULL && dst == NULL) 1316114878Sjulian goto done; 1317114878Sjulian 1318114878Sjulian /* 1319114878Sjulian * Set incoming MTU on L2CAP socket. It is RFCOMM session default MTU 1320114878Sjulian * plus 5 bytes: RFCOMM frame header, one extra byte for length and one 1321114878Sjulian * extra byte for credits. 1322114878Sjulian */ 1323114878Sjulian 1324114878Sjulian mtu = s->mtu + sizeof(struct rfcomm_frame_hdr) + 1 + 1; 1325114878Sjulian 1326114878Sjulian l2sopt.sopt_dir = SOPT_SET; 1327114878Sjulian l2sopt.sopt_level = SOL_L2CAP; 1328114878Sjulian l2sopt.sopt_name = SO_L2CAP_IMTU; 1329114878Sjulian l2sopt.sopt_val = (void *) &mtu; 1330114878Sjulian l2sopt.sopt_valsize = sizeof(mtu); 1331114878Sjulian l2sopt.sopt_td = NULL; 1332114878Sjulian 1333114878Sjulian error = sosetopt(s->l2so, &l2sopt); 1334114878Sjulian if (error != 0) 1335114878Sjulian goto bad; 1336114878Sjulian 1337114878Sjulian /* Bind socket to "src" address */ 1338114878Sjulian l2sa.l2cap_len = sizeof(l2sa); 1339114878Sjulian l2sa.l2cap_family = AF_BLUETOOTH; 1340114878Sjulian l2sa.l2cap_psm = (dst == NULL)? htole16(NG_L2CAP_PSM_RFCOMM) : 0; 1341114878Sjulian bcopy(src, &l2sa.l2cap_bdaddr, sizeof(l2sa.l2cap_bdaddr)); 1342114878Sjulian 1343114878Sjulian error = sobind(s->l2so, (struct sockaddr *) &l2sa, td); 1344114878Sjulian if (error != 0) 1345114878Sjulian goto bad; 1346114878Sjulian 1347114878Sjulian /* If "dst" is not NULL then initiate connect(), otherwise listen() */ 1348114878Sjulian if (dst == NULL) { 1349114878Sjulian s->flags = 0; 1350114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_LISTENING; 1351114878Sjulian 1352114878Sjulian error = solisten(s->l2so, 10, td); 1353114878Sjulian if (error != 0) 1354114878Sjulian goto bad; 1355114878Sjulian } else { 1356114878Sjulian s->flags = NG_BTSOCKET_RFCOMM_SESSION_INITIATOR; 1357114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CONNECTING; 1358114878Sjulian 1359114878Sjulian l2sa.l2cap_len = sizeof(l2sa); 1360114878Sjulian l2sa.l2cap_family = AF_BLUETOOTH; 1361114878Sjulian l2sa.l2cap_psm = htole16(NG_L2CAP_PSM_RFCOMM); 1362114878Sjulian bcopy(dst, &l2sa.l2cap_bdaddr, sizeof(l2sa.l2cap_bdaddr)); 1363114878Sjulian 1364114878Sjulian error = soconnect(s->l2so, (struct sockaddr *) &l2sa, td); 1365114878Sjulian if (error != 0) 1366114878Sjulian goto bad; 1367114878Sjulian } 1368114878Sjulian 1369114878Sjuliandone: 1370114878Sjulian LIST_INSERT_HEAD(&ng_btsocket_rfcomm_sessions, s, next); 1371114878Sjulian *sp = s; 1372114878Sjulian 1373114878Sjulian mtx_unlock(&s->session_mtx); 1374114878Sjulian 1375114878Sjulian return (0); 1376114878Sjulian 1377114878Sjulianbad: 1378114878Sjulian mtx_unlock(&s->session_mtx); 1379114878Sjulian 1380114878Sjulian /* Return L2CAP socket back to its original state */ 1381130653Srwatson SOCKBUF_LOCK(&l2so->so_rcv); 1382193272Sjhb soupcall_clear(s->l2so, SO_RCV); 1383130670Srwatson SOCKBUF_UNLOCK(&l2so->so_rcv); 1384130653Srwatson SOCKBUF_LOCK(&l2so->so_snd); 1385193272Sjhb soupcall_clear(s->l2so, SO_SND); 1386130670Srwatson SOCKBUF_UNLOCK(&l2so->so_snd); 1387114878Sjulian l2so->so_state &= ~SS_NBIO; 1388114878Sjulian 1389114878Sjulian mtx_destroy(&s->session_mtx); 1390114878Sjulian bzero(s, sizeof(*s)); 1391184205Sdes free(s, M_NETGRAPH_BTSOCKET_RFCOMM); 1392114878Sjulian 1393114878Sjulian return (error); 1394114878Sjulian} /* ng_btsocket_rfcomm_session_create */ 1395114878Sjulian 1396114878Sjulian/* 1397114878Sjulian * Process accept() on RFCOMM session 1398114878Sjulian * XXX FIXME locking for "l2so"? 1399114878Sjulian */ 1400114878Sjulian 1401114878Sjulianstatic int 1402114878Sjulianng_btsocket_rfcomm_session_accept(ng_btsocket_rfcomm_session_p s0) 1403114878Sjulian{ 1404114878Sjulian struct socket *l2so = NULL; 1405114878Sjulian struct sockaddr_l2cap *l2sa = NULL; 1406114878Sjulian ng_btsocket_l2cap_pcb_t *l2pcb = NULL; 1407114878Sjulian ng_btsocket_rfcomm_session_p s = NULL; 1408114878Sjulian int error = 0; 1409114878Sjulian 1410114878Sjulian mtx_assert(&ng_btsocket_rfcomm_sessions_mtx, MA_OWNED); 1411114878Sjulian mtx_assert(&s0->session_mtx, MA_OWNED); 1412114878Sjulian 1413114878Sjulian /* Check if there is a complete L2CAP connection in the queue */ 1414114878Sjulian if ((error = s0->l2so->so_error) != 0) { 1415114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1416114878Sjulian"%s: Could not accept connection on L2CAP socket, error=%d\n", __func__, error); 1417114878Sjulian s0->l2so->so_error = 0; 1418114878Sjulian 1419114878Sjulian return (error); 1420114878Sjulian } 1421114878Sjulian 1422129979Srwatson ACCEPT_LOCK(); 1423114878Sjulian if (TAILQ_EMPTY(&s0->l2so->so_comp)) { 1424129979Srwatson ACCEPT_UNLOCK(); 1425130480Srwatson if (s0->l2so->so_rcv.sb_state & SBS_CANTRCVMORE) 1426114878Sjulian return (ECONNABORTED); 1427114878Sjulian return (EWOULDBLOCK); 1428114878Sjulian } 1429114878Sjulian 1430114878Sjulian /* Accept incoming L2CAP connection */ 1431114878Sjulian l2so = TAILQ_FIRST(&s0->l2so->so_comp); 1432114878Sjulian if (l2so == NULL) 1433114878Sjulian panic("%s: l2so == NULL\n", __func__); 1434114878Sjulian 1435114878Sjulian TAILQ_REMOVE(&s0->l2so->so_comp, l2so, so_list); 1436114878Sjulian s0->l2so->so_qlen --; 1437129979Srwatson l2so->so_qstate &= ~SQ_COMP; 1438129979Srwatson l2so->so_head = NULL; 1439130387Srwatson SOCK_LOCK(l2so); 1440114878Sjulian soref(l2so); 1441114878Sjulian l2so->so_state |= SS_NBIO; 1442130387Srwatson SOCK_UNLOCK(l2so); 1443129979Srwatson ACCEPT_UNLOCK(); 1444114878Sjulian 1445114878Sjulian error = soaccept(l2so, (struct sockaddr **) &l2sa); 1446114878Sjulian if (error != 0) { 1447114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1448114878Sjulian"%s: soaccept() on L2CAP socket failed, error=%d\n", __func__, error); 1449114878Sjulian soclose(l2so); 1450114878Sjulian 1451114878Sjulian return (error); 1452114878Sjulian } 1453114878Sjulian 1454114878Sjulian /* 1455114878Sjulian * Check if there is already active RFCOMM session between two devices. 1456114878Sjulian * If so then close L2CAP connection. We only support one RFCOMM session 1457114878Sjulian * between each pair of devices. Note that here we assume session in any 1458114878Sjulian * state. The session even could be in the middle of disconnecting. 1459114878Sjulian */ 1460114878Sjulian 1461114878Sjulian l2pcb = so2l2cap_pcb(l2so); 1462114878Sjulian s = ng_btsocket_rfcomm_session_by_addr(&l2pcb->src, &l2pcb->dst); 1463114878Sjulian if (s == NULL) { 1464114878Sjulian /* Create a new RFCOMM session */ 1465114878Sjulian error = ng_btsocket_rfcomm_session_create(&s, l2so, NULL, NULL, 1466114878Sjulian curthread /* XXX */); 1467114878Sjulian if (error == 0) { 1468114878Sjulian mtx_lock(&s->session_mtx); 1469114878Sjulian 1470114878Sjulian s->flags = 0; 1471114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CONNECTED; 1472114878Sjulian 1473114878Sjulian /* 1474114878Sjulian * Adjust MTU on incomming connection. Reserve 5 bytes: 1475114878Sjulian * RFCOMM frame header, one extra byte for length and 1476114878Sjulian * one extra byte for credits. 1477114878Sjulian */ 1478114878Sjulian 1479114878Sjulian s->mtu = min(l2pcb->imtu, l2pcb->omtu) - 1480114878Sjulian sizeof(struct rfcomm_frame_hdr) - 1 - 1; 1481114878Sjulian 1482114878Sjulian mtx_unlock(&s->session_mtx); 1483114878Sjulian } else { 1484114878Sjulian NG_BTSOCKET_RFCOMM_ALERT( 1485114878Sjulian"%s: Failed to create new RFCOMM session, error=%d\n", __func__, error); 1486114878Sjulian 1487114878Sjulian soclose(l2so); 1488114878Sjulian } 1489114878Sjulian } else { 1490114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 1491114878Sjulian"%s: Rejecting duplicating RFCOMM session between src=%x:%x:%x:%x:%x:%x and " \ 1492114878Sjulian"dst=%x:%x:%x:%x:%x:%x, state=%d, flags=%#x\n", __func__, 1493114878Sjulian l2pcb->src.b[5], l2pcb->src.b[4], l2pcb->src.b[3], 1494114878Sjulian l2pcb->src.b[2], l2pcb->src.b[1], l2pcb->src.b[0], 1495114878Sjulian l2pcb->dst.b[5], l2pcb->dst.b[4], l2pcb->dst.b[3], 1496114878Sjulian l2pcb->dst.b[2], l2pcb->dst.b[1], l2pcb->dst.b[0], 1497114878Sjulian s->state, s->flags); 1498114878Sjulian 1499114878Sjulian error = EBUSY; 1500114878Sjulian soclose(l2so); 1501114878Sjulian } 1502114878Sjulian 1503114878Sjulian return (error); 1504114878Sjulian} /* ng_btsocket_rfcomm_session_accept */ 1505114878Sjulian 1506114878Sjulian/* 1507114878Sjulian * Process connect() on RFCOMM session 1508114878Sjulian * XXX FIXME locking for "l2so"? 1509114878Sjulian */ 1510114878Sjulian 1511114878Sjulianstatic int 1512114878Sjulianng_btsocket_rfcomm_session_connect(ng_btsocket_rfcomm_session_p s) 1513114878Sjulian{ 1514114878Sjulian ng_btsocket_l2cap_pcb_p l2pcb = so2l2cap_pcb(s->l2so); 1515114878Sjulian int error; 1516114878Sjulian 1517114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1518114878Sjulian 1519114878Sjulian /* First check if connection has failed */ 1520114878Sjulian if ((error = s->l2so->so_error) != 0) { 1521114878Sjulian s->l2so->so_error = 0; 1522114878Sjulian 1523114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1524114878Sjulian"%s: Could not connect RFCOMM session, error=%d, state=%d, flags=%#x\n", 1525114878Sjulian __func__, error, s->state, s->flags); 1526114878Sjulian 1527114878Sjulian return (error); 1528114878Sjulian } 1529114878Sjulian 1530114878Sjulian /* Is connection still in progress? */ 1531114878Sjulian if (s->l2so->so_state & SS_ISCONNECTING) 1532114878Sjulian return (0); 1533114878Sjulian 1534114878Sjulian /* 1535114878Sjulian * If we got here then we are connected. Send SABM on DLCI 0 to 1536114878Sjulian * open multiplexor channel. 1537114878Sjulian */ 1538114878Sjulian 1539114878Sjulian if (error == 0) { 1540114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CONNECTED; 1541114878Sjulian 1542114878Sjulian /* 1543114878Sjulian * Adjust MTU on outgoing connection. Reserve 5 bytes: RFCOMM 1544114878Sjulian * frame header, one extra byte for length and one extra byte 1545114878Sjulian * for credits. 1546114878Sjulian */ 1547114878Sjulian 1548114878Sjulian s->mtu = min(l2pcb->imtu, l2pcb->omtu) - 1549114878Sjulian sizeof(struct rfcomm_frame_hdr) - 1 - 1; 1550114878Sjulian 1551114878Sjulian error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_SABM,0); 1552114878Sjulian if (error == 0) 1553114878Sjulian error = ng_btsocket_rfcomm_task_wakeup(); 1554114878Sjulian } 1555114878Sjulian 1556114878Sjulian return (error); 1557114878Sjulian}/* ng_btsocket_rfcomm_session_connect */ 1558114878Sjulian 1559114878Sjulian/* 1560114878Sjulian * Receive data on RFCOMM session 1561114878Sjulian * XXX FIXME locking for "l2so"? 1562114878Sjulian */ 1563114878Sjulian 1564114878Sjulianstatic int 1565114878Sjulianng_btsocket_rfcomm_session_receive(ng_btsocket_rfcomm_session_p s) 1566114878Sjulian{ 1567114878Sjulian struct mbuf *m = NULL; 1568114878Sjulian struct uio uio; 1569114878Sjulian int more, flags, error; 1570114878Sjulian 1571114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1572114878Sjulian 1573114878Sjulian /* Can we read from the L2CAP socket? */ 1574114878Sjulian if (!soreadable(s->l2so)) 1575114878Sjulian return (0); 1576114878Sjulian 1577114878Sjulian /* First check for error on L2CAP socket */ 1578114878Sjulian if ((error = s->l2so->so_error) != 0) { 1579114878Sjulian s->l2so->so_error = 0; 1580114878Sjulian 1581114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1582114878Sjulian"%s: Could not receive data from L2CAP socket, error=%d, state=%d, flags=%#x\n", 1583114878Sjulian __func__, error, s->state, s->flags); 1584114878Sjulian 1585114878Sjulian return (error); 1586114878Sjulian } 1587114878Sjulian 1588114878Sjulian /* 1589114878Sjulian * Read all packets from the L2CAP socket. 1590114878Sjulian * XXX FIXME/VERIFY is that correct? For now use m->m_nextpkt as 1591114878Sjulian * indication that there is more packets on the socket's buffer. 1592114878Sjulian * Also what should we use in uio.uio_resid? 1593114878Sjulian * May be s->mtu + sizeof(struct rfcomm_frame_hdr) + 1 + 1? 1594114878Sjulian */ 1595114878Sjulian 1596114878Sjulian for (more = 1; more; ) { 1597114878Sjulian /* Try to get next packet from socket */ 1598114878Sjulian bzero(&uio, sizeof(uio)); 1599114878Sjulian/* uio.uio_td = NULL; */ 1600114878Sjulian uio.uio_resid = 1000000000; 1601114878Sjulian flags = MSG_DONTWAIT; 1602114878Sjulian 1603114878Sjulian m = NULL; 1604160619Srwatson error = soreceive(s->l2so, NULL, &uio, &m, 1605160619Srwatson (struct mbuf **) NULL, &flags); 1606114878Sjulian if (error != 0) { 1607114878Sjulian if (error == EWOULDBLOCK) 1608114878Sjulian return (0); /* XXX can happen? */ 1609114878Sjulian 1610114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1611114878Sjulian"%s: Could not receive data from L2CAP socket, error=%d\n", __func__, error); 1612114878Sjulian 1613114878Sjulian return (error); 1614114878Sjulian } 1615114878Sjulian 1616114878Sjulian more = (m->m_nextpkt != NULL); 1617114878Sjulian m->m_nextpkt = NULL; 1618114878Sjulian 1619114878Sjulian ng_btsocket_rfcomm_receive_frame(s, m); 1620114878Sjulian } 1621114878Sjulian 1622114878Sjulian return (0); 1623114878Sjulian} /* ng_btsocket_rfcomm_session_receive */ 1624114878Sjulian 1625114878Sjulian/* 1626114878Sjulian * Send data on RFCOMM session 1627114878Sjulian * XXX FIXME locking for "l2so"? 1628114878Sjulian */ 1629114878Sjulian 1630114878Sjulianstatic int 1631114878Sjulianng_btsocket_rfcomm_session_send(ng_btsocket_rfcomm_session_p s) 1632114878Sjulian{ 1633114878Sjulian struct mbuf *m = NULL; 1634114878Sjulian int error; 1635114878Sjulian 1636114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1637114878Sjulian 1638114878Sjulian /* Send as much as we can from the session queue */ 1639114878Sjulian while (sowriteable(s->l2so)) { 1640114878Sjulian /* Check if socket still OK */ 1641114878Sjulian if ((error = s->l2so->so_error) != 0) { 1642114878Sjulian s->l2so->so_error = 0; 1643114878Sjulian 1644114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1645114878Sjulian"%s: Detected error=%d on L2CAP socket, state=%d, flags=%#x\n", 1646114878Sjulian __func__, error, s->state, s->flags); 1647114878Sjulian 1648114878Sjulian return (error); 1649114878Sjulian } 1650114878Sjulian 1651114878Sjulian NG_BT_MBUFQ_DEQUEUE(&s->outq, m); 1652114878Sjulian if (m == NULL) 1653114878Sjulian return (0); /* we are done */ 1654114878Sjulian 1655114878Sjulian /* Call send function on the L2CAP socket */ 1656170972Semax error = (*s->l2so->so_proto->pr_usrreqs->pru_send)(s->l2so, 1657170972Semax 0, m, NULL, NULL, curthread /* XXX */); 1658114878Sjulian if (error != 0) { 1659114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1660114878Sjulian"%s: Could not send data to L2CAP socket, error=%d\n", __func__, error); 1661114878Sjulian 1662114878Sjulian return (error); 1663114878Sjulian } 1664114878Sjulian } 1665114878Sjulian 1666114878Sjulian return (0); 1667114878Sjulian} /* ng_btsocket_rfcomm_session_send */ 1668114878Sjulian 1669114878Sjulian/* 1670114878Sjulian * Close and disconnect all DLCs for the given session. Caller must hold 1671114878Sjulian * s->sesson_mtx. Will wakeup session. 1672114878Sjulian */ 1673114878Sjulian 1674114878Sjulianstatic void 1675114878Sjulianng_btsocket_rfcomm_session_clean(ng_btsocket_rfcomm_session_p s) 1676114878Sjulian{ 1677161623Semax ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb_next = NULL; 1678161623Semax int error; 1679114878Sjulian 1680114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1681114878Sjulian 1682114878Sjulian /* 1683114878Sjulian * Note: cannot use LIST_FOREACH because ng_btsocket_rfcomm_pcb_kill 1684114878Sjulian * will unlink DLC from the session 1685114878Sjulian */ 1686114878Sjulian 1687114878Sjulian for (pcb = LIST_FIRST(&s->dlcs); pcb != NULL; ) { 1688114878Sjulian mtx_lock(&pcb->pcb_mtx); 1689114878Sjulian pcb_next = LIST_NEXT(pcb, session_next); 1690114878Sjulian 1691114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 1692114878Sjulian"%s: Disconnecting dlci=%d, state=%d, flags=%#x\n", 1693114878Sjulian __func__, pcb->dlci, pcb->state, pcb->flags); 1694114878Sjulian 1695114878Sjulian if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONNECTED) 1696114878Sjulian error = ECONNRESET; 1697114878Sjulian else 1698114878Sjulian error = ECONNREFUSED; 1699114878Sjulian 1700161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, error); 1701114878Sjulian 1702114878Sjulian mtx_unlock(&pcb->pcb_mtx); 1703114878Sjulian pcb = pcb_next; 1704114878Sjulian } 1705114878Sjulian} /* ng_btsocket_rfcomm_session_clean */ 1706114878Sjulian 1707114878Sjulian/* 1708114878Sjulian * Process all DLCs on the session. Caller MUST hold s->session_mtx. 1709114878Sjulian */ 1710114878Sjulian 1711114878Sjulianstatic void 1712114878Sjulianng_btsocket_rfcomm_session_process_pcb(ng_btsocket_rfcomm_session_p s) 1713114878Sjulian{ 1714161623Semax ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb_next = NULL; 1715161623Semax int error; 1716114878Sjulian 1717114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1718114878Sjulian 1719114878Sjulian /* 1720114878Sjulian * Note: cannot use LIST_FOREACH because ng_btsocket_rfcomm_pcb_kill 1721114878Sjulian * will unlink DLC from the session 1722114878Sjulian */ 1723114878Sjulian 1724114878Sjulian for (pcb = LIST_FIRST(&s->dlcs); pcb != NULL; ) { 1725114878Sjulian mtx_lock(&pcb->pcb_mtx); 1726114878Sjulian pcb_next = LIST_NEXT(pcb, session_next); 1727114878Sjulian 1728114878Sjulian switch (pcb->state) { 1729114878Sjulian 1730114878Sjulian /* 1731114878Sjulian * If DLC in W4_CONNECT state then we should check for both 1732114878Sjulian * timeout and detach. 1733114878Sjulian */ 1734114878Sjulian 1735114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT: 1736161623Semax if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_DETACHED) 1737161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, 0); 1738161623Semax else if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT) 1739161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, ETIMEDOUT); 1740114878Sjulian break; 1741114878Sjulian 1742114878Sjulian /* 1743114878Sjulian * If DLC in CONFIGURING or CONNECTING state then we only 1744114878Sjulian * should check for timeout. If detach() was called then 1745114878Sjulian * DLC will be moved into DISCONNECTING state. 1746114878Sjulian */ 1747114878Sjulian 1748114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING: 1749114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONNECTING: 1750114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT) 1751161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, ETIMEDOUT); 1752114878Sjulian break; 1753114878Sjulian 1754114878Sjulian /* 1755114878Sjulian * If DLC in CONNECTED state then we need to send data (if any) 1756114878Sjulian * from the socket's send queue. Note that we will send data 1757114878Sjulian * from either all sockets or none. This may overload session's 1758114878Sjulian * outgoing queue (but we do not check for that). 1759114878Sjulian * 1760114878Sjulian * XXX FIXME need scheduler for RFCOMM sockets 1761114878Sjulian */ 1762114878Sjulian 1763114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONNECTED: 1764114878Sjulian error = ng_btsocket_rfcomm_pcb_send(pcb, ALOT); 1765114878Sjulian if (error != 0) 1766161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, error); 1767114878Sjulian break; 1768114878Sjulian 1769114878Sjulian /* 1770114878Sjulian * If DLC in DISCONNECTING state then we must send DISC frame. 1771114878Sjulian * Note that if DLC has timeout set then we do not need to 1772114878Sjulian * resend DISC frame. 1773114878Sjulian * 1774114878Sjulian * XXX FIXME need to drain all data from the socket's queue 1775114878Sjulian * if LINGER option was set 1776114878Sjulian */ 1777114878Sjulian 1778114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING: 1779114878Sjulian if (!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)) { 1780114878Sjulian error = ng_btsocket_rfcomm_send_command( 1781114878Sjulian pcb->session, RFCOMM_FRAME_DISC, 1782114878Sjulian pcb->dlci); 1783114878Sjulian if (error == 0) 1784114878Sjulian ng_btsocket_rfcomm_timeout(pcb); 1785161623Semax else 1786161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, error); 1787114878Sjulian } else if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT) 1788161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, ETIMEDOUT); 1789114878Sjulian break; 1790114878Sjulian 1791114878Sjulian/* case NG_BTSOCKET_RFCOMM_DLC_CLOSED: */ 1792114878Sjulian default: 1793114878Sjulian panic("%s: Invalid DLC state=%d, flags=%#x\n", 1794114878Sjulian __func__, pcb->state, pcb->flags); 1795114878Sjulian break; 1796114878Sjulian } 1797114878Sjulian 1798114878Sjulian mtx_unlock(&pcb->pcb_mtx); 1799114878Sjulian pcb = pcb_next; 1800114878Sjulian } 1801114878Sjulian} /* ng_btsocket_rfcomm_session_process_pcb */ 1802114878Sjulian 1803114878Sjulian/* 1804114878Sjulian * Find RFCOMM session between "src" and "dst". 1805114878Sjulian * Caller MUST hold ng_btsocket_rfcomm_sessions_mtx. 1806114878Sjulian */ 1807114878Sjulian 1808114878Sjulianstatic ng_btsocket_rfcomm_session_p 1809114878Sjulianng_btsocket_rfcomm_session_by_addr(bdaddr_p src, bdaddr_p dst) 1810114878Sjulian{ 1811114878Sjulian ng_btsocket_rfcomm_session_p s = NULL; 1812114878Sjulian ng_btsocket_l2cap_pcb_p l2pcb = NULL; 1813114878Sjulian int any_src; 1814114878Sjulian 1815114878Sjulian mtx_assert(&ng_btsocket_rfcomm_sessions_mtx, MA_OWNED); 1816114878Sjulian 1817114878Sjulian any_src = (bcmp(src, NG_HCI_BDADDR_ANY, sizeof(*src)) == 0); 1818114878Sjulian 1819114878Sjulian LIST_FOREACH(s, &ng_btsocket_rfcomm_sessions, next) { 1820114878Sjulian l2pcb = so2l2cap_pcb(s->l2so); 1821114878Sjulian 1822114878Sjulian if ((any_src || bcmp(&l2pcb->src, src, sizeof(*src)) == 0) && 1823114878Sjulian bcmp(&l2pcb->dst, dst, sizeof(*dst)) == 0) 1824114878Sjulian break; 1825114878Sjulian } 1826114878Sjulian 1827114878Sjulian return (s); 1828114878Sjulian} /* ng_btsocket_rfcomm_session_by_addr */ 1829114878Sjulian 1830114878Sjulian/***************************************************************************** 1831114878Sjulian ***************************************************************************** 1832114878Sjulian ** RFCOMM 1833114878Sjulian ***************************************************************************** 1834114878Sjulian *****************************************************************************/ 1835114878Sjulian 1836114878Sjulian/* 1837114878Sjulian * Process incoming RFCOMM frame. Caller must hold s->session_mtx. 1838114878Sjulian * XXX FIXME check frame length 1839114878Sjulian */ 1840114878Sjulian 1841114878Sjulianstatic int 1842114878Sjulianng_btsocket_rfcomm_receive_frame(ng_btsocket_rfcomm_session_p s, 1843114878Sjulian struct mbuf *m0) 1844114878Sjulian{ 1845114878Sjulian struct rfcomm_frame_hdr *hdr = NULL; 1846114878Sjulian struct mbuf *m = NULL; 1847114878Sjulian u_int16_t length; 1848114878Sjulian u_int8_t dlci, type; 1849114878Sjulian int error = 0; 1850114878Sjulian 1851114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1852114878Sjulian 1853114878Sjulian /* Pullup as much as we can into first mbuf (for direct access) */ 1854114878Sjulian length = min(m0->m_pkthdr.len, MHLEN); 1855114878Sjulian if (m0->m_len < length) { 1856114878Sjulian if ((m0 = m_pullup(m0, length)) == NULL) { 1857114878Sjulian NG_BTSOCKET_RFCOMM_ALERT( 1858114878Sjulian"%s: m_pullup(%d) failed\n", __func__, length); 1859114878Sjulian 1860114878Sjulian return (ENOBUFS); 1861114878Sjulian } 1862114878Sjulian } 1863114878Sjulian 1864114878Sjulian hdr = mtod(m0, struct rfcomm_frame_hdr *); 1865114878Sjulian dlci = RFCOMM_DLCI(hdr->address); 1866114878Sjulian type = RFCOMM_TYPE(hdr->control); 1867114878Sjulian 1868114878Sjulian /* Test EA bit in length. If not set then we have 2 bytes of length */ 1869114878Sjulian if (!RFCOMM_EA(hdr->length)) { 1870114878Sjulian bcopy(&hdr->length, &length, sizeof(length)); 1871144721Semax length = le16toh(length) >> 1; 1872114878Sjulian m_adj(m0, sizeof(*hdr) + 1); 1873114878Sjulian } else { 1874114878Sjulian length = hdr->length >> 1; 1875114878Sjulian m_adj(m0, sizeof(*hdr)); 1876114878Sjulian } 1877114878Sjulian 1878114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 1879114878Sjulian"%s: Got frame type=%#x, dlci=%d, length=%d, cr=%d, pf=%d, len=%d\n", 1880114878Sjulian __func__, type, dlci, length, RFCOMM_CR(hdr->address), 1881114878Sjulian RFCOMM_PF(hdr->control), m0->m_pkthdr.len); 1882114878Sjulian 1883114878Sjulian /* 1884114878Sjulian * Get FCS (the last byte in the frame) 1885114878Sjulian * XXX this will not work if mbuf chain ends with empty mbuf. 1886114878Sjulian * XXX let's hope it never happens :) 1887114878Sjulian */ 1888114878Sjulian 1889114878Sjulian for (m = m0; m->m_next != NULL; m = m->m_next) 1890114878Sjulian ; 1891114878Sjulian if (m->m_len <= 0) 1892114878Sjulian panic("%s: Empty mbuf at the end of the chain, len=%d\n", 1893114878Sjulian __func__, m->m_len); 1894114878Sjulian 1895114878Sjulian /* 1896114878Sjulian * Check FCS. We only need to calculate FCS on first 2 or 3 bytes 1897114878Sjulian * and already m_pullup'ed mbuf chain, so it should be safe. 1898114878Sjulian */ 1899114878Sjulian 1900114878Sjulian if (ng_btsocket_rfcomm_check_fcs((u_int8_t *) hdr, type, m->m_data[m->m_len - 1])) { 1901114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1902114878Sjulian"%s: Invalid RFCOMM packet. Bad checksum\n", __func__); 1903114878Sjulian NG_FREE_M(m0); 1904114878Sjulian 1905114878Sjulian return (EINVAL); 1906114878Sjulian } 1907114878Sjulian 1908114878Sjulian m_adj(m0, -1); /* Trim FCS byte */ 1909114878Sjulian 1910114878Sjulian /* 1911114878Sjulian * Process RFCOMM frame. 1912114878Sjulian * 1913114878Sjulian * From TS 07.10 spec 1914114878Sjulian * 1915114878Sjulian * "... In the case where a SABM or DISC command with the P bit set 1916114878Sjulian * to 0 is received then the received frame shall be discarded..." 1917114878Sjulian * 1918114878Sjulian * "... If a unsolicited DM response is received then the frame shall 1919114878Sjulian * be processed irrespective of the P/F setting... " 1920114878Sjulian * 1921114878Sjulian * "... The station may transmit response frames with the F bit set 1922114878Sjulian * to 0 at any opportunity on an asynchronous basis. However, in the 1923114878Sjulian * case where a UA response is received with the F bit set to 0 then 1924114878Sjulian * the received frame shall be discarded..." 1925114878Sjulian * 1926114878Sjulian * From Bluetooth spec 1927114878Sjulian * 1928114878Sjulian * "... When credit based flow control is being used, the meaning of 1929114878Sjulian * the P/F bit in the control field of the RFCOMM header is redefined 1930114878Sjulian * for UIH frames..." 1931114878Sjulian */ 1932114878Sjulian 1933114878Sjulian switch (type) { 1934114878Sjulian case RFCOMM_FRAME_SABM: 1935114878Sjulian if (RFCOMM_PF(hdr->control)) 1936114878Sjulian error = ng_btsocket_rfcomm_receive_sabm(s, dlci); 1937114878Sjulian break; 1938114878Sjulian 1939114878Sjulian case RFCOMM_FRAME_DISC: 1940114878Sjulian if (RFCOMM_PF(hdr->control)) 1941114878Sjulian error = ng_btsocket_rfcomm_receive_disc(s, dlci); 1942114878Sjulian break; 1943114878Sjulian 1944114878Sjulian case RFCOMM_FRAME_UA: 1945114878Sjulian if (RFCOMM_PF(hdr->control)) 1946114878Sjulian error = ng_btsocket_rfcomm_receive_ua(s, dlci); 1947114878Sjulian break; 1948114878Sjulian 1949114878Sjulian case RFCOMM_FRAME_DM: 1950114878Sjulian error = ng_btsocket_rfcomm_receive_dm(s, dlci); 1951114878Sjulian break; 1952114878Sjulian 1953114878Sjulian case RFCOMM_FRAME_UIH: 1954114878Sjulian if (dlci == 0) 1955114878Sjulian error = ng_btsocket_rfcomm_receive_mcc(s, m0); 1956114878Sjulian else 1957114878Sjulian error = ng_btsocket_rfcomm_receive_uih(s, dlci, 1958114878Sjulian RFCOMM_PF(hdr->control), m0); 1959114878Sjulian 1960114878Sjulian return (error); 1961114878Sjulian /* NOT REACHED */ 1962114878Sjulian 1963114878Sjulian default: 1964114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 1965114878Sjulian"%s: Invalid RFCOMM packet. Unknown type=%#x\n", __func__, type); 1966114878Sjulian error = EINVAL; 1967114878Sjulian break; 1968114878Sjulian } 1969114878Sjulian 1970114878Sjulian NG_FREE_M(m0); 1971114878Sjulian 1972114878Sjulian return (error); 1973114878Sjulian} /* ng_btsocket_rfcomm_receive_frame */ 1974114878Sjulian 1975114878Sjulian/* 1976114878Sjulian * Process RFCOMM SABM frame 1977114878Sjulian */ 1978114878Sjulian 1979114878Sjulianstatic int 1980114878Sjulianng_btsocket_rfcomm_receive_sabm(ng_btsocket_rfcomm_session_p s, int dlci) 1981114878Sjulian{ 1982161623Semax ng_btsocket_rfcomm_pcb_p pcb = NULL; 1983161623Semax int error = 0; 1984114878Sjulian 1985114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 1986114878Sjulian 1987114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 1988114878Sjulian"%s: Got SABM, session state=%d, flags=%#x, mtu=%d, dlci=%d\n", 1989114878Sjulian __func__, s->state, s->flags, s->mtu, dlci); 1990114878Sjulian 1991114878Sjulian /* DLCI == 0 means open multiplexor channel */ 1992114878Sjulian if (dlci == 0) { 1993114878Sjulian switch (s->state) { 1994114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED: 1995114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_OPEN: 1996114878Sjulian error = ng_btsocket_rfcomm_send_command(s, 1997114878Sjulian RFCOMM_FRAME_UA, dlci); 1998114878Sjulian if (error == 0) { 1999114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_OPEN; 2000114878Sjulian ng_btsocket_rfcomm_connect_cfm(s); 2001114878Sjulian } else { 2002114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 2003114878Sjulian ng_btsocket_rfcomm_session_clean(s); 2004114878Sjulian } 2005114878Sjulian break; 2006114878Sjulian 2007114878Sjulian default: 2008114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2009114878Sjulian"%s: Got SABM for session in invalid state state=%d, flags=%#x\n", 2010114878Sjulian __func__, s->state, s->flags); 2011114878Sjulian error = EINVAL; 2012114878Sjulian break; 2013114878Sjulian } 2014114878Sjulian 2015114878Sjulian return (error); 2016114878Sjulian } 2017114878Sjulian 2018114878Sjulian /* Make sure multiplexor channel is open */ 2019114878Sjulian if (s->state != NG_BTSOCKET_RFCOMM_SESSION_OPEN) { 2020114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2021114878Sjulian"%s: Got SABM for dlci=%d with mulitplexor channel closed, state=%d, " \ 2022114878Sjulian"flags=%#x\n", __func__, dlci, s->state, s->flags); 2023114878Sjulian 2024114878Sjulian return (EINVAL); 2025114878Sjulian } 2026114878Sjulian 2027114878Sjulian /* 2028114878Sjulian * Check if we have this DLCI. This might happen when remote 2029114878Sjulian * peer uses PN command before actual open (SABM) happens. 2030114878Sjulian */ 2031114878Sjulian 2032114878Sjulian pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci); 2033114878Sjulian if (pcb != NULL) { 2034114878Sjulian mtx_lock(&pcb->pcb_mtx); 2035114878Sjulian 2036114878Sjulian if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTING) { 2037114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2038114878Sjulian"%s: Got SABM for dlci=%d in invalid state=%d, flags=%#x\n", 2039114878Sjulian __func__, dlci, pcb->state, pcb->flags); 2040114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2041114878Sjulian 2042114878Sjulian return (ENOENT); 2043114878Sjulian } 2044114878Sjulian 2045114878Sjulian ng_btsocket_rfcomm_untimeout(pcb); 2046114878Sjulian 2047114878Sjulian error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_UA,dlci); 2048114878Sjulian if (error == 0) 2049114878Sjulian error = ng_btsocket_rfcomm_send_msc(pcb); 2050114878Sjulian 2051114878Sjulian if (error == 0) { 2052114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTED; 2053114878Sjulian soisconnected(pcb->so); 2054161623Semax } else 2055161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, error); 2056114878Sjulian 2057114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2058114878Sjulian 2059114878Sjulian return (error); 2060114878Sjulian } 2061114878Sjulian 2062114878Sjulian /* 2063114878Sjulian * We do not have requested DLCI, so it must be an incoming connection 2064114878Sjulian * with default parameters. Try to accept it. 2065114878Sjulian */ 2066114878Sjulian 2067114878Sjulian pcb = ng_btsocket_rfcomm_connect_ind(s, RFCOMM_SRVCHANNEL(dlci)); 2068114878Sjulian if (pcb != NULL) { 2069114878Sjulian mtx_lock(&pcb->pcb_mtx); 2070114878Sjulian 2071114878Sjulian pcb->dlci = dlci; 2072114878Sjulian 2073114878Sjulian error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_UA,dlci); 2074121054Semax if (error == 0) 2075121054Semax error = ng_btsocket_rfcomm_send_msc(pcb); 2076121054Semax 2077114878Sjulian if (error == 0) { 2078114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTED; 2079114878Sjulian soisconnected(pcb->so); 2080161623Semax } else 2081161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, error); 2082114878Sjulian 2083114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2084114878Sjulian } else 2085114878Sjulian /* Nobody is listen()ing on the requested DLCI */ 2086114878Sjulian error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_DM,dlci); 2087114878Sjulian 2088114878Sjulian return (error); 2089114878Sjulian} /* ng_btsocket_rfcomm_receive_sabm */ 2090114878Sjulian 2091114878Sjulian/* 2092114878Sjulian * Process RFCOMM DISC frame 2093114878Sjulian */ 2094114878Sjulian 2095114878Sjulianstatic int 2096114878Sjulianng_btsocket_rfcomm_receive_disc(ng_btsocket_rfcomm_session_p s, int dlci) 2097114878Sjulian{ 2098114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = NULL; 2099114878Sjulian int error = 0; 2100114878Sjulian 2101114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2102114878Sjulian 2103114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2104114878Sjulian"%s: Got DISC, session state=%d, flags=%#x, mtu=%d, dlci=%d\n", 2105114878Sjulian __func__, s->state, s->flags, s->mtu, dlci); 2106114878Sjulian 2107114878Sjulian /* DLCI == 0 means close multiplexor channel */ 2108114878Sjulian if (dlci == 0) { 2109114878Sjulian /* XXX FIXME assume that remote side will close the socket */ 2110114878Sjulian error = ng_btsocket_rfcomm_send_command(s, RFCOMM_FRAME_UA, 0); 2111128591Semax if (error == 0) { 2112128591Semax if (s->state == NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING) 2113128591Semax s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; /* XXX */ 2114128591Semax else 2115128591Semax s->state = NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING; 2116128591Semax } else 2117114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; /* XXX */ 2118114878Sjulian 2119114878Sjulian ng_btsocket_rfcomm_session_clean(s); 2120114878Sjulian } else { 2121114878Sjulian pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci); 2122114878Sjulian if (pcb != NULL) { 2123161623Semax int err; 2124114878Sjulian 2125114878Sjulian mtx_lock(&pcb->pcb_mtx); 2126114878Sjulian 2127114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2128114878Sjulian"%s: Got DISC for dlci=%d, state=%d, flags=%#x\n", 2129114878Sjulian __func__, dlci, pcb->state, pcb->flags); 2130114878Sjulian 2131114878Sjulian error = ng_btsocket_rfcomm_send_command(s, 2132114878Sjulian RFCOMM_FRAME_UA, dlci); 2133114878Sjulian 2134114878Sjulian if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONNECTED) 2135114878Sjulian err = 0; 2136114878Sjulian else 2137114878Sjulian err = ECONNREFUSED; 2138114878Sjulian 2139161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, err); 2140114878Sjulian 2141114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2142114878Sjulian } else { 2143114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2144114878Sjulian"%s: Got DISC for non-existing dlci=%d\n", __func__, dlci); 2145114878Sjulian 2146114878Sjulian error = ng_btsocket_rfcomm_send_command(s, 2147114878Sjulian RFCOMM_FRAME_DM, dlci); 2148114878Sjulian } 2149114878Sjulian } 2150114878Sjulian 2151114878Sjulian return (error); 2152114878Sjulian} /* ng_btsocket_rfcomm_receive_disc */ 2153114878Sjulian 2154114878Sjulian/* 2155114878Sjulian * Process RFCOMM UA frame 2156114878Sjulian */ 2157114878Sjulian 2158114878Sjulianstatic int 2159114878Sjulianng_btsocket_rfcomm_receive_ua(ng_btsocket_rfcomm_session_p s, int dlci) 2160114878Sjulian{ 2161114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = NULL; 2162114878Sjulian int error = 0; 2163114878Sjulian 2164114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2165114878Sjulian 2166114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2167114878Sjulian"%s: Got UA, session state=%d, flags=%#x, mtu=%d, dlci=%d\n", 2168114878Sjulian __func__, s->state, s->flags, s->mtu, dlci); 2169114878Sjulian 2170114878Sjulian /* dlci == 0 means multiplexor channel */ 2171114878Sjulian if (dlci == 0) { 2172114878Sjulian switch (s->state) { 2173114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED: 2174114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_OPEN; 2175114878Sjulian ng_btsocket_rfcomm_connect_cfm(s); 2176114878Sjulian break; 2177114878Sjulian 2178114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING: 2179114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 2180114878Sjulian ng_btsocket_rfcomm_session_clean(s); 2181114878Sjulian break; 2182114878Sjulian 2183114878Sjulian default: 2184114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2185114878Sjulian"%s: Got UA for session in invalid state=%d(%d), flags=%#x, mtu=%d\n", 2186114878Sjulian __func__, s->state, INITIATOR(s), s->flags, 2187114878Sjulian s->mtu); 2188114878Sjulian error = ENOENT; 2189114878Sjulian break; 2190114878Sjulian } 2191114878Sjulian 2192114878Sjulian return (error); 2193114878Sjulian } 2194114878Sjulian 2195114878Sjulian /* Check if we have this DLCI */ 2196114878Sjulian pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci); 2197114878Sjulian if (pcb != NULL) { 2198114878Sjulian mtx_lock(&pcb->pcb_mtx); 2199114878Sjulian 2200114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2201114878Sjulian"%s: Got UA for dlci=%d, state=%d, flags=%#x\n", 2202114878Sjulian __func__, dlci, pcb->state, pcb->flags); 2203114878Sjulian 2204114878Sjulian switch (pcb->state) { 2205114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONNECTING: 2206114878Sjulian ng_btsocket_rfcomm_untimeout(pcb); 2207114878Sjulian 2208114878Sjulian error = ng_btsocket_rfcomm_send_msc(pcb); 2209114878Sjulian if (error == 0) { 2210114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTED; 2211114878Sjulian soisconnected(pcb->so); 2212114878Sjulian } 2213114878Sjulian break; 2214114878Sjulian 2215114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING: 2216161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, 0); 2217114878Sjulian break; 2218114878Sjulian 2219114878Sjulian default: 2220114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2221114878Sjulian"%s: Got UA for dlci=%d in invalid state=%d, flags=%#x\n", 2222114878Sjulian __func__, dlci, pcb->state, pcb->flags); 2223114878Sjulian error = ENOENT; 2224114878Sjulian break; 2225114878Sjulian } 2226114878Sjulian 2227114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2228114878Sjulian } else { 2229114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2230114878Sjulian"%s: Got UA for non-existing dlci=%d\n", __func__, dlci); 2231114878Sjulian 2232114878Sjulian error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_DM,dlci); 2233114878Sjulian } 2234114878Sjulian 2235114878Sjulian return (error); 2236114878Sjulian} /* ng_btsocket_rfcomm_receive_ua */ 2237114878Sjulian 2238114878Sjulian/* 2239114878Sjulian * Process RFCOMM DM frame 2240114878Sjulian */ 2241114878Sjulian 2242114878Sjulianstatic int 2243114878Sjulianng_btsocket_rfcomm_receive_dm(ng_btsocket_rfcomm_session_p s, int dlci) 2244114878Sjulian{ 2245114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = NULL; 2246114878Sjulian int error; 2247114878Sjulian 2248114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2249114878Sjulian 2250114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2251114878Sjulian"%s: Got DM, session state=%d, flags=%#x, mtu=%d, dlci=%d\n", 2252114878Sjulian __func__, s->state, s->flags, s->mtu, dlci); 2253114878Sjulian 2254114878Sjulian /* DLCI == 0 means multiplexor channel */ 2255114878Sjulian if (dlci == 0) { 2256114878Sjulian /* Disconnect all dlc's on the session */ 2257114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 2258114878Sjulian ng_btsocket_rfcomm_session_clean(s); 2259114878Sjulian } else { 2260114878Sjulian pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci); 2261114878Sjulian if (pcb != NULL) { 2262114878Sjulian mtx_lock(&pcb->pcb_mtx); 2263114878Sjulian 2264114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2265114878Sjulian"%s: Got DM for dlci=%d, state=%d, flags=%#x\n", 2266114878Sjulian __func__, dlci, pcb->state, pcb->flags); 2267114878Sjulian 2268114878Sjulian if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONNECTED) 2269114878Sjulian error = ECONNRESET; 2270114878Sjulian else 2271114878Sjulian error = ECONNREFUSED; 2272114878Sjulian 2273161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, error); 2274114878Sjulian 2275114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2276114878Sjulian } else 2277114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2278114878Sjulian"%s: Got DM for non-existing dlci=%d\n", __func__, dlci); 2279114878Sjulian } 2280114878Sjulian 2281114878Sjulian return (0); 2282114878Sjulian} /* ng_btsocket_rfcomm_receive_dm */ 2283114878Sjulian 2284114878Sjulian/* 2285114878Sjulian * Process RFCOMM UIH frame (data) 2286114878Sjulian */ 2287114878Sjulian 2288114878Sjulianstatic int 2289114878Sjulianng_btsocket_rfcomm_receive_uih(ng_btsocket_rfcomm_session_p s, int dlci, 2290114878Sjulian int pf, struct mbuf *m0) 2291114878Sjulian{ 2292114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = NULL; 2293114878Sjulian int error = 0; 2294114878Sjulian 2295114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2296114878Sjulian 2297114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2298114878Sjulian"%s: Got UIH, session state=%d, flags=%#x, mtu=%d, dlci=%d, pf=%d, len=%d\n", 2299114878Sjulian __func__, s->state, s->flags, s->mtu, dlci, pf, 2300114878Sjulian m0->m_pkthdr.len); 2301114878Sjulian 2302114878Sjulian /* XXX should we do it here? Check for session flow control */ 2303114878Sjulian if (s->flags & NG_BTSOCKET_RFCOMM_SESSION_LFC) { 2304114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2305114878Sjulian"%s: Got UIH with session flow control asserted, state=%d, flags=%#x\n", 2306114878Sjulian __func__, s->state, s->flags); 2307114878Sjulian goto drop; 2308114878Sjulian } 2309114878Sjulian 2310114878Sjulian /* Check if we have this dlci */ 2311114878Sjulian pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci); 2312114878Sjulian if (pcb == NULL) { 2313114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2314114878Sjulian"%s: Got UIH for non-existing dlci=%d\n", __func__, dlci); 2315114878Sjulian error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_DM,dlci); 2316114878Sjulian goto drop; 2317114878Sjulian } 2318114878Sjulian 2319114878Sjulian mtx_lock(&pcb->pcb_mtx); 2320114878Sjulian 2321114878Sjulian /* Check dlci state */ 2322114878Sjulian if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTED) { 2323114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2324114878Sjulian"%s: Got UIH for dlci=%d in invalid state=%d, flags=%#x\n", 2325114878Sjulian __func__, dlci, pcb->state, pcb->flags); 2326114878Sjulian error = EINVAL; 2327114878Sjulian goto drop1; 2328114878Sjulian } 2329114878Sjulian 2330114878Sjulian /* Check dlci flow control */ 2331114878Sjulian if (((pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) && pcb->rx_cred <= 0) || 2332114878Sjulian (pcb->lmodem & RFCOMM_MODEM_FC)) { 2333114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2334114878Sjulian"%s: Got UIH for dlci=%d with asserted flow control, state=%d, " \ 2335114878Sjulian"flags=%#x, rx_cred=%d, lmodem=%#x\n", 2336114878Sjulian __func__, dlci, pcb->state, pcb->flags, 2337114878Sjulian pcb->rx_cred, pcb->lmodem); 2338114878Sjulian goto drop1; 2339114878Sjulian } 2340114878Sjulian 2341114878Sjulian /* Did we get any credits? */ 2342114878Sjulian if ((pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) && pf) { 2343114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2344114878Sjulian"%s: Got %d more credits for dlci=%d, state=%d, flags=%#x, " \ 2345114878Sjulian"rx_cred=%d, tx_cred=%d\n", 2346114878Sjulian __func__, *mtod(m0, u_int8_t *), dlci, pcb->state, 2347114878Sjulian pcb->flags, pcb->rx_cred, pcb->tx_cred); 2348114878Sjulian 2349114878Sjulian pcb->tx_cred += *mtod(m0, u_int8_t *); 2350114878Sjulian m_adj(m0, 1); 2351114878Sjulian 2352114878Sjulian /* Send more from the DLC. XXX check for errors? */ 2353114878Sjulian ng_btsocket_rfcomm_pcb_send(pcb, ALOT); 2354114878Sjulian } 2355114878Sjulian 2356114878Sjulian /* OK the of the rest of the mbuf is the data */ 2357114878Sjulian if (m0->m_pkthdr.len > 0) { 2358114878Sjulian /* If we are using credit flow control decrease rx_cred here */ 2359114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) { 2360114878Sjulian /* Give remote peer more credits (if needed) */ 2361114878Sjulian if (-- pcb->rx_cred <= RFCOMM_MAX_CREDITS / 2) 2362114878Sjulian ng_btsocket_rfcomm_send_credits(pcb); 2363114878Sjulian else 2364114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2365114878Sjulian"%s: Remote side still has credits, dlci=%d, state=%d, flags=%#x, " \ 2366114878Sjulian"rx_cred=%d, tx_cred=%d\n", __func__, dlci, pcb->state, pcb->flags, 2367114878Sjulian pcb->rx_cred, pcb->tx_cred); 2368114878Sjulian } 2369114878Sjulian 2370114878Sjulian /* Check packet against mtu on dlci */ 2371114878Sjulian if (m0->m_pkthdr.len > pcb->mtu) { 2372114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2373114878Sjulian"%s: Got oversized UIH for dlci=%d, state=%d, flags=%#x, mtu=%d, len=%d\n", 2374114878Sjulian __func__, dlci, pcb->state, pcb->flags, 2375114878Sjulian pcb->mtu, m0->m_pkthdr.len); 2376114878Sjulian 2377114878Sjulian error = EMSGSIZE; 2378114878Sjulian } else if (m0->m_pkthdr.len > sbspace(&pcb->so->so_rcv)) { 2379114878Sjulian 2380114878Sjulian /* 2381114878Sjulian * This is really bad. Receive queue on socket does 2382114878Sjulian * not have enough space for the packet. We do not 2383114878Sjulian * have any other choice but drop the packet. 2384114878Sjulian */ 2385114878Sjulian 2386114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2387114878Sjulian"%s: Not enough space in socket receive queue. Dropping UIH for dlci=%d, " \ 2388114878Sjulian"state=%d, flags=%#x, len=%d, space=%ld\n", 2389114878Sjulian __func__, dlci, pcb->state, pcb->flags, 2390114878Sjulian m0->m_pkthdr.len, sbspace(&pcb->so->so_rcv)); 2391114878Sjulian 2392114878Sjulian error = ENOBUFS; 2393114878Sjulian } else { 2394114878Sjulian /* Append packet to the socket receive queue */ 2395114878Sjulian sbappend(&pcb->so->so_rcv, m0); 2396114878Sjulian m0 = NULL; 2397114878Sjulian 2398114878Sjulian sorwakeup(pcb->so); 2399114878Sjulian } 2400114878Sjulian } 2401114878Sjuliandrop1: 2402114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2403114878Sjuliandrop: 2404114878Sjulian NG_FREE_M(m0); /* checks for != NULL */ 2405114878Sjulian 2406114878Sjulian return (error); 2407114878Sjulian} /* ng_btsocket_rfcomm_receive_uih */ 2408114878Sjulian 2409114878Sjulian/* 2410114878Sjulian * Process RFCOMM MCC command (Multiplexor) 2411114878Sjulian * 2412114878Sjulian * From TS 07.10 spec 2413114878Sjulian * 2414114878Sjulian * "5.4.3.1 Information Data 2415114878Sjulian * 2416114878Sjulian * ...The frames (UIH) sent by the initiating station have the C/R bit set 2417114878Sjulian * to 1 and those sent by the responding station have the C/R bit set to 0..." 2418114878Sjulian * 2419114878Sjulian * "5.4.6.2 Operating procedures 2420114878Sjulian * 2421114878Sjulian * Messages always exist in pairs; a command message and a corresponding 2422114878Sjulian * response message. If the C/R bit is set to 1 the message is a command, 2423114878Sjulian * if it is set to 0 the message is a response... 2424114878Sjulian * 2425114878Sjulian * ... 2426114878Sjulian * 2427114878Sjulian * NOTE: Notice that when UIH frames are used to convey information on DLCI 0 2428114878Sjulian * there are at least two different fields that contain a C/R bit, and the 2429114878Sjulian * bits are set of different form. The C/R bit in the Type field shall be set 2430114878Sjulian * as it is stated above, while the C/R bit in the Address field (see subclause 2431114878Sjulian * 5.2.1.2) shall be set as it is described in subclause 5.4.3.1." 2432114878Sjulian */ 2433114878Sjulian 2434114878Sjulianstatic int 2435114878Sjulianng_btsocket_rfcomm_receive_mcc(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2436114878Sjulian{ 2437114878Sjulian struct rfcomm_mcc_hdr *hdr = NULL; 2438114878Sjulian u_int8_t cr, type, length; 2439114878Sjulian 2440114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2441114878Sjulian 2442114878Sjulian /* 2443114878Sjulian * We can access data directly in the first mbuf, because we have 2444114878Sjulian * m_pullup()'ed mbuf chain in ng_btsocket_rfcomm_receive_frame(). 2445114878Sjulian * All MCC commands should fit into single mbuf (except probably TEST). 2446114878Sjulian */ 2447114878Sjulian 2448114878Sjulian hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2449114878Sjulian cr = RFCOMM_CR(hdr->type); 2450114878Sjulian type = RFCOMM_MCC_TYPE(hdr->type); 2451114878Sjulian length = RFCOMM_MCC_LENGTH(hdr->length); 2452114878Sjulian 2453114878Sjulian /* Check MCC frame length */ 2454114878Sjulian if (sizeof(*hdr) + length != m0->m_pkthdr.len) { 2455114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2456114878Sjulian"%s: Invalid MCC frame length=%d, len=%d\n", 2457114878Sjulian __func__, length, m0->m_pkthdr.len); 2458114878Sjulian NG_FREE_M(m0); 2459114878Sjulian 2460114878Sjulian return (EMSGSIZE); 2461114878Sjulian } 2462114878Sjulian 2463114878Sjulian switch (type) { 2464114878Sjulian case RFCOMM_MCC_TEST: 2465114878Sjulian return (ng_btsocket_rfcomm_receive_test(s, m0)); 2466114878Sjulian /* NOT REACHED */ 2467114878Sjulian 2468114878Sjulian case RFCOMM_MCC_FCON: 2469114878Sjulian case RFCOMM_MCC_FCOFF: 2470114878Sjulian return (ng_btsocket_rfcomm_receive_fc(s, m0)); 2471114878Sjulian /* NOT REACHED */ 2472114878Sjulian 2473114878Sjulian case RFCOMM_MCC_MSC: 2474114878Sjulian return (ng_btsocket_rfcomm_receive_msc(s, m0)); 2475114878Sjulian /* NOT REACHED */ 2476114878Sjulian 2477114878Sjulian case RFCOMM_MCC_RPN: 2478114878Sjulian return (ng_btsocket_rfcomm_receive_rpn(s, m0)); 2479114878Sjulian /* NOT REACHED */ 2480114878Sjulian 2481114878Sjulian case RFCOMM_MCC_RLS: 2482114878Sjulian return (ng_btsocket_rfcomm_receive_rls(s, m0)); 2483114878Sjulian /* NOT REACHED */ 2484114878Sjulian 2485114878Sjulian case RFCOMM_MCC_PN: 2486114878Sjulian return (ng_btsocket_rfcomm_receive_pn(s, m0)); 2487114878Sjulian /* NOT REACHED */ 2488114878Sjulian 2489114878Sjulian case RFCOMM_MCC_NSC: 2490114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2491114878Sjulian"%s: Got MCC NSC, type=%#x, cr=%d, length=%d, session state=%d, flags=%#x, " \ 2492114878Sjulian"mtu=%d, len=%d\n", __func__, RFCOMM_MCC_TYPE(*((u_int8_t *)(hdr + 1))), cr, 2493114878Sjulian length, s->state, s->flags, s->mtu, m0->m_pkthdr.len); 2494114878Sjulian NG_FREE_M(m0); 2495114878Sjulian break; 2496114878Sjulian 2497114878Sjulian default: 2498114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2499114878Sjulian"%s: Got unknown MCC, type=%#x, cr=%d, length=%d, session state=%d, " \ 2500114878Sjulian"flags=%#x, mtu=%d, len=%d\n", 2501114878Sjulian __func__, type, cr, length, s->state, s->flags, 2502114878Sjulian s->mtu, m0->m_pkthdr.len); 2503114878Sjulian 2504114878Sjulian /* Reuse mbuf to send NSC */ 2505114878Sjulian hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2506114878Sjulian m0->m_pkthdr.len = m0->m_len = sizeof(*hdr); 2507114878Sjulian 2508114878Sjulian /* Create MCC NSC header */ 2509114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_NSC); 2510114878Sjulian hdr->length = RFCOMM_MKLEN8(1); 2511114878Sjulian 2512114878Sjulian /* Put back MCC command type we did not like */ 2513114878Sjulian m0->m_data[m0->m_len] = RFCOMM_MKMCC_TYPE(cr, type); 2514114878Sjulian m0->m_pkthdr.len ++; 2515114878Sjulian m0->m_len ++; 2516114878Sjulian 2517114878Sjulian /* Send UIH frame */ 2518114878Sjulian return (ng_btsocket_rfcomm_send_uih(s, 2519114878Sjulian RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0)); 2520114878Sjulian /* NOT REACHED */ 2521114878Sjulian } 2522114878Sjulian 2523114878Sjulian return (0); 2524114878Sjulian} /* ng_btsocket_rfcomm_receive_mcc */ 2525114878Sjulian 2526114878Sjulian/* 2527114878Sjulian * Receive RFCOMM TEST MCC command 2528114878Sjulian */ 2529114878Sjulian 2530114878Sjulianstatic int 2531114878Sjulianng_btsocket_rfcomm_receive_test(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2532114878Sjulian{ 2533114878Sjulian struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2534114878Sjulian int error = 0; 2535114878Sjulian 2536114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2537114878Sjulian 2538114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2539114878Sjulian"%s: Got MCC TEST, cr=%d, length=%d, session state=%d, flags=%#x, mtu=%d, " \ 2540114878Sjulian"len=%d\n", __func__, RFCOMM_CR(hdr->type), RFCOMM_MCC_LENGTH(hdr->length), 2541114878Sjulian s->state, s->flags, s->mtu, m0->m_pkthdr.len); 2542114878Sjulian 2543114878Sjulian if (RFCOMM_CR(hdr->type)) { 2544114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_TEST); 2545114878Sjulian error = ng_btsocket_rfcomm_send_uih(s, 2546114878Sjulian RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0); 2547114878Sjulian } else 2548114878Sjulian NG_FREE_M(m0); /* XXX ignore response */ 2549114878Sjulian 2550114878Sjulian return (error); 2551114878Sjulian} /* ng_btsocket_rfcomm_receive_test */ 2552114878Sjulian 2553114878Sjulian/* 2554114878Sjulian * Receive RFCOMM FCON/FCOFF MCC command 2555114878Sjulian */ 2556114878Sjulian 2557114878Sjulianstatic int 2558114878Sjulianng_btsocket_rfcomm_receive_fc(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2559114878Sjulian{ 2560114878Sjulian struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2561114878Sjulian u_int8_t type = RFCOMM_MCC_TYPE(hdr->type); 2562114878Sjulian int error = 0; 2563114878Sjulian 2564114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2565114878Sjulian 2566114878Sjulian /* 2567114878Sjulian * Turn ON/OFF aggregate flow on the entire session. When remote peer 2568114878Sjulian * asserted flow control no transmission shall occur except on dlci 0 2569114878Sjulian * (control channel). 2570114878Sjulian */ 2571114878Sjulian 2572114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2573114878Sjulian"%s: Got MCC FC%s, cr=%d, length=%d, session state=%d, flags=%#x, mtu=%d, " \ 2574114878Sjulian"len=%d\n", __func__, (type == RFCOMM_MCC_FCON)? "ON" : "OFF", 2575114878Sjulian RFCOMM_CR(hdr->type), RFCOMM_MCC_LENGTH(hdr->length), 2576114878Sjulian s->state, s->flags, s->mtu, m0->m_pkthdr.len); 2577114878Sjulian 2578114878Sjulian if (RFCOMM_CR(hdr->type)) { 2579114878Sjulian if (type == RFCOMM_MCC_FCON) 2580114878Sjulian s->flags &= ~NG_BTSOCKET_RFCOMM_SESSION_RFC; 2581114878Sjulian else 2582114878Sjulian s->flags |= NG_BTSOCKET_RFCOMM_SESSION_RFC; 2583114878Sjulian 2584114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(0, type); 2585114878Sjulian error = ng_btsocket_rfcomm_send_uih(s, 2586114878Sjulian RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0); 2587114878Sjulian } else 2588114878Sjulian NG_FREE_M(m0); /* XXX ignore response */ 2589114878Sjulian 2590114878Sjulian return (error); 2591114878Sjulian} /* ng_btsocket_rfcomm_receive_fc */ 2592114878Sjulian 2593114878Sjulian/* 2594114878Sjulian * Receive RFCOMM MSC MCC command 2595114878Sjulian */ 2596114878Sjulian 2597114878Sjulianstatic int 2598114878Sjulianng_btsocket_rfcomm_receive_msc(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2599114878Sjulian{ 2600114878Sjulian struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr*); 2601114878Sjulian struct rfcomm_mcc_msc *msc = (struct rfcomm_mcc_msc *)(hdr+1); 2602114878Sjulian ng_btsocket_rfcomm_pcb_t *pcb = NULL; 2603114878Sjulian int error = 0; 2604114878Sjulian 2605114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2606114878Sjulian 2607114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2608114878Sjulian"%s: Got MCC MSC, dlci=%d, cr=%d, length=%d, session state=%d, flags=%#x, " \ 2609114878Sjulian"mtu=%d, len=%d\n", 2610114878Sjulian __func__, RFCOMM_DLCI(msc->address), RFCOMM_CR(hdr->type), 2611114878Sjulian RFCOMM_MCC_LENGTH(hdr->length), s->state, s->flags, 2612114878Sjulian s->mtu, m0->m_pkthdr.len); 2613114878Sjulian 2614114878Sjulian if (RFCOMM_CR(hdr->type)) { 2615114878Sjulian pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, RFCOMM_DLCI(msc->address)); 2616114878Sjulian if (pcb == NULL) { 2617114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2618114878Sjulian"%s: Got MSC command for non-existing dlci=%d\n", 2619114878Sjulian __func__, RFCOMM_DLCI(msc->address)); 2620114878Sjulian NG_FREE_M(m0); 2621114878Sjulian 2622114878Sjulian return (ENOENT); 2623114878Sjulian } 2624114878Sjulian 2625114878Sjulian mtx_lock(&pcb->pcb_mtx); 2626114878Sjulian 2627114878Sjulian if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTING && 2628114878Sjulian pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTED) { 2629114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2630114878Sjulian"%s: Got MSC on dlci=%d in invalid state=%d\n", 2631114878Sjulian __func__, RFCOMM_DLCI(msc->address), 2632114878Sjulian pcb->state); 2633114878Sjulian 2634114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2635114878Sjulian NG_FREE_M(m0); 2636114878Sjulian 2637114878Sjulian return (EINVAL); 2638114878Sjulian } 2639114878Sjulian 2640114878Sjulian pcb->rmodem = msc->modem; /* Update remote port signals */ 2641114878Sjulian 2642114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_MSC); 2643114878Sjulian error = ng_btsocket_rfcomm_send_uih(s, 2644114878Sjulian RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0); 2645114878Sjulian 2646114878Sjulian#if 0 /* YYY */ 2647114878Sjulian /* Send more data from DLC. XXX check for errors? */ 2648114878Sjulian if (!(pcb->rmodem & RFCOMM_MODEM_FC) && 2649114878Sjulian !(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC)) 2650114878Sjulian ng_btsocket_rfcomm_pcb_send(pcb, ALOT); 2651114878Sjulian#endif /* YYY */ 2652114878Sjulian 2653114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2654114878Sjulian } else 2655114878Sjulian NG_FREE_M(m0); /* XXX ignore response */ 2656114878Sjulian 2657114878Sjulian return (error); 2658114878Sjulian} /* ng_btsocket_rfcomm_receive_msc */ 2659114878Sjulian 2660114878Sjulian/* 2661114878Sjulian * Receive RFCOMM RPN MCC command 2662114878Sjulian * XXX FIXME do we need htole16/le16toh for RPN param_mask? 2663114878Sjulian */ 2664114878Sjulian 2665114878Sjulianstatic int 2666114878Sjulianng_btsocket_rfcomm_receive_rpn(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2667114878Sjulian{ 2668114878Sjulian struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2669114878Sjulian struct rfcomm_mcc_rpn *rpn = (struct rfcomm_mcc_rpn *)(hdr + 1); 2670114878Sjulian int error = 0; 2671114878Sjulian u_int16_t param_mask; 2672114878Sjulian u_int8_t bit_rate, data_bits, stop_bits, parity, 2673114878Sjulian flow_control, xon_char, xoff_char; 2674114878Sjulian 2675114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2676114878Sjulian 2677114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2678114878Sjulian"%s: Got MCC RPN, dlci=%d, cr=%d, length=%d, session state=%d, flags=%#x, " \ 2679114878Sjulian"mtu=%d, len=%d\n", 2680114878Sjulian __func__, RFCOMM_DLCI(rpn->dlci), RFCOMM_CR(hdr->type), 2681114878Sjulian RFCOMM_MCC_LENGTH(hdr->length), s->state, s->flags, 2682114878Sjulian s->mtu, m0->m_pkthdr.len); 2683114878Sjulian 2684114878Sjulian if (RFCOMM_CR(hdr->type)) { 2685114878Sjulian param_mask = RFCOMM_RPN_PM_ALL; 2686114878Sjulian 2687114878Sjulian if (RFCOMM_MCC_LENGTH(hdr->length) == 1) { 2688114878Sjulian /* Request - return default setting */ 2689114878Sjulian bit_rate = RFCOMM_RPN_BR_115200; 2690114878Sjulian data_bits = RFCOMM_RPN_DATA_8; 2691114878Sjulian stop_bits = RFCOMM_RPN_STOP_1; 2692114878Sjulian parity = RFCOMM_RPN_PARITY_NONE; 2693114878Sjulian flow_control = RFCOMM_RPN_FLOW_NONE; 2694114878Sjulian xon_char = RFCOMM_RPN_XON_CHAR; 2695114878Sjulian xoff_char = RFCOMM_RPN_XOFF_CHAR; 2696114878Sjulian } else { 2697114878Sjulian /* 2698114878Sjulian * Ignore/accept bit_rate, 8 bits, 1 stop bit, no 2699114878Sjulian * parity, no flow control lines, default XON/XOFF 2700114878Sjulian * chars. 2701114878Sjulian */ 2702114878Sjulian 2703114878Sjulian bit_rate = rpn->bit_rate; 2704114878Sjulian rpn->param_mask = le16toh(rpn->param_mask); /* XXX */ 2705114878Sjulian 2706114878Sjulian data_bits = RFCOMM_RPN_DATA_BITS(rpn->line_settings); 2707114878Sjulian if (rpn->param_mask & RFCOMM_RPN_PM_DATA && 2708114878Sjulian data_bits != RFCOMM_RPN_DATA_8) { 2709114878Sjulian data_bits = RFCOMM_RPN_DATA_8; 2710114878Sjulian param_mask ^= RFCOMM_RPN_PM_DATA; 2711114878Sjulian } 2712114878Sjulian 2713114878Sjulian stop_bits = RFCOMM_RPN_STOP_BITS(rpn->line_settings); 2714114878Sjulian if (rpn->param_mask & RFCOMM_RPN_PM_STOP && 2715114878Sjulian stop_bits != RFCOMM_RPN_STOP_1) { 2716114878Sjulian stop_bits = RFCOMM_RPN_STOP_1; 2717114878Sjulian param_mask ^= RFCOMM_RPN_PM_STOP; 2718114878Sjulian } 2719114878Sjulian 2720114878Sjulian parity = RFCOMM_RPN_PARITY(rpn->line_settings); 2721114878Sjulian if (rpn->param_mask & RFCOMM_RPN_PM_PARITY && 2722114878Sjulian parity != RFCOMM_RPN_PARITY_NONE) { 2723114878Sjulian parity = RFCOMM_RPN_PARITY_NONE; 2724114878Sjulian param_mask ^= RFCOMM_RPN_PM_PARITY; 2725114878Sjulian } 2726114878Sjulian 2727114878Sjulian flow_control = rpn->flow_control; 2728114878Sjulian if (rpn->param_mask & RFCOMM_RPN_PM_FLOW && 2729114878Sjulian flow_control != RFCOMM_RPN_FLOW_NONE) { 2730114878Sjulian flow_control = RFCOMM_RPN_FLOW_NONE; 2731114878Sjulian param_mask ^= RFCOMM_RPN_PM_FLOW; 2732114878Sjulian } 2733114878Sjulian 2734114878Sjulian xon_char = rpn->xon_char; 2735114878Sjulian if (rpn->param_mask & RFCOMM_RPN_PM_XON && 2736114878Sjulian xon_char != RFCOMM_RPN_XON_CHAR) { 2737114878Sjulian xon_char = RFCOMM_RPN_XON_CHAR; 2738114878Sjulian param_mask ^= RFCOMM_RPN_PM_XON; 2739114878Sjulian } 2740114878Sjulian 2741114878Sjulian xoff_char = rpn->xoff_char; 2742114878Sjulian if (rpn->param_mask & RFCOMM_RPN_PM_XOFF && 2743114878Sjulian xoff_char != RFCOMM_RPN_XOFF_CHAR) { 2744114878Sjulian xoff_char = RFCOMM_RPN_XOFF_CHAR; 2745114878Sjulian param_mask ^= RFCOMM_RPN_PM_XOFF; 2746114878Sjulian } 2747114878Sjulian } 2748114878Sjulian 2749114878Sjulian rpn->bit_rate = bit_rate; 2750114878Sjulian rpn->line_settings = RFCOMM_MKRPN_LINE_SETTINGS(data_bits, 2751114878Sjulian stop_bits, parity); 2752114878Sjulian rpn->flow_control = flow_control; 2753114878Sjulian rpn->xon_char = xon_char; 2754114878Sjulian rpn->xoff_char = xoff_char; 2755114878Sjulian rpn->param_mask = htole16(param_mask); /* XXX */ 2756114878Sjulian 2757114878Sjulian m0->m_pkthdr.len = m0->m_len = sizeof(*hdr) + sizeof(*rpn); 2758114878Sjulian 2759114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_RPN); 2760114878Sjulian error = ng_btsocket_rfcomm_send_uih(s, 2761114878Sjulian RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0); 2762114878Sjulian } else 2763114878Sjulian NG_FREE_M(m0); /* XXX ignore response */ 2764114878Sjulian 2765114878Sjulian return (error); 2766114878Sjulian} /* ng_btsocket_rfcomm_receive_rpn */ 2767114878Sjulian 2768114878Sjulian/* 2769114878Sjulian * Receive RFCOMM RLS MCC command 2770114878Sjulian */ 2771114878Sjulian 2772114878Sjulianstatic int 2773114878Sjulianng_btsocket_rfcomm_receive_rls(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2774114878Sjulian{ 2775114878Sjulian struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2776114878Sjulian struct rfcomm_mcc_rls *rls = (struct rfcomm_mcc_rls *)(hdr + 1); 2777114878Sjulian int error = 0; 2778114878Sjulian 2779114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2780114878Sjulian 2781114878Sjulian /* 2782114878Sjulian * XXX FIXME Do we have to do anything else here? Remote peer tries to 2783114878Sjulian * tell us something about DLCI. Just report what we have received and 2784114878Sjulian * return back received values as required by TS 07.10 spec. 2785114878Sjulian */ 2786114878Sjulian 2787114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2788114878Sjulian"%s: Got MCC RLS, dlci=%d, status=%#x, cr=%d, length=%d, session state=%d, " \ 2789114878Sjulian"flags=%#x, mtu=%d, len=%d\n", 2790114878Sjulian __func__, RFCOMM_DLCI(rls->address), rls->status, 2791114878Sjulian RFCOMM_CR(hdr->type), RFCOMM_MCC_LENGTH(hdr->length), 2792114878Sjulian s->state, s->flags, s->mtu, m0->m_pkthdr.len); 2793114878Sjulian 2794114878Sjulian if (RFCOMM_CR(hdr->type)) { 2795114878Sjulian if (rls->status & 0x1) 2796114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 2797114878Sjulian"%s: Got RLS dlci=%d, error=%#x\n", __func__, RFCOMM_DLCI(rls->address), 2798114878Sjulian rls->status >> 1); 2799114878Sjulian 2800114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_RLS); 2801114878Sjulian error = ng_btsocket_rfcomm_send_uih(s, 2802114878Sjulian RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0); 2803114878Sjulian } else 2804114878Sjulian NG_FREE_M(m0); /* XXX ignore responses */ 2805114878Sjulian 2806114878Sjulian return (error); 2807114878Sjulian} /* ng_btsocket_rfcomm_receive_rls */ 2808114878Sjulian 2809114878Sjulian/* 2810114878Sjulian * Receive RFCOMM PN MCC command 2811114878Sjulian */ 2812114878Sjulian 2813114878Sjulianstatic int 2814114878Sjulianng_btsocket_rfcomm_receive_pn(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2815114878Sjulian{ 2816114878Sjulian struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr*); 2817114878Sjulian struct rfcomm_mcc_pn *pn = (struct rfcomm_mcc_pn *)(hdr+1); 2818114878Sjulian ng_btsocket_rfcomm_pcb_t *pcb = NULL; 2819114878Sjulian int error = 0; 2820114878Sjulian 2821114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2822114878Sjulian 2823114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2824114878Sjulian"%s: Got MCC PN, dlci=%d, cr=%d, length=%d, flow_control=%#x, priority=%d, " \ 2825114878Sjulian"ack_timer=%d, mtu=%d, max_retrans=%d, credits=%d, session state=%d, " \ 2826114878Sjulian"flags=%#x, session mtu=%d, len=%d\n", 2827114878Sjulian __func__, pn->dlci, RFCOMM_CR(hdr->type), 2828114878Sjulian RFCOMM_MCC_LENGTH(hdr->length), pn->flow_control, pn->priority, 2829114878Sjulian pn->ack_timer, le16toh(pn->mtu), pn->max_retrans, pn->credits, 2830114878Sjulian s->state, s->flags, s->mtu, m0->m_pkthdr.len); 2831114878Sjulian 2832114878Sjulian if (pn->dlci == 0) { 2833114878Sjulian NG_BTSOCKET_RFCOMM_ERR("%s: Zero dlci in MCC PN\n", __func__); 2834114878Sjulian NG_FREE_M(m0); 2835114878Sjulian 2836114878Sjulian return (EINVAL); 2837114878Sjulian } 2838114878Sjulian 2839114878Sjulian /* Check if we have this dlci */ 2840114878Sjulian pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, pn->dlci); 2841114878Sjulian if (pcb != NULL) { 2842114878Sjulian mtx_lock(&pcb->pcb_mtx); 2843114878Sjulian 2844114878Sjulian if (RFCOMM_CR(hdr->type)) { 2845114878Sjulian /* PN Request */ 2846114878Sjulian ng_btsocket_rfcomm_set_pn(pcb, 1, pn->flow_control, 2847114878Sjulian pn->credits, pn->mtu); 2848114878Sjulian 2849114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) { 2850114878Sjulian pn->flow_control = 0xe0; 2851114878Sjulian pn->credits = RFCOMM_DEFAULT_CREDITS; 2852114878Sjulian } else { 2853114878Sjulian pn->flow_control = 0; 2854114878Sjulian pn->credits = 0; 2855114878Sjulian } 2856114878Sjulian 2857114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_PN); 2858114878Sjulian error = ng_btsocket_rfcomm_send_uih(s, 2859114878Sjulian RFCOMM_MKADDRESS(INITIATOR(s), 0), 2860114878Sjulian 0, 0, m0); 2861114878Sjulian } else { 2862114878Sjulian /* PN Response - proceed with SABM. Timeout still set */ 2863114878Sjulian if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONFIGURING) { 2864114878Sjulian ng_btsocket_rfcomm_set_pn(pcb, 0, 2865114878Sjulian pn->flow_control, pn->credits, pn->mtu); 2866114878Sjulian 2867114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTING; 2868114878Sjulian error = ng_btsocket_rfcomm_send_command(s, 2869114878Sjulian RFCOMM_FRAME_SABM, pn->dlci); 2870114878Sjulian } else 2871114878Sjulian NG_BTSOCKET_RFCOMM_WARN( 2872114878Sjulian"%s: Got PN response for dlci=%d in invalid state=%d\n", 2873114878Sjulian __func__, pn->dlci, pcb->state); 2874114878Sjulian 2875114878Sjulian NG_FREE_M(m0); 2876114878Sjulian } 2877114878Sjulian 2878114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2879114878Sjulian } else if (RFCOMM_CR(hdr->type)) { 2880114878Sjulian /* PN request to non-existing dlci - incomming connection */ 2881114878Sjulian pcb = ng_btsocket_rfcomm_connect_ind(s, 2882114878Sjulian RFCOMM_SRVCHANNEL(pn->dlci)); 2883114878Sjulian if (pcb != NULL) { 2884114878Sjulian mtx_lock(&pcb->pcb_mtx); 2885114878Sjulian 2886114878Sjulian pcb->dlci = pn->dlci; 2887114878Sjulian 2888114878Sjulian ng_btsocket_rfcomm_set_pn(pcb, 1, pn->flow_control, 2889114878Sjulian pn->credits, pn->mtu); 2890114878Sjulian 2891114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) { 2892114878Sjulian pn->flow_control = 0xe0; 2893114878Sjulian pn->credits = RFCOMM_DEFAULT_CREDITS; 2894114878Sjulian } else { 2895114878Sjulian pn->flow_control = 0; 2896114878Sjulian pn->credits = 0; 2897114878Sjulian } 2898114878Sjulian 2899114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_PN); 2900114878Sjulian error = ng_btsocket_rfcomm_send_uih(s, 2901114878Sjulian RFCOMM_MKADDRESS(INITIATOR(s), 0), 2902114878Sjulian 0, 0, m0); 2903114878Sjulian 2904114878Sjulian if (error == 0) { 2905114878Sjulian ng_btsocket_rfcomm_timeout(pcb); 2906114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTING; 2907114878Sjulian soisconnecting(pcb->so); 2908161623Semax } else 2909161623Semax ng_btsocket_rfcomm_pcb_kill(pcb, error); 2910114878Sjulian 2911114878Sjulian mtx_unlock(&pcb->pcb_mtx); 2912114878Sjulian } else { 2913114878Sjulian /* Nobody is listen()ing on this channel */ 2914114878Sjulian error = ng_btsocket_rfcomm_send_command(s, 2915114878Sjulian RFCOMM_FRAME_DM, pn->dlci); 2916114878Sjulian NG_FREE_M(m0); 2917114878Sjulian } 2918114878Sjulian } else 2919114878Sjulian NG_FREE_M(m0); /* XXX ignore response to non-existing dlci */ 2920114878Sjulian 2921114878Sjulian return (error); 2922114878Sjulian} /* ng_btsocket_rfcomm_receive_pn */ 2923114878Sjulian 2924114878Sjulian/* 2925114878Sjulian * Set PN parameters for dlci. Caller must hold pcb->pcb_mtx. 2926114878Sjulian * 2927114878Sjulian * From Bluetooth spec. 2928114878Sjulian * 2929114878Sjulian * "... The CL1 - CL4 field is completely redefined. (In TS07.10 this defines 2930114878Sjulian * the convergence layer to use, which is not applicable to RFCOMM. In RFCOMM, 2931114878Sjulian * in Bluetooth versions up to 1.0B, this field was forced to 0). 2932114878Sjulian * 2933114878Sjulian * In the PN request sent prior to a DLC establishment, this field must contain 2934114878Sjulian * the value 15 (0xF), indicating support of credit based flow control in the 2935114878Sjulian * sender. See Table 5.3 below. If the PN response contains any other value 2936114878Sjulian * than 14 (0xE) in this field, it is inferred that the peer RFCOMM entity is 2937114878Sjulian * not supporting the credit based flow control feature. (This is only possible 2938114878Sjulian * if the peer RFCOMM implementation is only conforming to Bluetooth version 2939114878Sjulian * 1.0B.) If a PN request is sent on an already open DLC, then this field must 2940114878Sjulian * contain the value zero; it is not possible to set initial credits more 2941114878Sjulian * than once per DLC activation. A responding implementation must set this 2942114878Sjulian * field in the PN response to 14 (0xE), if (and only if) the value in the PN 2943114878Sjulian * request was 15..." 2944114878Sjulian */ 2945114878Sjulian 2946114878Sjulianstatic void 2947114878Sjulianng_btsocket_rfcomm_set_pn(ng_btsocket_rfcomm_pcb_p pcb, u_int8_t cr, 2948114878Sjulian u_int8_t flow_control, u_int8_t credits, u_int16_t mtu) 2949114878Sjulian{ 2950114878Sjulian mtx_assert(&pcb->pcb_mtx, MA_OWNED); 2951114878Sjulian 2952114878Sjulian pcb->mtu = le16toh(mtu); 2953114878Sjulian 2954114878Sjulian if (cr) { 2955114878Sjulian if (flow_control == 0xf0) { 2956114878Sjulian pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_CFC; 2957114878Sjulian pcb->tx_cred = credits; 2958114878Sjulian } else { 2959114878Sjulian pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_CFC; 2960114878Sjulian pcb->tx_cred = 0; 2961114878Sjulian } 2962114878Sjulian } else { 2963114878Sjulian if (flow_control == 0xe0) { 2964114878Sjulian pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_CFC; 2965114878Sjulian pcb->tx_cred = credits; 2966114878Sjulian } else { 2967114878Sjulian pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_CFC; 2968114878Sjulian pcb->tx_cred = 0; 2969114878Sjulian } 2970114878Sjulian } 2971114878Sjulian 2972114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2973114878Sjulian"%s: cr=%d, dlci=%d, state=%d, flags=%#x, mtu=%d, rx_cred=%d, tx_cred=%d\n", 2974114878Sjulian __func__, cr, pcb->dlci, pcb->state, pcb->flags, pcb->mtu, 2975114878Sjulian pcb->rx_cred, pcb->tx_cred); 2976114878Sjulian} /* ng_btsocket_rfcomm_set_pn */ 2977114878Sjulian 2978114878Sjulian/* 2979114878Sjulian * Send RFCOMM SABM/DISC/UA/DM frames. Caller must hold s->session_mtx 2980114878Sjulian */ 2981114878Sjulian 2982114878Sjulianstatic int 2983114878Sjulianng_btsocket_rfcomm_send_command(ng_btsocket_rfcomm_session_p s, 2984114878Sjulian u_int8_t type, u_int8_t dlci) 2985114878Sjulian{ 2986114878Sjulian struct rfcomm_cmd_hdr *hdr = NULL; 2987114878Sjulian struct mbuf *m = NULL; 2988114878Sjulian int cr; 2989114878Sjulian 2990114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 2991114878Sjulian 2992114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 2993114878Sjulian"%s: Sending command type %#x, session state=%d, flags=%#x, mtu=%d, dlci=%d\n", 2994114878Sjulian __func__, type, s->state, s->flags, s->mtu, dlci); 2995114878Sjulian 2996114878Sjulian switch (type) { 2997114878Sjulian case RFCOMM_FRAME_SABM: 2998114878Sjulian case RFCOMM_FRAME_DISC: 2999114878Sjulian cr = INITIATOR(s); 3000114878Sjulian break; 3001114878Sjulian 3002114878Sjulian case RFCOMM_FRAME_UA: 3003114878Sjulian case RFCOMM_FRAME_DM: 3004114878Sjulian cr = !INITIATOR(s); 3005114878Sjulian break; 3006114878Sjulian 3007114878Sjulian default: 3008114878Sjulian panic("%s: Invalid frame type=%#x\n", __func__, type); 3009114878Sjulian return (EINVAL); 3010114878Sjulian /* NOT REACHED */ 3011114878Sjulian } 3012114878Sjulian 3013243882Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 3014114878Sjulian if (m == NULL) 3015114878Sjulian return (ENOBUFS); 3016114878Sjulian 3017114878Sjulian m->m_pkthdr.len = m->m_len = sizeof(*hdr); 3018114878Sjulian 3019114878Sjulian hdr = mtod(m, struct rfcomm_cmd_hdr *); 3020114878Sjulian hdr->address = RFCOMM_MKADDRESS(cr, dlci); 3021114878Sjulian hdr->control = RFCOMM_MKCONTROL(type, 1); 3022114878Sjulian hdr->length = RFCOMM_MKLEN8(0); 3023114878Sjulian hdr->fcs = ng_btsocket_rfcomm_fcs3((u_int8_t *) hdr); 3024114878Sjulian 3025114878Sjulian NG_BT_MBUFQ_ENQUEUE(&s->outq, m); 3026114878Sjulian 3027114878Sjulian return (0); 3028114878Sjulian} /* ng_btsocket_rfcomm_send_command */ 3029114878Sjulian 3030114878Sjulian/* 3031114878Sjulian * Send RFCOMM UIH frame. Caller must hold s->session_mtx 3032114878Sjulian */ 3033114878Sjulian 3034114878Sjulianstatic int 3035114878Sjulianng_btsocket_rfcomm_send_uih(ng_btsocket_rfcomm_session_p s, u_int8_t address, 3036114878Sjulian u_int8_t pf, u_int8_t credits, struct mbuf *data) 3037114878Sjulian{ 3038114878Sjulian struct rfcomm_frame_hdr *hdr = NULL; 3039114878Sjulian struct mbuf *m = NULL, *mcrc = NULL; 3040114878Sjulian u_int16_t length; 3041114878Sjulian 3042114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 3043114878Sjulian 3044243882Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 3045114878Sjulian if (m == NULL) { 3046114878Sjulian NG_FREE_M(data); 3047114878Sjulian return (ENOBUFS); 3048114878Sjulian } 3049114878Sjulian m->m_pkthdr.len = m->m_len = sizeof(*hdr); 3050114878Sjulian 3051243882Sglebius MGET(mcrc, M_NOWAIT, MT_DATA); 3052114878Sjulian if (mcrc == NULL) { 3053114878Sjulian NG_FREE_M(data); 3054114878Sjulian return (ENOBUFS); 3055114878Sjulian } 3056114878Sjulian mcrc->m_len = 1; 3057114878Sjulian 3058114878Sjulian /* Fill UIH frame header */ 3059114878Sjulian hdr = mtod(m, struct rfcomm_frame_hdr *); 3060114878Sjulian hdr->address = address; 3061114878Sjulian hdr->control = RFCOMM_MKCONTROL(RFCOMM_FRAME_UIH, pf); 3062114878Sjulian 3063114878Sjulian /* Calculate FCS */ 3064114878Sjulian mcrc->m_data[0] = ng_btsocket_rfcomm_fcs2((u_int8_t *) hdr); 3065114878Sjulian 3066114878Sjulian /* Put length back */ 3067114878Sjulian length = (data != NULL)? data->m_pkthdr.len : 0; 3068114878Sjulian if (length > 127) { 3069114878Sjulian u_int16_t l = htole16(RFCOMM_MKLEN16(length)); 3070114878Sjulian 3071114878Sjulian bcopy(&l, &hdr->length, sizeof(l)); 3072114878Sjulian m->m_pkthdr.len ++; 3073114878Sjulian m->m_len ++; 3074114878Sjulian } else 3075114878Sjulian hdr->length = RFCOMM_MKLEN8(length); 3076114878Sjulian 3077114878Sjulian if (pf) { 3078114878Sjulian m->m_data[m->m_len] = credits; 3079114878Sjulian m->m_pkthdr.len ++; 3080114878Sjulian m->m_len ++; 3081114878Sjulian } 3082114878Sjulian 3083114878Sjulian /* Add payload */ 3084114878Sjulian if (data != NULL) { 3085114878Sjulian m_cat(m, data); 3086114878Sjulian m->m_pkthdr.len += length; 3087114878Sjulian } 3088114878Sjulian 3089114878Sjulian /* Put FCS back */ 3090114878Sjulian m_cat(m, mcrc); 3091114878Sjulian m->m_pkthdr.len ++; 3092114878Sjulian 3093114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3094114878Sjulian"%s: Sending UIH state=%d, flags=%#x, address=%d, length=%d, pf=%d, " \ 3095114878Sjulian"credits=%d, len=%d\n", 3096114878Sjulian __func__, s->state, s->flags, address, length, pf, credits, 3097114878Sjulian m->m_pkthdr.len); 3098114878Sjulian 3099114878Sjulian NG_BT_MBUFQ_ENQUEUE(&s->outq, m); 3100114878Sjulian 3101114878Sjulian return (0); 3102114878Sjulian} /* ng_btsocket_rfcomm_send_uih */ 3103114878Sjulian 3104114878Sjulian/* 3105114878Sjulian * Send MSC request. Caller must hold pcb->pcb_mtx and pcb->session->session_mtx 3106114878Sjulian */ 3107114878Sjulian 3108114878Sjulianstatic int 3109114878Sjulianng_btsocket_rfcomm_send_msc(ng_btsocket_rfcomm_pcb_p pcb) 3110114878Sjulian{ 3111114878Sjulian struct mbuf *m = NULL; 3112114878Sjulian struct rfcomm_mcc_hdr *hdr = NULL; 3113114878Sjulian struct rfcomm_mcc_msc *msc = NULL; 3114114878Sjulian 3115114878Sjulian mtx_assert(&pcb->session->session_mtx, MA_OWNED); 3116114878Sjulian mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3117114878Sjulian 3118243882Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 3119114878Sjulian if (m == NULL) 3120114878Sjulian return (ENOBUFS); 3121114878Sjulian 3122114878Sjulian m->m_pkthdr.len = m->m_len = sizeof(*hdr) + sizeof(*msc); 3123114878Sjulian 3124114878Sjulian hdr = mtod(m, struct rfcomm_mcc_hdr *); 3125114878Sjulian msc = (struct rfcomm_mcc_msc *)(hdr + 1); 3126114878Sjulian 3127114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(1, RFCOMM_MCC_MSC); 3128114878Sjulian hdr->length = RFCOMM_MKLEN8(sizeof(*msc)); 3129114878Sjulian 3130114878Sjulian msc->address = RFCOMM_MKADDRESS(1, pcb->dlci); 3131114878Sjulian msc->modem = pcb->lmodem; 3132114878Sjulian 3133114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3134114878Sjulian"%s: Sending MSC dlci=%d, state=%d, flags=%#x, address=%d, modem=%#x\n", 3135114878Sjulian __func__, pcb->dlci, pcb->state, pcb->flags, msc->address, 3136114878Sjulian msc->modem); 3137114878Sjulian 3138114878Sjulian return (ng_btsocket_rfcomm_send_uih(pcb->session, 3139114878Sjulian RFCOMM_MKADDRESS(INITIATOR(pcb->session), 0), 0, 0, m)); 3140114878Sjulian} /* ng_btsocket_rfcomm_send_msc */ 3141114878Sjulian 3142114878Sjulian/* 3143114878Sjulian * Send PN request. Caller must hold pcb->pcb_mtx and pcb->session->session_mtx 3144114878Sjulian */ 3145114878Sjulian 3146114878Sjulianstatic int 3147114878Sjulianng_btsocket_rfcomm_send_pn(ng_btsocket_rfcomm_pcb_p pcb) 3148114878Sjulian{ 3149114878Sjulian struct mbuf *m = NULL; 3150114878Sjulian struct rfcomm_mcc_hdr *hdr = NULL; 3151114878Sjulian struct rfcomm_mcc_pn *pn = NULL; 3152114878Sjulian 3153114878Sjulian mtx_assert(&pcb->session->session_mtx, MA_OWNED); 3154114878Sjulian mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3155114878Sjulian 3156243882Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 3157114878Sjulian if (m == NULL) 3158114878Sjulian return (ENOBUFS); 3159114878Sjulian 3160114878Sjulian m->m_pkthdr.len = m->m_len = sizeof(*hdr) + sizeof(*pn); 3161114878Sjulian 3162114878Sjulian hdr = mtod(m, struct rfcomm_mcc_hdr *); 3163114878Sjulian pn = (struct rfcomm_mcc_pn *)(hdr + 1); 3164114878Sjulian 3165114878Sjulian hdr->type = RFCOMM_MKMCC_TYPE(1, RFCOMM_MCC_PN); 3166114878Sjulian hdr->length = RFCOMM_MKLEN8(sizeof(*pn)); 3167114878Sjulian 3168114878Sjulian pn->dlci = pcb->dlci; 3169121054Semax 3170121054Semax /* 3171121054Semax * Set default DLCI priority as described in GSM 07.10 3172121054Semax * (ETSI TS 101 369) clause 5.6 page 42 3173121054Semax */ 3174121054Semax 3175121054Semax pn->priority = (pcb->dlci < 56)? (((pcb->dlci >> 3) << 3) + 7) : 61; 3176114878Sjulian pn->ack_timer = 0; 3177114878Sjulian pn->mtu = htole16(pcb->mtu); 3178114878Sjulian pn->max_retrans = 0; 3179114878Sjulian 3180114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) { 3181114878Sjulian pn->flow_control = 0xf0; 3182114878Sjulian pn->credits = pcb->rx_cred; 3183114878Sjulian } else { 3184114878Sjulian pn->flow_control = 0; 3185114878Sjulian pn->credits = 0; 3186114878Sjulian } 3187114878Sjulian 3188114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3189114878Sjulian"%s: Sending PN dlci=%d, state=%d, flags=%#x, mtu=%d, flow_control=%#x, " \ 3190114878Sjulian"credits=%d\n", __func__, pcb->dlci, pcb->state, pcb->flags, pcb->mtu, 3191114878Sjulian pn->flow_control, pn->credits); 3192114878Sjulian 3193114878Sjulian return (ng_btsocket_rfcomm_send_uih(pcb->session, 3194114878Sjulian RFCOMM_MKADDRESS(INITIATOR(pcb->session), 0), 0, 0, m)); 3195114878Sjulian} /* ng_btsocket_rfcomm_send_pn */ 3196114878Sjulian 3197114878Sjulian/* 3198114878Sjulian * Calculate and send credits based on available space in receive buffer 3199114878Sjulian */ 3200114878Sjulian 3201114878Sjulianstatic int 3202114878Sjulianng_btsocket_rfcomm_send_credits(ng_btsocket_rfcomm_pcb_p pcb) 3203114878Sjulian{ 3204114878Sjulian int error = 0; 3205114878Sjulian u_int8_t credits; 3206114878Sjulian 3207114878Sjulian mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3208114878Sjulian mtx_assert(&pcb->session->session_mtx, MA_OWNED); 3209114878Sjulian 3210114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3211114878Sjulian"%s: Sending more credits, dlci=%d, state=%d, flags=%#x, mtu=%d, " \ 3212114878Sjulian"space=%ld, tx_cred=%d, rx_cred=%d\n", 3213114878Sjulian __func__, pcb->dlci, pcb->state, pcb->flags, pcb->mtu, 3214114878Sjulian sbspace(&pcb->so->so_rcv), pcb->tx_cred, pcb->rx_cred); 3215114878Sjulian 3216114878Sjulian credits = sbspace(&pcb->so->so_rcv) / pcb->mtu; 3217114878Sjulian if (credits > 0) { 3218114878Sjulian if (pcb->rx_cred + credits > RFCOMM_MAX_CREDITS) 3219114878Sjulian credits = RFCOMM_MAX_CREDITS - pcb->rx_cred; 3220114878Sjulian 3221114878Sjulian error = ng_btsocket_rfcomm_send_uih( 3222114878Sjulian pcb->session, 3223114878Sjulian RFCOMM_MKADDRESS(INITIATOR(pcb->session), 3224114878Sjulian pcb->dlci), 1, credits, NULL); 3225114878Sjulian if (error == 0) { 3226114878Sjulian pcb->rx_cred += credits; 3227114878Sjulian 3228114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3229114878Sjulian"%s: Gave remote side %d more credits, dlci=%d, state=%d, flags=%#x, " \ 3230114878Sjulian"rx_cred=%d, tx_cred=%d\n", __func__, credits, pcb->dlci, pcb->state, 3231114878Sjulian pcb->flags, pcb->rx_cred, pcb->tx_cred); 3232114878Sjulian } else 3233114878Sjulian NG_BTSOCKET_RFCOMM_ERR( 3234114878Sjulian"%s: Could not send credits, error=%d, dlci=%d, state=%d, flags=%#x, " \ 3235114878Sjulian"mtu=%d, space=%ld, tx_cred=%d, rx_cred=%d\n", 3236114878Sjulian __func__, error, pcb->dlci, pcb->state, 3237114878Sjulian pcb->flags, pcb->mtu, sbspace(&pcb->so->so_rcv), 3238114878Sjulian pcb->tx_cred, pcb->rx_cred); 3239114878Sjulian } 3240114878Sjulian 3241114878Sjulian return (error); 3242114878Sjulian} /* ng_btsocket_rfcomm_send_credits */ 3243114878Sjulian 3244114878Sjulian/***************************************************************************** 3245114878Sjulian ***************************************************************************** 3246114878Sjulian ** RFCOMM DLCs 3247114878Sjulian ***************************************************************************** 3248114878Sjulian *****************************************************************************/ 3249114878Sjulian 3250114878Sjulian/* 3251114878Sjulian * Send data from socket send buffer 3252114878Sjulian * Caller must hold pcb->pcb_mtx and pcb->session->session_mtx 3253114878Sjulian */ 3254114878Sjulian 3255114878Sjulianstatic int 3256114878Sjulianng_btsocket_rfcomm_pcb_send(ng_btsocket_rfcomm_pcb_p pcb, int limit) 3257114878Sjulian{ 3258114878Sjulian struct mbuf *m = NULL; 3259114878Sjulian int sent, length, error; 3260114878Sjulian 3261114878Sjulian mtx_assert(&pcb->session->session_mtx, MA_OWNED); 3262114878Sjulian mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3263114878Sjulian 3264114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) 3265114878Sjulian limit = min(limit, pcb->tx_cred); 3266114878Sjulian else if (!(pcb->rmodem & RFCOMM_MODEM_FC)) 3267114878Sjulian limit = min(limit, RFCOMM_MAX_CREDITS); /* XXX ??? */ 3268114878Sjulian else 3269114878Sjulian limit = 0; 3270114878Sjulian 3271114878Sjulian if (limit == 0) { 3272114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3273114878Sjulian"%s: Could not send - remote flow control asserted, dlci=%d, flags=%#x, " \ 3274114878Sjulian"rmodem=%#x, tx_cred=%d\n", 3275114878Sjulian __func__, pcb->dlci, pcb->flags, pcb->rmodem, 3276114878Sjulian pcb->tx_cred); 3277114878Sjulian 3278114878Sjulian return (0); 3279114878Sjulian } 3280114878Sjulian 3281114878Sjulian for (error = 0, sent = 0; sent < limit; sent ++) { 3282114878Sjulian length = min(pcb->mtu, pcb->so->so_snd.sb_cc); 3283114878Sjulian if (length == 0) 3284114878Sjulian break; 3285114878Sjulian 3286114878Sjulian /* Get the chunk from the socket's send buffer */ 3287114878Sjulian m = ng_btsocket_rfcomm_prepare_packet(&pcb->so->so_snd, length); 3288114878Sjulian if (m == NULL) { 3289114878Sjulian error = ENOBUFS; 3290114878Sjulian break; 3291114878Sjulian } 3292114878Sjulian 3293114878Sjulian sbdrop(&pcb->so->so_snd, length); 3294114878Sjulian 3295114878Sjulian error = ng_btsocket_rfcomm_send_uih(pcb->session, 3296114878Sjulian RFCOMM_MKADDRESS(INITIATOR(pcb->session), 3297114878Sjulian pcb->dlci), 0, 0, m); 3298114878Sjulian if (error != 0) 3299114878Sjulian break; 3300114878Sjulian } 3301114878Sjulian 3302114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) 3303114878Sjulian pcb->tx_cred -= sent; 3304114878Sjulian 3305114878Sjulian if (error == 0 && sent > 0) { 3306114878Sjulian pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_SENDING; 3307114878Sjulian sowwakeup(pcb->so); 3308114878Sjulian } 3309114878Sjulian 3310114878Sjulian return (error); 3311114878Sjulian} /* ng_btsocket_rfcomm_pcb_send */ 3312114878Sjulian 3313114878Sjulian/* 3314114878Sjulian * Unlink and disconnect DLC. If ng_btsocket_rfcomm_pcb_kill() returns 3315114878Sjulian * non zero value than socket has no reference and has to be detached. 3316114878Sjulian * Caller must hold pcb->pcb_mtx and pcb->session->session_mtx 3317114878Sjulian */ 3318114878Sjulian 3319161623Semaxstatic void 3320114878Sjulianng_btsocket_rfcomm_pcb_kill(ng_btsocket_rfcomm_pcb_p pcb, int error) 3321114878Sjulian{ 3322114878Sjulian ng_btsocket_rfcomm_session_p s = pcb->session; 3323114878Sjulian 3324114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3325114878Sjulian"%s: Killing DLC, so=%p, dlci=%d, state=%d, flags=%#x, error=%d\n", 3326114878Sjulian __func__, pcb->so, pcb->dlci, pcb->state, pcb->flags, error); 3327114878Sjulian 3328114878Sjulian if (pcb->session == NULL) 3329114878Sjulian panic("%s: DLC without session, pcb=%p, state=%d, flags=%#x\n", 3330114878Sjulian __func__, pcb, pcb->state, pcb->flags); 3331114878Sjulian 3332142542Ssam mtx_assert(&pcb->session->session_mtx, MA_OWNED); 3333142542Ssam mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3334142542Ssam 3335114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO) 3336114878Sjulian ng_btsocket_rfcomm_untimeout(pcb); 3337114878Sjulian 3338114878Sjulian /* Detach DLC from the session. Does not matter which state DLC in */ 3339114878Sjulian LIST_REMOVE(pcb, session_next); 3340114878Sjulian pcb->session = NULL; 3341114878Sjulian 3342114878Sjulian /* Change DLC state and wakeup all sleepers */ 3343114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_CLOSED; 3344114878Sjulian pcb->so->so_error = error; 3345114878Sjulian soisdisconnected(pcb->so); 3346114878Sjulian wakeup(&pcb->state); 3347114878Sjulian 3348114878Sjulian /* Check if we have any DLCs left on the session */ 3349114878Sjulian if (LIST_EMPTY(&s->dlcs) && INITIATOR(s)) { 3350114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3351114878Sjulian"%s: Disconnecting session, state=%d, flags=%#x, mtu=%d\n", 3352114878Sjulian __func__, s->state, s->flags, s->mtu); 3353114878Sjulian 3354114878Sjulian switch (s->state) { 3355114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CLOSED: 3356114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING: 3357114878Sjulian /* 3358114878Sjulian * Do not have to do anything here. We can get here 3359114878Sjulian * when L2CAP connection was terminated or we have 3360114878Sjulian * received DISC on multiplexor channel 3361114878Sjulian */ 3362114878Sjulian break; 3363114878Sjulian 3364114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_OPEN: 3365114878Sjulian /* Send DISC on multiplexor channel */ 3366114878Sjulian error = ng_btsocket_rfcomm_send_command(s, 3367114878Sjulian RFCOMM_FRAME_DISC, 0); 3368114878Sjulian if (error == 0) { 3369114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING; 3370114878Sjulian break; 3371114878Sjulian } 3372114878Sjulian /* FALL THROUGH */ 3373114878Sjulian 3374114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CONNECTING: 3375114878Sjulian case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED: 3376114878Sjulian s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 3377114878Sjulian break; 3378114878Sjulian 3379114878Sjulian/* case NG_BTSOCKET_RFCOMM_SESSION_LISTENING: */ 3380114878Sjulian default: 3381114878Sjulian panic("%s: Invalid session state=%d, flags=%#x\n", 3382114878Sjulian __func__, s->state, s->flags); 3383114878Sjulian break; 3384114878Sjulian } 3385114878Sjulian 3386114878Sjulian ng_btsocket_rfcomm_task_wakeup(); 3387114878Sjulian } 3388114878Sjulian} /* ng_btsocket_rfcomm_pcb_kill */ 3389114878Sjulian 3390114878Sjulian/* 3391114878Sjulian * Look for given dlci for given RFCOMM session. Caller must hold s->session_mtx 3392114878Sjulian */ 3393114878Sjulian 3394114878Sjulianstatic ng_btsocket_rfcomm_pcb_p 3395114878Sjulianng_btsocket_rfcomm_pcb_by_dlci(ng_btsocket_rfcomm_session_p s, int dlci) 3396114878Sjulian{ 3397114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = NULL; 3398114878Sjulian 3399114878Sjulian mtx_assert(&s->session_mtx, MA_OWNED); 3400114878Sjulian 3401114878Sjulian LIST_FOREACH(pcb, &s->dlcs, session_next) 3402114878Sjulian if (pcb->dlci == dlci) 3403114878Sjulian break; 3404114878Sjulian 3405114878Sjulian return (pcb); 3406114878Sjulian} /* ng_btsocket_rfcomm_pcb_by_dlci */ 3407114878Sjulian 3408114878Sjulian/* 3409114878Sjulian * Look for socket that listens on given src address and given channel 3410114878Sjulian */ 3411114878Sjulian 3412114878Sjulianstatic ng_btsocket_rfcomm_pcb_p 3413114878Sjulianng_btsocket_rfcomm_pcb_listener(bdaddr_p src, int channel) 3414114878Sjulian{ 3415114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb1 = NULL; 3416114878Sjulian 3417114878Sjulian mtx_lock(&ng_btsocket_rfcomm_sockets_mtx); 3418114878Sjulian 3419114878Sjulian LIST_FOREACH(pcb, &ng_btsocket_rfcomm_sockets, next) { 3420114878Sjulian if (pcb->channel != channel || 3421114878Sjulian !(pcb->so->so_options & SO_ACCEPTCONN)) 3422114878Sjulian continue; 3423114878Sjulian 3424114878Sjulian if (bcmp(&pcb->src, src, sizeof(*src)) == 0) 3425114878Sjulian break; 3426114878Sjulian 3427114878Sjulian if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) 3428114878Sjulian pcb1 = pcb; 3429114878Sjulian } 3430114878Sjulian 3431114878Sjulian mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 3432114878Sjulian 3433114878Sjulian return ((pcb != NULL)? pcb : pcb1); 3434114878Sjulian} /* ng_btsocket_rfcomm_pcb_listener */ 3435114878Sjulian 3436114878Sjulian/***************************************************************************** 3437114878Sjulian ***************************************************************************** 3438114878Sjulian ** Misc. functions 3439114878Sjulian ***************************************************************************** 3440114878Sjulian *****************************************************************************/ 3441114878Sjulian 3442114878Sjulian/* 3443114878Sjulian * Set timeout. Caller MUST hold pcb_mtx 3444114878Sjulian */ 3445114878Sjulian 3446114878Sjulianstatic void 3447114878Sjulianng_btsocket_rfcomm_timeout(ng_btsocket_rfcomm_pcb_p pcb) 3448114878Sjulian{ 3449114878Sjulian mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3450114878Sjulian 3451114878Sjulian if (!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)) { 3452114878Sjulian pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_TIMO; 3453114878Sjulian pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT; 3454114878Sjulian pcb->timo = timeout(ng_btsocket_rfcomm_process_timeout, pcb, 3455114878Sjulian ng_btsocket_rfcomm_timo * hz); 3456114878Sjulian } else 3457114878Sjulian panic("%s: Duplicated socket timeout?!\n", __func__); 3458114878Sjulian} /* ng_btsocket_rfcomm_timeout */ 3459114878Sjulian 3460114878Sjulian/* 3461114878Sjulian * Unset pcb timeout. Caller MUST hold pcb_mtx 3462114878Sjulian */ 3463114878Sjulian 3464114878Sjulianstatic void 3465114878Sjulianng_btsocket_rfcomm_untimeout(ng_btsocket_rfcomm_pcb_p pcb) 3466114878Sjulian{ 3467114878Sjulian mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3468114878Sjulian 3469114878Sjulian if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO) { 3470114878Sjulian untimeout(ng_btsocket_rfcomm_process_timeout, pcb, pcb->timo); 3471114878Sjulian pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMO; 3472114878Sjulian pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT; 3473114878Sjulian } else 3474114878Sjulian panic("%s: No socket timeout?!\n", __func__); 3475114878Sjulian} /* ng_btsocket_rfcomm_timeout */ 3476114878Sjulian 3477114878Sjulian/* 3478114878Sjulian * Process pcb timeout 3479114878Sjulian */ 3480114878Sjulian 3481114878Sjulianstatic void 3482114878Sjulianng_btsocket_rfcomm_process_timeout(void *xpcb) 3483114878Sjulian{ 3484114878Sjulian ng_btsocket_rfcomm_pcb_p pcb = (ng_btsocket_rfcomm_pcb_p) xpcb; 3485114878Sjulian 3486114878Sjulian mtx_lock(&pcb->pcb_mtx); 3487114878Sjulian 3488114878Sjulian NG_BTSOCKET_RFCOMM_INFO( 3489114878Sjulian"%s: Timeout, so=%p, dlci=%d, state=%d, flags=%#x\n", 3490114878Sjulian __func__, pcb->so, pcb->dlci, pcb->state, pcb->flags); 3491114878Sjulian 3492114878Sjulian pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMO; 3493114878Sjulian pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT; 3494114878Sjulian 3495114878Sjulian switch (pcb->state) { 3496114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING: 3497114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_CONNECTING: 3498114878Sjulian pcb->state = NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING; 3499114878Sjulian break; 3500114878Sjulian 3501114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT: 3502114878Sjulian case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING: 3503114878Sjulian break; 3504114878Sjulian 3505114878Sjulian default: 3506114878Sjulian panic( 3507114878Sjulian"%s: DLC timeout in invalid state, dlci=%d, state=%d, flags=%#x\n", 3508114878Sjulian __func__, pcb->dlci, pcb->state, pcb->flags); 3509114878Sjulian break; 3510114878Sjulian } 3511114878Sjulian 3512114878Sjulian ng_btsocket_rfcomm_task_wakeup(); 3513114878Sjulian 3514114878Sjulian mtx_unlock(&pcb->pcb_mtx); 3515114878Sjulian} /* ng_btsocket_rfcomm_process_timeout */ 3516114878Sjulian 3517114878Sjulian/* 3518114878Sjulian * Get up to length bytes from the socket buffer 3519114878Sjulian */ 3520114878Sjulian 3521114878Sjulianstatic struct mbuf * 3522114878Sjulianng_btsocket_rfcomm_prepare_packet(struct sockbuf *sb, int length) 3523114878Sjulian{ 3524114878Sjulian struct mbuf *top = NULL, *m = NULL, *n = NULL, *nextpkt = NULL; 3525114878Sjulian int mlen, noff, len; 3526114878Sjulian 3527243882Sglebius MGETHDR(top, M_NOWAIT, MT_DATA); 3528114878Sjulian if (top == NULL) 3529114878Sjulian return (NULL); 3530114878Sjulian 3531114878Sjulian top->m_pkthdr.len = length; 3532114878Sjulian top->m_len = 0; 3533114878Sjulian mlen = MHLEN; 3534114878Sjulian 3535114878Sjulian m = top; 3536114878Sjulian n = sb->sb_mb; 3537114878Sjulian nextpkt = n->m_nextpkt; 3538114878Sjulian noff = 0; 3539114878Sjulian 3540114878Sjulian while (length > 0 && n != NULL) { 3541114878Sjulian len = min(mlen - m->m_len, n->m_len - noff); 3542114878Sjulian if (len > length) 3543114878Sjulian len = length; 3544114878Sjulian 3545114878Sjulian bcopy(mtod(n, caddr_t)+noff, mtod(m, caddr_t)+m->m_len, len); 3546114878Sjulian m->m_len += len; 3547114878Sjulian noff += len; 3548114878Sjulian length -= len; 3549114878Sjulian 3550114878Sjulian if (length > 0 && m->m_len == mlen) { 3551243882Sglebius MGET(m->m_next, M_NOWAIT, MT_DATA); 3552114878Sjulian if (m->m_next == NULL) { 3553114878Sjulian NG_FREE_M(top); 3554114878Sjulian return (NULL); 3555114878Sjulian } 3556114878Sjulian 3557114878Sjulian m = m->m_next; 3558114878Sjulian m->m_len = 0; 3559114878Sjulian mlen = MLEN; 3560114878Sjulian } 3561114878Sjulian 3562114878Sjulian if (noff == n->m_len) { 3563114878Sjulian noff = 0; 3564114878Sjulian n = n->m_next; 3565114878Sjulian 3566114878Sjulian if (n == NULL) 3567114878Sjulian n = nextpkt; 3568114878Sjulian 3569114878Sjulian nextpkt = (n != NULL)? n->m_nextpkt : NULL; 3570114878Sjulian } 3571114878Sjulian } 3572114878Sjulian 3573114878Sjulian if (length < 0) 3574114878Sjulian panic("%s: length=%d\n", __func__, length); 3575114878Sjulian if (length > 0 && n == NULL) 3576114878Sjulian panic("%s: bogus length=%d, n=%p\n", __func__, length, n); 3577114878Sjulian 3578114878Sjulian return (top); 3579114878Sjulian} /* ng_btsocket_rfcomm_prepare_packet */ 3580114878Sjulian 3581