diff options
-rwxr-xr-x | hcid/dbus-test | 36 | ||||
-rw-r--r-- | hcid/dbus.c | 272 | ||||
-rw-r--r-- | hcid/dbus.h | 19 |
3 files changed, 197 insertions, 130 deletions
diff --git a/hcid/dbus-test b/hcid/dbus-test index 926be2fc..6c195fbb 100755 --- a/hcid/dbus-test +++ b/hcid/dbus-test @@ -9,10 +9,10 @@ import getopt from signal import * mgr_cmds = [ "DeviceList", "DefaultDevice" ] -dev_cmds = [ "Up", "Down", "SetProperty", "GetProperty", "Inquiry", +dev_cmds = [ "Up", "Down", "SetProperty", "GetProperty", "SetMode", "GetMode", "Inquiry", "CancelInquiry", "PeriodicInquiry","CancelPeriodic", "RemoteName", "Connections", "Authenticate", "RoleSwitch" ] -dev_setprop_bool = [ "auth", "encrypt", "discoverable", "connectable" ] +dev_setprop_bool = [ "auth", "encrypt" ] dev_setprop_byte = [ "incmode" ] dev_prop_filter = ["/org/bluez/Device/hci0", "/org/bluez/Device/hci1", "/org/bluez/Device/hci2", "/org/bluez/Device/hci3", @@ -88,6 +88,10 @@ class Tester: self.bus.add_signal_receiver(self.dev_property_changed, 'PropertyChanged','org.bluez.Device', 'org.bluez',path) + for path in dev_prop_filter: + self.bus.add_signal_receiver(self.dev_mode_changed, + 'ModeChanged','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') @@ -166,11 +170,12 @@ class Tester: dbus_message = keywords["dbus_message"] 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) + @dbus.decorators.explicitly_pass_message + def dev_mode_changed(*args, **keywords): + mode = args[1] + dbus_message = keywords["dbus_message"] + print 'Device %s scan mode changed: %x' % (dbus_message.get_path(), mode) def signal_cb(self, sig, frame): print 'Caught signal, exiting' @@ -224,6 +229,25 @@ class Tester: except dbus.DBusException, e: print 'Sending %s failed: %s' % (self.cmd, e) sys.exit(1) + elif self.cmd == 'SetMode': + if len(self.cmd_args) != 1: + print 'Usage: %s -i <dev> SetMode scan_enable' % self.name + print 'scan_enable values: 0(no scan), 1(connectable), 2(connectable and discoverable)' % self.name + sys.exit(1) + try: + print self.dev.SetMode(dbus.Byte(self.cmd_args[0])) + except dbus.DBusException, e: + print 'Sending %s failed: %s' % (self.cmd, e) + sys.exit(1) + elif self.cmd == 'GetMode': + if len(self.cmd_args) != 0: + print 'Usage: %s -i <dev> GetMode' % self.name + sys.exit(1) + try: + print self.dev.GetMode() + except dbus.DBusException, e: + print 'Sending %s failed: %s' % (self.cmd, e) + sys.exit(1) # Device.Controller methods elif self.cmd == 'Inquiry': try: diff --git a/hcid/dbus.c b/hcid/dbus.c index f68ae732..ce3c3a5e 100644 --- a/hcid/dbus.c +++ b/hcid/dbus.c @@ -276,16 +276,18 @@ 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_get_mode_req(DBusMessage *msg, void *data); +static DBusMessage* handle_device_set_mode_req(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_GET_MODE, handle_device_get_mode_req, DEV_GET_MODE_SIGNATURE }, + { DEV_SET_MODE, handle_device_set_mode_req, DEV_SET_MODE_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 }, @@ -296,8 +298,6 @@ static const struct service_data device_services[] = { 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_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} @@ -1993,6 +1993,110 @@ failed: return reply; } +static DBusMessage* handle_device_get_mode_req(DBusMessage *msg, void *data) +{ + const struct hci_dbus_data *dbus_data = data; + DBusMessage *reply = NULL; + const uint8_t hci_mode = dbus_data->path_data; + uint8_t scan_mode; + + switch (hci_mode) { + case SCAN_DISABLED: + scan_mode = MODE_OFF; + break; + case SCAN_PAGE: + scan_mode = MODE_CONNECTABLE; + break; + case (SCAN_PAGE | SCAN_INQUIRY): + scan_mode = MODE_DISCOVERABLE; + break; + case SCAN_INQUIRY: + /* inquiry scan mode is not handled, return 0xff */ + default: + /* reserved */ + scan_mode = 0xff; + } + + reply = dbus_message_new_method_return(msg); + + dbus_message_append_args(reply, + DBUS_TYPE_BYTE, &scan_mode, + DBUS_TYPE_INVALID); + + return reply; +} + +static DBusMessage* handle_device_set_mode_req(DBusMessage *msg, void *data) +{ + const struct hci_dbus_data *dbus_data = data; + DBusMessage *reply = NULL; + struct hci_request rq; + int dd = -1; + const uint8_t scan_mode; + uint8_t hci_mode; + uint8_t status = 0; + const uint8_t current_mode = dbus_data->path_data; + + dbus_message_get_args(msg, NULL, + DBUS_TYPE_BYTE, &scan_mode, + DBUS_TYPE_INVALID); + + switch (scan_mode) { + case MODE_OFF: + hci_mode = SCAN_DISABLED; + break; + case MODE_CONNECTABLE: + hci_mode = SCAN_PAGE; + break; + case MODE_DISCOVERABLE: + hci_mode = (SCAN_PAGE | SCAN_INQUIRY); + break; + default: + /* invalid mode */ + reply = bluez_new_failure_msg(msg, BLUEZ_EDBUS_WRONG_PARAM); + goto failed; + } + + 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; + } + + /* Check if the new requested mode is different from the current */ + if (current_mode != hci_mode) { + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_HOST_CTL; + rq.ocf = OCF_WRITE_SCAN_ENABLE; + rq.cparam = &hci_mode; + rq.clen = sizeof(hci_mode); + 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", status); + reply = bluez_new_failure_msg(msg, BLUEZ_EBT_OFFSET | status); + goto failed; + } + + } + + reply = dbus_message_new_method_return(msg); + +failed: + if (dd >= 0) + close(dd); + + return reply; +} + static DBusMessage* handle_device_set_property_req(DBusMessage *msg, void *data) { const struct service_data *handlers = set_property_services; @@ -2258,113 +2362,18 @@ 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) { + DBusMessage *message = NULL; + struct hci_dbus_data *pdata = NULL; 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; + int id; + int dd = -1; + uint8_t scan_mode; baswap(&tmp, local); local_addr = batostr(&tmp); id = hci_devid(local_addr); @@ -2405,39 +2414,56 @@ void hcid_dbus_setscan_enable_complete(bdaddr_t *local) goto failed; } - old_data = pdata->path_data; + /* update the current scan mode value */ 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); + switch (rp.enable) { + case SCAN_DISABLED: + scan_mode = MODE_OFF; + break; + case SCAN_PAGE: + scan_mode = MODE_CONNECTABLE; + break; + case (SCAN_PAGE | SCAN_INQUIRY): + scan_mode = MODE_DISCOVERABLE; + break; + case SCAN_INQUIRY: + /* ignore, this event should not be sent*/ + default: + /* ignore, reserved */ + goto failed; + } + + message = dbus_message_new_signal(path, DEVICE_INTERFACE, + BLUEZ_HCI_SCAN_MODE_CHANGED); + if (message == NULL) { + syslog(LOG_ERR, "Can't allocate D-BUS inquiry complete message"); + goto failed; } - /* 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_message_append_args(message, + DBUS_TYPE_BYTE, &scan_mode, + DBUS_TYPE_INVALID); + + if (dbus_connection_send(connection, message, NULL) == FALSE) { + syslog(LOG_ERR, "Can't send D-BUS ModeChanged(%x) signal", rp.enable); + goto failed; } + dbus_connection_flush(connection); failed: + + if (message) + dbus_message_unref(message); + 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; diff --git a/hcid/dbus.h b/hcid/dbus.h index da031108..8f779eee 100644 --- a/hcid/dbus.h +++ b/hcid/dbus.h @@ -101,6 +101,7 @@ /* /org/bluez/Device signals */ #define BLUEZ_HCI_PROPERTY_CHANGED "PropertyChanged" +#define BLUEZ_HCI_SCAN_MODE_CHANGED "ModeChanged" /* Control interface signals */ #define BLUEZ_HCI_INQ_START "InquiryStart" @@ -125,6 +126,20 @@ #define DEV_DOWN "Down" #define DEV_SET_PROPERTY "SetProperty" #define DEV_GET_PROPERTY "GetProperty" +#define DEV_SET_MODE "SetMode" +#define DEV_GET_MODE "GetMode" + +/* + * Scanning modes + * off: remote devices are not allowed to find or connect to this device + * connectable: remote devices are allowed to connect, but they are not + * allowed to find it. + * discoverable: remote devices are allowed to connect and find this device + */ +#define MODE_OFF 0x00 +#define MODE_CONNECTABLE 0x01 +#define MODE_DISCOVERABLE 0x02 + #define DEV_PROPERTY_AUTH "auth" #define DEV_PROPERTY_ENCRYPT "encrypt" @@ -136,7 +151,9 @@ #define DEV_UP_SIGNATURE __END_SIG__ #define DEV_DOWN_SIGNATURE __END_SIG__ -#define DEV_RESET_SIGNATURE __END_SIG__ +#define DEV_SET_MODE_SIGNATURE DBUS_TYPE_BYTE_AS_STRING\ + __END_SIG__ +#define DEV_GET_MODE_SIGNATURE __END_SIG__ #define DEV_SET_PROPERTY_SIGNATURE_BOOL DBUS_TYPE_STRING_AS_STRING \ DBUS_TYPE_BOOLEAN_AS_STRING \ __END_SIG__ |