Path: blob/main/sys/netgraph/bluetooth/socket/ng_btsocket_rfcomm.c
34677 views
/*1* ng_btsocket_rfcomm.c2*/34/*-5* SPDX-License-Identifier: BSD-2-Clause6*7* Copyright (c) 2001-2003 Maksim Yevmenkin <[email protected]>8* All rights reserved.9*10* Redistribution and use in source and binary forms, with or without11* modification, are permitted provided that the following conditions12* are met:13* 1. Redistributions of source code must retain the above copyright14* notice, this list of conditions and the following disclaimer.15* 2. Redistributions in binary form must reproduce the above copyright16* notice, this list of conditions and the following disclaimer in the17* documentation and/or other materials provided with the distribution.18*19* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND20* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE21* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE22* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE23* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL24* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS25* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)26* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT27* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY28* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF29* SUCH DAMAGE.30*31* $Id: ng_btsocket_rfcomm.c,v 1.28 2003/09/14 23:29:06 max Exp $32*/3334#include <sys/param.h>35#include <sys/systm.h>36#include <sys/bitstring.h>37#include <sys/domain.h>38#include <sys/endian.h>39#include <sys/errno.h>40#include <sys/filedesc.h>41#include <sys/ioccom.h>42#include <sys/kernel.h>43#include <sys/lock.h>44#include <sys/malloc.h>45#include <sys/mbuf.h>46#include <sys/mutex.h>47#include <sys/proc.h>48#include <sys/protosw.h>49#include <sys/queue.h>50#include <sys/socket.h>51#include <sys/socketvar.h>52#include <sys/sysctl.h>53#include <sys/taskqueue.h>54#include <sys/uio.h>5556#include <net/vnet.h>5758#include <netgraph/ng_message.h>59#include <netgraph/netgraph.h>60#include <netgraph/bluetooth/include/ng_bluetooth.h>61#include <netgraph/bluetooth/include/ng_hci.h>62#include <netgraph/bluetooth/include/ng_l2cap.h>63#include <netgraph/bluetooth/include/ng_btsocket.h>64#include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>65#include <netgraph/bluetooth/include/ng_btsocket_rfcomm.h>6667/* MALLOC define */68#ifdef NG_SEPARATE_MALLOC69static MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_RFCOMM, "netgraph_btsocks_rfcomm",70"Netgraph Bluetooth RFCOMM sockets");71#else72#define M_NETGRAPH_BTSOCKET_RFCOMM M_NETGRAPH73#endif /* NG_SEPARATE_MALLOC */7475/* Debug */76#define NG_BTSOCKET_RFCOMM_INFO \77if (ng_btsocket_rfcomm_debug_level >= NG_BTSOCKET_INFO_LEVEL && \78ppsratecheck(&ng_btsocket_rfcomm_lasttime, &ng_btsocket_rfcomm_curpps, 1)) \79printf8081#define NG_BTSOCKET_RFCOMM_WARN \82if (ng_btsocket_rfcomm_debug_level >= NG_BTSOCKET_WARN_LEVEL && \83ppsratecheck(&ng_btsocket_rfcomm_lasttime, &ng_btsocket_rfcomm_curpps, 1)) \84printf8586#define NG_BTSOCKET_RFCOMM_ERR \87if (ng_btsocket_rfcomm_debug_level >= NG_BTSOCKET_ERR_LEVEL && \88ppsratecheck(&ng_btsocket_rfcomm_lasttime, &ng_btsocket_rfcomm_curpps, 1)) \89printf9091#define NG_BTSOCKET_RFCOMM_ALERT \92if (ng_btsocket_rfcomm_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \93ppsratecheck(&ng_btsocket_rfcomm_lasttime, &ng_btsocket_rfcomm_curpps, 1)) \94printf9596#define ALOT 0x7fff9798/* Local prototypes */99static int ng_btsocket_rfcomm_upcall100(struct socket *so, void *arg, int waitflag);101static void ng_btsocket_rfcomm_sessions_task102(void *ctx, int pending);103static void ng_btsocket_rfcomm_session_task104(ng_btsocket_rfcomm_session_p s);105#define ng_btsocket_rfcomm_task_wakeup() \106taskqueue_enqueue(taskqueue_swi_giant, &ng_btsocket_rfcomm_task)107108static ng_btsocket_rfcomm_pcb_p ng_btsocket_rfcomm_connect_ind109(ng_btsocket_rfcomm_session_p s, int channel);110static void ng_btsocket_rfcomm_connect_cfm111(ng_btsocket_rfcomm_session_p s);112113static int ng_btsocket_rfcomm_session_create114(ng_btsocket_rfcomm_session_p *sp, struct socket *l2so,115bdaddr_p src, bdaddr_p dst, struct thread *td);116static int ng_btsocket_rfcomm_session_accept117(ng_btsocket_rfcomm_session_p s0);118static int ng_btsocket_rfcomm_session_connect119(ng_btsocket_rfcomm_session_p s);120static int ng_btsocket_rfcomm_session_receive121(ng_btsocket_rfcomm_session_p s);122static int ng_btsocket_rfcomm_session_send123(ng_btsocket_rfcomm_session_p s);124static void ng_btsocket_rfcomm_session_clean125(ng_btsocket_rfcomm_session_p s);126static void ng_btsocket_rfcomm_session_process_pcb127(ng_btsocket_rfcomm_session_p s);128static ng_btsocket_rfcomm_session_p ng_btsocket_rfcomm_session_by_addr129(bdaddr_p src, bdaddr_p dst);130131static int ng_btsocket_rfcomm_receive_frame132(ng_btsocket_rfcomm_session_p s, struct mbuf *m0);133static int ng_btsocket_rfcomm_receive_sabm134(ng_btsocket_rfcomm_session_p s, int dlci);135static int ng_btsocket_rfcomm_receive_disc136(ng_btsocket_rfcomm_session_p s, int dlci);137static int ng_btsocket_rfcomm_receive_ua138(ng_btsocket_rfcomm_session_p s, int dlci);139static int ng_btsocket_rfcomm_receive_dm140(ng_btsocket_rfcomm_session_p s, int dlci);141static int ng_btsocket_rfcomm_receive_uih142(ng_btsocket_rfcomm_session_p s, int dlci, int pf, struct mbuf *m0);143static int ng_btsocket_rfcomm_receive_mcc144(ng_btsocket_rfcomm_session_p s, struct mbuf *m0);145static int ng_btsocket_rfcomm_receive_test146(ng_btsocket_rfcomm_session_p s, struct mbuf *m0);147static int ng_btsocket_rfcomm_receive_fc148(ng_btsocket_rfcomm_session_p s, struct mbuf *m0);149static int ng_btsocket_rfcomm_receive_msc150(ng_btsocket_rfcomm_session_p s, struct mbuf *m0);151static int ng_btsocket_rfcomm_receive_rpn152(ng_btsocket_rfcomm_session_p s, struct mbuf *m0);153static int ng_btsocket_rfcomm_receive_rls154(ng_btsocket_rfcomm_session_p s, struct mbuf *m0);155static int ng_btsocket_rfcomm_receive_pn156(ng_btsocket_rfcomm_session_p s, struct mbuf *m0);157static void ng_btsocket_rfcomm_set_pn158(ng_btsocket_rfcomm_pcb_p pcb, u_int8_t cr, u_int8_t flow_control,159u_int8_t credits, u_int16_t mtu);160161static int ng_btsocket_rfcomm_send_command162(ng_btsocket_rfcomm_session_p s, u_int8_t type, u_int8_t dlci);163static int ng_btsocket_rfcomm_send_uih164(ng_btsocket_rfcomm_session_p s, u_int8_t address, u_int8_t pf,165u_int8_t credits, struct mbuf *data);166static int ng_btsocket_rfcomm_send_msc167(ng_btsocket_rfcomm_pcb_p pcb);168static int ng_btsocket_rfcomm_send_pn169(ng_btsocket_rfcomm_pcb_p pcb);170static int ng_btsocket_rfcomm_send_credits171(ng_btsocket_rfcomm_pcb_p pcb);172173static int ng_btsocket_rfcomm_pcb_send174(ng_btsocket_rfcomm_pcb_p pcb, int limit);175static void ng_btsocket_rfcomm_pcb_kill176(ng_btsocket_rfcomm_pcb_p pcb, int error);177static ng_btsocket_rfcomm_pcb_p ng_btsocket_rfcomm_pcb_by_dlci178(ng_btsocket_rfcomm_session_p s, int dlci);179static ng_btsocket_rfcomm_pcb_p ng_btsocket_rfcomm_pcb_listener180(bdaddr_p src, int channel);181182static void ng_btsocket_rfcomm_timeout183(ng_btsocket_rfcomm_pcb_p pcb);184static void ng_btsocket_rfcomm_untimeout185(ng_btsocket_rfcomm_pcb_p pcb);186static void ng_btsocket_rfcomm_process_timeout187(void *xpcb);188189static struct mbuf * ng_btsocket_rfcomm_prepare_packet190(struct sockbuf *sb, int length);191192/* Globals */193extern int ifqmaxlen;194static u_int32_t ng_btsocket_rfcomm_debug_level;195static u_int32_t ng_btsocket_rfcomm_timo;196struct task ng_btsocket_rfcomm_task;197static LIST_HEAD(, ng_btsocket_rfcomm_session) ng_btsocket_rfcomm_sessions;198static struct mtx ng_btsocket_rfcomm_sessions_mtx;199static LIST_HEAD(, ng_btsocket_rfcomm_pcb) ng_btsocket_rfcomm_sockets;200static struct mtx ng_btsocket_rfcomm_sockets_mtx;201static struct timeval ng_btsocket_rfcomm_lasttime;202static int ng_btsocket_rfcomm_curpps;203204/* Sysctl tree */205SYSCTL_DECL(_net_bluetooth_rfcomm_sockets);206static SYSCTL_NODE(_net_bluetooth_rfcomm_sockets, OID_AUTO, stream,207CTLFLAG_RW | CTLFLAG_MPSAFE, 0,208"Bluetooth STREAM RFCOMM sockets family");209SYSCTL_UINT(_net_bluetooth_rfcomm_sockets_stream, OID_AUTO, debug_level,210CTLFLAG_RW,211&ng_btsocket_rfcomm_debug_level, NG_BTSOCKET_INFO_LEVEL,212"Bluetooth STREAM RFCOMM sockets debug level");213SYSCTL_UINT(_net_bluetooth_rfcomm_sockets_stream, OID_AUTO, timeout,214CTLFLAG_RW,215&ng_btsocket_rfcomm_timo, 60,216"Bluetooth STREAM RFCOMM sockets timeout");217218/*****************************************************************************219*****************************************************************************220** RFCOMM CRC221*****************************************************************************222*****************************************************************************/223224static u_int8_t ng_btsocket_rfcomm_crc_table[256] = {2250x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,2260x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,2270x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,2280x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,2292300x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,2310x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,2320x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,2330x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,2342350x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,2360x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,2370x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,2380x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,2392400x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,2410x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,2420x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,2430x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,2442450xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,2460xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,2470xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,2480xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,2492500xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,2510xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,2520xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,2530xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,2542550x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,2560x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,2570x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,2580x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,2592600xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,2610xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,2620xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,2630xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf264};265266/* CRC */267static u_int8_t268ng_btsocket_rfcomm_crc(u_int8_t *data, int length)269{270u_int8_t crc = 0xff;271272while (length --)273crc = ng_btsocket_rfcomm_crc_table[crc ^ *data++];274275return (crc);276} /* ng_btsocket_rfcomm_crc */277278/* FCS on 2 bytes */279static u_int8_t280ng_btsocket_rfcomm_fcs2(u_int8_t *data)281{282return (0xff - ng_btsocket_rfcomm_crc(data, 2));283} /* ng_btsocket_rfcomm_fcs2 */284285/* FCS on 3 bytes */286static u_int8_t287ng_btsocket_rfcomm_fcs3(u_int8_t *data)288{289return (0xff - ng_btsocket_rfcomm_crc(data, 3));290} /* ng_btsocket_rfcomm_fcs3 */291292/*293* Check FCS294*295* From Bluetooth spec296*297* "... In 07.10, the frame check sequence (FCS) is calculated on different298* sets of fields for different frame types. These are the fields that the299* FCS are calculated on:300*301* For SABM, DISC, UA, DM frames: on Address, Control and length field.302* For UIH frames: on Address and Control field.303*304* (This is stated here for clarification, and to set the standard for RFCOMM;305* the fields included in FCS calculation have actually changed in version306* 7.0.0 of TS 07.10, but RFCOMM will not change the FCS calculation scheme307* from the one above.) ..."308*/309310static int311ng_btsocket_rfcomm_check_fcs(u_int8_t *data, int type, u_int8_t fcs)312{313if (type != RFCOMM_FRAME_UIH)314return (ng_btsocket_rfcomm_fcs3(data) != fcs);315316return (ng_btsocket_rfcomm_fcs2(data) != fcs);317} /* ng_btsocket_rfcomm_check_fcs */318319/*****************************************************************************320*****************************************************************************321** Socket interface322*****************************************************************************323*****************************************************************************/324325/*326* Initialize everything327*/328329static void330ng_btsocket_rfcomm_init(void *arg __unused)331{332333ng_btsocket_rfcomm_debug_level = NG_BTSOCKET_WARN_LEVEL;334ng_btsocket_rfcomm_timo = 60;335336/* RFCOMM task */337TASK_INIT(&ng_btsocket_rfcomm_task, 0,338ng_btsocket_rfcomm_sessions_task, NULL);339340/* RFCOMM sessions list */341LIST_INIT(&ng_btsocket_rfcomm_sessions);342mtx_init(&ng_btsocket_rfcomm_sessions_mtx,343"btsocks_rfcomm_sessions_mtx", NULL, MTX_DEF);344345/* RFCOMM sockets list */346LIST_INIT(&ng_btsocket_rfcomm_sockets);347mtx_init(&ng_btsocket_rfcomm_sockets_mtx,348"btsocks_rfcomm_sockets_mtx", NULL, MTX_DEF);349} /* ng_btsocket_rfcomm_init */350SYSINIT(ng_btsocket_rfcomm_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD,351ng_btsocket_rfcomm_init, NULL);352353/*354* Abort connection on socket355*/356357void358ng_btsocket_rfcomm_abort(struct socket *so)359{360361so->so_error = ECONNABORTED;362(void)ng_btsocket_rfcomm_disconnect(so);363} /* ng_btsocket_rfcomm_abort */364365void366ng_btsocket_rfcomm_close(struct socket *so)367{368369(void)ng_btsocket_rfcomm_disconnect(so);370} /* ng_btsocket_rfcomm_close */371372/*373* Create and attach new socket374*/375376int377ng_btsocket_rfcomm_attach(struct socket *so, int proto, struct thread *td)378{379ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so);380int error;381382/* Check socket and protocol */383if (so->so_type != SOCK_STREAM)384return (ESOCKTNOSUPPORT);385386#if 0 /* XXX sonewconn() calls pr_attach() with proto == 0 */387if (proto != 0)388if (proto != BLUETOOTH_PROTO_RFCOMM)389return (EPROTONOSUPPORT);390#endif /* XXX */391392if (pcb != NULL)393return (EISCONN);394395/* Reserve send and receive space if it is not reserved yet */396if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) {397error = soreserve(so, NG_BTSOCKET_RFCOMM_SENDSPACE,398NG_BTSOCKET_RFCOMM_RECVSPACE);399if (error != 0)400return (error);401}402403/* Allocate the PCB */404pcb = malloc(sizeof(*pcb),405M_NETGRAPH_BTSOCKET_RFCOMM, M_NOWAIT | M_ZERO);406if (pcb == NULL)407return (ENOMEM);408409/* Link the PCB and the socket */410so->so_pcb = (caddr_t) pcb;411pcb->so = so;412413/* Initialize PCB */414pcb->state = NG_BTSOCKET_RFCOMM_DLC_CLOSED;415pcb->flags = NG_BTSOCKET_RFCOMM_DLC_CFC;416417pcb->lmodem =418pcb->rmodem = (RFCOMM_MODEM_RTC | RFCOMM_MODEM_RTR | RFCOMM_MODEM_DV);419420pcb->mtu = RFCOMM_DEFAULT_MTU;421pcb->tx_cred = 0;422pcb->rx_cred = RFCOMM_DEFAULT_CREDITS;423424mtx_init(&pcb->pcb_mtx, "btsocks_rfcomm_pcb_mtx", NULL, MTX_DEF);425callout_init_mtx(&pcb->timo, &pcb->pcb_mtx, 0);426427/* Add the PCB to the list */428mtx_lock(&ng_btsocket_rfcomm_sockets_mtx);429LIST_INSERT_HEAD(&ng_btsocket_rfcomm_sockets, pcb, next);430mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);431432return (0);433} /* ng_btsocket_rfcomm_attach */434435/*436* Bind socket437*/438439int440ng_btsocket_rfcomm_bind(struct socket *so, struct sockaddr *nam,441struct thread *td)442{443ng_btsocket_rfcomm_pcb_t *pcb = so2rfcomm_pcb(so), *pcb1;444struct sockaddr_rfcomm *sa = (struct sockaddr_rfcomm *) nam;445446if (pcb == NULL)447return (EINVAL);448449/* Verify address */450if (sa == NULL)451return (EINVAL);452if (sa->rfcomm_family != AF_BLUETOOTH)453return (EAFNOSUPPORT);454if (sa->rfcomm_len != sizeof(*sa))455return (EINVAL);456if (sa->rfcomm_channel > 30)457return (EINVAL);458459mtx_lock(&pcb->pcb_mtx);460461if (sa->rfcomm_channel != 0) {462mtx_lock(&ng_btsocket_rfcomm_sockets_mtx);463464LIST_FOREACH(pcb1, &ng_btsocket_rfcomm_sockets, next) {465if (pcb1->channel == sa->rfcomm_channel &&466bcmp(&pcb1->src, &sa->rfcomm_bdaddr,467sizeof(pcb1->src)) == 0) {468mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);469mtx_unlock(&pcb->pcb_mtx);470471return (EADDRINUSE);472}473}474475mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);476}477478bcopy(&sa->rfcomm_bdaddr, &pcb->src, sizeof(pcb->src));479pcb->channel = sa->rfcomm_channel;480481mtx_unlock(&pcb->pcb_mtx);482483return (0);484} /* ng_btsocket_rfcomm_bind */485486/*487* Connect socket488*/489490int491ng_btsocket_rfcomm_connect(struct socket *so, struct sockaddr *nam,492struct thread *td)493{494ng_btsocket_rfcomm_pcb_t *pcb = so2rfcomm_pcb(so);495struct sockaddr_rfcomm *sa = (struct sockaddr_rfcomm *) nam;496ng_btsocket_rfcomm_session_t *s = NULL;497struct socket *l2so = NULL;498int dlci, error = 0;499500if (pcb == NULL)501return (EINVAL);502503/* Verify address */504if (sa == NULL)505return (EINVAL);506if (sa->rfcomm_family != AF_BLUETOOTH)507return (EAFNOSUPPORT);508if (sa->rfcomm_len != sizeof(*sa))509return (EINVAL);510if (sa->rfcomm_channel > 30)511return (EINVAL);512if (sa->rfcomm_channel == 0 ||513bcmp(&sa->rfcomm_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)514return (EDESTADDRREQ);515516/*517* Note that we will not check for errors in socreate() because518* if we failed to create L2CAP socket at this point we still519* might have already open session.520*/521522error = socreate(PF_BLUETOOTH, &l2so, SOCK_SEQPACKET,523BLUETOOTH_PROTO_L2CAP, td->td_ucred, td);524525/*526* Look for session between "pcb->src" and "sa->rfcomm_bdaddr" (dst)527*/528529mtx_lock(&ng_btsocket_rfcomm_sessions_mtx);530531s = ng_btsocket_rfcomm_session_by_addr(&pcb->src, &sa->rfcomm_bdaddr);532if (s == NULL) {533/*534* We need to create new RFCOMM session. Check if we have L2CAP535* socket. If l2so == NULL then error has the error code from536* socreate()537*/538539if (l2so == NULL) {540mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx);541return (error);542}543544error = ng_btsocket_rfcomm_session_create(&s, l2so,545&pcb->src, &sa->rfcomm_bdaddr, td);546if (error != 0) {547mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx);548soclose(l2so);549550return (error);551}552} else if (l2so != NULL)553soclose(l2so); /* we don't need new L2CAP socket */554555/*556* Check if we already have the same DLCI the same session557*/558559mtx_lock(&s->session_mtx);560mtx_lock(&pcb->pcb_mtx);561562dlci = RFCOMM_MKDLCI(!INITIATOR(s), sa->rfcomm_channel);563564if (ng_btsocket_rfcomm_pcb_by_dlci(s, dlci) != NULL) {565mtx_unlock(&pcb->pcb_mtx);566mtx_unlock(&s->session_mtx);567mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx);568569return (EBUSY);570}571572/*573* Check session state and if its not acceptable then refuse connection574*/575576switch (s->state) {577case NG_BTSOCKET_RFCOMM_SESSION_CONNECTING:578case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED:579case NG_BTSOCKET_RFCOMM_SESSION_OPEN:580/*581* Update destination address and channel and attach582* DLC to the session583*/584585bcopy(&sa->rfcomm_bdaddr, &pcb->dst, sizeof(pcb->dst));586pcb->channel = sa->rfcomm_channel;587pcb->dlci = dlci;588589LIST_INSERT_HEAD(&s->dlcs, pcb, session_next);590pcb->session = s;591592ng_btsocket_rfcomm_timeout(pcb);593soisconnecting(pcb->so);594595if (s->state == NG_BTSOCKET_RFCOMM_SESSION_OPEN) {596pcb->mtu = s->mtu;597bcopy(&so2l2cap_pcb(s->l2so)->src, &pcb->src,598sizeof(pcb->src));599600pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONFIGURING;601602error = ng_btsocket_rfcomm_send_pn(pcb);603if (error == 0)604error = ng_btsocket_rfcomm_task_wakeup();605} else606pcb->state = NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT;607break;608609default:610error = ECONNRESET;611break;612}613614mtx_unlock(&pcb->pcb_mtx);615mtx_unlock(&s->session_mtx);616mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx);617618return (error);619} /* ng_btsocket_rfcomm_connect */620621/*622* Process ioctl's calls on socket.623* XXX FIXME this should provide interface to the RFCOMM multiplexor channel624*/625626int627ng_btsocket_rfcomm_control(struct socket *so, u_long cmd, void *data,628struct ifnet *ifp, struct thread *td)629{630return (EINVAL);631} /* ng_btsocket_rfcomm_control */632633/*634* Process getsockopt/setsockopt system calls635*/636637int638ng_btsocket_rfcomm_ctloutput(struct socket *so, struct sockopt *sopt)639{640ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so);641struct ng_btsocket_rfcomm_fc_info fcinfo;642int error = 0;643644if (pcb == NULL)645return (EINVAL);646if (sopt->sopt_level != SOL_RFCOMM)647return (0);648649mtx_lock(&pcb->pcb_mtx);650651switch (sopt->sopt_dir) {652case SOPT_GET:653switch (sopt->sopt_name) {654case SO_RFCOMM_MTU:655error = sooptcopyout(sopt, &pcb->mtu, sizeof(pcb->mtu));656break;657658case SO_RFCOMM_FC_INFO:659fcinfo.lmodem = pcb->lmodem;660fcinfo.rmodem = pcb->rmodem;661fcinfo.tx_cred = pcb->tx_cred;662fcinfo.rx_cred = pcb->rx_cred;663fcinfo.cfc = (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC)?6641 : 0;665fcinfo.reserved = 0;666667error = sooptcopyout(sopt, &fcinfo, sizeof(fcinfo));668break;669670default:671error = ENOPROTOOPT;672break;673}674break;675676case SOPT_SET:677switch (sopt->sopt_name) {678default:679error = ENOPROTOOPT;680break;681}682break;683684default:685error = EINVAL;686break;687}688689mtx_unlock(&pcb->pcb_mtx);690691return (error);692} /* ng_btsocket_rfcomm_ctloutput */693694/*695* Detach and destroy socket696*/697698void699ng_btsocket_rfcomm_detach(struct socket *so)700{701ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so);702703KASSERT(pcb != NULL, ("ng_btsocket_rfcomm_detach: pcb == NULL"));704705mtx_lock(&pcb->pcb_mtx);706707switch (pcb->state) {708case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT:709case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING:710case NG_BTSOCKET_RFCOMM_DLC_CONNECTING:711case NG_BTSOCKET_RFCOMM_DLC_CONNECTED:712/* XXX What to do with pending request? */713if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)714ng_btsocket_rfcomm_untimeout(pcb);715716if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT)717pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_DETACHED;718else719pcb->state = NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING;720721ng_btsocket_rfcomm_task_wakeup();722break;723724case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING:725ng_btsocket_rfcomm_task_wakeup();726break;727}728729while (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CLOSED)730msleep(&pcb->state, &pcb->pcb_mtx, PZERO, "rf_det", 0);731732if (pcb->session != NULL)733panic("%s: pcb->session != NULL\n", __func__);734if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)735panic("%s: timeout on closed DLC, flags=%#x\n",736__func__, pcb->flags);737738mtx_lock(&ng_btsocket_rfcomm_sockets_mtx);739LIST_REMOVE(pcb, next);740mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);741742mtx_unlock(&pcb->pcb_mtx);743744mtx_destroy(&pcb->pcb_mtx);745bzero(pcb, sizeof(*pcb));746free(pcb, M_NETGRAPH_BTSOCKET_RFCOMM);747748soisdisconnected(so);749so->so_pcb = NULL;750} /* ng_btsocket_rfcomm_detach */751752/*753* Disconnect socket754*/755756int757ng_btsocket_rfcomm_disconnect(struct socket *so)758{759ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so);760761if (pcb == NULL)762return (EINVAL);763764mtx_lock(&pcb->pcb_mtx);765766if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING) {767mtx_unlock(&pcb->pcb_mtx);768return (EINPROGRESS);769}770771/* XXX What to do with pending request? */772if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)773ng_btsocket_rfcomm_untimeout(pcb);774775switch (pcb->state) {776case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING: /* XXX can we get here? */777case NG_BTSOCKET_RFCOMM_DLC_CONNECTING: /* XXX can we get here? */778case NG_BTSOCKET_RFCOMM_DLC_CONNECTED:779780/*781* Just change DLC state and enqueue RFCOMM task. It will782* queue and send DISC on the DLC.783*/784785pcb->state = NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING;786soisdisconnecting(so);787788ng_btsocket_rfcomm_task_wakeup();789break;790791case NG_BTSOCKET_RFCOMM_DLC_CLOSED:792case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT:793break;794795default:796panic("%s: Invalid DLC state=%d, flags=%#x\n",797__func__, pcb->state, pcb->flags);798break;799}800801mtx_unlock(&pcb->pcb_mtx);802803return (0);804} /* ng_btsocket_rfcomm_disconnect */805806/*807* Listen on socket. First call to listen() will create listening RFCOMM session808*/809810int811ng_btsocket_rfcomm_listen(struct socket *so, int backlog, struct thread *td)812{813ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so), pcb1;814ng_btsocket_rfcomm_session_p s = NULL;815struct socket *l2so = NULL;816int error, socreate_error, usedchannels;817818if (pcb == NULL)819return (EINVAL);820if (pcb->channel > 30)821return (EADDRNOTAVAIL);822823usedchannels = 0;824825mtx_lock(&pcb->pcb_mtx);826827if (pcb->channel == 0) {828mtx_lock(&ng_btsocket_rfcomm_sockets_mtx);829830LIST_FOREACH(pcb1, &ng_btsocket_rfcomm_sockets, next)831if (pcb1->channel != 0 &&832bcmp(&pcb1->src, &pcb->src, sizeof(pcb->src)) == 0)833usedchannels |= (1 << (pcb1->channel - 1));834835for (pcb->channel = 30; pcb->channel > 0; pcb->channel --)836if (!(usedchannels & (1 << (pcb->channel - 1))))837break;838839if (pcb->channel == 0) {840mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);841mtx_unlock(&pcb->pcb_mtx);842843return (EADDRNOTAVAIL);844}845846mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);847}848849mtx_unlock(&pcb->pcb_mtx);850851/*852* Note that we will not check for errors in socreate() because853* if we failed to create L2CAP socket at this point we still854* might have already open session.855*/856857socreate_error = socreate(PF_BLUETOOTH, &l2so, SOCK_SEQPACKET,858BLUETOOTH_PROTO_L2CAP, td->td_ucred, td);859860/*861* Transition the socket and session into the LISTENING state. Check862* for collisions first, as there can only be one.863*/864mtx_lock(&ng_btsocket_rfcomm_sessions_mtx);865SOCK_LOCK(so);866error = solisten_proto_check(so);867SOCK_UNLOCK(so);868if (error != 0)869goto out;870871LIST_FOREACH(s, &ng_btsocket_rfcomm_sessions, next)872if (s->state == NG_BTSOCKET_RFCOMM_SESSION_LISTENING)873break;874875if (s == NULL) {876/*877* We need to create default RFCOMM session. Check if we have878* L2CAP socket. If l2so == NULL then error has the error code879* from socreate()880*/881if (l2so == NULL) {882solisten_proto_abort(so);883error = socreate_error;884goto out;885}886887/*888* Create default listen RFCOMM session. The default RFCOMM889* session will listen on ANY address.890*891* XXX FIXME Note that currently there is no way to adjust MTU892* for the default session.893*/894error = ng_btsocket_rfcomm_session_create(&s, l2so,895NG_HCI_BDADDR_ANY, NULL, td);896if (error != 0) {897solisten_proto_abort(so);898goto out;899}900l2so = NULL;901}902SOCK_LOCK(so);903solisten_proto(so, backlog);904SOCK_UNLOCK(so);905out:906mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx);907/*908* If we still have an l2so reference here, it's unneeded, so release909* it.910*/911if (l2so != NULL)912soclose(l2so);913return (error);914} /* ng_btsocket_listen */915916/*917* Return peer address for getpeername(2) or for accept(2). For the latter918* case no extra work to do here, socket must be connected and ready.919*/920int921ng_btsocket_rfcomm_peeraddr(struct socket *so, struct sockaddr *sa)922{923ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so);924struct sockaddr_rfcomm *rfcomm = (struct sockaddr_rfcomm *)sa;925926if (pcb == NULL)927return (EINVAL);928929*rfcomm = (struct sockaddr_rfcomm ){930.rfcomm_len = sizeof(struct sockaddr_rfcomm),931.rfcomm_family = AF_BLUETOOTH,932.rfcomm_channel = pcb->channel,933};934bcopy(&pcb->dst, &rfcomm->rfcomm_bdaddr, sizeof(rfcomm->rfcomm_bdaddr));935936return (0);937}938939/*940* Send data to socket941*/942943int944ng_btsocket_rfcomm_send(struct socket *so, int flags, struct mbuf *m,945struct sockaddr *nam, struct mbuf *control, struct thread *td)946{947ng_btsocket_rfcomm_pcb_t *pcb = so2rfcomm_pcb(so);948int error = 0;949950/* Check socket and input */951if (pcb == NULL || m == NULL || control != NULL) {952error = EINVAL;953goto drop;954}955956mtx_lock(&pcb->pcb_mtx);957958/* Make sure DLC is connected */959if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTED) {960mtx_unlock(&pcb->pcb_mtx);961error = ENOTCONN;962goto drop;963}964965/* Put the packet on the socket's send queue and wakeup RFCOMM task */966sbappend(&pcb->so->so_snd, m, flags);967m = NULL;968969if (!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_SENDING)) {970pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_SENDING;971error = ng_btsocket_rfcomm_task_wakeup();972}973974mtx_unlock(&pcb->pcb_mtx);975drop:976NG_FREE_M(m); /* checks for != NULL */977NG_FREE_M(control);978979return (error);980} /* ng_btsocket_rfcomm_send */981982/*983* Get socket address984*/985986int987ng_btsocket_rfcomm_sockaddr(struct socket *so, struct sockaddr *sa)988{989ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so);990struct sockaddr_rfcomm *rfcomm = (struct sockaddr_rfcomm *)sa;991992if (pcb == NULL)993return (EINVAL);994995*rfcomm = (struct sockaddr_rfcomm ){996.rfcomm_len = sizeof(struct sockaddr_rfcomm),997.rfcomm_family = AF_BLUETOOTH,998.rfcomm_channel = pcb->channel,999};1000bcopy(&pcb->src, &rfcomm->rfcomm_bdaddr, sizeof(rfcomm->rfcomm_bdaddr));10011002return (0);1003}10041005/*1006* Upcall function for L2CAP sockets. Enqueue RFCOMM task.1007*/10081009static int1010ng_btsocket_rfcomm_upcall(struct socket *so, void *arg, int waitflag)1011{1012int error;10131014if (so == NULL)1015panic("%s: so == NULL\n", __func__);10161017if ((error = ng_btsocket_rfcomm_task_wakeup()) != 0)1018NG_BTSOCKET_RFCOMM_ALERT(1019"%s: Could not enqueue RFCOMM task, error=%d\n", __func__, error);1020return (SU_OK);1021} /* ng_btsocket_rfcomm_upcall */10221023/*1024* RFCOMM task. Will handle all RFCOMM sessions in one pass.1025* XXX FIXME does not scale very well1026*/10271028static void1029ng_btsocket_rfcomm_sessions_task(void *ctx, int pending)1030{1031ng_btsocket_rfcomm_session_p s = NULL, s_next = NULL;10321033mtx_lock(&ng_btsocket_rfcomm_sessions_mtx);10341035for (s = LIST_FIRST(&ng_btsocket_rfcomm_sessions); s != NULL; ) {1036mtx_lock(&s->session_mtx);1037s_next = LIST_NEXT(s, next);10381039ng_btsocket_rfcomm_session_task(s);10401041if (s->state == NG_BTSOCKET_RFCOMM_SESSION_CLOSED) {1042/* Unlink and clean the session */1043LIST_REMOVE(s, next);10441045NG_BT_MBUFQ_DRAIN(&s->outq);1046if (!LIST_EMPTY(&s->dlcs))1047panic("%s: DLC list is not empty\n", __func__);10481049/* Close L2CAP socket */1050SOCKBUF_LOCK(&s->l2so->so_rcv);1051soupcall_clear(s->l2so, SO_RCV);1052SOCKBUF_UNLOCK(&s->l2so->so_rcv);1053SOCKBUF_LOCK(&s->l2so->so_snd);1054soupcall_clear(s->l2so, SO_SND);1055SOCKBUF_UNLOCK(&s->l2so->so_snd);1056soclose(s->l2so);10571058mtx_unlock(&s->session_mtx);10591060mtx_destroy(&s->session_mtx);1061bzero(s, sizeof(*s));1062free(s, M_NETGRAPH_BTSOCKET_RFCOMM);1063} else1064mtx_unlock(&s->session_mtx);10651066s = s_next;1067}10681069mtx_unlock(&ng_btsocket_rfcomm_sessions_mtx);1070} /* ng_btsocket_rfcomm_sessions_task */10711072/*1073* Process RFCOMM session. Will handle all RFCOMM sockets in one pass.1074*/10751076static void1077ng_btsocket_rfcomm_session_task(ng_btsocket_rfcomm_session_p s)1078{1079mtx_assert(&s->session_mtx, MA_OWNED);10801081if (s->l2so->so_rcv.sb_state & SBS_CANTRCVMORE) {1082NG_BTSOCKET_RFCOMM_INFO(1083"%s: L2CAP connection has been terminated, so=%p, so_state=%#x, so_count=%d, " \1084"state=%d, flags=%#x\n", __func__, s->l2so, s->l2so->so_state,1085s->l2so->so_count, s->state, s->flags);10861087s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;1088ng_btsocket_rfcomm_session_clean(s);1089}10901091/* Now process upcall */1092switch (s->state) {1093/* Try to accept new L2CAP connection(s) */1094case NG_BTSOCKET_RFCOMM_SESSION_LISTENING:1095while (ng_btsocket_rfcomm_session_accept(s) == 0)1096;1097break;10981099/* Process the results of the L2CAP connect */1100case NG_BTSOCKET_RFCOMM_SESSION_CONNECTING:1101ng_btsocket_rfcomm_session_process_pcb(s);11021103if (ng_btsocket_rfcomm_session_connect(s) != 0) {1104s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;1105ng_btsocket_rfcomm_session_clean(s);1106}1107break;11081109/* Try to receive/send more data */1110case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED:1111case NG_BTSOCKET_RFCOMM_SESSION_OPEN:1112case NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING:1113ng_btsocket_rfcomm_session_process_pcb(s);11141115if (ng_btsocket_rfcomm_session_receive(s) != 0) {1116s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;1117ng_btsocket_rfcomm_session_clean(s);1118} else if (ng_btsocket_rfcomm_session_send(s) != 0) {1119s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;1120ng_btsocket_rfcomm_session_clean(s);1121}1122break;11231124case NG_BTSOCKET_RFCOMM_SESSION_CLOSED:1125break;11261127default:1128panic("%s: Invalid session state=%d, flags=%#x\n",1129__func__, s->state, s->flags);1130break;1131}1132} /* ng_btsocket_rfcomm_session_task */11331134/*1135* Process RFCOMM connection indicator. Caller must hold s->session_mtx1136*/11371138static ng_btsocket_rfcomm_pcb_p1139ng_btsocket_rfcomm_connect_ind(ng_btsocket_rfcomm_session_p s, int channel)1140{1141ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb1 = NULL;1142ng_btsocket_l2cap_pcb_p l2pcb = NULL;1143struct socket *so1;11441145mtx_assert(&s->session_mtx, MA_OWNED);11461147/*1148* Try to find RFCOMM socket that listens on given source address1149* and channel. This will return the best possible match.1150*/11511152l2pcb = so2l2cap_pcb(s->l2so);1153pcb = ng_btsocket_rfcomm_pcb_listener(&l2pcb->src, channel);1154if (pcb == NULL)1155return (NULL);11561157/*1158* Check the pending connections queue and if we have space then1159* create new socket and set proper source and destination address,1160* and channel.1161*/11621163mtx_lock(&pcb->pcb_mtx);11641165CURVNET_SET(pcb->so->so_vnet);1166so1 = sonewconn(pcb->so, 0);1167CURVNET_RESTORE();11681169mtx_unlock(&pcb->pcb_mtx);11701171if (so1 == NULL)1172return (NULL);11731174/*1175* If we got here than we have created new socket. So complete the1176* connection. Set source and destination address from the session.1177*/11781179pcb1 = so2rfcomm_pcb(so1);1180if (pcb1 == NULL)1181panic("%s: pcb1 == NULL\n", __func__);11821183mtx_lock(&pcb1->pcb_mtx);11841185bcopy(&l2pcb->src, &pcb1->src, sizeof(pcb1->src));1186bcopy(&l2pcb->dst, &pcb1->dst, sizeof(pcb1->dst));1187pcb1->channel = channel;11881189/* Link new DLC to the session. We already hold s->session_mtx */1190LIST_INSERT_HEAD(&s->dlcs, pcb1, session_next);1191pcb1->session = s;11921193mtx_unlock(&pcb1->pcb_mtx);11941195return (pcb1);1196} /* ng_btsocket_rfcomm_connect_ind */11971198/*1199* Process RFCOMM connect confirmation. Caller must hold s->session_mtx.1200*/12011202static void1203ng_btsocket_rfcomm_connect_cfm(ng_btsocket_rfcomm_session_p s)1204{1205ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb_next = NULL;1206int error;12071208mtx_assert(&s->session_mtx, MA_OWNED);12091210/*1211* Wake up all waiting sockets and send PN request for each of them.1212* Note that timeout already been set in ng_btsocket_rfcomm_connect()1213*1214* Note: cannot use LIST_FOREACH because ng_btsocket_rfcomm_pcb_kill1215* will unlink DLC from the session1216*/12171218for (pcb = LIST_FIRST(&s->dlcs); pcb != NULL; ) {1219mtx_lock(&pcb->pcb_mtx);1220pcb_next = LIST_NEXT(pcb, session_next);12211222if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT) {1223pcb->mtu = s->mtu;1224bcopy(&so2l2cap_pcb(s->l2so)->src, &pcb->src,1225sizeof(pcb->src));12261227error = ng_btsocket_rfcomm_send_pn(pcb);1228if (error == 0)1229pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONFIGURING;1230else1231ng_btsocket_rfcomm_pcb_kill(pcb, error);1232}12331234mtx_unlock(&pcb->pcb_mtx);1235pcb = pcb_next;1236}1237} /* ng_btsocket_rfcomm_connect_cfm */12381239/*****************************************************************************1240*****************************************************************************1241** RFCOMM sessions1242*****************************************************************************1243*****************************************************************************/12441245/*1246* Create new RFCOMM session. That function WILL NOT take ownership over l2so.1247* Caller MUST free l2so if function failed.1248*/12491250static int1251ng_btsocket_rfcomm_session_create(ng_btsocket_rfcomm_session_p *sp,1252struct socket *l2so, bdaddr_p src, bdaddr_p dst,1253struct thread *td)1254{1255ng_btsocket_rfcomm_session_p s = NULL;1256struct sockaddr_l2cap l2sa;1257struct sockopt l2sopt;1258int error;1259u_int16_t mtu;12601261mtx_assert(&ng_btsocket_rfcomm_sessions_mtx, MA_OWNED);12621263/* Allocate the RFCOMM session */1264s = malloc(sizeof(*s),1265M_NETGRAPH_BTSOCKET_RFCOMM, M_NOWAIT | M_ZERO);1266if (s == NULL)1267return (ENOMEM);12681269/* Set defaults */1270s->mtu = RFCOMM_DEFAULT_MTU;1271s->flags = 0;1272s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;1273NG_BT_MBUFQ_INIT(&s->outq, ifqmaxlen);12741275/*1276* XXX Mark session mutex as DUPOK to prevent "duplicated lock of1277* the same type" message. When accepting new L2CAP connection1278* ng_btsocket_rfcomm_session_accept() holds both session mutexes1279* for "old" (accepting) session and "new" (created) session.1280*/12811282mtx_init(&s->session_mtx, "btsocks_rfcomm_session_mtx", NULL,1283MTX_DEF|MTX_DUPOK);12841285LIST_INIT(&s->dlcs);12861287/* Prepare L2CAP socket */1288SOCKBUF_LOCK(&l2so->so_rcv);1289soupcall_set(l2so, SO_RCV, ng_btsocket_rfcomm_upcall, NULL);1290SOCKBUF_UNLOCK(&l2so->so_rcv);1291SOCKBUF_LOCK(&l2so->so_snd);1292soupcall_set(l2so, SO_SND, ng_btsocket_rfcomm_upcall, NULL);1293SOCKBUF_UNLOCK(&l2so->so_snd);1294l2so->so_state |= SS_NBIO;1295s->l2so = l2so;12961297mtx_lock(&s->session_mtx);12981299/*1300* "src" == NULL and "dst" == NULL means just create session.1301* caller must do the rest1302*/13031304if (src == NULL && dst == NULL)1305goto done;13061307/*1308* Set incoming MTU on L2CAP socket. It is RFCOMM session default MTU1309* plus 5 bytes: RFCOMM frame header, one extra byte for length and one1310* extra byte for credits.1311*/13121313mtu = s->mtu + sizeof(struct rfcomm_frame_hdr) + 1 + 1;13141315l2sopt.sopt_dir = SOPT_SET;1316l2sopt.sopt_level = SOL_L2CAP;1317l2sopt.sopt_name = SO_L2CAP_IMTU;1318l2sopt.sopt_val = (void *) &mtu;1319l2sopt.sopt_valsize = sizeof(mtu);1320l2sopt.sopt_td = NULL;13211322error = sosetopt(s->l2so, &l2sopt);1323if (error != 0)1324goto bad;13251326/* Bind socket to "src" address */1327l2sa.l2cap_len = sizeof(l2sa);1328l2sa.l2cap_family = AF_BLUETOOTH;1329l2sa.l2cap_psm = (dst == NULL)? htole16(NG_L2CAP_PSM_RFCOMM) : 0;1330bcopy(src, &l2sa.l2cap_bdaddr, sizeof(l2sa.l2cap_bdaddr));1331l2sa.l2cap_cid = 0;1332l2sa.l2cap_bdaddr_type = BDADDR_BREDR;13331334error = sobind(s->l2so, (struct sockaddr *) &l2sa, td);1335if (error != 0)1336goto bad;13371338/* If "dst" is not NULL then initiate connect(), otherwise listen() */1339if (dst == NULL) {1340s->flags = 0;1341s->state = NG_BTSOCKET_RFCOMM_SESSION_LISTENING;13421343error = solisten(s->l2so, 10, td);1344if (error != 0)1345goto bad;1346} else {1347s->flags = NG_BTSOCKET_RFCOMM_SESSION_INITIATOR;1348s->state = NG_BTSOCKET_RFCOMM_SESSION_CONNECTING;13491350l2sa.l2cap_len = sizeof(l2sa);1351l2sa.l2cap_family = AF_BLUETOOTH;1352l2sa.l2cap_psm = htole16(NG_L2CAP_PSM_RFCOMM);1353bcopy(dst, &l2sa.l2cap_bdaddr, sizeof(l2sa.l2cap_bdaddr));1354l2sa.l2cap_cid = 0;1355l2sa.l2cap_bdaddr_type = BDADDR_BREDR;13561357error = soconnect(s->l2so, (struct sockaddr *) &l2sa, td);1358if (error != 0)1359goto bad;1360}13611362done:1363LIST_INSERT_HEAD(&ng_btsocket_rfcomm_sessions, s, next);1364*sp = s;13651366mtx_unlock(&s->session_mtx);13671368return (0);13691370bad:1371mtx_unlock(&s->session_mtx);13721373/* Return L2CAP socket back to its original state */1374SOCKBUF_LOCK(&l2so->so_rcv);1375soupcall_clear(s->l2so, SO_RCV);1376SOCKBUF_UNLOCK(&l2so->so_rcv);1377SOCKBUF_LOCK(&l2so->so_snd);1378soupcall_clear(s->l2so, SO_SND);1379SOCKBUF_UNLOCK(&l2so->so_snd);1380l2so->so_state &= ~SS_NBIO;13811382mtx_destroy(&s->session_mtx);1383bzero(s, sizeof(*s));1384free(s, M_NETGRAPH_BTSOCKET_RFCOMM);13851386return (error);1387} /* ng_btsocket_rfcomm_session_create */13881389/*1390* Process accept() on RFCOMM session1391* XXX FIXME locking for "l2so"?1392*/13931394static int1395ng_btsocket_rfcomm_session_accept(ng_btsocket_rfcomm_session_p s0)1396{1397struct socket *l2so;1398struct sockaddr_l2cap l2sa = { .l2cap_len = sizeof(l2sa) };1399ng_btsocket_l2cap_pcb_t *l2pcb = NULL;1400ng_btsocket_rfcomm_session_p s = NULL;1401int error;14021403mtx_assert(&ng_btsocket_rfcomm_sessions_mtx, MA_OWNED);1404mtx_assert(&s0->session_mtx, MA_OWNED);14051406SOLISTEN_LOCK(s0->l2so);1407error = solisten_dequeue(s0->l2so, &l2so, 0);1408if (error == EWOULDBLOCK)1409return (error);1410if (error) {1411NG_BTSOCKET_RFCOMM_ERR(1412"%s: Could not accept connection on L2CAP socket, error=%d\n", __func__, error);1413return (error);1414}14151416error = soaccept(l2so, (struct sockaddr *)&l2sa);1417if (error != 0) {1418NG_BTSOCKET_RFCOMM_ERR(1419"%s: soaccept() on L2CAP socket failed, error=%d\n", __func__, error);1420soclose(l2so);14211422return (error);1423}14241425/*1426* Check if there is already active RFCOMM session between two devices.1427* If so then close L2CAP connection. We only support one RFCOMM session1428* between each pair of devices. Note that here we assume session in any1429* state. The session even could be in the middle of disconnecting.1430*/14311432l2pcb = so2l2cap_pcb(l2so);1433s = ng_btsocket_rfcomm_session_by_addr(&l2pcb->src, &l2pcb->dst);1434if (s == NULL) {1435/* Create a new RFCOMM session */1436error = ng_btsocket_rfcomm_session_create(&s, l2so, NULL, NULL,1437curthread /* XXX */);1438if (error == 0) {1439mtx_lock(&s->session_mtx);14401441s->flags = 0;1442s->state = NG_BTSOCKET_RFCOMM_SESSION_CONNECTED;14431444/*1445* Adjust MTU on incoming connection. Reserve 5 bytes:1446* RFCOMM frame header, one extra byte for length and1447* one extra byte for credits.1448*/14491450s->mtu = min(l2pcb->imtu, l2pcb->omtu) -1451sizeof(struct rfcomm_frame_hdr) - 1 - 1;14521453mtx_unlock(&s->session_mtx);1454} else {1455NG_BTSOCKET_RFCOMM_ALERT(1456"%s: Failed to create new RFCOMM session, error=%d\n", __func__, error);14571458soclose(l2so);1459}1460} else {1461NG_BTSOCKET_RFCOMM_WARN(1462"%s: Rejecting duplicating RFCOMM session between src=%x:%x:%x:%x:%x:%x and " \1463"dst=%x:%x:%x:%x:%x:%x, state=%d, flags=%#x\n", __func__,1464l2pcb->src.b[5], l2pcb->src.b[4], l2pcb->src.b[3],1465l2pcb->src.b[2], l2pcb->src.b[1], l2pcb->src.b[0],1466l2pcb->dst.b[5], l2pcb->dst.b[4], l2pcb->dst.b[3],1467l2pcb->dst.b[2], l2pcb->dst.b[1], l2pcb->dst.b[0],1468s->state, s->flags);14691470error = EBUSY;1471soclose(l2so);1472}14731474return (error);1475} /* ng_btsocket_rfcomm_session_accept */14761477/*1478* Process connect() on RFCOMM session1479* XXX FIXME locking for "l2so"?1480*/14811482static int1483ng_btsocket_rfcomm_session_connect(ng_btsocket_rfcomm_session_p s)1484{1485ng_btsocket_l2cap_pcb_p l2pcb = so2l2cap_pcb(s->l2so);1486int error;14871488mtx_assert(&s->session_mtx, MA_OWNED);14891490/* First check if connection has failed */1491if ((error = s->l2so->so_error) != 0) {1492s->l2so->so_error = 0;14931494NG_BTSOCKET_RFCOMM_ERR(1495"%s: Could not connect RFCOMM session, error=%d, state=%d, flags=%#x\n",1496__func__, error, s->state, s->flags);14971498return (error);1499}15001501/* Is connection still in progress? */1502if (s->l2so->so_state & SS_ISCONNECTING)1503return (0);15041505/*1506* If we got here then we are connected. Send SABM on DLCI 0 to1507* open multiplexor channel.1508*/15091510if (error == 0) {1511s->state = NG_BTSOCKET_RFCOMM_SESSION_CONNECTED;15121513/*1514* Adjust MTU on outgoing connection. Reserve 5 bytes: RFCOMM1515* frame header, one extra byte for length and one extra byte1516* for credits.1517*/15181519s->mtu = min(l2pcb->imtu, l2pcb->omtu) -1520sizeof(struct rfcomm_frame_hdr) - 1 - 1;15211522error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_SABM,0);1523if (error == 0)1524error = ng_btsocket_rfcomm_task_wakeup();1525}15261527return (error);1528}/* ng_btsocket_rfcomm_session_connect */15291530/*1531* Receive data on RFCOMM session1532* XXX FIXME locking for "l2so"?1533*/15341535static int1536ng_btsocket_rfcomm_session_receive(ng_btsocket_rfcomm_session_p s)1537{1538struct mbuf *m = NULL;1539struct uio uio;1540int more, flags, error;15411542mtx_assert(&s->session_mtx, MA_OWNED);15431544/* Can we read from the L2CAP socket? */1545if (!soreadable(s->l2so))1546return (0);15471548/* First check for error on L2CAP socket */1549if ((error = s->l2so->so_error) != 0) {1550s->l2so->so_error = 0;15511552NG_BTSOCKET_RFCOMM_ERR(1553"%s: Could not receive data from L2CAP socket, error=%d, state=%d, flags=%#x\n",1554__func__, error, s->state, s->flags);15551556return (error);1557}15581559/*1560* Read all packets from the L2CAP socket.1561* XXX FIXME/VERIFY is that correct? For now use m->m_nextpkt as1562* indication that there is more packets on the socket's buffer.1563* Also what should we use in uio.uio_resid?1564* May be s->mtu + sizeof(struct rfcomm_frame_hdr) + 1 + 1?1565*/15661567for (more = 1; more; ) {1568/* Try to get next packet from socket */1569bzero(&uio, sizeof(uio));1570/* uio.uio_td = NULL; */1571uio.uio_resid = 1000000000;1572flags = MSG_DONTWAIT;15731574m = NULL;1575error = soreceive(s->l2so, NULL, &uio, &m,1576(struct mbuf **) NULL, &flags);1577if (error != 0) {1578if (error == EWOULDBLOCK)1579return (0); /* XXX can happen? */15801581NG_BTSOCKET_RFCOMM_ERR(1582"%s: Could not receive data from L2CAP socket, error=%d\n", __func__, error);15831584return (error);1585}15861587more = (m->m_nextpkt != NULL);1588m->m_nextpkt = NULL;15891590ng_btsocket_rfcomm_receive_frame(s, m);1591}15921593return (0);1594} /* ng_btsocket_rfcomm_session_receive */15951596/*1597* Send data on RFCOMM session1598* XXX FIXME locking for "l2so"?1599*/16001601static int1602ng_btsocket_rfcomm_session_send(ng_btsocket_rfcomm_session_p s)1603{1604struct mbuf *m = NULL;1605int error;16061607mtx_assert(&s->session_mtx, MA_OWNED);16081609/* Send as much as we can from the session queue */1610while (sowriteable(s->l2so)) {1611/* Check if socket still OK */1612if ((error = s->l2so->so_error) != 0) {1613s->l2so->so_error = 0;16141615NG_BTSOCKET_RFCOMM_ERR(1616"%s: Detected error=%d on L2CAP socket, state=%d, flags=%#x\n",1617__func__, error, s->state, s->flags);16181619return (error);1620}16211622NG_BT_MBUFQ_DEQUEUE(&s->outq, m);1623if (m == NULL)1624return (0); /* we are done */16251626/* Call send function on the L2CAP socket */1627error = s->l2so->so_proto->pr_send(s->l2so, 0, m, NULL, NULL,1628curthread /* XXX */);1629if (error != 0) {1630NG_BTSOCKET_RFCOMM_ERR(1631"%s: Could not send data to L2CAP socket, error=%d\n", __func__, error);16321633return (error);1634}1635}16361637return (0);1638} /* ng_btsocket_rfcomm_session_send */16391640/*1641* Close and disconnect all DLCs for the given session. Caller must hold1642* s->sesson_mtx. Will wakeup session.1643*/16441645static void1646ng_btsocket_rfcomm_session_clean(ng_btsocket_rfcomm_session_p s)1647{1648ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb_next = NULL;1649int error;16501651mtx_assert(&s->session_mtx, MA_OWNED);16521653/*1654* Note: cannot use LIST_FOREACH because ng_btsocket_rfcomm_pcb_kill1655* will unlink DLC from the session1656*/16571658for (pcb = LIST_FIRST(&s->dlcs); pcb != NULL; ) {1659mtx_lock(&pcb->pcb_mtx);1660pcb_next = LIST_NEXT(pcb, session_next);16611662NG_BTSOCKET_RFCOMM_INFO(1663"%s: Disconnecting dlci=%d, state=%d, flags=%#x\n",1664__func__, pcb->dlci, pcb->state, pcb->flags);16651666if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONNECTED)1667error = ECONNRESET;1668else1669error = ECONNREFUSED;16701671ng_btsocket_rfcomm_pcb_kill(pcb, error);16721673mtx_unlock(&pcb->pcb_mtx);1674pcb = pcb_next;1675}1676} /* ng_btsocket_rfcomm_session_clean */16771678/*1679* Process all DLCs on the session. Caller MUST hold s->session_mtx.1680*/16811682static void1683ng_btsocket_rfcomm_session_process_pcb(ng_btsocket_rfcomm_session_p s)1684{1685ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb_next = NULL;1686int error;16871688mtx_assert(&s->session_mtx, MA_OWNED);16891690/*1691* Note: cannot use LIST_FOREACH because ng_btsocket_rfcomm_pcb_kill1692* will unlink DLC from the session1693*/16941695for (pcb = LIST_FIRST(&s->dlcs); pcb != NULL; ) {1696mtx_lock(&pcb->pcb_mtx);1697pcb_next = LIST_NEXT(pcb, session_next);16981699switch (pcb->state) {1700/*1701* If DLC in W4_CONNECT state then we should check for both1702* timeout and detach.1703*/17041705case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT:1706if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_DETACHED)1707ng_btsocket_rfcomm_pcb_kill(pcb, 0);1708else if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT)1709ng_btsocket_rfcomm_pcb_kill(pcb, ETIMEDOUT);1710break;17111712/*1713* If DLC in CONFIGURING or CONNECTING state then we only1714* should check for timeout. If detach() was called then1715* DLC will be moved into DISCONNECTING state.1716*/17171718case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING:1719case NG_BTSOCKET_RFCOMM_DLC_CONNECTING:1720if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT)1721ng_btsocket_rfcomm_pcb_kill(pcb, ETIMEDOUT);1722break;17231724/*1725* If DLC in CONNECTED state then we need to send data (if any)1726* from the socket's send queue. Note that we will send data1727* from either all sockets or none. This may overload session's1728* outgoing queue (but we do not check for that).1729*1730* XXX FIXME need scheduler for RFCOMM sockets1731*/17321733case NG_BTSOCKET_RFCOMM_DLC_CONNECTED:1734error = ng_btsocket_rfcomm_pcb_send(pcb, ALOT);1735if (error != 0)1736ng_btsocket_rfcomm_pcb_kill(pcb, error);1737break;17381739/*1740* If DLC in DISCONNECTING state then we must send DISC frame.1741* Note that if DLC has timeout set then we do not need to1742* resend DISC frame.1743*1744* XXX FIXME need to drain all data from the socket's queue1745* if LINGER option was set1746*/17471748case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING:1749if (!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)) {1750error = ng_btsocket_rfcomm_send_command(1751pcb->session, RFCOMM_FRAME_DISC,1752pcb->dlci);1753if (error == 0)1754ng_btsocket_rfcomm_timeout(pcb);1755else1756ng_btsocket_rfcomm_pcb_kill(pcb, error);1757} else if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT)1758ng_btsocket_rfcomm_pcb_kill(pcb, ETIMEDOUT);1759break;17601761/* case NG_BTSOCKET_RFCOMM_DLC_CLOSED: */1762default:1763panic("%s: Invalid DLC state=%d, flags=%#x\n",1764__func__, pcb->state, pcb->flags);1765break;1766}17671768mtx_unlock(&pcb->pcb_mtx);1769pcb = pcb_next;1770}1771} /* ng_btsocket_rfcomm_session_process_pcb */17721773/*1774* Find RFCOMM session between "src" and "dst".1775* Caller MUST hold ng_btsocket_rfcomm_sessions_mtx.1776*/17771778static ng_btsocket_rfcomm_session_p1779ng_btsocket_rfcomm_session_by_addr(bdaddr_p src, bdaddr_p dst)1780{1781ng_btsocket_rfcomm_session_p s = NULL;1782ng_btsocket_l2cap_pcb_p l2pcb = NULL;1783int any_src;17841785mtx_assert(&ng_btsocket_rfcomm_sessions_mtx, MA_OWNED);17861787any_src = (bcmp(src, NG_HCI_BDADDR_ANY, sizeof(*src)) == 0);17881789LIST_FOREACH(s, &ng_btsocket_rfcomm_sessions, next) {1790l2pcb = so2l2cap_pcb(s->l2so);17911792if ((any_src || bcmp(&l2pcb->src, src, sizeof(*src)) == 0) &&1793bcmp(&l2pcb->dst, dst, sizeof(*dst)) == 0)1794break;1795}17961797return (s);1798} /* ng_btsocket_rfcomm_session_by_addr */17991800/*****************************************************************************1801*****************************************************************************1802** RFCOMM1803*****************************************************************************1804*****************************************************************************/18051806/*1807* Process incoming RFCOMM frame. Caller must hold s->session_mtx.1808* XXX FIXME check frame length1809*/18101811static int1812ng_btsocket_rfcomm_receive_frame(ng_btsocket_rfcomm_session_p s,1813struct mbuf *m0)1814{1815struct rfcomm_frame_hdr *hdr = NULL;1816struct mbuf *m = NULL;1817u_int16_t length;1818u_int8_t dlci, type;1819int error = 0;18201821mtx_assert(&s->session_mtx, MA_OWNED);18221823/* Pullup as much as we can into first mbuf (for direct access) */1824length = min(m0->m_pkthdr.len, MHLEN);1825if (m0->m_len < length) {1826if ((m0 = m_pullup(m0, length)) == NULL) {1827NG_BTSOCKET_RFCOMM_ALERT(1828"%s: m_pullup(%d) failed\n", __func__, length);18291830return (ENOBUFS);1831}1832}18331834hdr = mtod(m0, struct rfcomm_frame_hdr *);1835dlci = RFCOMM_DLCI(hdr->address);1836type = RFCOMM_TYPE(hdr->control);18371838/* Test EA bit in length. If not set then we have 2 bytes of length */1839if (!RFCOMM_EA(hdr->length)) {1840bcopy(&hdr->length, &length, sizeof(length));1841length = le16toh(length) >> 1;1842m_adj(m0, sizeof(*hdr) + 1);1843} else {1844length = hdr->length >> 1;1845m_adj(m0, sizeof(*hdr));1846}18471848NG_BTSOCKET_RFCOMM_INFO(1849"%s: Got frame type=%#x, dlci=%d, length=%d, cr=%d, pf=%d, len=%d\n",1850__func__, type, dlci, length, RFCOMM_CR(hdr->address),1851RFCOMM_PF(hdr->control), m0->m_pkthdr.len);18521853/*1854* Get FCS (the last byte in the frame)1855* XXX this will not work if mbuf chain ends with empty mbuf.1856* XXX let's hope it never happens :)1857*/18581859for (m = m0; m->m_next != NULL; m = m->m_next)1860;1861if (m->m_len <= 0)1862panic("%s: Empty mbuf at the end of the chain, len=%d\n",1863__func__, m->m_len);18641865/*1866* Check FCS. We only need to calculate FCS on first 2 or 3 bytes1867* and already m_pullup'ed mbuf chain, so it should be safe.1868*/18691870if (ng_btsocket_rfcomm_check_fcs((u_int8_t *) hdr, type, m->m_data[m->m_len - 1])) {1871NG_BTSOCKET_RFCOMM_ERR(1872"%s: Invalid RFCOMM packet. Bad checksum\n", __func__);1873NG_FREE_M(m0);18741875return (EINVAL);1876}18771878m_adj(m0, -1); /* Trim FCS byte */18791880/*1881* Process RFCOMM frame.1882*1883* From TS 07.10 spec1884*1885* "... In the case where a SABM or DISC command with the P bit set1886* to 0 is received then the received frame shall be discarded..."1887*1888* "... If a unsolicited DM response is received then the frame shall1889* be processed irrespective of the P/F setting... "1890*1891* "... The station may transmit response frames with the F bit set1892* to 0 at any opportunity on an asynchronous basis. However, in the1893* case where a UA response is received with the F bit set to 0 then1894* the received frame shall be discarded..."1895*1896* From Bluetooth spec1897*1898* "... When credit based flow control is being used, the meaning of1899* the P/F bit in the control field of the RFCOMM header is redefined1900* for UIH frames..."1901*/19021903switch (type) {1904case RFCOMM_FRAME_SABM:1905if (RFCOMM_PF(hdr->control))1906error = ng_btsocket_rfcomm_receive_sabm(s, dlci);1907break;19081909case RFCOMM_FRAME_DISC:1910if (RFCOMM_PF(hdr->control))1911error = ng_btsocket_rfcomm_receive_disc(s, dlci);1912break;19131914case RFCOMM_FRAME_UA:1915if (RFCOMM_PF(hdr->control))1916error = ng_btsocket_rfcomm_receive_ua(s, dlci);1917break;19181919case RFCOMM_FRAME_DM:1920error = ng_btsocket_rfcomm_receive_dm(s, dlci);1921break;19221923case RFCOMM_FRAME_UIH:1924if (dlci == 0)1925error = ng_btsocket_rfcomm_receive_mcc(s, m0);1926else1927error = ng_btsocket_rfcomm_receive_uih(s, dlci,1928RFCOMM_PF(hdr->control), m0);19291930return (error);1931/* NOT REACHED */19321933default:1934NG_BTSOCKET_RFCOMM_ERR(1935"%s: Invalid RFCOMM packet. Unknown type=%#x\n", __func__, type);1936error = EINVAL;1937break;1938}19391940NG_FREE_M(m0);19411942return (error);1943} /* ng_btsocket_rfcomm_receive_frame */19441945/*1946* Process RFCOMM SABM frame1947*/19481949static int1950ng_btsocket_rfcomm_receive_sabm(ng_btsocket_rfcomm_session_p s, int dlci)1951{1952ng_btsocket_rfcomm_pcb_p pcb = NULL;1953int error = 0;19541955mtx_assert(&s->session_mtx, MA_OWNED);19561957NG_BTSOCKET_RFCOMM_INFO(1958"%s: Got SABM, session state=%d, flags=%#x, mtu=%d, dlci=%d\n",1959__func__, s->state, s->flags, s->mtu, dlci);19601961/* DLCI == 0 means open multiplexor channel */1962if (dlci == 0) {1963switch (s->state) {1964case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED:1965case NG_BTSOCKET_RFCOMM_SESSION_OPEN:1966error = ng_btsocket_rfcomm_send_command(s,1967RFCOMM_FRAME_UA, dlci);1968if (error == 0) {1969s->state = NG_BTSOCKET_RFCOMM_SESSION_OPEN;1970ng_btsocket_rfcomm_connect_cfm(s);1971} else {1972s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;1973ng_btsocket_rfcomm_session_clean(s);1974}1975break;19761977default:1978NG_BTSOCKET_RFCOMM_WARN(1979"%s: Got SABM for session in invalid state state=%d, flags=%#x\n",1980__func__, s->state, s->flags);1981error = EINVAL;1982break;1983}19841985return (error);1986}19871988/* Make sure multiplexor channel is open */1989if (s->state != NG_BTSOCKET_RFCOMM_SESSION_OPEN) {1990NG_BTSOCKET_RFCOMM_ERR(1991"%s: Got SABM for dlci=%d with multiplexor channel closed, state=%d, " \1992"flags=%#x\n", __func__, dlci, s->state, s->flags);19931994return (EINVAL);1995}19961997/*1998* Check if we have this DLCI. This might happen when remote1999* peer uses PN command before actual open (SABM) happens.2000*/20012002pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci);2003if (pcb != NULL) {2004mtx_lock(&pcb->pcb_mtx);20052006if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTING) {2007NG_BTSOCKET_RFCOMM_ERR(2008"%s: Got SABM for dlci=%d in invalid state=%d, flags=%#x\n",2009__func__, dlci, pcb->state, pcb->flags);2010mtx_unlock(&pcb->pcb_mtx);20112012return (ENOENT);2013}20142015ng_btsocket_rfcomm_untimeout(pcb);20162017error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_UA,dlci);2018if (error == 0)2019error = ng_btsocket_rfcomm_send_msc(pcb);20202021if (error == 0) {2022pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTED;2023soisconnected(pcb->so);2024} else2025ng_btsocket_rfcomm_pcb_kill(pcb, error);20262027mtx_unlock(&pcb->pcb_mtx);20282029return (error);2030}20312032/*2033* We do not have requested DLCI, so it must be an incoming connection2034* with default parameters. Try to accept it.2035*/20362037pcb = ng_btsocket_rfcomm_connect_ind(s, RFCOMM_SRVCHANNEL(dlci));2038if (pcb != NULL) {2039mtx_lock(&pcb->pcb_mtx);20402041pcb->dlci = dlci;20422043error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_UA,dlci);2044if (error == 0)2045error = ng_btsocket_rfcomm_send_msc(pcb);20462047if (error == 0) {2048pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTED;2049soisconnected(pcb->so);2050} else2051ng_btsocket_rfcomm_pcb_kill(pcb, error);20522053mtx_unlock(&pcb->pcb_mtx);2054} else2055/* Nobody is listen()ing on the requested DLCI */2056error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_DM,dlci);20572058return (error);2059} /* ng_btsocket_rfcomm_receive_sabm */20602061/*2062* Process RFCOMM DISC frame2063*/20642065static int2066ng_btsocket_rfcomm_receive_disc(ng_btsocket_rfcomm_session_p s, int dlci)2067{2068ng_btsocket_rfcomm_pcb_p pcb = NULL;2069int error = 0;20702071mtx_assert(&s->session_mtx, MA_OWNED);20722073NG_BTSOCKET_RFCOMM_INFO(2074"%s: Got DISC, session state=%d, flags=%#x, mtu=%d, dlci=%d\n",2075__func__, s->state, s->flags, s->mtu, dlci);20762077/* DLCI == 0 means close multiplexor channel */2078if (dlci == 0) {2079/* XXX FIXME assume that remote side will close the socket */2080error = ng_btsocket_rfcomm_send_command(s, RFCOMM_FRAME_UA, 0);2081if (error == 0) {2082if (s->state == NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING)2083s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; /* XXX */2084else2085s->state = NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING;2086} else2087s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED; /* XXX */20882089ng_btsocket_rfcomm_session_clean(s);2090} else {2091pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci);2092if (pcb != NULL) {2093int err;20942095mtx_lock(&pcb->pcb_mtx);20962097NG_BTSOCKET_RFCOMM_INFO(2098"%s: Got DISC for dlci=%d, state=%d, flags=%#x\n",2099__func__, dlci, pcb->state, pcb->flags);21002101error = ng_btsocket_rfcomm_send_command(s,2102RFCOMM_FRAME_UA, dlci);21032104if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONNECTED)2105err = 0;2106else2107err = ECONNREFUSED;21082109ng_btsocket_rfcomm_pcb_kill(pcb, err);21102111mtx_unlock(&pcb->pcb_mtx);2112} else {2113NG_BTSOCKET_RFCOMM_WARN(2114"%s: Got DISC for non-existing dlci=%d\n", __func__, dlci);21152116error = ng_btsocket_rfcomm_send_command(s,2117RFCOMM_FRAME_DM, dlci);2118}2119}21202121return (error);2122} /* ng_btsocket_rfcomm_receive_disc */21232124/*2125* Process RFCOMM UA frame2126*/21272128static int2129ng_btsocket_rfcomm_receive_ua(ng_btsocket_rfcomm_session_p s, int dlci)2130{2131ng_btsocket_rfcomm_pcb_p pcb = NULL;2132int error = 0;21332134mtx_assert(&s->session_mtx, MA_OWNED);21352136NG_BTSOCKET_RFCOMM_INFO(2137"%s: Got UA, session state=%d, flags=%#x, mtu=%d, dlci=%d\n",2138__func__, s->state, s->flags, s->mtu, dlci);21392140/* dlci == 0 means multiplexor channel */2141if (dlci == 0) {2142switch (s->state) {2143case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED:2144s->state = NG_BTSOCKET_RFCOMM_SESSION_OPEN;2145ng_btsocket_rfcomm_connect_cfm(s);2146break;21472148case NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING:2149s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;2150ng_btsocket_rfcomm_session_clean(s);2151break;21522153default:2154NG_BTSOCKET_RFCOMM_WARN(2155"%s: Got UA for session in invalid state=%d(%d), flags=%#x, mtu=%d\n",2156__func__, s->state, INITIATOR(s), s->flags,2157s->mtu);2158error = ENOENT;2159break;2160}21612162return (error);2163}21642165/* Check if we have this DLCI */2166pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci);2167if (pcb != NULL) {2168mtx_lock(&pcb->pcb_mtx);21692170NG_BTSOCKET_RFCOMM_INFO(2171"%s: Got UA for dlci=%d, state=%d, flags=%#x\n",2172__func__, dlci, pcb->state, pcb->flags);21732174switch (pcb->state) {2175case NG_BTSOCKET_RFCOMM_DLC_CONNECTING:2176ng_btsocket_rfcomm_untimeout(pcb);21772178error = ng_btsocket_rfcomm_send_msc(pcb);2179if (error == 0) {2180pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTED;2181soisconnected(pcb->so);2182}2183break;21842185case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING:2186ng_btsocket_rfcomm_pcb_kill(pcb, 0);2187break;21882189default:2190NG_BTSOCKET_RFCOMM_WARN(2191"%s: Got UA for dlci=%d in invalid state=%d, flags=%#x\n",2192__func__, dlci, pcb->state, pcb->flags);2193error = ENOENT;2194break;2195}21962197mtx_unlock(&pcb->pcb_mtx);2198} else {2199NG_BTSOCKET_RFCOMM_WARN(2200"%s: Got UA for non-existing dlci=%d\n", __func__, dlci);22012202error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_DM,dlci);2203}22042205return (error);2206} /* ng_btsocket_rfcomm_receive_ua */22072208/*2209* Process RFCOMM DM frame2210*/22112212static int2213ng_btsocket_rfcomm_receive_dm(ng_btsocket_rfcomm_session_p s, int dlci)2214{2215ng_btsocket_rfcomm_pcb_p pcb = NULL;2216int error;22172218mtx_assert(&s->session_mtx, MA_OWNED);22192220NG_BTSOCKET_RFCOMM_INFO(2221"%s: Got DM, session state=%d, flags=%#x, mtu=%d, dlci=%d\n",2222__func__, s->state, s->flags, s->mtu, dlci);22232224/* DLCI == 0 means multiplexor channel */2225if (dlci == 0) {2226/* Disconnect all dlc's on the session */2227s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;2228ng_btsocket_rfcomm_session_clean(s);2229} else {2230pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci);2231if (pcb != NULL) {2232mtx_lock(&pcb->pcb_mtx);22332234NG_BTSOCKET_RFCOMM_INFO(2235"%s: Got DM for dlci=%d, state=%d, flags=%#x\n",2236__func__, dlci, pcb->state, pcb->flags);22372238if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONNECTED)2239error = ECONNRESET;2240else2241error = ECONNREFUSED;22422243ng_btsocket_rfcomm_pcb_kill(pcb, error);22442245mtx_unlock(&pcb->pcb_mtx);2246} else2247NG_BTSOCKET_RFCOMM_WARN(2248"%s: Got DM for non-existing dlci=%d\n", __func__, dlci);2249}22502251return (0);2252} /* ng_btsocket_rfcomm_receive_dm */22532254/*2255* Process RFCOMM UIH frame (data)2256*/22572258static int2259ng_btsocket_rfcomm_receive_uih(ng_btsocket_rfcomm_session_p s, int dlci,2260int pf, struct mbuf *m0)2261{2262ng_btsocket_rfcomm_pcb_p pcb = NULL;2263int error = 0;22642265mtx_assert(&s->session_mtx, MA_OWNED);22662267NG_BTSOCKET_RFCOMM_INFO(2268"%s: Got UIH, session state=%d, flags=%#x, mtu=%d, dlci=%d, pf=%d, len=%d\n",2269__func__, s->state, s->flags, s->mtu, dlci, pf,2270m0->m_pkthdr.len);22712272/* XXX should we do it here? Check for session flow control */2273if (s->flags & NG_BTSOCKET_RFCOMM_SESSION_LFC) {2274NG_BTSOCKET_RFCOMM_WARN(2275"%s: Got UIH with session flow control asserted, state=%d, flags=%#x\n",2276__func__, s->state, s->flags);2277goto drop;2278}22792280/* Check if we have this dlci */2281pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, dlci);2282if (pcb == NULL) {2283NG_BTSOCKET_RFCOMM_WARN(2284"%s: Got UIH for non-existing dlci=%d\n", __func__, dlci);2285error = ng_btsocket_rfcomm_send_command(s,RFCOMM_FRAME_DM,dlci);2286goto drop;2287}22882289mtx_lock(&pcb->pcb_mtx);22902291/* Check dlci state */2292if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTED) {2293NG_BTSOCKET_RFCOMM_WARN(2294"%s: Got UIH for dlci=%d in invalid state=%d, flags=%#x\n",2295__func__, dlci, pcb->state, pcb->flags);2296error = EINVAL;2297goto drop1;2298}22992300/* Check dlci flow control */2301if (((pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) && pcb->rx_cred <= 0) ||2302(pcb->lmodem & RFCOMM_MODEM_FC)) {2303NG_BTSOCKET_RFCOMM_ERR(2304"%s: Got UIH for dlci=%d with asserted flow control, state=%d, " \2305"flags=%#x, rx_cred=%d, lmodem=%#x\n",2306__func__, dlci, pcb->state, pcb->flags,2307pcb->rx_cred, pcb->lmodem);2308goto drop1;2309}23102311/* Did we get any credits? */2312if ((pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) && pf) {2313NG_BTSOCKET_RFCOMM_INFO(2314"%s: Got %d more credits for dlci=%d, state=%d, flags=%#x, " \2315"rx_cred=%d, tx_cred=%d\n",2316__func__, *mtod(m0, u_int8_t *), dlci, pcb->state,2317pcb->flags, pcb->rx_cred, pcb->tx_cred);23182319pcb->tx_cred += *mtod(m0, u_int8_t *);2320m_adj(m0, 1);23212322/* Send more from the DLC. XXX check for errors? */2323ng_btsocket_rfcomm_pcb_send(pcb, ALOT);2324}23252326/* OK the of the rest of the mbuf is the data */2327if (m0->m_pkthdr.len > 0) {2328/* If we are using credit flow control decrease rx_cred here */2329if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) {2330/* Give remote peer more credits (if needed) */2331if (-- pcb->rx_cred <= RFCOMM_MAX_CREDITS / 2)2332ng_btsocket_rfcomm_send_credits(pcb);2333else2334NG_BTSOCKET_RFCOMM_INFO(2335"%s: Remote side still has credits, dlci=%d, state=%d, flags=%#x, " \2336"rx_cred=%d, tx_cred=%d\n", __func__, dlci, pcb->state, pcb->flags,2337pcb->rx_cred, pcb->tx_cred);2338}23392340/* Check packet against mtu on dlci */2341if (m0->m_pkthdr.len > pcb->mtu) {2342NG_BTSOCKET_RFCOMM_ERR(2343"%s: Got oversized UIH for dlci=%d, state=%d, flags=%#x, mtu=%d, len=%d\n",2344__func__, dlci, pcb->state, pcb->flags,2345pcb->mtu, m0->m_pkthdr.len);23462347error = EMSGSIZE;2348} else if (m0->m_pkthdr.len > sbspace(&pcb->so->so_rcv)) {2349/*2350* This is really bad. Receive queue on socket does2351* not have enough space for the packet. We do not2352* have any other choice but drop the packet.2353*/23542355NG_BTSOCKET_RFCOMM_ERR(2356"%s: Not enough space in socket receive queue. Dropping UIH for dlci=%d, " \2357"state=%d, flags=%#x, len=%d, space=%ld\n",2358__func__, dlci, pcb->state, pcb->flags,2359m0->m_pkthdr.len, sbspace(&pcb->so->so_rcv));23602361error = ENOBUFS;2362} else {2363/* Append packet to the socket receive queue */2364sbappend(&pcb->so->so_rcv, m0, 0);2365m0 = NULL;23662367sorwakeup(pcb->so);2368}2369}2370drop1:2371mtx_unlock(&pcb->pcb_mtx);2372drop:2373NG_FREE_M(m0); /* checks for != NULL */23742375return (error);2376} /* ng_btsocket_rfcomm_receive_uih */23772378/*2379* Process RFCOMM MCC command (Multiplexor)2380*2381* From TS 07.10 spec2382*2383* "5.4.3.1 Information Data2384*2385* ...The frames (UIH) sent by the initiating station have the C/R bit set2386* to 1 and those sent by the responding station have the C/R bit set to 0..."2387*2388* "5.4.6.2 Operating procedures2389*2390* Messages always exist in pairs; a command message and a corresponding2391* response message. If the C/R bit is set to 1 the message is a command,2392* if it is set to 0 the message is a response...2393*2394* ...2395*2396* NOTE: Notice that when UIH frames are used to convey information on DLCI 02397* there are at least two different fields that contain a C/R bit, and the2398* bits are set of different form. The C/R bit in the Type field shall be set2399* as it is stated above, while the C/R bit in the Address field (see subclause2400* 5.2.1.2) shall be set as it is described in subclause 5.4.3.1."2401*/24022403static int2404ng_btsocket_rfcomm_receive_mcc(ng_btsocket_rfcomm_session_p s, struct mbuf *m0)2405{2406struct rfcomm_mcc_hdr *hdr = NULL;2407u_int8_t cr, type, length;24082409mtx_assert(&s->session_mtx, MA_OWNED);24102411/*2412* We can access data directly in the first mbuf, because we have2413* m_pullup()'ed mbuf chain in ng_btsocket_rfcomm_receive_frame().2414* All MCC commands should fit into single mbuf (except probably TEST).2415*/24162417hdr = mtod(m0, struct rfcomm_mcc_hdr *);2418cr = RFCOMM_CR(hdr->type);2419type = RFCOMM_MCC_TYPE(hdr->type);2420length = RFCOMM_MCC_LENGTH(hdr->length);24212422/* Check MCC frame length */2423if (sizeof(*hdr) + length != m0->m_pkthdr.len) {2424NG_BTSOCKET_RFCOMM_ERR(2425"%s: Invalid MCC frame length=%d, len=%d\n",2426__func__, length, m0->m_pkthdr.len);2427NG_FREE_M(m0);24282429return (EMSGSIZE);2430}24312432switch (type) {2433case RFCOMM_MCC_TEST:2434return (ng_btsocket_rfcomm_receive_test(s, m0));2435/* NOT REACHED */24362437case RFCOMM_MCC_FCON:2438case RFCOMM_MCC_FCOFF:2439return (ng_btsocket_rfcomm_receive_fc(s, m0));2440/* NOT REACHED */24412442case RFCOMM_MCC_MSC:2443return (ng_btsocket_rfcomm_receive_msc(s, m0));2444/* NOT REACHED */24452446case RFCOMM_MCC_RPN:2447return (ng_btsocket_rfcomm_receive_rpn(s, m0));2448/* NOT REACHED */24492450case RFCOMM_MCC_RLS:2451return (ng_btsocket_rfcomm_receive_rls(s, m0));2452/* NOT REACHED */24532454case RFCOMM_MCC_PN:2455return (ng_btsocket_rfcomm_receive_pn(s, m0));2456/* NOT REACHED */24572458case RFCOMM_MCC_NSC:2459NG_BTSOCKET_RFCOMM_ERR(2460"%s: Got MCC NSC, type=%#x, cr=%d, length=%d, session state=%d, flags=%#x, " \2461"mtu=%d, len=%d\n", __func__, RFCOMM_MCC_TYPE(*((u_int8_t *)(hdr + 1))), cr,2462length, s->state, s->flags, s->mtu, m0->m_pkthdr.len);2463NG_FREE_M(m0);2464break;24652466default:2467NG_BTSOCKET_RFCOMM_ERR(2468"%s: Got unknown MCC, type=%#x, cr=%d, length=%d, session state=%d, " \2469"flags=%#x, mtu=%d, len=%d\n",2470__func__, type, cr, length, s->state, s->flags,2471s->mtu, m0->m_pkthdr.len);24722473/* Reuse mbuf to send NSC */2474hdr = mtod(m0, struct rfcomm_mcc_hdr *);2475m0->m_pkthdr.len = m0->m_len = sizeof(*hdr);24762477/* Create MCC NSC header */2478hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_NSC);2479hdr->length = RFCOMM_MKLEN8(1);24802481/* Put back MCC command type we did not like */2482m0->m_data[m0->m_len] = RFCOMM_MKMCC_TYPE(cr, type);2483m0->m_pkthdr.len ++;2484m0->m_len ++;24852486/* Send UIH frame */2487return (ng_btsocket_rfcomm_send_uih(s,2488RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0));2489/* NOT REACHED */2490}24912492return (0);2493} /* ng_btsocket_rfcomm_receive_mcc */24942495/*2496* Receive RFCOMM TEST MCC command2497*/24982499static int2500ng_btsocket_rfcomm_receive_test(ng_btsocket_rfcomm_session_p s, struct mbuf *m0)2501{2502struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr *);2503int error = 0;25042505mtx_assert(&s->session_mtx, MA_OWNED);25062507NG_BTSOCKET_RFCOMM_INFO(2508"%s: Got MCC TEST, cr=%d, length=%d, session state=%d, flags=%#x, mtu=%d, " \2509"len=%d\n", __func__, RFCOMM_CR(hdr->type), RFCOMM_MCC_LENGTH(hdr->length),2510s->state, s->flags, s->mtu, m0->m_pkthdr.len);25112512if (RFCOMM_CR(hdr->type)) {2513hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_TEST);2514error = ng_btsocket_rfcomm_send_uih(s,2515RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0);2516} else2517NG_FREE_M(m0); /* XXX ignore response */25182519return (error);2520} /* ng_btsocket_rfcomm_receive_test */25212522/*2523* Receive RFCOMM FCON/FCOFF MCC command2524*/25252526static int2527ng_btsocket_rfcomm_receive_fc(ng_btsocket_rfcomm_session_p s, struct mbuf *m0)2528{2529struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr *);2530u_int8_t type = RFCOMM_MCC_TYPE(hdr->type);2531int error = 0;25322533mtx_assert(&s->session_mtx, MA_OWNED);25342535/*2536* Turn ON/OFF aggregate flow on the entire session. When remote peer2537* asserted flow control no transmission shall occur except on dlci 02538* (control channel).2539*/25402541NG_BTSOCKET_RFCOMM_INFO(2542"%s: Got MCC FC%s, cr=%d, length=%d, session state=%d, flags=%#x, mtu=%d, " \2543"len=%d\n", __func__, (type == RFCOMM_MCC_FCON)? "ON" : "OFF",2544RFCOMM_CR(hdr->type), RFCOMM_MCC_LENGTH(hdr->length),2545s->state, s->flags, s->mtu, m0->m_pkthdr.len);25462547if (RFCOMM_CR(hdr->type)) {2548if (type == RFCOMM_MCC_FCON)2549s->flags &= ~NG_BTSOCKET_RFCOMM_SESSION_RFC;2550else2551s->flags |= NG_BTSOCKET_RFCOMM_SESSION_RFC;25522553hdr->type = RFCOMM_MKMCC_TYPE(0, type);2554error = ng_btsocket_rfcomm_send_uih(s,2555RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0);2556} else2557NG_FREE_M(m0); /* XXX ignore response */25582559return (error);2560} /* ng_btsocket_rfcomm_receive_fc */25612562/*2563* Receive RFCOMM MSC MCC command2564*/25652566static int2567ng_btsocket_rfcomm_receive_msc(ng_btsocket_rfcomm_session_p s, struct mbuf *m0)2568{2569struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr*);2570struct rfcomm_mcc_msc *msc = (struct rfcomm_mcc_msc *)(hdr+1);2571ng_btsocket_rfcomm_pcb_t *pcb = NULL;2572int error = 0;25732574mtx_assert(&s->session_mtx, MA_OWNED);25752576NG_BTSOCKET_RFCOMM_INFO(2577"%s: Got MCC MSC, dlci=%d, cr=%d, length=%d, session state=%d, flags=%#x, " \2578"mtu=%d, len=%d\n",2579__func__, RFCOMM_DLCI(msc->address), RFCOMM_CR(hdr->type),2580RFCOMM_MCC_LENGTH(hdr->length), s->state, s->flags,2581s->mtu, m0->m_pkthdr.len);25822583if (RFCOMM_CR(hdr->type)) {2584pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, RFCOMM_DLCI(msc->address));2585if (pcb == NULL) {2586NG_BTSOCKET_RFCOMM_WARN(2587"%s: Got MSC command for non-existing dlci=%d\n",2588__func__, RFCOMM_DLCI(msc->address));2589NG_FREE_M(m0);25902591return (ENOENT);2592}25932594mtx_lock(&pcb->pcb_mtx);25952596if (pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTING &&2597pcb->state != NG_BTSOCKET_RFCOMM_DLC_CONNECTED) {2598NG_BTSOCKET_RFCOMM_WARN(2599"%s: Got MSC on dlci=%d in invalid state=%d\n",2600__func__, RFCOMM_DLCI(msc->address),2601pcb->state);26022603mtx_unlock(&pcb->pcb_mtx);2604NG_FREE_M(m0);26052606return (EINVAL);2607}26082609pcb->rmodem = msc->modem; /* Update remote port signals */26102611hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_MSC);2612error = ng_btsocket_rfcomm_send_uih(s,2613RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0);26142615#if 0 /* YYY */2616/* Send more data from DLC. XXX check for errors? */2617if (!(pcb->rmodem & RFCOMM_MODEM_FC) &&2618!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC))2619ng_btsocket_rfcomm_pcb_send(pcb, ALOT);2620#endif /* YYY */26212622mtx_unlock(&pcb->pcb_mtx);2623} else2624NG_FREE_M(m0); /* XXX ignore response */26252626return (error);2627} /* ng_btsocket_rfcomm_receive_msc */26282629/*2630* Receive RFCOMM RPN MCC command2631* XXX FIXME do we need htole16/le16toh for RPN param_mask?2632*/26332634static int2635ng_btsocket_rfcomm_receive_rpn(ng_btsocket_rfcomm_session_p s, struct mbuf *m0)2636{2637struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr *);2638struct rfcomm_mcc_rpn *rpn = (struct rfcomm_mcc_rpn *)(hdr + 1);2639int error = 0;2640u_int16_t param_mask;2641u_int8_t bit_rate, data_bits, stop_bits, parity,2642flow_control, xon_char, xoff_char;26432644mtx_assert(&s->session_mtx, MA_OWNED);26452646NG_BTSOCKET_RFCOMM_INFO(2647"%s: Got MCC RPN, dlci=%d, cr=%d, length=%d, session state=%d, flags=%#x, " \2648"mtu=%d, len=%d\n",2649__func__, RFCOMM_DLCI(rpn->dlci), RFCOMM_CR(hdr->type),2650RFCOMM_MCC_LENGTH(hdr->length), s->state, s->flags,2651s->mtu, m0->m_pkthdr.len);26522653if (RFCOMM_CR(hdr->type)) {2654param_mask = RFCOMM_RPN_PM_ALL;26552656if (RFCOMM_MCC_LENGTH(hdr->length) == 1) {2657/* Request - return default setting */2658bit_rate = RFCOMM_RPN_BR_115200;2659data_bits = RFCOMM_RPN_DATA_8;2660stop_bits = RFCOMM_RPN_STOP_1;2661parity = RFCOMM_RPN_PARITY_NONE;2662flow_control = RFCOMM_RPN_FLOW_NONE;2663xon_char = RFCOMM_RPN_XON_CHAR;2664xoff_char = RFCOMM_RPN_XOFF_CHAR;2665} else {2666/*2667* Ignore/accept bit_rate, 8 bits, 1 stop bit, no2668* parity, no flow control lines, default XON/XOFF2669* chars.2670*/26712672bit_rate = rpn->bit_rate;2673rpn->param_mask = le16toh(rpn->param_mask); /* XXX */26742675data_bits = RFCOMM_RPN_DATA_BITS(rpn->line_settings);2676if (rpn->param_mask & RFCOMM_RPN_PM_DATA &&2677data_bits != RFCOMM_RPN_DATA_8) {2678data_bits = RFCOMM_RPN_DATA_8;2679param_mask ^= RFCOMM_RPN_PM_DATA;2680}26812682stop_bits = RFCOMM_RPN_STOP_BITS(rpn->line_settings);2683if (rpn->param_mask & RFCOMM_RPN_PM_STOP &&2684stop_bits != RFCOMM_RPN_STOP_1) {2685stop_bits = RFCOMM_RPN_STOP_1;2686param_mask ^= RFCOMM_RPN_PM_STOP;2687}26882689parity = RFCOMM_RPN_PARITY(rpn->line_settings);2690if (rpn->param_mask & RFCOMM_RPN_PM_PARITY &&2691parity != RFCOMM_RPN_PARITY_NONE) {2692parity = RFCOMM_RPN_PARITY_NONE;2693param_mask ^= RFCOMM_RPN_PM_PARITY;2694}26952696flow_control = rpn->flow_control;2697if (rpn->param_mask & RFCOMM_RPN_PM_FLOW &&2698flow_control != RFCOMM_RPN_FLOW_NONE) {2699flow_control = RFCOMM_RPN_FLOW_NONE;2700param_mask ^= RFCOMM_RPN_PM_FLOW;2701}27022703xon_char = rpn->xon_char;2704if (rpn->param_mask & RFCOMM_RPN_PM_XON &&2705xon_char != RFCOMM_RPN_XON_CHAR) {2706xon_char = RFCOMM_RPN_XON_CHAR;2707param_mask ^= RFCOMM_RPN_PM_XON;2708}27092710xoff_char = rpn->xoff_char;2711if (rpn->param_mask & RFCOMM_RPN_PM_XOFF &&2712xoff_char != RFCOMM_RPN_XOFF_CHAR) {2713xoff_char = RFCOMM_RPN_XOFF_CHAR;2714param_mask ^= RFCOMM_RPN_PM_XOFF;2715}2716}27172718rpn->bit_rate = bit_rate;2719rpn->line_settings = RFCOMM_MKRPN_LINE_SETTINGS(data_bits,2720stop_bits, parity);2721rpn->flow_control = flow_control;2722rpn->xon_char = xon_char;2723rpn->xoff_char = xoff_char;2724rpn->param_mask = htole16(param_mask); /* XXX */27252726m0->m_pkthdr.len = m0->m_len = sizeof(*hdr) + sizeof(*rpn);27272728hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_RPN);2729error = ng_btsocket_rfcomm_send_uih(s,2730RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0);2731} else2732NG_FREE_M(m0); /* XXX ignore response */27332734return (error);2735} /* ng_btsocket_rfcomm_receive_rpn */27362737/*2738* Receive RFCOMM RLS MCC command2739*/27402741static int2742ng_btsocket_rfcomm_receive_rls(ng_btsocket_rfcomm_session_p s, struct mbuf *m0)2743{2744struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr *);2745struct rfcomm_mcc_rls *rls = (struct rfcomm_mcc_rls *)(hdr + 1);2746int error = 0;27472748mtx_assert(&s->session_mtx, MA_OWNED);27492750/*2751* XXX FIXME Do we have to do anything else here? Remote peer tries to2752* tell us something about DLCI. Just report what we have received and2753* return back received values as required by TS 07.10 spec.2754*/27552756NG_BTSOCKET_RFCOMM_INFO(2757"%s: Got MCC RLS, dlci=%d, status=%#x, cr=%d, length=%d, session state=%d, " \2758"flags=%#x, mtu=%d, len=%d\n",2759__func__, RFCOMM_DLCI(rls->address), rls->status,2760RFCOMM_CR(hdr->type), RFCOMM_MCC_LENGTH(hdr->length),2761s->state, s->flags, s->mtu, m0->m_pkthdr.len);27622763if (RFCOMM_CR(hdr->type)) {2764if (rls->status & 0x1)2765NG_BTSOCKET_RFCOMM_ERR(2766"%s: Got RLS dlci=%d, error=%#x\n", __func__, RFCOMM_DLCI(rls->address),2767rls->status >> 1);27682769hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_RLS);2770error = ng_btsocket_rfcomm_send_uih(s,2771RFCOMM_MKADDRESS(INITIATOR(s), 0), 0, 0, m0);2772} else2773NG_FREE_M(m0); /* XXX ignore responses */27742775return (error);2776} /* ng_btsocket_rfcomm_receive_rls */27772778/*2779* Receive RFCOMM PN MCC command2780*/27812782static int2783ng_btsocket_rfcomm_receive_pn(ng_btsocket_rfcomm_session_p s, struct mbuf *m0)2784{2785struct rfcomm_mcc_hdr *hdr = mtod(m0, struct rfcomm_mcc_hdr*);2786struct rfcomm_mcc_pn *pn = (struct rfcomm_mcc_pn *)(hdr+1);2787ng_btsocket_rfcomm_pcb_t *pcb = NULL;2788int error = 0;27892790mtx_assert(&s->session_mtx, MA_OWNED);27912792NG_BTSOCKET_RFCOMM_INFO(2793"%s: Got MCC PN, dlci=%d, cr=%d, length=%d, flow_control=%#x, priority=%d, " \2794"ack_timer=%d, mtu=%d, max_retrans=%d, credits=%d, session state=%d, " \2795"flags=%#x, session mtu=%d, len=%d\n",2796__func__, pn->dlci, RFCOMM_CR(hdr->type),2797RFCOMM_MCC_LENGTH(hdr->length), pn->flow_control, pn->priority,2798pn->ack_timer, le16toh(pn->mtu), pn->max_retrans, pn->credits,2799s->state, s->flags, s->mtu, m0->m_pkthdr.len);28002801if (pn->dlci == 0) {2802NG_BTSOCKET_RFCOMM_ERR("%s: Zero dlci in MCC PN\n", __func__);2803NG_FREE_M(m0);28042805return (EINVAL);2806}28072808/* Check if we have this dlci */2809pcb = ng_btsocket_rfcomm_pcb_by_dlci(s, pn->dlci);2810if (pcb != NULL) {2811mtx_lock(&pcb->pcb_mtx);28122813if (RFCOMM_CR(hdr->type)) {2814/* PN Request */2815ng_btsocket_rfcomm_set_pn(pcb, 1, pn->flow_control,2816pn->credits, pn->mtu);28172818if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) {2819pn->flow_control = 0xe0;2820pn->credits = RFCOMM_DEFAULT_CREDITS;2821} else {2822pn->flow_control = 0;2823pn->credits = 0;2824}28252826hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_PN);2827error = ng_btsocket_rfcomm_send_uih(s,2828RFCOMM_MKADDRESS(INITIATOR(s), 0),28290, 0, m0);2830} else {2831/* PN Response - proceed with SABM. Timeout still set */2832if (pcb->state == NG_BTSOCKET_RFCOMM_DLC_CONFIGURING) {2833ng_btsocket_rfcomm_set_pn(pcb, 0,2834pn->flow_control, pn->credits, pn->mtu);28352836pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTING;2837error = ng_btsocket_rfcomm_send_command(s,2838RFCOMM_FRAME_SABM, pn->dlci);2839} else2840NG_BTSOCKET_RFCOMM_WARN(2841"%s: Got PN response for dlci=%d in invalid state=%d\n",2842__func__, pn->dlci, pcb->state);28432844NG_FREE_M(m0);2845}28462847mtx_unlock(&pcb->pcb_mtx);2848} else if (RFCOMM_CR(hdr->type)) {2849/* PN request to non-existing dlci - incoming connection */2850pcb = ng_btsocket_rfcomm_connect_ind(s,2851RFCOMM_SRVCHANNEL(pn->dlci));2852if (pcb != NULL) {2853mtx_lock(&pcb->pcb_mtx);28542855pcb->dlci = pn->dlci;28562857ng_btsocket_rfcomm_set_pn(pcb, 1, pn->flow_control,2858pn->credits, pn->mtu);28592860if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) {2861pn->flow_control = 0xe0;2862pn->credits = RFCOMM_DEFAULT_CREDITS;2863} else {2864pn->flow_control = 0;2865pn->credits = 0;2866}28672868hdr->type = RFCOMM_MKMCC_TYPE(0, RFCOMM_MCC_PN);2869error = ng_btsocket_rfcomm_send_uih(s,2870RFCOMM_MKADDRESS(INITIATOR(s), 0),28710, 0, m0);28722873if (error == 0) {2874ng_btsocket_rfcomm_timeout(pcb);2875pcb->state = NG_BTSOCKET_RFCOMM_DLC_CONNECTING;2876soisconnecting(pcb->so);2877} else2878ng_btsocket_rfcomm_pcb_kill(pcb, error);28792880mtx_unlock(&pcb->pcb_mtx);2881} else {2882/* Nobody is listen()ing on this channel */2883error = ng_btsocket_rfcomm_send_command(s,2884RFCOMM_FRAME_DM, pn->dlci);2885NG_FREE_M(m0);2886}2887} else2888NG_FREE_M(m0); /* XXX ignore response to non-existing dlci */28892890return (error);2891} /* ng_btsocket_rfcomm_receive_pn */28922893/*2894* Set PN parameters for dlci. Caller must hold pcb->pcb_mtx.2895*2896* From Bluetooth spec.2897*2898* "... The CL1 - CL4 field is completely redefined. (In TS07.10 this defines2899* the convergence layer to use, which is not applicable to RFCOMM. In RFCOMM,2900* in Bluetooth versions up to 1.0B, this field was forced to 0).2901*2902* In the PN request sent prior to a DLC establishment, this field must contain2903* the value 15 (0xF), indicating support of credit based flow control in the2904* sender. See Table 5.3 below. If the PN response contains any other value2905* than 14 (0xE) in this field, it is inferred that the peer RFCOMM entity is2906* not supporting the credit based flow control feature. (This is only possible2907* if the peer RFCOMM implementation is only conforming to Bluetooth version2908* 1.0B.) If a PN request is sent on an already open DLC, then this field must2909* contain the value zero; it is not possible to set initial credits more2910* than once per DLC activation. A responding implementation must set this2911* field in the PN response to 14 (0xE), if (and only if) the value in the PN2912* request was 15..."2913*/29142915static void2916ng_btsocket_rfcomm_set_pn(ng_btsocket_rfcomm_pcb_p pcb, u_int8_t cr,2917u_int8_t flow_control, u_int8_t credits, u_int16_t mtu)2918{2919mtx_assert(&pcb->pcb_mtx, MA_OWNED);29202921pcb->mtu = le16toh(mtu);29222923if (cr) {2924if (flow_control == 0xf0) {2925pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_CFC;2926pcb->tx_cred = credits;2927} else {2928pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_CFC;2929pcb->tx_cred = 0;2930}2931} else {2932if (flow_control == 0xe0) {2933pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_CFC;2934pcb->tx_cred = credits;2935} else {2936pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_CFC;2937pcb->tx_cred = 0;2938}2939}29402941NG_BTSOCKET_RFCOMM_INFO(2942"%s: cr=%d, dlci=%d, state=%d, flags=%#x, mtu=%d, rx_cred=%d, tx_cred=%d\n",2943__func__, cr, pcb->dlci, pcb->state, pcb->flags, pcb->mtu,2944pcb->rx_cred, pcb->tx_cred);2945} /* ng_btsocket_rfcomm_set_pn */29462947/*2948* Send RFCOMM SABM/DISC/UA/DM frames. Caller must hold s->session_mtx2949*/29502951static int2952ng_btsocket_rfcomm_send_command(ng_btsocket_rfcomm_session_p s,2953u_int8_t type, u_int8_t dlci)2954{2955struct rfcomm_cmd_hdr *hdr = NULL;2956struct mbuf *m = NULL;2957int cr;29582959mtx_assert(&s->session_mtx, MA_OWNED);29602961NG_BTSOCKET_RFCOMM_INFO(2962"%s: Sending command type %#x, session state=%d, flags=%#x, mtu=%d, dlci=%d\n",2963__func__, type, s->state, s->flags, s->mtu, dlci);29642965switch (type) {2966case RFCOMM_FRAME_SABM:2967case RFCOMM_FRAME_DISC:2968cr = INITIATOR(s);2969break;29702971case RFCOMM_FRAME_UA:2972case RFCOMM_FRAME_DM:2973cr = !INITIATOR(s);2974break;29752976default:2977panic("%s: Invalid frame type=%#x\n", __func__, type);2978return (EINVAL);2979/* NOT REACHED */2980}29812982MGETHDR(m, M_NOWAIT, MT_DATA);2983if (m == NULL)2984return (ENOBUFS);29852986m->m_pkthdr.len = m->m_len = sizeof(*hdr);29872988hdr = mtod(m, struct rfcomm_cmd_hdr *);2989hdr->address = RFCOMM_MKADDRESS(cr, dlci);2990hdr->control = RFCOMM_MKCONTROL(type, 1);2991hdr->length = RFCOMM_MKLEN8(0);2992hdr->fcs = ng_btsocket_rfcomm_fcs3((u_int8_t *) hdr);29932994NG_BT_MBUFQ_ENQUEUE(&s->outq, m);29952996return (0);2997} /* ng_btsocket_rfcomm_send_command */29982999/*3000* Send RFCOMM UIH frame. Caller must hold s->session_mtx3001*/30023003static int3004ng_btsocket_rfcomm_send_uih(ng_btsocket_rfcomm_session_p s, u_int8_t address,3005u_int8_t pf, u_int8_t credits, struct mbuf *data)3006{3007struct rfcomm_frame_hdr *hdr = NULL;3008struct mbuf *m = NULL, *mcrc = NULL;3009u_int16_t length;30103011mtx_assert(&s->session_mtx, MA_OWNED);30123013MGETHDR(m, M_NOWAIT, MT_DATA);3014if (m == NULL) {3015NG_FREE_M(data);3016return (ENOBUFS);3017}3018m->m_pkthdr.len = m->m_len = sizeof(*hdr);30193020MGET(mcrc, M_NOWAIT, MT_DATA);3021if (mcrc == NULL) {3022NG_FREE_M(data);3023return (ENOBUFS);3024}3025mcrc->m_len = 1;30263027/* Fill UIH frame header */3028hdr = mtod(m, struct rfcomm_frame_hdr *);3029hdr->address = address;3030hdr->control = RFCOMM_MKCONTROL(RFCOMM_FRAME_UIH, pf);30313032/* Calculate FCS */3033mcrc->m_data[0] = ng_btsocket_rfcomm_fcs2((u_int8_t *) hdr);30343035/* Put length back */3036length = (data != NULL)? data->m_pkthdr.len : 0;3037if (length > 127) {3038u_int16_t l = htole16(RFCOMM_MKLEN16(length));30393040bcopy(&l, &hdr->length, sizeof(l));3041m->m_pkthdr.len ++;3042m->m_len ++;3043} else3044hdr->length = RFCOMM_MKLEN8(length);30453046if (pf) {3047m->m_data[m->m_len] = credits;3048m->m_pkthdr.len ++;3049m->m_len ++;3050}30513052/* Add payload */3053if (data != NULL) {3054m_cat(m, data);3055m->m_pkthdr.len += length;3056}30573058/* Put FCS back */3059m_cat(m, mcrc);3060m->m_pkthdr.len ++;30613062NG_BTSOCKET_RFCOMM_INFO(3063"%s: Sending UIH state=%d, flags=%#x, address=%d, length=%d, pf=%d, " \3064"credits=%d, len=%d\n",3065__func__, s->state, s->flags, address, length, pf, credits,3066m->m_pkthdr.len);30673068NG_BT_MBUFQ_ENQUEUE(&s->outq, m);30693070return (0);3071} /* ng_btsocket_rfcomm_send_uih */30723073/*3074* Send MSC request. Caller must hold pcb->pcb_mtx and pcb->session->session_mtx3075*/30763077static int3078ng_btsocket_rfcomm_send_msc(ng_btsocket_rfcomm_pcb_p pcb)3079{3080struct mbuf *m = NULL;3081struct rfcomm_mcc_hdr *hdr = NULL;3082struct rfcomm_mcc_msc *msc = NULL;30833084mtx_assert(&pcb->session->session_mtx, MA_OWNED);3085mtx_assert(&pcb->pcb_mtx, MA_OWNED);30863087MGETHDR(m, M_NOWAIT, MT_DATA);3088if (m == NULL)3089return (ENOBUFS);30903091m->m_pkthdr.len = m->m_len = sizeof(*hdr) + sizeof(*msc);30923093hdr = mtod(m, struct rfcomm_mcc_hdr *);3094msc = (struct rfcomm_mcc_msc *)(hdr + 1);30953096hdr->type = RFCOMM_MKMCC_TYPE(1, RFCOMM_MCC_MSC);3097hdr->length = RFCOMM_MKLEN8(sizeof(*msc));30983099msc->address = RFCOMM_MKADDRESS(1, pcb->dlci);3100msc->modem = pcb->lmodem;31013102NG_BTSOCKET_RFCOMM_INFO(3103"%s: Sending MSC dlci=%d, state=%d, flags=%#x, address=%d, modem=%#x\n",3104__func__, pcb->dlci, pcb->state, pcb->flags, msc->address,3105msc->modem);31063107return (ng_btsocket_rfcomm_send_uih(pcb->session,3108RFCOMM_MKADDRESS(INITIATOR(pcb->session), 0), 0, 0, m));3109} /* ng_btsocket_rfcomm_send_msc */31103111/*3112* Send PN request. Caller must hold pcb->pcb_mtx and pcb->session->session_mtx3113*/31143115static int3116ng_btsocket_rfcomm_send_pn(ng_btsocket_rfcomm_pcb_p pcb)3117{3118struct mbuf *m = NULL;3119struct rfcomm_mcc_hdr *hdr = NULL;3120struct rfcomm_mcc_pn *pn = NULL;31213122mtx_assert(&pcb->session->session_mtx, MA_OWNED);3123mtx_assert(&pcb->pcb_mtx, MA_OWNED);31243125MGETHDR(m, M_NOWAIT, MT_DATA);3126if (m == NULL)3127return (ENOBUFS);31283129m->m_pkthdr.len = m->m_len = sizeof(*hdr) + sizeof(*pn);31303131hdr = mtod(m, struct rfcomm_mcc_hdr *);3132pn = (struct rfcomm_mcc_pn *)(hdr + 1);31333134hdr->type = RFCOMM_MKMCC_TYPE(1, RFCOMM_MCC_PN);3135hdr->length = RFCOMM_MKLEN8(sizeof(*pn));31363137pn->dlci = pcb->dlci;31383139/*3140* Set default DLCI priority as described in GSM 07.103141* (ETSI TS 101 369) clause 5.6 page 423142*/31433144pn->priority = (pcb->dlci < 56)? (((pcb->dlci >> 3) << 3) + 7) : 61;3145pn->ack_timer = 0;3146pn->mtu = htole16(pcb->mtu);3147pn->max_retrans = 0;31483149if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) {3150pn->flow_control = 0xf0;3151pn->credits = pcb->rx_cred;3152} else {3153pn->flow_control = 0;3154pn->credits = 0;3155}31563157NG_BTSOCKET_RFCOMM_INFO(3158"%s: Sending PN dlci=%d, state=%d, flags=%#x, mtu=%d, flow_control=%#x, " \3159"credits=%d\n", __func__, pcb->dlci, pcb->state, pcb->flags, pcb->mtu,3160pn->flow_control, pn->credits);31613162return (ng_btsocket_rfcomm_send_uih(pcb->session,3163RFCOMM_MKADDRESS(INITIATOR(pcb->session), 0), 0, 0, m));3164} /* ng_btsocket_rfcomm_send_pn */31653166/*3167* Calculate and send credits based on available space in receive buffer3168*/31693170static int3171ng_btsocket_rfcomm_send_credits(ng_btsocket_rfcomm_pcb_p pcb)3172{3173int error = 0;3174u_int8_t credits;31753176mtx_assert(&pcb->pcb_mtx, MA_OWNED);3177mtx_assert(&pcb->session->session_mtx, MA_OWNED);31783179NG_BTSOCKET_RFCOMM_INFO(3180"%s: Sending more credits, dlci=%d, state=%d, flags=%#x, mtu=%d, " \3181"space=%ld, tx_cred=%d, rx_cred=%d\n",3182__func__, pcb->dlci, pcb->state, pcb->flags, pcb->mtu,3183sbspace(&pcb->so->so_rcv), pcb->tx_cred, pcb->rx_cred);31843185credits = sbspace(&pcb->so->so_rcv) / pcb->mtu;3186if (credits > 0) {3187if (pcb->rx_cred + credits > RFCOMM_MAX_CREDITS)3188credits = RFCOMM_MAX_CREDITS - pcb->rx_cred;31893190error = ng_btsocket_rfcomm_send_uih(3191pcb->session,3192RFCOMM_MKADDRESS(INITIATOR(pcb->session),3193pcb->dlci), 1, credits, NULL);3194if (error == 0) {3195pcb->rx_cred += credits;31963197NG_BTSOCKET_RFCOMM_INFO(3198"%s: Gave remote side %d more credits, dlci=%d, state=%d, flags=%#x, " \3199"rx_cred=%d, tx_cred=%d\n", __func__, credits, pcb->dlci, pcb->state,3200pcb->flags, pcb->rx_cred, pcb->tx_cred);3201} else3202NG_BTSOCKET_RFCOMM_ERR(3203"%s: Could not send credits, error=%d, dlci=%d, state=%d, flags=%#x, " \3204"mtu=%d, space=%ld, tx_cred=%d, rx_cred=%d\n",3205__func__, error, pcb->dlci, pcb->state,3206pcb->flags, pcb->mtu, sbspace(&pcb->so->so_rcv),3207pcb->tx_cred, pcb->rx_cred);3208}32093210return (error);3211} /* ng_btsocket_rfcomm_send_credits */32123213/*****************************************************************************3214*****************************************************************************3215** RFCOMM DLCs3216*****************************************************************************3217*****************************************************************************/32183219/*3220* Send data from socket send buffer3221* Caller must hold pcb->pcb_mtx and pcb->session->session_mtx3222*/32233224static int3225ng_btsocket_rfcomm_pcb_send(ng_btsocket_rfcomm_pcb_p pcb, int limit)3226{3227struct mbuf *m = NULL;3228int sent, length, error;32293230mtx_assert(&pcb->session->session_mtx, MA_OWNED);3231mtx_assert(&pcb->pcb_mtx, MA_OWNED);32323233if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC)3234limit = min(limit, pcb->tx_cred);3235else if (!(pcb->rmodem & RFCOMM_MODEM_FC))3236limit = min(limit, RFCOMM_MAX_CREDITS); /* XXX ??? */3237else3238limit = 0;32393240if (limit == 0) {3241NG_BTSOCKET_RFCOMM_INFO(3242"%s: Could not send - remote flow control asserted, dlci=%d, flags=%#x, " \3243"rmodem=%#x, tx_cred=%d\n",3244__func__, pcb->dlci, pcb->flags, pcb->rmodem,3245pcb->tx_cred);32463247return (0);3248}32493250for (error = 0, sent = 0; sent < limit; sent ++) {3251length = min(pcb->mtu, sbavail(&pcb->so->so_snd));3252if (length == 0)3253break;32543255/* Get the chunk from the socket's send buffer */3256m = ng_btsocket_rfcomm_prepare_packet(&pcb->so->so_snd, length);3257if (m == NULL) {3258error = ENOBUFS;3259break;3260}32613262sbdrop(&pcb->so->so_snd, length);32633264error = ng_btsocket_rfcomm_send_uih(pcb->session,3265RFCOMM_MKADDRESS(INITIATOR(pcb->session),3266pcb->dlci), 0, 0, m);3267if (error != 0)3268break;3269}32703271if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC)3272pcb->tx_cred -= sent;32733274if (error == 0 && sent > 0) {3275pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_SENDING;3276sowwakeup(pcb->so);3277}32783279return (error);3280} /* ng_btsocket_rfcomm_pcb_send */32813282/*3283* Unlink and disconnect DLC. If ng_btsocket_rfcomm_pcb_kill() returns3284* non zero value than socket has no reference and has to be detached.3285* Caller must hold pcb->pcb_mtx and pcb->session->session_mtx3286*/32873288static void3289ng_btsocket_rfcomm_pcb_kill(ng_btsocket_rfcomm_pcb_p pcb, int error)3290{3291ng_btsocket_rfcomm_session_p s = pcb->session;32923293NG_BTSOCKET_RFCOMM_INFO(3294"%s: Killing DLC, so=%p, dlci=%d, state=%d, flags=%#x, error=%d\n",3295__func__, pcb->so, pcb->dlci, pcb->state, pcb->flags, error);32963297if (pcb->session == NULL)3298panic("%s: DLC without session, pcb=%p, state=%d, flags=%#x\n",3299__func__, pcb, pcb->state, pcb->flags);33003301mtx_assert(&pcb->session->session_mtx, MA_OWNED);3302mtx_assert(&pcb->pcb_mtx, MA_OWNED);33033304if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)3305ng_btsocket_rfcomm_untimeout(pcb);33063307/* Detach DLC from the session. Does not matter which state DLC in */3308LIST_REMOVE(pcb, session_next);3309pcb->session = NULL;33103311/* Change DLC state and wakeup all sleepers */3312pcb->state = NG_BTSOCKET_RFCOMM_DLC_CLOSED;3313pcb->so->so_error = error;3314soisdisconnected(pcb->so);3315wakeup(&pcb->state);33163317/* Check if we have any DLCs left on the session */3318if (LIST_EMPTY(&s->dlcs) && INITIATOR(s)) {3319NG_BTSOCKET_RFCOMM_INFO(3320"%s: Disconnecting session, state=%d, flags=%#x, mtu=%d\n",3321__func__, s->state, s->flags, s->mtu);33223323switch (s->state) {3324case NG_BTSOCKET_RFCOMM_SESSION_CLOSED:3325case NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING:3326/*3327* Do not have to do anything here. We can get here3328* when L2CAP connection was terminated or we have3329* received DISC on multiplexor channel3330*/3331break;33323333case NG_BTSOCKET_RFCOMM_SESSION_OPEN:3334/* Send DISC on multiplexor channel */3335error = ng_btsocket_rfcomm_send_command(s,3336RFCOMM_FRAME_DISC, 0);3337if (error == 0) {3338s->state = NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING;3339break;3340}3341/* FALL THROUGH */33423343case NG_BTSOCKET_RFCOMM_SESSION_CONNECTING:3344case NG_BTSOCKET_RFCOMM_SESSION_CONNECTED:3345s->state = NG_BTSOCKET_RFCOMM_SESSION_CLOSED;3346break;33473348/* case NG_BTSOCKET_RFCOMM_SESSION_LISTENING: */3349default:3350panic("%s: Invalid session state=%d, flags=%#x\n",3351__func__, s->state, s->flags);3352break;3353}33543355ng_btsocket_rfcomm_task_wakeup();3356}3357} /* ng_btsocket_rfcomm_pcb_kill */33583359/*3360* Look for given dlci for given RFCOMM session. Caller must hold s->session_mtx3361*/33623363static ng_btsocket_rfcomm_pcb_p3364ng_btsocket_rfcomm_pcb_by_dlci(ng_btsocket_rfcomm_session_p s, int dlci)3365{3366ng_btsocket_rfcomm_pcb_p pcb = NULL;33673368mtx_assert(&s->session_mtx, MA_OWNED);33693370LIST_FOREACH(pcb, &s->dlcs, session_next)3371if (pcb->dlci == dlci)3372break;33733374return (pcb);3375} /* ng_btsocket_rfcomm_pcb_by_dlci */33763377/*3378* Look for socket that listens on given src address and given channel3379*/33803381static ng_btsocket_rfcomm_pcb_p3382ng_btsocket_rfcomm_pcb_listener(bdaddr_p src, int channel)3383{3384ng_btsocket_rfcomm_pcb_p pcb = NULL, pcb1 = NULL;33853386mtx_lock(&ng_btsocket_rfcomm_sockets_mtx);33873388LIST_FOREACH(pcb, &ng_btsocket_rfcomm_sockets, next) {3389if (pcb->channel != channel || !SOLISTENING(pcb->so))3390continue;33913392if (bcmp(&pcb->src, src, sizeof(*src)) == 0)3393break;33943395if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)3396pcb1 = pcb;3397}33983399mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);34003401return ((pcb != NULL)? pcb : pcb1);3402} /* ng_btsocket_rfcomm_pcb_listener */34033404/*****************************************************************************3405*****************************************************************************3406** Misc. functions3407*****************************************************************************3408*****************************************************************************/34093410/*3411* Set timeout. Caller MUST hold pcb_mtx3412*/34133414static void3415ng_btsocket_rfcomm_timeout(ng_btsocket_rfcomm_pcb_p pcb)3416{3417mtx_assert(&pcb->pcb_mtx, MA_OWNED);34183419if (!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO)) {3420pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_TIMO;3421pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT;3422callout_reset(&pcb->timo, ng_btsocket_rfcomm_timo * hz,3423ng_btsocket_rfcomm_process_timeout, pcb);3424} else3425panic("%s: Duplicated socket timeout?!\n", __func__);3426} /* ng_btsocket_rfcomm_timeout */34273428/*3429* Unset pcb timeout. Caller MUST hold pcb_mtx3430*/34313432static void3433ng_btsocket_rfcomm_untimeout(ng_btsocket_rfcomm_pcb_p pcb)3434{3435mtx_assert(&pcb->pcb_mtx, MA_OWNED);34363437if (pcb->flags & NG_BTSOCKET_RFCOMM_DLC_TIMO) {3438callout_stop(&pcb->timo);3439pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMO;3440pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT;3441} else3442panic("%s: No socket timeout?!\n", __func__);3443} /* ng_btsocket_rfcomm_timeout */34443445/*3446* Process pcb timeout3447*/34483449static void3450ng_btsocket_rfcomm_process_timeout(void *xpcb)3451{3452ng_btsocket_rfcomm_pcb_p pcb = (ng_btsocket_rfcomm_pcb_p) xpcb;34533454mtx_assert(&pcb->pcb_mtx, MA_OWNED);34553456NG_BTSOCKET_RFCOMM_INFO(3457"%s: Timeout, so=%p, dlci=%d, state=%d, flags=%#x\n",3458__func__, pcb->so, pcb->dlci, pcb->state, pcb->flags);34593460pcb->flags &= ~NG_BTSOCKET_RFCOMM_DLC_TIMO;3461pcb->flags |= NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT;34623463switch (pcb->state) {3464case NG_BTSOCKET_RFCOMM_DLC_CONFIGURING:3465case NG_BTSOCKET_RFCOMM_DLC_CONNECTING:3466pcb->state = NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING;3467break;34683469case NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT:3470case NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING:3471break;34723473default:3474panic(3475"%s: DLC timeout in invalid state, dlci=%d, state=%d, flags=%#x\n",3476__func__, pcb->dlci, pcb->state, pcb->flags);3477break;3478}34793480ng_btsocket_rfcomm_task_wakeup();3481} /* ng_btsocket_rfcomm_process_timeout */34823483/*3484* Get up to length bytes from the socket buffer3485*/34863487static struct mbuf *3488ng_btsocket_rfcomm_prepare_packet(struct sockbuf *sb, int length)3489{3490struct mbuf *top = NULL, *m = NULL, *n = NULL, *nextpkt = NULL;3491int mlen, noff, len;34923493MGETHDR(top, M_NOWAIT, MT_DATA);3494if (top == NULL)3495return (NULL);34963497top->m_pkthdr.len = length;3498top->m_len = 0;3499mlen = MHLEN;35003501m = top;3502n = sb->sb_mb;3503nextpkt = n->m_nextpkt;3504noff = 0;35053506while (length > 0 && n != NULL) {3507len = min(mlen - m->m_len, n->m_len - noff);3508if (len > length)3509len = length;35103511bcopy(mtod(n, caddr_t)+noff, mtod(m, caddr_t)+m->m_len, len);3512m->m_len += len;3513noff += len;3514length -= len;35153516if (length > 0 && m->m_len == mlen) {3517MGET(m->m_next, M_NOWAIT, MT_DATA);3518if (m->m_next == NULL) {3519NG_FREE_M(top);3520return (NULL);3521}35223523m = m->m_next;3524m->m_len = 0;3525mlen = MLEN;3526}35273528if (noff == n->m_len) {3529noff = 0;3530n = n->m_next;35313532if (n == NULL)3533n = nextpkt;35343535nextpkt = (n != NULL)? n->m_nextpkt : NULL;3536}3537}35383539if (length < 0)3540panic("%s: length=%d\n", __func__, length);3541if (length > 0 && n == NULL)3542panic("%s: bogus length=%d, n=%p\n", __func__, length, n);35433544return (top);3545} /* ng_btsocket_rfcomm_prepare_packet */354635473548