Merge remote-tracking branch 'cros/upstream' into 'cros/master'

Contains the following commits:
0bbe65c libmbim-glib,proxy: plug memleak (Aleksander Morgado)
4064021 libmbim-glib,proxy: always use realpath in the MbimDevice (Aleksander Morgado)
b0ede0c libmbim-glib,device: use realpath basename to look for descriptors file (Aleksander Morgado)
4932766 libmbim-glib,utils: new helpers to work with symlinks (Aleksander Morgado)
2999e9a mbimcli: add --query-provisioned-contexts flag (Eric Caruso)

Change-Id: I5986dd430acdfc70a53435de9da01fb04b735879
diff --git a/src/libmbim-glib/mbim-device.c b/src/libmbim-glib/mbim-device.c
index 113fd36..6d38a39 100644
--- a/src/libmbim-glib/mbim-device.c
+++ b/src/libmbim-glib/mbim-device.c
@@ -862,8 +862,9 @@
     GUdevDevice *device = NULL;
     GUdevDevice *parent_device = NULL;
     GUdevDevice *grandparent_device = NULL;
-    gchar *descriptors_path = NULL;
-    gchar *device_basename = NULL;
+    gchar       *descriptors_path = NULL;
+    gchar       *device_basename = NULL;
+    GError      *error = NULL;
 
     client = g_udev_client_new (NULL);
     if (!G_UDEV_IS_CLIENT (client)) {
@@ -884,7 +885,14 @@
      *   Which is the one with the descriptors file.
      */
 
-    device_basename = g_path_get_basename (self->priv->path);
+    device_basename = __mbim_utils_get_devname (self->priv->path, &error);
+    if (!device_basename) {
+        g_warning ("[%s] Invalid path for cdc-wdm control port: %s",
+                   self->priv->path_display, error->message);
+        g_clear_error (&error);
+        goto out;
+    }
+
     device = g_udev_client_query_by_subsystem_and_name (client, "usb", device_basename);
     if (!device) {
         device = g_udev_client_query_by_subsystem_and_name (client, "usbmisc", device_basename);
diff --git a/src/libmbim-glib/mbim-proxy.c b/src/libmbim-glib/mbim-proxy.c
index 508e935..912e1f0 100644
--- a/src/libmbim-glib/mbim-proxy.c
+++ b/src/libmbim-glib/mbim-proxy.c
@@ -744,10 +744,12 @@
                                Client      *client,
                                MbimMessage *message)
 {
-    Request *request;
+    Request    *request;
     MbimDevice *device;
-    gchar *path;
-    GFile *file;
+    gchar      *incoming_path;
+    gchar      *path;
+    GFile      *file;
+    GError     *error = NULL;
 
     /* create request holder */
     request = request_new (self, client, message);
@@ -767,13 +769,27 @@
     }
 
     /* Retrieve path from request */
-    path = _mbim_message_read_string (message, 0, 0);
-    if (!path) {
+    incoming_path = _mbim_message_read_string (message, 0, 0);
+    if (!incoming_path) {
         request->response = build_proxy_control_command_done (message, MBIM_STATUS_ERROR_INVALID_PARAMETERS);
         request_complete_and_free (request);
         return TRUE;
     }
 
+    /* The incoming path may be a symlink. In the proxy, we always use the real path of the
+     * device, so that clients using different symlinks for the same file don't collide with
+     * each other. */
+    path = __mbim_utils_get_devpath (incoming_path, &error);
+    if (!path) {
+        g_warning ("Error looking up real device path: %s", error->message);
+        g_error_free (error);
+        request->response = build_proxy_control_command_done (message, MBIM_STATUS_ERROR_INVALID_PARAMETERS);
+        request_complete_and_free (request);
+        g_free (incoming_path);
+        return TRUE;
+    }
+    g_free (incoming_path);
+
     /* Only allow subsequent requests with the same path */
     if (client->device) {
         if (g_str_equal (path, mbim_device_get_path (client->device)))
diff --git a/src/libmbim-glib/mbim-utils.c b/src/libmbim-glib/mbim-utils.c
index f360542..f168e6d 100644
--- a/src/libmbim-glib/mbim-utils.c
+++ b/src/libmbim-glib/mbim-utils.c
@@ -18,13 +18,16 @@
  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  * Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2013 - 2014 Aleksander Morgado <aleksander@aleksander.es>
+ * Copyright (C) 2013 - 2019 Aleksander Morgado <aleksander@aleksander.es>
  */
 
 #include <config.h>
 #include <string.h>
 #include <stdint.h>
 #include <stdio.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <errno.h>
 #include <pwd.h>
 
 #include "mbim-utils.h"
@@ -79,6 +82,45 @@
 
 /*****************************************************************************/
 
+gchar *
+__mbim_utils_get_devpath (const gchar  *cdc_wdm_path,
+                          GError      **error)
+{
+    gchar *aux;
+
+    if (!g_file_test (cdc_wdm_path, G_FILE_TEST_IS_SYMLINK))
+        return g_strdup (cdc_wdm_path);
+
+    aux = realpath (cdc_wdm_path, NULL);
+    if (!aux) {
+        int saved_errno = errno;
+
+        g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED,
+                     "Couldn't get realpath: %s", g_strerror (saved_errno));
+        return NULL;
+    }
+
+    return aux;
+}
+
+gchar *
+__mbim_utils_get_devname (const gchar  *cdc_wdm_path,
+                          GError      **error)
+{
+    gchar *aux;
+    gchar *devname = NULL;
+
+    aux = __mbim_utils_get_devpath (cdc_wdm_path, error);
+    if (aux) {
+        devname = g_path_get_basename (aux);
+        g_free (aux);
+    }
+
+    return devname;
+}
+
+/*****************************************************************************/
+
 static volatile gint __traces_enabled = FALSE;
 
 /**
diff --git a/src/libmbim-glib/mbim-utils.h b/src/libmbim-glib/mbim-utils.h
index 77ed4ca..858ae17 100644
--- a/src/libmbim-glib/mbim-utils.h
+++ b/src/libmbim-glib/mbim-utils.h
@@ -39,8 +39,12 @@
 /* Other private methods */
 
 #if defined (LIBMBIM_GLIB_COMPILATION)
-gboolean __mbim_user_allowed (uid_t uid,
-                              GError **error);
+gboolean  __mbim_user_allowed      (uid_t         uid,
+                                    GError      **error);
+gchar    *__mbim_utils_get_devpath (const gchar  *cdc_wdm_path,
+                                    GError      **error);
+gchar    *__mbim_utils_get_devname (const gchar  *cdc_wdm_path,
+                                    GError      **error);
 #endif
 
 G_END_DECLS
diff --git a/src/mbimcli/mbimcli-basic-connect.c b/src/mbimcli/mbimcli-basic-connect.c
index b3dc408..ff84f0d 100644
--- a/src/mbimcli/mbimcli-basic-connect.c
+++ b/src/mbimcli/mbimcli-basic-connect.c
@@ -70,6 +70,7 @@
 static gchar    *set_connect_deactivate_str;
 static gboolean  query_packet_statistics_flag;
 static gchar    *query_ip_packet_filters_str;
+static gboolean  query_provisioned_contexts_flag;
 
 static gboolean query_connection_state_arg_parse (const char *option_name,
                                                   const char *value,
@@ -200,6 +201,10 @@
       "Query IP packet filters (SessionID is optional, defaults to 0)",
       "[SessionID]"
     },
+    { "query-provisioned-contexts", 0, 0, G_OPTION_ARG_NONE, &query_provisioned_contexts_flag,
+      "Query provisioned contexts",
+      NULL
+    },
     { NULL }
 };
 
@@ -293,7 +298,8 @@
                  !!query_ip_configuration_str +
                  !!set_connect_deactivate_str +
                  query_packet_statistics_flag +
-                 !!query_ip_packet_filters_str);
+                 !!query_ip_packet_filters_str +
+                 query_provisioned_contexts_flag);
 
     if (n_actions > 1) {
         g_printerr ("error: too many Basic Connect actions requested\n");
@@ -1765,6 +1771,68 @@
     shutdown (TRUE);
 }
 
+static void
+provisioned_contexts_ready (MbimDevice   *device,
+                            GAsyncResult *res)
+{
+    MbimMessage *response;
+    MbimProvisionedContextElement **provisioned_contexts;
+    guint32 provisioned_contexts_count;
+    int i;
+    GError *error = NULL;
+
+    response = mbim_device_command_finish (device, res, &error);
+    if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) {
+        g_printerr ("error: operation failed: %s\n", error->message);
+        g_error_free (error);
+        if (response)
+            mbim_message_unref (response);
+        shutdown (FALSE);
+        return;
+    }
+
+    if (!mbim_message_provisioned_contexts_response_parse (
+            response,
+            &provisioned_contexts_count,
+            &provisioned_contexts,
+            &error)) {
+        g_printerr ("error: couldn't parse response message: %s\n", error->message);
+        g_error_free (error);
+        mbim_message_unref (response);
+        shutdown (FALSE);
+        return;
+    }
+
+    g_print ("[%s] Provisioned contexts (%u):\n",
+             mbim_device_get_path_display (device),
+             provisioned_contexts_count);
+
+    for (i = 0; i < provisioned_contexts_count; i++) {
+        g_print ("\tContext ID %u:\n"
+                 "\t   Context type: '%s'\n"
+                 "\t  Access string: '%s'\n"
+                 "\t       Username: '%s'\n"
+                 "\t       Password: '%s'\n"
+                 "\t    Compression: '%s'\n"
+                 "\t  Auth protocol: '%s'\n",
+                 provisioned_contexts[i]->context_id,
+                 VALIDATE_UNKNOWN (mbim_context_type_get_string (
+                     mbim_uuid_to_context_type (&provisioned_contexts[i]->context_type))),
+                 VALIDATE_UNKNOWN (provisioned_contexts[i]->access_string),
+                 VALIDATE_UNKNOWN (provisioned_contexts[i]->user_name),
+                 VALIDATE_UNKNOWN (provisioned_contexts[i]->password),
+                 VALIDATE_UNKNOWN (mbim_compression_get_string (
+                     provisioned_contexts[i]->compression)),
+                 VALIDATE_UNKNOWN (mbim_auth_protocol_get_string (
+                     provisioned_contexts[i]->auth_protocol)));
+    }
+
+    mbim_provisioned_context_element_array_free (provisioned_contexts);
+
+    mbim_message_unref (response);
+    shutdown (TRUE);
+}
+
 void
 mbimcli_basic_connect_run (MbimDevice   *device,
                            GCancellable *cancellable)
@@ -2321,5 +2389,20 @@
         return;
     }
 
+    /* Provisioned contexts? */
+    if (query_provisioned_contexts_flag) {
+        MbimMessage *request;
+
+        request = mbim_message_provisioned_contexts_query_new (NULL);
+        mbim_device_command (ctx->device,
+                             request,
+                             10,
+                             ctx->cancellable,
+                             (GAsyncReadyCallback)provisioned_contexts_ready,
+                             NULL);
+        mbim_message_unref (request);
+        return;
+    }
+
     g_warn_if_reached ();
 }