⬢ DragonFlyBSD Kernel Audit
DF-5740 / sock_stub.c
← back to finding ↓ download raw
/*
 * sock_stub.c -- minimal L2CAP/SCO/RFCOMM/socket glue for the
 * hci_sock_harness KLD.
 *
 * The production netbt code (sys/netbt/hci_socket.c, hci_event.c,
 * hci_link.c, hci_misc.c, hci_unit.c, bt_input.c, bt_proto.c) is compiled
 * VERBATIM into this module.  Everything those files need from the layers
 * we do not compile (l2cap_*.c except the two link-engine helpers,
 * sco_upper.c, sco_socket.c, rfcomm_*.c, hci_ioctl.c) is stubbed here:
 *
 *   - the four pr_usrreqs / ctloutput functions referenced by btsw[]
 *     (bt_proto.c) -- only BTPROTO_HCI sockets are created by the trigger,
 *     the others just have to exist for the table to link;
 *   - l2cap_close/l2cap_start/l2cap_request_free/l2cap_recv_frame and the
 *     signalling senders used by hci_acl_linkmode()/hci_link.c;
 *   - the SCO listener/list + sco_detach (hci_link.c);
 *   - hci_ioctl (referenced by hci_socket.c:hci_scontrol; the trigger
 *     issues no bt ioctls).
 *
 * NOTE: hci_mtap() and hci_drop() are NOT stubbed -- they come VERBATIM
 * from hci_socket.c.  That is the code under test.
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/msgport.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/systm.h>
#include <sys/types.h>
#include <net/if.h>
#include <sys/msgport2.h>

#include <netbt/bluetooth.h>
#include <netbt/hci.h>
#include <netbt/l2cap.h>
#include <netbt/sco.h>

#include "stub.h"

/* ------------------------------------------------------------------ */
/* btsw[] references (bt_proto.c) -- inert definitions                */

int l2cap_sendspace = 4096;
int l2cap_recvspace = 4096;
int l2cap_response_timeout = 20;
int l2cap_response_extended_timeout = 60;
int rfcomm_sendspace = 4096;
int rfcomm_recvspace = 4096;
int rfcomm_mtu_default = 127;
int rfcomm_ack_timeout = 2;
int rfcomm_mcc_timeout = 4;
int sco_sendspace = 4096;
int sco_recvspace = 4096;

/* defined in l2cap_misc.c / rfcomm_dlc.c normally; bt_proto.c only
 * assigns them in netbt_init(), so provide the storage here */
vm_zone_t l2cap_pdu_pool;
vm_zone_t l2cap_req_pool;
vm_zone_t rfcomm_credit_pool;

/*
 * Inert pr_usrreqs for the protocols we don't compile.  None of these
 * paths are exercised (the trigger only opens BTPROTO_HCI sockets);
 * they exist so btsw[] links.
 */
#define STUB_USRREQS {			\
	.pru_abort = pr_generic_notsupp,	\
	.pru_accept = pr_generic_notsupp,	\
	.pru_attach = pr_generic_notsupp,	\
	.pru_bind = pr_generic_notsupp,		\
	.pru_connect = pr_generic_notsupp,	\
	.pru_connect2 = pr_generic_notsupp,	\
	.pru_control = pr_generic_notsupp,	\
	.pru_detach = pr_generic_notsupp,	\
	.pru_disconnect = pr_generic_notsupp,	\
	.pru_listen = pr_generic_notsupp,	\
	.pru_peeraddr = pr_generic_notsupp,	\
	.pru_rcvd = pr_generic_notsupp,		\
	.pru_rcvoob = pr_generic_notsupp,	\
	.pru_send = pr_generic_notsupp,		\
	.pru_sense = pru_sense_null,		\
	.pru_shutdown = pr_generic_notsupp,	\
	.pru_sockaddr = pr_generic_notsupp,	\
	.pru_sosend = sosend,			\
	.pru_soreceive = soreceive,		\
}

struct pr_usrreqs l2cap_usrreqs = STUB_USRREQS;
struct pr_usrreqs sco_usrreqs = STUB_USRREQS;
struct pr_usrreqs rfcomm_usrreqs = STUB_USRREQS;

/* l2cap.h / sco.h already declare the first two; rfcomm.h does not */
void rfcomm_ctloutput(netmsg_t msg);

void
l2cap_ctloutput(netmsg_t msg)
{
	lwkt_replymsg(&msg->ctloutput.base.lmsg, ENOPROTOOPT);
}

void
sco_ctloutput(netmsg_t msg)
{
	lwkt_replymsg(&msg->ctloutput.base.lmsg, ENOPROTOOPT);
}

void
rfcomm_ctloutput(netmsg_t msg)
{
	lwkt_replymsg(&msg->ctloutput.base.lmsg, ENOPROTOOPT);
}

/* ------------------------------------------------------------------ */
/* hci_socket.c:hci_scontrol -> hci_ioctl (hci_ioctl.c not compiled)  */

int
hci_ioctl(unsigned long cmd, void *data, struct proc *p)
{
	return ENOTTY;
}

/* ------------------------------------------------------------------ */
/* l2cap pieces used by the verbatim link engine (hci_link.c etc.)    */

struct l2cap_channel_list l2cap_active_list =
    LIST_HEAD_INITIALIZER(l2cap_active_list);

void
l2cap_close(struct l2cap_channel *chan, int err)
{
	if (chan->lc_lcid != L2CAP_NULL_CID) {
		LIST_REMOVE(chan, lc_ncid);
		chan->lc_lcid = L2CAP_NULL_CID;
	}
}

int
l2cap_start(struct l2cap_channel *chan)
{
	return 0;
}

void
l2cap_request_free(struct l2cap_req *req)
{
	kfree(req, M_BLUETOOTH);
}

void
l2cap_recv_frame(struct mbuf *m, struct hci_link *link)
{
	m_freem(m);
}

int
l2cap_send_connect_req(struct l2cap_channel *chan)
{
	return 0;
}

int
l2cap_send_connect_rsp(struct hci_link *link, uint8_t ident,
    uint16_t dcid, uint16_t scid, uint16_t result)
{
	return 0;
}

int
l2cap_send_config_req(struct l2cap_channel *chan)
{
	return 0;
}

/* ------------------------------------------------------------------ */
/* SCO pieces used by hci_link.c (same as the DF-5739 rig)            */

struct sco_pcb_list sco_pcb = LIST_HEAD_INITIALIZER(sco_pcb);

int stub_sco_newconn_count;
int stub_sco_disconnected_count;

static void *stub_sco_newconn(void *, struct sockaddr_bt *,
			      struct sockaddr_bt *);
static void stub_sco_disconnected(void *, int);
static void stub_sco_connected(void *);

static const struct btproto stub_sco_btproto = {
	NULL,			/* connecting */
	stub_sco_connected,	/* connected */
	stub_sco_disconnected,	/* disconnected */
	stub_sco_newconn,	/* newconn */
	NULL,			/* complete */
	NULL,			/* linkmode */
	NULL,			/* input */
};

static struct sco_pcb stub_listener;

void
stub_sco_init(void)
{
	memset(&stub_listener, 0, sizeof(stub_listener));
	stub_listener.sp_flags = SP_LISTENING;
	stub_listener.sp_proto = &stub_sco_btproto;
	LIST_INSERT_HEAD(&sco_pcb, &stub_listener, sp_next);
}

static void *
stub_sco_newconn(void *upper, struct sockaddr_bt *laddr,
		 struct sockaddr_bt *raddr)
{
	struct sco_pcb *pcb;

	pcb = kmalloc(sizeof(*pcb), M_BLUETOOTH, M_NOWAIT | M_ZERO);
	if (pcb == NULL)
		return NULL;

	pcb->sp_proto = &stub_sco_btproto;
	LIST_INSERT_HEAD(&sco_pcb, pcb, sp_next);
	stub_sco_newconn_count++;

	return pcb;
}

static void
stub_sco_connected(void *arg)
{
}

static void
stub_sco_disconnected(void *arg, int err)
{
	stub_sco_disconnected_count++;
}

int
sco_detach(struct sco_pcb **handle)
{
	struct sco_pcb *pcb = *handle;

	*handle = NULL;
	if (pcb == NULL)
		return EINVAL;

	if (pcb != &stub_listener) {
		LIST_REMOVE(pcb, sp_next);
		kfree(pcb, M_BLUETOOTH);
	}
	return 0;
}