/*
 *
 *  BlueZ - Bluetooth protocol stack for Linux
 *
 *  Copyright (C) 2011-2012  Intel Corporation
 *  Copyright (C) 2004-2010  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 <unistd.h>
#include <alloca.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/l2cap.h>

#include "monitor/mainloop.h"

static bool send_message(const bdaddr_t *src, const bdaddr_t *dst,
							uint16_t psm)
{
	const unsigned char buf[] = { 0x42, 0x23 };
	struct sockaddr_l2 addr;
	ssize_t len;
	int fd;

	fd = socket(PF_BLUETOOTH, SOCK_DGRAM | SOCK_CLOEXEC, BTPROTO_L2CAP);
	if (fd < 0) {
		perror("Failed to create transmitter socket");
		return false;
	}

	memset(&addr, 0, sizeof(addr));
	addr.l2_family = AF_BLUETOOTH;
	bacpy(&addr.l2_bdaddr, src);

	if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
		perror("Failed to bind transmitter socket");
		close(fd);
		return false;
	}

	memset(&addr, 0, sizeof(addr));
	addr.l2_family = AF_BLUETOOTH;
	bacpy(&addr.l2_bdaddr, dst);
	addr.l2_psm = htobs(psm);

	if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
		perror("Failed to connect transmitter socket");
		close(fd);
		return false;
	}

	len = send(fd, buf, sizeof(buf), 0);
	if (len < 0) {
		perror("Failed to send message");
		close(fd);
		return false;
	}

	return true;
}

static void receiver_callback(int fd, uint32_t events, void *user_data)
{
	unsigned char buf[512];
	struct sockaddr_l2 addr;
	socklen_t addrlen = sizeof(addr);
	char str[18];
	ssize_t len, i;

	if (events & (EPOLLERR | EPOLLHUP)) {
		close(fd);
		mainloop_remove_fd(fd);
		return;
	}

	len = recvfrom(fd, buf, sizeof(buf), 0,
				(struct sockaddr *) &addr, &addrlen);
	if (len < 0) {
		perror("Failed to receive data");
		return;
	}

	if (addrlen > 0) {
		ba2str(&addr.l2_bdaddr, str);
		printf("RX Address: %s PSM: %d CID: %d\n", str,
				btohs(addr.l2_psm), btohs(addr.l2_cid));
	}

	printf("RX Data:");
	for (i = 0; i < len; i++)
		printf(" 0x%02x", buf[i]);
	printf("\n");
}

static bool create_receiver(const bdaddr_t *bdaddr, uint16_t psm)
{
	struct sockaddr_l2 addr;
	int fd;

	fd = socket(PF_BLUETOOTH, SOCK_DGRAM | SOCK_CLOEXEC, BTPROTO_L2CAP);
	if (fd < 0) {
		perror("Failed to create receiver socket");
		return false;
	}

	memset(&addr, 0, sizeof(addr));
	addr.l2_family = AF_BLUETOOTH;
	bacpy(&addr.l2_bdaddr, bdaddr);
	addr.l2_psm = htobs(psm);

	if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
		perror("Failed to bind receiver socket");
		close(fd);
		return false;
	}

	mainloop_add_fd(fd, EPOLLIN, receiver_callback, NULL, NULL);

	return true;
}

static bool activate_controller(int fd, struct hci_dev_info *di)
{
	if (!hci_test_bit(HCI_UP, &di->flags)) {
		char addr[18];

		ba2str(&di->bdaddr, addr);
		printf("Activating controller %s\n", addr);

		if (ioctl(fd, HCIDEVUP, di->dev_id) < 0) {
			if (errno != EALREADY) {
				perror("Failed to bring up HCI device");
				return false;
			}
		}
	}
	return true;
}

static bool enable_connections(int fd, struct hci_dev_info *di)
{
	if (!hci_test_bit(HCI_PSCAN, &di->flags)) {
		struct hci_dev_req dr;
		char addr[18];

		ba2str(&di->bdaddr, addr);
		printf("Enabling connections on %s\n", addr);

		dr.dev_id  = di->dev_id;
		dr.dev_opt = SCAN_PAGE;

		if (ioctl(fd, HCISETSCAN, (unsigned long) &dr) < 0) {
			perror("Failed to enable connections");
			return false;
		}
	}
	return true;
}

static bdaddr_t bdaddr_src;
static bdaddr_t bdaddr_dst;

static bool find_controllers(void)
{
	struct hci_dev_list_req *dl;
	struct hci_dev_req *dr;
	bool result;
	int fd, i;

	fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
	if (fd < 0) {
		perror("Failed to open raw HCI socket");
		return false;
	}

	dl = malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
	if (!dl) {
		perror("Failed allocate HCI device request memory");
		close(fd);
		return false;
	}

	dl->dev_num = HCI_MAX_DEV;
	dr = dl->dev_req;

	if (ioctl(fd, HCIGETDEVLIST, (void *) dl) < 0) {
		perror("Failed to get HCI device list");
		result = false;
		goto done;
	}

	result = true;

	for (i = 0; i< dl->dev_num && result; i++) {
		struct hci_dev_info di;

		di.dev_id = (dr + i)->dev_id;

		if (ioctl(fd, HCIGETDEVINFO, (void *) &di) < 0)
			continue;

		if (((di.type & 0x30) >> 4) != HCI_BREDR)
			continue;

		if (!bacmp(&bdaddr_src, BDADDR_ANY)) {
			bacpy(&bdaddr_src, &di.bdaddr);
			result = activate_controller(fd, &di);
		} else if (!bacmp(&bdaddr_dst, BDADDR_ANY)) {
			bacpy(&bdaddr_dst, &di.bdaddr);
			result = activate_controller(fd, &di);
			if (result)
				result = enable_connections(fd, &di);
		}
	}

done:
	free(dl);
	close(fd);
	return result;
}

int main(int argc ,char *argv[])
{
	char addr_src[18], addr_dst[18];

	bacpy(&bdaddr_src, BDADDR_ANY);
	bacpy(&bdaddr_dst, BDADDR_ANY);

	if (!find_controllers())
		return EXIT_FAILURE;

	if (!bacmp(&bdaddr_src, BDADDR_ANY) ||
				!bacmp(&bdaddr_dst, BDADDR_ANY)) {
		fprintf(stderr, "Two controllers are required\n");
		return EXIT_FAILURE;
	}

	ba2str(&bdaddr_src, addr_src);
	ba2str(&bdaddr_dst, addr_dst);

	printf("%s -> %s\n", addr_src, addr_dst);

	mainloop_init();

	create_receiver(&bdaddr_dst, 0x0021);
	send_message(&bdaddr_src, &bdaddr_dst, 0x0021);

	return mainloop_run();
}
