blob: d0cd0d2209eb114dc7040199bd1b3d8fcd061c5a [file] [log] [blame]
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* libmbim-glib -- GLib/GIO based library to control MBIM devices
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright (C) 2014 Aleksander Morgado <aleksander@aleksander.es>
* Copyright (C) 2014 Smith Micro Software, Inc.
*/
#include <string.h>
#include "mbim-proxy-helpers.h"
#include "mbim-message-private.h"
#include "mbim-message.h"
#include "mbim-cid.h"
#include "mbim-uuid.h"
/*****************************************************************************/
static gboolean
cmp_event_entry_contents (const MbimEventEntry *in,
const MbimEventEntry *out)
{
guint i, o;
g_assert (mbim_uuid_cmp (&(in->device_service_id), &(out->device_service_id)));
/* First, compare number of cids in the array */
if (in->cids_count != out->cids_count)
return FALSE;
if (in->cids_count == 0)
g_assert (in->cids == NULL);
if (out->cids_count == 0)
g_assert (out->cids == NULL);
for (i = 0; i < in->cids_count; i++) {
for (o = 0; o < out->cids_count; o++) {
if (in->cids[i] == out->cids[o])
break;
}
if (o == out->cids_count)
return FALSE;
}
return TRUE;
}
gboolean
_mbim_proxy_helper_service_subscribe_list_cmp (const MbimEventEntry * const *a,
gsize a_size,
const MbimEventEntry * const *b,
gsize b_size)
{
gsize i, o;
/* First, compare number of entries a the array */
if (a_size != b_size)
return FALSE;
/* Now compare each service one by one */
for (i = 0; i < a_size; i++) {
/* Look for this same service a the other array */
for (o = 0; o < b_size; o++) {
/* When service found, compare contents */
if (mbim_uuid_cmp (&(a[i]->device_service_id), &(b[o]->device_service_id))) {
if (!cmp_event_entry_contents (a[i], b[o]))
return FALSE;
break;
}
}
/* Service not found! */
if (!b[o])
return FALSE;
}
return TRUE;
}
/*****************************************************************************/
void
_mbim_proxy_helper_service_subscribe_list_debug (const MbimEventEntry * const *list,
gsize list_size)
{
gsize i;
for (i = 0; i < list_size; i++) {
const MbimEventEntry *entry = list[i];
MbimService service;
gchar *str;
service = mbim_uuid_to_service (&entry->device_service_id);
str = mbim_uuid_get_printable (&entry->device_service_id);
g_debug ("[service %u] %s (%s)",
(guint)i, str, mbim_service_lookup_name (service));
g_free (str);
if (entry->cids_count == 0)
g_debug ("[service %u] all CIDs enabled", (guint)i);
else {
guint j;
g_debug ("[service %u] %u CIDs enabled", (guint)i, entry->cids_count);;
for (j = 0; j < entry->cids_count; j++) {
const gchar *cid_str;
cid_str = mbim_cid_get_printable (service, entry->cids[j]);
g_debug ("[service %u] [cid %u] %u (%s)",
(guint)i, j, entry->cids[j], cid_str ? cid_str : "unknown");
}
}
}
}
/*****************************************************************************/
MbimEventEntry **
_mbim_proxy_helper_service_subscribe_standard_list_new (gsize *out_size)
{
gsize i;
MbimService service;
MbimEventEntry **out;
g_assert (out_size != NULL);
out = g_new0 (MbimEventEntry *, 1 + (MBIM_SERVICE_DSS - MBIM_SERVICE_BASIC_CONNECT + 1));
for (service = MBIM_SERVICE_BASIC_CONNECT, i = 0;
service <= MBIM_SERVICE_DSS;
service++, i++) {
out[i] = g_new0 (MbimEventEntry, 1);
memcpy (&out[i]->device_service_id, mbim_uuid_from_service (service), sizeof (MbimUuid));
}
*out_size = i;
return out;
}
/*****************************************************************************/
MbimEventEntry **
_mbim_proxy_helper_service_subscribe_request_parse (MbimMessage *message,
gsize *out_size)
{
MbimEventEntry **array = NULL;
guint32 i;
guint32 element_count;
guint32 offset = 0;
guint32 array_offset;
MbimEventEntry *event;
g_assert (message != NULL);
g_assert (out_size != NULL);
element_count = _mbim_message_read_guint32 (message, offset);
if (element_count) {
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;
array[i] = event;
offset += 8;
}
array[element_count] = NULL;
}
*out_size = element_count;
return array;
}
/*****************************************************************************/
MbimEventEntry **
_mbim_proxy_helper_service_subscribe_list_merge (MbimEventEntry **in,
gsize in_size,
MbimEventEntry **merge,
gsize merge_size,
gsize *out_size)
{
gsize m;
g_assert (out_size != NULL);
*out_size = in_size;
if (!merge || !merge_size)
return in;
for (m = 0; m < merge_size; m++) {
MbimEventEntry *entry = NULL;
/* look for matching uuid */
if (in && in_size) {
gsize i;
for (i = 0; i < in_size; i++) {
if (mbim_uuid_cmp (&merge[m]->device_service_id, &in[i]->device_service_id)) {
entry = in[i];
break;
}
}
}
/* matching uuid not found in merge array, add it */
if (!entry) {
gsize o;
/* Index of the new element to add... */
o = *out_size;
/* Increase number of events in the output array */
(*out_size)++;
in = g_realloc (in, sizeof (MbimEventEntry *) * (*out_size + 1));
in[o] = g_memdup (merge[m], sizeof (MbimEventEntry));
if (merge[m]->cids_count)
in[o]->cids = g_memdup (merge[m]->cids, sizeof (guint32) * merge[m]->cids_count);
else
in[o]->cids = NULL;
in[*out_size] = NULL;
} else {
gsize cm, co;
/* matching uuid found, add cids */
if (!entry->cids_count)
/* all cids already enabled for uuid */
continue;
/* If we're adding all enabled cids, directly apply that */
if (merge[m]->cids_count == 0) {
g_free (entry->cids);
entry->cids = NULL;
entry->cids_count = 0;
}
for (cm = 0; cm < merge[m]->cids_count; cm++) {
for (co = 0; co < entry->cids_count; co++) {
if (merge[m]->cids[cm] == entry->cids[co]) {
break;
}
}
if (co == entry->cids_count) {
/* cid not found in merge array, add it */
entry->cids = g_realloc (entry->cids, sizeof (guint32) * (++entry->cids_count));
entry->cids[co] = merge[m]->cids[cm];
}
}
}
}
return in;
}