[PATCH] libmbim-glib, proxy: Filter indications based on MBIM_CID_BASIC_CONNECT_DEVICE_SERVICE_SUBSCRIBE_LIST
Greg Suarez
gpsuarez2512 at gmail.com
Mon Jun 9 12:00:06 PDT 2014
Previously mbim-proxy tracked and filtered indications of non-standard
services based on whether a client has sent a message to the device with
a matching UUID. This patch removes that tracking and filtering and
instead tracks and filters indications based on the client sending
the MBIM_CID_BASIC_CONNECT_DEVICE_SERVICE_SUBSCRIBE_LIST command to
the device.
The client will receive all indications if it never sends the
MBIM_CID_BASIC_CONNECT_DEVICE_SERVICE_SUBSCRIBE_LIST command.
Once the client sends the
MBIM_CID_BASIC_CONNECT_DEVICE_SERVICE_SUBSCRIBE_LIST command, the
client will only receive indications specified in the command.
---
src/libmbim-glib/mbim-proxy.c | 308 +++++++++++++++++++++++++++++++++++-------
1 file changed, 260 insertions(+), 48 deletions(-)
diff --git a/src/libmbim-glib/mbim-proxy.c b/src/libmbim-glib/mbim-proxy.c
index dccca4d..ef8ae81 100644
--- a/src/libmbim-glib/mbim-proxy.c
+++ b/src/libmbim-glib/mbim-proxy.c
@@ -38,6 +38,7 @@
#include "mbim-cid.h"
#include "mbim-enum-types.h"
#include "mbim-error-types.h"
+#include "mbim-basic-connect.h"
#define BUFFER_SIZE 512
@@ -51,6 +52,7 @@ enum {
static GParamSpec *properties[PROP_LAST];
+
struct _MbimProxyPrivate {
/* Unix socket service */
GSocketService *socket_service;
@@ -93,10 +95,11 @@ typedef struct {
GByteArray *buffer;
MbimDevice *device;
MbimMessage *internal_proxy_open_request;
- GArray *mbim_client_info_array;
guint indication_id;
gchar *device_file_path;
gboolean opening_device;
+ gboolean service_subscriber_list_enabled;
+ MbimEventEntry **mbim_event_entry_array;
} Client;
typedef struct {
@@ -129,7 +132,8 @@ client_free (Client *client)
if (client->internal_proxy_open_request)
mbim_message_unref (client->internal_proxy_open_request);
- g_array_unref (client->mbim_client_info_array);
+ if (client->mbim_event_entry_array)
+ mbim_event_entry_array_free (client->mbim_event_entry_array);
g_object_unref (client->connection);
g_slice_free (Client, client);
@@ -141,9 +145,10 @@ get_n_clients_with_device (MbimProxy *self,
{
GList *l;
guint n = 0;
+ Client *client;
for (l = self->priv->clients; l; l = g_list_next (l)) {
- Client *client = l->data;
+ client = l->data;
if (device == client->device ||
g_str_equal (mbim_device_get_path (device), mbim_device_get_path (client->device)))
@@ -296,16 +301,32 @@ indication_cb (MbimDevice *device,
guint i;
GError *error = NULL;
gboolean forward_indication = FALSE;
+ MbimEventEntry *event = NULL;
+
+ if (client->service_subscriber_list_enabled) {
+ /* if client sent the device service subscribe list with element count 0 then
+ ignore all indications */
+ if (client->mbim_event_entry_array) {
+ for (i = 0; client->mbim_event_entry_array[i]; i++) {
+ if (mbim_uuid_cmp (mbim_message_indicate_status_get_service_id (message),
+ &client->mbim_event_entry_array[i]->device_service_id)) {
+ event = client->mbim_event_entry_array[i];
+ break;
+ }
+ }
- if (mbim_message_indicate_status_get_service (message) == MBIM_SERVICE_INVALID) {
- for (i = 0; i < client->mbim_client_info_array->len; i++) {
- MbimClientInfo *info;
-
- info = &g_array_index (client->mbim_client_info_array, MbimClientInfo, i);
- /* If service UUID match, forward to the remote client */
- if (mbim_uuid_cmp (mbim_message_indicate_status_get_service_id (message), &info->uuid)) {
- forward_indication = TRUE;
- break;
+ if (event) {
+ /* found matching service, search for cid */
+ if (event->cids_count) {
+ for (i = 0; i < event->cids_count; i++) {
+ if (mbim_message_indicate_status_get_cid (message) == event->cids[i]) {
+ forward_indication = TRUE;
+ break;
+ }
+ }
+ } else
+ /* cids_count of 0 enables all indications for the service */
+ forward_indication = TRUE;
}
}
} else
@@ -518,50 +539,244 @@ process_internal_proxy_config (Client *client,
return TRUE;
}
+
+static MbimEventEntry **
+standard_service_subscribe_list_new( void )
+{
+ guint32 i, service;
+ MbimEventEntry **out;
+
+
+ out = g_new0 (MbimEventEntry *, MBIM_SERVICE_MS_FIRMWARE_ID);
+
+ for (service = MBIM_SERVICE_BASIC_CONNECT, i = 0;
+ service < MBIM_SERVICE_MS_FIRMWARE_ID;
+ service++, i++) {
+
+ out[i] = g_new0 (MbimEventEntry, 1);
+ memcpy (&out[i]->device_service_id, mbim_uuid_from_service(service), sizeof (MbimUuid));
+ }
+
+ return out;
+}
+
static void
-track_uuid (Client *client,
- gboolean track,
- MbimMessage *message)
+track_service_subscribe_list (Client *client,
+ MbimMessage *message)
{
- gchar *uuid_display;
- MbimClientInfo info;
- guint i;
- gboolean exists;
+ guint32 i;
+ guint32 element_count;
+ guint32 offset = 0;
+ guint32 array_offset;
+ MbimEventEntry *event;
- memcpy (&info.uuid, mbim_message_command_done_get_service_id (message), sizeof (info.uuid));
- uuid_display = mbim_uuid_get_printable (&info.uuid);
- /* Check if it already exists */
- for (i = 0; i < client->mbim_client_info_array->len; i++) {
- MbimClientInfo *existing;
+ client->service_subscriber_list_enabled = TRUE;
- existing = &g_array_index (client->mbim_client_info_array, MbimClientInfo, i);
- if (mbim_uuid_cmp (&info.uuid, &existing->uuid))
- break;
+ if (client->mbim_event_entry_array) {
+ mbim_event_entry_array_free (client->mbim_event_entry_array);
+ client->mbim_event_entry_array = NULL;
}
- exists = (i < client->mbim_client_info_array->len);
- if (track && !exists) {
- g_debug ("MBIM client tracked [%s,%s]",
- mbim_device_get_path_display (client->device),
- uuid_display);
- g_array_append_val (client->mbim_client_info_array, info);
- } else if (!track && exists) {
- g_debug ("MBIM client untracked [%s,%s]",
- mbim_device_get_path_display (client->device),
- uuid_display);
- g_array_remove_index (client->mbim_client_info_array, i);
+ element_count = _mbim_message_read_guint32 (message, offset);
+ if (element_count) {
+ client->mbim_event_entry_array = g_new (MbimEventEntry *, element_count + 1);
+
+ offset += 4;
+ for (i = 0; i < element_count; i++) {
+ array_offset = _mbim_message_read_guint32 (message, offset);
+
+ event = g_new (MbimEventEntry, 1);
+
+ memcpy (&(event->device_service_id), _mbim_message_read_uuid (message, array_offset), 16);
+ array_offset += 16;
+
+ event->cids_count = _mbim_message_read_guint32 (message, array_offset);
+ array_offset += 4;
+
+ if (event->cids_count)
+ event->cids = _mbim_message_read_guint32_array (message, event->cids_count, array_offset);
+ else
+ event->cids = NULL;
+
+ client->mbim_event_entry_array[i] = event;
+ offset += 8;
+ }
+
+ client->mbim_event_entry_array[element_count] = NULL;
}
+}
- g_free (uuid_display);
+static MbimEventEntry **
+merge_client_service_subscribe_lists (MbimProxy *self, guint32 *events_count)
+{
+ guint32 i, ii;
+ guint32 out_idx, out_cid_idx;
+ GList *l;
+ MbimEventEntry *entry;
+ MbimEventEntry **out;
+ Client *client;
+
+ out = standard_service_subscribe_list_new ();
+
+ for (l = self->priv->clients; l; l = g_list_next (l)) {
+ client = l->data;
+ if (!client->mbim_event_entry_array)
+ continue;
+
+ for (i = 0; client->mbim_event_entry_array[i]; i++) {
+ entry = NULL;
+
+ /* look for matching uuid */
+ for (out_idx = 0; out[out_idx]; out_idx++) {
+ if (!memcmp (&client->mbim_event_entry_array[i]->device_service_id,
+ &out[out_idx]->device_service_id,
+ sizeof (MbimUuid))) {
+ entry = out[out_idx];
+ break;
+ }
+ }
+
+ if (!entry) {
+ /* matching uuid not found in merge array, add it */
+ out = g_realloc (out, sizeof (*out) * (out_idx + 2));
+ out[out_idx] = g_memdup (client->mbim_event_entry_array[i], sizeof (MbimEventEntry));
+ if (client->mbim_event_entry_array[i]->cids_count)
+ out[out_idx]->cids = g_memdup (client->mbim_event_entry_array[i]->cids,
+ sizeof (guint32) * client->mbim_event_entry_array[i]->cids_count);
+ else
+ out[out_idx]->cids = NULL;
+
+ out[++out_idx] = NULL;
+ *events_count = out_idx;
+ } else {
+ /* matching uuid found, add cids */
+ if (!entry->cids_count)
+ /* all cids already enabled for uuid */
+ continue;
+
+ for (ii = 0; ii < client->mbim_event_entry_array[i]->cids_count; ii++) {
+ for (out_cid_idx = 0; out_cid_idx < entry->cids_count; out_cid_idx++) {
+ if (client->mbim_event_entry_array[i]->cids[ii] == entry->cids[out_cid_idx]) {
+ break;
+ }
+ }
+
+ if (out_cid_idx == entry->cids_count) {
+ /* cid not found in merge array, add it */
+ entry->cids = g_realloc (entry->cids, sizeof (guint32) * (entry->cids_count++));
+ entry->cids[out_cid_idx] = client->mbim_event_entry_array[i]->cids[ii];
+ }
+ }
+ }
+ }
+ }
+
+ return out;
}
typedef struct {
Client *client;
guint32 transaction_id;
+ gpointer data;
+ guint32 data_len;
} Request;
static void
+request_free (Request *request)
+{
+ if (request->data)
+ g_free (request->data);
+
+ g_slice_free (Request, request);
+}
+
+static void
+device_service_subscribe_list_set_ready (MbimDevice *device,
+ GAsyncResult *res,
+ Request *request)
+{
+ MbimMessage *response;
+ MbimStatusError error_status_code;
+ struct command_done_message *command_done;
+ GError *error = NULL;
+
+ response = mbim_device_command_finish (device, res, &error);
+ if (!response) {
+ g_warning ("sending request to device failed: %s", error->message);
+ if (!mbim_device_is_open (device)) {
+ g_debug ("device is closed");
+ connection_close (request->client);
+ }
+
+ g_error_free (error);
+ g_slice_free (Request, request);
+ return;
+ }
+ error_status_code = ((struct full_message *)(response->data))->message.command_done.status_code;
+ mbim_message_unref (response);
+
+ response = (MbimMessage *)_mbim_message_allocate (MBIM_MESSAGE_TYPE_COMMAND_DONE,
+ request->transaction_id,
+ sizeof (struct command_done_message) +
+ request->data_len);
+ command_done = &(((struct full_message *)(response->data))->message.command_done);
+ command_done->fragment_header.total = GUINT32_TO_LE (1);
+ command_done->fragment_header.current = 0;
+ memcpy (command_done->service_id, MBIM_UUID_BASIC_CONNECT, sizeof(MbimUuid));
+ command_done->command_id = GUINT32_TO_LE (MBIM_CID_BASIC_CONNECT_DEVICE_SERVICE_SUBSCRIBE_LIST);
+ command_done->status_code = error_status_code;
+ command_done->buffer_length = request->data_len;
+ memcpy (&command_done->buffer[0], request->data, request->data_len);
+
+ if (!send_message (request->client, response, &error))
+ connection_close (request->client);
+
+ mbim_message_unref (response);
+ request_free (request);
+}
+
+static gboolean
+process_device_service_subscribe_list (Client *client,
+ MbimMessage *message)
+{
+ MbimEventEntry **events;
+ guint32 events_count = 0;
+ Request *request;
+ const guint8 *raw_buff;
+ guint32 raw_len;
+
+
+ /* trace the service subscribe list for the client */
+ track_service_subscribe_list (client, message);
+
+ /* merge all service subscribe list for all clients to set on device */
+ events = merge_client_service_subscribe_lists (client->proxy, &events_count);
+
+ /* save the raw message data to send back as response to client */
+ raw_buff = mbim_message_command_get_raw_information_buffer (message, &raw_len);
+
+ request = g_slice_new0 (Request);
+ request->client = client;
+ request->transaction_id = mbim_message_get_transaction_id (message);
+ request->data = g_memdup (raw_buff, raw_len);
+ request->data_len = raw_len;
+
+ message = mbim_message_device_service_subscribe_list_set_new (events_count, (const MbimEventEntry *const *)events, NULL);
+ mbim_message_set_transaction_id (message, mbim_device_get_next_transaction_id (client->device));
+
+ mbim_device_command (client->device,
+ message,
+ 300,
+ NULL,
+ (GAsyncReadyCallback)device_service_subscribe_list_set_ready,
+ request);
+
+ mbim_event_entry_array_free (events);
+ return TRUE;
+}
+
+static void
device_command_ready (MbimDevice *device,
GAsyncResult *res,
Request *request)
@@ -582,12 +797,6 @@ device_command_ready (MbimDevice *device,
return;
}
- /* track custom uuids */
- if (mbim_message_get_message_type (response) == MBIM_MESSAGE_TYPE_COMMAND_DONE) {
- if (mbim_message_command_done_get_service (response) == MBIM_SERVICE_INVALID)
- track_uuid (request->client, TRUE, response);
- }
-
/* replace reponse transaction id with the requested transaction id */
((struct header *)(response->data))->transaction_id = GUINT32_TO_LE (request->transaction_id);
@@ -595,7 +804,7 @@ device_command_ready (MbimDevice *device,
connection_close (request->client);
mbim_message_unref (response);
- g_slice_free (Request, request);
+ request_free (request);
}
static gboolean
@@ -615,7 +824,11 @@ process_message (Client *client,
if (mbim_message_command_get_service (message) == MBIM_SERVICE_PROXY_CONTROL &&
mbim_message_command_get_cid (message) == MBIM_CID_PROXY_CONTROL_CONFIGURATION)
return process_internal_proxy_config (client, message);
- /* Non-proxy control message, go on */
+
+ /* device service subscribe list message? */
+ if (mbim_message_command_get_service (message) == MBIM_SERVICE_BASIC_CONNECT &&
+ mbim_message_command_get_cid (message) == MBIM_CID_BASIC_CONNECT_DEVICE_SERVICE_SUBSCRIBE_LIST)
+ return process_device_service_subscribe_list (client, message);
break;
default:
g_debug ("invalid message from client: not a command message");
@@ -762,7 +975,6 @@ incoming_cb (GSocketService *service,
client,
NULL);
g_source_attach (client->connection_readable_source, NULL);
- client->mbim_client_info_array = g_array_sized_new (FALSE, FALSE, sizeof (MbimClientInfo), 8);
/* Keep the client info around */
self->priv->clients = g_list_append (self->priv->clients, client);
--
1.9.3
More information about the libmbim-devel
mailing list