From 537efeed8fd5758a642afd3ca1df82f69a22d14b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 24 Dec 2005 12:45:37 +0000 Subject: Add support for device scan property --- hcid/dbus-test | 24 +++-- hcid/dbus.c | 311 ++++++++++++++++++++++++++++++++++++++++++++++++-------- hcid/dbus.h | 3 +- hcid/hcid.h | 2 + hcid/security.c | 2 + 5 files changed, 291 insertions(+), 51 deletions(-) diff --git a/hcid/dbus-test b/hcid/dbus-test index 00cdfeda..926be2fc 100755 --- a/hcid/dbus-test +++ b/hcid/dbus-test @@ -14,6 +14,9 @@ dev_cmds = [ "Up", "Down", "SetProperty", "GetProperty", "Inquiry", "Connections", "Authenticate", "RoleSwitch" ] dev_setprop_bool = [ "auth", "encrypt", "discoverable", "connectable" ] dev_setprop_byte = [ "incmode" ] +dev_prop_filter = ["/org/bluez/Device/hci0", "/org/bluez/Device/hci1", + "/org/bluez/Device/hci2", "/org/bluez/Device/hci3", + "/org/bluez/Device/hci4", "/org/bluez/Device/hci5"] class Tester: exit_events = [] @@ -81,10 +84,10 @@ class Tester: self.dev.connect_to_signal('Up', self.dev_up) self.dev.connect_to_signal('Down', self.dev_down) - self.bus.add_signal_receiver(self.dev_name_changed, 'DeviceNameChanged', - 'org.bluez.Device', 'org.bluez', - '/org/bluez/Device/hci0') - + for path in dev_prop_filter: + self.bus.add_signal_receiver(self.dev_property_changed, + 'PropertyChanged','org.bluez.Device', + 'org.bluez',path) obj = self.bus.get_object('org.bluez', '%s/Controller' % self.dev_path) self.ctl = dbus.Interface(obj, 'org.bluez.Device.Controller') @@ -157,10 +160,17 @@ class Tester: print 'Down' @dbus.decorators.explicitly_pass_message - def dev_name_changed(*args, **keywords): - name = args[1] + def dev_property_changed(*args, **keywords): + property = args[1] + param = args[2] dbus_message = keywords["dbus_message"] - print 'Device %s name changed: %s' % (dbus_message.get_path(), name) + if property == 'name': + print 'Device %s name changed: %s' % (dbus_message.get_path(), param) + elif property == 'connectable': + print 'Device %s connectable scan property changed: %d' % (dbus_message.get_path(), param) + elif property == 'discoverable': + print 'Device %s discoverable scan property changed: %d' % (dbus_message.get_path(), param) + def signal_cb(self, sig, frame): print 'Caught signal, exiting' diff --git a/hcid/dbus.c b/hcid/dbus.c index e8c5ec41..c7d7f871 100644 --- a/hcid/dbus.c +++ b/hcid/dbus.c @@ -79,6 +79,7 @@ struct service_data { struct hci_dbus_data { uint16_t dev_id; uint16_t path_id; + uint32_t path_data; }; typedef int register_function_t(DBusConnection *conn, uint16_t id); @@ -136,6 +137,7 @@ static const bluez_error_t dbus_error_array[] = { { BLUEZ_EDBUS_NO_MEM, "No memory" }, { BLUEZ_EDBUS_CONN_NOT_FOUND, "Connection not found" }, { BLUEZ_EDBUS_UNKNOWN_PATH, "Unknown D-BUS path" }, + { BLUEZ_EDBUS_NOT_IMPLEMENTED, "Method not implemented" }, { 0, NULL } }; @@ -274,34 +276,36 @@ static const DBusObjectPathVTable obj_mgr_vtable = { */ static DBusMessage* handle_device_up_req(DBusMessage *msg, void *data); static DBusMessage* handle_device_down_req(DBusMessage *msg, void *data); -static DBusMessage* handle_device_set_propety_req(DBusMessage *msg, void *data); -static DBusMessage* handle_device_get_propety_req(DBusMessage *msg, void *data); -static DBusMessage* handle_device_set_propety_req_name(DBusMessage *msg, void *data); -static DBusMessage* handle_device_get_propety_req_name(DBusMessage *msg, void *data); +static DBusMessage* handle_device_set_property_req(DBusMessage *msg, void *data); +static DBusMessage* handle_device_get_property_req(DBusMessage *msg, void *data); +static DBusMessage* handle_device_set_property_req_name(DBusMessage *msg, void *data); +static DBusMessage* handle_device_get_property_req_name(DBusMessage *msg, void *data); +static DBusMessage* handle_device_set_property_req_pscan(DBusMessage *msg, void *data); +static DBusMessage* handle_device_set_property_req_iscan(DBusMessage *msg, void *data); static const struct service_data device_services[] = { { DEV_UP, handle_device_up_req, DEV_UP_SIGNATURE }, { DEV_DOWN, handle_device_down_req, DEV_DOWN_SIGNATURE }, - { DEV_SET_PROPERTY, handle_device_set_propety_req, DEV_SET_PROPERTY_SIGNATURE_BOOL }, - { DEV_SET_PROPERTY, handle_device_set_propety_req, DEV_SET_PROPERTY_SIGNATURE_STR }, - { DEV_SET_PROPERTY, handle_device_set_propety_req, DEV_SET_PROPERTY_SIGNATURE_BYTE }, - { DEV_GET_PROPERTY, handle_device_get_propety_req, DEV_GET_PROPERTY_SIGNATURE }, + { DEV_SET_PROPERTY, handle_device_set_property_req, DEV_SET_PROPERTY_SIGNATURE_BOOL }, + { DEV_SET_PROPERTY, handle_device_set_property_req, DEV_SET_PROPERTY_SIGNATURE_STR }, + { DEV_SET_PROPERTY, handle_device_set_property_req, DEV_SET_PROPERTY_SIGNATURE_BYTE }, + { DEV_GET_PROPERTY, handle_device_get_property_req, DEV_GET_PROPERTY_SIGNATURE }, { NULL, NULL, NULL} }; static const struct service_data set_property_services[] = { { DEV_PROPERTY_AUTH, handle_not_implemented_req, DEV_SET_PROPERTY_SIGNATURE_BOOL }, { DEV_PROPERTY_ENCRYPT, handle_not_implemented_req, DEV_SET_PROPERTY_SIGNATURE_BOOL }, - { DEV_PROPERTY_PSCAN, handle_not_implemented_req, DEV_SET_PROPERTY_SIGNATURE_BOOL }, - { DEV_PROPERTY_ISCAN, handle_not_implemented_req, DEV_SET_PROPERTY_SIGNATURE_BOOL }, - { DEV_PROPERTY_NAME, handle_device_set_propety_req_name, DEV_SET_PROPERTY_SIGNATURE_STR }, + { DEV_PROPERTY_PSCAN, handle_device_set_property_req_pscan, DEV_SET_PROPERTY_SIGNATURE_BOOL }, + { DEV_PROPERTY_ISCAN, handle_device_set_property_req_iscan, DEV_SET_PROPERTY_SIGNATURE_BOOL }, + { DEV_PROPERTY_NAME, handle_device_set_property_req_name, DEV_SET_PROPERTY_SIGNATURE_STR }, { DEV_PROPERTY_INCMODE, handle_not_implemented_req, DEV_SET_PROPERTY_SIGNATURE_BYTE }, { NULL, NULL, NULL} }; static const struct service_data get_property_services[] = { { DEV_PROPERTY_DEV_INFO, handle_not_implemented_req, DEV_GET_PROPERTY_SIGNATURE }, - { DEV_PROPERTY_NAME, handle_device_get_propety_req_name, DEV_GET_PROPERTY_SIGNATURE }, + { DEV_PROPERTY_NAME, handle_device_get_property_req_name, DEV_GET_PROPERTY_SIGNATURE }, { DEV_PROPERTY_INCMODE, handle_not_implemented_req, DEV_GET_PROPERTY_SIGNATURE }, { NULL, NULL, NULL} }; @@ -947,12 +951,44 @@ gboolean hcid_dbus_register_device(uint16_t id) char *pptr = path; gboolean ret; DBusMessage *message = NULL; + int dd = -1; + read_scan_enable_rp rp; + struct hci_request rq; + struct hci_dbus_data* pdata; snprintf(path, sizeof(path), "%s/hci%d", DEVICE_PATH, id); + ret = register_dbus_path(path, DEVICE_PATH_ID, id, &obj_dev_vtable, FALSE); + + dd = hci_open_dev(id); + if (dd < 0) { + syslog(LOG_ERR, "HCI device open failed: hci%d", id); + rp.enable = SCAN_PAGE | SCAN_INQUIRY; + } else { + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_HOST_CTL; + rq.ocf = OCF_READ_SCAN_ENABLE; + rq.rparam = &rp; + rq.rlen = READ_SCAN_ENABLE_RP_SIZE; + + if (hci_send_req(dd, &rq, 500) < 0) { + syslog(LOG_ERR, "Sending read scan enable command failed: %s (%d)", + strerror(errno), errno); + rp.enable = SCAN_PAGE | SCAN_INQUIRY; + } else if (rp.status) { + syslog(LOG_ERR, "Getting scan enable failed with status 0x%02x", + rp.status); + rp.enable = SCAN_PAGE | SCAN_INQUIRY; + } + } + + if (!dbus_connection_get_object_path_data(connection, path, (void*) &pdata)) + syslog(LOG_ERR, "Getting path data failed!"); + else + pdata->path_data = rp.enable; /* Keep the current scan status */ + message = dbus_message_new_signal(MANAGER_PATH, MANAGER_INTERFACE, BLUEZ_MGR_DEV_ADDED); - if (message == NULL) { syslog(LOG_ERR, "Can't allocate D-BUS remote name message"); goto failed; @@ -970,12 +1006,13 @@ gboolean hcid_dbus_register_device(uint16_t id) dbus_connection_flush(connection); failed: - dbus_message_unref(message); - - ret = register_dbus_path(path, DEVICE_PATH_ID, id, &obj_dev_vtable, FALSE); - + if (message) + dbus_message_unref(message); + if (ret && default_dev < 0) default_dev = id; + if (dd >= 0) + close(dd); return ret; } @@ -1945,7 +1982,7 @@ failed: return reply; } -static DBusMessage* handle_device_set_propety_req(DBusMessage *msg, void *data) +static DBusMessage* handle_device_set_property_req(DBusMessage *msg, void *data) { const struct service_data *handlers = set_property_services; DBusMessageIter iter; @@ -1979,7 +2016,7 @@ static DBusMessage* handle_device_set_propety_req(DBusMessage *msg, void *data) return reply; } -static DBusMessage* handle_device_get_propety_req(DBusMessage *msg, void *data) +static DBusMessage* handle_device_get_property_req(DBusMessage *msg, void *data) { const struct service_data *handlers = get_property_services; DBusMessageIter iter; @@ -2005,7 +2042,36 @@ static DBusMessage* handle_device_get_propety_req(DBusMessage *msg, void *data) return reply; } -static DBusMessage* handle_device_set_propety_req_name(DBusMessage *msg, void *data) +static void send_property_changed_signal(const int devid, const char *prop_name, const int prop_type, void *value) +{ + DBusMessage *message = NULL; + char path[MAX_PATH_LENGTH]; + + snprintf(path, sizeof(path)-1, "%s/hci%d", DEVICE_PATH, devid); + path[MAX_PATH_LENGTH-1]='\0'; + + message = dbus_message_new_signal(path, DEVICE_INTERFACE, + BLUEZ_HCI_PROPERTY_CHANGED); + if (message == NULL) { + syslog(LOG_ERR, "Can't allocate D-BUS inquiry complete message"); + goto failed; + } + dbus_message_append_args(message, + DBUS_TYPE_STRING, &prop_name, + prop_type, value, + DBUS_TYPE_INVALID); + + if (dbus_connection_send(connection, message, NULL) == FALSE) { + syslog(LOG_ERR, "Can't send D-BUS PropertChanged(%s) signal",prop_name); + goto failed; + } + +failed: + if (message) + dbus_message_unref(message); +} + +static DBusMessage* handle_device_set_property_req_name(DBusMessage *msg, void *data) { struct hci_dbus_data *dbus_data = data; DBusMessageIter iter; @@ -2066,8 +2132,6 @@ failed: void hcid_dbus_setname_complete(bdaddr_t *local) { - DBusMessage *message = NULL; - char path[MAX_PATH_LENGTH]; char *local_addr; bdaddr_t tmp; int id; @@ -2085,15 +2149,6 @@ void hcid_dbus_setname_complete(bdaddr_t *local) goto failed; } - snprintf(path, sizeof(path), "%s/hci%d", DEVICE_PATH, id); - - message = dbus_message_new_signal(path, DEVICE_INTERFACE, - BLUEZ_HCI_SET_NAME); - if (message == NULL) { - syslog(LOG_ERR, "Can't allocate D-BUS inquiry complete message"); - goto failed; - } - dd = hci_open_dev(id); memset(&rq, 0, sizeof(rq)); if (dd < 0) { @@ -2118,27 +2173,19 @@ void hcid_dbus_setname_complete(bdaddr_t *local) } strncpy(name,pname,sizeof(name)-1); - name[248]='\0'; + name[248] = '\0'; pname = name; - dbus_message_append_args(message, - DBUS_TYPE_STRING, &pname, - DBUS_TYPE_INVALID); - - if (dbus_connection_send(connection, message, NULL) == FALSE) { - syslog(LOG_ERR, "Can't send D-BUS NameChanged signal"); - goto failed; - } + send_property_changed_signal(id, DEV_PROPERTY_NAME, DBUS_TYPE_STRING, &pname); dbus_connection_flush(connection); failed: if (dd >= 0) close(dd); - dbus_message_unref(message); bt_free(local_addr); } -static DBusMessage* handle_device_get_propety_req_name(DBusMessage *msg, void *data) +static DBusMessage* handle_device_get_property_req_name(DBusMessage *msg, void *data) { struct hci_dbus_data *dbus_data = data; DBusMessage *reply = NULL; @@ -2194,6 +2241,184 @@ failed: return reply; } +static DBusMessage* write_scan_enable(DBusMessage *msg, void *data, gboolean ispscan) +{ + struct hci_dbus_data *dbus_data = data; + DBusMessageIter iter; + DBusMessage *reply = NULL; + int dd = -1; + read_scan_enable_rp rp; + uint8_t enable; + uint8_t status; + uint8_t scan_change, scan_keep; + struct hci_request rq; + gboolean prop_value; /* new requested value for the iscan or pscan */ + + dbus_message_iter_init(msg, &iter); + dbus_message_iter_next(&iter); + dbus_message_iter_get_basic(&iter, &prop_value); + + dd = hci_open_dev(dbus_data->dev_id); + if (dd < 0) { + syslog(LOG_ERR, "HCI device open failed: hci%d", dbus_data->dev_id); + reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_ENODEV); + goto failed; + } + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_HOST_CTL; + rq.ocf = OCF_READ_SCAN_ENABLE; + rq.rparam = &rp; + rq.rlen = READ_SCAN_ENABLE_RP_SIZE; + + if (hci_send_req(dd, &rq, 100) < 0) { + syslog(LOG_ERR, "Sending read scan enable command failed: %s (%d)", + strerror(errno), errno); + reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET + errno); + goto failed; + } + + if (rp.status) { + syslog(LOG_ERR, "Getting scan enable failed with status 0x%02x", + rp.status); + reply = bluez_new_failure_msg(msg, BLUEZ_EBT_OFFSET + rp.status); + goto failed; + } + + if (ispscan) { /* Page scan */ + scan_change = SCAN_PAGE; + scan_keep = SCAN_INQUIRY; + } else { /* Inquiry scan */ + scan_change = SCAN_INQUIRY; + scan_keep = SCAN_PAGE; + } + + /* This is an optimization. We want to avoid overwrite the value + if the requested scan property will not change. */ + if (prop_value && !(rp.enable & scan_change)) + /* Enable the requested scan type (e.g. page scan). Keep the + the other type untouched. */ + enable = (rp.enable & scan_keep) | scan_change; + else if (!prop_value && (rp.enable & scan_change)) + /* Disable the requested scan type (e.g. page scan). Keep the + the other type untouched. */ + enable = (rp.enable & scan_keep); + else { /* Property not changed. Do nothing. Return ok. */ + reply = dbus_message_new_method_return(msg); + goto failed; + } + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_HOST_CTL; + rq.ocf = OCF_WRITE_SCAN_ENABLE; + rq.cparam = &enable; + rq.clen = sizeof(enable); + rq.rparam = &status; + rq.rlen = sizeof(status); + + if (hci_send_req(dd, &rq, 100) < 0) { + syslog(LOG_ERR, "Sending write scan enable command failed: %s (%d)", + strerror(errno), errno); + reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET + errno); + goto failed; + } + if (status) { + syslog(LOG_ERR, "Setting scan enable failed with status 0x%02x", rp.status); + reply = bluez_new_failure_msg(msg, BLUEZ_EBT_OFFSET + rp.status); + goto failed; + } + reply = dbus_message_new_method_return(msg); + +failed: + if (dd >= 0) + close(dd); + return reply; + +} + +void hcid_dbus_setscan_enable_complete(bdaddr_t *local) +{ + char *local_addr; + char path[MAX_PATH_LENGTH]; + bdaddr_t tmp; + int id; + int dd = -1; + gboolean se; + read_scan_enable_rp rp; + struct hci_request rq; + struct hci_dbus_data *pdata = NULL; + uint32_t old_data; + + baswap(&tmp, local); local_addr = batostr(&tmp); + id = hci_devid(local_addr); + if (id < 0) { + syslog(LOG_ERR, "No matching device id for %s", local_addr); + goto failed; + } + + snprintf(path, sizeof(path), "%s/hci%d", DEVICE_PATH, id); + + dd = hci_open_dev(id); + memset(&rq, 0, sizeof(rq)); + + if (dd < 0) { + syslog(LOG_ERR, "HCI device open failed: hci%d", id); + goto failed; + } + rq.ogf = OGF_HOST_CTL; + rq.ocf = OCF_READ_SCAN_ENABLE; + rq.rparam = &rp; + rq.rlen = READ_SCAN_ENABLE_RP_SIZE; + if (hci_send_req(dd, &rq, 100) < 0) { + syslog(LOG_ERR, + "Sending read scan enable command failed: %s (%d)", + strerror(errno), errno); + goto failed; + } + if (rp.status) { + syslog(LOG_ERR, + "Getting scan enable failed with status 0x%02x", + rp.status); + goto failed; + } + + if (!dbus_connection_get_object_path_data(connection, path, (void*) &pdata)) { + syslog(LOG_ERR, "Getting path data failed!"); + goto failed; + } + + old_data = pdata->path_data; + pdata->path_data = rp.enable; + + /* If the new page scan flag is different from what we had, send a signal. */ + if((rp.enable & SCAN_PAGE) != (old_data & SCAN_PAGE)) { + se = (rp.enable & SCAN_PAGE); + send_property_changed_signal(id, DEV_PROPERTY_PSCAN, DBUS_TYPE_BOOLEAN, &se); + } + /* If the new inquity scan flag is different from what we had, send a signal. */ + if ((rp.enable & SCAN_INQUIRY) != (old_data & SCAN_INQUIRY)) { + se = (rp.enable & SCAN_INQUIRY); + send_property_changed_signal(id, DEV_PROPERTY_ISCAN, DBUS_TYPE_BOOLEAN, &se); + } + + dbus_connection_flush(connection); + +failed: + if (dd >= 0) + close(dd); + bt_free(local_addr); +} + +static DBusMessage* handle_device_set_property_req_pscan(DBusMessage *msg, void *data) +{ + return write_scan_enable(msg, data, TRUE); +} + +static DBusMessage* handle_device_set_property_req_iscan(DBusMessage *msg, void *data) +{ + return write_scan_enable(msg, data, FALSE); +} + static DBusMessage* handle_device_list_req(DBusMessage *msg, void *data) { DBusMessageIter iter; @@ -2339,5 +2564,5 @@ static DBusMessage* handle_not_implemented_req(DBusMessage *msg, void *data) syslog(LOG_INFO, "Not Implemented - path %s iface %s method %s", path, iface, method); - return NULL; + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); } diff --git a/hcid/dbus.h b/hcid/dbus.h index 949f4b0d..aca14132 100644 --- a/hcid/dbus.h +++ b/hcid/dbus.h @@ -100,7 +100,7 @@ #define DEV_HCI_INTERFACE DEVICE_INTERFACE "." BLUEZ_HCI /* /org/bluez/Device signals */ -#define BLUEZ_HCI_SET_NAME "DeviceNameChanged" +#define BLUEZ_HCI_PROPERTY_CHANGED "PropertyChanged" /* Control interface signals */ #define BLUEZ_HCI_INQ_START "InquiryStart" @@ -227,6 +227,7 @@ #define BLUEZ_EDBUS_NO_MEM (0x05 + BLUEZ_EDBUS_OFFSET) #define BLUEZ_EDBUS_CONN_NOT_FOUND (0x06 + BLUEZ_EDBUS_OFFSET) #define BLUEZ_EDBUS_UNKNOWN_PATH (0x07 + BLUEZ_EDBUS_OFFSET) +#define BLUEZ_EDBUS_NOT_IMPLEMENTED (0x08 + BLUEZ_EDBUS_OFFSET) /* D-Bus error code, class BLUEZ_ESYSTEM_OFFSET */ #define BLUEZ_ESYSTEM_ENODEV (ENODEV + BLUEZ_ESYSTEM_OFFSET) diff --git a/hcid/hcid.h b/hcid/hcid.h index bac3ef26..3b15716e 100644 --- a/hcid/hcid.h +++ b/hcid/hcid.h @@ -135,6 +135,7 @@ void hcid_dbus_conn_complete(bdaddr_t *local, bdaddr_t *peer); void hcid_dbus_disconn_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t reason); void hcid_dbus_auth_complete(bdaddr_t *local, bdaddr_t *peer, const uint8_t status); void hcid_dbus_setname_complete(bdaddr_t *local); +void hcid_dbus_setscan_enable_complete(bdaddr_t *local); #else static inline void hcid_dbus_inquiry_start(bdaddr_t *local) {} static inline void hcid_dbus_inquiry_complete(bdaddr_t *local) {} @@ -145,6 +146,7 @@ static inline void hcid_dbus_conn_complete(bdaddr_t *local, bdaddr_t *peer) {} static inline void hcid_dbus_disconn_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t reason) {} static inline void hcid_dbus_auth_complete(bdaddr_t *local, bdaddr_t *peer, const uint8_t status) {} static inline void hcid_dbus_setname_complete(bdaddr_t *local) {} +static inline void hcid_dbus_setscan_enable_complete(bdaddr_t *local) {} #endif int write_device_name(bdaddr_t *local, bdaddr_t *peer, char *name); diff --git a/hcid/security.c b/hcid/security.c index 76a8600d..eaaa7936 100644 --- a/hcid/security.c +++ b/hcid/security.c @@ -498,6 +498,8 @@ static inline void cmd_complete(int dev, bdaddr_t *sba, void *ptr) case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME): hcid_dbus_setname_complete(sba); break; + case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE): + hcid_dbus_setscan_enable_complete(sba); }; } -- cgit