summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/adapter-api.txt9
-rw-r--r--src/adapter.c68
-rw-r--r--src/adapter.h2
-rw-r--r--src/dbus-hci.c8
-rw-r--r--src/storage.c30
-rw-r--r--src/storage.h2
6 files changed, 117 insertions, 2 deletions
diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt
index a13273f8..d0adf189 100644
--- a/doc/adapter-api.txt
+++ b/doc/adapter-api.txt
@@ -266,6 +266,15 @@ Properties string Address [readonly]
this property will be updated via a PropertyChanged
signal.
+ boolean Pairable [readwrite]
+
+ Switch an adapter to pairable or non-pairable. This is
+ a global setting and should only be used by the
+ settings application.
+
+ Note that this property only affects incoming pairing
+ requests.
+
uint32 DiscoverableTimeout [readwrite]
The discoverable timeout in seconds. A value of zero
diff --git a/src/adapter.c b/src/adapter.c
index 1f20cb40..8d76d4b2 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -114,6 +114,7 @@ struct btd_adapter {
guint scheduler_id; /* Scheduler handle */
struct hci_dev dev; /* hci info */
+ gboolean pairable; /* pairable state */
};
static inline DBusMessage *invalid_args(DBusMessage *msg)
@@ -627,7 +628,7 @@ static DBusMessage *set_mode(DBusConnection *conn, DBusMessage *msg,
adapter->discov_timeout_id = 0;
}
- if (!adapter->mode_sessions && !adapter->discov_timeout)
+ if (!adapter->mode_sessions && adapter->discov_timeout)
adapter_set_discov_timeout(adapter,
adapter->discov_timeout * 1000);
}
@@ -666,12 +667,40 @@ static DBusMessage *set_discoverable(DBusConnection *conn, DBusMessage *msg,
strmode = discoverable ? "discoverable" : "connectable";
mode = get_mode(&adapter->bdaddr, strmode);
+ if (mode == MODE_DISCOVERABLE && adapter->pairable)
+ mode = MODE_LIMITED;
+
if (mode == adapter->mode)
return dbus_message_new_method_return(msg);
return set_mode(conn, msg, mode, data);
}
+static DBusMessage *set_pairable(DBusConnection *conn, DBusMessage *msg,
+ gboolean pairable, void *data)
+{
+ struct btd_adapter *adapter = data;
+
+ if (pairable == adapter->pairable)
+ goto done;
+
+ adapter->pairable = pairable;
+
+ write_device_pairable(&adapter->bdaddr, pairable);
+
+ emit_property_changed(connection, adapter->path,
+ ADAPTER_INTERFACE, "Pairable",
+ DBUS_TYPE_BOOLEAN, &pairable);
+
+ if (adapter->scan_mode & SCAN_INQUIRY) {
+ uint8_t mode = pairable ? MODE_LIMITED : MODE_DISCOVERABLE;
+ return set_mode(conn, msg, mode, data);
+ }
+
+done:
+ return dbus_message_new_method_return(msg);
+}
+
static struct session_req *find_session(GSList *list, DBusMessage *msg)
{
GSList *l;
@@ -1657,6 +1686,10 @@ static DBusMessage *get_properties(DBusConnection *conn,
value = adapter->scan_mode & SCAN_INQUIRY ? TRUE : FALSE;
dict_append_entry(&dict, "Discoverable", DBUS_TYPE_BOOLEAN, &value);
+ /* Pairable */
+ dict_append_entry(&dict, "Pairable", DBUS_TYPE_BOOLEAN,
+ &adapter->pairable);
+
/* DiscoverableTimeout */
dict_append_entry(&dict, "DiscoverableTimeout",
DBUS_TYPE_UINT32, &adapter->discov_timeout);
@@ -1760,6 +1793,15 @@ static DBusMessage *set_property(DBusConnection *conn,
dbus_message_iter_get_basic(&sub, &timeout);
return set_discoverable_timeout(conn, msg, timeout, data);
+ } else if (g_str_equal("Pairable", property)) {
+ gboolean pairable;
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
+ return invalid_args(msg);
+
+ dbus_message_iter_get_basic(&sub, &pairable);
+
+ return set_pairable(conn, msg, pairable, data);
}
return invalid_args(msg);
@@ -2409,6 +2451,10 @@ static void adapter_up(struct btd_adapter *adapter, int dd)
adapter->discov_timeout = get_discoverable_timeout(srcaddr);
adapter->state = DISCOVER_TYPE_NONE;
+ /* Set pairable mode */
+ if (read_device_pairable(&adapter->bdaddr, &adapter->pairable) < 0)
+ adapter->pairable = TRUE;
+
/* Set scan mode */
if (read_device_mode(srcaddr, mode, sizeof(mode)) == 0) {
if (!strcmp(mode, "off")) {
@@ -2437,7 +2483,8 @@ static void adapter_up(struct btd_adapter *adapter, int dd)
} else if (!strcmp(mode, "discoverable")) {
/* Set discoverable only if timeout is 0 */
if (adapter->discov_timeout == 0) {
- adapter->mode = MODE_DISCOVERABLE;
+ adapter->mode = adapter->pairable ?
+ MODE_LIMITED : MODE_DISCOVERABLE;
adapter->scan_mode = SCAN_PAGE | SCAN_INQUIRY;
} else {
adapter->mode = MODE_CONNECTABLE;
@@ -2497,6 +2544,10 @@ static void adapter_up(struct btd_adapter *adapter, int dd)
ADAPTER_INTERFACE, "Discoverable",
DBUS_TYPE_BOOLEAN, &discoverable);
+ emit_property_changed(connection, adapter->path,
+ ADAPTER_INTERFACE, "Pairable",
+ DBUS_TYPE_BOOLEAN, &adapter->pairable);
+
load_drivers(adapter);
load_devices(adapter);
}
@@ -3496,3 +3547,16 @@ void btd_adapter_any_release_path(void)
g_free(adapter_any_path);
adapter_any_path = NULL;
}
+
+gboolean adapter_is_pairable(struct btd_adapter *adapter)
+{
+ return adapter->pairable;
+}
+
+gboolean adapter_pairing_initiator(struct btd_adapter *adapter, bdaddr_t *bda)
+{
+ if (!adapter->bonding)
+ return FALSE;
+
+ return (bacmp(&adapter->bonding->bdaddr, bda) == 0);
+}
diff --git a/src/adapter.h b/src/adapter.h
index 7d666a5b..eb206ac6 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -184,3 +184,5 @@ const char *adapter_any_get_path(void);
const char *btd_adapter_any_request_path(void);
void btd_adapter_any_release_path(void);
+gboolean adapter_is_pairable(struct btd_adapter *adapter);
+gboolean adapter_pairing_initiator(struct btd_adapter *adapter, bdaddr_t *bda);
diff --git a/src/dbus-hci.c b/src/dbus-hci.c
index 5b0a1f96..6f9f1bc5 100644
--- a/src/dbus-hci.c
+++ b/src/dbus-hci.c
@@ -239,6 +239,10 @@ int hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci)
return -1;
}
+ if (!adapter_pairing_initiator(adapter, sba) &&
+ !adapter_is_pairable(adapter))
+ return -EPERM;
+
ba2str(&ci->bdaddr, addr);
device = adapter_find_device(adapter, addr);
@@ -1466,6 +1470,10 @@ int hcid_dbus_get_io_cap(bdaddr_t *local, bdaddr_t *remote,
if (get_auth_requirements(local, remote, auth) < 0)
return -1;
+ if (!adapter_pairing_initiator(adapter, remote) &&
+ !adapter_is_pairable(adapter))
+ return -EPERM;
+
ba2str(remote, addr);
/* For CreatePairedDevice use dedicated bonding */
diff --git a/src/storage.c b/src/storage.c
index ac1ec5bd..212f7ce2 100644
--- a/src/storage.c
+++ b/src/storage.c
@@ -1028,3 +1028,33 @@ int read_device_id(const gchar *srcaddr, const gchar *dstaddr,
return 0;
}
+
+int write_device_pairable(bdaddr_t *bdaddr, gboolean mode)
+{
+ char filename[PATH_MAX + 1];
+
+ create_filename(filename, PATH_MAX, bdaddr, "config");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ return textfile_put(filename, "pairable", mode ? "yes" : "no");
+}
+
+int read_device_pairable(bdaddr_t *bdaddr, gboolean *mode)
+{
+ char filename[PATH_MAX + 1], *str;
+
+ create_filename(filename, PATH_MAX, bdaddr, "config");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ str = textfile_get(filename, "pairable");
+ if (!str)
+ return -ENOENT;
+
+ *mode = strcmp(str, "yes") == 0 ? TRUE : FALSE;
+
+ free(str);
+
+ return 0;
+}
diff --git a/src/storage.h b/src/storage.h
index 29f08d80..b6bedbed 100644
--- a/src/storage.h
+++ b/src/storage.h
@@ -68,6 +68,8 @@ int store_device_id(const gchar *src, const gchar *dst,
int read_device_id(const gchar *src, const gchar *dst,
uint16_t *source, uint16_t *vendor,
uint16_t *product, uint16_t *version);
+int write_device_pairable(bdaddr_t *local, gboolean mode);
+int read_device_pairable(bdaddr_t *local, gboolean *mode);
#define PNP_UUID "00001200-0000-1000-8000-00805f9b34fb"