⬢ DragonFlyBSD Kernel Audit
DF-5764 / stub.c
← back to finding ↓ download raw
/*
 * stub.c -- HCI/SCO-layer stubs for the l2pw_harness KLD (DF-5764).
 *
 * The production netbt files compiled VERBATIM into this module are
 *   l2cap_upper.c  (l2cap_send / l2cap_disconnect / l2cap_detach)
 *   l2cap_lower.c  (THE FILE UNDER AUDIT: l2cap_start / l2cap_close)
 *   l2cap_misc.c   (zones, cid alloc, request alloc/free)
 *   l2cap_signal.c (l2cap_send_disconnect_req et al.)
 *   hci_link.c     (hci_acl_send / hci_acl_start / hci_acl_complete /
 *                   hci_link_alloc / hci_link_free / hci_acl_close)
 * -- so the failure path under test (hci_acl_send's ENETDOWN branch,
 * hci_link.c:546-549) is production code, not a stub.
 *
 * Everything those files need from the layers we do NOT compile
 * (hci_event.c, hci_unit.c, hci_socket.c, bt_proto.c, sco_upper.c,
 * l2cap_socket.c) is provided here with the minimum faithful behaviour:
 *
 *   - bluetooth_debug (defined by hci_event.c in production): keep at 0
 *   - M_BLUETOOTH malloc type (bt_proto.c)
 *   - empty sco_pcb listener list (sco_upper.c) -- never matched
 *   - sco_detach(): symbol only, never called on our paths
 *   - hci_send_cmd(): symbol only (hci_acl_open/timeout paths we don't drive)
 *   - hci_output_acl(): fragment sink -- count + free (what the USB
 *     transport + controller would do with the fragment)
 *
 * The channel upper layer (what l2cap_socket.c provides in production)
 * is a fake btproto with counters.
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/systm.h>
#include <sys/types.h>
#include <net/if.h>

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

#include "l2uh.h"

/* defined by hci_event.c in production; keep debug prints OFF */
int bluetooth_debug = 0;

/* real malloc type lives in bt_proto.c which we do not compile in */
MALLOC_DEFINE(M_BLUETOOTH, "Bluetooth", "Bluetooth system memory");

/* empty SCO listener list (sco_upper.c) */
struct sco_pcb_list sco_pcb = LIST_HEAD_INITIALIZER(sco_pcb);

/* counters for the fake upper layer (what l2cap_socket.c would do) */
int stub_proto_disconnected_count;
int stub_proto_complete_count;
int stub_proto_connecting_count;

/* ACL fragments handed to the transport (hci_output_acl sink) */
int stub_acl_output_count;

static void stub_connecting(void *);
static void stub_connected(void *);
static void stub_disconnected(void *, int);
static void *stub_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
static void stub_complete(void *, int);
static void stub_linkmode(void *, int);
static void stub_input(void *, struct mbuf *);

const struct btproto stub_btproto = {
	stub_connecting,
	stub_connected,
	stub_disconnected,
	stub_newconn,
	stub_complete,
	stub_linkmode,
	stub_input,
};

static void
stub_connecting(void *arg)
{
	stub_proto_connecting_count++;
}

static void
stub_connected(void *arg)
{
}

static void
stub_disconnected(void *arg, int err)
{
	stub_proto_disconnected_count++;
}

static void *
stub_newconn(void *arg, struct sockaddr_bt *laddr, struct sockaddr_bt *raddr)
{
	return NULL;
}

static void
stub_complete(void *arg, int count)
{
	stub_proto_complete_count++;
}

static void
stub_linkmode(void *arg, int new)
{
}

static void
stub_input(void *arg, struct mbuf *m)
{
	m_freem(m);
}

/* ------------------------------------------------------------------ */
/* HCI-layer symbols used by the compiled production files */

int
hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *ptr, uint8_t len)
{
	/* symbol only: hci_acl_open()/hci_acl_timeout() paths are not driven */
	return 0;
}

void
hci_output_acl(struct hci_unit *unit, struct mbuf *m)
{
	/* the transport took the fragment */
	stub_acl_output_count++;
	m_freem(m);
}

int
sco_detach(struct sco_pcb **handle)
{
	/* symbol only, never called on our paths */
	return 0;
}

struct hci_unit *
hci_unit_lookup(bdaddr_t *bdaddr)
{
	/* symbol only (hci_unit.c in production), not on our paths */
	return NULL;
}

int
hci_route_lookup(bdaddr_t *laddr, bdaddr_t *raddr)
{
	/* symbol only (l2cap_connect() path, which the harness bypasses) */
	return 0;
}

struct hci_memo *
hci_memo_find(struct hci_unit *unit, bdaddr_t *bdaddr)
{
	/* symbol only (hci_unit.c): hci_acl_open() path, not driven */
	return NULL;
}

struct hci_memo *
hci_memo_new(struct hci_unit *unit, bdaddr_t *bdaddr)
{
	/* symbol only (hci_unit.c): hci_link_free() takes this only when
	 * hl_clock != 0; the rig's links never have one */
	return NULL;
}