diff --git a/doc/network-api.txt b/doc/network-api.txt
index 2ec59ab..109da28 100644
--- a/doc/network-api.txt
+++ b/doc/network-api.txt
Interface org.bluez.Network1
Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+Methods string Connect(string uuid)
+
+ Connect to the network device and return the network
+ interface name. Examples of the interface name are
+ bnep0, bnep1 etc.
+
+ uuid can be either one of "gn", "panu" or "nap" (case
+ insensitive) or a traditional string representation of
+ UUID or a hexadecimal number.
+
+ The connection will be closed and network device
+ released either upon calling Disconnect() or when
+ the client disappears from the message bus.
+
+ Possible errors: org.bluez.Error.AlreadyConnected
+ org.bluez.Error.ConnectionAttemptFailed
+
+ void Disconnect()
+
+ Disconnect from the network device.
+
+ To abort a connection attempt in case of errors or
+ timeouts in the client it is fine to call this method.
+
+ Possible errors: org.bluez.Error.Failed
+
Properties boolean Connected [readonly]
Indicates if the device is connected.
diff --git a/profiles/network/common.c b/profiles/network/common.c
index 8589a3e..34bdc0e 100644
--- a/profiles/network/common.c
+++ b/profiles/network/common.c
{ NULL }
};
+uint16_t bnep_service_id(const char *svc)
+{
+ int i;
+ uint16_t id;
+
+ /* Friendly service name */
+ for (i = 0; __svc[i].name; i++) {
+ if (!strcasecmp(svc, __svc[i].name))
+ return __svc[i].id;
+ }
+
+ /* UUID 128 string */
+ for (i = 0; __svc[i].uuid128; i++) {
+ if (!strcasecmp(svc, __svc[i].uuid128))
+ return __svc[i].id;
+ }
+
+ /* Try convert to HEX */
+ id = strtol(svc, NULL, 16);
+ if ((id < BNEP_SVC_PANU) || (id > BNEP_SVC_GN))
+ return 0;
+
+ return id;
+}
+
const char *bnep_uuid(uint16_t id)
{
int i;
diff --git a/profiles/network/common.h b/profiles/network/common.h
index ca357c4..9a8caac 100644
--- a/profiles/network/common.h
+++ b/profiles/network/common.h
int bnep_init(void);
int bnep_cleanup(void);
+uint16_t bnep_service_id(const char *svc);
const char *bnep_uuid(uint16_t id);
const char *bnep_name(uint16_t id);
diff --git a/profiles/network/connection.c b/profiles/network/connection.c
index 5fa3e1b..b56312f 100644
--- a/profiles/network/connection.c
+++ b/profiles/network/connection.c
struct network_peer *peer;
guint attempt_cnt;
guint timeout_source;
+ DBusMessage *connect;
};
struct __service_16 {
return FALSE;
}
+static void local_connect_cb(struct network_conn *nc, int err)
+{
+ DBusConnection *conn = btd_get_dbus_connection();
+ const char *pdev = nc->dev;
+
+ if (err < 0) {
+ DBusMessage *reply = btd_error_failed(nc->connect,
+ strerror(-err));
+ g_dbus_send_message(conn, reply);
+ } else {
+ g_dbus_send_reply(conn, nc->connect, DBUS_TYPE_STRING, &pdev,
+ DBUS_TYPE_INVALID);
+ }
+
+ dbus_message_unref(nc->connect);
+ nc->connect = NULL;
+}
+
static void cancel_connection(struct network_conn *nc, int err)
{
if (nc->timeout_source > 0) {
}
network_connected(nc->peer->device, nc->id, err);
+ if (nc->connect)
+ local_connect_cb(nc, err);
g_io_channel_shutdown(nc->io, TRUE, NULL);
g_io_channel_unref(nc->io);
bnep_if_up(nc->dev);
network_connected(nc->peer->device, nc->id, 0);
+ if (nc->connect)
+ local_connect_cb(nc, 0);
conn = btd_get_dbus_connection();
path = device_get_path(nc->peer->device);
cancel_connection(nc, -EIO);
}
+static DBusMessage *local_connect(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct network_peer *peer = data;
+ struct network_conn *nc;
+ const char *svc;
+ uint16_t id;
+ int err;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &svc,
+ DBUS_TYPE_INVALID) == FALSE)
+ return btd_error_invalid_args(msg);
+
+ id = bnep_service_id(svc);
+
+ nc = find_connection(peer->connections, id);
+ if (nc && nc->connect)
+ return btd_error_busy(msg);
+
+ err = connection_connect(peer->device, id);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ nc = find_connection(peer->connections, id);
+ if (!nc)
+ return btd_error_failed(msg, strerror(-err));
+
+ nc->connect = dbus_message_ref(msg);
+
+ return NULL;
+}
+
/* Connect and initiate BNEP session */
int connection_connect(struct btd_device *device, uint16_t id)
{
return 0;
}
+static DBusMessage *local_disconnect(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct network_peer *peer = data;
+ GSList *l;
+
+ for (l = peer->connections; l; l = l->next) {
+ struct network_conn *nc = l->data;
+ int err;
+
+ if (nc->state == DISCONNECTED)
+ continue;
+
+ err = connection_disconnect(peer->device, nc->id);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ }
+
+ return btd_error_not_connected(msg);
+}
+
static gboolean
network_property_get_connected(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *data)
connection_destroy(NULL, nc);
+ if (nc->connect)
+ dbus_message_unref(nc->connect);
+
g_free(nc);
nc = NULL;
}
peer_free(peer);
}
+static const GDBusMethodTable connection_methods[] = {
+ { GDBUS_ASYNC_METHOD("Connect",
+ GDBUS_ARGS({"uuid", "s"}),
+ GDBUS_ARGS({"interface", "s"}),
+ local_connect) },
+ { GDBUS_METHOD("Disconnect",
+ NULL, NULL, local_disconnect) },
+ { }
+};
+
static const GDBusPropertyTable connection_properties[] = {
{ "Connected", "b", network_property_get_connected },
{ "Interface", "s", network_property_get_interface, NULL,
if (g_dbus_register_interface(btd_get_dbus_connection(), path,
NETWORK_PEER_INTERFACE,
- NULL, NULL, connection_properties,
+ connection_methods,
+ NULL, connection_properties,
peer, path_unregister) == FALSE) {
error("D-Bus failed to register %s interface",
NETWORK_PEER_INTERFACE);