summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2006-02-11 11:11:21 +0000
committerMarcel Holtmann <marcel@holtmann.org>2006-02-11 11:11:21 +0000
commitdfc20857eb381b464b8fd6efdaac59e4a15f5d6d (patch)
tree573b3ef091cc61d5b81cd17605669641a49d4709
parent518bb944173c2036486b25a764966bd738bb5ecf (diff)
Add basic device functions
-rw-r--r--hcid/Makefile.am7
-rw-r--r--hcid/dbus.c101
-rw-r--r--hcid/device.c267
-rw-r--r--hcid/hcid.h12
-rw-r--r--hcid/main.c10
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");