[PATCH] libmbim-glib, proxy: Filter indications based on MBIM_CID_BASIC_CONNECT_DEVICE_SERVICE_SUBSCRIBE_LIST
Aleksander Morgado
aleksander at aleksander.es
Fri Jun 13 06:51:00 PDT 2014
On Mon, Jun 9, 2014 at 9:00 PM, Greg Suarez <gpsuarez2512 at gmail.com> wrote:
> 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.
Pushed to the greg/proxy branch for now; I'll try to review it this weekend.
> ---
> 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
>
--
Aleksander
https://aleksander.es
More information about the libmbim-devel
mailing list