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