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

📄 hciemu.c

📁 这是Linux环境下的蓝牙源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	case OCF_READ_LOCAL_NAME:		ln.status = 0x00;		memcpy(ln.name, vdev.name, sizeof(ln.name));		command_complete(ogf, ocf, sizeof(ln), &ln);		break;	case OCF_WRITE_CONN_ACCEPT_TIMEOUT:	case OCF_WRITE_PAGE_TIMEOUT:		status = 0x00;		command_complete(ogf, ocf, 1, &status);		break;	case OCF_WRITE_SCAN_ENABLE:		status = scan_enable(data);		command_complete(ogf, ocf, 1, &status);		break;	case OCF_WRITE_AUTH_ENABLE:		status = 0x00;		command_complete(ogf, ocf, 1, &status);		break;	case OCF_WRITE_ENCRYPT_MODE:		status = 0x00;		command_complete(ogf, ocf, 1, &status);		break;	case OCF_READ_CLASS_OF_DEV:		cd.status = 0x00;		memcpy(cd.dev_class, vdev.dev_class, 3);		command_complete(ogf, ocf, sizeof(cd), &cd);		break;	case OCF_WRITE_CLASS_OF_DEV:		status = 0x00;		memcpy(vdev.dev_class, data, 3);		command_complete(ogf, ocf, 1, &status);		break;	case OCF_READ_INQUIRY_MODE:		im.status = 0x00;		im.mode = vdev.inq_mode;		command_complete(ogf, ocf, sizeof(im), &im);		break;	case OCF_WRITE_INQUIRY_MODE:		status = 0x00;		vdev.inq_mode = data[0];		command_complete(ogf, ocf, 1, &status);		break;	case OCF_READ_EXT_INQUIRY_RESPONSE:		ir.status = 0x00;		ir.fec = vdev.eir_fec;		memcpy(ir.data, vdev.eir_data, 240);		command_complete(ogf, ocf, sizeof(ir), &ir);		break;	case OCF_WRITE_EXT_INQUIRY_RESPONSE:		status = 0x00;		vdev.eir_fec = data[0];		memcpy(vdev.eir_data, data + 1, 240);		command_complete(ogf, ocf, 1, &status);		break;	default:		status = 0x01;		command_complete(ogf, ocf, 1, &status);		break;	}}static void inline hci_info_param(uint16_t ocf, int plen, uint8_t *data){	read_local_version_rp lv;	read_local_features_rp lf;	read_local_ext_features_rp ef;	read_buffer_size_rp bs;	read_bd_addr_rp ba;	uint8_t status;	const uint16_t ogf = OGF_INFO_PARAM;	switch (ocf) {	case OCF_READ_LOCAL_VERSION:		lv.status = 0x00;		lv.hci_ver = 0x03;		lv.hci_rev = htobs(0x0000);		lv.lmp_ver = 0x03;		lv.manufacturer = htobs(29);		lv.lmp_subver = htobs(0x0000);		command_complete(ogf, ocf, sizeof(lv), &lv);		break;	case OCF_READ_LOCAL_FEATURES:		lf.status = 0x00;		memcpy(lf.features, vdev.features, 8);		command_complete(ogf, ocf, sizeof(lf), &lf);		break;	case OCF_READ_LOCAL_EXT_FEATURES:		ef.status = 0x00;		if (*data == 0) {			ef.page_num = 0;			ef.max_page_num = 0;			memcpy(ef.features, vdev.features, 8);		} else {			ef.page_num = *data;			ef.max_page_num = 0;			memset(ef.features, 0, 8);		}		command_complete(ogf, ocf, sizeof(ef), &ef);		break;	case OCF_READ_BUFFER_SIZE:		bs.status = 0x00;		bs.acl_mtu = htobs(VHCI_ACL_MTU);		bs.sco_mtu = 0;		bs.acl_max_pkt = htobs(VHCI_ACL_MAX_PKT);		bs.sco_max_pkt = htobs(0);		command_complete(ogf, ocf, sizeof(bs), &bs);		break;	case OCF_READ_BD_ADDR:		ba.status = 0x00;		bacpy(&ba.bdaddr, &vdev.bdaddr);		command_complete(ogf, ocf, sizeof(ba), &ba);		break;	default:		status = 0x01;		command_complete(ogf, ocf, 1, &status);		break;	}}static void hci_command(uint8_t *data){	hci_command_hdr *ch;	uint8_t *ptr = data;	uint16_t ogf, ocf;	ch = (hci_command_hdr *) ptr;	ptr += HCI_COMMAND_HDR_SIZE;	ch->opcode = btohs(ch->opcode);	ogf = cmd_opcode_ogf(ch->opcode);	ocf = cmd_opcode_ocf(ch->opcode);	switch (ogf) {	case OGF_LINK_CTL:		hci_link_control(ocf, ch->plen, ptr);		break;	case OGF_LINK_POLICY:		hci_link_policy(ocf, ch->plen, ptr);		break;	case OGF_HOST_CTL:		hci_host_control(ocf, ch->plen, ptr);		break;	case OGF_INFO_PARAM:		hci_info_param(ocf, ch->plen, ptr);		break;	}}static void hci_acl_data(uint8_t *data){	hci_acl_hdr *ah = (void *) data;	struct vhci_conn *conn;	uint16_t handle;	int fd;	handle = acl_handle(btohs(ah->handle));	if (handle > VHCI_MAX_CONN || !(conn = vconn[handle - 1])) {		syslog(LOG_ERR, "Bad connection handle %d", handle);		return;	}	fd = g_io_channel_unix_get_fd(conn->chan);	if (write_n(fd, data, btohs(ah->dlen) + HCI_ACL_HDR_SIZE) < 0) {		close_connection(conn);		return;	}	if (++vdev.acl_cnt > VHCI_ACL_MAX_PKT - 1) {		/* Send num of complete packets event */		num_completed_pkts(conn);		vdev.acl_cnt = 0;	}}static gboolean io_acl_data(GIOChannel *chan, GIOCondition cond, gpointer data){	struct vhci_conn *conn = (struct vhci_conn *) data;	unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr;	hci_acl_hdr *ah;	uint16_t flags;	int fd, err, len;	if (cond & G_IO_NVAL) {		g_io_channel_unref(chan);		return FALSE;	}	if (cond & G_IO_HUP) {		close_connection(conn);		return FALSE;	}	fd = g_io_channel_unix_get_fd(chan);	ptr = buf + 1;	if (read_n(fd, ptr, HCI_ACL_HDR_SIZE) <= 0) {		close_connection(conn);		return FALSE;	}	ah = (void *) ptr;	ptr += HCI_ACL_HDR_SIZE;	len = btohs(ah->dlen);	if (read_n(fd, ptr, len) <= 0) {		close_connection(conn);		return FALSE;	}	buf[0] = HCI_ACLDATA_PKT;	flags = acl_flags(btohs(ah->handle));	ah->handle = htobs(acl_handle_pack(conn->handle, flags));	len += HCI_ACL_HDR_SIZE + 1;	write_snoop(vdev.dd, HCI_ACLDATA_PKT, 1, buf, len);	err = write(vdev.fd, buf, len);	return TRUE;}static gboolean io_conn_ind(GIOChannel *chan, GIOCondition cond, gpointer data){	struct vhci_link_info info;	struct vhci_conn *conn;	struct sockaddr_in sa;	socklen_t len;	int sk, nsk, h;	if (cond & G_IO_NVAL)		return FALSE;	sk = g_io_channel_unix_get_fd(chan);	len = sizeof(sa);	if ((nsk = accept(sk, (struct sockaddr *) &sa, &len)) < 0)		return TRUE;	if (read_n(nsk, &info, sizeof(info)) < 0) {		syslog(LOG_ERR, "Can't read link info");		return TRUE;	}	if (!(conn = malloc(sizeof(*conn)))) {		syslog(LOG_ERR, "Can't alloc new connection");		close(nsk);		return TRUE;	}	bacpy(&conn->dest, &info.bdaddr);	for (h = 0; h < VHCI_MAX_CONN; h++)		if (!vconn[h])			goto accepted;	syslog(LOG_ERR, "Too many connections");	free(conn);	close(nsk);	return TRUE;accepted:	vconn[h] = conn;	conn->handle = h + 1;	conn->chan = g_io_channel_unix_new(nsk);	connect_request(conn);	return TRUE;}static gboolean io_hci_data(GIOChannel *chan, GIOCondition cond, gpointer data){	unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr;	int type;	gsize len;	GIOError err;	ptr = buf;	if ((err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len))) {		if (err == G_IO_ERROR_AGAIN)			return TRUE;		syslog(LOG_ERR, "Read failed: %s (%d)", strerror(errno), errno);		g_io_channel_unref(chan);		g_main_loop_quit(event_loop);		return FALSE;	}	type = *ptr++;	write_snoop(vdev.dd, type, 0, buf, len);	switch (type) {	case HCI_COMMAND_PKT:		hci_command(ptr);		break;	case HCI_ACLDATA_PKT:		hci_acl_data(ptr);		break;	default:		syslog(LOG_ERR, "Unknown packet type 0x%2.2x", type);		break;	}	return TRUE;}static int getbdaddrbyname(char *str, bdaddr_t *ba){	int i, n, len;	len = strlen(str);	/* Check address format */	for (i = 0, n = 0; i < len; i++)		if (str[i] == ':')			n++;	if (n == 5) {		/* BD address */		baswap(ba, strtoba(str));		return 0;	}	if (n == 1) {		/* IP address + port */		struct hostent *hent;		bdaddr_t b;		char *ptr;		ptr = strchr(str, ':');		*ptr++ = 0;		if (!(hent = gethostbyname(str))) {			fprintf(stderr, "Can't resolve %s\n", str);			return -2;		}		memcpy(&b, hent->h_addr, 4);		*(uint16_t *) (&b.b[4]) = htons(atoi(ptr));		baswap(ba, &b);		return 0;	}	fprintf(stderr, "Invalid address format\n");	return -1;}static void rewrite_bdaddr(unsigned char *buf, int len, bdaddr_t *bdaddr){	hci_event_hdr *eh;	unsigned char *ptr = buf;	int type;	if (!bdaddr)		return;	if (!bacmp(bdaddr, BDADDR_ANY))		return;	type = *ptr++;	switch (type) {	case HCI_EVENT_PKT:		eh = (hci_event_hdr *) ptr;		ptr += HCI_EVENT_HDR_SIZE;		if (eh->evt == EVT_CMD_COMPLETE) {			evt_cmd_complete *cc = (void *) ptr;			ptr += EVT_CMD_COMPLETE_SIZE;			if (cc->opcode == htobs(cmd_opcode_pack(OGF_INFO_PARAM,						OCF_READ_BD_ADDR))) {				bacpy((bdaddr_t *) (ptr + 1), bdaddr);			}		}		break;	}}static int run_proxy(int fd, int dev, bdaddr_t *bdaddr){	unsigned char buf[HCI_MAX_FRAME_SIZE + 1];	struct hci_dev_info di;	struct hci_filter flt;	struct pollfd p[2];	int dd, err, len, need_raw;	dd = hci_open_dev(dev);	if (dd < 0) {		syslog(LOG_ERR, "Can't open device hci%d: %s (%d)",						dev, strerror(errno), errno);		return 1;	}	if (hci_devinfo(dev, &di) < 0) {		syslog(LOG_ERR, "Can't get device info for hci%d: %s (%d)",						dev, strerror(errno), errno);		hci_close_dev(dd);		return 1;	}	need_raw = !hci_test_bit(HCI_RAW, &di.flags);	hci_filter_clear(&flt);	hci_filter_all_ptypes(&flt);	hci_filter_all_events(&flt);	if (setsockopt(dd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {		syslog(LOG_ERR, "Can't set filter for hci%d: %s (%d)",						dev, strerror(errno), errno);		hci_close_dev(dd);		return 1;	}	if (need_raw) {		if (ioctl(dd, HCISETRAW, 1) < 0) {			syslog(LOG_ERR, "Can't set raw mode on hci%d: %s (%d)",						dev, strerror(errno), errno);			hci_close_dev(dd);			return 1;		}	}	p[0].fd = fd;	p[0].events = POLLIN;	p[1].fd = dd;	p[1].events = POLLIN;	while (!__io_canceled) {		p[0].revents = 0;		p[1].revents = 0;		err = poll(p, 2, 500);		if (err < 0)			break;		if (!err)			continue;		if (p[0].revents & POLLIN) {			len = read(fd, buf, sizeof(buf));			if (len > 0) {				rewrite_bdaddr(buf, len, bdaddr);				err = write(dd, buf, len);			}		}		if (p[1].revents & POLLIN) {			len = read(dd, buf, sizeof(buf));			if (len > 0) {				rewrite_bdaddr(buf, len, bdaddr);				err = write(fd, buf, len);			}		}	}	if (need_raw) {		if (ioctl(dd, HCISETRAW, 0) < 0)			syslog(LOG_ERR, "Can't clear raw mode on hci%d: %s (%d)",						dev, strerror(errno), errno);	}	hci_close_dev(dd);	syslog(LOG_INFO, "Exit");	return 0;}static void usage(void){	printf("hciemu - HCI emulator ver %s\n", VERSION);	printf("Usage: \n");	printf("\thciemu [-n] local_address\n");}static struct option main_options[] = {	{ "device",	1, 0, 'd' },	{ "bdaddr",	1, 0, 'b' },	{ "snoop",	1, 0, 's' },	{ "nodetach",	0, 0, 'n' },	{ "help",	0, 0, 'h' },	{ 0 }};int main(int argc, char *argv[]){	struct sigaction sa;	GIOChannel *dev_io;	char *device = NULL, *snoop = NULL;	bdaddr_t bdaddr;	int fd, dd, opt, detach = 1, dev = -1;	bacpy(&bdaddr, BDADDR_ANY);	while ((opt=getopt_long(argc, argv, "d:b:s:nh", main_options, NULL)) != EOF) {		switch(opt) {		case 'd':			device = strdup(optarg);			break;		case 'b':			str2ba(optarg, &bdaddr);			break;		case 's':			snoop = strdup(optarg);			break;		case 'n':			detach = 0;			break;		case 'h':		default:			usage();			exit(0);		}	}	argc -= optind;	argv += optind;	optind = 0;	if (argc < 1) {		usage();		exit(1);	}	if (strlen(argv[0]) > 3 && !strncasecmp(argv[0], "hci", 3)) {		dev = hci_devid(argv[0]);		if (dev < 0) {			perror("Invalid device");			exit(1);		}	} else {		if (getbdaddrbyname(argv[0], &vdev.bdaddr) < 0)			exit(1);	}	if (detach) {		if (daemon(0, 0)) {			perror("Can't start daemon");			exit(1);		}	}	/* Start logging to syslog and stderr */	openlog("hciemu", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);	syslog(LOG_INFO, "HCI emulation daemon ver %s started", VERSION);	memset(&sa, 0, sizeof(sa));	sa.sa_flags   = SA_NOCLDSTOP;	sa.sa_handler = SIG_IGN;	sigaction(SIGCHLD, &sa, NULL);	sigaction(SIGPIPE, &sa, NULL);	sa.sa_handler = sig_term;	sigaction(SIGTERM, &sa, NULL);	sigaction(SIGINT,  &sa, NULL);	io_init();	if (!device && dev >= 0)		device = strdup(GHCI_DEV);	/* Open and create virtual HCI device */	if (device) {		fd = open(device, O_RDWR);		if (fd < 0) {			syslog(LOG_ERR, "Can't open device %s: %s (%d)",						device, strerror(errno), errno);			free(device);			exit(1);		}		free(device);	} else {		fd = open(VHCI_DEV, O_RDWR);		if (fd < 0) {			fd = open(VHCI_UDEV, O_RDWR);			if (fd < 0) {				syslog(LOG_ERR, "Can't open device %s: %s (%d)",						VHCI_DEV, strerror(errno), errno);				exit(1);			}		}	}	/* Create snoop file */	if (snoop) {		dd = create_snoop(snoop);		if (dd < 0)			syslog(LOG_ERR, "Can't create snoop file %s: %s (%d)",						snoop, strerror(errno), errno);		free(snoop);	} else		dd = -1;	/* Create event loop */	event_loop = g_main_loop_new(NULL, FALSE);	if (dev >= 0)		return run_proxy(fd, dev, &bdaddr);	/* Device settings */	vdev.features[0] = 0xff;	vdev.features[1] = 0xff;	vdev.features[2] = 0x8f;	vdev.features[3] = 0xfe;	vdev.features[4] = 0x9b;	vdev.features[5] = 0xf9;	vdev.features[6] = 0x01;	vdev.features[7] = 0x80;	memset(vdev.name, 0, sizeof(vdev.name));	strncpy((char *) vdev.name, "BlueZ (Virtual HCI)", sizeof(vdev.name));	vdev.dev_class[0] = 0x00;	vdev.dev_class[1] = 0x00;	vdev.dev_class[2] = 0x00;	vdev.inq_mode = 0x00;	vdev.eir_fec = 0x00;	memset(vdev.eir_data, 0, sizeof(vdev.eir_data));	vdev.fd = fd;	vdev.dd = dd;	dev_io = g_io_channel_unix_new(fd);	g_io_add_watch(dev_io, G_IO_IN, io_hci_data, NULL);	setpriority(PRIO_PROCESS, 0, -19);	/* Start event processor */	g_main_loop_run(event_loop);	close(fd);	if (dd >= 0)		close(dd);	syslog(LOG_INFO, "Exit");	return 0;}

⌨️ 快捷键说明

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