⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hciemu.c

📁 这是Linux环境下的蓝牙源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * *  BlueZ - Bluetooth protocol stack for Linux * *  Copyright (C) 2000-2002  Maxim Krasnyansky <maxk@qualcomm.com> *  Copyright (C) 2003-2008  Marcel Holtmann <marcel@holtmann.org> * * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA * */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <errno.h>#include <ctype.h>#include <fcntl.h>#include <unistd.h>#include <stdlib.h>#include <stdint.h>#include <string.h>#include <signal.h>#include <getopt.h>#include <syslog.h>#include <sys/time.h>#include <sys/stat.h>#include <sys/poll.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <sys/resource.h>#include <bluetooth/bluetooth.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include <netdb.h>#include <glib.h>#if __BYTE_ORDER == __LITTLE_ENDIANstatic inline uint64_t ntoh64(uint64_t n){	uint64_t h;	uint64_t tmp = ntohl(n & 0x00000000ffffffff);	h = ntohl(n >> 32);	h |= tmp << 32;	return h;}#elif __BYTE_ORDER == __BIG_ENDIAN#define ntoh64(x) (x)#else#error "Unknown byte order"#endif#define hton64(x) ntoh64(x)#define GHCI_DEV		"/dev/ghci"#define VHCI_DEV		"/dev/vhci"#define VHCI_UDEV		"/dev/hci_vhci"#define VHCI_MAX_CONN		12#define VHCI_ACL_MTU		192#define VHCI_ACL_MAX_PKT	8struct vhci_device {	uint8_t		features[8];	uint8_t		name[248];	uint8_t		dev_class[3];	uint8_t		inq_mode;	uint8_t		eir_fec;	uint8_t		eir_data[240];	uint16_t	acl_cnt;	bdaddr_t	bdaddr;	int		fd;	int		dd;	GIOChannel	*scan;};struct vhci_conn {	bdaddr_t	dest;	uint16_t	handle;	GIOChannel	*chan;};struct vhci_link_info {	bdaddr_t	bdaddr;	uint8_t		dev_class[3];	uint8_t		link_type;	uint8_t		role;} __attribute__ ((packed));static struct vhci_device vdev;static struct vhci_conn *vconn[VHCI_MAX_CONN];struct btsnoop_hdr {	uint8_t		id[8];		/* Identification Pattern */	uint32_t	version;	/* Version Number = 1 */	uint32_t	type;		/* Datalink Type */} __attribute__ ((packed));#define BTSNOOP_HDR_SIZE (sizeof(struct btsnoop_hdr))struct btsnoop_pkt {	uint32_t	size;		/* Original Length */	uint32_t	len;		/* Included Length */	uint32_t	flags;		/* Packet Flags */	uint32_t	drops;		/* Cumulative Drops */	uint64_t	ts;		/* Timestamp microseconds */	uint8_t		data[0];	/* Packet Data */} __attribute__ ((packed));#define BTSNOOP_PKT_SIZE (sizeof(struct btsnoop_pkt))static uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 };static GMainLoop *event_loop;static volatile sig_atomic_t __io_canceled;static inline void io_init(void){	__io_canceled = 0;}static inline void io_cancel(void){	__io_canceled = 1;}static void sig_term(int sig){	io_cancel();	g_main_loop_quit(event_loop);}static gboolean io_acl_data(GIOChannel *chan, GIOCondition cond, gpointer data);static gboolean io_conn_ind(GIOChannel *chan, GIOCondition cond, gpointer data);static gboolean io_hci_data(GIOChannel *chan, GIOCondition cond, gpointer data);static inline int read_n(int fd, void *buf, int len){	register int w, t = 0;	while (!__io_canceled && len > 0) {		if ((w = read(fd, buf, len)) < 0 ){			if( errno == EINTR || errno == EAGAIN )				continue;			return -1;		}		if (!w)			return 0;		len -= w; buf += w; t += w;	}	return t;}/* Write exactly len bytes (Signal safe)*/static inline int write_n(int fd, void *buf, int len){	register int w, t = 0;	while (!__io_canceled && len > 0) {		if ((w = write(fd, buf, len)) < 0 ){			if( errno == EINTR || errno == EAGAIN )				continue;			return -1;		}		if (!w)			return 0;		len -= w; buf += w; t += w;	}	return t;}static int create_snoop(char *file){	struct btsnoop_hdr hdr;	int fd, len;	fd = open(file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);	if (fd < 0)		return fd;	memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));	hdr.version = htonl(1);	hdr.type = htonl(1002);	len = write(fd, &hdr, BTSNOOP_HDR_SIZE);	if (len < 0) {		close(fd);		return -EIO;	}	if (len != BTSNOOP_HDR_SIZE) {		close(fd);		return -1;	}	return fd;}static int write_snoop(int fd, int type, int incoming, unsigned char *buf, int len){	struct btsnoop_pkt pkt;	struct timeval tv;	uint32_t size = len;	uint64_t ts;	int err;	if (fd < 0)		return -1;	memset(&tv, 0, sizeof(tv));	gettimeofday(&tv, NULL);	ts = (tv.tv_sec - 946684800ll) * 1000000ll + tv.tv_usec;	pkt.size = htonl(size);	pkt.len  = pkt.size;	pkt.flags = ntohl(incoming & 0x01);	pkt.drops = htonl(0);	pkt.ts = hton64(ts + 0x00E03AB44A676000ll);	if (type == HCI_COMMAND_PKT || type == HCI_EVENT_PKT)		pkt.flags |= ntohl(0x02);	err = write(fd, &pkt, BTSNOOP_PKT_SIZE);	err = write(fd, buf, size);	return 0;}static struct vhci_conn *conn_get_by_bdaddr(bdaddr_t *ba){	register int i;	for (i = 0; i < VHCI_MAX_CONN; i++)		if (!bacmp(&vconn[i]->dest, ba))			return vconn[i];	return NULL;}static void command_status(uint16_t ogf, uint16_t ocf, uint8_t status){	uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;	evt_cmd_status *cs;	hci_event_hdr *he;	/* Packet type */	*ptr++ = HCI_EVENT_PKT;	/* Event header */	he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;	he->evt  = EVT_CMD_STATUS;	he->plen = EVT_CMD_STATUS_SIZE;	cs = (void *) ptr; ptr += EVT_CMD_STATUS_SIZE;	cs->status = status;	cs->ncmd   = 1;	cs->opcode = htobs(cmd_opcode_pack(ogf, ocf));	write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);	if (write(vdev.fd, buf, ptr - buf) < 0)		syslog(LOG_ERR, "Can't send event: %s(%d)",						strerror(errno), errno);}static void command_complete(uint16_t ogf, uint16_t ocf, int plen, void *data){	uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;	evt_cmd_complete *cc;	hci_event_hdr *he;	/* Packet type */	*ptr++ = HCI_EVENT_PKT;	/* Event header */	he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;	he->evt  = EVT_CMD_COMPLETE;	he->plen = EVT_CMD_COMPLETE_SIZE + plen; 	cc = (void *) ptr; ptr += EVT_CMD_COMPLETE_SIZE;	cc->ncmd = 1;	cc->opcode = htobs(cmd_opcode_pack(ogf, ocf));	if (plen) {		memcpy(ptr, data, plen);		ptr += plen;	}	write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);	if (write(vdev.fd, buf, ptr - buf) < 0)		syslog(LOG_ERR, "Can't send event: %s(%d)",						strerror(errno), errno);}static void connect_request(struct vhci_conn *conn){	uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;	evt_conn_request *cr;	hci_event_hdr *he;	/* Packet type */	*ptr++ = HCI_EVENT_PKT;	/* Event header */	he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;	he->evt  = EVT_CONN_REQUEST;	he->plen = EVT_CONN_REQUEST_SIZE; 	cr = (void *) ptr; ptr += EVT_CONN_REQUEST_SIZE;	bacpy(&cr->bdaddr, &conn->dest);	memset(&cr->dev_class, 0, sizeof(cr->dev_class));	cr->link_type = ACL_LINK;	write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);	if (write(vdev.fd, buf, ptr - buf) < 0)		syslog(LOG_ERR, "Can't send event: %s (%d)",						strerror(errno), errno);}static void connect_complete(struct vhci_conn *conn){	uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;	evt_conn_complete *cc;	hci_event_hdr *he;	/* Packet type */	*ptr++ = HCI_EVENT_PKT;	/* Event header */	he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;	he->evt  = EVT_CONN_COMPLETE;	he->plen = EVT_CONN_COMPLETE_SIZE; 	cc = (void *) ptr; ptr += EVT_CONN_COMPLETE_SIZE;	bacpy(&cc->bdaddr, &conn->dest);	cc->status = 0x00;	cc->handle = htobs(conn->handle);	cc->link_type = ACL_LINK;	cc->encr_mode = 0x00;	write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);	if (write(vdev.fd, buf, ptr - buf) < 0)		syslog(LOG_ERR, "Can't send event: %s (%d)",						strerror(errno), errno);}static void disconn_complete(struct vhci_conn *conn){	uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;	evt_disconn_complete *dc;	hci_event_hdr *he;	/* Packet type */	*ptr++ = HCI_EVENT_PKT;	/* Event header */	he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;	he->evt  = EVT_DISCONN_COMPLETE;	he->plen = EVT_DISCONN_COMPLETE_SIZE;	dc = (void *) ptr; ptr += EVT_DISCONN_COMPLETE_SIZE;	dc->status = 0x00;	dc->handle = htobs(conn->handle);	dc->reason = 0x00;	write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);	if (write(vdev.fd, buf, ptr - buf) < 0)		syslog(LOG_ERR, "Can't send event: %s (%d)",						strerror(errno), errno);	vdev.acl_cnt = 0;}static void num_completed_pkts(struct vhci_conn *conn){	uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;	evt_num_comp_pkts *np;	hci_event_hdr *he;	/* Packet type */	*ptr++ = HCI_EVENT_PKT;	/* Event header */	he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;	he->evt  = EVT_NUM_COMP_PKTS;	he->plen = EVT_NUM_COMP_PKTS_SIZE;	np = (void *) ptr; ptr += EVT_NUM_COMP_PKTS_SIZE;	np->num_hndl = 1;	*((uint16_t *) ptr) = htobs(conn->handle); ptr += 2;	*((uint16_t *) ptr) = htobs(vdev.acl_cnt); ptr += 2;	write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);	if (write(vdev.fd, buf, ptr - buf) < 0)		syslog(LOG_ERR, "Can't send event: %s (%d)",						strerror(errno), errno);}static int scan_enable(uint8_t *data){	struct sockaddr_in sa;	GIOChannel *sk_io;	bdaddr_t ba;	int sk, opt;	if (!(*data & SCAN_PAGE)) {		if (vdev.scan) {			g_io_channel_close(vdev.scan);			vdev.scan = NULL;		}		return 0;	}	if (vdev.scan)		return 0;	if ((sk = socket(AF_INET, SOCK_STREAM, 0)) < 0) {		syslog(LOG_ERR, "Can't create socket: %s (%d)",						strerror(errno), errno);		return 1;	}	opt = 1;	setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));	baswap(&ba, &vdev.bdaddr);	sa.sin_family = AF_INET;	sa.sin_addr.s_addr = *(uint32_t *) &ba;	sa.sin_port = *(uint16_t *) &ba.b[4];	if (bind(sk, (struct sockaddr *) &sa, sizeof(sa))) {		syslog(LOG_ERR, "Can't bind socket: %s (%d)",						strerror(errno), errno);		goto failed;	}	if (listen(sk, 10)) {		syslog(LOG_ERR, "Can't listen on socket: %s (%d)",						strerror(errno), errno);		goto failed;	}	sk_io = g_io_channel_unix_new(sk);	g_io_add_watch(sk_io, G_IO_IN | G_IO_NVAL, io_conn_ind, NULL);	vdev.scan = sk_io;	return 0;failed:	close(sk);	return 1;}static void accept_connection(uint8_t *data){	accept_conn_req_cp *cp = (void *) data;	struct vhci_conn *conn;	if (!(conn = conn_get_by_bdaddr(&cp->bdaddr)))		return;	connect_complete(conn);	g_io_add_watch(conn->chan, G_IO_IN | G_IO_NVAL | G_IO_HUP,			io_acl_data, (gpointer) conn);}static void close_connection(struct vhci_conn *conn){	syslog(LOG_INFO, "Closing connection %s handle %d",					batostr(&conn->dest), conn->handle);	g_io_channel_close(conn->chan);	g_io_channel_unref(conn->chan);	vconn[conn->handle - 1] = NULL;	disconn_complete(conn);	free(conn);}static void disconnect(uint8_t *data){	disconnect_cp *cp = (void *) data;	struct vhci_conn *conn;	uint16_t handle;	handle = btohs(cp->handle);	if (handle - 1 > VHCI_MAX_CONN)		return;	if (!(conn = vconn[handle-1]))		return;	close_connection(conn);}static void create_connection(uint8_t *data){	create_conn_cp *cp = (void *) data;	struct vhci_link_info info;	struct vhci_conn *conn;	struct sockaddr_in sa;	int h, sk, opt;	bdaddr_t ba;	for (h = 0; h < VHCI_MAX_CONN; h++)		if (!vconn[h])			goto do_connect;	syslog(LOG_ERR, "Too many connections");	return;do_connect:	if ((sk = socket(AF_INET, SOCK_STREAM, 0)) < 0) {		syslog(LOG_ERR, "Can't create socket: %s (%d)",						strerror(errno), errno);		return;	}	opt = 1;	setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));	baswap(&ba, &vdev.bdaddr);	sa.sin_family = AF_INET;	sa.sin_addr.s_addr = INADDR_ANY;	// *(uint32_t *) &ba;	sa.sin_port = 0;			// *(uint16_t *) &ba.b[4];	if (bind(sk, (struct sockaddr *) &sa, sizeof(sa))) {		syslog(LOG_ERR, "Can't bind socket: %s (%d)",						strerror(errno), errno);		close(sk);		return;	}	baswap(&ba, &cp->bdaddr);	sa.sin_family = AF_INET;	sa.sin_addr.s_addr = *(uint32_t *) &ba;	sa.sin_port = *(uint16_t *) &ba.b[4];	if (connect(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) {		syslog(LOG_ERR, "Can't connect: %s (%d)",						strerror(errno), errno);		close(sk);		return;	}	/* Send info */	memset(&info, 0, sizeof(info));	bacpy(&info.bdaddr, &vdev.bdaddr);	info.link_type = ACL_LINK;	info.role = 1;	write_n(sk, (void *) &info, sizeof(info));	if (!(conn = malloc(sizeof(*conn)))) {		syslog(LOG_ERR, "Can't alloc new connection: %s (%d)",						strerror(errno), errno);		close(sk);		return;	}	memcpy((uint8_t *) &ba, (uint8_t *) &sa.sin_addr, 4);	memcpy((uint8_t *) &ba.b[4], (uint8_t *) &sa.sin_port, 2);	baswap(&conn->dest, &ba);	vconn[h] = conn;	conn->handle = h + 1;	conn->chan = g_io_channel_unix_new(sk);	connect_complete(conn);	g_io_add_watch(conn->chan, G_IO_IN | G_IO_NVAL | G_IO_HUP,				io_acl_data, (gpointer) conn);	return;}static void inline hci_link_control(uint16_t ocf, int plen, uint8_t *data){	uint8_t status;	const uint16_t ogf = OGF_LINK_CTL;	switch (ocf) {	case OCF_CREATE_CONN:		command_status(ogf, ocf, 0x00);		create_connection(data);		break;	case OCF_ACCEPT_CONN_REQ:		command_status(ogf, ocf, 0x00);		accept_connection(data);		break;	case OCF_DISCONNECT:		command_status(ogf, ocf, 0x00);		disconnect(data);		break;	default:		status = 0x01;		command_complete(ogf, ocf, 1, &status);		break;	}}static void inline hci_link_policy(uint16_t ocf, int plen, uint8_t *data){	uint8_t status;	const uint16_t ogf = OGF_INFO_PARAM;	switch (ocf) {	default:		status = 0x01;		command_complete(ogf, ocf, 1, &status);		break;	}}static void inline hci_host_control(uint16_t ocf, int plen, uint8_t *data){	read_local_name_rp ln;	read_class_of_dev_rp cd;	read_inquiry_mode_rp im;	read_ext_inquiry_response_rp ir;	uint8_t status;	const uint16_t ogf = OGF_HOST_CTL;	switch (ocf) {	case OCF_RESET:		status = 0x00;		command_complete(ogf, ocf, 1, &status);		break;	case OCF_SET_EVENT_FLT:		status = 0x00;		command_complete(ogf, ocf, 1, &status);		break;	case OCF_CHANGE_LOCAL_NAME:		status = 0x00;		memcpy(vdev.name, data, sizeof(vdev.name));		command_complete(ogf, ocf, 1, &status);		break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -