1f2bb1caeSJulian Elischer /* 2f2bb1caeSJulian Elischer * ng_btsocket_rfcomm.c 3c398230bSWarner Losh */ 4c398230bSWarner Losh 5c398230bSWarner Losh /*- 6fe267a55SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 7fe267a55SPedro F. Giffuni * 8f2bb1caeSJulian Elischer * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> 9f2bb1caeSJulian Elischer * All rights reserved. 10f2bb1caeSJulian Elischer * 11f2bb1caeSJulian Elischer * Redistribution and use in source and binary forms, with or without 12f2bb1caeSJulian Elischer * modification, are permitted provided that the following conditions 13f2bb1caeSJulian Elischer * are met: 14f2bb1caeSJulian Elischer * 1. Redistributions of source code must retain the above copyright 15f2bb1caeSJulian Elischer * notice, this list of conditions and the following disclaimer. 16f2bb1caeSJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 17f2bb1caeSJulian Elischer * notice, this list of conditions and the following disclaimer in the 18f2bb1caeSJulian Elischer * documentation and/or other materials provided with the distribution. 19f2bb1caeSJulian Elischer * 20f2bb1caeSJulian Elischer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21f2bb1caeSJulian Elischer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22f2bb1caeSJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23f2bb1caeSJulian Elischer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24f2bb1caeSJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25f2bb1caeSJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26f2bb1caeSJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27f2bb1caeSJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28f2bb1caeSJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29f2bb1caeSJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30f2bb1caeSJulian Elischer * SUCH DAMAGE. 31f2bb1caeSJulian Elischer * 320986ab12SMaksim Yevmenkin * $Id: ng_btsocket_rfcomm.c,v 1.28 2003/09/14 23:29:06 max Exp $ 33f2bb1caeSJulian Elischer * $FreeBSD$ 34f2bb1caeSJulian Elischer */ 35f2bb1caeSJulian Elischer 36f2bb1caeSJulian Elischer #include <sys/param.h> 37f2bb1caeSJulian Elischer #include <sys/systm.h> 380986ab12SMaksim Yevmenkin #include <sys/bitstring.h> 39f2bb1caeSJulian Elischer #include <sys/domain.h> 40f2bb1caeSJulian Elischer #include <sys/endian.h> 41f2bb1caeSJulian Elischer #include <sys/errno.h> 42f2bb1caeSJulian Elischer #include <sys/filedesc.h> 43f2bb1caeSJulian Elischer #include <sys/ioccom.h> 44f2bb1caeSJulian Elischer #include <sys/kernel.h> 45f2bb1caeSJulian Elischer #include <sys/lock.h> 46f2bb1caeSJulian Elischer #include <sys/malloc.h> 47f2bb1caeSJulian Elischer #include <sys/mbuf.h> 48f2bb1caeSJulian Elischer #include <sys/mutex.h> 49f2bb1caeSJulian Elischer #include <sys/proc.h> 50f2bb1caeSJulian Elischer #include <sys/protosw.h> 51f2bb1caeSJulian Elischer #include <sys/queue.h> 52f2bb1caeSJulian Elischer #include <sys/socket.h> 53f2bb1caeSJulian Elischer #include <sys/socketvar.h> 54f2bb1caeSJulian Elischer #include <sys/sysctl.h> 55f2bb1caeSJulian Elischer #include <sys/taskqueue.h> 56f2bb1caeSJulian Elischer #include <sys/uio.h> 571fb51a12SBjoern A. Zeeb 581fb51a12SBjoern A. Zeeb #include <net/vnet.h> 591fb51a12SBjoern A. Zeeb 60f2bb1caeSJulian Elischer #include <netgraph/ng_message.h> 61f2bb1caeSJulian Elischer #include <netgraph/netgraph.h> 62b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_bluetooth.h> 63b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_hci.h> 64b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_l2cap.h> 65b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_btsocket.h> 66b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_btsocket_l2cap.h> 67b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_btsocket_rfcomm.h> 68f2bb1caeSJulian Elischer 69f2bb1caeSJulian Elischer /* MALLOC define */ 70f2bb1caeSJulian Elischer #ifdef NG_SEPARATE_MALLOC 71d745c852SEd Schouten static MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_RFCOMM, "netgraph_btsocks_rfcomm", 72f2bb1caeSJulian Elischer "Netgraph Bluetooth RFCOMM sockets"); 73f2bb1caeSJulian Elischer #else 74f2bb1caeSJulian Elischer #define M_NETGRAPH_BTSOCKET_RFCOMM M_NETGRAPH 75f2bb1caeSJulian Elischer #endif /* NG_SEPARATE_MALLOC */ 76f2bb1caeSJulian Elischer 77f2bb1caeSJulian Elischer /* Debug */ 78f2bb1caeSJulian Elischer #define NG_BTSOCKET_RFCOMM_INFO \ 794fa708efSMaksim Yevmenkin if (ng_btsocket_rfcomm_debug_level >= NG_BTSOCKET_INFO_LEVEL && \ 804fa708efSMaksim Yevmenkin ppsratecheck(&ng_btsocket_rfcomm_lasttime, &ng_btsocket_rfcomm_curpps, 1)) \ 81f2bb1caeSJulian Elischer printf 82f2bb1caeSJulian Elischer 83f2bb1caeSJulian Elischer #define NG_BTSOCKET_RFCOMM_WARN \ 844fa708efSMaksim Yevmenkin if (ng_btsocket_rfcomm_debug_level >= NG_BTSOCKET_WARN_LEVEL && \ 854fa708efSMaksim Yevmenkin ppsratecheck(&ng_btsocket_rfcomm_lasttime, &ng_btsocket_rfcomm_curpps, 1)) \ 86f2bb1caeSJulian Elischer printf 87f2bb1caeSJulian Elischer 88f2bb1caeSJulian Elischer #define NG_BTSOCKET_RFCOMM_ERR \ 894fa708efSMaksim Yevmenkin if (ng_btsocket_rfcomm_debug_level >= NG_BTSOCKET_ERR_LEVEL && \ 904fa708efSMaksim Yevmenkin ppsratecheck(&ng_btsocket_rfcomm_lasttime, &ng_btsocket_rfcomm_curpps, 1)) \ 91f2bb1caeSJulian Elischer printf 92f2bb1caeSJulian Elischer 93f2bb1caeSJulian Elischer #define NG_BTSOCKET_RFCOMM_ALERT \ 944fa708efSMaksim Yevmenkin if (ng_btsocket_rfcomm_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \ 954fa708efSMaksim Yevmenkin ppsratecheck(&ng_btsocket_rfcomm_lasttime, &ng_btsocket_rfcomm_curpps, 1)) \ 96f2bb1caeSJulian Elischer printf 97f2bb1caeSJulian Elischer 98f2bb1caeSJulian Elischer #define ALOT 0x7fff 99f2bb1caeSJulian Elischer 100f2bb1caeSJulian Elischer /* Local prototypes */ 10174fb0ba7SJohn Baldwin static int ng_btsocket_rfcomm_upcall 102f2bb1caeSJulian Elischer (struct socket *so, void *arg, int waitflag); 103f2bb1caeSJulian Elischer static void ng_btsocket_rfcomm_sessions_task 104f2bb1caeSJulian Elischer (void *ctx, int pending); 105f2bb1caeSJulian Elischer static void ng_btsocket_rfcomm_session_task 106f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s); 107f2bb1caeSJulian Elischer #define ng_btsocket_rfcomm_task_wakeup() \ 108f2bb1caeSJulian Elischer taskqueue_enqueue(taskqueue_swi_giant, &ng_btsocket_rfcomm_task) 109f2bb1caeSJulian Elischer 110f2bb1caeSJulian Elischer static ng_btsocket_rfcomm_pcb_p ng_btsocket_rfcomm_connect_ind 111f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s, int channel); 112f2bb1caeSJulian Elischer static void ng_btsocket_rfcomm_connect_cfm 113f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s); 114f2bb1caeSJulian Elischer 115f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_session_create 116f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p *sp, struct socket *l2so, 117f2bb1caeSJulian Elischer bdaddr_p src, bdaddr_p dst, struct thread *td); 118f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_session_accept 119f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s0); 120f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_session_connect 121f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s); 122f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_session_receive 123f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s); 124f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_session_send 125f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s); 126f2bb1caeSJulian Elischer static void ng_btsocket_rfcomm_session_clean 127f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s); 128f2bb1caeSJulian Elischer static void ng_btsocket_rfcomm_session_process_pcb 129f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s); 130f2bb1caeSJulian Elischer static ng_btsocket_rfcomm_session_p ng_btsocket_rfcomm_session_by_addr 131f2bb1caeSJulian Elischer (bdaddr_p src, bdaddr_p dst); 132f2bb1caeSJulian Elischer 133f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_receive_frame 134f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s, struct mbuf *m0); 135f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_receive_sabm 136f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s, int dlci); 137f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_receive_disc 138f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s, int dlci); 139f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_receive_ua 140f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s, int dlci); 141f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_receive_dm 142f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s, int dlci); 143f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_receive_uih 144f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s, int dlci, int pf, struct mbuf *m0); 145f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_receive_mcc 146f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s, struct mbuf *m0); 147f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_receive_test 148f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s, struct mbuf *m0); 149f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_receive_fc 150f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s, struct mbuf *m0); 151f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_receive_msc 152f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s, struct mbuf *m0); 153f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_receive_rpn 154f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s, struct mbuf *m0); 155f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_receive_rls 156f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s, struct mbuf *m0); 157f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_receive_pn 158f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s, struct mbuf *m0); 159f2bb1caeSJulian Elischer static void ng_btsocket_rfcomm_set_pn 160f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_pcb_p pcb, u_int8_t cr, u_int8_t flow_control, 161f2bb1caeSJulian Elischer u_int8_t credits, u_int16_t mtu); 162f2bb1caeSJulian Elischer 163f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_send_command 164f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s, u_int8_t type, u_int8_t dlci); 165f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_send_uih 166f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s, u_int8_t address, u_int8_t pf, 167f2bb1caeSJulian Elischer u_int8_t credits, struct mbuf *data); 168f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_send_msc 169f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_pcb_p pcb); 170f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_send_pn 171f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_pcb_p pcb); 172f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_send_credits 173f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_pcb_p pcb); 174f2bb1caeSJulian Elischer 175f2bb1caeSJulian Elischer static int ng_btsocket_rfcomm_pcb_send 176f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_pcb_p pcb, int limit); 1777c380856SMaksim Yevmenkin static void ng_btsocket_rfcomm_pcb_kill 178f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_pcb_p pcb, int error); 179f2bb1caeSJulian Elischer static ng_btsocket_rfcomm_pcb_p ng_btsocket_rfcomm_pcb_by_dlci 180f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_session_p s, int dlci); 181f2bb1caeSJulian Elischer static ng_btsocket_rfcomm_pcb_p ng_btsocket_rfcomm_pcb_listener 182f2bb1caeSJulian Elischer (bdaddr_p src, int channel); 183f2bb1caeSJulian Elischer 184f2bb1caeSJulian Elischer static void ng_btsocket_rfcomm_timeout 185f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_pcb_p pcb); 186f2bb1caeSJulian Elischer static void ng_btsocket_rfcomm_untimeout 187f2bb1caeSJulian Elischer (ng_btsocket_rfcomm_pcb_p pcb); 188f2bb1caeSJulian Elischer static void ng_btsocket_rfcomm_process_timeout 189f2bb1caeSJulian Elischer (void *xpcb); 190f2bb1caeSJulian Elischer 191f2bb1caeSJulian Elischer static struct mbuf * ng_btsocket_rfcomm_prepare_packet 192f2bb1caeSJulian Elischer (struct sockbuf *sb, int length); 193f2bb1caeSJulian Elischer 194f2bb1caeSJulian Elischer /* Globals */ 195f2bb1caeSJulian Elischer extern int ifqmaxlen; 196f2bb1caeSJulian Elischer static u_int32_t ng_btsocket_rfcomm_debug_level; 197f2bb1caeSJulian Elischer static u_int32_t ng_btsocket_rfcomm_timo; 198f2bb1caeSJulian Elischer struct task ng_btsocket_rfcomm_task; 199f2bb1caeSJulian Elischer static LIST_HEAD(, ng_btsocket_rfcomm_session) ng_btsocket_rfcomm_sessions; 200f2bb1caeSJulian Elischer static struct mtx ng_btsocket_rfcomm_sessions_mtx; 201f2bb1caeSJulian Elischer static LIST_HEAD(, ng_btsocket_rfcomm_pcb) ng_btsocket_rfcomm_sockets; 202f2bb1caeSJulian Elischer static struct mtx ng_btsocket_rfcomm_sockets_mtx; 2034fa708efSMaksim Yevmenkin static struct timeval ng_btsocket_rfcomm_lasttime; 2044fa708efSMaksim Yevmenkin static int ng_btsocket_rfcomm_curpps; 205f2bb1caeSJulian Elischer 206f2bb1caeSJulian Elischer /* Sysctl tree */ 207f2bb1caeSJulian Elischer SYSCTL_DECL(_net_bluetooth_rfcomm_sockets); 2087029da5cSPawel Biernacki static SYSCTL_NODE(_net_bluetooth_rfcomm_sockets, OID_AUTO, stream, 2097029da5cSPawel Biernacki CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 2107029da5cSPawel Biernacki "Bluetooth STREAM RFCOMM sockets family"); 211f29fc085SMatthew D Fleming SYSCTL_UINT(_net_bluetooth_rfcomm_sockets_stream, OID_AUTO, debug_level, 212f2bb1caeSJulian Elischer CTLFLAG_RW, 213f2bb1caeSJulian Elischer &ng_btsocket_rfcomm_debug_level, NG_BTSOCKET_INFO_LEVEL, 214f2bb1caeSJulian Elischer "Bluetooth STREAM RFCOMM sockets debug level"); 215f29fc085SMatthew D Fleming SYSCTL_UINT(_net_bluetooth_rfcomm_sockets_stream, OID_AUTO, timeout, 216f2bb1caeSJulian Elischer CTLFLAG_RW, 217f2bb1caeSJulian Elischer &ng_btsocket_rfcomm_timo, 60, 218f2bb1caeSJulian Elischer "Bluetooth STREAM RFCOMM sockets timeout"); 219f2bb1caeSJulian Elischer 220f2bb1caeSJulian Elischer /***************************************************************************** 221f2bb1caeSJulian Elischer ***************************************************************************** 222f2bb1caeSJulian Elischer ** RFCOMM CRC 223f2bb1caeSJulian Elischer ***************************************************************************** 224f2bb1caeSJulian Elischer *****************************************************************************/ 225f2bb1caeSJulian Elischer 226f2bb1caeSJulian Elischer static u_int8_t ng_btsocket_rfcomm_crc_table[256] = { 227f2bb1caeSJulian Elischer 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75, 228f2bb1caeSJulian Elischer 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b, 229f2bb1caeSJulian Elischer 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69, 230f2bb1caeSJulian Elischer 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67, 231f2bb1caeSJulian Elischer 232f2bb1caeSJulian Elischer 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d, 233f2bb1caeSJulian Elischer 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43, 234f2bb1caeSJulian Elischer 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51, 235f2bb1caeSJulian Elischer 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f, 236f2bb1caeSJulian Elischer 237f2bb1caeSJulian Elischer 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05, 238f2bb1caeSJulian Elischer 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b, 239f2bb1caeSJulian Elischer 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19, 240f2bb1caeSJulian Elischer 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17, 241f2bb1caeSJulian Elischer 242f2bb1caeSJulian Elischer 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d, 243f2bb1caeSJulian Elischer 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33, 244f2bb1caeSJulian Elischer 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21, 245f2bb1caeSJulian Elischer 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f, 246f2bb1caeSJulian Elischer 247f2bb1caeSJulian Elischer 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95, 248f2bb1caeSJulian Elischer 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b, 249f2bb1caeSJulian Elischer 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89, 250f2bb1caeSJulian Elischer 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87, 251f2bb1caeSJulian Elischer 252f2bb1caeSJulian Elischer 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad, 253f2bb1caeSJulian Elischer 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3, 254f2bb1caeSJulian Elischer 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1, 255f2bb1caeSJulian Elischer 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf, 256f2bb1caeSJulian Elischer 257f2bb1caeSJulian Elischer 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5, 258f2bb1caeSJulian Elischer 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb, 259f2bb1caeSJulian Elischer 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9, 260f2bb1caeSJulian Elischer 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7, 261f2bb1caeSJulian Elischer 262f2bb1caeSJulian Elischer 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd, 263f2bb1caeSJulian Elischer 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3, 264f2bb1caeSJulian Elischer 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1, 265f2bb1caeSJulian Elischer 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf 266f2bb1caeSJulian Elischer }; 267f2bb1caeSJulian Elischer 268f2bb1caeSJulian Elischer /* CRC */ 269f2bb1caeSJulian Elischer static u_int8_t 270f2bb1caeSJulian Elischer ng_btsocket_rfcomm_crc(u_int8_t *data, int length) 271f2bb1caeSJulian Elischer { 272f2bb1caeSJulian Elischer u_int8_t crc = 0xff; 273f2bb1caeSJulian Elischer 274f2bb1caeSJulian Elischer while (length --) 275f2bb1caeSJulian Elischer crc = ng_btsocket_rfcomm_crc_table[crc ^ *data++]; 276f2bb1caeSJulian Elischer 277f2bb1caeSJulian Elischer return (crc); 278f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_crc */ 279f2bb1caeSJulian Elischer 280f2bb1caeSJulian Elischer /* FCS on 2 bytes */ 281f2bb1caeSJulian Elischer static u_int8_t 282f2bb1caeSJulian Elischer ng_btsocket_rfcomm_fcs2(u_int8_t *data) 283f2bb1caeSJulian Elischer { 284f2bb1caeSJulian Elischer return (0xff - ng_btsocket_rfcomm_crc(data, 2)); 285f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_fcs2 */ 286f2bb1caeSJulian Elischer 287f2bb1caeSJulian Elischer /* FCS on 3 bytes */ 288f2bb1caeSJulian Elischer static u_int8_t 289f2bb1caeSJulian Elischer ng_btsocket_rfcomm_fcs3(u_int8_t *data) 290f2bb1caeSJulian Elischer { 291f2bb1caeSJulian Elischer return (0xff - ng_btsocket_rfcomm_crc(data, 3)); 292f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_fcs3 */ 293f2bb1caeSJulian Elischer 294f2bb1caeSJulian Elischer /* 295f2bb1caeSJulian Elischer * Check FCS 296f2bb1caeSJulian Elischer * 297f2bb1caeSJulian Elischer * From Bluetooth spec 298f2bb1caeSJulian Elischer * 299f2bb1caeSJulian Elischer * "... In 07.10, the frame check sequence (FCS) is calculated on different 300f2bb1caeSJulian Elischer * sets of fields for different frame types. These are the fields that the 301f2bb1caeSJulian Elischer * FCS are calculated on: 302f2bb1caeSJulian Elischer * 303f2bb1caeSJulian Elischer * For SABM, DISC, UA, DM frames: on Address, Control and length field. 304f2bb1caeSJulian Elischer * For UIH frames: on Address and Control field. 305f2bb1caeSJulian Elischer * 306f2bb1caeSJulian Elischer * (This is stated here for clarification, and to set the standard for RFCOMM; 307f2bb1caeSJulian Elischer * the fields included in FCS calculation have actually changed in version 308f2bb1caeSJulian Elischer * 7.0.0 of TS 07.10, but RFCOMM will not change the FCS calculation scheme 309f2bb1caeSJulian Elischer * from the one above.) ..." 310f2bb1caeSJulian Elischer */ 311f2bb1caeSJulian Elischer 312f2bb1caeSJulian Elischer static int 313f2bb1caeSJulian Elischer ng_btsocket_rfcomm_check_fcs(u_int8_t *data, int type, u_int8_t fcs) 314f2bb1caeSJulian Elischer { 315f2bb1caeSJulian Elischer if (type != RFCOMM_FRAME_UIH) 316f2bb1caeSJulian Elischer return (ng_btsocket_rfcomm_fcs3(data) != fcs); 317f2bb1caeSJulian Elischer 318f2bb1caeSJulian Elischer return (ng_btsocket_rfcomm_fcs2(data) != fcs); 319f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_check_fcs */ 320f2bb1caeSJulian Elischer 321f2bb1caeSJulian Elischer /***************************************************************************** 322f2bb1caeSJulian Elischer ***************************************************************************** 323f2bb1caeSJulian Elischer ** Socket interface 324f2bb1caeSJulian Elischer ***************************************************************************** 325f2bb1caeSJulian Elischer *****************************************************************************/ 326f2bb1caeSJulian Elischer 327f2bb1caeSJulian Elischer /* 328f2bb1caeSJulian Elischer * Initialize everything 329f2bb1caeSJulian Elischer */ 330f2bb1caeSJulian Elischer 331f2bb1caeSJulian Elischer void 332f2bb1caeSJulian Elischer ng_btsocket_rfcomm_init(void) 333f2bb1caeSJulian Elischer { 3344a8e4eb5SMikolaj Golub 3354a8e4eb5SMikolaj Golub /* Skip initialization of globals for non-default instances. */ 3364a8e4eb5SMikolaj Golub if (!IS_DEFAULT_VNET(curvnet)) 3374a8e4eb5SMikolaj Golub return; 3384a8e4eb5SMikolaj Golub 339f2bb1caeSJulian Elischer ng_btsocket_rfcomm_debug_level = NG_BTSOCKET_WARN_LEVEL; 340f2bb1caeSJulian Elischer ng_btsocket_rfcomm_timo = 60; 341f2bb1caeSJulian Elischer 342f2bb1caeSJulian Elischer /* RFCOMM task */ 343f2bb1caeSJulian Elischer TASK_INIT(&ng_btsocket_rfcomm_task, 0, 344f2bb1caeSJulian Elischer ng_btsocket_rfcomm_sessions_task, NULL); 345f2bb1caeSJulian Elischer 346f2bb1caeSJulian Elischer /* RFCOMM sessions list */ 347f2bb1caeSJulian Elischer LIST_INIT(&ng_btsocket_rfcomm_sessions); 348f2bb1caeSJulian Elischer mtx_init(&ng_btsocket_rfcomm_sessions_mtx, 349f2bb1caeSJulian Elischer "btsocks_rfcomm_sessions_mtx", NULL, MTX_DEF); 350f2bb1caeSJulian Elischer 351f2bb1caeSJulian Elischer /* RFCOMM sockets list */ 352f2bb1caeSJulian Elischer LIST_INIT(&ng_btsocket_rfcomm_sockets); 353f2bb1caeSJulian Elischer mtx_init(&ng_btsocket_rfcomm_sockets_mtx, 354f2bb1caeSJulian Elischer "btsocks_rfcomm_sockets_mtx", NULL, MTX_DEF); 355f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_init */ 356f2bb1caeSJulian Elischer 357f2bb1caeSJulian Elischer /* 358f2bb1caeSJulian Elischer * Abort connection on socket 359f2bb1caeSJulian Elischer */ 360f2bb1caeSJulian Elischer 361ac45e92fSRobert Watson void 362f2bb1caeSJulian Elischer ng_btsocket_rfcomm_abort(struct socket *so) 363f2bb1caeSJulian Elischer { 364f2bb1caeSJulian Elischer 365a152f8a3SRobert Watson so->so_error = ECONNABORTED; 366a152f8a3SRobert Watson (void)ng_btsocket_rfcomm_disconnect(so); 367f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_abort */ 368f2bb1caeSJulian Elischer 369a152f8a3SRobert Watson void 370a152f8a3SRobert Watson ng_btsocket_rfcomm_close(struct socket *so) 371a152f8a3SRobert Watson { 372a152f8a3SRobert Watson 373a152f8a3SRobert Watson (void)ng_btsocket_rfcomm_disconnect(so); 374a152f8a3SRobert Watson } /* ng_btsocket_rfcomm_close */ 375a152f8a3SRobert Watson 376f2bb1caeSJulian Elischer /* 377f2bb1caeSJulian Elischer * Accept connection on socket. Nothing to do here, socket must be connected 378f2bb1caeSJulian Elischer * and ready, so just return peer address and be done with it. 379f2bb1caeSJulian Elischer */ 380f2bb1caeSJulian Elischer 381f2bb1caeSJulian Elischer int 382f2bb1caeSJulian Elischer ng_btsocket_rfcomm_accept(struct socket *so, struct sockaddr **nam) 383f2bb1caeSJulian Elischer { 384f2bb1caeSJulian Elischer return (ng_btsocket_rfcomm_peeraddr(so, nam)); 385f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_accept */ 386f2bb1caeSJulian Elischer 387f2bb1caeSJulian Elischer /* 388f2bb1caeSJulian Elischer * Create and attach new socket 389f2bb1caeSJulian Elischer */ 390f2bb1caeSJulian Elischer 391f2bb1caeSJulian Elischer int 392f2bb1caeSJulian Elischer ng_btsocket_rfcomm_attach(struct socket *so, int proto, struct thread *td) 393f2bb1caeSJulian Elischer { 394f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 395f2bb1caeSJulian Elischer int error; 396f2bb1caeSJulian Elischer 397f2bb1caeSJulian Elischer /* Check socket and protocol */ 398f2bb1caeSJulian Elischer if (so->so_type != SOCK_STREAM) 399f2bb1caeSJulian Elischer return (ESOCKTNOSUPPORT); 400f2bb1caeSJulian Elischer 401f2bb1caeSJulian Elischer #if 0 /* XXX sonewconn() calls "pru_attach" with proto == 0 */ 402f2bb1caeSJulian Elischer if (proto != 0) 403f2bb1caeSJulian Elischer if (proto != BLUETOOTH_PROTO_RFCOMM) 404f2bb1caeSJulian Elischer return (EPROTONOSUPPORT); 405f2bb1caeSJulian Elischer #endif /* XXX */ 406f2bb1caeSJulian Elischer 407f2bb1caeSJulian Elischer if (pcb != NULL) 408f2bb1caeSJulian Elischer return (EISCONN); 409f2bb1caeSJulian Elischer 410f2bb1caeSJulian Elischer /* Reserve send and receive space if it is not reserved yet */ 411f2bb1caeSJulian Elischer if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) { 412f2bb1caeSJulian Elischer error = soreserve(so, NG_BTSOCKET_RFCOMM_SENDSPACE, 413f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_RECVSPACE); 414f2bb1caeSJulian Elischer if (error != 0) 415f2bb1caeSJulian Elischer return (error); 416f2bb1caeSJulian Elischer } 417f2bb1caeSJulian Elischer 418f2bb1caeSJulian Elischer /* Allocate the PCB */ 4191ede983cSDag-Erling Smørgrav pcb = malloc(sizeof(*pcb), 420f2bb1caeSJulian Elischer M_NETGRAPH_BTSOCKET_RFCOMM, M_NOWAIT | M_ZERO); 421f2bb1caeSJulian Elischer if (pcb == NULL) 422f2bb1caeSJulian Elischer return (ENOMEM); 423f2bb1caeSJulian Elischer 424f2bb1caeSJulian Elischer /* Link the PCB and the socket */ 425f2bb1caeSJulian Elischer so->so_pcb = (caddr_t) pcb; 426f2bb1caeSJulian Elischer pcb->so = so; 427f2bb1caeSJulian Elischer 428f2bb1caeSJulian Elischer /* Initialize PCB */ 429f2bb1caeSJulian Elischer pcb->state = NG_BTSOCKET_RFCOMM_DLC_CLOSED; 430f2bb1caeSJulian Elischer pcb->flags = NG_BTSOCKET_RFCOMM_DLC_CFC; 431f2bb1caeSJulian Elischer 432f2bb1caeSJulian Elischer pcb->lmodem = 433f2bb1caeSJulian Elischer pcb->rmodem = (RFCOMM_MODEM_RTC | RFCOMM_MODEM_RTR | RFCOMM_MODEM_DV); 434f2bb1caeSJulian Elischer 435f2bb1caeSJulian Elischer pcb->mtu = RFCOMM_DEFAULT_MTU; 436f2bb1caeSJulian Elischer pcb->tx_cred = 0; 437f2bb1caeSJulian Elischer pcb->rx_cred = RFCOMM_DEFAULT_CREDITS; 438f2bb1caeSJulian Elischer 439f2bb1caeSJulian Elischer mtx_init(&pcb->pcb_mtx, "btsocks_rfcomm_pcb_mtx", NULL, MTX_DEF); 4403d1592efSJohn Baldwin callout_init_mtx(&pcb->timo, &pcb->pcb_mtx, 0); 441f2bb1caeSJulian Elischer 442f2bb1caeSJulian Elischer /* Add the PCB to the list */ 443f2bb1caeSJulian Elischer mtx_lock(&ng_btsocket_rfcomm_sockets_mtx); 444f2bb1caeSJulian Elischer LIST_INSERT_HEAD(&ng_btsocket_rfcomm_sockets, pcb, next); 445f2bb1caeSJulian Elischer mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 446f2bb1caeSJulian Elischer 447f2bb1caeSJulian Elischer return (0); 448f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_attach */ 449f2bb1caeSJulian Elischer 450f2bb1caeSJulian Elischer /* 451f2bb1caeSJulian Elischer * Bind socket 452f2bb1caeSJulian Elischer */ 453f2bb1caeSJulian Elischer 454f2bb1caeSJulian Elischer int 455f2bb1caeSJulian Elischer ng_btsocket_rfcomm_bind(struct socket *so, struct sockaddr *nam, 456f2bb1caeSJulian Elischer struct thread *td) 457f2bb1caeSJulian Elischer { 458a6f3c1e3SMaksim Yevmenkin ng_btsocket_rfcomm_pcb_t *pcb = so2rfcomm_pcb(so), *pcb1; 459f2bb1caeSJulian Elischer struct sockaddr_rfcomm *sa = (struct sockaddr_rfcomm *) nam; 460f2bb1caeSJulian Elischer 461f2bb1caeSJulian Elischer if (pcb == NULL) 462f2bb1caeSJulian Elischer return (EINVAL); 463f2bb1caeSJulian Elischer 464f2bb1caeSJulian Elischer /* Verify address */ 465f2bb1caeSJulian Elischer if (sa == NULL) 466f2bb1caeSJulian Elischer return (EINVAL); 467f2bb1caeSJulian Elischer if (sa->rfcomm_family != AF_BLUETOOTH) 468f2bb1caeSJulian Elischer return (EAFNOSUPPORT); 469f2bb1caeSJulian Elischer if (sa->rfcomm_len != sizeof(*sa)) 470f2bb1caeSJulian Elischer return (EINVAL); 471f2bb1caeSJulian Elischer if (sa->rfcomm_channel > 30) 472f2bb1caeSJulian Elischer return (EINVAL); 473a6f3c1e3SMaksim Yevmenkin 474a6f3c1e3SMaksim Yevmenkin mtx_lock(&pcb->pcb_mtx); 475a6f3c1e3SMaksim Yevmenkin 476a6f3c1e3SMaksim Yevmenkin if (sa->rfcomm_channel != 0) { 477a6f3c1e3SMaksim Yevmenkin mtx_lock(&ng_btsocket_rfcomm_sockets_mtx); 478a6f3c1e3SMaksim Yevmenkin 479a6f3c1e3SMaksim Yevmenkin LIST_FOREACH(pcb1, &ng_btsocket_rfcomm_sockets, next) { 480a6f3c1e3SMaksim Yevmenkin if (pcb1->channel == sa->rfcomm_channel && 481a6f3c1e3SMaksim Yevmenkin bcmp(&pcb1->src, &sa->rfcomm_bdaddr, 482a6f3c1e3SMaksim Yevmenkin sizeof(pcb1->src)) == 0) { 483a6f3c1e3SMaksim Yevmenkin mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 484a6f3c1e3SMaksim Yevmenkin mtx_unlock(&pcb->pcb_mtx); 485a6f3c1e3SMaksim Yevmenkin 486f2bb1caeSJulian Elischer return (EADDRINUSE); 487a6f3c1e3SMaksim Yevmenkin } 488a6f3c1e3SMaksim Yevmenkin } 489a6f3c1e3SMaksim Yevmenkin 490a6f3c1e3SMaksim Yevmenkin mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 491a6f3c1e3SMaksim Yevmenkin } 492f2bb1caeSJulian Elischer 493f2bb1caeSJulian Elischer bcopy(&sa->rfcomm_bdaddr, &pcb->src, sizeof(pcb->src)); 494f2bb1caeSJulian Elischer pcb->channel = sa->rfcomm_channel; 495f2bb1caeSJulian Elischer 496a6f3c1e3SMaksim Yevmenkin mtx_unlock(&pcb->pcb_mtx); 497a6f3c1e3SMaksim Yevmenkin 498f2bb1caeSJulian Elischer return (0); 499f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_bind */ 500f2bb1caeSJulian Elischer 501f2bb1caeSJulian Elischer /* 502f2bb1caeSJulian Elischer * Connect socket 503f2bb1caeSJulian Elischer */ 504f2bb1caeSJulian Elischer 505f2bb1caeSJulian Elischer int 506f2bb1caeSJulian Elischer ng_btsocket_rfcomm_connect(struct socket *so, struct sockaddr *nam, 507f2bb1caeSJulian Elischer struct thread *td) 508f2bb1caeSJulian Elischer { 509f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_t *pcb = so2rfcomm_pcb(so); 510f2bb1caeSJulian Elischer struct sockaddr_rfcomm *sa = (struct sockaddr_rfcomm *) nam; 511f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_t *s = NULL; 512f2bb1caeSJulian Elischer struct socket *l2so = NULL; 513f2bb1caeSJulian Elischer int dlci, error = 0; 514f2bb1caeSJulian Elischer 515f2bb1caeSJulian Elischer if (pcb == NULL) 516f2bb1caeSJulian Elischer return (EINVAL); 517f2bb1caeSJulian Elischer 518f2bb1caeSJulian Elischer /* Verify address */ 519f2bb1caeSJulian Elischer if (sa == NULL) 520f2bb1caeSJulian Elischer return (EINVAL); 521f2bb1caeSJulian Elischer if (sa->rfcomm_family != AF_BLUETOOTH) 522f2bb1caeSJulian Elischer return (EAFNOSUPPORT); 523f2bb1caeSJulian Elischer if (sa->rfcomm_len != sizeof(*sa)) 524f2bb1caeSJulian Elischer return (EINVAL); 525f2bb1caeSJulian Elischer if (sa->rfcomm_channel > 30) 526f2bb1caeSJulian Elischer return (EINVAL); 527f2bb1caeSJulian Elischer if (sa->rfcomm_channel == 0 || 528f2bb1caeSJulian Elischer bcmp(&sa->rfcomm_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) 529f2bb1caeSJulian Elischer return (EDESTADDRREQ); 530f2bb1caeSJulian Elischer 531f2bb1caeSJulian Elischer /* 532320a8190SMaksim Yevmenkin * Note that we will not check for errors in socreate() because 533320a8190SMaksim Yevmenkin * if we failed to create L2CAP socket at this point we still 534320a8190SMaksim Yevmenkin * might have already open session. 535f2bb1caeSJulian Elischer */ 536f2bb1caeSJulian Elischer 537f2bb1caeSJulian Elischer error = socreate(PF_BLUETOOTH, &l2so, SOCK_SEQPACKET, 538f2bb1caeSJulian Elischer BLUETOOTH_PROTO_L2CAP, td->td_ucred, td); 539f2bb1caeSJulian Elischer 540f2bb1caeSJulian Elischer /* 541f2bb1caeSJulian Elischer * Look for session between "pcb->src" and "sa->rfcomm_bdaddr" (dst) 542f2bb1caeSJulian Elischer */ 543f2bb1caeSJulian Elischer 544f2bb1caeSJulian Elischer mtx_lock(&ng_btsocket_rfcomm_sessions_mtx); 545f2bb1caeSJulian Elischer 546f2bb1caeSJulian Elischer s = ng_btsocket_rfcomm_session_by_addr(&pcb->src, &sa->rfcomm_bdaddr); 547f2bb1caeSJulian Elischer if (s == NULL) { 548f2bb1caeSJulian Elischer /* 549f2bb1caeSJulian Elischer * We need to create new RFCOMM session. Check if we have L2CAP 550f2bb1caeSJulian Elischer * socket. If l2so == NULL then error has the error code from 551f2bb1caeSJulian Elischer * socreate() 552f2bb1caeSJulian Elischer */ 553f2bb1caeSJulian Elischer 554f2bb1caeSJulian Elischer if (l2so == NULL) { 555f2bb1caeSJulian Elischer mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 556f2bb1caeSJulian Elischer return (error); 557f2bb1caeSJulian Elischer } 558f2bb1caeSJulian Elischer 559f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_session_create(&s, l2so, 560f2bb1caeSJulian Elischer &pcb->src, &sa->rfcomm_bdaddr, td); 561f2bb1caeSJulian Elischer if (error != 0) { 562f2bb1caeSJulian Elischer mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 563f2bb1caeSJulian Elischer soclose(l2so); 564f2bb1caeSJulian Elischer 565f2bb1caeSJulian Elischer return (error); 566f2bb1caeSJulian Elischer } 567f2bb1caeSJulian Elischer } else if (l2so != NULL) 568f2bb1caeSJulian Elischer soclose(l2so); /* we don't need new L2CAP socket */ 569f2bb1caeSJulian Elischer 570f2bb1caeSJulian Elischer /* 5716bccea7cSRebecca Cran * Check if we already have the same DLCI the same session 572f2bb1caeSJulian Elischer */ 573f2bb1caeSJulian Elischer 574f2bb1caeSJulian Elischer mtx_lock(&s->session_mtx); 575f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 576f2bb1caeSJulian Elischer 577f2bb1caeSJulian Elischer dlci = RFCOMM_MKDLCI(!INITIATOR(s), sa->rfcomm_channel); 578f2bb1caeSJulian Elischer 579f2bb1caeSJulian Elischer if (ng_btsocket_rfcomm_pcb_by_dlci(s, dlci) != NULL) { 580f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 581f2bb1caeSJulian Elischer mtx_unlock(&s->session_mtx); 582f2bb1caeSJulian Elischer mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 583f2bb1caeSJulian Elischer 584f2bb1caeSJulian Elischer return (EBUSY); 585f2bb1caeSJulian Elischer } 586f2bb1caeSJulian Elischer 587f2bb1caeSJulian Elischer /* 588f2bb1caeSJulian Elischer * Check session state and if its not acceptable then refuse connection 589f2bb1caeSJulian Elischer */ 590f2bb1caeSJulian Elischer 591f2bb1caeSJulian Elischer switch (s->state) { 592f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_CONNECTING: 593f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED: 594f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_OPEN: 595f2bb1caeSJulian Elischer /* 596f2bb1caeSJulian Elischer * Update destination address and channel and attach 597f2bb1caeSJulian Elischer * DLC to the session 598f2bb1caeSJulian Elischer */ 599f2bb1caeSJulian Elischer 600f2bb1caeSJulian Elischer bcopy(&sa->rfcomm_bdaddr, &pcb->dst, sizeof(pcb->dst)); 601f2bb1caeSJulian Elischer pcb->channel = sa->rfcomm_channel; 602f2bb1caeSJulian Elischer pcb->dlci = dlci; 603f2bb1caeSJulian Elischer 604f2bb1caeSJulian Elischer LIST_INSERT_HEAD(&s->dlcs, pcb, session_next); 605f2bb1caeSJulian Elischer pcb->session = s; 606f2bb1caeSJulian Elischer 607f2bb1caeSJulian Elischer ng_btsocket_rfcomm_timeout(pcb); 608f2bb1caeSJulian Elischer soisconnecting(pcb->so); 609f2bb1caeSJulian Elischer 610f2bb1caeSJulian Elischer if (s->state == NG_BTSOCKET_RFCOMM_SESSION_OPEN) { 611f2bb1caeSJulian Elischer pcb->mtu = s->mtu; 612f2bb1caeSJulian Elischer bcopy(&so2l2cap_pcb(s->l2so)->src, &pcb->src, 613f2bb1caeSJulian Elischer sizeof(pcb->src)); 614f2bb1caeSJulian Elischer 615f2bb1caeSJulian Elischer pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONFIGURING; 616f2bb1caeSJulian Elischer 617f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_pn(pcb); 618f2bb1caeSJulian Elischer if (error == 0) 619f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_task_wakeup(); 620f2bb1caeSJulian Elischer } else 621f2bb1caeSJulian Elischer pcb->state = NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT; 622f2bb1caeSJulian Elischer break; 623f2bb1caeSJulian Elischer 624f2bb1caeSJulian Elischer default: 625f2bb1caeSJulian Elischer error = ECONNRESET; 626f2bb1caeSJulian Elischer break; 627f2bb1caeSJulian Elischer } 628f2bb1caeSJulian Elischer 629f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 630f2bb1caeSJulian Elischer mtx_unlock(&s->session_mtx); 631f2bb1caeSJulian Elischer mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 632f2bb1caeSJulian Elischer 633f2bb1caeSJulian Elischer return (error); 634f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_connect */ 635f2bb1caeSJulian Elischer 636f2bb1caeSJulian Elischer /* 637f2bb1caeSJulian Elischer * Process ioctl's calls on socket. 638f2bb1caeSJulian Elischer * XXX FIXME this should provide interface to the RFCOMM multiplexor channel 639f2bb1caeSJulian Elischer */ 640f2bb1caeSJulian Elischer 641f2bb1caeSJulian Elischer int 642f2bb1caeSJulian Elischer ng_btsocket_rfcomm_control(struct socket *so, u_long cmd, caddr_t data, 643f2bb1caeSJulian Elischer struct ifnet *ifp, struct thread *td) 644f2bb1caeSJulian Elischer { 645f2bb1caeSJulian Elischer return (EINVAL); 646f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_control */ 647f2bb1caeSJulian Elischer 648f2bb1caeSJulian Elischer /* 649f2bb1caeSJulian Elischer * Process getsockopt/setsockopt system calls 650f2bb1caeSJulian Elischer */ 651f2bb1caeSJulian Elischer 652f2bb1caeSJulian Elischer int 653f2bb1caeSJulian Elischer ng_btsocket_rfcomm_ctloutput(struct socket *so, struct sockopt *sopt) 654f2bb1caeSJulian Elischer { 655f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 656f2bb1caeSJulian Elischer struct ng_btsocket_rfcomm_fc_info fcinfo; 657f2bb1caeSJulian Elischer int error = 0; 658f2bb1caeSJulian Elischer 659f2bb1caeSJulian Elischer if (pcb == NULL) 660f2bb1caeSJulian Elischer return (EINVAL); 661f2bb1caeSJulian Elischer if (sopt->sopt_level != SOL_RFCOMM) 662f2bb1caeSJulian Elischer return (0); 663f2bb1caeSJulian Elischer 664f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 665f2bb1caeSJulian Elischer 666f2bb1caeSJulian Elischer switch (sopt->sopt_dir) { 667f2bb1caeSJulian Elischer case SOPT_GET: 668f2bb1caeSJulian Elischer switch (sopt->sopt_name) { 669f2bb1caeSJulian Elischer case SO_RFCOMM_MTU: 670f2bb1caeSJulian Elischer error = sooptcopyout(sopt, &pcb->mtu, sizeof(pcb->mtu)); 671f2bb1caeSJulian Elischer break; 672f2bb1caeSJulian Elischer 673f2bb1caeSJulian Elischer case SO_RFCOMM_FC_INFO: 674f2bb1caeSJulian Elischer fcinfo.lmodem = pcb->lmodem; 675f2bb1caeSJulian Elischer fcinfo.rmodem = pcb->rmodem; 676f2bb1caeSJulian Elischer fcinfo.tx_cred = pcb->tx_cred; 677f2bb1caeSJulian Elischer fcinfo.rx_cred = pcb->rx_cred; 678f2bb1caeSJulian Elischer fcinfo.cfc = (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC)? 679f2bb1caeSJulian Elischer 1 : 0; 680f2bb1caeSJulian Elischer fcinfo.reserved = 0; 681f2bb1caeSJulian Elischer 682f2bb1caeSJulian Elischer error = sooptcopyout(sopt, &fcinfo, sizeof(fcinfo)); 683f2bb1caeSJulian Elischer break; 684f2bb1caeSJulian Elischer 685f2bb1caeSJulian Elischer default: 686f2bb1caeSJulian Elischer error = ENOPROTOOPT; 687f2bb1caeSJulian Elischer break; 688f2bb1caeSJulian Elischer } 689f2bb1caeSJulian Elischer break; 690f2bb1caeSJulian Elischer 691f2bb1caeSJulian Elischer case SOPT_SET: 692f2bb1caeSJulian Elischer switch (sopt->sopt_name) { 693f2bb1caeSJulian Elischer default: 694f2bb1caeSJulian Elischer error = ENOPROTOOPT; 695f2bb1caeSJulian Elischer break; 696f2bb1caeSJulian Elischer } 697f2bb1caeSJulian Elischer break; 698f2bb1caeSJulian Elischer 699f2bb1caeSJulian Elischer default: 700f2bb1caeSJulian Elischer error = EINVAL; 701f2bb1caeSJulian Elischer break; 702f2bb1caeSJulian Elischer } 703f2bb1caeSJulian Elischer 704f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 705f2bb1caeSJulian Elischer 706f2bb1caeSJulian Elischer return (error); 707f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_ctloutput */ 708f2bb1caeSJulian Elischer 709f2bb1caeSJulian Elischer /* 710f2bb1caeSJulian Elischer * Detach and destroy socket 711f2bb1caeSJulian Elischer */ 712f2bb1caeSJulian Elischer 713bc725eafSRobert Watson void 714f2bb1caeSJulian Elischer ng_btsocket_rfcomm_detach(struct socket *so) 715f2bb1caeSJulian Elischer { 716f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 717f2bb1caeSJulian Elischer 718bc725eafSRobert Watson KASSERT(pcb != NULL, ("ng_btsocket_rfcomm_detach: pcb == NULL")); 719f2bb1caeSJulian Elischer 720f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 721f2bb1caeSJulian Elischer 722f2bb1caeSJulian Elischer switch (pcb->state) { 723f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT: 724f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING: 725f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_CONNECTING: 726f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_CONNECTED: 727f2bb1caeSJulian Elischer /* XXX What to do with pending request? */ 728f2bb1caeSJulian Elischer if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO) 729f2bb1caeSJulian Elischer ng_btsocket_rfcomm_untimeout(pcb); 730f2bb1caeSJulian Elischer 731f2bb1caeSJulian Elischer if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT) 732f2bb1caeSJulian Elischer pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_DETACHED; 733f2bb1caeSJulian Elischer else 734f2bb1caeSJulian Elischer pcb->state = NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING; 735f2bb1caeSJulian Elischer 736f2bb1caeSJulian Elischer ng_btsocket_rfcomm_task_wakeup(); 737f2bb1caeSJulian Elischer break; 738f2bb1caeSJulian Elischer 739f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING: 740f2bb1caeSJulian Elischer ng_btsocket_rfcomm_task_wakeup(); 741f2bb1caeSJulian Elischer break; 742f2bb1caeSJulian Elischer } 743f2bb1caeSJulian Elischer 744f2bb1caeSJulian Elischer while (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CLOSED) 745f2bb1caeSJulian Elischer msleep(&pcb->state, &pcb->pcb_mtx, PZERO, "rf_det", 0); 746f2bb1caeSJulian Elischer 747f2bb1caeSJulian Elischer if (pcb->session != NULL) 748f2bb1caeSJulian Elischer panic("%s: pcb->session != NULL\n", __func__); 749f2bb1caeSJulian Elischer if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO) 750f2bb1caeSJulian Elischer panic("%s: timeout on closed DLC, flags=%#x\n", 751f2bb1caeSJulian Elischer __func__, pcb->flags); 752f2bb1caeSJulian Elischer 753f2bb1caeSJulian Elischer mtx_lock(&ng_btsocket_rfcomm_sockets_mtx); 754f2bb1caeSJulian Elischer LIST_REMOVE(pcb, next); 755f2bb1caeSJulian Elischer mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 756f2bb1caeSJulian Elischer 757f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 758f2bb1caeSJulian Elischer 759f2bb1caeSJulian Elischer mtx_destroy(&pcb->pcb_mtx); 760f2bb1caeSJulian Elischer bzero(pcb, sizeof(*pcb)); 7611ede983cSDag-Erling Smørgrav free(pcb, M_NETGRAPH_BTSOCKET_RFCOMM); 762f2bb1caeSJulian Elischer 763f2bb1caeSJulian Elischer soisdisconnected(so); 764f2bb1caeSJulian Elischer so->so_pcb = NULL; 765f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_detach */ 766f2bb1caeSJulian Elischer 767f2bb1caeSJulian Elischer /* 768f2bb1caeSJulian Elischer * Disconnect socket 769f2bb1caeSJulian Elischer */ 770f2bb1caeSJulian Elischer 771f2bb1caeSJulian Elischer int 772f2bb1caeSJulian Elischer ng_btsocket_rfcomm_disconnect(struct socket *so) 773f2bb1caeSJulian Elischer { 774f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 775f2bb1caeSJulian Elischer 776f2bb1caeSJulian Elischer if (pcb == NULL) 777f2bb1caeSJulian Elischer return (EINVAL); 778f2bb1caeSJulian Elischer 779f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 780f2bb1caeSJulian Elischer 781f2bb1caeSJulian Elischer if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING) { 782f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 783f2bb1caeSJulian Elischer return (EINPROGRESS); 784f2bb1caeSJulian Elischer } 785f2bb1caeSJulian Elischer 786f2bb1caeSJulian Elischer /* XXX What to do with pending request? */ 787f2bb1caeSJulian Elischer if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO) 788f2bb1caeSJulian Elischer ng_btsocket_rfcomm_untimeout(pcb); 789f2bb1caeSJulian Elischer 790f2bb1caeSJulian Elischer switch (pcb->state) { 791f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING: /* XXX can we get here? */ 792f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_CONNECTING: /* XXX can we get here? */ 793f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_CONNECTED: 794f2bb1caeSJulian Elischer 795f2bb1caeSJulian Elischer /* 796f2bb1caeSJulian Elischer * Just change DLC state and enqueue RFCOMM task. It will 797f2bb1caeSJulian Elischer * queue and send DISC on the DLC. 798f2bb1caeSJulian Elischer */ 799f2bb1caeSJulian Elischer 800f2bb1caeSJulian Elischer pcb->state = NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING; 801f2bb1caeSJulian Elischer soisdisconnecting(so); 802f2bb1caeSJulian Elischer 803f2bb1caeSJulian Elischer ng_btsocket_rfcomm_task_wakeup(); 804f2bb1caeSJulian Elischer break; 805f2bb1caeSJulian Elischer 8067c380856SMaksim Yevmenkin case NG_BTSOCKET_RFCOMM_DLC_CLOSED: 8077c380856SMaksim Yevmenkin case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT: 8087c380856SMaksim Yevmenkin break; 8097c380856SMaksim Yevmenkin 810f2bb1caeSJulian Elischer default: 811f2bb1caeSJulian Elischer panic("%s: Invalid DLC state=%d, flags=%#x\n", 812f2bb1caeSJulian Elischer __func__, pcb->state, pcb->flags); 813f2bb1caeSJulian Elischer break; 814f2bb1caeSJulian Elischer } 815f2bb1caeSJulian Elischer 816f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 817f2bb1caeSJulian Elischer 818f2bb1caeSJulian Elischer return (0); 819f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_disconnect */ 820f2bb1caeSJulian Elischer 821f2bb1caeSJulian Elischer /* 822f2bb1caeSJulian Elischer * Listen on socket. First call to listen() will create listening RFCOMM session 823f2bb1caeSJulian Elischer */ 824f2bb1caeSJulian Elischer 825f2bb1caeSJulian Elischer int 826d374e81eSRobert Watson ng_btsocket_rfcomm_listen(struct socket *so, int backlog, struct thread *td) 827f2bb1caeSJulian Elischer { 828a6f3c1e3SMaksim Yevmenkin ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so), pcb1; 829f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_p s = NULL; 830f2bb1caeSJulian Elischer struct socket *l2so = NULL; 831a6f3c1e3SMaksim Yevmenkin int error, socreate_error, usedchannels; 832f2bb1caeSJulian Elischer 833f2bb1caeSJulian Elischer if (pcb == NULL) 834f2bb1caeSJulian Elischer return (EINVAL); 835a6f3c1e3SMaksim Yevmenkin if (pcb->channel > 30) 836d46210e6SMaksim Yevmenkin return (EADDRNOTAVAIL); 837f2bb1caeSJulian Elischer 838a6f3c1e3SMaksim Yevmenkin usedchannels = 0; 839a6f3c1e3SMaksim Yevmenkin 840a6f3c1e3SMaksim Yevmenkin mtx_lock(&pcb->pcb_mtx); 841a6f3c1e3SMaksim Yevmenkin 842a6f3c1e3SMaksim Yevmenkin if (pcb->channel == 0) { 843a6f3c1e3SMaksim Yevmenkin mtx_lock(&ng_btsocket_rfcomm_sockets_mtx); 844a6f3c1e3SMaksim Yevmenkin 845a6f3c1e3SMaksim Yevmenkin LIST_FOREACH(pcb1, &ng_btsocket_rfcomm_sockets, next) 846a6f3c1e3SMaksim Yevmenkin if (pcb1->channel != 0 && 847a6f3c1e3SMaksim Yevmenkin bcmp(&pcb1->src, &pcb->src, sizeof(pcb->src)) == 0) 848a6f3c1e3SMaksim Yevmenkin usedchannels |= (1 << (pcb1->channel - 1)); 849a6f3c1e3SMaksim Yevmenkin 850a6f3c1e3SMaksim Yevmenkin for (pcb->channel = 30; pcb->channel > 0; pcb->channel --) 851a6f3c1e3SMaksim Yevmenkin if (!(usedchannels & (1 << (pcb->channel - 1)))) 852a6f3c1e3SMaksim Yevmenkin break; 853a6f3c1e3SMaksim Yevmenkin 854a6f3c1e3SMaksim Yevmenkin if (pcb->channel == 0) { 855a6f3c1e3SMaksim Yevmenkin mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 856a6f3c1e3SMaksim Yevmenkin mtx_unlock(&pcb->pcb_mtx); 857a6f3c1e3SMaksim Yevmenkin 858a6f3c1e3SMaksim Yevmenkin return (EADDRNOTAVAIL); 859a6f3c1e3SMaksim Yevmenkin } 860a6f3c1e3SMaksim Yevmenkin 861a6f3c1e3SMaksim Yevmenkin mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 862a6f3c1e3SMaksim Yevmenkin } 863a6f3c1e3SMaksim Yevmenkin 864a6f3c1e3SMaksim Yevmenkin mtx_unlock(&pcb->pcb_mtx); 865a6f3c1e3SMaksim Yevmenkin 866f2bb1caeSJulian Elischer /* 867320a8190SMaksim Yevmenkin * Note that we will not check for errors in socreate() because 868320a8190SMaksim Yevmenkin * if we failed to create L2CAP socket at this point we still 869320a8190SMaksim Yevmenkin * might have already open session. 870f2bb1caeSJulian Elischer */ 871f2bb1caeSJulian Elischer 8720daccb9cSRobert Watson socreate_error = socreate(PF_BLUETOOTH, &l2so, SOCK_SEQPACKET, 873f2bb1caeSJulian Elischer BLUETOOTH_PROTO_L2CAP, td->td_ucred, td); 874f2bb1caeSJulian Elischer 875f2bb1caeSJulian Elischer /* 8760daccb9cSRobert Watson * Transition the socket and session into the LISTENING state. Check 8770daccb9cSRobert Watson * for collisions first, as there can only be one. 878f2bb1caeSJulian Elischer */ 879f2bb1caeSJulian Elischer mtx_lock(&ng_btsocket_rfcomm_sessions_mtx); 8800daccb9cSRobert Watson SOCK_LOCK(so); 8810daccb9cSRobert Watson error = solisten_proto_check(so); 8827c380856SMaksim Yevmenkin SOCK_UNLOCK(so); 8830daccb9cSRobert Watson if (error != 0) 8840daccb9cSRobert Watson goto out; 885f2bb1caeSJulian Elischer 886f2bb1caeSJulian Elischer LIST_FOREACH(s, &ng_btsocket_rfcomm_sessions, next) 887f2bb1caeSJulian Elischer if (s->state == NG_BTSOCKET_RFCOMM_SESSION_LISTENING) 888f2bb1caeSJulian Elischer break; 889f2bb1caeSJulian Elischer 890f2bb1caeSJulian Elischer if (s == NULL) { 891f2bb1caeSJulian Elischer /* 892f2bb1caeSJulian Elischer * We need to create default RFCOMM session. Check if we have 893f2bb1caeSJulian Elischer * L2CAP socket. If l2so == NULL then error has the error code 894f2bb1caeSJulian Elischer * from socreate() 895f2bb1caeSJulian Elischer */ 896f2bb1caeSJulian Elischer if (l2so == NULL) { 8970daccb9cSRobert Watson error = socreate_error; 8980daccb9cSRobert Watson goto out; 899f2bb1caeSJulian Elischer } 900f2bb1caeSJulian Elischer 901f2bb1caeSJulian Elischer /* 902f2bb1caeSJulian Elischer * Create default listen RFCOMM session. The default RFCOMM 903f2bb1caeSJulian Elischer * session will listen on ANY address. 904f2bb1caeSJulian Elischer * 905f2bb1caeSJulian Elischer * XXX FIXME Note that currently there is no way to adjust MTU 906f2bb1caeSJulian Elischer * for the default session. 907f2bb1caeSJulian Elischer */ 908f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_session_create(&s, l2so, 909f2bb1caeSJulian Elischer NG_HCI_BDADDR_ANY, NULL, td); 9100daccb9cSRobert Watson if (error != 0) 9110daccb9cSRobert Watson goto out; 9120daccb9cSRobert Watson l2so = NULL; 913f2bb1caeSJulian Elischer } 9147c380856SMaksim Yevmenkin SOCK_LOCK(so); 915d374e81eSRobert Watson solisten_proto(so, backlog); 9160daccb9cSRobert Watson SOCK_UNLOCK(so); 9177c380856SMaksim Yevmenkin out: 918f2bb1caeSJulian Elischer mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 9190daccb9cSRobert Watson /* 9200daccb9cSRobert Watson * If we still have an l2so reference here, it's unneeded, so release 9210daccb9cSRobert Watson * it. 9220daccb9cSRobert Watson */ 9230daccb9cSRobert Watson if (l2so != NULL) 9240daccb9cSRobert Watson soclose(l2so); 9250daccb9cSRobert Watson return (error); 926f2bb1caeSJulian Elischer } /* ng_btsocket_listen */ 927f2bb1caeSJulian Elischer 928f2bb1caeSJulian Elischer /* 929f2bb1caeSJulian Elischer * Get peer address 930f2bb1caeSJulian Elischer */ 931f2bb1caeSJulian Elischer 932f2bb1caeSJulian Elischer int 933f2bb1caeSJulian Elischer ng_btsocket_rfcomm_peeraddr(struct socket *so, struct sockaddr **nam) 934f2bb1caeSJulian Elischer { 935f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 936f2bb1caeSJulian Elischer struct sockaddr_rfcomm sa; 937f2bb1caeSJulian Elischer 938f2bb1caeSJulian Elischer if (pcb == NULL) 939f2bb1caeSJulian Elischer return (EINVAL); 940f2bb1caeSJulian Elischer 941f2bb1caeSJulian Elischer bcopy(&pcb->dst, &sa.rfcomm_bdaddr, sizeof(sa.rfcomm_bdaddr)); 942f2bb1caeSJulian Elischer sa.rfcomm_channel = pcb->channel; 943f2bb1caeSJulian Elischer sa.rfcomm_len = sizeof(sa); 944f2bb1caeSJulian Elischer sa.rfcomm_family = AF_BLUETOOTH; 945f2bb1caeSJulian Elischer 946746e5bf0SRobert Watson *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 947f2bb1caeSJulian Elischer 948f2bb1caeSJulian Elischer return ((*nam == NULL)? ENOMEM : 0); 949f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_peeraddr */ 950f2bb1caeSJulian Elischer 951f2bb1caeSJulian Elischer /* 952f2bb1caeSJulian Elischer * Send data to socket 953f2bb1caeSJulian Elischer */ 954f2bb1caeSJulian Elischer 955f2bb1caeSJulian Elischer int 956f2bb1caeSJulian Elischer ng_btsocket_rfcomm_send(struct socket *so, int flags, struct mbuf *m, 957f2bb1caeSJulian Elischer struct sockaddr *nam, struct mbuf *control, struct thread *td) 958f2bb1caeSJulian Elischer { 959f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_t *pcb = so2rfcomm_pcb(so); 960f2bb1caeSJulian Elischer int error = 0; 961f2bb1caeSJulian Elischer 962f2bb1caeSJulian Elischer /* Check socket and input */ 963f2bb1caeSJulian Elischer if (pcb == NULL || m == NULL || control != NULL) { 964f2bb1caeSJulian Elischer error = EINVAL; 965f2bb1caeSJulian Elischer goto drop; 966f2bb1caeSJulian Elischer } 967f2bb1caeSJulian Elischer 968f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 969f2bb1caeSJulian Elischer 970f2bb1caeSJulian Elischer /* Make sure DLC is connected */ 971f2bb1caeSJulian Elischer if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTED) { 972f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 973f2bb1caeSJulian Elischer error = ENOTCONN; 974f2bb1caeSJulian Elischer goto drop; 975f2bb1caeSJulian Elischer } 976f2bb1caeSJulian Elischer 977f2bb1caeSJulian Elischer /* Put the packet on the socket's send queue and wakeup RFCOMM task */ 978829fae90SGleb Smirnoff sbappend(&pcb->so->so_snd, m, flags); 979f2bb1caeSJulian Elischer m = NULL; 980f2bb1caeSJulian Elischer 981f2bb1caeSJulian Elischer if (!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_SENDING)) { 982f2bb1caeSJulian Elischer pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_SENDING; 983f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_task_wakeup(); 984f2bb1caeSJulian Elischer } 985f2bb1caeSJulian Elischer 986f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 987f2bb1caeSJulian Elischer drop: 988f2bb1caeSJulian Elischer NG_FREE_M(m); /* checks for != NULL */ 989f2bb1caeSJulian Elischer NG_FREE_M(control); 990f2bb1caeSJulian Elischer 991f2bb1caeSJulian Elischer return (error); 992f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_send */ 993f2bb1caeSJulian Elischer 994f2bb1caeSJulian Elischer /* 995f2bb1caeSJulian Elischer * Get socket address 996f2bb1caeSJulian Elischer */ 997f2bb1caeSJulian Elischer 998f2bb1caeSJulian Elischer int 999f2bb1caeSJulian Elischer ng_btsocket_rfcomm_sockaddr(struct socket *so, struct sockaddr **nam) 1000f2bb1caeSJulian Elischer { 1001f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so); 1002f2bb1caeSJulian Elischer struct sockaddr_rfcomm sa; 1003f2bb1caeSJulian Elischer 1004f2bb1caeSJulian Elischer if (pcb == NULL) 1005f2bb1caeSJulian Elischer return (EINVAL); 1006f2bb1caeSJulian Elischer 1007f2bb1caeSJulian Elischer bcopy(&pcb->src, &sa.rfcomm_bdaddr, sizeof(sa.rfcomm_bdaddr)); 1008f2bb1caeSJulian Elischer sa.rfcomm_channel = pcb->channel; 1009f2bb1caeSJulian Elischer sa.rfcomm_len = sizeof(sa); 1010f2bb1caeSJulian Elischer sa.rfcomm_family = AF_BLUETOOTH; 1011f2bb1caeSJulian Elischer 1012746e5bf0SRobert Watson *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 1013f2bb1caeSJulian Elischer 1014f2bb1caeSJulian Elischer return ((*nam == NULL)? ENOMEM : 0); 1015f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_sockaddr */ 1016f2bb1caeSJulian Elischer 1017f2bb1caeSJulian Elischer /* 1018f2bb1caeSJulian Elischer * Upcall function for L2CAP sockets. Enqueue RFCOMM task. 1019f2bb1caeSJulian Elischer */ 1020f2bb1caeSJulian Elischer 102174fb0ba7SJohn Baldwin static int 1022f2bb1caeSJulian Elischer ng_btsocket_rfcomm_upcall(struct socket *so, void *arg, int waitflag) 1023f2bb1caeSJulian Elischer { 1024f2bb1caeSJulian Elischer int error; 1025f2bb1caeSJulian Elischer 1026f2bb1caeSJulian Elischer if (so == NULL) 1027f2bb1caeSJulian Elischer panic("%s: so == NULL\n", __func__); 1028f2bb1caeSJulian Elischer 1029f2bb1caeSJulian Elischer if ((error = ng_btsocket_rfcomm_task_wakeup()) != 0) 1030f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ALERT( 1031f2bb1caeSJulian Elischer "%s: Could not enqueue RFCOMM task, error=%d\n", __func__, error); 103274fb0ba7SJohn Baldwin return (SU_OK); 1033f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_upcall */ 1034f2bb1caeSJulian Elischer 1035f2bb1caeSJulian Elischer /* 1036f2bb1caeSJulian Elischer * RFCOMM task. Will handle all RFCOMM sessions in one pass. 1037f2bb1caeSJulian Elischer * XXX FIXME does not scale very well 1038f2bb1caeSJulian Elischer */ 1039f2bb1caeSJulian Elischer 1040f2bb1caeSJulian Elischer static void 1041f2bb1caeSJulian Elischer ng_btsocket_rfcomm_sessions_task(void *ctx, int pending) 1042f2bb1caeSJulian Elischer { 1043f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_p s = NULL, s_next = NULL; 1044f2bb1caeSJulian Elischer 1045f2bb1caeSJulian Elischer mtx_lock(&ng_btsocket_rfcomm_sessions_mtx); 1046f2bb1caeSJulian Elischer 1047f2bb1caeSJulian Elischer for (s = LIST_FIRST(&ng_btsocket_rfcomm_sessions); s != NULL; ) { 1048f2bb1caeSJulian Elischer mtx_lock(&s->session_mtx); 1049f2bb1caeSJulian Elischer s_next = LIST_NEXT(s, next); 1050f2bb1caeSJulian Elischer 1051f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_task(s); 1052f2bb1caeSJulian Elischer 1053f2bb1caeSJulian Elischer if (s->state == NG_BTSOCKET_RFCOMM_SESSION_CLOSED) { 1054f2bb1caeSJulian Elischer /* Unlink and clean the session */ 1055f2bb1caeSJulian Elischer LIST_REMOVE(s, next); 1056f2bb1caeSJulian Elischer 1057f2bb1caeSJulian Elischer NG_BT_MBUFQ_DRAIN(&s->outq); 1058f2bb1caeSJulian Elischer if (!LIST_EMPTY(&s->dlcs)) 1059f2bb1caeSJulian Elischer panic("%s: DLC list is not empty\n", __func__); 1060f2bb1caeSJulian Elischer 1061f2bb1caeSJulian Elischer /* Close L2CAP socket */ 10629535efc0SRobert Watson SOCKBUF_LOCK(&s->l2so->so_rcv); 106374fb0ba7SJohn Baldwin soupcall_clear(s->l2so, SO_RCV); 10649535efc0SRobert Watson SOCKBUF_UNLOCK(&s->l2so->so_rcv); 10659535efc0SRobert Watson SOCKBUF_LOCK(&s->l2so->so_snd); 106674fb0ba7SJohn Baldwin soupcall_clear(s->l2so, SO_SND); 10679535efc0SRobert Watson SOCKBUF_UNLOCK(&s->l2so->so_snd); 1068f2bb1caeSJulian Elischer soclose(s->l2so); 1069f2bb1caeSJulian Elischer 1070f2bb1caeSJulian Elischer mtx_unlock(&s->session_mtx); 1071f2bb1caeSJulian Elischer 1072f2bb1caeSJulian Elischer mtx_destroy(&s->session_mtx); 1073f2bb1caeSJulian Elischer bzero(s, sizeof(*s)); 10741ede983cSDag-Erling Smørgrav free(s, M_NETGRAPH_BTSOCKET_RFCOMM); 1075f2bb1caeSJulian Elischer } else 1076f2bb1caeSJulian Elischer mtx_unlock(&s->session_mtx); 1077f2bb1caeSJulian Elischer 1078f2bb1caeSJulian Elischer s = s_next; 1079f2bb1caeSJulian Elischer } 1080f2bb1caeSJulian Elischer 1081f2bb1caeSJulian Elischer mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx); 1082f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_sessions_task */ 1083f2bb1caeSJulian Elischer 1084f2bb1caeSJulian Elischer /* 1085f2bb1caeSJulian Elischer * Process RFCOMM session. Will handle all RFCOMM sockets in one pass. 1086f2bb1caeSJulian Elischer */ 1087f2bb1caeSJulian Elischer 1088f2bb1caeSJulian Elischer static void 1089f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_task(ng_btsocket_rfcomm_session_p s) 1090f2bb1caeSJulian Elischer { 1091f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 1092f2bb1caeSJulian Elischer 1093c0b99ffaSRobert Watson if (s->l2so->so_rcv.sb_state & SBS_CANTRCVMORE) { 1094f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 1095f2bb1caeSJulian Elischer "%s: L2CAP connection has been terminated, so=%p, so_state=%#x, so_count=%d, " \ 1096f2bb1caeSJulian Elischer "state=%d, flags=%#x\n", __func__, s->l2so, s->l2so->so_state, 1097f2bb1caeSJulian Elischer s->l2so->so_count, s->state, s->flags); 1098f2bb1caeSJulian Elischer 1099f2bb1caeSJulian Elischer s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 1100f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_clean(s); 1101f2bb1caeSJulian Elischer } 1102f2bb1caeSJulian Elischer 1103f2bb1caeSJulian Elischer /* Now process upcall */ 1104f2bb1caeSJulian Elischer switch (s->state) { 1105f2bb1caeSJulian Elischer /* Try to accept new L2CAP connection(s) */ 1106f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_LISTENING: 1107f2bb1caeSJulian Elischer while (ng_btsocket_rfcomm_session_accept(s) == 0) 1108f2bb1caeSJulian Elischer ; 1109f2bb1caeSJulian Elischer break; 1110f2bb1caeSJulian Elischer 1111f2bb1caeSJulian Elischer /* Process the results of the L2CAP connect */ 1112f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_CONNECTING: 1113f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_process_pcb(s); 1114f2bb1caeSJulian Elischer 1115f2bb1caeSJulian Elischer if (ng_btsocket_rfcomm_session_connect(s) != 0) { 1116f2bb1caeSJulian Elischer s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 1117f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_clean(s); 1118f2bb1caeSJulian Elischer } 1119f2bb1caeSJulian Elischer break; 1120f2bb1caeSJulian Elischer 1121f2bb1caeSJulian Elischer /* Try to receive/send more data */ 1122f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED: 1123f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_OPEN: 1124f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING: 1125f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_process_pcb(s); 1126f2bb1caeSJulian Elischer 1127f2bb1caeSJulian Elischer if (ng_btsocket_rfcomm_session_receive(s) != 0) { 1128f2bb1caeSJulian Elischer s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 1129f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_clean(s); 1130f2bb1caeSJulian Elischer } else if (ng_btsocket_rfcomm_session_send(s) != 0) { 1131f2bb1caeSJulian Elischer s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 1132f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_clean(s); 1133f2bb1caeSJulian Elischer } 1134f2bb1caeSJulian Elischer break; 1135f2bb1caeSJulian Elischer 1136f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_CLOSED: 1137f2bb1caeSJulian Elischer break; 1138f2bb1caeSJulian Elischer 1139f2bb1caeSJulian Elischer default: 1140f2bb1caeSJulian Elischer panic("%s: Invalid session state=%d, flags=%#x\n", 1141f2bb1caeSJulian Elischer __func__, s->state, s->flags); 1142f2bb1caeSJulian Elischer break; 1143f2bb1caeSJulian Elischer } 1144f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_session_task */ 1145f2bb1caeSJulian Elischer 1146f2bb1caeSJulian Elischer /* 1147f2bb1caeSJulian Elischer * Process RFCOMM connection indicator. Caller must hold s->session_mtx 1148f2bb1caeSJulian Elischer */ 1149f2bb1caeSJulian Elischer 1150f2bb1caeSJulian Elischer static ng_btsocket_rfcomm_pcb_p 1151f2bb1caeSJulian Elischer ng_btsocket_rfcomm_connect_ind(ng_btsocket_rfcomm_session_p s, int channel) 1152f2bb1caeSJulian Elischer { 1153f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb1 = NULL; 1154f2bb1caeSJulian Elischer ng_btsocket_l2cap_pcb_p l2pcb = NULL; 1155779f106aSGleb Smirnoff struct socket *so1; 1156f2bb1caeSJulian Elischer 1157f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 1158f2bb1caeSJulian Elischer 1159f2bb1caeSJulian Elischer /* 1160f2bb1caeSJulian Elischer * Try to find RFCOMM socket that listens on given source address 1161f2bb1caeSJulian Elischer * and channel. This will return the best possible match. 1162f2bb1caeSJulian Elischer */ 1163f2bb1caeSJulian Elischer 1164f2bb1caeSJulian Elischer l2pcb = so2l2cap_pcb(s->l2so); 1165f2bb1caeSJulian Elischer pcb = ng_btsocket_rfcomm_pcb_listener(&l2pcb->src, channel); 1166f2bb1caeSJulian Elischer if (pcb == NULL) 1167f2bb1caeSJulian Elischer return (NULL); 1168f2bb1caeSJulian Elischer 1169f2bb1caeSJulian Elischer /* 1170f2bb1caeSJulian Elischer * Check the pending connections queue and if we have space then 1171f2bb1caeSJulian Elischer * create new socket and set proper source and destination address, 1172f2bb1caeSJulian Elischer * and channel. 1173f2bb1caeSJulian Elischer */ 1174f2bb1caeSJulian Elischer 1175f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 1176f2bb1caeSJulian Elischer 11771fb51a12SBjoern A. Zeeb CURVNET_SET(pcb->so->so_vnet); 1178f2bb1caeSJulian Elischer so1 = sonewconn(pcb->so, 0); 11791fb51a12SBjoern A. Zeeb CURVNET_RESTORE(); 1180f2bb1caeSJulian Elischer 1181f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 1182f2bb1caeSJulian Elischer 1183f2bb1caeSJulian Elischer if (so1 == NULL) 1184f2bb1caeSJulian Elischer return (NULL); 1185f2bb1caeSJulian Elischer 1186f2bb1caeSJulian Elischer /* 1187f2bb1caeSJulian Elischer * If we got here than we have created new socket. So complete the 1188f2bb1caeSJulian Elischer * connection. Set source and destination address from the session. 1189f2bb1caeSJulian Elischer */ 1190f2bb1caeSJulian Elischer 1191f2bb1caeSJulian Elischer pcb1 = so2rfcomm_pcb(so1); 1192f2bb1caeSJulian Elischer if (pcb1 == NULL) 1193f2bb1caeSJulian Elischer panic("%s: pcb1 == NULL\n", __func__); 1194f2bb1caeSJulian Elischer 1195f2bb1caeSJulian Elischer mtx_lock(&pcb1->pcb_mtx); 1196f2bb1caeSJulian Elischer 1197f2bb1caeSJulian Elischer bcopy(&l2pcb->src, &pcb1->src, sizeof(pcb1->src)); 1198f2bb1caeSJulian Elischer bcopy(&l2pcb->dst, &pcb1->dst, sizeof(pcb1->dst)); 1199f2bb1caeSJulian Elischer pcb1->channel = channel; 1200f2bb1caeSJulian Elischer 1201f2bb1caeSJulian Elischer /* Link new DLC to the session. We already hold s->session_mtx */ 1202f2bb1caeSJulian Elischer LIST_INSERT_HEAD(&s->dlcs, pcb1, session_next); 1203f2bb1caeSJulian Elischer pcb1->session = s; 1204f2bb1caeSJulian Elischer 1205f2bb1caeSJulian Elischer mtx_unlock(&pcb1->pcb_mtx); 1206f2bb1caeSJulian Elischer 1207f2bb1caeSJulian Elischer return (pcb1); 1208f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_connect_ind */ 1209f2bb1caeSJulian Elischer 1210f2bb1caeSJulian Elischer /* 1211f2bb1caeSJulian Elischer * Process RFCOMM connect confirmation. Caller must hold s->session_mtx. 1212f2bb1caeSJulian Elischer */ 1213f2bb1caeSJulian Elischer 1214f2bb1caeSJulian Elischer static void 1215f2bb1caeSJulian Elischer ng_btsocket_rfcomm_connect_cfm(ng_btsocket_rfcomm_session_p s) 1216f2bb1caeSJulian Elischer { 1217f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb_next = NULL; 1218f2bb1caeSJulian Elischer int error; 1219f2bb1caeSJulian Elischer 1220f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 1221f2bb1caeSJulian Elischer 1222f2bb1caeSJulian Elischer /* 1223f2bb1caeSJulian Elischer * Wake up all waiting sockets and send PN request for each of them. 1224f2bb1caeSJulian Elischer * Note that timeout already been set in ng_btsocket_rfcomm_connect() 1225f2bb1caeSJulian Elischer * 1226f2bb1caeSJulian Elischer * Note: cannot use LIST_FOREACH because ng_btsocket_rfcomm_pcb_kill 1227f2bb1caeSJulian Elischer * will unlink DLC from the session 1228f2bb1caeSJulian Elischer */ 1229f2bb1caeSJulian Elischer 1230f2bb1caeSJulian Elischer for (pcb = LIST_FIRST(&s->dlcs); pcb != NULL; ) { 1231f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 1232f2bb1caeSJulian Elischer pcb_next = LIST_NEXT(pcb, session_next); 1233f2bb1caeSJulian Elischer 1234f2bb1caeSJulian Elischer if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT) { 1235f2bb1caeSJulian Elischer pcb->mtu = s->mtu; 1236f2bb1caeSJulian Elischer bcopy(&so2l2cap_pcb(s->l2so)->src, &pcb->src, 1237f2bb1caeSJulian Elischer sizeof(pcb->src)); 1238f2bb1caeSJulian Elischer 1239f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_pn(pcb); 1240f2bb1caeSJulian Elischer if (error == 0) 1241f2bb1caeSJulian Elischer pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONFIGURING; 1242f2bb1caeSJulian Elischer else 12437c380856SMaksim Yevmenkin ng_btsocket_rfcomm_pcb_kill(pcb, error); 1244f2bb1caeSJulian Elischer } 1245f2bb1caeSJulian Elischer 1246f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 1247f2bb1caeSJulian Elischer pcb = pcb_next; 1248f2bb1caeSJulian Elischer } 1249f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_connect_cfm */ 1250f2bb1caeSJulian Elischer 1251f2bb1caeSJulian Elischer /***************************************************************************** 1252f2bb1caeSJulian Elischer ***************************************************************************** 1253f2bb1caeSJulian Elischer ** RFCOMM sessions 1254f2bb1caeSJulian Elischer ***************************************************************************** 1255f2bb1caeSJulian Elischer *****************************************************************************/ 1256f2bb1caeSJulian Elischer 1257f2bb1caeSJulian Elischer /* 1258f2bb1caeSJulian Elischer * Create new RFCOMM session. That function WILL NOT take ownership over l2so. 1259f2bb1caeSJulian Elischer * Caller MUST free l2so if function failed. 1260f2bb1caeSJulian Elischer */ 1261f2bb1caeSJulian Elischer 1262f2bb1caeSJulian Elischer static int 1263f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_create(ng_btsocket_rfcomm_session_p *sp, 1264f2bb1caeSJulian Elischer struct socket *l2so, bdaddr_p src, bdaddr_p dst, 1265f2bb1caeSJulian Elischer struct thread *td) 1266f2bb1caeSJulian Elischer { 1267f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_p s = NULL; 1268f2bb1caeSJulian Elischer struct sockaddr_l2cap l2sa; 1269f2bb1caeSJulian Elischer struct sockopt l2sopt; 1270231e9556SMaksim Yevmenkin int error; 1271231e9556SMaksim Yevmenkin u_int16_t mtu; 1272f2bb1caeSJulian Elischer 1273f2bb1caeSJulian Elischer mtx_assert(&ng_btsocket_rfcomm_sessions_mtx, MA_OWNED); 1274f2bb1caeSJulian Elischer 1275f2bb1caeSJulian Elischer /* Allocate the RFCOMM session */ 12761ede983cSDag-Erling Smørgrav s = malloc(sizeof(*s), 1277f2bb1caeSJulian Elischer M_NETGRAPH_BTSOCKET_RFCOMM, M_NOWAIT | M_ZERO); 1278f2bb1caeSJulian Elischer if (s == NULL) 1279f2bb1caeSJulian Elischer return (ENOMEM); 1280f2bb1caeSJulian Elischer 1281f2bb1caeSJulian Elischer /* Set defaults */ 1282f2bb1caeSJulian Elischer s->mtu = RFCOMM_DEFAULT_MTU; 1283f2bb1caeSJulian Elischer s->flags = 0; 1284f2bb1caeSJulian Elischer s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 1285f2bb1caeSJulian Elischer NG_BT_MBUFQ_INIT(&s->outq, ifqmaxlen); 1286f2bb1caeSJulian Elischer 1287f2bb1caeSJulian Elischer /* 1288f2bb1caeSJulian Elischer * XXX Mark session mutex as DUPOK to prevent "duplicated lock of 1289f2bb1caeSJulian Elischer * the same type" message. When accepting new L2CAP connection 1290f2bb1caeSJulian Elischer * ng_btsocket_rfcomm_session_accept() holds both session mutexes 1291f2bb1caeSJulian Elischer * for "old" (accepting) session and "new" (created) session. 1292f2bb1caeSJulian Elischer */ 1293f2bb1caeSJulian Elischer 1294f2bb1caeSJulian Elischer mtx_init(&s->session_mtx, "btsocks_rfcomm_session_mtx", NULL, 1295f2bb1caeSJulian Elischer MTX_DEF|MTX_DUPOK); 1296f2bb1caeSJulian Elischer 1297f2bb1caeSJulian Elischer LIST_INIT(&s->dlcs); 1298f2bb1caeSJulian Elischer 1299f2bb1caeSJulian Elischer /* Prepare L2CAP socket */ 13009535efc0SRobert Watson SOCKBUF_LOCK(&l2so->so_rcv); 130174fb0ba7SJohn Baldwin soupcall_set(l2so, SO_RCV, ng_btsocket_rfcomm_upcall, NULL); 13029535efc0SRobert Watson SOCKBUF_UNLOCK(&l2so->so_rcv); 13039535efc0SRobert Watson SOCKBUF_LOCK(&l2so->so_snd); 130474fb0ba7SJohn Baldwin soupcall_set(l2so, SO_SND, ng_btsocket_rfcomm_upcall, NULL); 13059535efc0SRobert Watson SOCKBUF_UNLOCK(&l2so->so_snd); 1306f2bb1caeSJulian Elischer l2so->so_state |= SS_NBIO; 1307f2bb1caeSJulian Elischer s->l2so = l2so; 1308f2bb1caeSJulian Elischer 1309f2bb1caeSJulian Elischer mtx_lock(&s->session_mtx); 1310f2bb1caeSJulian Elischer 1311f2bb1caeSJulian Elischer /* 1312f2bb1caeSJulian Elischer * "src" == NULL and "dst" == NULL means just create session. 1313f2bb1caeSJulian Elischer * caller must do the rest 1314f2bb1caeSJulian Elischer */ 1315f2bb1caeSJulian Elischer 1316f2bb1caeSJulian Elischer if (src == NULL && dst == NULL) 1317f2bb1caeSJulian Elischer goto done; 1318f2bb1caeSJulian Elischer 1319f2bb1caeSJulian Elischer /* 1320f2bb1caeSJulian Elischer * Set incoming MTU on L2CAP socket. It is RFCOMM session default MTU 1321f2bb1caeSJulian Elischer * plus 5 bytes: RFCOMM frame header, one extra byte for length and one 1322f2bb1caeSJulian Elischer * extra byte for credits. 1323f2bb1caeSJulian Elischer */ 1324f2bb1caeSJulian Elischer 1325f2bb1caeSJulian Elischer mtu = s->mtu + sizeof(struct rfcomm_frame_hdr) + 1 + 1; 1326f2bb1caeSJulian Elischer 1327f2bb1caeSJulian Elischer l2sopt.sopt_dir = SOPT_SET; 1328f2bb1caeSJulian Elischer l2sopt.sopt_level = SOL_L2CAP; 1329f2bb1caeSJulian Elischer l2sopt.sopt_name = SO_L2CAP_IMTU; 1330f2bb1caeSJulian Elischer l2sopt.sopt_val = (void *) &mtu; 1331f2bb1caeSJulian Elischer l2sopt.sopt_valsize = sizeof(mtu); 1332f2bb1caeSJulian Elischer l2sopt.sopt_td = NULL; 1333f2bb1caeSJulian Elischer 1334f2bb1caeSJulian Elischer error = sosetopt(s->l2so, &l2sopt); 1335f2bb1caeSJulian Elischer if (error != 0) 1336f2bb1caeSJulian Elischer goto bad; 1337f2bb1caeSJulian Elischer 1338f2bb1caeSJulian Elischer /* Bind socket to "src" address */ 1339f2bb1caeSJulian Elischer l2sa.l2cap_len = sizeof(l2sa); 1340f2bb1caeSJulian Elischer l2sa.l2cap_family = AF_BLUETOOTH; 1341f2bb1caeSJulian Elischer l2sa.l2cap_psm = (dst == NULL)? htole16(NG_L2CAP_PSM_RFCOMM) : 0; 1342f2bb1caeSJulian Elischer bcopy(src, &l2sa.l2cap_bdaddr, sizeof(l2sa.l2cap_bdaddr)); 134399043514STakanori Watanabe l2sa.l2cap_cid = 0; 134499043514STakanori Watanabe l2sa.l2cap_bdaddr_type = BDADDR_BREDR; 1345f2bb1caeSJulian Elischer 1346f2bb1caeSJulian Elischer error = sobind(s->l2so, (struct sockaddr *) &l2sa, td); 1347f2bb1caeSJulian Elischer if (error != 0) 1348f2bb1caeSJulian Elischer goto bad; 1349f2bb1caeSJulian Elischer 1350f2bb1caeSJulian Elischer /* If "dst" is not NULL then initiate connect(), otherwise listen() */ 1351f2bb1caeSJulian Elischer if (dst == NULL) { 1352f2bb1caeSJulian Elischer s->flags = 0; 1353f2bb1caeSJulian Elischer s->state = NG_BTSOCKET_RFCOMM_SESSION_LISTENING; 1354f2bb1caeSJulian Elischer 1355f2bb1caeSJulian Elischer error = solisten(s->l2so, 10, td); 1356f2bb1caeSJulian Elischer if (error != 0) 1357f2bb1caeSJulian Elischer goto bad; 1358f2bb1caeSJulian Elischer } else { 1359f2bb1caeSJulian Elischer s->flags = NG_BTSOCKET_RFCOMM_SESSION_INITIATOR; 1360f2bb1caeSJulian Elischer s->state = NG_BTSOCKET_RFCOMM_SESSION_CONNECTING; 1361f2bb1caeSJulian Elischer 1362f2bb1caeSJulian Elischer l2sa.l2cap_len = sizeof(l2sa); 1363f2bb1caeSJulian Elischer l2sa.l2cap_family = AF_BLUETOOTH; 1364f2bb1caeSJulian Elischer l2sa.l2cap_psm = htole16(NG_L2CAP_PSM_RFCOMM); 1365f2bb1caeSJulian Elischer bcopy(dst, &l2sa.l2cap_bdaddr, sizeof(l2sa.l2cap_bdaddr)); 136699043514STakanori Watanabe l2sa.l2cap_cid = 0; 136799043514STakanori Watanabe l2sa.l2cap_bdaddr_type = BDADDR_BREDR; 1368f2bb1caeSJulian Elischer 1369f2bb1caeSJulian Elischer error = soconnect(s->l2so, (struct sockaddr *) &l2sa, td); 1370f2bb1caeSJulian Elischer if (error != 0) 1371f2bb1caeSJulian Elischer goto bad; 1372f2bb1caeSJulian Elischer } 1373f2bb1caeSJulian Elischer 1374f2bb1caeSJulian Elischer done: 1375f2bb1caeSJulian Elischer LIST_INSERT_HEAD(&ng_btsocket_rfcomm_sessions, s, next); 1376f2bb1caeSJulian Elischer *sp = s; 1377f2bb1caeSJulian Elischer 1378f2bb1caeSJulian Elischer mtx_unlock(&s->session_mtx); 1379f2bb1caeSJulian Elischer 1380f2bb1caeSJulian Elischer return (0); 1381f2bb1caeSJulian Elischer 1382f2bb1caeSJulian Elischer bad: 1383f2bb1caeSJulian Elischer mtx_unlock(&s->session_mtx); 1384f2bb1caeSJulian Elischer 1385f2bb1caeSJulian Elischer /* Return L2CAP socket back to its original state */ 13869535efc0SRobert Watson SOCKBUF_LOCK(&l2so->so_rcv); 138774fb0ba7SJohn Baldwin soupcall_clear(s->l2so, SO_RCV); 138868548aa4SRobert Watson SOCKBUF_UNLOCK(&l2so->so_rcv); 13899535efc0SRobert Watson SOCKBUF_LOCK(&l2so->so_snd); 139074fb0ba7SJohn Baldwin soupcall_clear(s->l2so, SO_SND); 139168548aa4SRobert Watson SOCKBUF_UNLOCK(&l2so->so_snd); 1392f2bb1caeSJulian Elischer l2so->so_state &= ~SS_NBIO; 1393f2bb1caeSJulian Elischer 1394f2bb1caeSJulian Elischer mtx_destroy(&s->session_mtx); 1395f2bb1caeSJulian Elischer bzero(s, sizeof(*s)); 13961ede983cSDag-Erling Smørgrav free(s, M_NETGRAPH_BTSOCKET_RFCOMM); 1397f2bb1caeSJulian Elischer 1398f2bb1caeSJulian Elischer return (error); 1399f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_session_create */ 1400f2bb1caeSJulian Elischer 1401f2bb1caeSJulian Elischer /* 1402f2bb1caeSJulian Elischer * Process accept() on RFCOMM session 1403f2bb1caeSJulian Elischer * XXX FIXME locking for "l2so"? 1404f2bb1caeSJulian Elischer */ 1405f2bb1caeSJulian Elischer 1406f2bb1caeSJulian Elischer static int 1407f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_accept(ng_btsocket_rfcomm_session_p s0) 1408f2bb1caeSJulian Elischer { 1409779f106aSGleb Smirnoff struct socket *l2so; 1410f2bb1caeSJulian Elischer struct sockaddr_l2cap *l2sa = NULL; 1411f2bb1caeSJulian Elischer ng_btsocket_l2cap_pcb_t *l2pcb = NULL; 1412f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_p s = NULL; 1413779f106aSGleb Smirnoff int error; 1414f2bb1caeSJulian Elischer 1415f2bb1caeSJulian Elischer mtx_assert(&ng_btsocket_rfcomm_sessions_mtx, MA_OWNED); 1416f2bb1caeSJulian Elischer mtx_assert(&s0->session_mtx, MA_OWNED); 1417f2bb1caeSJulian Elischer 1418779f106aSGleb Smirnoff SOLISTEN_LOCK(s0->l2so); 1419779f106aSGleb Smirnoff error = solisten_dequeue(s0->l2so, &l2so, 0); 1420779f106aSGleb Smirnoff if (error == EWOULDBLOCK) 1421779f106aSGleb Smirnoff return (error); 1422779f106aSGleb Smirnoff if (error) { 1423f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 1424f2bb1caeSJulian Elischer "%s: Could not accept connection on L2CAP socket, error=%d\n", __func__, error); 1425f2bb1caeSJulian Elischer return (error); 1426f2bb1caeSJulian Elischer } 1427f2bb1caeSJulian Elischer 1428f2bb1caeSJulian Elischer error = soaccept(l2so, (struct sockaddr **) &l2sa); 1429f2bb1caeSJulian Elischer if (error != 0) { 1430f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 1431f2bb1caeSJulian Elischer "%s: soaccept() on L2CAP socket failed, error=%d\n", __func__, error); 1432f2bb1caeSJulian Elischer soclose(l2so); 1433f2bb1caeSJulian Elischer 1434f2bb1caeSJulian Elischer return (error); 1435f2bb1caeSJulian Elischer } 1436f2bb1caeSJulian Elischer 1437f2bb1caeSJulian Elischer /* 1438f2bb1caeSJulian Elischer * Check if there is already active RFCOMM session between two devices. 1439f2bb1caeSJulian Elischer * If so then close L2CAP connection. We only support one RFCOMM session 1440f2bb1caeSJulian Elischer * between each pair of devices. Note that here we assume session in any 1441f2bb1caeSJulian Elischer * state. The session even could be in the middle of disconnecting. 1442f2bb1caeSJulian Elischer */ 1443f2bb1caeSJulian Elischer 1444f2bb1caeSJulian Elischer l2pcb = so2l2cap_pcb(l2so); 1445f2bb1caeSJulian Elischer s = ng_btsocket_rfcomm_session_by_addr(&l2pcb->src, &l2pcb->dst); 1446f2bb1caeSJulian Elischer if (s == NULL) { 1447f2bb1caeSJulian Elischer /* Create a new RFCOMM session */ 1448f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_session_create(&s, l2so, NULL, NULL, 1449f2bb1caeSJulian Elischer curthread /* XXX */); 1450f2bb1caeSJulian Elischer if (error == 0) { 1451f2bb1caeSJulian Elischer mtx_lock(&s->session_mtx); 1452f2bb1caeSJulian Elischer 1453f2bb1caeSJulian Elischer s->flags = 0; 1454f2bb1caeSJulian Elischer s->state = NG_BTSOCKET_RFCOMM_SESSION_CONNECTED; 1455f2bb1caeSJulian Elischer 1456f2bb1caeSJulian Elischer /* 1457053359b7SPedro F. Giffuni * Adjust MTU on incoming connection. Reserve 5 bytes: 1458f2bb1caeSJulian Elischer * RFCOMM frame header, one extra byte for length and 1459f2bb1caeSJulian Elischer * one extra byte for credits. 1460f2bb1caeSJulian Elischer */ 1461f2bb1caeSJulian Elischer 1462f2bb1caeSJulian Elischer s->mtu = min(l2pcb->imtu, l2pcb->omtu) - 1463f2bb1caeSJulian Elischer sizeof(struct rfcomm_frame_hdr) - 1 - 1; 1464f2bb1caeSJulian Elischer 1465f2bb1caeSJulian Elischer mtx_unlock(&s->session_mtx); 1466f2bb1caeSJulian Elischer } else { 1467f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ALERT( 1468f2bb1caeSJulian Elischer "%s: Failed to create new RFCOMM session, error=%d\n", __func__, error); 1469f2bb1caeSJulian Elischer 1470f2bb1caeSJulian Elischer soclose(l2so); 1471f2bb1caeSJulian Elischer } 1472f2bb1caeSJulian Elischer } else { 1473f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_WARN( 1474f2bb1caeSJulian Elischer "%s: Rejecting duplicating RFCOMM session between src=%x:%x:%x:%x:%x:%x and " \ 1475f2bb1caeSJulian Elischer "dst=%x:%x:%x:%x:%x:%x, state=%d, flags=%#x\n", __func__, 1476f2bb1caeSJulian Elischer l2pcb->src.b[5], l2pcb->src.b[4], l2pcb->src.b[3], 1477f2bb1caeSJulian Elischer l2pcb->src.b[2], l2pcb->src.b[1], l2pcb->src.b[0], 1478f2bb1caeSJulian Elischer l2pcb->dst.b[5], l2pcb->dst.b[4], l2pcb->dst.b[3], 1479f2bb1caeSJulian Elischer l2pcb->dst.b[2], l2pcb->dst.b[1], l2pcb->dst.b[0], 1480f2bb1caeSJulian Elischer s->state, s->flags); 1481f2bb1caeSJulian Elischer 1482f2bb1caeSJulian Elischer error = EBUSY; 1483f2bb1caeSJulian Elischer soclose(l2so); 1484f2bb1caeSJulian Elischer } 1485f2bb1caeSJulian Elischer 1486f2bb1caeSJulian Elischer return (error); 1487f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_session_accept */ 1488f2bb1caeSJulian Elischer 1489f2bb1caeSJulian Elischer /* 1490f2bb1caeSJulian Elischer * Process connect() on RFCOMM session 1491f2bb1caeSJulian Elischer * XXX FIXME locking for "l2so"? 1492f2bb1caeSJulian Elischer */ 1493f2bb1caeSJulian Elischer 1494f2bb1caeSJulian Elischer static int 1495f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_connect(ng_btsocket_rfcomm_session_p s) 1496f2bb1caeSJulian Elischer { 1497f2bb1caeSJulian Elischer ng_btsocket_l2cap_pcb_p l2pcb = so2l2cap_pcb(s->l2so); 1498f2bb1caeSJulian Elischer int error; 1499f2bb1caeSJulian Elischer 1500f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 1501f2bb1caeSJulian Elischer 1502f2bb1caeSJulian Elischer /* First check if connection has failed */ 1503f2bb1caeSJulian Elischer if ((error = s->l2so->so_error) != 0) { 1504f2bb1caeSJulian Elischer s->l2so->so_error = 0; 1505f2bb1caeSJulian Elischer 1506f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 1507f2bb1caeSJulian Elischer "%s: Could not connect RFCOMM session, error=%d, state=%d, flags=%#x\n", 1508f2bb1caeSJulian Elischer __func__, error, s->state, s->flags); 1509f2bb1caeSJulian Elischer 1510f2bb1caeSJulian Elischer return (error); 1511f2bb1caeSJulian Elischer } 1512f2bb1caeSJulian Elischer 1513f2bb1caeSJulian Elischer /* Is connection still in progress? */ 1514f2bb1caeSJulian Elischer if (s->l2so->so_state & SS_ISCONNECTING) 1515f2bb1caeSJulian Elischer return (0); 1516f2bb1caeSJulian Elischer 1517f2bb1caeSJulian Elischer /* 1518f2bb1caeSJulian Elischer * If we got here then we are connected. Send SABM on DLCI 0 to 1519f2bb1caeSJulian Elischer * open multiplexor channel. 1520f2bb1caeSJulian Elischer */ 1521f2bb1caeSJulian Elischer 1522f2bb1caeSJulian Elischer if (error == 0) { 1523f2bb1caeSJulian Elischer s->state = NG_BTSOCKET_RFCOMM_SESSION_CONNECTED; 1524f2bb1caeSJulian Elischer 1525f2bb1caeSJulian Elischer /* 1526f2bb1caeSJulian Elischer * Adjust MTU on outgoing connection. Reserve 5 bytes: RFCOMM 1527f2bb1caeSJulian Elischer * frame header, one extra byte for length and one extra byte 1528f2bb1caeSJulian Elischer * for credits. 1529f2bb1caeSJulian Elischer */ 1530f2bb1caeSJulian Elischer 1531f2bb1caeSJulian Elischer s->mtu = min(l2pcb->imtu, l2pcb->omtu) - 1532f2bb1caeSJulian Elischer sizeof(struct rfcomm_frame_hdr) - 1 - 1; 1533f2bb1caeSJulian Elischer 1534f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_SABM,0); 1535f2bb1caeSJulian Elischer if (error == 0) 1536f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_task_wakeup(); 1537f2bb1caeSJulian Elischer } 1538f2bb1caeSJulian Elischer 1539f2bb1caeSJulian Elischer return (error); 1540f2bb1caeSJulian Elischer }/* ng_btsocket_rfcomm_session_connect */ 1541f2bb1caeSJulian Elischer 1542f2bb1caeSJulian Elischer /* 1543f2bb1caeSJulian Elischer * Receive data on RFCOMM session 1544f2bb1caeSJulian Elischer * XXX FIXME locking for "l2so"? 1545f2bb1caeSJulian Elischer */ 1546f2bb1caeSJulian Elischer 1547f2bb1caeSJulian Elischer static int 1548f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_receive(ng_btsocket_rfcomm_session_p s) 1549f2bb1caeSJulian Elischer { 1550f2bb1caeSJulian Elischer struct mbuf *m = NULL; 1551f2bb1caeSJulian Elischer struct uio uio; 1552f2bb1caeSJulian Elischer int more, flags, error; 1553f2bb1caeSJulian Elischer 1554f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 1555f2bb1caeSJulian Elischer 1556f2bb1caeSJulian Elischer /* Can we read from the L2CAP socket? */ 1557f2bb1caeSJulian Elischer if (!soreadable(s->l2so)) 1558f2bb1caeSJulian Elischer return (0); 1559f2bb1caeSJulian Elischer 1560f2bb1caeSJulian Elischer /* First check for error on L2CAP socket */ 1561f2bb1caeSJulian Elischer if ((error = s->l2so->so_error) != 0) { 1562f2bb1caeSJulian Elischer s->l2so->so_error = 0; 1563f2bb1caeSJulian Elischer 1564f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 1565f2bb1caeSJulian Elischer "%s: Could not receive data from L2CAP socket, error=%d, state=%d, flags=%#x\n", 1566f2bb1caeSJulian Elischer __func__, error, s->state, s->flags); 1567f2bb1caeSJulian Elischer 1568f2bb1caeSJulian Elischer return (error); 1569f2bb1caeSJulian Elischer } 1570f2bb1caeSJulian Elischer 1571f2bb1caeSJulian Elischer /* 1572f2bb1caeSJulian Elischer * Read all packets from the L2CAP socket. 1573f2bb1caeSJulian Elischer * XXX FIXME/VERIFY is that correct? For now use m->m_nextpkt as 1574f2bb1caeSJulian Elischer * indication that there is more packets on the socket's buffer. 1575f2bb1caeSJulian Elischer * Also what should we use in uio.uio_resid? 1576f2bb1caeSJulian Elischer * May be s->mtu + sizeof(struct rfcomm_frame_hdr) + 1 + 1? 1577f2bb1caeSJulian Elischer */ 1578f2bb1caeSJulian Elischer 1579f2bb1caeSJulian Elischer for (more = 1; more; ) { 1580f2bb1caeSJulian Elischer /* Try to get next packet from socket */ 1581f2bb1caeSJulian Elischer bzero(&uio, sizeof(uio)); 1582f2bb1caeSJulian Elischer /* uio.uio_td = NULL; */ 1583f2bb1caeSJulian Elischer uio.uio_resid = 1000000000; 1584f2bb1caeSJulian Elischer flags = MSG_DONTWAIT; 1585f2bb1caeSJulian Elischer 1586f2bb1caeSJulian Elischer m = NULL; 1587b0668f71SRobert Watson error = soreceive(s->l2so, NULL, &uio, &m, 1588b0668f71SRobert Watson (struct mbuf **) NULL, &flags); 1589f2bb1caeSJulian Elischer if (error != 0) { 1590f2bb1caeSJulian Elischer if (error == EWOULDBLOCK) 1591f2bb1caeSJulian Elischer return (0); /* XXX can happen? */ 1592f2bb1caeSJulian Elischer 1593f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 1594f2bb1caeSJulian Elischer "%s: Could not receive data from L2CAP socket, error=%d\n", __func__, error); 1595f2bb1caeSJulian Elischer 1596f2bb1caeSJulian Elischer return (error); 1597f2bb1caeSJulian Elischer } 1598f2bb1caeSJulian Elischer 1599f2bb1caeSJulian Elischer more = (m->m_nextpkt != NULL); 1600f2bb1caeSJulian Elischer m->m_nextpkt = NULL; 1601f2bb1caeSJulian Elischer 1602f2bb1caeSJulian Elischer ng_btsocket_rfcomm_receive_frame(s, m); 1603f2bb1caeSJulian Elischer } 1604f2bb1caeSJulian Elischer 1605f2bb1caeSJulian Elischer return (0); 1606f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_session_receive */ 1607f2bb1caeSJulian Elischer 1608f2bb1caeSJulian Elischer /* 1609f2bb1caeSJulian Elischer * Send data on RFCOMM session 1610f2bb1caeSJulian Elischer * XXX FIXME locking for "l2so"? 1611f2bb1caeSJulian Elischer */ 1612f2bb1caeSJulian Elischer 1613f2bb1caeSJulian Elischer static int 1614f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_send(ng_btsocket_rfcomm_session_p s) 1615f2bb1caeSJulian Elischer { 1616f2bb1caeSJulian Elischer struct mbuf *m = NULL; 1617f2bb1caeSJulian Elischer int error; 1618f2bb1caeSJulian Elischer 1619f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 1620f2bb1caeSJulian Elischer 1621f2bb1caeSJulian Elischer /* Send as much as we can from the session queue */ 1622f2bb1caeSJulian Elischer while (sowriteable(s->l2so)) { 1623f2bb1caeSJulian Elischer /* Check if socket still OK */ 1624f2bb1caeSJulian Elischer if ((error = s->l2so->so_error) != 0) { 1625f2bb1caeSJulian Elischer s->l2so->so_error = 0; 1626f2bb1caeSJulian Elischer 1627f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 1628f2bb1caeSJulian Elischer "%s: Detected error=%d on L2CAP socket, state=%d, flags=%#x\n", 1629f2bb1caeSJulian Elischer __func__, error, s->state, s->flags); 1630f2bb1caeSJulian Elischer 1631f2bb1caeSJulian Elischer return (error); 1632f2bb1caeSJulian Elischer } 1633f2bb1caeSJulian Elischer 1634f2bb1caeSJulian Elischer NG_BT_MBUFQ_DEQUEUE(&s->outq, m); 1635f2bb1caeSJulian Elischer if (m == NULL) 1636f2bb1caeSJulian Elischer return (0); /* we are done */ 1637f2bb1caeSJulian Elischer 1638f2bb1caeSJulian Elischer /* Call send function on the L2CAP socket */ 1639280c458aSMaksim Yevmenkin error = (*s->l2so->so_proto->pr_usrreqs->pru_send)(s->l2so, 1640280c458aSMaksim Yevmenkin 0, m, NULL, NULL, curthread /* XXX */); 1641f2bb1caeSJulian Elischer if (error != 0) { 1642f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 1643f2bb1caeSJulian Elischer "%s: Could not send data to L2CAP socket, error=%d\n", __func__, error); 1644f2bb1caeSJulian Elischer 1645f2bb1caeSJulian Elischer return (error); 1646f2bb1caeSJulian Elischer } 1647f2bb1caeSJulian Elischer } 1648f2bb1caeSJulian Elischer 1649f2bb1caeSJulian Elischer return (0); 1650f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_session_send */ 1651f2bb1caeSJulian Elischer 1652f2bb1caeSJulian Elischer /* 1653f2bb1caeSJulian Elischer * Close and disconnect all DLCs for the given session. Caller must hold 1654f2bb1caeSJulian Elischer * s->sesson_mtx. Will wakeup session. 1655f2bb1caeSJulian Elischer */ 1656f2bb1caeSJulian Elischer 1657f2bb1caeSJulian Elischer static void 1658f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_clean(ng_btsocket_rfcomm_session_p s) 1659f2bb1caeSJulian Elischer { 1660f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb_next = NULL; 1661f2bb1caeSJulian Elischer int error; 1662f2bb1caeSJulian Elischer 1663f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 1664f2bb1caeSJulian Elischer 1665f2bb1caeSJulian Elischer /* 1666f2bb1caeSJulian Elischer * Note: cannot use LIST_FOREACH because ng_btsocket_rfcomm_pcb_kill 1667f2bb1caeSJulian Elischer * will unlink DLC from the session 1668f2bb1caeSJulian Elischer */ 1669f2bb1caeSJulian Elischer 1670f2bb1caeSJulian Elischer for (pcb = LIST_FIRST(&s->dlcs); pcb != NULL; ) { 1671f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 1672f2bb1caeSJulian Elischer pcb_next = LIST_NEXT(pcb, session_next); 1673f2bb1caeSJulian Elischer 1674f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 1675f2bb1caeSJulian Elischer "%s: Disconnecting dlci=%d, state=%d, flags=%#x\n", 1676f2bb1caeSJulian Elischer __func__, pcb->dlci, pcb->state, pcb->flags); 1677f2bb1caeSJulian Elischer 1678f2bb1caeSJulian Elischer if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONNECTED) 1679f2bb1caeSJulian Elischer error = ECONNRESET; 1680f2bb1caeSJulian Elischer else 1681f2bb1caeSJulian Elischer error = ECONNREFUSED; 1682f2bb1caeSJulian Elischer 16837c380856SMaksim Yevmenkin ng_btsocket_rfcomm_pcb_kill(pcb, error); 1684f2bb1caeSJulian Elischer 1685f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 1686f2bb1caeSJulian Elischer pcb = pcb_next; 1687f2bb1caeSJulian Elischer } 1688f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_session_clean */ 1689f2bb1caeSJulian Elischer 1690f2bb1caeSJulian Elischer /* 1691f2bb1caeSJulian Elischer * Process all DLCs on the session. Caller MUST hold s->session_mtx. 1692f2bb1caeSJulian Elischer */ 1693f2bb1caeSJulian Elischer 1694f2bb1caeSJulian Elischer static void 1695f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_process_pcb(ng_btsocket_rfcomm_session_p s) 1696f2bb1caeSJulian Elischer { 1697f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb_next = NULL; 1698f2bb1caeSJulian Elischer int error; 1699f2bb1caeSJulian Elischer 1700f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 1701f2bb1caeSJulian Elischer 1702f2bb1caeSJulian Elischer /* 1703f2bb1caeSJulian Elischer * Note: cannot use LIST_FOREACH because ng_btsocket_rfcomm_pcb_kill 1704f2bb1caeSJulian Elischer * will unlink DLC from the session 1705f2bb1caeSJulian Elischer */ 1706f2bb1caeSJulian Elischer 1707f2bb1caeSJulian Elischer for (pcb = LIST_FIRST(&s->dlcs); pcb != NULL; ) { 1708f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 1709f2bb1caeSJulian Elischer pcb_next = LIST_NEXT(pcb, session_next); 1710f2bb1caeSJulian Elischer 1711f2bb1caeSJulian Elischer switch (pcb->state) { 1712f2bb1caeSJulian Elischer 1713f2bb1caeSJulian Elischer /* 1714f2bb1caeSJulian Elischer * If DLC in W4_CONNECT state then we should check for both 1715f2bb1caeSJulian Elischer * timeout and detach. 1716f2bb1caeSJulian Elischer */ 1717f2bb1caeSJulian Elischer 1718f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT: 17197c380856SMaksim Yevmenkin if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_DETACHED) 17207c380856SMaksim Yevmenkin ng_btsocket_rfcomm_pcb_kill(pcb, 0); 17217c380856SMaksim Yevmenkin else if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT) 17227c380856SMaksim Yevmenkin ng_btsocket_rfcomm_pcb_kill(pcb, ETIMEDOUT); 1723f2bb1caeSJulian Elischer break; 1724f2bb1caeSJulian Elischer 1725f2bb1caeSJulian Elischer /* 1726f2bb1caeSJulian Elischer * If DLC in CONFIGURING or CONNECTING state then we only 1727f2bb1caeSJulian Elischer * should check for timeout. If detach() was called then 1728f2bb1caeSJulian Elischer * DLC will be moved into DISCONNECTING state. 1729f2bb1caeSJulian Elischer */ 1730f2bb1caeSJulian Elischer 1731f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING: 1732f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_CONNECTING: 1733f2bb1caeSJulian Elischer if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT) 17347c380856SMaksim Yevmenkin ng_btsocket_rfcomm_pcb_kill(pcb, ETIMEDOUT); 1735f2bb1caeSJulian Elischer break; 1736f2bb1caeSJulian Elischer 1737f2bb1caeSJulian Elischer /* 1738f2bb1caeSJulian Elischer * If DLC in CONNECTED state then we need to send data (if any) 1739f2bb1caeSJulian Elischer * from the socket's send queue. Note that we will send data 1740f2bb1caeSJulian Elischer * from either all sockets or none. This may overload session's 1741f2bb1caeSJulian Elischer * outgoing queue (but we do not check for that). 1742f2bb1caeSJulian Elischer * 1743f2bb1caeSJulian Elischer * XXX FIXME need scheduler for RFCOMM sockets 1744f2bb1caeSJulian Elischer */ 1745f2bb1caeSJulian Elischer 1746f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_CONNECTED: 1747f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_pcb_send(pcb, ALOT); 1748f2bb1caeSJulian Elischer if (error != 0) 17497c380856SMaksim Yevmenkin ng_btsocket_rfcomm_pcb_kill(pcb, error); 1750f2bb1caeSJulian Elischer break; 1751f2bb1caeSJulian Elischer 1752f2bb1caeSJulian Elischer /* 1753f2bb1caeSJulian Elischer * If DLC in DISCONNECTING state then we must send DISC frame. 1754f2bb1caeSJulian Elischer * Note that if DLC has timeout set then we do not need to 1755f2bb1caeSJulian Elischer * resend DISC frame. 1756f2bb1caeSJulian Elischer * 1757f2bb1caeSJulian Elischer * XXX FIXME need to drain all data from the socket's queue 1758f2bb1caeSJulian Elischer * if LINGER option was set 1759f2bb1caeSJulian Elischer */ 1760f2bb1caeSJulian Elischer 1761f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING: 1762f2bb1caeSJulian Elischer if (!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)) { 1763f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_command( 1764f2bb1caeSJulian Elischer pcb->session, RFCOMM_FRAME_DISC, 1765f2bb1caeSJulian Elischer pcb->dlci); 1766f2bb1caeSJulian Elischer if (error == 0) 1767f2bb1caeSJulian Elischer ng_btsocket_rfcomm_timeout(pcb); 17687c380856SMaksim Yevmenkin else 17697c380856SMaksim Yevmenkin ng_btsocket_rfcomm_pcb_kill(pcb, error); 1770f2bb1caeSJulian Elischer } else if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT) 17717c380856SMaksim Yevmenkin ng_btsocket_rfcomm_pcb_kill(pcb, ETIMEDOUT); 1772f2bb1caeSJulian Elischer break; 1773f2bb1caeSJulian Elischer 1774f2bb1caeSJulian Elischer /* case NG_BTSOCKET_RFCOMM_DLC_CLOSED: */ 1775f2bb1caeSJulian Elischer default: 1776f2bb1caeSJulian Elischer panic("%s: Invalid DLC state=%d, flags=%#x\n", 1777f2bb1caeSJulian Elischer __func__, pcb->state, pcb->flags); 1778f2bb1caeSJulian Elischer break; 1779f2bb1caeSJulian Elischer } 1780f2bb1caeSJulian Elischer 1781f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 1782f2bb1caeSJulian Elischer pcb = pcb_next; 1783f2bb1caeSJulian Elischer } 1784f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_session_process_pcb */ 1785f2bb1caeSJulian Elischer 1786f2bb1caeSJulian Elischer /* 1787f2bb1caeSJulian Elischer * Find RFCOMM session between "src" and "dst". 1788f2bb1caeSJulian Elischer * Caller MUST hold ng_btsocket_rfcomm_sessions_mtx. 1789f2bb1caeSJulian Elischer */ 1790f2bb1caeSJulian Elischer 1791f2bb1caeSJulian Elischer static ng_btsocket_rfcomm_session_p 1792f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_by_addr(bdaddr_p src, bdaddr_p dst) 1793f2bb1caeSJulian Elischer { 1794f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_p s = NULL; 1795f2bb1caeSJulian Elischer ng_btsocket_l2cap_pcb_p l2pcb = NULL; 1796f2bb1caeSJulian Elischer int any_src; 1797f2bb1caeSJulian Elischer 1798f2bb1caeSJulian Elischer mtx_assert(&ng_btsocket_rfcomm_sessions_mtx, MA_OWNED); 1799f2bb1caeSJulian Elischer 1800f2bb1caeSJulian Elischer any_src = (bcmp(src, NG_HCI_BDADDR_ANY, sizeof(*src)) == 0); 1801f2bb1caeSJulian Elischer 1802f2bb1caeSJulian Elischer LIST_FOREACH(s, &ng_btsocket_rfcomm_sessions, next) { 1803f2bb1caeSJulian Elischer l2pcb = so2l2cap_pcb(s->l2so); 1804f2bb1caeSJulian Elischer 1805f2bb1caeSJulian Elischer if ((any_src || bcmp(&l2pcb->src, src, sizeof(*src)) == 0) && 1806f2bb1caeSJulian Elischer bcmp(&l2pcb->dst, dst, sizeof(*dst)) == 0) 1807f2bb1caeSJulian Elischer break; 1808f2bb1caeSJulian Elischer } 1809f2bb1caeSJulian Elischer 1810f2bb1caeSJulian Elischer return (s); 1811f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_session_by_addr */ 1812f2bb1caeSJulian Elischer 1813f2bb1caeSJulian Elischer /***************************************************************************** 1814f2bb1caeSJulian Elischer ***************************************************************************** 1815f2bb1caeSJulian Elischer ** RFCOMM 1816f2bb1caeSJulian Elischer ***************************************************************************** 1817f2bb1caeSJulian Elischer *****************************************************************************/ 1818f2bb1caeSJulian Elischer 1819f2bb1caeSJulian Elischer /* 1820f2bb1caeSJulian Elischer * Process incoming RFCOMM frame. Caller must hold s->session_mtx. 1821f2bb1caeSJulian Elischer * XXX FIXME check frame length 1822f2bb1caeSJulian Elischer */ 1823f2bb1caeSJulian Elischer 1824f2bb1caeSJulian Elischer static int 1825f2bb1caeSJulian Elischer ng_btsocket_rfcomm_receive_frame(ng_btsocket_rfcomm_session_p s, 1826f2bb1caeSJulian Elischer struct mbuf *m0) 1827f2bb1caeSJulian Elischer { 1828f2bb1caeSJulian Elischer struct rfcomm_frame_hdr *hdr = NULL; 1829f2bb1caeSJulian Elischer struct mbuf *m = NULL; 1830f2bb1caeSJulian Elischer u_int16_t length; 1831f2bb1caeSJulian Elischer u_int8_t dlci, type; 1832f2bb1caeSJulian Elischer int error = 0; 1833f2bb1caeSJulian Elischer 1834f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 1835f2bb1caeSJulian Elischer 1836f2bb1caeSJulian Elischer /* Pullup as much as we can into first mbuf (for direct access) */ 1837f2bb1caeSJulian Elischer length = min(m0->m_pkthdr.len, MHLEN); 1838f2bb1caeSJulian Elischer if (m0->m_len < length) { 1839f2bb1caeSJulian Elischer if ((m0 = m_pullup(m0, length)) == NULL) { 1840f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ALERT( 1841f2bb1caeSJulian Elischer "%s: m_pullup(%d) failed\n", __func__, length); 1842f2bb1caeSJulian Elischer 1843f2bb1caeSJulian Elischer return (ENOBUFS); 1844f2bb1caeSJulian Elischer } 1845f2bb1caeSJulian Elischer } 1846f2bb1caeSJulian Elischer 1847f2bb1caeSJulian Elischer hdr = mtod(m0, struct rfcomm_frame_hdr *); 1848f2bb1caeSJulian Elischer dlci = RFCOMM_DLCI(hdr->address); 1849f2bb1caeSJulian Elischer type = RFCOMM_TYPE(hdr->control); 1850f2bb1caeSJulian Elischer 1851f2bb1caeSJulian Elischer /* Test EA bit in length. If not set then we have 2 bytes of length */ 1852f2bb1caeSJulian Elischer if (!RFCOMM_EA(hdr->length)) { 1853f2bb1caeSJulian Elischer bcopy(&hdr->length, &length, sizeof(length)); 1854f93b258cSMaksim Yevmenkin length = le16toh(length) >> 1; 1855f2bb1caeSJulian Elischer m_adj(m0, sizeof(*hdr) + 1); 1856f2bb1caeSJulian Elischer } else { 1857f2bb1caeSJulian Elischer length = hdr->length >> 1; 1858f2bb1caeSJulian Elischer m_adj(m0, sizeof(*hdr)); 1859f2bb1caeSJulian Elischer } 1860f2bb1caeSJulian Elischer 1861f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 1862f2bb1caeSJulian Elischer "%s: Got frame type=%#x, dlci=%d, length=%d, cr=%d, pf=%d, len=%d\n", 1863f2bb1caeSJulian Elischer __func__, type, dlci, length, RFCOMM_CR(hdr->address), 1864f2bb1caeSJulian Elischer RFCOMM_PF(hdr->control), m0->m_pkthdr.len); 1865f2bb1caeSJulian Elischer 1866f2bb1caeSJulian Elischer /* 1867f2bb1caeSJulian Elischer * Get FCS (the last byte in the frame) 1868f2bb1caeSJulian Elischer * XXX this will not work if mbuf chain ends with empty mbuf. 1869f2bb1caeSJulian Elischer * XXX let's hope it never happens :) 1870f2bb1caeSJulian Elischer */ 1871f2bb1caeSJulian Elischer 1872f2bb1caeSJulian Elischer for (m = m0; m->m_next != NULL; m = m->m_next) 1873f2bb1caeSJulian Elischer ; 1874f2bb1caeSJulian Elischer if (m->m_len <= 0) 1875f2bb1caeSJulian Elischer panic("%s: Empty mbuf at the end of the chain, len=%d\n", 1876f2bb1caeSJulian Elischer __func__, m->m_len); 1877f2bb1caeSJulian Elischer 1878f2bb1caeSJulian Elischer /* 1879f2bb1caeSJulian Elischer * Check FCS. We only need to calculate FCS on first 2 or 3 bytes 1880f2bb1caeSJulian Elischer * and already m_pullup'ed mbuf chain, so it should be safe. 1881f2bb1caeSJulian Elischer */ 1882f2bb1caeSJulian Elischer 1883f2bb1caeSJulian Elischer if (ng_btsocket_rfcomm_check_fcs((u_int8_t *) hdr, type, m->m_data[m->m_len - 1])) { 1884f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 1885f2bb1caeSJulian Elischer "%s: Invalid RFCOMM packet. Bad checksum\n", __func__); 1886f2bb1caeSJulian Elischer NG_FREE_M(m0); 1887f2bb1caeSJulian Elischer 1888f2bb1caeSJulian Elischer return (EINVAL); 1889f2bb1caeSJulian Elischer } 1890f2bb1caeSJulian Elischer 1891f2bb1caeSJulian Elischer m_adj(m0, -1); /* Trim FCS byte */ 1892f2bb1caeSJulian Elischer 1893f2bb1caeSJulian Elischer /* 1894f2bb1caeSJulian Elischer * Process RFCOMM frame. 1895f2bb1caeSJulian Elischer * 1896f2bb1caeSJulian Elischer * From TS 07.10 spec 1897f2bb1caeSJulian Elischer * 1898f2bb1caeSJulian Elischer * "... In the case where a SABM or DISC command with the P bit set 1899f2bb1caeSJulian Elischer * to 0 is received then the received frame shall be discarded..." 1900f2bb1caeSJulian Elischer * 1901f2bb1caeSJulian Elischer * "... If a unsolicited DM response is received then the frame shall 1902f2bb1caeSJulian Elischer * be processed irrespective of the P/F setting... " 1903f2bb1caeSJulian Elischer * 1904f2bb1caeSJulian Elischer * "... The station may transmit response frames with the F bit set 1905f2bb1caeSJulian Elischer * to 0 at any opportunity on an asynchronous basis. However, in the 1906f2bb1caeSJulian Elischer * case where a UA response is received with the F bit set to 0 then 1907f2bb1caeSJulian Elischer * the received frame shall be discarded..." 1908f2bb1caeSJulian Elischer * 1909f2bb1caeSJulian Elischer * From Bluetooth spec 1910f2bb1caeSJulian Elischer * 1911f2bb1caeSJulian Elischer * "... When credit based flow control is being used, the meaning of 1912f2bb1caeSJulian Elischer * the P/F bit in the control field of the RFCOMM header is redefined 1913f2bb1caeSJulian Elischer * for UIH frames..." 1914f2bb1caeSJulian Elischer */ 1915f2bb1caeSJulian Elischer 1916f2bb1caeSJulian Elischer switch (type) { 1917f2bb1caeSJulian Elischer case RFCOMM_FRAME_SABM: 1918f2bb1caeSJulian Elischer if (RFCOMM_PF(hdr->control)) 1919f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_receive_sabm(s, dlci); 1920f2bb1caeSJulian Elischer break; 1921f2bb1caeSJulian Elischer 1922f2bb1caeSJulian Elischer case RFCOMM_FRAME_DISC: 1923f2bb1caeSJulian Elischer if (RFCOMM_PF(hdr->control)) 1924f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_receive_disc(s, dlci); 1925f2bb1caeSJulian Elischer break; 1926f2bb1caeSJulian Elischer 1927f2bb1caeSJulian Elischer case RFCOMM_FRAME_UA: 1928f2bb1caeSJulian Elischer if (RFCOMM_PF(hdr->control)) 1929f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_receive_ua(s, dlci); 1930f2bb1caeSJulian Elischer break; 1931f2bb1caeSJulian Elischer 1932f2bb1caeSJulian Elischer case RFCOMM_FRAME_DM: 1933f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_receive_dm(s, dlci); 1934f2bb1caeSJulian Elischer break; 1935f2bb1caeSJulian Elischer 1936f2bb1caeSJulian Elischer case RFCOMM_FRAME_UIH: 1937f2bb1caeSJulian Elischer if (dlci == 0) 1938f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_receive_mcc(s, m0); 1939f2bb1caeSJulian Elischer else 1940f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_receive_uih(s, dlci, 1941f2bb1caeSJulian Elischer RFCOMM_PF(hdr->control), m0); 1942f2bb1caeSJulian Elischer 1943f2bb1caeSJulian Elischer return (error); 1944f2bb1caeSJulian Elischer /* NOT REACHED */ 1945f2bb1caeSJulian Elischer 1946f2bb1caeSJulian Elischer default: 1947f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 1948f2bb1caeSJulian Elischer "%s: Invalid RFCOMM packet. Unknown type=%#x\n", __func__, type); 1949f2bb1caeSJulian Elischer error = EINVAL; 1950f2bb1caeSJulian Elischer break; 1951f2bb1caeSJulian Elischer } 1952f2bb1caeSJulian Elischer 1953f2bb1caeSJulian Elischer NG_FREE_M(m0); 1954f2bb1caeSJulian Elischer 1955f2bb1caeSJulian Elischer return (error); 1956f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_receive_frame */ 1957f2bb1caeSJulian Elischer 1958f2bb1caeSJulian Elischer /* 1959f2bb1caeSJulian Elischer * Process RFCOMM SABM frame 1960f2bb1caeSJulian Elischer */ 1961f2bb1caeSJulian Elischer 1962f2bb1caeSJulian Elischer static int 1963f2bb1caeSJulian Elischer ng_btsocket_rfcomm_receive_sabm(ng_btsocket_rfcomm_session_p s, int dlci) 1964f2bb1caeSJulian Elischer { 1965f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = NULL; 1966f2bb1caeSJulian Elischer int error = 0; 1967f2bb1caeSJulian Elischer 1968f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 1969f2bb1caeSJulian Elischer 1970f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 1971f2bb1caeSJulian Elischer "%s: Got SABM, session state=%d, flags=%#x, mtu=%d, dlci=%d\n", 1972f2bb1caeSJulian Elischer __func__, s->state, s->flags, s->mtu, dlci); 1973f2bb1caeSJulian Elischer 1974f2bb1caeSJulian Elischer /* DLCI == 0 means open multiplexor channel */ 1975f2bb1caeSJulian Elischer if (dlci == 0) { 1976f2bb1caeSJulian Elischer switch (s->state) { 1977f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED: 1978f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_OPEN: 1979f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_command(s, 1980f2bb1caeSJulian Elischer RFCOMM_FRAME_UA, dlci); 1981f2bb1caeSJulian Elischer if (error == 0) { 1982f2bb1caeSJulian Elischer s->state = NG_BTSOCKET_RFCOMM_SESSION_OPEN; 1983f2bb1caeSJulian Elischer ng_btsocket_rfcomm_connect_cfm(s); 1984f2bb1caeSJulian Elischer } else { 1985f2bb1caeSJulian Elischer s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 1986f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_clean(s); 1987f2bb1caeSJulian Elischer } 1988f2bb1caeSJulian Elischer break; 1989f2bb1caeSJulian Elischer 1990f2bb1caeSJulian Elischer default: 1991f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_WARN( 1992f2bb1caeSJulian Elischer "%s: Got SABM for session in invalid state state=%d, flags=%#x\n", 1993f2bb1caeSJulian Elischer __func__, s->state, s->flags); 1994f2bb1caeSJulian Elischer error = EINVAL; 1995f2bb1caeSJulian Elischer break; 1996f2bb1caeSJulian Elischer } 1997f2bb1caeSJulian Elischer 1998f2bb1caeSJulian Elischer return (error); 1999f2bb1caeSJulian Elischer } 2000f2bb1caeSJulian Elischer 2001f2bb1caeSJulian Elischer /* Make sure multiplexor channel is open */ 2002f2bb1caeSJulian Elischer if (s->state != NG_BTSOCKET_RFCOMM_SESSION_OPEN) { 2003f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 2004f2bb1caeSJulian Elischer "%s: Got SABM for dlci=%d with mulitplexor channel closed, state=%d, " \ 2005f2bb1caeSJulian Elischer "flags=%#x\n", __func__, dlci, s->state, s->flags); 2006f2bb1caeSJulian Elischer 2007f2bb1caeSJulian Elischer return (EINVAL); 2008f2bb1caeSJulian Elischer } 2009f2bb1caeSJulian Elischer 2010f2bb1caeSJulian Elischer /* 2011f2bb1caeSJulian Elischer * Check if we have this DLCI. This might happen when remote 2012f2bb1caeSJulian Elischer * peer uses PN command before actual open (SABM) happens. 2013f2bb1caeSJulian Elischer */ 2014f2bb1caeSJulian Elischer 2015f2bb1caeSJulian Elischer pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci); 2016f2bb1caeSJulian Elischer if (pcb != NULL) { 2017f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 2018f2bb1caeSJulian Elischer 2019f2bb1caeSJulian Elischer if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTING) { 2020f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 2021f2bb1caeSJulian Elischer "%s: Got SABM for dlci=%d in invalid state=%d, flags=%#x\n", 2022f2bb1caeSJulian Elischer __func__, dlci, pcb->state, pcb->flags); 2023f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 2024f2bb1caeSJulian Elischer 2025f2bb1caeSJulian Elischer return (ENOENT); 2026f2bb1caeSJulian Elischer } 2027f2bb1caeSJulian Elischer 2028f2bb1caeSJulian Elischer ng_btsocket_rfcomm_untimeout(pcb); 2029f2bb1caeSJulian Elischer 2030f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_UA,dlci); 2031f2bb1caeSJulian Elischer if (error == 0) 2032f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_msc(pcb); 2033f2bb1caeSJulian Elischer 2034f2bb1caeSJulian Elischer if (error == 0) { 2035f2bb1caeSJulian Elischer pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTED; 2036f2bb1caeSJulian Elischer soisconnected(pcb->so); 20377c380856SMaksim Yevmenkin } else 20387c380856SMaksim Yevmenkin ng_btsocket_rfcomm_pcb_kill(pcb, error); 2039f2bb1caeSJulian Elischer 2040f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 2041f2bb1caeSJulian Elischer 2042f2bb1caeSJulian Elischer return (error); 2043f2bb1caeSJulian Elischer } 2044f2bb1caeSJulian Elischer 2045f2bb1caeSJulian Elischer /* 2046f2bb1caeSJulian Elischer * We do not have requested DLCI, so it must be an incoming connection 2047f2bb1caeSJulian Elischer * with default parameters. Try to accept it. 2048f2bb1caeSJulian Elischer */ 2049f2bb1caeSJulian Elischer 2050f2bb1caeSJulian Elischer pcb = ng_btsocket_rfcomm_connect_ind(s, RFCOMM_SRVCHANNEL(dlci)); 2051f2bb1caeSJulian Elischer if (pcb != NULL) { 2052f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 2053f2bb1caeSJulian Elischer 2054f2bb1caeSJulian Elischer pcb->dlci = dlci; 2055f2bb1caeSJulian Elischer 2056f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_UA,dlci); 20570986ab12SMaksim Yevmenkin if (error == 0) 20580986ab12SMaksim Yevmenkin error = ng_btsocket_rfcomm_send_msc(pcb); 20590986ab12SMaksim Yevmenkin 2060f2bb1caeSJulian Elischer if (error == 0) { 2061f2bb1caeSJulian Elischer pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTED; 2062f2bb1caeSJulian Elischer soisconnected(pcb->so); 20637c380856SMaksim Yevmenkin } else 20647c380856SMaksim Yevmenkin ng_btsocket_rfcomm_pcb_kill(pcb, error); 2065f2bb1caeSJulian Elischer 2066f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 2067f2bb1caeSJulian Elischer } else 2068f2bb1caeSJulian Elischer /* Nobody is listen()ing on the requested DLCI */ 2069f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_DM,dlci); 2070f2bb1caeSJulian Elischer 2071f2bb1caeSJulian Elischer return (error); 2072f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_receive_sabm */ 2073f2bb1caeSJulian Elischer 2074f2bb1caeSJulian Elischer /* 2075f2bb1caeSJulian Elischer * Process RFCOMM DISC frame 2076f2bb1caeSJulian Elischer */ 2077f2bb1caeSJulian Elischer 2078f2bb1caeSJulian Elischer static int 2079f2bb1caeSJulian Elischer ng_btsocket_rfcomm_receive_disc(ng_btsocket_rfcomm_session_p s, int dlci) 2080f2bb1caeSJulian Elischer { 2081f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = NULL; 2082f2bb1caeSJulian Elischer int error = 0; 2083f2bb1caeSJulian Elischer 2084f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 2085f2bb1caeSJulian Elischer 2086f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 2087f2bb1caeSJulian Elischer "%s: Got DISC, session state=%d, flags=%#x, mtu=%d, dlci=%d\n", 2088f2bb1caeSJulian Elischer __func__, s->state, s->flags, s->mtu, dlci); 2089f2bb1caeSJulian Elischer 2090f2bb1caeSJulian Elischer /* DLCI == 0 means close multiplexor channel */ 2091f2bb1caeSJulian Elischer if (dlci == 0) { 2092f2bb1caeSJulian Elischer /* XXX FIXME assume that remote side will close the socket */ 2093f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_command(s, RFCOMM_FRAME_UA, 0); 209448bd0712SMaksim Yevmenkin if (error == 0) { 209548bd0712SMaksim Yevmenkin if (s->state == NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING) 209648bd0712SMaksim Yevmenkin s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; /* XXX */ 2097f2bb1caeSJulian Elischer else 209848bd0712SMaksim Yevmenkin s->state = NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING; 209948bd0712SMaksim Yevmenkin } else 2100f2bb1caeSJulian Elischer s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; /* XXX */ 2101f2bb1caeSJulian Elischer 2102f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_clean(s); 2103f2bb1caeSJulian Elischer } else { 2104f2bb1caeSJulian Elischer pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci); 2105f2bb1caeSJulian Elischer if (pcb != NULL) { 2106f2bb1caeSJulian Elischer int err; 2107f2bb1caeSJulian Elischer 2108f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 2109f2bb1caeSJulian Elischer 2110f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 2111f2bb1caeSJulian Elischer "%s: Got DISC for dlci=%d, state=%d, flags=%#x\n", 2112f2bb1caeSJulian Elischer __func__, dlci, pcb->state, pcb->flags); 2113f2bb1caeSJulian Elischer 2114f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_command(s, 2115f2bb1caeSJulian Elischer RFCOMM_FRAME_UA, dlci); 2116f2bb1caeSJulian Elischer 2117f2bb1caeSJulian Elischer if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONNECTED) 2118f2bb1caeSJulian Elischer err = 0; 2119f2bb1caeSJulian Elischer else 2120f2bb1caeSJulian Elischer err = ECONNREFUSED; 2121f2bb1caeSJulian Elischer 21227c380856SMaksim Yevmenkin ng_btsocket_rfcomm_pcb_kill(pcb, err); 2123f2bb1caeSJulian Elischer 2124f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 2125f2bb1caeSJulian Elischer } else { 2126f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_WARN( 2127f2bb1caeSJulian Elischer "%s: Got DISC for non-existing dlci=%d\n", __func__, dlci); 2128f2bb1caeSJulian Elischer 2129f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_command(s, 2130f2bb1caeSJulian Elischer RFCOMM_FRAME_DM, dlci); 2131f2bb1caeSJulian Elischer } 2132f2bb1caeSJulian Elischer } 2133f2bb1caeSJulian Elischer 2134f2bb1caeSJulian Elischer return (error); 2135f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_receive_disc */ 2136f2bb1caeSJulian Elischer 2137f2bb1caeSJulian Elischer /* 2138f2bb1caeSJulian Elischer * Process RFCOMM UA frame 2139f2bb1caeSJulian Elischer */ 2140f2bb1caeSJulian Elischer 2141f2bb1caeSJulian Elischer static int 2142f2bb1caeSJulian Elischer ng_btsocket_rfcomm_receive_ua(ng_btsocket_rfcomm_session_p s, int dlci) 2143f2bb1caeSJulian Elischer { 2144f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = NULL; 2145f2bb1caeSJulian Elischer int error = 0; 2146f2bb1caeSJulian Elischer 2147f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 2148f2bb1caeSJulian Elischer 2149f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 2150f2bb1caeSJulian Elischer "%s: Got UA, session state=%d, flags=%#x, mtu=%d, dlci=%d\n", 2151f2bb1caeSJulian Elischer __func__, s->state, s->flags, s->mtu, dlci); 2152f2bb1caeSJulian Elischer 2153f2bb1caeSJulian Elischer /* dlci == 0 means multiplexor channel */ 2154f2bb1caeSJulian Elischer if (dlci == 0) { 2155f2bb1caeSJulian Elischer switch (s->state) { 2156f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED: 2157f2bb1caeSJulian Elischer s->state = NG_BTSOCKET_RFCOMM_SESSION_OPEN; 2158f2bb1caeSJulian Elischer ng_btsocket_rfcomm_connect_cfm(s); 2159f2bb1caeSJulian Elischer break; 2160f2bb1caeSJulian Elischer 2161f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING: 2162f2bb1caeSJulian Elischer s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 2163f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_clean(s); 2164f2bb1caeSJulian Elischer break; 2165f2bb1caeSJulian Elischer 2166f2bb1caeSJulian Elischer default: 2167f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_WARN( 2168f2bb1caeSJulian Elischer "%s: Got UA for session in invalid state=%d(%d), flags=%#x, mtu=%d\n", 2169f2bb1caeSJulian Elischer __func__, s->state, INITIATOR(s), s->flags, 2170f2bb1caeSJulian Elischer s->mtu); 2171f2bb1caeSJulian Elischer error = ENOENT; 2172f2bb1caeSJulian Elischer break; 2173f2bb1caeSJulian Elischer } 2174f2bb1caeSJulian Elischer 2175f2bb1caeSJulian Elischer return (error); 2176f2bb1caeSJulian Elischer } 2177f2bb1caeSJulian Elischer 2178f2bb1caeSJulian Elischer /* Check if we have this DLCI */ 2179f2bb1caeSJulian Elischer pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci); 2180f2bb1caeSJulian Elischer if (pcb != NULL) { 2181f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 2182f2bb1caeSJulian Elischer 2183f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 2184f2bb1caeSJulian Elischer "%s: Got UA for dlci=%d, state=%d, flags=%#x\n", 2185f2bb1caeSJulian Elischer __func__, dlci, pcb->state, pcb->flags); 2186f2bb1caeSJulian Elischer 2187f2bb1caeSJulian Elischer switch (pcb->state) { 2188f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_CONNECTING: 2189f2bb1caeSJulian Elischer ng_btsocket_rfcomm_untimeout(pcb); 2190f2bb1caeSJulian Elischer 2191f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_msc(pcb); 2192f2bb1caeSJulian Elischer if (error == 0) { 2193f2bb1caeSJulian Elischer pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTED; 2194f2bb1caeSJulian Elischer soisconnected(pcb->so); 2195f2bb1caeSJulian Elischer } 2196f2bb1caeSJulian Elischer break; 2197f2bb1caeSJulian Elischer 2198f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING: 21997c380856SMaksim Yevmenkin ng_btsocket_rfcomm_pcb_kill(pcb, 0); 2200f2bb1caeSJulian Elischer break; 2201f2bb1caeSJulian Elischer 2202f2bb1caeSJulian Elischer default: 2203f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_WARN( 2204f2bb1caeSJulian Elischer "%s: Got UA for dlci=%d in invalid state=%d, flags=%#x\n", 2205f2bb1caeSJulian Elischer __func__, dlci, pcb->state, pcb->flags); 2206f2bb1caeSJulian Elischer error = ENOENT; 2207f2bb1caeSJulian Elischer break; 2208f2bb1caeSJulian Elischer } 2209f2bb1caeSJulian Elischer 2210f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 2211f2bb1caeSJulian Elischer } else { 2212f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_WARN( 2213f2bb1caeSJulian Elischer "%s: Got UA for non-existing dlci=%d\n", __func__, dlci); 2214f2bb1caeSJulian Elischer 2215f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_DM,dlci); 2216f2bb1caeSJulian Elischer } 2217f2bb1caeSJulian Elischer 2218f2bb1caeSJulian Elischer return (error); 2219f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_receive_ua */ 2220f2bb1caeSJulian Elischer 2221f2bb1caeSJulian Elischer /* 2222f2bb1caeSJulian Elischer * Process RFCOMM DM frame 2223f2bb1caeSJulian Elischer */ 2224f2bb1caeSJulian Elischer 2225f2bb1caeSJulian Elischer static int 2226f2bb1caeSJulian Elischer ng_btsocket_rfcomm_receive_dm(ng_btsocket_rfcomm_session_p s, int dlci) 2227f2bb1caeSJulian Elischer { 2228f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = NULL; 2229f2bb1caeSJulian Elischer int error; 2230f2bb1caeSJulian Elischer 2231f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 2232f2bb1caeSJulian Elischer 2233f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 2234f2bb1caeSJulian Elischer "%s: Got DM, session state=%d, flags=%#x, mtu=%d, dlci=%d\n", 2235f2bb1caeSJulian Elischer __func__, s->state, s->flags, s->mtu, dlci); 2236f2bb1caeSJulian Elischer 2237f2bb1caeSJulian Elischer /* DLCI == 0 means multiplexor channel */ 2238f2bb1caeSJulian Elischer if (dlci == 0) { 2239f2bb1caeSJulian Elischer /* Disconnect all dlc's on the session */ 2240f2bb1caeSJulian Elischer s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 2241f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_clean(s); 2242f2bb1caeSJulian Elischer } else { 2243f2bb1caeSJulian Elischer pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci); 2244f2bb1caeSJulian Elischer if (pcb != NULL) { 2245f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 2246f2bb1caeSJulian Elischer 2247f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 2248f2bb1caeSJulian Elischer "%s: Got DM for dlci=%d, state=%d, flags=%#x\n", 2249f2bb1caeSJulian Elischer __func__, dlci, pcb->state, pcb->flags); 2250f2bb1caeSJulian Elischer 2251f2bb1caeSJulian Elischer if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONNECTED) 2252f2bb1caeSJulian Elischer error = ECONNRESET; 2253f2bb1caeSJulian Elischer else 2254f2bb1caeSJulian Elischer error = ECONNREFUSED; 2255f2bb1caeSJulian Elischer 22567c380856SMaksim Yevmenkin ng_btsocket_rfcomm_pcb_kill(pcb, error); 2257f2bb1caeSJulian Elischer 2258f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 2259f2bb1caeSJulian Elischer } else 2260f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_WARN( 2261f2bb1caeSJulian Elischer "%s: Got DM for non-existing dlci=%d\n", __func__, dlci); 2262f2bb1caeSJulian Elischer } 2263f2bb1caeSJulian Elischer 2264f2bb1caeSJulian Elischer return (0); 2265f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_receive_dm */ 2266f2bb1caeSJulian Elischer 2267f2bb1caeSJulian Elischer /* 2268f2bb1caeSJulian Elischer * Process RFCOMM UIH frame (data) 2269f2bb1caeSJulian Elischer */ 2270f2bb1caeSJulian Elischer 2271f2bb1caeSJulian Elischer static int 2272f2bb1caeSJulian Elischer ng_btsocket_rfcomm_receive_uih(ng_btsocket_rfcomm_session_p s, int dlci, 2273f2bb1caeSJulian Elischer int pf, struct mbuf *m0) 2274f2bb1caeSJulian Elischer { 2275f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = NULL; 2276f2bb1caeSJulian Elischer int error = 0; 2277f2bb1caeSJulian Elischer 2278f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 2279f2bb1caeSJulian Elischer 2280f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 2281f2bb1caeSJulian Elischer "%s: Got UIH, session state=%d, flags=%#x, mtu=%d, dlci=%d, pf=%d, len=%d\n", 2282f2bb1caeSJulian Elischer __func__, s->state, s->flags, s->mtu, dlci, pf, 2283f2bb1caeSJulian Elischer m0->m_pkthdr.len); 2284f2bb1caeSJulian Elischer 2285f2bb1caeSJulian Elischer /* XXX should we do it here? Check for session flow control */ 2286f2bb1caeSJulian Elischer if (s->flags & NG_BTSOCKET_RFCOMM_SESSION_LFC) { 2287f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_WARN( 2288f2bb1caeSJulian Elischer "%s: Got UIH with session flow control asserted, state=%d, flags=%#x\n", 2289f2bb1caeSJulian Elischer __func__, s->state, s->flags); 2290f2bb1caeSJulian Elischer goto drop; 2291f2bb1caeSJulian Elischer } 2292f2bb1caeSJulian Elischer 2293f2bb1caeSJulian Elischer /* Check if we have this dlci */ 2294f2bb1caeSJulian Elischer pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci); 2295f2bb1caeSJulian Elischer if (pcb == NULL) { 2296f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_WARN( 2297f2bb1caeSJulian Elischer "%s: Got UIH for non-existing dlci=%d\n", __func__, dlci); 2298f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_DM,dlci); 2299f2bb1caeSJulian Elischer goto drop; 2300f2bb1caeSJulian Elischer } 2301f2bb1caeSJulian Elischer 2302f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 2303f2bb1caeSJulian Elischer 2304f2bb1caeSJulian Elischer /* Check dlci state */ 2305f2bb1caeSJulian Elischer if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTED) { 2306f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_WARN( 2307f2bb1caeSJulian Elischer "%s: Got UIH for dlci=%d in invalid state=%d, flags=%#x\n", 2308f2bb1caeSJulian Elischer __func__, dlci, pcb->state, pcb->flags); 2309f2bb1caeSJulian Elischer error = EINVAL; 2310f2bb1caeSJulian Elischer goto drop1; 2311f2bb1caeSJulian Elischer } 2312f2bb1caeSJulian Elischer 2313f2bb1caeSJulian Elischer /* Check dlci flow control */ 2314f2bb1caeSJulian Elischer if (((pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) && pcb->rx_cred <= 0) || 2315f2bb1caeSJulian Elischer (pcb->lmodem & RFCOMM_MODEM_FC)) { 2316f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 2317f2bb1caeSJulian Elischer "%s: Got UIH for dlci=%d with asserted flow control, state=%d, " \ 2318f2bb1caeSJulian Elischer "flags=%#x, rx_cred=%d, lmodem=%#x\n", 2319f2bb1caeSJulian Elischer __func__, dlci, pcb->state, pcb->flags, 2320f2bb1caeSJulian Elischer pcb->rx_cred, pcb->lmodem); 2321f2bb1caeSJulian Elischer goto drop1; 2322f2bb1caeSJulian Elischer } 2323f2bb1caeSJulian Elischer 2324f2bb1caeSJulian Elischer /* Did we get any credits? */ 2325f2bb1caeSJulian Elischer if ((pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) && pf) { 2326f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 2327f2bb1caeSJulian Elischer "%s: Got %d more credits for dlci=%d, state=%d, flags=%#x, " \ 2328f2bb1caeSJulian Elischer "rx_cred=%d, tx_cred=%d\n", 2329f2bb1caeSJulian Elischer __func__, *mtod(m0, u_int8_t *), dlci, pcb->state, 2330f2bb1caeSJulian Elischer pcb->flags, pcb->rx_cred, pcb->tx_cred); 2331f2bb1caeSJulian Elischer 2332f2bb1caeSJulian Elischer pcb->tx_cred += *mtod(m0, u_int8_t *); 2333f2bb1caeSJulian Elischer m_adj(m0, 1); 2334f2bb1caeSJulian Elischer 2335f2bb1caeSJulian Elischer /* Send more from the DLC. XXX check for errors? */ 2336f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_send(pcb, ALOT); 2337f2bb1caeSJulian Elischer } 2338f2bb1caeSJulian Elischer 2339f2bb1caeSJulian Elischer /* OK the of the rest of the mbuf is the data */ 2340f2bb1caeSJulian Elischer if (m0->m_pkthdr.len > 0) { 2341f2bb1caeSJulian Elischer /* If we are using credit flow control decrease rx_cred here */ 2342f2bb1caeSJulian Elischer if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) { 2343f2bb1caeSJulian Elischer /* Give remote peer more credits (if needed) */ 2344f2bb1caeSJulian Elischer if (-- pcb->rx_cred <= RFCOMM_MAX_CREDITS / 2) 2345f2bb1caeSJulian Elischer ng_btsocket_rfcomm_send_credits(pcb); 2346f2bb1caeSJulian Elischer else 2347f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 2348f2bb1caeSJulian Elischer "%s: Remote side still has credits, dlci=%d, state=%d, flags=%#x, " \ 2349f2bb1caeSJulian Elischer "rx_cred=%d, tx_cred=%d\n", __func__, dlci, pcb->state, pcb->flags, 2350f2bb1caeSJulian Elischer pcb->rx_cred, pcb->tx_cred); 2351f2bb1caeSJulian Elischer } 2352f2bb1caeSJulian Elischer 2353f2bb1caeSJulian Elischer /* Check packet against mtu on dlci */ 2354f2bb1caeSJulian Elischer if (m0->m_pkthdr.len > pcb->mtu) { 2355f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 2356f2bb1caeSJulian Elischer "%s: Got oversized UIH for dlci=%d, state=%d, flags=%#x, mtu=%d, len=%d\n", 2357f2bb1caeSJulian Elischer __func__, dlci, pcb->state, pcb->flags, 2358f2bb1caeSJulian Elischer pcb->mtu, m0->m_pkthdr.len); 2359f2bb1caeSJulian Elischer 2360f2bb1caeSJulian Elischer error = EMSGSIZE; 2361f2bb1caeSJulian Elischer } else if (m0->m_pkthdr.len > sbspace(&pcb->so->so_rcv)) { 2362f2bb1caeSJulian Elischer 2363f2bb1caeSJulian Elischer /* 2364f2bb1caeSJulian Elischer * This is really bad. Receive queue on socket does 2365f2bb1caeSJulian Elischer * not have enough space for the packet. We do not 2366f2bb1caeSJulian Elischer * have any other choice but drop the packet. 2367f2bb1caeSJulian Elischer */ 2368f2bb1caeSJulian Elischer 2369f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 2370f2bb1caeSJulian Elischer "%s: Not enough space in socket receive queue. Dropping UIH for dlci=%d, " \ 2371f2bb1caeSJulian Elischer "state=%d, flags=%#x, len=%d, space=%ld\n", 2372f2bb1caeSJulian Elischer __func__, dlci, pcb->state, pcb->flags, 2373f2bb1caeSJulian Elischer m0->m_pkthdr.len, sbspace(&pcb->so->so_rcv)); 2374f2bb1caeSJulian Elischer 2375f2bb1caeSJulian Elischer error = ENOBUFS; 2376f2bb1caeSJulian Elischer } else { 2377f2bb1caeSJulian Elischer /* Append packet to the socket receive queue */ 2378829fae90SGleb Smirnoff sbappend(&pcb->so->so_rcv, m0, 0); 2379f2bb1caeSJulian Elischer m0 = NULL; 2380f2bb1caeSJulian Elischer 2381f2bb1caeSJulian Elischer sorwakeup(pcb->so); 2382f2bb1caeSJulian Elischer } 2383f2bb1caeSJulian Elischer } 2384f2bb1caeSJulian Elischer drop1: 2385f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 2386f2bb1caeSJulian Elischer drop: 2387f2bb1caeSJulian Elischer NG_FREE_M(m0); /* checks for != NULL */ 2388f2bb1caeSJulian Elischer 2389f2bb1caeSJulian Elischer return (error); 2390f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_receive_uih */ 2391f2bb1caeSJulian Elischer 2392f2bb1caeSJulian Elischer /* 2393f2bb1caeSJulian Elischer * Process RFCOMM MCC command (Multiplexor) 2394f2bb1caeSJulian Elischer * 2395f2bb1caeSJulian Elischer * From TS 07.10 spec 2396f2bb1caeSJulian Elischer * 2397f2bb1caeSJulian Elischer * "5.4.3.1 Information Data 2398f2bb1caeSJulian Elischer * 2399f2bb1caeSJulian Elischer * ...The frames (UIH) sent by the initiating station have the C/R bit set 2400f2bb1caeSJulian Elischer * to 1 and those sent by the responding station have the C/R bit set to 0..." 2401f2bb1caeSJulian Elischer * 2402f2bb1caeSJulian Elischer * "5.4.6.2 Operating procedures 2403f2bb1caeSJulian Elischer * 2404f2bb1caeSJulian Elischer * Messages always exist in pairs; a command message and a corresponding 2405f2bb1caeSJulian Elischer * response message. If the C/R bit is set to 1 the message is a command, 2406f2bb1caeSJulian Elischer * if it is set to 0 the message is a response... 2407f2bb1caeSJulian Elischer * 2408f2bb1caeSJulian Elischer * ... 2409f2bb1caeSJulian Elischer * 2410f2bb1caeSJulian Elischer * NOTE: Notice that when UIH frames are used to convey information on DLCI 0 2411f2bb1caeSJulian Elischer * there are at least two different fields that contain a C/R bit, and the 2412f2bb1caeSJulian Elischer * bits are set of different form. The C/R bit in the Type field shall be set 2413f2bb1caeSJulian Elischer * as it is stated above, while the C/R bit in the Address field (see subclause 2414f2bb1caeSJulian Elischer * 5.2.1.2) shall be set as it is described in subclause 5.4.3.1." 2415f2bb1caeSJulian Elischer */ 2416f2bb1caeSJulian Elischer 2417f2bb1caeSJulian Elischer static int 2418f2bb1caeSJulian Elischer ng_btsocket_rfcomm_receive_mcc(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2419f2bb1caeSJulian Elischer { 2420f2bb1caeSJulian Elischer struct rfcomm_mcc_hdr *hdr = NULL; 2421f2bb1caeSJulian Elischer u_int8_t cr, type, length; 2422f2bb1caeSJulian Elischer 2423f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 2424f2bb1caeSJulian Elischer 2425f2bb1caeSJulian Elischer /* 2426f2bb1caeSJulian Elischer * We can access data directly in the first mbuf, because we have 2427f2bb1caeSJulian Elischer * m_pullup()'ed mbuf chain in ng_btsocket_rfcomm_receive_frame(). 2428f2bb1caeSJulian Elischer * All MCC commands should fit into single mbuf (except probably TEST). 2429f2bb1caeSJulian Elischer */ 2430f2bb1caeSJulian Elischer 2431f2bb1caeSJulian Elischer hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2432f2bb1caeSJulian Elischer cr = RFCOMM_CR(hdr->type); 2433f2bb1caeSJulian Elischer type = RFCOMM_MCC_TYPE(hdr->type); 2434f2bb1caeSJulian Elischer length = RFCOMM_MCC_LENGTH(hdr->length); 2435f2bb1caeSJulian Elischer 2436f2bb1caeSJulian Elischer /* Check MCC frame length */ 2437f2bb1caeSJulian Elischer if (sizeof(*hdr) + length != m0->m_pkthdr.len) { 2438f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 2439f2bb1caeSJulian Elischer "%s: Invalid MCC frame length=%d, len=%d\n", 2440f2bb1caeSJulian Elischer __func__, length, m0->m_pkthdr.len); 2441f2bb1caeSJulian Elischer NG_FREE_M(m0); 2442f2bb1caeSJulian Elischer 2443f2bb1caeSJulian Elischer return (EMSGSIZE); 2444f2bb1caeSJulian Elischer } 2445f2bb1caeSJulian Elischer 2446f2bb1caeSJulian Elischer switch (type) { 2447f2bb1caeSJulian Elischer case RFCOMM_MCC_TEST: 2448f2bb1caeSJulian Elischer return (ng_btsocket_rfcomm_receive_test(s, m0)); 2449f2bb1caeSJulian Elischer /* NOT REACHED */ 2450f2bb1caeSJulian Elischer 2451f2bb1caeSJulian Elischer case RFCOMM_MCC_FCON: 2452f2bb1caeSJulian Elischer case RFCOMM_MCC_FCOFF: 2453f2bb1caeSJulian Elischer return (ng_btsocket_rfcomm_receive_fc(s, m0)); 2454f2bb1caeSJulian Elischer /* NOT REACHED */ 2455f2bb1caeSJulian Elischer 2456f2bb1caeSJulian Elischer case RFCOMM_MCC_MSC: 2457f2bb1caeSJulian Elischer return (ng_btsocket_rfcomm_receive_msc(s, m0)); 2458f2bb1caeSJulian Elischer /* NOT REACHED */ 2459f2bb1caeSJulian Elischer 2460f2bb1caeSJulian Elischer case RFCOMM_MCC_RPN: 2461f2bb1caeSJulian Elischer return (ng_btsocket_rfcomm_receive_rpn(s, m0)); 2462f2bb1caeSJulian Elischer /* NOT REACHED */ 2463f2bb1caeSJulian Elischer 2464f2bb1caeSJulian Elischer case RFCOMM_MCC_RLS: 2465f2bb1caeSJulian Elischer return (ng_btsocket_rfcomm_receive_rls(s, m0)); 2466f2bb1caeSJulian Elischer /* NOT REACHED */ 2467f2bb1caeSJulian Elischer 2468f2bb1caeSJulian Elischer case RFCOMM_MCC_PN: 2469f2bb1caeSJulian Elischer return (ng_btsocket_rfcomm_receive_pn(s, m0)); 2470f2bb1caeSJulian Elischer /* NOT REACHED */ 2471f2bb1caeSJulian Elischer 2472f2bb1caeSJulian Elischer case RFCOMM_MCC_NSC: 2473f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 2474f2bb1caeSJulian Elischer "%s: Got MCC NSC, type=%#x, cr=%d, length=%d, session state=%d, flags=%#x, " \ 2475f2bb1caeSJulian Elischer "mtu=%d, len=%d\n", __func__, RFCOMM_MCC_TYPE(*((u_int8_t *)(hdr + 1))), cr, 2476f2bb1caeSJulian Elischer length, s->state, s->flags, s->mtu, m0->m_pkthdr.len); 2477f2bb1caeSJulian Elischer NG_FREE_M(m0); 2478f2bb1caeSJulian Elischer break; 2479f2bb1caeSJulian Elischer 2480f2bb1caeSJulian Elischer default: 2481f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 2482f2bb1caeSJulian Elischer "%s: Got unknown MCC, type=%#x, cr=%d, length=%d, session state=%d, " \ 2483f2bb1caeSJulian Elischer "flags=%#x, mtu=%d, len=%d\n", 2484f2bb1caeSJulian Elischer __func__, type, cr, length, s->state, s->flags, 2485f2bb1caeSJulian Elischer s->mtu, m0->m_pkthdr.len); 2486f2bb1caeSJulian Elischer 2487f2bb1caeSJulian Elischer /* Reuse mbuf to send NSC */ 2488f2bb1caeSJulian Elischer hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2489f2bb1caeSJulian Elischer m0->m_pkthdr.len = m0->m_len = sizeof(*hdr); 2490f2bb1caeSJulian Elischer 2491f2bb1caeSJulian Elischer /* Create MCC NSC header */ 2492f2bb1caeSJulian Elischer hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_NSC); 2493f2bb1caeSJulian Elischer hdr->length = RFCOMM_MKLEN8(1); 2494f2bb1caeSJulian Elischer 2495f2bb1caeSJulian Elischer /* Put back MCC command type we did not like */ 2496f2bb1caeSJulian Elischer m0->m_data[m0->m_len] = RFCOMM_MKMCC_TYPE(cr, type); 2497f2bb1caeSJulian Elischer m0->m_pkthdr.len ++; 2498f2bb1caeSJulian Elischer m0->m_len ++; 2499f2bb1caeSJulian Elischer 2500f2bb1caeSJulian Elischer /* Send UIH frame */ 2501f2bb1caeSJulian Elischer return (ng_btsocket_rfcomm_send_uih(s, 2502f2bb1caeSJulian Elischer RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0)); 2503f2bb1caeSJulian Elischer /* NOT REACHED */ 2504f2bb1caeSJulian Elischer } 2505f2bb1caeSJulian Elischer 2506f2bb1caeSJulian Elischer return (0); 2507f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_receive_mcc */ 2508f2bb1caeSJulian Elischer 2509f2bb1caeSJulian Elischer /* 2510f2bb1caeSJulian Elischer * Receive RFCOMM TEST MCC command 2511f2bb1caeSJulian Elischer */ 2512f2bb1caeSJulian Elischer 2513f2bb1caeSJulian Elischer static int 2514f2bb1caeSJulian Elischer ng_btsocket_rfcomm_receive_test(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2515f2bb1caeSJulian Elischer { 2516f2bb1caeSJulian Elischer struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2517f2bb1caeSJulian Elischer int error = 0; 2518f2bb1caeSJulian Elischer 2519f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 2520f2bb1caeSJulian Elischer 2521f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 2522f2bb1caeSJulian Elischer "%s: Got MCC TEST, cr=%d, length=%d, session state=%d, flags=%#x, mtu=%d, " \ 2523f2bb1caeSJulian Elischer "len=%d\n", __func__, RFCOMM_CR(hdr->type), RFCOMM_MCC_LENGTH(hdr->length), 2524f2bb1caeSJulian Elischer s->state, s->flags, s->mtu, m0->m_pkthdr.len); 2525f2bb1caeSJulian Elischer 2526f2bb1caeSJulian Elischer if (RFCOMM_CR(hdr->type)) { 2527f2bb1caeSJulian Elischer hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_TEST); 2528f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_uih(s, 2529f2bb1caeSJulian Elischer RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0); 2530f2bb1caeSJulian Elischer } else 2531f2bb1caeSJulian Elischer NG_FREE_M(m0); /* XXX ignore response */ 2532f2bb1caeSJulian Elischer 2533f2bb1caeSJulian Elischer return (error); 2534f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_receive_test */ 2535f2bb1caeSJulian Elischer 2536f2bb1caeSJulian Elischer /* 2537f2bb1caeSJulian Elischer * Receive RFCOMM FCON/FCOFF MCC command 2538f2bb1caeSJulian Elischer */ 2539f2bb1caeSJulian Elischer 2540f2bb1caeSJulian Elischer static int 2541f2bb1caeSJulian Elischer ng_btsocket_rfcomm_receive_fc(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2542f2bb1caeSJulian Elischer { 2543f2bb1caeSJulian Elischer struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2544f2bb1caeSJulian Elischer u_int8_t type = RFCOMM_MCC_TYPE(hdr->type); 2545f2bb1caeSJulian Elischer int error = 0; 2546f2bb1caeSJulian Elischer 2547f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 2548f2bb1caeSJulian Elischer 2549f2bb1caeSJulian Elischer /* 2550f2bb1caeSJulian Elischer * Turn ON/OFF aggregate flow on the entire session. When remote peer 2551f2bb1caeSJulian Elischer * asserted flow control no transmission shall occur except on dlci 0 2552f2bb1caeSJulian Elischer * (control channel). 2553f2bb1caeSJulian Elischer */ 2554f2bb1caeSJulian Elischer 2555f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 2556f2bb1caeSJulian Elischer "%s: Got MCC FC%s, cr=%d, length=%d, session state=%d, flags=%#x, mtu=%d, " \ 2557f2bb1caeSJulian Elischer "len=%d\n", __func__, (type == RFCOMM_MCC_FCON)? "ON" : "OFF", 2558f2bb1caeSJulian Elischer RFCOMM_CR(hdr->type), RFCOMM_MCC_LENGTH(hdr->length), 2559f2bb1caeSJulian Elischer s->state, s->flags, s->mtu, m0->m_pkthdr.len); 2560f2bb1caeSJulian Elischer 2561f2bb1caeSJulian Elischer if (RFCOMM_CR(hdr->type)) { 2562f2bb1caeSJulian Elischer if (type == RFCOMM_MCC_FCON) 2563f2bb1caeSJulian Elischer s->flags &= ~NG_BTSOCKET_RFCOMM_SESSION_RFC; 2564f2bb1caeSJulian Elischer else 2565f2bb1caeSJulian Elischer s->flags |= NG_BTSOCKET_RFCOMM_SESSION_RFC; 2566f2bb1caeSJulian Elischer 2567f2bb1caeSJulian Elischer hdr->type = RFCOMM_MKMCC_TYPE(0, type); 2568f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_uih(s, 2569f2bb1caeSJulian Elischer RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0); 2570f2bb1caeSJulian Elischer } else 2571f2bb1caeSJulian Elischer NG_FREE_M(m0); /* XXX ignore response */ 2572f2bb1caeSJulian Elischer 2573f2bb1caeSJulian Elischer return (error); 2574f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_receive_fc */ 2575f2bb1caeSJulian Elischer 2576f2bb1caeSJulian Elischer /* 2577f2bb1caeSJulian Elischer * Receive RFCOMM MSC MCC command 2578f2bb1caeSJulian Elischer */ 2579f2bb1caeSJulian Elischer 2580f2bb1caeSJulian Elischer static int 2581f2bb1caeSJulian Elischer ng_btsocket_rfcomm_receive_msc(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2582f2bb1caeSJulian Elischer { 2583f2bb1caeSJulian Elischer struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr*); 2584f2bb1caeSJulian Elischer struct rfcomm_mcc_msc *msc = (struct rfcomm_mcc_msc *)(hdr+1); 2585f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_t *pcb = NULL; 2586f2bb1caeSJulian Elischer int error = 0; 2587f2bb1caeSJulian Elischer 2588f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 2589f2bb1caeSJulian Elischer 2590f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 2591f2bb1caeSJulian Elischer "%s: Got MCC MSC, dlci=%d, cr=%d, length=%d, session state=%d, flags=%#x, " \ 2592f2bb1caeSJulian Elischer "mtu=%d, len=%d\n", 2593f2bb1caeSJulian Elischer __func__, RFCOMM_DLCI(msc->address), RFCOMM_CR(hdr->type), 2594f2bb1caeSJulian Elischer RFCOMM_MCC_LENGTH(hdr->length), s->state, s->flags, 2595f2bb1caeSJulian Elischer s->mtu, m0->m_pkthdr.len); 2596f2bb1caeSJulian Elischer 2597f2bb1caeSJulian Elischer if (RFCOMM_CR(hdr->type)) { 2598f2bb1caeSJulian Elischer pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, RFCOMM_DLCI(msc->address)); 2599f2bb1caeSJulian Elischer if (pcb == NULL) { 2600f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_WARN( 2601f2bb1caeSJulian Elischer "%s: Got MSC command for non-existing dlci=%d\n", 2602f2bb1caeSJulian Elischer __func__, RFCOMM_DLCI(msc->address)); 2603f2bb1caeSJulian Elischer NG_FREE_M(m0); 2604f2bb1caeSJulian Elischer 2605f2bb1caeSJulian Elischer return (ENOENT); 2606f2bb1caeSJulian Elischer } 2607f2bb1caeSJulian Elischer 2608f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 2609f2bb1caeSJulian Elischer 2610f2bb1caeSJulian Elischer if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTING && 2611f2bb1caeSJulian Elischer pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTED) { 2612f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_WARN( 2613f2bb1caeSJulian Elischer "%s: Got MSC on dlci=%d in invalid state=%d\n", 2614f2bb1caeSJulian Elischer __func__, RFCOMM_DLCI(msc->address), 2615f2bb1caeSJulian Elischer pcb->state); 2616f2bb1caeSJulian Elischer 2617f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 2618f2bb1caeSJulian Elischer NG_FREE_M(m0); 2619f2bb1caeSJulian Elischer 2620f2bb1caeSJulian Elischer return (EINVAL); 2621f2bb1caeSJulian Elischer } 2622f2bb1caeSJulian Elischer 2623f2bb1caeSJulian Elischer pcb->rmodem = msc->modem; /* Update remote port signals */ 2624f2bb1caeSJulian Elischer 2625f2bb1caeSJulian Elischer hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_MSC); 2626f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_uih(s, 2627f2bb1caeSJulian Elischer RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0); 2628f2bb1caeSJulian Elischer 2629f2bb1caeSJulian Elischer #if 0 /* YYY */ 2630f2bb1caeSJulian Elischer /* Send more data from DLC. XXX check for errors? */ 2631f2bb1caeSJulian Elischer if (!(pcb->rmodem & RFCOMM_MODEM_FC) && 2632f2bb1caeSJulian Elischer !(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC)) 2633f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_send(pcb, ALOT); 2634f2bb1caeSJulian Elischer #endif /* YYY */ 2635f2bb1caeSJulian Elischer 2636f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 2637f2bb1caeSJulian Elischer } else 2638f2bb1caeSJulian Elischer NG_FREE_M(m0); /* XXX ignore response */ 2639f2bb1caeSJulian Elischer 2640f2bb1caeSJulian Elischer return (error); 2641f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_receive_msc */ 2642f2bb1caeSJulian Elischer 2643f2bb1caeSJulian Elischer /* 2644f2bb1caeSJulian Elischer * Receive RFCOMM RPN MCC command 2645f2bb1caeSJulian Elischer * XXX FIXME do we need htole16/le16toh for RPN param_mask? 2646f2bb1caeSJulian Elischer */ 2647f2bb1caeSJulian Elischer 2648f2bb1caeSJulian Elischer static int 2649f2bb1caeSJulian Elischer ng_btsocket_rfcomm_receive_rpn(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2650f2bb1caeSJulian Elischer { 2651f2bb1caeSJulian Elischer struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2652f2bb1caeSJulian Elischer struct rfcomm_mcc_rpn *rpn = (struct rfcomm_mcc_rpn *)(hdr + 1); 2653f2bb1caeSJulian Elischer int error = 0; 2654f2bb1caeSJulian Elischer u_int16_t param_mask; 2655f2bb1caeSJulian Elischer u_int8_t bit_rate, data_bits, stop_bits, parity, 2656f2bb1caeSJulian Elischer flow_control, xon_char, xoff_char; 2657f2bb1caeSJulian Elischer 2658f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 2659f2bb1caeSJulian Elischer 2660f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 2661f2bb1caeSJulian Elischer "%s: Got MCC RPN, dlci=%d, cr=%d, length=%d, session state=%d, flags=%#x, " \ 2662f2bb1caeSJulian Elischer "mtu=%d, len=%d\n", 2663f2bb1caeSJulian Elischer __func__, RFCOMM_DLCI(rpn->dlci), RFCOMM_CR(hdr->type), 2664f2bb1caeSJulian Elischer RFCOMM_MCC_LENGTH(hdr->length), s->state, s->flags, 2665f2bb1caeSJulian Elischer s->mtu, m0->m_pkthdr.len); 2666f2bb1caeSJulian Elischer 2667f2bb1caeSJulian Elischer if (RFCOMM_CR(hdr->type)) { 2668f2bb1caeSJulian Elischer param_mask = RFCOMM_RPN_PM_ALL; 2669f2bb1caeSJulian Elischer 2670f2bb1caeSJulian Elischer if (RFCOMM_MCC_LENGTH(hdr->length) == 1) { 2671f2bb1caeSJulian Elischer /* Request - return default setting */ 2672f2bb1caeSJulian Elischer bit_rate = RFCOMM_RPN_BR_115200; 2673f2bb1caeSJulian Elischer data_bits = RFCOMM_RPN_DATA_8; 2674f2bb1caeSJulian Elischer stop_bits = RFCOMM_RPN_STOP_1; 2675f2bb1caeSJulian Elischer parity = RFCOMM_RPN_PARITY_NONE; 2676f2bb1caeSJulian Elischer flow_control = RFCOMM_RPN_FLOW_NONE; 2677f2bb1caeSJulian Elischer xon_char = RFCOMM_RPN_XON_CHAR; 2678f2bb1caeSJulian Elischer xoff_char = RFCOMM_RPN_XOFF_CHAR; 2679f2bb1caeSJulian Elischer } else { 2680f2bb1caeSJulian Elischer /* 2681f2bb1caeSJulian Elischer * Ignore/accept bit_rate, 8 bits, 1 stop bit, no 2682f2bb1caeSJulian Elischer * parity, no flow control lines, default XON/XOFF 2683f2bb1caeSJulian Elischer * chars. 2684f2bb1caeSJulian Elischer */ 2685f2bb1caeSJulian Elischer 2686f2bb1caeSJulian Elischer bit_rate = rpn->bit_rate; 2687f2bb1caeSJulian Elischer rpn->param_mask = le16toh(rpn->param_mask); /* XXX */ 2688f2bb1caeSJulian Elischer 2689f2bb1caeSJulian Elischer data_bits = RFCOMM_RPN_DATA_BITS(rpn->line_settings); 2690f2bb1caeSJulian Elischer if (rpn->param_mask & RFCOMM_RPN_PM_DATA && 2691f2bb1caeSJulian Elischer data_bits != RFCOMM_RPN_DATA_8) { 2692f2bb1caeSJulian Elischer data_bits = RFCOMM_RPN_DATA_8; 2693f2bb1caeSJulian Elischer param_mask ^= RFCOMM_RPN_PM_DATA; 2694f2bb1caeSJulian Elischer } 2695f2bb1caeSJulian Elischer 2696f2bb1caeSJulian Elischer stop_bits = RFCOMM_RPN_STOP_BITS(rpn->line_settings); 2697f2bb1caeSJulian Elischer if (rpn->param_mask & RFCOMM_RPN_PM_STOP && 2698f2bb1caeSJulian Elischer stop_bits != RFCOMM_RPN_STOP_1) { 2699f2bb1caeSJulian Elischer stop_bits = RFCOMM_RPN_STOP_1; 2700f2bb1caeSJulian Elischer param_mask ^= RFCOMM_RPN_PM_STOP; 2701f2bb1caeSJulian Elischer } 2702f2bb1caeSJulian Elischer 2703f2bb1caeSJulian Elischer parity = RFCOMM_RPN_PARITY(rpn->line_settings); 2704f2bb1caeSJulian Elischer if (rpn->param_mask & RFCOMM_RPN_PM_PARITY && 2705f2bb1caeSJulian Elischer parity != RFCOMM_RPN_PARITY_NONE) { 2706f2bb1caeSJulian Elischer parity = RFCOMM_RPN_PARITY_NONE; 2707f2bb1caeSJulian Elischer param_mask ^= RFCOMM_RPN_PM_PARITY; 2708f2bb1caeSJulian Elischer } 2709f2bb1caeSJulian Elischer 2710f2bb1caeSJulian Elischer flow_control = rpn->flow_control; 2711f2bb1caeSJulian Elischer if (rpn->param_mask & RFCOMM_RPN_PM_FLOW && 2712f2bb1caeSJulian Elischer flow_control != RFCOMM_RPN_FLOW_NONE) { 2713f2bb1caeSJulian Elischer flow_control = RFCOMM_RPN_FLOW_NONE; 2714f2bb1caeSJulian Elischer param_mask ^= RFCOMM_RPN_PM_FLOW; 2715f2bb1caeSJulian Elischer } 2716f2bb1caeSJulian Elischer 2717f2bb1caeSJulian Elischer xon_char = rpn->xon_char; 2718f2bb1caeSJulian Elischer if (rpn->param_mask & RFCOMM_RPN_PM_XON && 2719f2bb1caeSJulian Elischer xon_char != RFCOMM_RPN_XON_CHAR) { 2720f2bb1caeSJulian Elischer xon_char = RFCOMM_RPN_XON_CHAR; 2721f2bb1caeSJulian Elischer param_mask ^= RFCOMM_RPN_PM_XON; 2722f2bb1caeSJulian Elischer } 2723f2bb1caeSJulian Elischer 2724f2bb1caeSJulian Elischer xoff_char = rpn->xoff_char; 2725f2bb1caeSJulian Elischer if (rpn->param_mask & RFCOMM_RPN_PM_XOFF && 2726f2bb1caeSJulian Elischer xoff_char != RFCOMM_RPN_XOFF_CHAR) { 2727f2bb1caeSJulian Elischer xoff_char = RFCOMM_RPN_XOFF_CHAR; 2728f2bb1caeSJulian Elischer param_mask ^= RFCOMM_RPN_PM_XOFF; 2729f2bb1caeSJulian Elischer } 2730f2bb1caeSJulian Elischer } 2731f2bb1caeSJulian Elischer 2732f2bb1caeSJulian Elischer rpn->bit_rate = bit_rate; 2733f2bb1caeSJulian Elischer rpn->line_settings = RFCOMM_MKRPN_LINE_SETTINGS(data_bits, 2734f2bb1caeSJulian Elischer stop_bits, parity); 2735f2bb1caeSJulian Elischer rpn->flow_control = flow_control; 2736f2bb1caeSJulian Elischer rpn->xon_char = xon_char; 2737f2bb1caeSJulian Elischer rpn->xoff_char = xoff_char; 2738f2bb1caeSJulian Elischer rpn->param_mask = htole16(param_mask); /* XXX */ 2739f2bb1caeSJulian Elischer 2740f2bb1caeSJulian Elischer m0->m_pkthdr.len = m0->m_len = sizeof(*hdr) + sizeof(*rpn); 2741f2bb1caeSJulian Elischer 2742f2bb1caeSJulian Elischer hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_RPN); 2743f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_uih(s, 2744f2bb1caeSJulian Elischer RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0); 2745f2bb1caeSJulian Elischer } else 2746f2bb1caeSJulian Elischer NG_FREE_M(m0); /* XXX ignore response */ 2747f2bb1caeSJulian Elischer 2748f2bb1caeSJulian Elischer return (error); 2749f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_receive_rpn */ 2750f2bb1caeSJulian Elischer 2751f2bb1caeSJulian Elischer /* 2752f2bb1caeSJulian Elischer * Receive RFCOMM RLS MCC command 2753f2bb1caeSJulian Elischer */ 2754f2bb1caeSJulian Elischer 2755f2bb1caeSJulian Elischer static int 2756f2bb1caeSJulian Elischer ng_btsocket_rfcomm_receive_rls(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2757f2bb1caeSJulian Elischer { 2758f2bb1caeSJulian Elischer struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr *); 2759f2bb1caeSJulian Elischer struct rfcomm_mcc_rls *rls = (struct rfcomm_mcc_rls *)(hdr + 1); 2760f2bb1caeSJulian Elischer int error = 0; 2761f2bb1caeSJulian Elischer 2762f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 2763f2bb1caeSJulian Elischer 2764f2bb1caeSJulian Elischer /* 2765f2bb1caeSJulian Elischer * XXX FIXME Do we have to do anything else here? Remote peer tries to 2766f2bb1caeSJulian Elischer * tell us something about DLCI. Just report what we have received and 2767f2bb1caeSJulian Elischer * return back received values as required by TS 07.10 spec. 2768f2bb1caeSJulian Elischer */ 2769f2bb1caeSJulian Elischer 2770f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 2771f2bb1caeSJulian Elischer "%s: Got MCC RLS, dlci=%d, status=%#x, cr=%d, length=%d, session state=%d, " \ 2772f2bb1caeSJulian Elischer "flags=%#x, mtu=%d, len=%d\n", 2773f2bb1caeSJulian Elischer __func__, RFCOMM_DLCI(rls->address), rls->status, 2774f2bb1caeSJulian Elischer RFCOMM_CR(hdr->type), RFCOMM_MCC_LENGTH(hdr->length), 2775f2bb1caeSJulian Elischer s->state, s->flags, s->mtu, m0->m_pkthdr.len); 2776f2bb1caeSJulian Elischer 2777f2bb1caeSJulian Elischer if (RFCOMM_CR(hdr->type)) { 2778f2bb1caeSJulian Elischer if (rls->status & 0x1) 2779f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 2780f2bb1caeSJulian Elischer "%s: Got RLS dlci=%d, error=%#x\n", __func__, RFCOMM_DLCI(rls->address), 2781f2bb1caeSJulian Elischer rls->status >> 1); 2782f2bb1caeSJulian Elischer 2783f2bb1caeSJulian Elischer hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_RLS); 2784f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_uih(s, 2785f2bb1caeSJulian Elischer RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0); 2786f2bb1caeSJulian Elischer } else 2787f2bb1caeSJulian Elischer NG_FREE_M(m0); /* XXX ignore responses */ 2788f2bb1caeSJulian Elischer 2789f2bb1caeSJulian Elischer return (error); 2790f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_receive_rls */ 2791f2bb1caeSJulian Elischer 2792f2bb1caeSJulian Elischer /* 2793f2bb1caeSJulian Elischer * Receive RFCOMM PN MCC command 2794f2bb1caeSJulian Elischer */ 2795f2bb1caeSJulian Elischer 2796f2bb1caeSJulian Elischer static int 2797f2bb1caeSJulian Elischer ng_btsocket_rfcomm_receive_pn(ng_btsocket_rfcomm_session_p s, struct mbuf *m0) 2798f2bb1caeSJulian Elischer { 2799f2bb1caeSJulian Elischer struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr*); 2800f2bb1caeSJulian Elischer struct rfcomm_mcc_pn *pn = (struct rfcomm_mcc_pn *)(hdr+1); 2801f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_t *pcb = NULL; 2802f2bb1caeSJulian Elischer int error = 0; 2803f2bb1caeSJulian Elischer 2804f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 2805f2bb1caeSJulian Elischer 2806f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 2807f2bb1caeSJulian Elischer "%s: Got MCC PN, dlci=%d, cr=%d, length=%d, flow_control=%#x, priority=%d, " \ 2808f2bb1caeSJulian Elischer "ack_timer=%d, mtu=%d, max_retrans=%d, credits=%d, session state=%d, " \ 2809f2bb1caeSJulian Elischer "flags=%#x, session mtu=%d, len=%d\n", 2810f2bb1caeSJulian Elischer __func__, pn->dlci, RFCOMM_CR(hdr->type), 2811f2bb1caeSJulian Elischer RFCOMM_MCC_LENGTH(hdr->length), pn->flow_control, pn->priority, 2812f2bb1caeSJulian Elischer pn->ack_timer, le16toh(pn->mtu), pn->max_retrans, pn->credits, 2813f2bb1caeSJulian Elischer s->state, s->flags, s->mtu, m0->m_pkthdr.len); 2814f2bb1caeSJulian Elischer 2815f2bb1caeSJulian Elischer if (pn->dlci == 0) { 2816f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR("%s: Zero dlci in MCC PN\n", __func__); 2817f2bb1caeSJulian Elischer NG_FREE_M(m0); 2818f2bb1caeSJulian Elischer 2819f2bb1caeSJulian Elischer return (EINVAL); 2820f2bb1caeSJulian Elischer } 2821f2bb1caeSJulian Elischer 2822f2bb1caeSJulian Elischer /* Check if we have this dlci */ 2823f2bb1caeSJulian Elischer pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, pn->dlci); 2824f2bb1caeSJulian Elischer if (pcb != NULL) { 2825f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 2826f2bb1caeSJulian Elischer 2827f2bb1caeSJulian Elischer if (RFCOMM_CR(hdr->type)) { 2828f2bb1caeSJulian Elischer /* PN Request */ 2829f2bb1caeSJulian Elischer ng_btsocket_rfcomm_set_pn(pcb, 1, pn->flow_control, 2830f2bb1caeSJulian Elischer pn->credits, pn->mtu); 2831f2bb1caeSJulian Elischer 2832f2bb1caeSJulian Elischer if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) { 2833f2bb1caeSJulian Elischer pn->flow_control = 0xe0; 2834f2bb1caeSJulian Elischer pn->credits = RFCOMM_DEFAULT_CREDITS; 2835f2bb1caeSJulian Elischer } else { 2836f2bb1caeSJulian Elischer pn->flow_control = 0; 2837f2bb1caeSJulian Elischer pn->credits = 0; 2838f2bb1caeSJulian Elischer } 2839f2bb1caeSJulian Elischer 2840f2bb1caeSJulian Elischer hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_PN); 2841f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_uih(s, 2842f2bb1caeSJulian Elischer RFCOMM_MKADDRESS(INITIATOR(s), 0), 2843f2bb1caeSJulian Elischer 0, 0, m0); 2844f2bb1caeSJulian Elischer } else { 2845f2bb1caeSJulian Elischer /* PN Response - proceed with SABM. Timeout still set */ 2846f2bb1caeSJulian Elischer if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONFIGURING) { 2847f2bb1caeSJulian Elischer ng_btsocket_rfcomm_set_pn(pcb, 0, 2848f2bb1caeSJulian Elischer pn->flow_control, pn->credits, pn->mtu); 2849f2bb1caeSJulian Elischer 2850f2bb1caeSJulian Elischer pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTING; 2851f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_command(s, 2852f2bb1caeSJulian Elischer RFCOMM_FRAME_SABM, pn->dlci); 2853f2bb1caeSJulian Elischer } else 2854f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_WARN( 2855f2bb1caeSJulian Elischer "%s: Got PN response for dlci=%d in invalid state=%d\n", 2856f2bb1caeSJulian Elischer __func__, pn->dlci, pcb->state); 2857f2bb1caeSJulian Elischer 2858f2bb1caeSJulian Elischer NG_FREE_M(m0); 2859f2bb1caeSJulian Elischer } 2860f2bb1caeSJulian Elischer 2861f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 2862f2bb1caeSJulian Elischer } else if (RFCOMM_CR(hdr->type)) { 2863053359b7SPedro F. Giffuni /* PN request to non-existing dlci - incoming connection */ 2864f2bb1caeSJulian Elischer pcb = ng_btsocket_rfcomm_connect_ind(s, 2865f2bb1caeSJulian Elischer RFCOMM_SRVCHANNEL(pn->dlci)); 2866f2bb1caeSJulian Elischer if (pcb != NULL) { 2867f2bb1caeSJulian Elischer mtx_lock(&pcb->pcb_mtx); 2868f2bb1caeSJulian Elischer 2869f2bb1caeSJulian Elischer pcb->dlci = pn->dlci; 2870f2bb1caeSJulian Elischer 2871f2bb1caeSJulian Elischer ng_btsocket_rfcomm_set_pn(pcb, 1, pn->flow_control, 2872f2bb1caeSJulian Elischer pn->credits, pn->mtu); 2873f2bb1caeSJulian Elischer 2874f2bb1caeSJulian Elischer if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) { 2875f2bb1caeSJulian Elischer pn->flow_control = 0xe0; 2876f2bb1caeSJulian Elischer pn->credits = RFCOMM_DEFAULT_CREDITS; 2877f2bb1caeSJulian Elischer } else { 2878f2bb1caeSJulian Elischer pn->flow_control = 0; 2879f2bb1caeSJulian Elischer pn->credits = 0; 2880f2bb1caeSJulian Elischer } 2881f2bb1caeSJulian Elischer 2882f2bb1caeSJulian Elischer hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_PN); 2883f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_uih(s, 2884f2bb1caeSJulian Elischer RFCOMM_MKADDRESS(INITIATOR(s), 0), 2885f2bb1caeSJulian Elischer 0, 0, m0); 2886f2bb1caeSJulian Elischer 2887f2bb1caeSJulian Elischer if (error == 0) { 2888f2bb1caeSJulian Elischer ng_btsocket_rfcomm_timeout(pcb); 2889f2bb1caeSJulian Elischer pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTING; 2890f2bb1caeSJulian Elischer soisconnecting(pcb->so); 28917c380856SMaksim Yevmenkin } else 28927c380856SMaksim Yevmenkin ng_btsocket_rfcomm_pcb_kill(pcb, error); 2893f2bb1caeSJulian Elischer 2894f2bb1caeSJulian Elischer mtx_unlock(&pcb->pcb_mtx); 2895f2bb1caeSJulian Elischer } else { 2896f2bb1caeSJulian Elischer /* Nobody is listen()ing on this channel */ 2897f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_command(s, 2898f2bb1caeSJulian Elischer RFCOMM_FRAME_DM, pn->dlci); 2899f2bb1caeSJulian Elischer NG_FREE_M(m0); 2900f2bb1caeSJulian Elischer } 2901f2bb1caeSJulian Elischer } else 2902f2bb1caeSJulian Elischer NG_FREE_M(m0); /* XXX ignore response to non-existing dlci */ 2903f2bb1caeSJulian Elischer 2904f2bb1caeSJulian Elischer return (error); 2905f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_receive_pn */ 2906f2bb1caeSJulian Elischer 2907f2bb1caeSJulian Elischer /* 2908f2bb1caeSJulian Elischer * Set PN parameters for dlci. Caller must hold pcb->pcb_mtx. 2909f2bb1caeSJulian Elischer * 2910f2bb1caeSJulian Elischer * From Bluetooth spec. 2911f2bb1caeSJulian Elischer * 2912f2bb1caeSJulian Elischer * "... The CL1 - CL4 field is completely redefined. (In TS07.10 this defines 2913f2bb1caeSJulian Elischer * the convergence layer to use, which is not applicable to RFCOMM. In RFCOMM, 2914f2bb1caeSJulian Elischer * in Bluetooth versions up to 1.0B, this field was forced to 0). 2915f2bb1caeSJulian Elischer * 2916f2bb1caeSJulian Elischer * In the PN request sent prior to a DLC establishment, this field must contain 2917f2bb1caeSJulian Elischer * the value 15 (0xF), indicating support of credit based flow control in the 2918f2bb1caeSJulian Elischer * sender. See Table 5.3 below. If the PN response contains any other value 2919f2bb1caeSJulian Elischer * than 14 (0xE) in this field, it is inferred that the peer RFCOMM entity is 2920f2bb1caeSJulian Elischer * not supporting the credit based flow control feature. (This is only possible 2921f2bb1caeSJulian Elischer * if the peer RFCOMM implementation is only conforming to Bluetooth version 2922f2bb1caeSJulian Elischer * 1.0B.) If a PN request is sent on an already open DLC, then this field must 2923f2bb1caeSJulian Elischer * contain the value zero; it is not possible to set initial credits more 2924f2bb1caeSJulian Elischer * than once per DLC activation. A responding implementation must set this 2925f2bb1caeSJulian Elischer * field in the PN response to 14 (0xE), if (and only if) the value in the PN 2926f2bb1caeSJulian Elischer * request was 15..." 2927f2bb1caeSJulian Elischer */ 2928f2bb1caeSJulian Elischer 2929f2bb1caeSJulian Elischer static void 2930f2bb1caeSJulian Elischer ng_btsocket_rfcomm_set_pn(ng_btsocket_rfcomm_pcb_p pcb, u_int8_t cr, 2931f2bb1caeSJulian Elischer u_int8_t flow_control, u_int8_t credits, u_int16_t mtu) 2932f2bb1caeSJulian Elischer { 2933f2bb1caeSJulian Elischer mtx_assert(&pcb->pcb_mtx, MA_OWNED); 2934f2bb1caeSJulian Elischer 2935f2bb1caeSJulian Elischer pcb->mtu = le16toh(mtu); 2936f2bb1caeSJulian Elischer 2937f2bb1caeSJulian Elischer if (cr) { 2938f2bb1caeSJulian Elischer if (flow_control == 0xf0) { 2939f2bb1caeSJulian Elischer pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_CFC; 2940f2bb1caeSJulian Elischer pcb->tx_cred = credits; 2941f2bb1caeSJulian Elischer } else { 2942f2bb1caeSJulian Elischer pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_CFC; 2943f2bb1caeSJulian Elischer pcb->tx_cred = 0; 2944f2bb1caeSJulian Elischer } 2945f2bb1caeSJulian Elischer } else { 2946f2bb1caeSJulian Elischer if (flow_control == 0xe0) { 2947f2bb1caeSJulian Elischer pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_CFC; 2948f2bb1caeSJulian Elischer pcb->tx_cred = credits; 2949f2bb1caeSJulian Elischer } else { 2950f2bb1caeSJulian Elischer pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_CFC; 2951f2bb1caeSJulian Elischer pcb->tx_cred = 0; 2952f2bb1caeSJulian Elischer } 2953f2bb1caeSJulian Elischer } 2954f2bb1caeSJulian Elischer 2955f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 2956f2bb1caeSJulian Elischer "%s: cr=%d, dlci=%d, state=%d, flags=%#x, mtu=%d, rx_cred=%d, tx_cred=%d\n", 2957f2bb1caeSJulian Elischer __func__, cr, pcb->dlci, pcb->state, pcb->flags, pcb->mtu, 2958f2bb1caeSJulian Elischer pcb->rx_cred, pcb->tx_cred); 2959f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_set_pn */ 2960f2bb1caeSJulian Elischer 2961f2bb1caeSJulian Elischer /* 2962f2bb1caeSJulian Elischer * Send RFCOMM SABM/DISC/UA/DM frames. Caller must hold s->session_mtx 2963f2bb1caeSJulian Elischer */ 2964f2bb1caeSJulian Elischer 2965f2bb1caeSJulian Elischer static int 2966f2bb1caeSJulian Elischer ng_btsocket_rfcomm_send_command(ng_btsocket_rfcomm_session_p s, 2967f2bb1caeSJulian Elischer u_int8_t type, u_int8_t dlci) 2968f2bb1caeSJulian Elischer { 2969f2bb1caeSJulian Elischer struct rfcomm_cmd_hdr *hdr = NULL; 2970f2bb1caeSJulian Elischer struct mbuf *m = NULL; 2971f2bb1caeSJulian Elischer int cr; 2972f2bb1caeSJulian Elischer 2973f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 2974f2bb1caeSJulian Elischer 2975f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 2976f2bb1caeSJulian Elischer "%s: Sending command type %#x, session state=%d, flags=%#x, mtu=%d, dlci=%d\n", 2977f2bb1caeSJulian Elischer __func__, type, s->state, s->flags, s->mtu, dlci); 2978f2bb1caeSJulian Elischer 2979f2bb1caeSJulian Elischer switch (type) { 2980f2bb1caeSJulian Elischer case RFCOMM_FRAME_SABM: 2981f2bb1caeSJulian Elischer case RFCOMM_FRAME_DISC: 2982f2bb1caeSJulian Elischer cr = INITIATOR(s); 2983f2bb1caeSJulian Elischer break; 2984f2bb1caeSJulian Elischer 2985f2bb1caeSJulian Elischer case RFCOMM_FRAME_UA: 2986f2bb1caeSJulian Elischer case RFCOMM_FRAME_DM: 2987f2bb1caeSJulian Elischer cr = !INITIATOR(s); 2988f2bb1caeSJulian Elischer break; 2989f2bb1caeSJulian Elischer 2990f2bb1caeSJulian Elischer default: 2991f2bb1caeSJulian Elischer panic("%s: Invalid frame type=%#x\n", __func__, type); 2992f2bb1caeSJulian Elischer return (EINVAL); 2993f2bb1caeSJulian Elischer /* NOT REACHED */ 2994f2bb1caeSJulian Elischer } 2995f2bb1caeSJulian Elischer 2996eb1b1807SGleb Smirnoff MGETHDR(m, M_NOWAIT, MT_DATA); 2997f2bb1caeSJulian Elischer if (m == NULL) 2998f2bb1caeSJulian Elischer return (ENOBUFS); 2999f2bb1caeSJulian Elischer 3000f2bb1caeSJulian Elischer m->m_pkthdr.len = m->m_len = sizeof(*hdr); 3001f2bb1caeSJulian Elischer 3002f2bb1caeSJulian Elischer hdr = mtod(m, struct rfcomm_cmd_hdr *); 3003f2bb1caeSJulian Elischer hdr->address = RFCOMM_MKADDRESS(cr, dlci); 3004f2bb1caeSJulian Elischer hdr->control = RFCOMM_MKCONTROL(type, 1); 3005f2bb1caeSJulian Elischer hdr->length = RFCOMM_MKLEN8(0); 3006f2bb1caeSJulian Elischer hdr->fcs = ng_btsocket_rfcomm_fcs3((u_int8_t *) hdr); 3007f2bb1caeSJulian Elischer 3008f2bb1caeSJulian Elischer NG_BT_MBUFQ_ENQUEUE(&s->outq, m); 3009f2bb1caeSJulian Elischer 3010f2bb1caeSJulian Elischer return (0); 3011f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_send_command */ 3012f2bb1caeSJulian Elischer 3013f2bb1caeSJulian Elischer /* 3014f2bb1caeSJulian Elischer * Send RFCOMM UIH frame. Caller must hold s->session_mtx 3015f2bb1caeSJulian Elischer */ 3016f2bb1caeSJulian Elischer 3017f2bb1caeSJulian Elischer static int 3018f2bb1caeSJulian Elischer ng_btsocket_rfcomm_send_uih(ng_btsocket_rfcomm_session_p s, u_int8_t address, 3019f2bb1caeSJulian Elischer u_int8_t pf, u_int8_t credits, struct mbuf *data) 3020f2bb1caeSJulian Elischer { 3021f2bb1caeSJulian Elischer struct rfcomm_frame_hdr *hdr = NULL; 3022f2bb1caeSJulian Elischer struct mbuf *m = NULL, *mcrc = NULL; 3023f2bb1caeSJulian Elischer u_int16_t length; 3024f2bb1caeSJulian Elischer 3025f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 3026f2bb1caeSJulian Elischer 3027eb1b1807SGleb Smirnoff MGETHDR(m, M_NOWAIT, MT_DATA); 3028f2bb1caeSJulian Elischer if (m == NULL) { 3029f2bb1caeSJulian Elischer NG_FREE_M(data); 3030f2bb1caeSJulian Elischer return (ENOBUFS); 3031f2bb1caeSJulian Elischer } 3032f2bb1caeSJulian Elischer m->m_pkthdr.len = m->m_len = sizeof(*hdr); 3033f2bb1caeSJulian Elischer 3034eb1b1807SGleb Smirnoff MGET(mcrc, M_NOWAIT, MT_DATA); 3035f2bb1caeSJulian Elischer if (mcrc == NULL) { 3036f2bb1caeSJulian Elischer NG_FREE_M(data); 3037f2bb1caeSJulian Elischer return (ENOBUFS); 3038f2bb1caeSJulian Elischer } 3039f2bb1caeSJulian Elischer mcrc->m_len = 1; 3040f2bb1caeSJulian Elischer 3041f2bb1caeSJulian Elischer /* Fill UIH frame header */ 3042f2bb1caeSJulian Elischer hdr = mtod(m, struct rfcomm_frame_hdr *); 3043f2bb1caeSJulian Elischer hdr->address = address; 3044f2bb1caeSJulian Elischer hdr->control = RFCOMM_MKCONTROL(RFCOMM_FRAME_UIH, pf); 3045f2bb1caeSJulian Elischer 3046f2bb1caeSJulian Elischer /* Calculate FCS */ 3047f2bb1caeSJulian Elischer mcrc->m_data[0] = ng_btsocket_rfcomm_fcs2((u_int8_t *) hdr); 3048f2bb1caeSJulian Elischer 3049f2bb1caeSJulian Elischer /* Put length back */ 3050f2bb1caeSJulian Elischer length = (data != NULL)? data->m_pkthdr.len : 0; 3051f2bb1caeSJulian Elischer if (length > 127) { 3052f2bb1caeSJulian Elischer u_int16_t l = htole16(RFCOMM_MKLEN16(length)); 3053f2bb1caeSJulian Elischer 3054f2bb1caeSJulian Elischer bcopy(&l, &hdr->length, sizeof(l)); 3055f2bb1caeSJulian Elischer m->m_pkthdr.len ++; 3056f2bb1caeSJulian Elischer m->m_len ++; 3057f2bb1caeSJulian Elischer } else 3058f2bb1caeSJulian Elischer hdr->length = RFCOMM_MKLEN8(length); 3059f2bb1caeSJulian Elischer 3060f2bb1caeSJulian Elischer if (pf) { 3061f2bb1caeSJulian Elischer m->m_data[m->m_len] = credits; 3062f2bb1caeSJulian Elischer m->m_pkthdr.len ++; 3063f2bb1caeSJulian Elischer m->m_len ++; 3064f2bb1caeSJulian Elischer } 3065f2bb1caeSJulian Elischer 3066f2bb1caeSJulian Elischer /* Add payload */ 3067f2bb1caeSJulian Elischer if (data != NULL) { 3068f2bb1caeSJulian Elischer m_cat(m, data); 3069f2bb1caeSJulian Elischer m->m_pkthdr.len += length; 3070f2bb1caeSJulian Elischer } 3071f2bb1caeSJulian Elischer 3072f2bb1caeSJulian Elischer /* Put FCS back */ 3073f2bb1caeSJulian Elischer m_cat(m, mcrc); 3074f2bb1caeSJulian Elischer m->m_pkthdr.len ++; 3075f2bb1caeSJulian Elischer 3076f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 3077f2bb1caeSJulian Elischer "%s: Sending UIH state=%d, flags=%#x, address=%d, length=%d, pf=%d, " \ 3078f2bb1caeSJulian Elischer "credits=%d, len=%d\n", 3079f2bb1caeSJulian Elischer __func__, s->state, s->flags, address, length, pf, credits, 3080f2bb1caeSJulian Elischer m->m_pkthdr.len); 3081f2bb1caeSJulian Elischer 3082f2bb1caeSJulian Elischer NG_BT_MBUFQ_ENQUEUE(&s->outq, m); 3083f2bb1caeSJulian Elischer 3084f2bb1caeSJulian Elischer return (0); 3085f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_send_uih */ 3086f2bb1caeSJulian Elischer 3087f2bb1caeSJulian Elischer /* 3088f2bb1caeSJulian Elischer * Send MSC request. Caller must hold pcb->pcb_mtx and pcb->session->session_mtx 3089f2bb1caeSJulian Elischer */ 3090f2bb1caeSJulian Elischer 3091f2bb1caeSJulian Elischer static int 3092f2bb1caeSJulian Elischer ng_btsocket_rfcomm_send_msc(ng_btsocket_rfcomm_pcb_p pcb) 3093f2bb1caeSJulian Elischer { 3094f2bb1caeSJulian Elischer struct mbuf *m = NULL; 3095f2bb1caeSJulian Elischer struct rfcomm_mcc_hdr *hdr = NULL; 3096f2bb1caeSJulian Elischer struct rfcomm_mcc_msc *msc = NULL; 3097f2bb1caeSJulian Elischer 3098f2bb1caeSJulian Elischer mtx_assert(&pcb->session->session_mtx, MA_OWNED); 3099f2bb1caeSJulian Elischer mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3100f2bb1caeSJulian Elischer 3101eb1b1807SGleb Smirnoff MGETHDR(m, M_NOWAIT, MT_DATA); 3102f2bb1caeSJulian Elischer if (m == NULL) 3103f2bb1caeSJulian Elischer return (ENOBUFS); 3104f2bb1caeSJulian Elischer 3105f2bb1caeSJulian Elischer m->m_pkthdr.len = m->m_len = sizeof(*hdr) + sizeof(*msc); 3106f2bb1caeSJulian Elischer 3107f2bb1caeSJulian Elischer hdr = mtod(m, struct rfcomm_mcc_hdr *); 3108f2bb1caeSJulian Elischer msc = (struct rfcomm_mcc_msc *)(hdr + 1); 3109f2bb1caeSJulian Elischer 3110f2bb1caeSJulian Elischer hdr->type = RFCOMM_MKMCC_TYPE(1, RFCOMM_MCC_MSC); 3111f2bb1caeSJulian Elischer hdr->length = RFCOMM_MKLEN8(sizeof(*msc)); 3112f2bb1caeSJulian Elischer 3113f2bb1caeSJulian Elischer msc->address = RFCOMM_MKADDRESS(1, pcb->dlci); 3114f2bb1caeSJulian Elischer msc->modem = pcb->lmodem; 3115f2bb1caeSJulian Elischer 3116f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 3117f2bb1caeSJulian Elischer "%s: Sending MSC dlci=%d, state=%d, flags=%#x, address=%d, modem=%#x\n", 3118f2bb1caeSJulian Elischer __func__, pcb->dlci, pcb->state, pcb->flags, msc->address, 3119f2bb1caeSJulian Elischer msc->modem); 3120f2bb1caeSJulian Elischer 3121f2bb1caeSJulian Elischer return (ng_btsocket_rfcomm_send_uih(pcb->session, 3122f2bb1caeSJulian Elischer RFCOMM_MKADDRESS(INITIATOR(pcb->session), 0), 0, 0, m)); 3123f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_send_msc */ 3124f2bb1caeSJulian Elischer 3125f2bb1caeSJulian Elischer /* 3126f2bb1caeSJulian Elischer * Send PN request. Caller must hold pcb->pcb_mtx and pcb->session->session_mtx 3127f2bb1caeSJulian Elischer */ 3128f2bb1caeSJulian Elischer 3129f2bb1caeSJulian Elischer static int 3130f2bb1caeSJulian Elischer ng_btsocket_rfcomm_send_pn(ng_btsocket_rfcomm_pcb_p pcb) 3131f2bb1caeSJulian Elischer { 3132f2bb1caeSJulian Elischer struct mbuf *m = NULL; 3133f2bb1caeSJulian Elischer struct rfcomm_mcc_hdr *hdr = NULL; 3134f2bb1caeSJulian Elischer struct rfcomm_mcc_pn *pn = NULL; 3135f2bb1caeSJulian Elischer 3136f2bb1caeSJulian Elischer mtx_assert(&pcb->session->session_mtx, MA_OWNED); 3137f2bb1caeSJulian Elischer mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3138f2bb1caeSJulian Elischer 3139eb1b1807SGleb Smirnoff MGETHDR(m, M_NOWAIT, MT_DATA); 3140f2bb1caeSJulian Elischer if (m == NULL) 3141f2bb1caeSJulian Elischer return (ENOBUFS); 3142f2bb1caeSJulian Elischer 3143f2bb1caeSJulian Elischer m->m_pkthdr.len = m->m_len = sizeof(*hdr) + sizeof(*pn); 3144f2bb1caeSJulian Elischer 3145f2bb1caeSJulian Elischer hdr = mtod(m, struct rfcomm_mcc_hdr *); 3146f2bb1caeSJulian Elischer pn = (struct rfcomm_mcc_pn *)(hdr + 1); 3147f2bb1caeSJulian Elischer 3148f2bb1caeSJulian Elischer hdr->type = RFCOMM_MKMCC_TYPE(1, RFCOMM_MCC_PN); 3149f2bb1caeSJulian Elischer hdr->length = RFCOMM_MKLEN8(sizeof(*pn)); 3150f2bb1caeSJulian Elischer 3151f2bb1caeSJulian Elischer pn->dlci = pcb->dlci; 31520986ab12SMaksim Yevmenkin 31530986ab12SMaksim Yevmenkin /* 31540986ab12SMaksim Yevmenkin * Set default DLCI priority as described in GSM 07.10 31550986ab12SMaksim Yevmenkin * (ETSI TS 101 369) clause 5.6 page 42 31560986ab12SMaksim Yevmenkin */ 31570986ab12SMaksim Yevmenkin 31580986ab12SMaksim Yevmenkin pn->priority = (pcb->dlci < 56)? (((pcb->dlci >> 3) << 3) + 7) : 61; 3159f2bb1caeSJulian Elischer pn->ack_timer = 0; 3160f2bb1caeSJulian Elischer pn->mtu = htole16(pcb->mtu); 3161f2bb1caeSJulian Elischer pn->max_retrans = 0; 3162f2bb1caeSJulian Elischer 3163f2bb1caeSJulian Elischer if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) { 3164f2bb1caeSJulian Elischer pn->flow_control = 0xf0; 3165f2bb1caeSJulian Elischer pn->credits = pcb->rx_cred; 3166f2bb1caeSJulian Elischer } else { 3167f2bb1caeSJulian Elischer pn->flow_control = 0; 3168f2bb1caeSJulian Elischer pn->credits = 0; 3169f2bb1caeSJulian Elischer } 3170f2bb1caeSJulian Elischer 3171f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 3172f2bb1caeSJulian Elischer "%s: Sending PN dlci=%d, state=%d, flags=%#x, mtu=%d, flow_control=%#x, " \ 3173f2bb1caeSJulian Elischer "credits=%d\n", __func__, pcb->dlci, pcb->state, pcb->flags, pcb->mtu, 3174f2bb1caeSJulian Elischer pn->flow_control, pn->credits); 3175f2bb1caeSJulian Elischer 3176f2bb1caeSJulian Elischer return (ng_btsocket_rfcomm_send_uih(pcb->session, 3177f2bb1caeSJulian Elischer RFCOMM_MKADDRESS(INITIATOR(pcb->session), 0), 0, 0, m)); 3178f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_send_pn */ 3179f2bb1caeSJulian Elischer 3180f2bb1caeSJulian Elischer /* 3181f2bb1caeSJulian Elischer * Calculate and send credits based on available space in receive buffer 3182f2bb1caeSJulian Elischer */ 3183f2bb1caeSJulian Elischer 3184f2bb1caeSJulian Elischer static int 3185f2bb1caeSJulian Elischer ng_btsocket_rfcomm_send_credits(ng_btsocket_rfcomm_pcb_p pcb) 3186f2bb1caeSJulian Elischer { 3187f2bb1caeSJulian Elischer int error = 0; 3188f2bb1caeSJulian Elischer u_int8_t credits; 3189f2bb1caeSJulian Elischer 3190f2bb1caeSJulian Elischer mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3191f2bb1caeSJulian Elischer mtx_assert(&pcb->session->session_mtx, MA_OWNED); 3192f2bb1caeSJulian Elischer 3193f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 3194f2bb1caeSJulian Elischer "%s: Sending more credits, dlci=%d, state=%d, flags=%#x, mtu=%d, " \ 3195f2bb1caeSJulian Elischer "space=%ld, tx_cred=%d, rx_cred=%d\n", 3196f2bb1caeSJulian Elischer __func__, pcb->dlci, pcb->state, pcb->flags, pcb->mtu, 3197f2bb1caeSJulian Elischer sbspace(&pcb->so->so_rcv), pcb->tx_cred, pcb->rx_cred); 3198f2bb1caeSJulian Elischer 3199f2bb1caeSJulian Elischer credits = sbspace(&pcb->so->so_rcv) / pcb->mtu; 3200f2bb1caeSJulian Elischer if (credits > 0) { 3201f2bb1caeSJulian Elischer if (pcb->rx_cred + credits > RFCOMM_MAX_CREDITS) 3202f2bb1caeSJulian Elischer credits = RFCOMM_MAX_CREDITS - pcb->rx_cred; 3203f2bb1caeSJulian Elischer 3204f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_uih( 3205f2bb1caeSJulian Elischer pcb->session, 3206f2bb1caeSJulian Elischer RFCOMM_MKADDRESS(INITIATOR(pcb->session), 3207f2bb1caeSJulian Elischer pcb->dlci), 1, credits, NULL); 3208f2bb1caeSJulian Elischer if (error == 0) { 3209f2bb1caeSJulian Elischer pcb->rx_cred += credits; 3210f2bb1caeSJulian Elischer 3211f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 3212f2bb1caeSJulian Elischer "%s: Gave remote side %d more credits, dlci=%d, state=%d, flags=%#x, " \ 3213f2bb1caeSJulian Elischer "rx_cred=%d, tx_cred=%d\n", __func__, credits, pcb->dlci, pcb->state, 3214f2bb1caeSJulian Elischer pcb->flags, pcb->rx_cred, pcb->tx_cred); 3215f2bb1caeSJulian Elischer } else 3216f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_ERR( 3217f2bb1caeSJulian Elischer "%s: Could not send credits, error=%d, dlci=%d, state=%d, flags=%#x, " \ 3218f2bb1caeSJulian Elischer "mtu=%d, space=%ld, tx_cred=%d, rx_cred=%d\n", 3219f2bb1caeSJulian Elischer __func__, error, pcb->dlci, pcb->state, 3220f2bb1caeSJulian Elischer pcb->flags, pcb->mtu, sbspace(&pcb->so->so_rcv), 3221f2bb1caeSJulian Elischer pcb->tx_cred, pcb->rx_cred); 3222f2bb1caeSJulian Elischer } 3223f2bb1caeSJulian Elischer 3224f2bb1caeSJulian Elischer return (error); 3225f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_send_credits */ 3226f2bb1caeSJulian Elischer 3227f2bb1caeSJulian Elischer /***************************************************************************** 3228f2bb1caeSJulian Elischer ***************************************************************************** 3229f2bb1caeSJulian Elischer ** RFCOMM DLCs 3230f2bb1caeSJulian Elischer ***************************************************************************** 3231f2bb1caeSJulian Elischer *****************************************************************************/ 3232f2bb1caeSJulian Elischer 3233f2bb1caeSJulian Elischer /* 3234f2bb1caeSJulian Elischer * Send data from socket send buffer 3235f2bb1caeSJulian Elischer * Caller must hold pcb->pcb_mtx and pcb->session->session_mtx 3236f2bb1caeSJulian Elischer */ 3237f2bb1caeSJulian Elischer 3238f2bb1caeSJulian Elischer static int 3239f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_send(ng_btsocket_rfcomm_pcb_p pcb, int limit) 3240f2bb1caeSJulian Elischer { 3241f2bb1caeSJulian Elischer struct mbuf *m = NULL; 3242f2bb1caeSJulian Elischer int sent, length, error; 3243f2bb1caeSJulian Elischer 3244f2bb1caeSJulian Elischer mtx_assert(&pcb->session->session_mtx, MA_OWNED); 3245f2bb1caeSJulian Elischer mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3246f2bb1caeSJulian Elischer 3247f2bb1caeSJulian Elischer if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) 3248f2bb1caeSJulian Elischer limit = min(limit, pcb->tx_cred); 3249f2bb1caeSJulian Elischer else if (!(pcb->rmodem & RFCOMM_MODEM_FC)) 3250f2bb1caeSJulian Elischer limit = min(limit, RFCOMM_MAX_CREDITS); /* XXX ??? */ 3251f2bb1caeSJulian Elischer else 3252f2bb1caeSJulian Elischer limit = 0; 3253f2bb1caeSJulian Elischer 3254f2bb1caeSJulian Elischer if (limit == 0) { 3255f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 3256f2bb1caeSJulian Elischer "%s: Could not send - remote flow control asserted, dlci=%d, flags=%#x, " \ 3257f2bb1caeSJulian Elischer "rmodem=%#x, tx_cred=%d\n", 3258f2bb1caeSJulian Elischer __func__, pcb->dlci, pcb->flags, pcb->rmodem, 3259f2bb1caeSJulian Elischer pcb->tx_cred); 3260f2bb1caeSJulian Elischer 3261f2bb1caeSJulian Elischer return (0); 3262f2bb1caeSJulian Elischer } 3263f2bb1caeSJulian Elischer 3264f2bb1caeSJulian Elischer for (error = 0, sent = 0; sent < limit; sent ++) { 3265cfa6009eSGleb Smirnoff length = min(pcb->mtu, sbavail(&pcb->so->so_snd)); 3266f2bb1caeSJulian Elischer if (length == 0) 3267f2bb1caeSJulian Elischer break; 3268f2bb1caeSJulian Elischer 3269f2bb1caeSJulian Elischer /* Get the chunk from the socket's send buffer */ 3270f2bb1caeSJulian Elischer m = ng_btsocket_rfcomm_prepare_packet(&pcb->so->so_snd, length); 3271f2bb1caeSJulian Elischer if (m == NULL) { 3272f2bb1caeSJulian Elischer error = ENOBUFS; 3273f2bb1caeSJulian Elischer break; 3274f2bb1caeSJulian Elischer } 3275f2bb1caeSJulian Elischer 3276f2bb1caeSJulian Elischer sbdrop(&pcb->so->so_snd, length); 3277f2bb1caeSJulian Elischer 3278f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_uih(pcb->session, 3279f2bb1caeSJulian Elischer RFCOMM_MKADDRESS(INITIATOR(pcb->session), 3280f2bb1caeSJulian Elischer pcb->dlci), 0, 0, m); 3281f2bb1caeSJulian Elischer if (error != 0) 3282f2bb1caeSJulian Elischer break; 3283f2bb1caeSJulian Elischer } 3284f2bb1caeSJulian Elischer 3285f2bb1caeSJulian Elischer if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) 3286f2bb1caeSJulian Elischer pcb->tx_cred -= sent; 3287f2bb1caeSJulian Elischer 3288f2bb1caeSJulian Elischer if (error == 0 && sent > 0) { 3289f2bb1caeSJulian Elischer pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_SENDING; 3290f2bb1caeSJulian Elischer sowwakeup(pcb->so); 3291f2bb1caeSJulian Elischer } 3292f2bb1caeSJulian Elischer 3293f2bb1caeSJulian Elischer return (error); 3294f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_pcb_send */ 3295f2bb1caeSJulian Elischer 3296f2bb1caeSJulian Elischer /* 3297f2bb1caeSJulian Elischer * Unlink and disconnect DLC. If ng_btsocket_rfcomm_pcb_kill() returns 3298f2bb1caeSJulian Elischer * non zero value than socket has no reference and has to be detached. 3299f2bb1caeSJulian Elischer * Caller must hold pcb->pcb_mtx and pcb->session->session_mtx 3300f2bb1caeSJulian Elischer */ 3301f2bb1caeSJulian Elischer 33027c380856SMaksim Yevmenkin static void 3303f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_kill(ng_btsocket_rfcomm_pcb_p pcb, int error) 3304f2bb1caeSJulian Elischer { 3305f2bb1caeSJulian Elischer ng_btsocket_rfcomm_session_p s = pcb->session; 3306f2bb1caeSJulian Elischer 3307f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 3308f2bb1caeSJulian Elischer "%s: Killing DLC, so=%p, dlci=%d, state=%d, flags=%#x, error=%d\n", 3309f2bb1caeSJulian Elischer __func__, pcb->so, pcb->dlci, pcb->state, pcb->flags, error); 3310f2bb1caeSJulian Elischer 3311f2bb1caeSJulian Elischer if (pcb->session == NULL) 3312f2bb1caeSJulian Elischer panic("%s: DLC without session, pcb=%p, state=%d, flags=%#x\n", 3313f2bb1caeSJulian Elischer __func__, pcb, pcb->state, pcb->flags); 3314f2bb1caeSJulian Elischer 331581c95c52SSam Leffler mtx_assert(&pcb->session->session_mtx, MA_OWNED); 331681c95c52SSam Leffler mtx_assert(&pcb->pcb_mtx, MA_OWNED); 331781c95c52SSam Leffler 3318f2bb1caeSJulian Elischer if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO) 3319f2bb1caeSJulian Elischer ng_btsocket_rfcomm_untimeout(pcb); 3320f2bb1caeSJulian Elischer 3321f2bb1caeSJulian Elischer /* Detach DLC from the session. Does not matter which state DLC in */ 3322f2bb1caeSJulian Elischer LIST_REMOVE(pcb, session_next); 3323f2bb1caeSJulian Elischer pcb->session = NULL; 3324f2bb1caeSJulian Elischer 3325f2bb1caeSJulian Elischer /* Change DLC state and wakeup all sleepers */ 3326f2bb1caeSJulian Elischer pcb->state = NG_BTSOCKET_RFCOMM_DLC_CLOSED; 3327f2bb1caeSJulian Elischer pcb->so->so_error = error; 3328f2bb1caeSJulian Elischer soisdisconnected(pcb->so); 3329f2bb1caeSJulian Elischer wakeup(&pcb->state); 3330f2bb1caeSJulian Elischer 3331f2bb1caeSJulian Elischer /* Check if we have any DLCs left on the session */ 3332f2bb1caeSJulian Elischer if (LIST_EMPTY(&s->dlcs) && INITIATOR(s)) { 3333f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 3334f2bb1caeSJulian Elischer "%s: Disconnecting session, state=%d, flags=%#x, mtu=%d\n", 3335f2bb1caeSJulian Elischer __func__, s->state, s->flags, s->mtu); 3336f2bb1caeSJulian Elischer 3337f2bb1caeSJulian Elischer switch (s->state) { 3338f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_CLOSED: 3339f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING: 3340f2bb1caeSJulian Elischer /* 3341f2bb1caeSJulian Elischer * Do not have to do anything here. We can get here 3342f2bb1caeSJulian Elischer * when L2CAP connection was terminated or we have 3343f2bb1caeSJulian Elischer * received DISC on multiplexor channel 3344f2bb1caeSJulian Elischer */ 3345f2bb1caeSJulian Elischer break; 3346f2bb1caeSJulian Elischer 3347f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_OPEN: 3348f2bb1caeSJulian Elischer /* Send DISC on multiplexor channel */ 3349f2bb1caeSJulian Elischer error = ng_btsocket_rfcomm_send_command(s, 3350f2bb1caeSJulian Elischer RFCOMM_FRAME_DISC, 0); 3351f2bb1caeSJulian Elischer if (error == 0) { 3352f2bb1caeSJulian Elischer s->state = NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING; 3353f2bb1caeSJulian Elischer break; 3354f2bb1caeSJulian Elischer } 3355f2bb1caeSJulian Elischer /* FALL THROUGH */ 3356f2bb1caeSJulian Elischer 3357f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_CONNECTING: 3358f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED: 3359f2bb1caeSJulian Elischer s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; 3360f2bb1caeSJulian Elischer break; 3361f2bb1caeSJulian Elischer 3362f2bb1caeSJulian Elischer /* case NG_BTSOCKET_RFCOMM_SESSION_LISTENING: */ 3363f2bb1caeSJulian Elischer default: 3364f2bb1caeSJulian Elischer panic("%s: Invalid session state=%d, flags=%#x\n", 3365f2bb1caeSJulian Elischer __func__, s->state, s->flags); 3366f2bb1caeSJulian Elischer break; 3367f2bb1caeSJulian Elischer } 3368f2bb1caeSJulian Elischer 3369f2bb1caeSJulian Elischer ng_btsocket_rfcomm_task_wakeup(); 3370f2bb1caeSJulian Elischer } 3371f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_pcb_kill */ 3372f2bb1caeSJulian Elischer 3373f2bb1caeSJulian Elischer /* 3374f2bb1caeSJulian Elischer * Look for given dlci for given RFCOMM session. Caller must hold s->session_mtx 3375f2bb1caeSJulian Elischer */ 3376f2bb1caeSJulian Elischer 3377f2bb1caeSJulian Elischer static ng_btsocket_rfcomm_pcb_p 3378f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_by_dlci(ng_btsocket_rfcomm_session_p s, int dlci) 3379f2bb1caeSJulian Elischer { 3380f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = NULL; 3381f2bb1caeSJulian Elischer 3382f2bb1caeSJulian Elischer mtx_assert(&s->session_mtx, MA_OWNED); 3383f2bb1caeSJulian Elischer 3384f2bb1caeSJulian Elischer LIST_FOREACH(pcb, &s->dlcs, session_next) 3385f2bb1caeSJulian Elischer if (pcb->dlci == dlci) 3386f2bb1caeSJulian Elischer break; 3387f2bb1caeSJulian Elischer 3388f2bb1caeSJulian Elischer return (pcb); 3389f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_pcb_by_dlci */ 3390f2bb1caeSJulian Elischer 3391f2bb1caeSJulian Elischer /* 3392f2bb1caeSJulian Elischer * Look for socket that listens on given src address and given channel 3393f2bb1caeSJulian Elischer */ 3394f2bb1caeSJulian Elischer 3395f2bb1caeSJulian Elischer static ng_btsocket_rfcomm_pcb_p 3396f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_listener(bdaddr_p src, int channel) 3397f2bb1caeSJulian Elischer { 3398f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb1 = NULL; 3399f2bb1caeSJulian Elischer 3400f2bb1caeSJulian Elischer mtx_lock(&ng_btsocket_rfcomm_sockets_mtx); 3401f2bb1caeSJulian Elischer 3402f2bb1caeSJulian Elischer LIST_FOREACH(pcb, &ng_btsocket_rfcomm_sockets, next) { 3403f2bb1caeSJulian Elischer if (pcb->channel != channel || 3404f2bb1caeSJulian Elischer !(pcb->so->so_options & SO_ACCEPTCONN)) 3405f2bb1caeSJulian Elischer continue; 3406f2bb1caeSJulian Elischer 3407f2bb1caeSJulian Elischer if (bcmp(&pcb->src, src, sizeof(*src)) == 0) 3408f2bb1caeSJulian Elischer break; 3409f2bb1caeSJulian Elischer 3410f2bb1caeSJulian Elischer if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) 3411f2bb1caeSJulian Elischer pcb1 = pcb; 3412f2bb1caeSJulian Elischer } 3413f2bb1caeSJulian Elischer 3414f2bb1caeSJulian Elischer mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx); 3415f2bb1caeSJulian Elischer 3416f2bb1caeSJulian Elischer return ((pcb != NULL)? pcb : pcb1); 3417f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_pcb_listener */ 3418f2bb1caeSJulian Elischer 3419f2bb1caeSJulian Elischer /***************************************************************************** 3420f2bb1caeSJulian Elischer ***************************************************************************** 3421f2bb1caeSJulian Elischer ** Misc. functions 3422f2bb1caeSJulian Elischer ***************************************************************************** 3423f2bb1caeSJulian Elischer *****************************************************************************/ 3424f2bb1caeSJulian Elischer 3425f2bb1caeSJulian Elischer /* 3426f2bb1caeSJulian Elischer * Set timeout. Caller MUST hold pcb_mtx 3427f2bb1caeSJulian Elischer */ 3428f2bb1caeSJulian Elischer 3429f2bb1caeSJulian Elischer static void 3430f2bb1caeSJulian Elischer ng_btsocket_rfcomm_timeout(ng_btsocket_rfcomm_pcb_p pcb) 3431f2bb1caeSJulian Elischer { 3432f2bb1caeSJulian Elischer mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3433f2bb1caeSJulian Elischer 3434f2bb1caeSJulian Elischer if (!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)) { 3435f2bb1caeSJulian Elischer pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_TIMO; 3436f2bb1caeSJulian Elischer pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT; 34373d1592efSJohn Baldwin callout_reset(&pcb->timo, ng_btsocket_rfcomm_timo * hz, 34383d1592efSJohn Baldwin ng_btsocket_rfcomm_process_timeout, pcb); 3439f2bb1caeSJulian Elischer } else 3440f2bb1caeSJulian Elischer panic("%s: Duplicated socket timeout?!\n", __func__); 3441f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_timeout */ 3442f2bb1caeSJulian Elischer 3443f2bb1caeSJulian Elischer /* 3444f2bb1caeSJulian Elischer * Unset pcb timeout. Caller MUST hold pcb_mtx 3445f2bb1caeSJulian Elischer */ 3446f2bb1caeSJulian Elischer 3447f2bb1caeSJulian Elischer static void 3448f2bb1caeSJulian Elischer ng_btsocket_rfcomm_untimeout(ng_btsocket_rfcomm_pcb_p pcb) 3449f2bb1caeSJulian Elischer { 3450f2bb1caeSJulian Elischer mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3451f2bb1caeSJulian Elischer 3452f2bb1caeSJulian Elischer if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO) { 34533d1592efSJohn Baldwin callout_stop(&pcb->timo); 3454f2bb1caeSJulian Elischer pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMO; 3455f2bb1caeSJulian Elischer pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT; 3456f2bb1caeSJulian Elischer } else 3457f2bb1caeSJulian Elischer panic("%s: No socket timeout?!\n", __func__); 3458f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_timeout */ 3459f2bb1caeSJulian Elischer 3460f2bb1caeSJulian Elischer /* 3461f2bb1caeSJulian Elischer * Process pcb timeout 3462f2bb1caeSJulian Elischer */ 3463f2bb1caeSJulian Elischer 3464f2bb1caeSJulian Elischer static void 3465f2bb1caeSJulian Elischer ng_btsocket_rfcomm_process_timeout(void *xpcb) 3466f2bb1caeSJulian Elischer { 3467f2bb1caeSJulian Elischer ng_btsocket_rfcomm_pcb_p pcb = (ng_btsocket_rfcomm_pcb_p) xpcb; 3468f2bb1caeSJulian Elischer 34693d1592efSJohn Baldwin mtx_assert(&pcb->pcb_mtx, MA_OWNED); 3470f2bb1caeSJulian Elischer 3471f2bb1caeSJulian Elischer NG_BTSOCKET_RFCOMM_INFO( 3472f2bb1caeSJulian Elischer "%s: Timeout, so=%p, dlci=%d, state=%d, flags=%#x\n", 3473f2bb1caeSJulian Elischer __func__, pcb->so, pcb->dlci, pcb->state, pcb->flags); 3474f2bb1caeSJulian Elischer 3475f2bb1caeSJulian Elischer pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMO; 3476f2bb1caeSJulian Elischer pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT; 3477f2bb1caeSJulian Elischer 3478f2bb1caeSJulian Elischer switch (pcb->state) { 3479f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING: 3480f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_CONNECTING: 3481f2bb1caeSJulian Elischer pcb->state = NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING; 3482f2bb1caeSJulian Elischer break; 3483f2bb1caeSJulian Elischer 3484f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT: 3485f2bb1caeSJulian Elischer case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING: 3486f2bb1caeSJulian Elischer break; 3487f2bb1caeSJulian Elischer 3488f2bb1caeSJulian Elischer default: 3489f2bb1caeSJulian Elischer panic( 3490f2bb1caeSJulian Elischer "%s: DLC timeout in invalid state, dlci=%d, state=%d, flags=%#x\n", 3491f2bb1caeSJulian Elischer __func__, pcb->dlci, pcb->state, pcb->flags); 3492f2bb1caeSJulian Elischer break; 3493f2bb1caeSJulian Elischer } 3494f2bb1caeSJulian Elischer 3495f2bb1caeSJulian Elischer ng_btsocket_rfcomm_task_wakeup(); 3496f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_process_timeout */ 3497f2bb1caeSJulian Elischer 3498f2bb1caeSJulian Elischer /* 3499f2bb1caeSJulian Elischer * Get up to length bytes from the socket buffer 3500f2bb1caeSJulian Elischer */ 3501f2bb1caeSJulian Elischer 3502f2bb1caeSJulian Elischer static struct mbuf * 3503f2bb1caeSJulian Elischer ng_btsocket_rfcomm_prepare_packet(struct sockbuf *sb, int length) 3504f2bb1caeSJulian Elischer { 3505f2bb1caeSJulian Elischer struct mbuf *top = NULL, *m = NULL, *n = NULL, *nextpkt = NULL; 3506f2bb1caeSJulian Elischer int mlen, noff, len; 3507f2bb1caeSJulian Elischer 3508eb1b1807SGleb Smirnoff MGETHDR(top, M_NOWAIT, MT_DATA); 3509f2bb1caeSJulian Elischer if (top == NULL) 3510f2bb1caeSJulian Elischer return (NULL); 3511f2bb1caeSJulian Elischer 3512f2bb1caeSJulian Elischer top->m_pkthdr.len = length; 3513f2bb1caeSJulian Elischer top->m_len = 0; 3514f2bb1caeSJulian Elischer mlen = MHLEN; 3515f2bb1caeSJulian Elischer 3516f2bb1caeSJulian Elischer m = top; 3517f2bb1caeSJulian Elischer n = sb->sb_mb; 3518f2bb1caeSJulian Elischer nextpkt = n->m_nextpkt; 3519f2bb1caeSJulian Elischer noff = 0; 3520f2bb1caeSJulian Elischer 3521f2bb1caeSJulian Elischer while (length > 0 && n != NULL) { 3522f2bb1caeSJulian Elischer len = min(mlen - m->m_len, n->m_len - noff); 3523f2bb1caeSJulian Elischer if (len > length) 3524f2bb1caeSJulian Elischer len = length; 3525f2bb1caeSJulian Elischer 3526f2bb1caeSJulian Elischer bcopy(mtod(n, caddr_t)+noff, mtod(m, caddr_t)+m->m_len, len); 3527f2bb1caeSJulian Elischer m->m_len += len; 3528f2bb1caeSJulian Elischer noff += len; 3529f2bb1caeSJulian Elischer length -= len; 3530f2bb1caeSJulian Elischer 3531f2bb1caeSJulian Elischer if (length > 0 && m->m_len == mlen) { 3532eb1b1807SGleb Smirnoff MGET(m->m_next, M_NOWAIT, MT_DATA); 3533f2bb1caeSJulian Elischer if (m->m_next == NULL) { 3534f2bb1caeSJulian Elischer NG_FREE_M(top); 3535f2bb1caeSJulian Elischer return (NULL); 3536f2bb1caeSJulian Elischer } 3537f2bb1caeSJulian Elischer 3538f2bb1caeSJulian Elischer m = m->m_next; 3539f2bb1caeSJulian Elischer m->m_len = 0; 3540f2bb1caeSJulian Elischer mlen = MLEN; 3541f2bb1caeSJulian Elischer } 3542f2bb1caeSJulian Elischer 3543f2bb1caeSJulian Elischer if (noff == n->m_len) { 3544f2bb1caeSJulian Elischer noff = 0; 3545f2bb1caeSJulian Elischer n = n->m_next; 3546f2bb1caeSJulian Elischer 3547f2bb1caeSJulian Elischer if (n == NULL) 3548f2bb1caeSJulian Elischer n = nextpkt; 3549f2bb1caeSJulian Elischer 3550f2bb1caeSJulian Elischer nextpkt = (n != NULL)? n->m_nextpkt : NULL; 3551f2bb1caeSJulian Elischer } 3552f2bb1caeSJulian Elischer } 3553f2bb1caeSJulian Elischer 3554f2bb1caeSJulian Elischer if (length < 0) 3555f2bb1caeSJulian Elischer panic("%s: length=%d\n", __func__, length); 3556f2bb1caeSJulian Elischer if (length > 0 && n == NULL) 3557f2bb1caeSJulian Elischer panic("%s: bogus length=%d, n=%p\n", __func__, length, n); 3558f2bb1caeSJulian Elischer 3559f2bb1caeSJulian Elischer return (top); 3560f2bb1caeSJulian Elischer } /* ng_btsocket_rfcomm_prepare_packet */ 3561f2bb1caeSJulian Elischer 3562