diff options
| -rw-r--r-- | hcid/Makefile.am | 7 | ||||
| -rw-r--r-- | hcid/dbus.c | 101 | ||||
| -rw-r--r-- | hcid/device.c | 267 | ||||
| -rw-r--r-- | hcid/hcid.h | 12 | ||||
| -rw-r--r-- | hcid/main.c | 10 | 
5 files changed, 372 insertions, 25 deletions
diff --git a/hcid/Makefile.am b/hcid/Makefile.am index 2f5e2038..a4189f5f 100644 --- a/hcid/Makefile.am +++ b/hcid/Makefile.am @@ -27,8 +27,9 @@ dbus_hcid_libs    =  dbus_hcid_cflags  =  endif -hcid_SOURCES = main.c security.c storage.c hcid.h lib.c lib.h \ -		parser.h parser.y lexer.l kword.h kword.c $(dbus_hcid_sources) +hcid_SOURCES = main.c security.c device.c storage.c hcid.h lib.c lib.h \ +		parser.h parser.y lexer.l kword.h kword.c $(dbus_hcid_sources) \ +		$(top_builddir)/tools/oui.h $(top_builddir)/tools/oui.c  hcid_LDADD = $(dbus_hcid_libs) @BLUEZ_LIBS@ \  		$(top_builddir)/common/libglib-ectomy.a \ @@ -36,7 +37,7 @@ hcid_LDADD = $(dbus_hcid_libs) @BLUEZ_LIBS@ \  AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ $(dbus_hcid_cflags) -INCLUDES = -I$(top_srcdir)/common +INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/tools  man_MANS = hcid.8 hcid.conf.5 diff --git a/hcid/dbus.c b/hcid/dbus.c index 62d8e546..87abc7ff 100644 --- a/hcid/dbus.c +++ b/hcid/dbus.c @@ -1350,33 +1350,100 @@ static DBusHandlerResult msg_func_manager(DBusConnection *conn, DBusMessage *msg   *  Section reserved to device D-Bus services implementation   *   *****************************************************************/ +  static DBusMessage* handle_dev_get_address_req(DBusMessage *msg, void *data)  { -	/*FIXME: */ -	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +	struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	char str[18], *str_ptr = str; + +	get_device_address(dbus_data->dev_id, str, sizeof(str)); + +	reply = dbus_message_new_method_return(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, +					DBUS_TYPE_INVALID); + +	return reply;  } -static DBusMessage* handle_dev_get_alias_req(DBusMessage *msg, void *data) +static DBusMessage* handle_dev_get_version_req(DBusMessage *msg, void *data)  { -	/*FIXME: */ -	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +	struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	char str[20], *str_ptr = str; + +	get_device_version(dbus_data->dev_id, str, sizeof(str)); + +	reply = dbus_message_new_method_return(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage* handle_dev_get_revision_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	char str[20], *str_ptr = str; + +	get_device_revision(dbus_data->dev_id, str, sizeof(str)); + +	reply = dbus_message_new_method_return(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, +					DBUS_TYPE_INVALID); + +	return reply; +} + +static DBusMessage* handle_dev_get_manufacturer_req(DBusMessage *msg, void *data) +{ +	struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	char str[64], *str_ptr = str; + +	get_device_manufacturer(dbus_data->dev_id, str, sizeof(str)); + +	reply = dbus_message_new_method_return(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, +					DBUS_TYPE_INVALID); + +	return reply;  } +  static DBusMessage* handle_dev_get_company_req(DBusMessage *msg, void *data)  { -	/*FIXME: */ -	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +	struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	char str[64], *str_ptr = str; + +	get_device_company(dbus_data->dev_id, str, sizeof(str)); + +	reply = dbus_message_new_method_return(msg); + +	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, +					DBUS_TYPE_INVALID); + +	return reply;  } -static DBusMessage* handle_dev_get_discoverable_to_req(DBusMessage *msg, void *data) + +static DBusMessage* handle_dev_get_features_req(DBusMessage *msg, void *data)  {  	/*FIXME: */  	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED);  } -static DBusMessage* handle_dev_get_features_req(DBusMessage *msg, void *data) + +static DBusMessage* handle_dev_get_alias_req(DBusMessage *msg, void *data)  {  	/*FIXME: */  	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED);  } -static DBusMessage* handle_dev_get_manufacturer_req(DBusMessage *msg, void *data) + +static DBusMessage* handle_dev_get_discoverable_to_req(DBusMessage *msg, void *data)  {  	/*FIXME: */  	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); @@ -1472,22 +1539,12 @@ failed:  	return reply;  } -static DBusMessage* handle_dev_get_revision_req(DBusMessage *msg, void *data) -{ -	/*FIXME: */ -	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); -} -static DBusMessage* handle_dev_get_version_req(DBusMessage *msg, void *data) -{ -	/*FIXME: */ -	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); -} -  static DBusMessage* handle_dev_is_connectable_req(DBusMessage *msg, void *data)  {  	/*FIXME: */  	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED);  } +  static DBusMessage* handle_dev_is_discoverable_req(DBusMessage *msg, void *data)  {  	/*FIXME: */ @@ -1505,6 +1562,7 @@ static DBusMessage* handle_dev_set_class_req(DBusMessage *msg, void *data)  	/*FIXME: */  	return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED);  } +  static DBusMessage* handle_dev_set_discoverable_to_req(DBusMessage *msg, void *data)  {  	/*FIXME: */ @@ -2298,4 +2356,3 @@ static DBusMessage* handle_mgr_default_device_req(DBusMessage *msg, void *data)  failed:  	return reply;  } - diff --git a/hcid/device.c b/hcid/device.c new file mode 100644 index 00000000..71d97dbd --- /dev/null +++ b/hcid/device.c @@ -0,0 +1,267 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2004-2006  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 <stdlib.h> +#include <stdarg.h> +#include <syslog.h> +#include <string.h> +#include <sys/time.h> +#include <sys/socket.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> + +#include "oui.h" + +#define MAX_DEVICES 16 + +struct hci_peer { +	struct timeval lastseen; +	struct timeval lastused; + +	bdaddr_t bdaddr; +	uint32_t class; +	int8_t   rssi; +	uint8_t  data[240]; +	uint8_t  name[248]; + +	uint8_t  pscan_rep_mode; +	uint8_t  pscan_period_mode; +	uint8_t  pscan_mode; +	uint16_t clock_offset; + +	struct hci_peer *next; +}; + +struct hci_conn { +	bdaddr_t bdaddr; +	uint16_t handle; + +	struct hci_conn *next; +}; + +struct hci_dev { +	bdaddr_t bdaddr; +	uint8_t  features[8]; +	uint8_t  lmp_ver; +	uint16_t lmp_subver; +	uint16_t manufacturer; + +	struct hci_peer *peers; +	struct hci_conn *conns; +}; + +static struct hci_dev devices[MAX_DEVICES]; + +#define ASSERT_DEV_ID { if (dev_id >= MAX_DEVICES) return -ERANGE; } + +static void info(const char *format, ...) +{ +	va_list ap; + +	va_start(ap, format); + +	vsyslog(LOG_INFO, format, ap); + +	va_end(ap); +} + +static void err(const char *format, ...) +{ +	va_list ap; + +	va_start(ap, format); + +	vsyslog(LOG_ERR, format, ap); + +	va_end(ap); +} + +void init_devices(void) +{ +	int i; + +	for (i = 0; i < MAX_DEVICES; i++) +		memset(devices + i, 0, sizeof(struct hci_dev)); +} + +int add_device(uint16_t dev_id) +{ +	struct hci_dev *dev; +	struct hci_dev_info di; + +	ASSERT_DEV_ID; + +	dev = &devices[dev_id]; + +	if (hci_devinfo(dev_id, &di) < 0) +		return -errno; + +	bacpy(&dev->bdaddr, &di.bdaddr); +	memcpy(dev->features, di.features, 8); + +	info("Device hci%d has been added", dev_id); + +	return 0; +} + +int remove_device(uint16_t dev_id) +{ +	struct hci_dev *dev; + +	ASSERT_DEV_ID; + +	dev = &devices[dev_id]; + +	memset(dev, 0, sizeof(struct hci_dev)); + +	info("Device hci%d has been removed", dev_id); + +	return 0; +} + +int start_device(uint16_t dev_id) +{ +	struct hci_dev *dev; +	struct hci_version ver; +	int dd; + +	ASSERT_DEV_ID; + +	dev = &devices[dev_id]; + +	dd = hci_open_dev(dev_id); +	if (dd < 0) { +		err("Can't open device hci%d", +					dev_id, strerror(errno), errno); +		return -errno; +	} + +	if (hci_read_local_version(dd, &ver, 1000) < 0) { +		err("Can't read version info for hci%d: %s (%d)", +					dev_id, strerror(errno), errno); +		return -errno; +	} + +	dev->lmp_ver = ver.lmp_ver; +	dev->lmp_subver = ver.lmp_subver; +	dev->manufacturer = ver.manufacturer; + +	hci_close_dev(dd); + +	info("Device hci%d has been activated", dev_id); + +	return 0; +} + +int stop_device(uint16_t dev_id) +{ +	ASSERT_DEV_ID; + +	info("Device hci%d has been disabled", dev_id); + +	return 0; +} + +int get_device_address(uint16_t dev_id, char *address, size_t size) +{ +	ASSERT_DEV_ID; + +	if (size < 18) +		return -ENOBUFS; + +	return ba2str(&devices[dev_id].bdaddr, address); +} + +int get_device_version(uint16_t dev_id, char *version, size_t size) +{ +	struct hci_dev *dev; +	char edr[7], *tmp; +	int err; + +	ASSERT_DEV_ID; + +	if (size < 14) +		return -ENOBUFS; + +	dev = &devices[dev_id]; + +	if (dev->lmp_ver == 0x03 && +			(dev->features[3] & (LMP_EDR_ACL_2M | LMP_EDR_ACL_3M))) +		sprintf(edr, " + EDR"); +	else +		edr[0] = '\0'; + +	tmp = lmp_vertostr(dev->lmp_ver); + +	if (strlen(tmp) == 0) +		err = snprintf(version, size, "not assigned"); +	else +		err = snprintf(version, size, "Bluetooth %s%s", tmp, edr); + +	bt_free(tmp); + +	return err; +} + +int get_device_revision(uint16_t dev_id, char *revision, size_t size) +{ +	ASSERT_DEV_ID; + +	return snprintf(revision, size, "0x%02x", devices[dev_id].lmp_subver); +} + +int get_device_manufacturer(uint16_t dev_id, char *manufacturer, size_t size) +{ +	char *tmp; + +	ASSERT_DEV_ID; + +	tmp = bt_compidtostr(devices[dev_id].manufacturer); + +	return snprintf(manufacturer, size, "%s", tmp); +} + +int get_device_company(uint16_t dev_id, char *company, size_t size) +{ +	char *tmp, oui[9]; +	int err; + +	ASSERT_DEV_ID; + +	ba2oui(&devices[dev_id].bdaddr, oui); +	tmp = ouitocomp(oui); + +	err = snprintf(company, size, "%s", tmp); + +	free(tmp); + +	return err; +} diff --git a/hcid/hcid.h b/hcid/hcid.h index 064ee8c3..1f98c5a6 100644 --- a/hcid/hcid.h +++ b/hcid/hcid.h @@ -147,6 +147,18 @@ static inline void hcid_dbus_setname_complete(bdaddr_t *local) {}  static inline void hcid_dbus_setscan_enable_complete(bdaddr_t *local) {}  #endif +void init_devices(void); +int add_device(uint16_t dev_id); +int remove_device(uint16_t dev_id); +int start_device(uint16_t dev_id); +int stop_device(uint16_t dev_id); + +int get_device_address(uint16_t dev_id, char *address, size_t size); +int get_device_version(uint16_t dev_id, char *version, size_t size); +int get_device_revision(uint16_t dev_id, char *revision, size_t size); +int get_device_manufacturer(uint16_t dev_id, char *manufacturer, size_t size); +int get_device_company(uint16_t dev_id, char *company, size_t size); +  int write_device_name(bdaddr_t *local, bdaddr_t *peer, char *name);  int read_device_name(bdaddr_t *local, bdaddr_t *peer, char *name);  int write_version_info(bdaddr_t *local, bdaddr_t *peer, uint16_t manufacturer, uint8_t lmp_ver, uint16_t lmp_subver); diff --git a/hcid/main.c b/hcid/main.c index a41afe7b..2c307176 100644 --- a/hcid/main.c +++ b/hcid/main.c @@ -394,12 +394,16 @@ static void init_all_devices(int ctl)  		if (hcid.auto_init)  			init_device(dr->dev_id); +		add_device(dr->dev_id); +  		if (hcid.auto_init && hci_test_bit(HCI_UP, &dr->dev_opt))  			configure_device(dr->dev_id);  		if (hcid.security && hci_test_bit(HCI_UP, &dr->dev_opt))  			start_security_manager(dr->dev_id); +		start_device(dr->dev_id); +  #ifdef ENABLE_DBUS  		hcid_dbus_register_device(dr->dev_id);  #endif @@ -454,6 +458,7 @@ static inline void device_event(GIOChannel *chan, evt_stack_internal *si)  		syslog(LOG_INFO, "HCI dev %d registered", sd->dev_id);  		if (hcid.auto_init)  			init_device(sd->dev_id); +		add_device(sd->dev_id);  #ifdef ENABLE_DBUS  		hcid_dbus_register_device(sd->dev_id);  #endif @@ -464,6 +469,7 @@ static inline void device_event(GIOChannel *chan, evt_stack_internal *si)  #ifdef ENABLE_DBUS  		hcid_dbus_unregister_device(sd->dev_id);  #endif +		remove_device(sd->dev_id);  		break;  	case HCI_DEV_UP: @@ -472,12 +478,14 @@ static inline void device_event(GIOChannel *chan, evt_stack_internal *si)  			configure_device(sd->dev_id);  		if (hcid.security)  			start_security_manager(sd->dev_id); +		start_device(sd->dev_id);  		break;  	case HCI_DEV_DOWN:  		syslog(LOG_INFO, "HCI dev %d down", sd->dev_id);  		if (hcid.security)  			stop_security_manager(sd->dev_id); +		stop_device(sd->dev_id);  		break;  	}  } @@ -633,6 +641,8 @@ int main(int argc, char *argv[], char *env[])  	if (read_config(hcid.config_file) < 0)  		syslog(LOG_ERR, "Config load failed"); +	init_devices(); +  #ifdef ENABLE_DBUS  	if (hcid_dbus_init() == FALSE && hcid.dbus_pin_helper) {  		syslog(LOG_ERR, "Unable to get on D-BUS");  | 
