diff options
Diffstat (limited to 'hcid/dbus-hci.c')
-rw-r--r-- | hcid/dbus-hci.c | 107 |
1 files changed, 84 insertions, 23 deletions
diff --git a/hcid/dbus-hci.c b/hcid/dbus-hci.c index 10e61a0c..fa84053f 100644 --- a/hcid/dbus-hci.c +++ b/hcid/dbus-hci.c @@ -262,24 +262,34 @@ static dbus_bool_t send_adapter_signal(DBusConnection *conn, int devid, return ret; } -static void adapter_mode_changed(struct adapter *adapter, const char *path, uint8_t mode) +static void adapter_mode_changed(struct adapter *adapter, + const char *path, uint8_t scan_enable) { - const char *scan_mode; + const char *mode; - adapter->mode = mode; + adapter->scan_enable = scan_enable; - switch (mode) { + switch (scan_enable) { case SCAN_DISABLED: - scan_mode = MODE_OFF; - break; + mode = "off"; + adapter->mode = MODE_OFF; + break; case SCAN_PAGE: - scan_mode = MODE_CONNECTABLE; + mode = "connectable"; + adapter->mode = MODE_CONNECTABLE; break; case (SCAN_PAGE | SCAN_INQUIRY): - scan_mode = MODE_DISCOVERABLE; + if (adapter->discov_timeout != 0) adapter->timeout_id = g_timeout_add(adapter->discov_timeout * 1000, discov_timeout_handler, adapter); + + if (adapter->mode == MODE_LIMITED) { + mode = "limited"; + } else { + adapter->mode = MODE_DISCOVERABLE; + mode = "discoverable"; + } break; case SCAN_INQUIRY: /* Address the scenario where another app changed the scan mode */ @@ -294,7 +304,7 @@ static void adapter_mode_changed(struct adapter *adapter, const char *path, uint dbus_connection_emit_signal(connection, path, ADAPTER_INTERFACE, "ModeChanged", - DBUS_TYPE_STRING, &scan_mode, + DBUS_TYPE_STRING, &mode, DBUS_TYPE_INVALID); } @@ -542,7 +552,7 @@ int hcid_dbus_start_device(uint16_t id) struct adapter* adapter; struct hci_conn_list_req *cl = NULL; struct hci_conn_info *ci; - uint8_t mode; + const char *mode; int i, err, dd = -1, ret = -1; snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id); @@ -570,14 +580,13 @@ int hcid_dbus_start_device(uint16_t id) adapter->discov_timeout = get_discoverable_timeout(id); adapter->discov_type = DISCOVER_TYPE_NONE; - mode = get_startup_mode(id); - dd = hci_open_dev(id); if (dd < 0) goto failed; - hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &mode); - + adapter->scan_enable = get_startup_scan(id); + hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, + 1, &adapter->scan_enable); /* * Get the adapter Bluetooth address */ @@ -590,7 +599,10 @@ int hcid_dbus_start_device(uint16_t id) if (err < 0) goto failed; - adapter_mode_changed(adapter, path, mode); + adapter->mode = get_startup_mode(id); + if (adapter->mode == MODE_LIMITED) + set_limited_discoverable(dd, adapter->class, TRUE); + /* * retrieve the active connections: address the scenario where * the are active connections before the daemon've started @@ -611,6 +623,12 @@ int hcid_dbus_start_device(uint16_t id) ret = 0; + mode = mode2str(adapter->mode); + dbus_connection_emit_signal(connection, path, ADAPTER_INTERFACE, + "ModeChanged", + DBUS_TYPE_STRING, &mode, + DBUS_TYPE_INVALID); + failed: if (ret == 0 && get_default_adapter() < 0) set_default_adapter(id); @@ -640,7 +658,7 @@ int hcid_dbus_stop_device(uint16_t id) { char path[MAX_PATH_LENGTH]; struct adapter *adapter; - const char *scan_mode = MODE_OFF; + const char *mode = "off"; snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id); @@ -704,11 +722,12 @@ int hcid_dbus_stop_device(uint16_t id) } send_adapter_signal(connection, adapter->dev_id, "ModeChanged", - DBUS_TYPE_STRING, &scan_mode, + DBUS_TYPE_STRING, &mode, DBUS_TYPE_INVALID); adapter->up = 0; - adapter->mode = SCAN_DISABLED; + adapter->scan_enable = SCAN_DISABLED; + adapter->mode = MODE_OFF; adapter->discov_active = 0; adapter->pdiscov_active = 0; adapter->pinq_idle = 0; @@ -1615,16 +1634,55 @@ void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status, } +int set_limited_discoverable(int dd, const uint8_t *cls, gboolean limited) +{ + uint32_t dev_class; + int err; + int num = (limited ? 2 : 1); + uint8_t lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e }; + /* + * 1: giac + * 2: giac + liac + */ + if (hci_write_current_iac_lap(dd, num, lap, 1000) < 0) { + err = errno; + error("Can't write current IAC LAP: %s(%d)", + strerror(err), err); + return -err; + } + + if (limited) { + if (cls[1] & 0x20) + return 0; /* Already limited */ + + dev_class = (cls[2] << 16) | ((cls[1] | 0x20) << 8) | cls[0]; + } else { + if (!(cls[1] & 0x20)) + return 0; /* Already clear */ + + dev_class = (cls[2] << 16) | ((cls[1] & 0xdf) << 8) | cls[0]; + } + + if (hci_write_class_of_dev(dd, dev_class, 1000) < 0) { + err = errno; + error("Can't write class of device: %s(%d)", + strerror(err), err); + return -err; + } + + return 0; +} + gboolean discov_timeout_handler(void *data) { struct adapter *adapter = data; struct hci_request rq; int dd; - uint8_t hci_mode = adapter->mode; + uint8_t scan_enable = adapter->scan_enable; uint8_t status = 0; gboolean retval = TRUE; - hci_mode &= ~SCAN_INQUIRY; + scan_enable &= ~SCAN_INQUIRY; dd = hci_open_dev(adapter->dev_id); if (dd < 0) { @@ -1635,8 +1693,8 @@ gboolean discov_timeout_handler(void *data) 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.cparam = &scan_enable; + rq.clen = sizeof(scan_enable); rq.rparam = &status; rq.rlen = sizeof(status); rq.event = EVT_CMD_COMPLETE; @@ -1651,6 +1709,8 @@ gboolean discov_timeout_handler(void *data) goto failed; } + set_limited_discoverable(dd, adapter->class, FALSE); + adapter->timeout_id = 0; retval = FALSE; @@ -1769,7 +1829,7 @@ void hcid_dbus_setscan_enable_complete(bdaddr_t *local) adapter->timeout_id = 0; } - if (adapter->mode != rp.enable) + if (adapter->scan_enable != rp.enable) adapter_mode_changed(adapter, path, rp.enable); failed: @@ -1812,6 +1872,7 @@ void hcid_dbus_write_class_complete(bdaddr_t *local) write_local_class(local, cls); memcpy(adapter->class, cls, 3); + failed: if (dd >= 0) hci_close_dev(dd); |