From: Mikel Astiz <[email protected]>
v4 considers the review from Luiz and Johan, including:
- guint used for authorization ids, instead of int
- static local variable used to generate new ids
- service_auth_id renamed to auth_id
>From original cover-letter:
The agent-based profile authorization makes a special consideration for audio profiles: they are processed as if they all belonged to one single profile. This includes several internal policies that are inconvenient for IVI use-cases.
This patchset removes this exception by making use of the conventional authorization mechanism also for audio profiles.
The new approach is not straightforward since devices might send several connection requets in parallel (i.e. HFP, A2DP, AVRCP). This cannot be neither automatically rejected (EBUSY) nor forwarded in parallel to the agent, so a queue was added to store the pending authorization requests. These will be sent to the agent sequentially.
Mikel Astiz (5):
build: Update glib dependency to 2.32
adapter: Replace device authorizing flag
adapter: Use authorization id for cancelling
adapter: Queue parallel authorization requests
audio: Drop audio-specific authorization mechanism
acinclude.m4 | 4 +-
audio/avctp.c | 27 +++---
audio/avdtp.c | 23 ++++--
audio/device.c | 144 --------------------------------
audio/device.h | 12 +--
audio/manager.c | 28 ++++---
plugins/service.c | 18 ++--
profiles/input/server.c | 7 +-
profiles/network/server.c | 9 +-
profiles/sap/server.c | 8 +-
src/adapter.c | 204 +++++++++++++++++++++++++++++-----------------
src/adapter.h | 4 +-
src/device.c | 11 ---
src/device.h | 2 -
src/profile.c | 25 ++----
15 files changed, 207 insertions(+), 319 deletions(-)
--
1.7.11.4
From: Mikel Astiz <[email protected]>
Remove the audio-specific service authorization mechanism in favor of
using the conventional one.
The main difference is that audio profiles will be authorized
independently. Therefore a single connection might result in several
profile authorization requests to the agent (i.e. HFP, A2DP and AVRCP).
This removes any internal policy that would skip the authorization
procedure, making it simpler and more convenient for IVI use-cases.
Agents interested in simulating the old behavior are encouraged to
either set the device as trusted or just reply to the additional
authorization requests automatically without user intervention.
---
audio/avctp.c | 27 ++++------
audio/avdtp.c | 23 ++++++---
audio/device.c | 149 --------------------------------------------------------
audio/device.h | 12 +----
audio/manager.c | 28 ++++++-----
5 files changed, 43 insertions(+), 196 deletions(-)
diff --git a/audio/avctp.c b/audio/avctp.c
index 6fd5491..b7b3083 100644
--- a/audio/avctp.c
+++ b/audio/avctp.c
@@ -143,6 +143,7 @@ struct avctp {
GIOChannel *browsing_io;
guint control_io_id;
guint browsing_io_id;
+ guint auth_id;
uint16_t control_mtu;
uint16_t browsing_mtu;
@@ -360,13 +361,9 @@ static void avctp_disconnected(struct avctp *session)
g_source_remove(session->control_io_id);
session->control_io_id = 0;
- if (session->state == AVCTP_STATE_CONNECTING) {
- struct audio_device *dev;
-
- dev = manager_get_device(&session->server->src,
- &session->dst, FALSE);
- audio_device_cancel_authorization(dev, auth_cb,
- session);
+ if (session->auth_id != 0) {
+ btd_cancel_authorization(session->auth_id);
+ session->auth_id = 0;
}
}
@@ -409,15 +406,7 @@ static void avctp_set_state(struct avctp *session, avctp_state_t new_state)
switch (new_state) {
case AVCTP_STATE_DISCONNECTED:
DBG("AVCTP Disconnected");
-
avctp_disconnected(session);
-
- if (old_state != AVCTP_STATE_CONNECTED)
- break;
-
- if (!audio_device_is_active(dev, NULL))
- audio_device_set_authorized(dev, FALSE);
-
break;
case AVCTP_STATE_CONNECTING:
DBG("AVCTP Connecting");
@@ -769,6 +758,8 @@ static void auth_cb(DBusError *derr, void *user_data)
struct avctp *session = user_data;
GError *err = NULL;
+ session->auth_id = 0;
+
if (session->control_io_id) {
g_source_remove(session->control_io_id);
session->control_io_id = 0;
@@ -854,8 +845,10 @@ static void avctp_control_confirm(struct avctp *session, GIOChannel *chan,
avctp_set_state(session, AVCTP_STATE_CONNECTING);
session->control_io = g_io_channel_ref(chan);
- if (audio_device_request_authorization(dev, AVRCP_TARGET_UUID,
- auth_cb, session) < 0)
+ session->auth_id = btd_request_authorization(&dev->src, &dev->dst,
+ AVRCP_TARGET_UUID,
+ auth_cb, session);
+ if (session->auth_id == 0)
goto drop;
session->control_io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP |
diff --git a/audio/avdtp.c b/audio/avdtp.c
index d44c504..8836ca1 100644
--- a/audio/avdtp.c
+++ b/audio/avdtp.c
@@ -400,6 +400,8 @@ struct avdtp {
/* True if the entire device is being disconnected */
gboolean device_disconnect;
+ guint auth_id;
+
GIOChannel *io;
guint io_id;
@@ -1129,16 +1131,21 @@ static void release_stream(struct avdtp_stream *stream, struct avdtp *session)
static int avdtp_cancel_authorization(struct avdtp *session)
{
- struct audio_device *dev;
+ int err;
if (session->state != AVDTP_SESSION_STATE_CONNECTING)
return 0;
- dev = manager_get_device(&session->server->src, &session->dst, FALSE);
- if (dev == NULL)
- return -ENODEV;
+ if (session->auth_id == 0)
+ return 0;
- return audio_device_cancel_authorization(dev, auth_cb, session);
+ err = btd_cancel_authorization(session->auth_id);
+ if (err < 0)
+ return err;
+
+ session->auth_id = 0;
+
+ return 0;
}
static void connection_lost(struct avdtp *session, int err)
@@ -2507,7 +2514,6 @@ static void avdtp_confirm_cb(GIOChannel *chan, gpointer data)
struct audio_device *dev;
char address[18];
bdaddr_t src, dst;
- int perr;
GError *err = NULL;
bt_io_get(chan, &err,
@@ -2566,9 +2572,10 @@ static void avdtp_confirm_cb(GIOChannel *chan, gpointer data)
session->io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
(GIOFunc) session_cb, session);
- perr = audio_device_request_authorization(dev, ADVANCED_AUDIO_UUID,
+ session->auth_id = btd_request_authorization(&dev->src, &dev->dst,
+ ADVANCED_AUDIO_UUID,
auth_cb, session);
- if (perr < 0) {
+ if (session->auth_id == 0) {
avdtp_set_state(session, AVDTP_SESSION_STATE_DISCONNECTED);
avdtp_unref(session);
goto drop;
diff --git a/audio/device.c b/audio/device.c
index c6ae96a..175e3c0 100644
--- a/audio/device.c
+++ b/audio/device.c
@@ -71,19 +71,12 @@ typedef enum {
AUDIO_STATE_CONNECTED,
} audio_state_t;
-struct service_auth {
- service_auth_cb cb;
- void *user_data;
-};
-
struct dev_priv {
audio_state_t state;
headset_state_t hs_state;
sink_state_t sink_state;
avctp_state_t avctp_state;
- GSList *auths;
- guint auth_id;
DBusMessage *conn_req;
DBusMessage *dc_req;
@@ -94,8 +87,6 @@ struct dev_priv {
guint dc_id;
gboolean disconnecting;
- gboolean authorized;
- guint auth_idle_id;
};
static unsigned int sink_callback_id = 0;
@@ -110,8 +101,6 @@ static void device_free(struct audio_device *dev)
btd_device_unref(dev->btd_dev);
if (priv) {
- if (priv->auths)
- audio_device_cancel_authorization(dev, NULL, NULL);
if (priv->control_timer)
g_source_remove(priv->control_timer);
if (priv->avdtp_timer)
@@ -238,8 +227,6 @@ static void device_set_state(struct audio_device *dev, audio_state_t new_state)
return;
if (new_state == AUDIO_STATE_DISCONNECTED) {
- priv->authorized = FALSE;
-
if (priv->dc_id) {
device_remove_disconnect_watch(dev->btd_dev,
priv->dc_id);
@@ -732,139 +719,3 @@ void audio_device_unregister(struct audio_device *device)
device_free(device);
}
-
-static void auth_cb(DBusError *derr, void *user_data)
-{
- struct audio_device *dev = user_data;
- struct dev_priv *priv = dev->priv;
-
- priv->auth_id = 0;
-
- if (derr == NULL)
- priv->authorized = TRUE;
-
- while (priv->auths) {
- struct service_auth *auth = priv->auths->data;
-
- auth->cb(derr, auth->user_data);
- priv->auths = g_slist_remove(priv->auths, auth);
- g_free(auth);
- }
-}
-
-static gboolean auth_idle_cb(gpointer user_data)
-{
- struct audio_device *dev = user_data;
- struct dev_priv *priv = dev->priv;
-
- priv->auth_idle_id = 0;
-
- auth_cb(NULL, dev);
-
- return FALSE;
-}
-
-static gboolean audio_device_is_connected(struct audio_device *dev)
-{
- if (dev->headset) {
- headset_state_t state = headset_get_state(dev);
-
- if (state == HEADSET_STATE_CONNECTED ||
- state == HEADSET_STATE_PLAY_IN_PROGRESS ||
- state == HEADSET_STATE_PLAYING)
- return TRUE;
- }
-
- if (dev->sink) {
- sink_state_t state = sink_get_state(dev);
-
- if (state == SINK_STATE_CONNECTED ||
- state == SINK_STATE_PLAYING)
- return TRUE;
- }
-
- if (dev->source) {
- source_state_t state = source_get_state(dev);
-
- if (state == SOURCE_STATE_CONNECTED ||
- state == SOURCE_STATE_PLAYING)
- return TRUE;
- }
-
- return FALSE;
-}
-
-int audio_device_request_authorization(struct audio_device *dev,
- const char *uuid, service_auth_cb cb,
- void *user_data)
-{
- struct dev_priv *priv = dev->priv;
- struct service_auth *auth;
-
- auth = g_try_new0(struct service_auth, 1);
- if (!auth)
- return -ENOMEM;
-
- auth->cb = cb;
- auth->user_data = user_data;
-
- priv->auths = g_slist_append(priv->auths, auth);
- if (g_slist_length(priv->auths) > 1)
- return 0;
-
- if (priv->authorized || audio_device_is_connected(dev)) {
- priv->auth_idle_id = g_idle_add(auth_idle_cb, dev);
- return 0;
- }
-
- priv->auth_id = btd_request_authorization(&dev->src, &dev->dst, uuid,
- auth_cb, dev);
- if (priv->auth_id != 0)
- return 0;
-
- priv->auths = g_slist_remove(priv->auths, auth);
- g_free(auth);
-
- return -EPERM;
-}
-
-int audio_device_cancel_authorization(struct audio_device *dev,
- authorization_cb cb, void *user_data)
-{
- struct dev_priv *priv = dev->priv;
- GSList *l, *next;
-
- for (l = priv->auths; l != NULL; l = next) {
- struct service_auth *auth = l->data;
-
- next = g_slist_next(l);
-
- if (cb && auth->cb != cb)
- continue;
-
- if (user_data && auth->user_data != user_data)
- continue;
-
- priv->auths = g_slist_remove(priv->auths, auth);
- g_free(auth);
- }
-
- if (g_slist_length(priv->auths) == 0) {
- if (priv->auth_idle_id > 0) {
- g_source_remove(priv->auth_idle_id);
- priv->auth_idle_id = 0;
- } else {
- btd_cancel_authorization(priv->auth_id);
- priv->auth_id = 0;
- }
- }
-
- return 0;
-}
-
-void audio_device_set_authorized(struct audio_device *dev, gboolean auth)
-{
- struct dev_priv *priv = dev->priv;
-
- priv->authorized = auth;
-}
diff --git a/audio/device.h b/audio/device.h
index f9b868f..2b92528 100644
--- a/audio/device.h
+++ b/audio/device.h
@@ -47,6 +47,7 @@ struct audio_device {
struct target *target;
guint hs_preauth_id;
+ guint hs_auth_id;
struct dev_priv *priv;
};
@@ -59,14 +60,3 @@ void audio_device_unregister(struct audio_device *device);
gboolean audio_device_is_active(struct audio_device *dev,
const char *interface);
-
-typedef void (*authorization_cb) (DBusError *derr, void *user_data);
-
-int audio_device_cancel_authorization(struct audio_device *dev,
- authorization_cb cb, void *user_data);
-
-int audio_device_request_authorization(struct audio_device *dev,
- const char *uuid, authorization_cb cb,
- void *user_data);
-
-void audio_device_set_authorized(struct audio_device *dev, gboolean auth);
diff --git a/audio/manager.c b/audio/manager.c
index 70be01b..dbc98d5 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -300,6 +300,8 @@ static void headset_auth_cb(DBusError *derr, void *user_data)
GError *err = NULL;
GIOChannel *io;
+ device->hs_auth_id = 0;
+
if (device->hs_preauth_id) {
g_source_remove(device->hs_preauth_id);
device->hs_preauth_id = 0;
@@ -328,7 +330,8 @@ static gboolean hs_preauth_cb(GIOChannel *chan, GIOCondition cond,
DBG("Headset disconnected during authorization");
- audio_device_cancel_authorization(device, headset_auth_cb, device);
+ btd_cancel_authorization(device->hs_auth_id);
+ device->hs_auth_id = 0;
headset_set_state(device, HEADSET_STATE_DISCONNECTED);
@@ -343,7 +346,6 @@ static void ag_confirm(GIOChannel *chan, gpointer data)
struct audio_device *device;
gboolean hfp_active;
bdaddr_t src, dst;
- int perr;
GError *err = NULL;
uint8_t ch;
@@ -398,10 +400,13 @@ static void ag_confirm(GIOChannel *chan, gpointer data)
headset_set_state(device, HEADSET_STATE_CONNECTING);
- perr = audio_device_request_authorization(device, server_uuid,
- headset_auth_cb, device);
- if (perr < 0) {
- DBG("Authorization denied: %s", strerror(-perr));
+ device->hs_auth_id = btd_request_authorization(&device->src,
+ &device->dst,
+ server_uuid,
+ headset_auth_cb,
+ device);
+ if (device->hs_auth_id == 0) {
+ DBG("Authorization denied");
headset_set_state(device, HEADSET_STATE_DISCONNECTED);
return;
}
@@ -443,7 +448,7 @@ static void hf_io_cb(GIOChannel *chan, gpointer data)
uint8_t ch;
const char *server_uuid, *remote_uuid;
struct audio_device *device;
- int perr;
+ guint auth_id;
bt_io_get(chan, &err,
BT_IO_OPT_SOURCE_BDADDR, &src,
@@ -480,10 +485,11 @@ static void hf_io_cb(GIOChannel *chan, gpointer data)
goto drop;
}
- perr = audio_device_request_authorization(device, server_uuid,
- gateway_auth_cb, device);
- if (perr < 0) {
- DBG("Authorization denied: %s", strerror(-perr));
+ auth_id = btd_request_authorization(&device->src, &device->dst,
+ server_uuid, gateway_auth_cb,
+ device);
+ if (auth_id == 0) {
+ DBG("Authorization denied");
gateway_set_state(device, GATEWAY_STATE_DISCONNECTED);
}
--
1.7.11.4
From: Mikel Astiz <[email protected]>
Remote device could try to connect several profiles in parallel, or
several devices could be trying to connect services. Instead of
returning EBUSY, this patch adds a queue to each adapter such that the
authorization requests will be queued and processed sequentially.
---
src/adapter.c | 181 +++++++++++++++++++++++++++++++++-------------------------
1 file changed, 103 insertions(+), 78 deletions(-)
diff --git a/src/adapter.c b/src/adapter.c
index 982fd8d..f11be70 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -100,8 +100,10 @@ struct service_auth {
guint id;
service_auth_cb cb;
void *user_data;
+ const char *uuid;
struct btd_device *device;
struct btd_adapter *adapter;
+ struct agent *agent; /* NULL for queued auths */
};
struct btd_adapter {
@@ -125,8 +127,8 @@ struct btd_adapter {
GSList *found_devices;
GSList *oor_devices; /* out of range device list */
struct agent *agent; /* For the new API */
- guint auth_idle_id; /* Ongoing authorization (trusted) */
- struct service_auth *auth; /* Ongoing authorization */
+ guint auth_idle_id; /* Pending authorization dequeue */
+ GQueue *auths; /* Ongoing and pending auths */
GSList *connections; /* Connected devices */
GSList *devices; /* Devices structure pointers */
GSList *mode_sessions; /* Request Mode sessions */
@@ -154,6 +156,8 @@ struct btd_adapter {
GSList *profiles;
};
+static gboolean process_auth_queue(gpointer user_data);
+
static void dev_info_free(void *data)
{
struct remote_dev_info *dev = data;
@@ -947,16 +951,49 @@ static struct btd_device *adapter_create_device(struct btd_adapter *adapter,
return device;
}
+static void service_auth_cancel(struct service_auth *auth)
+{
+ DBusError derr;
+
+ dbus_error_init(&derr);
+ dbus_set_error_const(&derr, "org.bluez.Error.Canceled", NULL);
+
+ auth->cb(&derr, auth->user_data);
+
+ dbus_error_free(&derr);
+
+ if (auth->agent != NULL)
+ agent_cancel(auth->agent);
+
+ g_free(auth);
+}
+
void adapter_remove_device(struct btd_adapter *adapter,
struct btd_device *device,
gboolean remove_storage)
{
const gchar *dev_path = device_get_path(device);
- struct agent *agent;
+ GList *l;
adapter->devices = g_slist_remove(adapter->devices, device);
adapter->connections = g_slist_remove(adapter->connections, device);
+ l = adapter->auths->head;
+ while (l != NULL) {
+ struct service_auth *auth = l->data;
+ GList *next = g_list_next(l);
+
+ if (auth->device != device) {
+ l = next;
+ continue;
+ }
+
+ g_queue_delete_link(adapter->auths, l);
+ l = next;
+
+ service_auth_cancel(auth);
+ }
+
adapter_update_devices(adapter);
g_dbus_emit_signal(btd_get_dbus_connection(), adapter->path,
@@ -964,14 +1001,6 @@ void adapter_remove_device(struct btd_adapter *adapter,
DBUS_TYPE_OBJECT_PATH, &dev_path,
DBUS_TYPE_INVALID);
- agent = device_get_agent(device);
-
- if (agent && adapter->auth && adapter->auth->device == device) {
- g_free(adapter->auth);
- adapter->auth = NULL;
- agent_cancel(agent);
- }
-
device_remove(device, remove_storage);
}
@@ -2438,8 +2467,7 @@ static void adapter_free(gpointer user_data)
if (adapter->auth_idle_id)
g_source_remove(adapter->auth_idle_id);
- if (adapter->auth)
- g_free(adapter->auth);
+ g_queue_free_full(adapter->auths, g_free);
if (adapter->off_timer)
off_timer_remove(adapter);
@@ -2533,6 +2561,7 @@ struct btd_adapter *adapter_create(int id)
}
adapter->dev_id = id;
+ adapter->auths = g_queue_new();
snprintf(path, sizeof(path), "%s/hci%d", base_path, id);
adapter->path = g_strdup(path);
@@ -3176,26 +3205,60 @@ static void agent_auth_cb(struct agent *agent, DBusError *derr,
void *user_data)
{
struct btd_adapter *adapter = user_data;
- struct service_auth *auth = adapter->auth;
+ struct service_auth *auth = adapter->auths->head->data;
- adapter->auth = NULL;
+ g_queue_pop_head(adapter->auths);
auth->cb(derr, auth->user_data);
g_free(auth);
+
+ adapter->auth_idle_id = g_idle_add(process_auth_queue, adapter);
}
-static gboolean auth_idle_cb(gpointer user_data)
+static gboolean process_auth_queue(gpointer user_data)
{
struct btd_adapter *adapter = user_data;
- struct service_auth *auth = adapter->auth;
+ DBusError err;
- adapter->auth = NULL;
adapter->auth_idle_id = 0;
- auth->cb(NULL, auth->user_data);
+ dbus_error_init(&err);
+ dbus_set_error_const(&err, "org.bluez.Error.Rejected", NULL);
- g_free(auth);
+ while (!g_queue_is_empty(adapter->auths)) {
+ struct service_auth *auth = adapter->auths->head->data;
+ struct btd_device *device = auth->device;
+ const gchar *dev_path;
+
+ if (device_is_trusted(device) == TRUE) {
+ auth->cb(NULL, auth->user_data);
+ goto next;
+ }
+
+ auth->agent = device_get_agent(device);
+ if (auth->agent == NULL) {
+ warn("Can't find device agent");
+ auth->cb(&err, auth->user_data);
+ goto next;
+ }
+
+ dev_path = device_get_path(device);
+
+ if (agent_authorize(auth->agent, dev_path, auth->uuid,
+ agent_auth_cb, adapter, NULL) < 0) {
+ auth->cb(&err, auth->user_data);
+ goto next;
+ }
+
+ break;
+
+next:
+ g_free(auth);
+ g_queue_pop_head(adapter->auths);
+ }
+
+ dbus_error_free(&err);
return FALSE;
}
@@ -3206,10 +3269,7 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
{
struct service_auth *auth;
struct btd_device *device;
- struct agent *agent;
char address[18];
- const gchar *dev_path;
- int err;
static guint id = 0;
ba2str(dst, address);
@@ -3221,42 +3281,27 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
if (!g_slist_find(adapter->connections, device))
error("Authorization request for non-connected device!?");
- if (adapter->auth != NULL)
- return 0;
-
auth = g_try_new0(struct service_auth, 1);
if (!auth)
return 0;
auth->cb = cb;
auth->user_data = user_data;
+ auth->uuid = uuid;
auth->device = device;
auth->adapter = adapter;
auth->id = ++id;
- if (device_is_trusted(device) == TRUE) {
- adapter->auth_idle_id = g_idle_add(auth_idle_cb, adapter);
- goto done;
- }
+ g_queue_push_tail(adapter->auths, auth);
- agent = device_get_agent(device);
- if (!agent) {
- warn("Can't find device agent");
- g_free(auth);
- return 0;
- }
+ if (adapter->auths->length != 1)
+ return auth->id;
- dev_path = device_get_path(device);
+ if (adapter->auth_idle_id != 0)
+ return auth->id;
- err = agent_authorize(agent, dev_path, uuid, agent_auth_cb, adapter,
- NULL);
- if (err < 0) {
- g_free(auth);
- return 0;
- }
+ adapter->auth_idle_id = g_idle_add(process_auth_queue, adapter);
-done:
- adapter->auth = auth;
return auth->id;
}
@@ -3288,18 +3333,20 @@ guint btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
return 0;
}
-static struct btd_adapter *find_authorization(guint id)
+static struct service_auth *find_authorization(guint id)
{
GSList *l;
+ GList *l2;
for (l = manager_get_adapters(); l != NULL; l = g_slist_next(l)) {
struct btd_adapter *adapter = l->data;
- if (adapter->auth == NULL)
- continue;
+ for (l2 = adapter->auths->head; l2 != NULL; l2 = l2->next) {
+ struct service_auth *auth = l2->data;
- if (adapter->auth->id == id)
- return adapter;
+ if (auth->id == id)
+ return auth;
+ }
}
return NULL;
@@ -3307,39 +3354,17 @@ static struct btd_adapter *find_authorization(guint id)
int btd_cancel_authorization(guint id)
{
- struct btd_adapter *adapter;
- struct agent *agent;
- int err;
-
- adapter = find_authorization(id);
- if (adapter == NULL)
- return -EPERM;
-
- if (adapter->auth_idle_id) {
- g_source_remove(adapter->auth_idle_id);
- adapter->auth_idle_id = 0;
- g_free(adapter->auth);
- adapter->auth = NULL;
- return 0;
- }
-
- /*
- * FIXME: Cancel fails if authorization is requested to adapter's
- * agent and in the meanwhile CreatePairedDevice is called.
- */
+ struct service_auth *auth;
- agent = device_get_agent(adapter->auth->device);
- if (!agent)
+ auth = find_authorization(id);
+ if (auth == NULL)
return -EPERM;
- err = agent_cancel(agent);
+ g_queue_remove(auth->adapter->auths, auth);
- if (err == 0) {
- g_free(adapter->auth);
- adapter->auth = NULL;
- }
+ service_auth_cancel(auth);
- return err;
+ return 0;
}
static gchar *adapter_any_path = NULL;
--
1.7.11.4
From: Mikel Astiz <[email protected]>
Return a request id in btd_request_authorization() in order to be used
when the request needs to be cancelled. This id alone will be enough to
use btd_cancel_authorization().
---
audio/device.c | 25 +++++++++++-------
plugins/service.c | 18 ++++++++-----
profiles/input/server.c | 7 +++--
profiles/network/server.c | 9 +++----
profiles/sap/server.c | 8 +++---
src/adapter.c | 67 ++++++++++++++++++++++++++++-------------------
src/adapter.h | 4 +--
src/profile.c | 25 ++++++------------
8 files changed, 87 insertions(+), 76 deletions(-)
diff --git a/audio/device.c b/audio/device.c
index 99d6512..c6ae96a 100644
--- a/audio/device.c
+++ b/audio/device.c
@@ -83,6 +83,7 @@ struct dev_priv {
sink_state_t sink_state;
avctp_state_t avctp_state;
GSList *auths;
+ guint auth_id;
DBusMessage *conn_req;
DBusMessage *dc_req;
@@ -737,6 +738,8 @@ static void auth_cb(DBusError *derr, void *user_data)
struct audio_device *dev = user_data;
struct dev_priv *priv = dev->priv;
+ priv->auth_id = 0;
+
if (derr == NULL)
priv->authorized = TRUE;
@@ -797,7 +800,6 @@ int audio_device_request_authorization(struct audio_device *dev,
{
struct dev_priv *priv = dev->priv;
struct service_auth *auth;
- int err;
auth = g_try_new0(struct service_auth, 1);
if (!auth)
@@ -815,14 +817,15 @@ int audio_device_request_authorization(struct audio_device *dev,
return 0;
}
- err = btd_request_authorization(&dev->src, &dev->dst, uuid, auth_cb,
- dev);
- if (err < 0) {
- priv->auths = g_slist_remove(priv->auths, auth);
- g_free(auth);
- }
+ priv->auth_id = btd_request_authorization(&dev->src, &dev->dst, uuid,
+ auth_cb, dev);
+ if (priv->auth_id != 0)
+ return 0;
+
+ priv->auths = g_slist_remove(priv->auths, auth);
+ g_free(auth);
- return err;
+ return -EPERM;
}
int audio_device_cancel_authorization(struct audio_device *dev,
@@ -850,8 +853,10 @@ int audio_device_cancel_authorization(struct audio_device *dev,
if (priv->auth_idle_id > 0) {
g_source_remove(priv->auth_idle_id);
priv->auth_idle_id = 0;
- } else
- btd_cancel_authorization(&dev->src, &dev->dst);
+ } else {
+ btd_cancel_authorization(priv->auth_id);
+ priv->auth_id = 0;
+ }
}
return 0;
diff --git a/plugins/service.c b/plugins/service.c
index e02a673..45886ac 100644
--- a/plugins/service.c
+++ b/plugins/service.c
@@ -65,6 +65,7 @@ struct pending_auth {
char *sender;
bdaddr_t dst;
char uuid[MAX_LEN_UUID_STR];
+ guint id;
};
struct service_adapter {
@@ -557,8 +558,9 @@ done:
else
bacpy(&src, BDADDR_ANY);
- btd_request_authorization(&src, &auth->dst,
- auth->uuid, auth_cb, serv_adapter);
+ auth->id = btd_request_authorization(&src, &auth->dst,
+ auth->uuid, auth_cb,
+ serv_adapter);
}
static DBusMessage *request_authorization(DBusConnection *conn,
@@ -633,8 +635,9 @@ static DBusMessage *request_authorization(DBusConnection *conn,
else
bacpy(&src, BDADDR_ANY);
- if (btd_request_authorization(&src, &auth->dst, auth->uuid, auth_cb,
- serv_adapter) < 0) {
+ auth->id = btd_request_authorization(&src, &auth->dst, auth->uuid,
+ auth_cb, serv_adapter);
+ if (auth->id == 0) {
serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
auth);
g_free(auth);
@@ -664,7 +667,7 @@ static DBusMessage *cancel_authorization(DBusConnection *conn,
else
bacpy(&src, BDADDR_ANY);
- btd_cancel_authorization(&src, &auth->dst);
+ btd_cancel_authorization(auth->id);
reply = btd_error_not_authorized(auth->msg);
dbus_message_unref(auth->msg);
@@ -683,8 +686,9 @@ static DBusMessage *cancel_authorization(DBusConnection *conn,
else
bacpy(&src, BDADDR_ANY);
- btd_request_authorization(&src, &auth->dst,
- auth->uuid, auth_cb, serv_adapter);
+ auth->id = btd_request_authorization(&src, &auth->dst,
+ auth->uuid, auth_cb,
+ serv_adapter);
done:
return dbus_message_new_method_return(msg);
diff --git a/profiles/input/server.c b/profiles/input/server.c
index f71fdc0..eaf3b6a 100644
--- a/profiles/input/server.c
+++ b/profiles/input/server.c
@@ -154,7 +154,7 @@ static void confirm_event_cb(GIOChannel *chan, gpointer user_data)
bdaddr_t src, dst;
GError *err = NULL;
char addr[18];
- int ret;
+ guint ret;
bt_io_get(chan, &err,
BT_IO_OPT_SOURCE_BDADDR, &src,
@@ -179,12 +179,11 @@ static void confirm_event_cb(GIOChannel *chan, gpointer user_data)
ret = btd_request_authorization(&src, &dst, HID_UUID,
auth_callback, server);
- if (ret == 0)
+ if (ret != 0)
return;
ba2str(&src, addr);
- error("input: authorization for %s failed: %s (%d)",
- addr, strerror(-ret), -ret);
+ error("input: authorization for %s failed", addr);
g_io_channel_unref(server->confirm);
server->confirm = NULL;
diff --git a/profiles/network/server.c b/profiles/network/server.c
index 43ce9d9..6ee4770 100644
--- a/profiles/network/server.c
+++ b/profiles/network/server.c
@@ -500,10 +500,10 @@ static void confirm_event(GIOChannel *chan, gpointer user_data)
{
struct network_adapter *na = user_data;
struct network_server *ns;
- int perr;
bdaddr_t src, dst;
char address[18];
GError *err = NULL;
+ guint ret;
bt_io_get(chan, &err,
BT_IO_OPT_SOURCE_BDADDR, &src,
@@ -537,11 +537,10 @@ static void confirm_event(GIOChannel *chan, gpointer user_data)
bacpy(&na->setup->dst, &dst);
na->setup->io = g_io_channel_ref(chan);
- perr = btd_request_authorization(&src, &dst, BNEP_SVC_UUID,
+ ret = btd_request_authorization(&src, &dst, BNEP_SVC_UUID,
auth_cb, na);
- if (perr < 0) {
- error("Refusing connect from %s: %s (%d)", address,
- strerror(-perr), -perr);
+ if (ret == 0) {
+ error("Refusing connect from %s", address);
setup_destroy(na);
goto drop;
}
diff --git a/profiles/sap/server.c b/profiles/sap/server.c
index 6c5aa21..6072432 100644
--- a/profiles/sap/server.c
+++ b/profiles/sap/server.c
@@ -1213,7 +1213,7 @@ static void connect_confirm_cb(GIOChannel *io, gpointer data)
GError *gerr = NULL;
bdaddr_t src, dst;
char dstaddr[18];
- int err;
+ guint ret;
DBG("conn %p io %p", conn, io);
@@ -1253,10 +1253,10 @@ static void connect_confirm_cb(GIOChannel *io, gpointer data)
ba2str(&dst, dstaddr);
- err = btd_request_authorization(&src, &dst, SAP_UUID, connect_auth_cb,
+ ret = btd_request_authorization(&src, &dst, SAP_UUID, connect_auth_cb,
server);
- if (err < 0) {
- error("Authorization failure (err %d)", err);
+ if (ret == 0) {
+ error("Authorization failure");
sap_server_remove_conn(server);
return;
}
diff --git a/src/adapter.c b/src/adapter.c
index 524885c..982fd8d 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -97,6 +97,7 @@ struct session_req {
};
struct service_auth {
+ guint id;
service_auth_cb cb;
void *user_data;
struct btd_device *device;
@@ -3209,27 +3210,29 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
char address[18];
const gchar *dev_path;
int err;
+ static guint id = 0;
ba2str(dst, address);
device = adapter_find_device(adapter, address);
if (!device)
- return -EPERM;
+ return 0;
/* Device connected? */
if (!g_slist_find(adapter->connections, device))
error("Authorization request for non-connected device!?");
if (adapter->auth != NULL)
- return -EBUSY;
+ return 0;
auth = g_try_new0(struct service_auth, 1);
if (!auth)
- return -ENOMEM;
+ return 0;
auth->cb = cb;
auth->user_data = user_data;
auth->device = device;
auth->adapter = adapter;
+ auth->id = ++id;
if (device_is_trusted(device) == TRUE) {
adapter->auth_idle_id = g_idle_add(auth_idle_cb, adapter);
@@ -3240,7 +3243,7 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
if (!agent) {
warn("Can't find device agent");
g_free(auth);
- return -EPERM;
+ return 0;
}
dev_path = device_get_path(device);
@@ -3249,15 +3252,15 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
NULL);
if (err < 0) {
g_free(auth);
- return err;
+ return 0;
}
done:
adapter->auth = auth;
- return 0;
+ return auth->id;
}
-int btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
+guint btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
const char *uuid, service_auth_cb cb,
void *user_data)
{
@@ -3267,55 +3270,65 @@ int btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
if (bacmp(src, BDADDR_ANY) != 0) {
adapter = manager_find_adapter(src);
if (!adapter)
- return -EPERM;
+ return 0;
return adapter_authorize(adapter, dst, uuid, cb, user_data);
}
for (l = manager_get_adapters(); l != NULL; l = g_slist_next(l)) {
- int err;
+ guint id;
adapter = l->data;
- err = adapter_authorize(adapter, dst, uuid, cb, user_data);
- if (err == 0)
- return 0;
+ id = adapter_authorize(adapter, dst, uuid, cb, user_data);
+ if (id != 0)
+ return id;
}
- return -EPERM;
+ return 0;
}
-int btd_cancel_authorization(const bdaddr_t *src, const bdaddr_t *dst)
+static struct btd_adapter *find_authorization(guint id)
{
- struct btd_adapter *adapter = manager_find_adapter(src);
- struct btd_device *device;
+ GSList *l;
+
+ for (l = manager_get_adapters(); l != NULL; l = g_slist_next(l)) {
+ struct btd_adapter *adapter = l->data;
+
+ if (adapter->auth == NULL)
+ continue;
+
+ if (adapter->auth->id == id)
+ return adapter;
+ }
+
+ return NULL;
+}
+
+int btd_cancel_authorization(guint id)
+{
+ struct btd_adapter *adapter;
struct agent *agent;
- char address[18];
int err;
- if (!adapter)
- return -EPERM;
-
- ba2str(dst, address);
- device = adapter_find_device(adapter, address);
- if (!device)
+ adapter = find_authorization(id);
+ if (adapter == NULL)
return -EPERM;
if (adapter->auth_idle_id) {
g_source_remove(adapter->auth_idle_id);
adapter->auth_idle_id = 0;
+ g_free(adapter->auth);
+ adapter->auth = NULL;
return 0;
}
- if (!adapter->auth || adapter->auth->device != device)
- return -EPERM;
-
/*
* FIXME: Cancel fails if authorization is requested to adapter's
* agent and in the meanwhile CreatePairedDevice is called.
*/
- agent = device_get_agent(device);
+ agent = device_get_agent(adapter->auth->device);
if (!agent)
return -EPERM;
diff --git a/src/adapter.h b/src/adapter.h
index f34763f..436f167 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -149,9 +149,9 @@ void adapter_add_profile(struct btd_adapter *adapter, gpointer p);
void adapter_remove_profile(struct btd_adapter *adapter, gpointer p);
int btd_register_adapter_driver(struct btd_adapter_driver *driver);
void btd_unregister_adapter_driver(struct btd_adapter_driver *driver);
-int btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
+guint btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
const char *uuid, service_auth_cb cb, void *user_data);
-int btd_cancel_authorization(const bdaddr_t *src, const bdaddr_t *dst);
+int btd_cancel_authorization(guint id);
const char *adapter_any_get_path(void);
diff --git a/src/profile.c b/src/profile.c
index 24f7b28..a051cf7 100644
--- a/src/profile.c
+++ b/src/profile.c
@@ -72,7 +72,7 @@ struct ext_io {
GIOChannel *io;
guint io_id;
- bool authorizing;
+ guint auth_id;
DBusPendingCall *new_conn;
};
@@ -151,14 +151,8 @@ static void ext_io_destroy(gpointer p)
g_io_channel_shutdown(ext_io->io, FALSE, NULL);
g_io_channel_unref(ext_io->io);
- if (ext_io->authorizing) {
- bdaddr_t src, dst;
-
- if (bt_io_get(ext_io->io, NULL, BT_IO_OPT_SOURCE_BDADDR, &src,
- BT_IO_OPT_DEST_BDADDR, &dst,
- BT_IO_OPT_INVALID))
- btd_cancel_authorization(&src, &dst);
- }
+ if (ext_io->auth_id != 0)
+ btd_cancel_authorization(ext_io->auth_id);
if (ext_io->new_conn) {
dbus_pending_call_cancel(ext_io->new_conn);
@@ -318,7 +312,7 @@ static void ext_auth(DBusError *err, void *user_data)
GError *gerr = NULL;
char addr[18];
- conn->authorizing = false;
+ conn->auth_id = 0;
bt_io_get(conn->io, &gerr, BT_IO_OPT_DEST, addr, BT_IO_OPT_INVALID);
if (gerr != NULL) {
@@ -372,7 +366,6 @@ static void ext_confirm(GIOChannel *io, gpointer user_data)
GError *gerr = NULL;
bdaddr_t src, dst;
char addr[18];
- int err;
bt_io_get(io, &gerr,
BT_IO_OPT_SOURCE_BDADDR, &src,
@@ -390,16 +383,14 @@ static void ext_confirm(GIOChannel *io, gpointer user_data)
conn = create_conn(server, io);
- err = btd_request_authorization(&src, &dst, ext->uuid, ext_auth, conn);
- if (err < 0) {
- error("%s authorization failure: %s", ext->name,
- strerror(-err));
+ conn->auth_id = btd_request_authorization(&src, &dst, ext->uuid,
+ ext_auth, conn);
+ if (conn->auth_id == 0) {
+ error("%s authorization failure", ext->name);
ext_io_destroy(conn);
return;
}
- conn->authorizing = true;
-
ext->conns = g_slist_append(ext->conns, conn);
DBG("%s authorizing connection from %s", ext->name, addr);
--
1.7.11.4
From: Mikel Astiz <[email protected]>
Refactor code to drop the device authorizing flag by replacing it with a
private authorization pointer in btd_adapter. After all, no more than
one authorization can be ongoing, so the code is easier to follow if
this is made explicit.
---
src/adapter.c | 56 +++++++++++++++++++++++++++++++++++++-------------------
src/device.c | 11 -----------
src/device.h | 2 --
3 files changed, 37 insertions(+), 32 deletions(-)
diff --git a/src/adapter.c b/src/adapter.c
index 421cd43..524885c 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -124,7 +124,8 @@ struct btd_adapter {
GSList *found_devices;
GSList *oor_devices; /* out of range device list */
struct agent *agent; /* For the new API */
- guint auth_idle_id; /* Ongoing authorization */
+ guint auth_idle_id; /* Ongoing authorization (trusted) */
+ struct service_auth *auth; /* Ongoing authorization */
GSList *connections; /* Connected devices */
GSList *devices; /* Devices structure pointers */
GSList *mode_sessions; /* Request Mode sessions */
@@ -964,8 +965,11 @@ void adapter_remove_device(struct btd_adapter *adapter,
agent = device_get_agent(device);
- if (agent && device_is_authorizing(device))
+ if (agent && adapter->auth && adapter->auth->device == device) {
+ g_free(adapter->auth);
+ adapter->auth = NULL;
agent_cancel(agent);
+ }
device_remove(device, remove_storage);
}
@@ -2433,6 +2437,9 @@ static void adapter_free(gpointer user_data)
if (adapter->auth_idle_id)
g_source_remove(adapter->auth_idle_id);
+ if (adapter->auth)
+ g_free(adapter->auth);
+
if (adapter->off_timer)
off_timer_remove(adapter);
@@ -3167,22 +3174,28 @@ void btd_unregister_adapter_driver(struct btd_adapter_driver *driver)
static void agent_auth_cb(struct agent *agent, DBusError *derr,
void *user_data)
{
- struct service_auth *auth = user_data;
+ struct btd_adapter *adapter = user_data;
+ struct service_auth *auth = adapter->auth;
- device_set_authorizing(auth->device, FALSE);
+ adapter->auth = NULL;
auth->cb(derr, auth->user_data);
+
+ g_free(auth);
}
static gboolean auth_idle_cb(gpointer user_data)
{
- struct service_auth *auth = user_data;
- struct btd_adapter *adapter = auth->adapter;
+ struct btd_adapter *adapter = user_data;
+ struct service_auth *auth = adapter->auth;
+ adapter->auth = NULL;
adapter->auth_idle_id = 0;
auth->cb(NULL, auth->user_data);
+ g_free(auth);
+
return FALSE;
}
@@ -3206,7 +3219,7 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
if (!g_slist_find(adapter->connections, device))
error("Authorization request for non-connected device!?");
- if (adapter->auth_idle_id)
+ if (adapter->auth != NULL)
return -EBUSY;
auth = g_try_new0(struct service_auth, 1);
@@ -3219,10 +3232,8 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
auth->adapter = adapter;
if (device_is_trusted(device) == TRUE) {
- adapter->auth_idle_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
- auth_idle_cb, auth,
- g_free);
- return 0;
+ adapter->auth_idle_id = g_idle_add(auth_idle_cb, adapter);
+ goto done;
}
agent = device_get_agent(device);
@@ -3234,14 +3245,16 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
dev_path = device_get_path(device);
- err = agent_authorize(agent, dev_path, uuid, agent_auth_cb, auth,
- g_free);
- if (err < 0)
+ err = agent_authorize(agent, dev_path, uuid, agent_auth_cb, adapter,
+ NULL);
+ if (err < 0) {
g_free(auth);
- else
- device_set_authorizing(device, TRUE);
+ return err;
+ }
- return err;
+done:
+ adapter->auth = auth;
+ return 0;
}
int btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
@@ -3294,6 +3307,9 @@ int btd_cancel_authorization(const bdaddr_t *src, const bdaddr_t *dst)
return 0;
}
+ if (!adapter->auth || adapter->auth->device != device)
+ return -EPERM;
+
/*
* FIXME: Cancel fails if authorization is requested to adapter's
* agent and in the meanwhile CreatePairedDevice is called.
@@ -3305,8 +3321,10 @@ int btd_cancel_authorization(const bdaddr_t *src, const bdaddr_t *dst)
err = agent_cancel(agent);
- if (err == 0)
- device_set_authorizing(device, FALSE);
+ if (err == 0) {
+ g_free(adapter->auth);
+ adapter->auth = NULL;
+ }
return err;
}
diff --git a/src/device.c b/src/device.c
index efa3dbe..85b1d0c 100644
--- a/src/device.c
+++ b/src/device.c
@@ -163,7 +163,6 @@ struct btd_device {
gboolean bonded;
gboolean auto_connect;
- gboolean authorizing;
gint ref;
GIOChannel *att_io;
@@ -3040,16 +3039,6 @@ gboolean device_is_authenticating(struct btd_device *device)
return (device->authr != NULL);
}
-gboolean device_is_authorizing(struct btd_device *device)
-{
- return device->authorizing;
-}
-
-void device_set_authorizing(struct btd_device *device, gboolean auth)
-{
- device->authorizing = auth;
-}
-
void device_register_services(struct btd_device *device,
GSList *prim_list, int psm)
{
diff --git a/src/device.h b/src/device.h
index eb45244..e82fd0e 100644
--- a/src/device.h
+++ b/src/device.h
@@ -100,8 +100,6 @@ int device_notify_pincode(struct btd_device *device, gboolean secure,
const char *pincode, void *cb);
void device_cancel_authentication(struct btd_device *device, gboolean aborted);
gboolean device_is_authenticating(struct btd_device *device);
-gboolean device_is_authorizing(struct btd_device *device);
-void device_set_authorizing(struct btd_device *device, gboolean auth);
void device_add_connection(struct btd_device *device);
void device_remove_connection(struct btd_device *device);
void device_request_disconnect(struct btd_device *device, DBusMessage *msg);
--
1.7.11.4
From: Mikel Astiz <[email protected]>
This version of the library adds several convenient features such as
g_queue_free_full.
---
acinclude.m4 | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/acinclude.m4 b/acinclude.m4
index ed2d011..9f4b11f 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -99,8 +99,8 @@ AC_DEFUN([AC_PATH_DBUS], [
])
AC_DEFUN([AC_PATH_GLIB], [
- PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.28, dummy=yes,
- AC_MSG_ERROR(GLib >= 2.28 is required))
+ PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.32, dummy=yes,
+ AC_MSG_ERROR(GLib >= 2.32 is required))
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
])
--
1.7.11.4
Hi Mikel,
On Fri, Sep 28, 2012 at 7:32 PM, Mikel Astiz <[email protected]> wrote:
> From: Mikel Astiz <[email protected]>
>
> v4 considers the review from Luiz and Johan, including:
> - guint used for authorization ids, instead of int
> - static local variable used to generate new ids
> - service_auth_id renamed to auth_id
>
> From original cover-letter:
>
> The agent-based profile authorization makes a special consideration for audio profiles: they are processed as if they all belonged to one single profile. This includes several internal policies that are inconvenient for IVI use-cases.
>
> This patchset removes this exception by making use of the conventional authorization mechanism also for audio profiles.
>
> The new approach is not straightforward since devices might send several connection requets in parallel (i.e. HFP, A2DP, AVRCP). This cannot be neither automatically rejected (EBUSY) nor forwarded in parallel to the agent, so a queue was added to store the pending authorization requests. These will be sent to the agent sequentially.
>
> Mikel Astiz (5):
> build: Update glib dependency to 2.32
> adapter: Replace device authorizing flag
> adapter: Use authorization id for cancelling
> adapter: Queue parallel authorization requests
> audio: Drop audio-specific authorization mechanism
>
> acinclude.m4 | 4 +-
> audio/avctp.c | 27 +++---
> audio/avdtp.c | 23 ++++--
> audio/device.c | 144 --------------------------------
> audio/device.h | 12 +--
> audio/manager.c | 28 ++++---
> plugins/service.c | 18 ++--
> profiles/input/server.c | 7 +-
> profiles/network/server.c | 9 +-
> profiles/sap/server.c | 8 +-
> src/adapter.c | 204 +++++++++++++++++++++++++++++-----------------
> src/adapter.h | 4 +-
> src/device.c | 11 ---
> src/device.h | 2 -
> src/profile.c | 25 ++----
> 15 files changed, 207 insertions(+), 319 deletions(-)
>
> --
> 1.7.11.4
All 5 patches applied, thanks.
--
Luiz Augusto von Dentz