Diff between 6930cd12df8d3f5ee0bc92f785da590d02529bee and 096799fd522f388de4501d0bfafda468a8297e2b

Changed Files

File Additions Deletions Status
Makefile.tools +1 -0 modified
emulator/main.c +17 -2 modified
emulator/serial.c +234 -0 added
emulator/serial.h +37 -0 added

Full Patch

diff --git a/Makefile.tools b/Makefile.tools
index c24bdf7..d4ed087 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -50,6 +50,7 @@ emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
 				src/shared/timeout-mainloop.c \
 				src/shared/util.h src/shared/util.c \
 				src/shared/crypto.h src/shared/crypto.c \
+				emulator/serial.h emulator/serial.c \
 				emulator/server.h emulator/server.c \
 				emulator/vhci.h emulator/vhci.c \
 				emulator/btdev.h emulator/btdev.c \
diff --git a/emulator/main.c b/emulator/main.c
index bd2a29a..f9857d0 100644
--- a/emulator/main.c
+++ b/emulator/main.c
@@ -32,6 +32,7 @@
 #include <getopt.h>
 
 #include "monitor/mainloop.h"
+#include "serial.h"
 #include "server.h"
 #include "vhci.h"
 #include "amp.h"
@@ -53,6 +54,7 @@ static void usage(void)
 		"Usage:\n");
 	printf("\tbtvirt [options]\n");
 	printf("options:\n"
+		"\t-S                    Create local serial port\n"
 		"\t-s                    Create local server sockets\n"
 		"\t-l [num]              Number of local controllers\n"
 		"\t-L                    Create LE only controller\n"
@@ -62,6 +64,7 @@ static void usage(void)
 }
 
 static const struct option main_options[] = {
+	{ "serial",  no_argument,       NULL, 'S' },
 	{ "server",  no_argument,       NULL, 's' },
 	{ "local",   optional_argument, NULL, 'l' },
 	{ "le",      no_argument,       NULL, 'L' },
@@ -82,6 +85,7 @@ int main(int argc, char *argv[])
 	struct server *server4;
 	struct server *server5;
 	bool server_enabled = false;
+	bool serial_enabled = false;
 	int letest_count = 0;
 	int amptest_count = 0;
 	int vhci_count = 0;
@@ -94,12 +98,15 @@ int main(int argc, char *argv[])
 	for (;;) {
 		int opt;
 
-		opt = getopt_long(argc, argv, "sl::LBAUTvh",
+		opt = getopt_long(argc, argv, "Ssl::LBAUTvh",
 						main_options, NULL);
 		if (opt < 0)
 			break;
 
 		switch (opt) {
+		case 'S':
+			serial_enabled = true;
+			break;
 		case 's':
 			server_enabled = true;
 			break;
@@ -142,7 +149,7 @@ int main(int argc, char *argv[])
 	}
 
 	if (letest_count < 1 && amptest_count < 1 &&
-					vhci_count < 1 && !server_enabled) {
+			vhci_count < 1 && !server_enabled && !serial_enabled) {
 		fprintf(stderr, "No emulator specified\n");
 		return EXIT_FAILURE;
 	}
@@ -185,6 +192,14 @@ int main(int argc, char *argv[])
 		}
 	}
 
+	if (serial_enabled) {
+		struct serial *serial;
+
+		serial = serial_open(SERIAL_TYPE_BREDRLE);
+		if (!serial)
+			fprintf(stderr, "Failed to open serial emulation\n");
+	}
+
 	if (server_enabled) {
 		server1 = server_open_unix(SERVER_TYPE_BREDRLE,
 						"/tmp/bt-server-bredrle");
diff --git a/emulator/serial.c b/emulator/serial.c
new file mode 100644
index 0000000..d87a700
--- /dev/null
+++ b/emulator/serial.c
@@ -0,0 +1,234 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2014  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; 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 <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/epoll.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+
+#include "monitor/mainloop.h"
+#include "btdev.h"
+#include "serial.h"
+
+#define uninitialized_var(x) x = x
+
+struct serial {
+	enum serial_type type;
+	uint16_t id;
+	int fd;
+	char path[PATH_MAX];
+	struct btdev *btdev;
+	uint8_t *pkt_data;
+	uint8_t pkt_type;
+	uint16_t pkt_expect;
+	uint16_t pkt_len;
+	uint16_t pkt_offset;
+};
+
+static void serial_destroy(void *user_data)
+{
+	struct serial *serial = user_data;
+
+	btdev_destroy(serial->btdev);
+
+	close(serial->fd);
+
+	free(serial);
+}
+
+static void serial_write_callback(const void *data, uint16_t len,
+							void *user_data)
+{
+	struct serial *serial = user_data;
+	ssize_t written;
+
+	written = write(serial->fd, data, len);
+	if (written < 0)
+		return;
+}
+
+static void serial_read_callback(int fd, uint32_t events, void *user_data)
+{
+	struct serial *serial = user_data;
+	static uint8_t buf[4096];
+	uint8_t *ptr = buf;
+	ssize_t len;
+	uint16_t count;
+
+	if (events & (EPOLLERR | EPOLLHUP)) {
+		mainloop_remove_fd(serial->fd);
+		return;
+	}
+
+again:
+	len = read(serial->fd, buf + serial->pkt_offset,
+			sizeof(buf) - serial->pkt_offset);
+	if (len < 0) {
+		if (errno == EAGAIN)
+			goto again;
+		return;
+	}
+
+	if (!serial->btdev)
+		return;
+
+	count = serial->pkt_offset + len;
+
+	while (count > 0) {
+		hci_command_hdr *cmd_hdr;
+
+		if (!serial->pkt_data) {
+			serial->pkt_type = ptr[0];
+
+			switch (serial->pkt_type) {
+			case HCI_COMMAND_PKT:
+				if (count < HCI_COMMAND_HDR_SIZE + 1) {
+					serial->pkt_offset += len;
+					return;
+				}
+				cmd_hdr = (hci_command_hdr *) (ptr + 1);
+				serial->pkt_expect = HCI_COMMAND_HDR_SIZE +
+							cmd_hdr->plen + 1;
+				serial->pkt_data = malloc(serial->pkt_expect);
+				serial->pkt_len = 0;
+				break;
+			default:
+				printf("packet error\n");
+				return;
+			}
+
+			serial->pkt_offset = 0;
+		}
+
+		if (count >= serial->pkt_expect) {
+			memcpy(serial->pkt_data + serial->pkt_len,
+						ptr, serial->pkt_expect);
+			ptr += serial->pkt_expect;
+			count -= serial->pkt_expect;
+
+			btdev_receive_h4(serial->btdev, serial->pkt_data,
+					serial->pkt_len + serial->pkt_expect);
+
+			free(serial->pkt_data);
+			serial->pkt_data = NULL;
+		} else {
+			memcpy(serial->pkt_data + serial->pkt_len, ptr, count);
+			serial->pkt_len += count;
+			serial->pkt_expect -= count;
+			count = 0;
+		}
+	}
+}
+
+struct serial *serial_open(enum serial_type type)
+{
+	struct serial *serial;
+	enum btdev_type uninitialized_var(dev_type);
+
+	serial = malloc(sizeof(*serial));
+	if (!serial)
+		return NULL;
+
+	memset(serial, 0, sizeof(*serial));
+	serial->type = type;
+	serial->id = 0x42;
+
+	serial->fd = getpt();
+	if (serial->fd < 0) {
+		perror("Failed to get master pseudo terminal");
+		free(serial);
+		return NULL;
+	}
+
+	if (grantpt(serial->fd) < 0) {
+		perror("Failed to grant slave pseudo terminal");
+		close(serial->fd);
+		free(serial);
+		return NULL;
+	}
+
+	if (unlockpt(serial->fd) < 0) {
+		perror("Failed to unlock slave pseudo terminal");
+		close(serial->fd);
+		free(serial);
+		return NULL;
+	}
+
+	ptsname_r(serial->fd, serial->path, sizeof(serial->path));
+
+	printf("Pseudo terminal at %s\n", serial->path);
+
+	switch (serial->type) {
+	case SERIAL_TYPE_BREDRLE:
+		dev_type = BTDEV_TYPE_BREDRLE;
+		break;
+	case SERIAL_TYPE_BREDR:
+		dev_type = BTDEV_TYPE_BREDR;
+		break;
+	case SERIAL_TYPE_LE:
+		dev_type = BTDEV_TYPE_LE;
+		break;
+	case SERIAL_TYPE_AMP:
+		dev_type = BTDEV_TYPE_AMP;
+		break;
+	}
+
+	serial->btdev = btdev_create(type, serial->id);
+	if (!serial->btdev) {
+		close(serial->fd);
+		free(serial);
+		return NULL;
+	}
+
+	btdev_set_send_handler(serial->btdev, serial_write_callback, serial);
+
+	if (mainloop_add_fd(serial->fd, EPOLLIN, serial_read_callback,
+						serial, serial_destroy) < 0) {
+		btdev_destroy(serial->btdev);
+		close(serial->fd);
+		free(serial);
+		return NULL;
+	}
+
+	return serial;
+}
+
+void serial_close(struct serial *serial)
+{
+	if (!serial)
+		return;
+
+	mainloop_remove_fd(serial->fd);
+}
diff --git a/emulator/serial.h b/emulator/serial.h
new file mode 100644
index 0000000..4e5a56f
--- /dev/null
+++ b/emulator/serial.h
@@ -0,0 +1,37 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2014  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+
+enum serial_type {
+	SERIAL_TYPE_BREDRLE,
+	SERIAL_TYPE_BREDR,
+	SERIAL_TYPE_LE,
+	SERIAL_TYPE_AMP,
+};
+
+struct serial;
+
+struct serial *serial_open(enum serial_type type);
+void serial_close(struct serial *serial);