diff options
Diffstat (limited to 'hcid')
-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"); |