Merge remote-tracking branch 'cros/upstream' into 'cros/master'
diff --git a/docs/libmbim-icon.svg b/docs/libmbim-icon.svg
new file mode 100644
index 0000000..717ed09
--- /dev/null
+++ b/docs/libmbim-icon.svg
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="744.09448819"
+   height="1052.3622047"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="libmbim-logo.svg"
+   inkscape:export-filename="/home/aleksander/Pictures/ModeManager-logo-10.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient6094">
+      <stop
+         style="stop-color:#ff0300;stop-opacity:1;"
+         offset="0"
+         id="stop6096" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop6098" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient5769">
+      <stop
+         style="stop-color:#0c09ff;stop-opacity:1;"
+         offset="0"
+         id="stop5771" />
+      <stop
+         style="stop-color:#bac7ff;stop-opacity:0;"
+         offset="1"
+         id="stop5773" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient5724">
+      <stop
+         style="stop-color:#ff8900;stop-opacity:1;"
+         offset="0"
+         id="stop5726" />
+      <stop
+         style="stop-color:#ffbaba;stop-opacity:0;"
+         offset="1"
+         id="stop5728" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient5292">
+      <stop
+         id="stop5302"
+         offset="0"
+         style="stop-color:#ff0000;stop-opacity:0.26086956;" />
+      <stop
+         style="stop-color:#ff0000;stop-opacity:0;"
+         offset="1"
+         id="stop5296" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient5282">
+      <stop
+         style="stop-color:#f00000;stop-opacity:0.97457629;"
+         offset="0"
+         id="stop5284" />
+      <stop
+         id="stop5308"
+         offset="0.5"
+         style="stop-color:#f70000;stop-opacity:0.4745098;" />
+      <stop
+         style="stop-color:#ff0000;stop-opacity:0;"
+         offset="1"
+         id="stop5286" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3818">
+      <stop
+         style="stop-color:#ff0000;stop-opacity:1;"
+         offset="0"
+         id="stop3820" />
+      <stop
+         style="stop-color:#ff0000;stop-opacity:0;"
+         offset="1"
+         id="stop3822" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6094"
+       id="linearGradient6100"
+       x1="195.35713"
+       y1="719.68359"
+       x2="450.27313"
+       y2="717.39496"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.2781955,0,0,0.83050847,-878.91412,172.1932)" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.98994949"
+     inkscape:cx="5.3139229"
+     inkscape:cy="812.54229"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1600"
+     inkscape:window-height="834"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     showguides="false">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3780" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       sodipodi:type="arc"
+       style="opacity:0.50000000000000000;fill:none;stroke:#05a50d;stroke-width:6;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="path5800-8"
+       sodipodi:cx="-382.34274"
+       sodipodi:cy="326.56757"
+       sodipodi:rx="42.93148"
+       sodipodi:ry="40.406101"
+       d="m -396.33913,288.36909 a 42.93148,40.406101 0 0 1 56.92787,38.19848"
+       sodipodi:start="4.3803018"
+       sodipodi:end="6.2831853"
+       transform="translate(614.67785,85.610455)"
+       sodipodi:open="true" />
+    <path
+       sodipodi:type="arc"
+       style="fill:none;stroke:#045900;stroke-width:28.72183228000000099;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="path5800-1-5"
+       sodipodi:cx="-382.34274"
+       sodipodi:cy="326.56757"
+       sodipodi:rx="42.93148"
+       sodipodi:ry="40.406101"
+       d="m -394.32583,287.76737 a 42.93148,40.406101 0 0 1 54.91457,38.8002"
+       sodipodi:start="4.4295101"
+       sodipodi:end="6.2831853"
+       transform="matrix(0.24371704,0,0,0.24371704,324.88787,332.46101)"
+       sodipodi:open="true" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:0.75000000000000000;fill:none;stroke:#007f0e;stroke-width:11.44055462000000034;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="path5800-9-8"
+       sodipodi:cx="-382.34274"
+       sodipodi:cy="326.56757"
+       sodipodi:rx="42.93148"
+       sodipodi:ry="40.406101"
+       d="m -396.17542,288.31631 a 42.93148,40.406101 0 0 1 56.76416,38.25126"
+       sodipodi:start="4.3843327"
+       sodipodi:end="6.2831853"
+       transform="matrix(0.61185844,0,0,0.61185844,465.81116,211.88657)"
+       sodipodi:open="true" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:0.25000000000000000;fill:none;stroke:#02d300;stroke-width:3.62445903000000014;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="path5800-95-9"
+       sodipodi:cx="-382.34274"
+       sodipodi:cy="326.56757"
+       sodipodi:rx="42.93148"
+       sodipodi:ry="40.406101"
+       d="m -396.52453,288.42972 a 42.93148,40.406101 0 0 1 57.11327,38.13785"
+       sodipodi:start="4.3757301"
+       sodipodi:end="6.2831853"
+       transform="matrix(1.3795162,0,0,1.3795162,759.70335,-39.189369)"
+       sodipodi:open="true" />
+  </g>
+</svg>
diff --git a/docs/reference/libmbim-glib/libmbim-glib-common.sections b/docs/reference/libmbim-glib/libmbim-glib-common.sections
index 59f6021..a1d1103 100644
--- a/docs/reference/libmbim-glib/libmbim-glib-common.sections
+++ b/docs/reference/libmbim-glib/libmbim-glib-common.sections
@@ -24,6 +24,10 @@
 MBIM_UUID_MS_HOST_SHUTDOWN
 <SUBSECTION Methods>
 mbim_service_get_string
+mbim_service_lookup_name
+mbim_register_custom_service
+mbim_unregister_custom_service
+mbim_service_id_is_custom
 mbim_context_type_get_string
 mbim_uuid_cmp
 mbim_uuid_from_printable
diff --git a/src/libmbim-glib/mbim-enums.h b/src/libmbim-glib/mbim-enums.h
index 0d043f2..d851934 100644
--- a/src/libmbim-glib/mbim-enums.h
+++ b/src/libmbim-glib/mbim-enums.h
@@ -368,34 +368,76 @@
  * MbimNwError:
  * @MBIM_NW_ERROR_UNKNOWN: Unknown or unset error.
  * @MBIM_NW_ERROR_IMSI_UNKNOWN_IN_HLR: IMSI unknown in the HLR.
+ * @MBIM_NW_ERROR_ILLEGAL_MS: Illegal MS.
  * @MBIM_NW_ERROR_IMSI_UNKNOWN_IN_VLR: IMSI unknown in the VLR.
+ * @MBIM_NW_ERROR_IMEI_NOT_ACCEPTED: IMEI not accepted.
  * @MBIM_NW_ERROR_ILLEGAL_ME: Illegal ME.
  * @MBIM_NW_ERROR_GPRS_NOT_ALLOWED: GPRS not allowed.
  * @MBIM_NW_ERROR_GPRS_AND_NON_GPRS_NOT_ALLOWED: GPRS and non-GPRS not allowed.
+ * @MBIM_NW_ERROR_MS_IDENTITY_NOT_DERIVED_BY_NETWORK: MS identity cannot be derived by the network.
+ * @MBIM_NW_ERROR_IMPLICITLY_DETACHED: Implicitly detached.
  * @MBIM_NW_ERROR_PLMN_NOT_ALLOWED: PLMN not allowed.
  * @MBIM_NW_ERROR_LOCATION_AREA_NOT_ALLOWED: Location area not allowed.
  * @MBIM_NW_ERROR_ROAMING_NOT_ALLOWED_IN_LOCATION_AREA: Roaming not allowed in the location area.
  * @MBIM_NW_ERROR_GPRS_NOT_ALLOWED_IN_PLMN: GPRS not allowed in PLMN.
  * @MBIM_NW_ERROR_NO_CELLS_IN_LOCATION_AREA: No cells in location area.
+ * @MBIM_NW_ERROR_MSC_TEMPORARILY_NOT_REACHABLE: MSC temporarily not reachable.
  * @MBIM_NW_ERROR_NETWORK_FAILURE: Network failure.
+ * @MBIM_NW_ERROR_MAC_FAILURE: MAC failure.
+ * @MBIM_NW_ERROR_SYNCH_FAILURE: Synch failure.
  * @MBIM_NW_ERROR_CONGESTION: Congestion.
+ * @MBIM_NW_ERROR_GSM_AUTHENTICATION_UNACCEPTABLE: GSM authentication unacceptable.
+ * @MBIM_NW_ERROR_NOT_AUTHORIZED_FOR_CSG: Not authorized for this CSG.
+ * @MBIM_NW_ERROR_SERVICE_OPTION_NOT_SUPPORTED: Service option not supported.
+ * @MBIM_NW_ERROR_REQUESTED_SERVICE_OPTION_NOT_SUBSCRIBED: Requested service option not subscribed.
+ * @MBIM_NW_ERROR_SERVICE_OPTION_TEMPORARILY_OUT_OF_ORDER: Service option temporarily out of order.
+ * @MBIM_NW_ERROR_NO_PDP_CONTEXT_ACTIVATED: No PDP context activated.
+ * @MBIM_NW_ERROR_SEMANTICALLY_INCORRECT_MESSAGE: Semantically incorrect message.
+ * @MBIM_NW_ERROR_INVALID_MANDATORY_INFORMATION: Invalid mandatory information.
+ * @MBIM_NW_ERROR_MESSAGE_TYPE_NON_EXISTENT_OR_NOT_IMPLEMENTED: Message type non-existent or not implemented.
+ * @MBIM_NW_ERROR_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE: Message type not compatible with protocol state.
+ * @MBIM_NW_ERROR_INFORMATION_ELEMENT_NON_EXISTENT_OR_NOT_IMPLEMENTED: Information element non-existent or not implemented.
+ * @MBIM_NW_ERROR_CONDITIONAL_IE_ERROR: Conditional IE error.
+ * @MBIM_NW_ERROR_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE: Message not compatible with protocol state.
+ * @MBIM_NW_ERROR_PROTOCOL_ERROR_UNSPECIFIED: Protocol error, unspecified.
  *
  *  Network errors.
  */
 typedef enum {
-    MBIM_NW_ERROR_UNKNOWN                              = 0,
-    MBIM_NW_ERROR_IMSI_UNKNOWN_IN_HLR                  = 2,
-    MBIM_NW_ERROR_IMSI_UNKNOWN_IN_VLR                  = 4,
-    MBIM_NW_ERROR_ILLEGAL_ME                           = 6,
-    MBIM_NW_ERROR_GPRS_NOT_ALLOWED                     = 7,
-    MBIM_NW_ERROR_GPRS_AND_NON_GPRS_NOT_ALLOWED        = 8,
-    MBIM_NW_ERROR_PLMN_NOT_ALLOWED                     = 11,
-    MBIM_NW_ERROR_LOCATION_AREA_NOT_ALLOWED            = 12,
-    MBIM_NW_ERROR_ROAMING_NOT_ALLOWED_IN_LOCATION_AREA = 13,
-    MBIM_NW_ERROR_GPRS_NOT_ALLOWED_IN_PLMN             = 14,
-    MBIM_NW_ERROR_NO_CELLS_IN_LOCATION_AREA            = 15,
-    MBIM_NW_ERROR_NETWORK_FAILURE                      = 17,
-    MBIM_NW_ERROR_CONGESTION                           = 22
+    MBIM_NW_ERROR_UNKNOWN                                             = 0,
+    MBIM_NW_ERROR_IMSI_UNKNOWN_IN_HLR                                 = 2,
+    MBIM_NW_ERROR_ILLEGAL_MS                                          = 3,
+    MBIM_NW_ERROR_IMSI_UNKNOWN_IN_VLR                                 = 4,
+    MBIM_NW_ERROR_IMEI_NOT_ACCEPTED                                   = 5,
+    MBIM_NW_ERROR_ILLEGAL_ME                                          = 6,
+    MBIM_NW_ERROR_GPRS_NOT_ALLOWED                                    = 7,
+    MBIM_NW_ERROR_GPRS_AND_NON_GPRS_NOT_ALLOWED                       = 8,
+    MBIM_NW_ERROR_MS_IDENTITY_NOT_DERIVED_BY_NETWORK                  = 9,
+    MBIM_NW_ERROR_IMPLICITLY_DETACHED                                 = 10,
+    MBIM_NW_ERROR_PLMN_NOT_ALLOWED                                    = 11,
+    MBIM_NW_ERROR_LOCATION_AREA_NOT_ALLOWED                           = 12,
+    MBIM_NW_ERROR_ROAMING_NOT_ALLOWED_IN_LOCATION_AREA                = 13,
+    MBIM_NW_ERROR_GPRS_NOT_ALLOWED_IN_PLMN                            = 14,
+    MBIM_NW_ERROR_NO_CELLS_IN_LOCATION_AREA                           = 15,
+    MBIM_NW_ERROR_MSC_TEMPORARILY_NOT_REACHABLE                       = 16,
+    MBIM_NW_ERROR_NETWORK_FAILURE                                     = 17,
+    MBIM_NW_ERROR_MAC_FAILURE                                         = 20,
+    MBIM_NW_ERROR_SYNCH_FAILURE                                       = 21,
+    MBIM_NW_ERROR_CONGESTION                                          = 22,
+    MBIM_NW_ERROR_GSM_AUTHENTICATION_UNACCEPTABLE                     = 23,
+    MBIM_NW_ERROR_NOT_AUTHORIZED_FOR_CSG                              = 25,
+    MBIM_NW_ERROR_SERVICE_OPTION_NOT_SUPPORTED                        = 32,
+    MBIM_NW_ERROR_REQUESTED_SERVICE_OPTION_NOT_SUBSCRIBED             = 33,
+    MBIM_NW_ERROR_SERVICE_OPTION_TEMPORARILY_OUT_OF_ORDER             = 34,
+    MBIM_NW_ERROR_NO_PDP_CONTEXT_ACTIVATED                            = 40,
+    MBIM_NW_ERROR_SEMANTICALLY_INCORRECT_MESSAGE                      = 95,
+    MBIM_NW_ERROR_INVALID_MANDATORY_INFORMATION                       = 96,
+    MBIM_NW_ERROR_MESSAGE_TYPE_NON_EXISTENT_OR_NOT_IMPLEMENTED        = 97,
+    MBIM_NW_ERROR_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE     = 98,
+    MBIM_NW_ERROR_INFORMATION_ELEMENT_NON_EXISTENT_OR_NOT_IMPLEMENTED = 99,
+    MBIM_NW_ERROR_CONDITIONAL_IE_ERROR                                = 100,
+    MBIM_NW_ERROR_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE          = 101,
+    MBIM_NW_ERROR_PROTOCOL_ERROR_UNSPECIFIED                          = 111
 } MbimNwError;
 
 /**
diff --git a/src/libmbim-glib/mbim-message.c b/src/libmbim-glib/mbim-message.c
index 1a37766..7078129 100644
--- a/src/libmbim-glib/mbim-message.c
+++ b/src/libmbim-glib/mbim-message.c
@@ -1198,7 +1198,7 @@
                                     "%s  cid     = '%s' (0x%08x)\n"
                                     "%s  type    = '%s' (0x%08x)\n",
                                     line_prefix,
-                                    line_prefix, mbim_service_get_string (mbim_message_command_get_service (self)), uuid_printable,
+                                    line_prefix, mbim_service_lookup_name (mbim_message_command_get_service (self)), uuid_printable,
                                     line_prefix, cid_printable, mbim_message_command_get_cid (self),
                                     line_prefix, mbim_message_command_type_get_string (mbim_message_command_get_command_type (self)), mbim_message_command_get_command_type (self));
             g_free (uuid_printable);
@@ -1229,7 +1229,7 @@
                                     "%s  cid          = '%s' (0x%08x)\n",
                                     line_prefix,
                                     line_prefix, mbim_status_error_get_string (status), status,
-                                    line_prefix, mbim_service_get_string (mbim_message_command_done_get_service (self)), uuid_printable,
+                                    line_prefix, mbim_service_lookup_name (mbim_message_command_done_get_service (self)), uuid_printable,
                                     line_prefix, cid_printable, mbim_message_command_done_get_cid (self));
             g_free (uuid_printable);
         }
@@ -1255,7 +1255,7 @@
                                     "%s  service = '%s' (%s)\n"
                                     "%s  cid     = '%s' (0x%08x)\n",
                                     line_prefix,
-                                    line_prefix, mbim_service_get_string (mbim_message_indicate_status_get_service (self)), uuid_printable,
+                                    line_prefix, mbim_service_lookup_name (mbim_message_indicate_status_get_service (self)), uuid_printable,
                                     line_prefix, cid_printable, mbim_message_indicate_status_get_cid (self));
             g_free (uuid_printable);
         }
@@ -1738,7 +1738,7 @@
 
     /* Known service required */
     g_return_val_if_fail (service > MBIM_SERVICE_INVALID, FALSE);
-    g_return_val_if_fail (service <= MBIM_SERVICE_MS_HOST_SHUTDOWN, FALSE);
+    g_return_val_if_fail (service <= MBIM_SERVICE_MS_HOST_SHUTDOWN || mbim_service_id_is_custom (service), FALSE);
     service_id = mbim_uuid_from_service (service);
 
     self = _mbim_message_allocate (MBIM_MESSAGE_TYPE_COMMAND,
diff --git a/src/libmbim-glib/mbim-uuid.c b/src/libmbim-glib/mbim-uuid.c
index 2ee5e5e..8b53ed8 100644
--- a/src/libmbim-glib/mbim-uuid.c
+++ b/src/libmbim-glib/mbim-uuid.c
@@ -27,6 +27,7 @@
 #include <string.h>
 
 #include "mbim-uuid.h"
+#include "generated/mbim-enum-types.h"
 
 /**
  * SECTION: mbim-uuid
@@ -217,6 +218,127 @@
     .e = { 0x27, 0xd7, 0xfb, 0x80, 0x95, 0x9c }
 };
 
+static GList *mbim_custom_service_list = NULL;
+
+typedef struct {
+    guint service_id;
+    MbimUuid uuid;
+    gchar *nickname;
+} MbimCustomService;
+
+/**
+ * mbim_register_custom_service:
+ * @uuid: MbimUuid structure corresponding to service
+ * @nickname: a printable name for service
+ *
+ * Register a custom service
+ *
+ * Returns: TRUE if service has been registered, FALSE otherwise.
+ */
+guint
+mbim_register_custom_service (const MbimUuid *uuid,
+                              const gchar *nickname)
+{
+    MbimCustomService *s;
+    GList *l;
+    guint service_id = 100;
+
+    for (l = mbim_custom_service_list; l != NULL; l = l->next) {
+        s = (MbimCustomService *)l->data;
+        if (mbim_uuid_cmp (&s->uuid, uuid))
+            return s->service_id;
+        else
+            service_id = MAX (service_id, s->service_id);
+    }
+
+    /* create a new custom service */
+    s = g_slice_new (MbimCustomService);
+    s->service_id = service_id + 1;
+    memcpy (&s->uuid, uuid, sizeof (MbimUuid));
+    s->nickname = g_strdup (nickname);
+
+    mbim_custom_service_list = g_list_append (mbim_custom_service_list, s);
+    return s->service_id;
+}
+
+/**
+ * mbim_unregister_custom_service:
+ * @id: ID of the service to unregister.MbimUuid structure corresponding to service
+ *
+ * Unregister a custom service.
+ *
+ * Returns: TRUE if service has been unregistered, FALSE otherwise.
+ */
+gboolean
+mbim_unregister_custom_service (const guint id)
+{
+    MbimCustomService *s;
+    GList *l;
+
+    for (l = mbim_custom_service_list; l != NULL; l = l->next) {
+        s = (MbimCustomService *)l->data;
+        if (s->service_id == id) {
+            g_free (s->nickname);
+            g_slice_free (MbimCustomService, s);
+            mbim_custom_service_list = \
+                g_list_delete_link (mbim_custom_service_list, l);
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+/**
+ * mbim_service_id_is_custom:
+ * @id: ID of the service
+ *
+ * Checks whether @id is a custom or standard service.
+ *
+ * Returns: TRUE if service is custom, FALSE otherwise.
+ */
+gboolean
+mbim_service_id_is_custom (const guint id)
+{
+    GList *l;
+
+    if (id <= MBIM_SERVICE_MS_HOST_SHUTDOWN)
+        return FALSE;
+
+    for (l = mbim_custom_service_list; l != NULL; l = l->next) {
+        if (((MbimCustomService *)l->data)->service_id == id)
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+/**
+ * mbim_service_lookup_name:
+ * @service: a MbimService or custom service.
+ *
+ * Gets the nickname string for the @service.
+ *
+ * As opposed to mbim_service_get_string(), this methods takes into account
+ * custom services that may have been registered by the user.
+ *
+ * Returns: (transfer none): a string with the nickname, or %NULL if not found. Do not free the returned value.
+ */
+const gchar *
+mbim_service_lookup_name (guint service)
+{
+    GList *l;
+
+    if (service <= MBIM_SERVICE_MS_HOST_SHUTDOWN)
+        return mbim_service_get_string (service);
+
+    for (l = mbim_custom_service_list; l != NULL; l = l->next) {
+        if (service == ((MbimCustomService *)l->data)->service_id)
+            return ((MbimCustomService *)l->data)->nickname;
+    }
+    return NULL;
+}
+
 /**
  * mbim_uuid_from_service:
  * @service: a #MbimService.
@@ -228,7 +350,11 @@
 const MbimUuid *
 mbim_uuid_from_service (MbimService service)
 {
-    g_return_val_if_fail (service >= MBIM_SERVICE_INVALID && service <= MBIM_SERVICE_MS_HOST_SHUTDOWN,
+    GList *l;
+
+    g_return_val_if_fail (service >= MBIM_SERVICE_INVALID &&
+                          (service <= MBIM_SERVICE_MS_HOST_SHUTDOWN ||
+                           mbim_service_id_is_custom (service)),
                           &uuid_invalid);
 
     switch (service) {
@@ -253,6 +379,10 @@
     case MBIM_SERVICE_MS_HOST_SHUTDOWN:
         return &uuid_ms_host_shutdown;
     default:
+        for (l = mbim_custom_service_list; l != NULL; l = l->next) {
+            if (service == ((MbimCustomService *)l->data)->service_id)
+                return &((MbimCustomService *)l->data)->uuid;
+        }
         g_assert_not_reached ();
     }
 }
@@ -268,6 +398,8 @@
 MbimService
 mbim_uuid_to_service (const MbimUuid *uuid)
 {
+    GList *l;
+
     if (mbim_uuid_cmp (uuid, &uuid_basic_connect))
         return MBIM_SERVICE_BASIC_CONNECT;
 
@@ -295,6 +427,11 @@
     if (mbim_uuid_cmp (uuid, &uuid_ms_host_shutdown))
         return MBIM_SERVICE_MS_HOST_SHUTDOWN;
 
+    for (l = mbim_custom_service_list; l != NULL; l = l->next) {
+        if (mbim_uuid_cmp (&((MbimCustomService *)l->data)->uuid, uuid))
+            return ((MbimCustomService *)l->data)->service_id;
+    }
+
     return MBIM_SERVICE_INVALID;
 }
 
@@ -372,6 +509,7 @@
     .e = { 0x03, 0x3C, 0x39, 0xF6, 0x0D, 0xB9 }
 };
 
+
 /**
  * mbim_uuid_from_context_type:
  * @context_type: a #MbimContextType.
diff --git a/src/libmbim-glib/mbim-uuid.h b/src/libmbim-glib/mbim-uuid.h
index 50430b0..6ed74db 100644
--- a/src/libmbim-glib/mbim-uuid.h
+++ b/src/libmbim-glib/mbim-uuid.h
@@ -176,6 +176,15 @@
  */
 #define MBIM_UUID_MS_HOST_SHUTDOWN mbim_uuid_from_service (MBIM_SERVICE_MS_HOST_SHUTDOWN)
 
+const gchar *mbim_service_lookup_name (guint service);
+
+guint mbim_register_custom_service (const MbimUuid *uuid,
+                                    const gchar *nickname);
+
+gboolean mbim_unregister_custom_service (const guint id);
+
+gboolean mbim_service_id_is_custom (const guint id);
+
 /* To/From service */
 const MbimUuid *mbim_uuid_from_service  (MbimService     service);
 MbimService     mbim_uuid_to_service    (const MbimUuid *uuid);
@@ -210,6 +219,8 @@
     MBIM_CONTEXT_TYPE_LOCAL       = 9,
 } MbimContextType;
 
+const gchar *mbim_context_type_get_string (MbimContextType val);
+
 /* To/From context type */
 const MbimUuid  *mbim_uuid_from_context_type (MbimContextType  context_type);
 MbimContextType  mbim_uuid_to_context_type   (const MbimUuid  *uuid);
diff --git a/src/libmbim-glib/test/test-uuid.c b/src/libmbim-glib/test/test-uuid.c
index ce6e4bf..d8950ad 100644
--- a/src/libmbim-glib/test/test-uuid.c
+++ b/src/libmbim-glib/test/test-uuid.c
@@ -158,6 +158,35 @@
 
 /*****************************************************************************/
 
+static void
+test_uuid_custom (void)
+{
+    static const gchar *nick = "register_custom";
+    static const MbimUuid uuid_custom = {
+        .a = { 0x52, 0x65, 0x67, 0x69 },
+        .b = { 0x73, 0x74 },
+        .c = { 0x65, 0x72 },
+        .d = { 0x20, 0x63 },
+        .e = { 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x21 }
+    };
+    guint service;
+
+    /* SERVICE_AUTH is not a custom service */
+    g_assert (!mbim_service_id_is_custom (MBIM_SERVICE_AUTH));
+
+    service = mbim_register_custom_service (&uuid_custom, nick);
+    g_assert (mbim_service_id_is_custom (service));
+    g_assert (g_strcmp0 (mbim_service_lookup_name (service), nick) == 0);
+    g_assert (mbim_uuid_cmp (mbim_uuid_from_service (service), &uuid_custom));
+    g_assert (mbim_uuid_to_service (&uuid_custom) == service);
+    g_assert (mbim_unregister_custom_service (service));
+
+    /* once removed service is not custom */
+    g_assert (!mbim_service_id_is_custom (service));
+}
+
+/*****************************************************************************/
+
 int main (int argc, char **argv)
 {
     g_test_init (&argc, &argv, NULL);
@@ -181,5 +210,7 @@
     g_test_add_func ("/libmbim-glib/uuid/invalid/dashes", test_uuid_invalid_dashes);
     g_test_add_func ("/libmbim-glib/uuid/invalid/no-hex", test_uuid_invalid_no_hex);
 
+    g_test_add_func ("/libmbim-glib/uuid/custom", test_uuid_custom);
+
     return g_test_run ();
 }