Merge remote-tracking branch 'cros/upstream' into 'cros/master'
Change-Id: Ic23b12bf9950a6937439d9943df48a17046fb3e2
diff --git a/configure.ac b/configure.ac
index d26ca3e..d560db9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@
dnl The QMI version number
m4_define([qmi_major_version], [1])
m4_define([qmi_minor_version], [21])
-m4_define([qmi_micro_version], [3])
+m4_define([qmi_micro_version], [4])
m4_define([qmi_version],
[qmi_major_version.qmi_minor_version.qmi_micro_version])
diff --git a/data/qmi-service-wds.json b/data/qmi-service-wds.json
index d30a591..2993f32 100644
--- a/data/qmi-service-wds.json
+++ b/data/qmi-service-wds.json
@@ -1740,6 +1740,10 @@
{ "common-ref" : "WDS IPv4 Address Preference",
"since" : "1.22" },
{ "common-ref" : "WDS PDP Context Number",
+ "since" : "1.22" },
+ { "common-ref" : "WDS APN Disabled Flag",
+ "since" : "1.22" },
+ { "common-ref" : "WDS Roaming Disallowed Flag",
"since" : "1.22" } ],
"output" : [ { "common-ref" : "Operation Result" },
{ "common-ref" : "WDS Profile Identifier",
diff --git a/src/libqmi-glib/qmi-errors.h b/src/libqmi-glib/qmi-errors.h
index 4ff446c..b70ae6f 100644
--- a/src/libqmi-glib/qmi-errors.h
+++ b/src/libqmi-glib/qmi-errors.h
@@ -71,7 +71,7 @@
* @QMI_CORE_ERROR_TLV_NOT_FOUND: TLV not found.
* @QMI_CORE_ERROR_TLV_TOO_LONG: TLV is too long.
* @QMI_CORE_ERROR_UNSUPPORTED: Not supported.
- * @QMI_CORE_ERROR_TLV_EMPTY: TLV has no value. Since: 1.12.
+ * @QMI_CORE_ERROR_TLV_EMPTY: TLV has no value. Empty TLVs are not a real error, so this error type is never generated. Since: 1.12. Deprecated: 1.22.
* @QMI_CORE_ERROR_UNEXPECTED_MESSAGE: QMI message is unexpected. Since: 1.16.
*
* Common errors that may be reported by libqmi-glib.
diff --git a/src/libqmi-glib/qmi-message.c b/src/libqmi-glib/qmi-message.c
index f610020..0831057 100644
--- a/src/libqmi-glib/qmi-message.c
+++ b/src/libqmi-glib/qmi-message.c
@@ -585,15 +585,9 @@
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (self->len >= (tlv_offset + sizeof (struct tlv)), FALSE);
+ /* A TLV without content is actually not an error, e.g. TLV strings with no
+ * data are totally valid. */
tlv_length = self->len - tlv_offset;
- if (tlv_length == sizeof (struct tlv)) {
- g_set_error (error,
- QMI_CORE_ERROR,
- QMI_CORE_ERROR_TLV_EMPTY,
- "Empty TLV, no value set");
- g_byte_array_set_size (self, tlv_offset);
- return FALSE;
- }
/* Update length fields. */
tlv = tlv_get_header (self, tlv_offset);
@@ -873,11 +867,6 @@
}
tlv_length = GUINT16_FROM_LE (tlv->length);
- if (!tlv_length) {
- g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_EMPTY,
- "TLV 0x%02X is empty", type);
- return 0;
- }
if (((guint8 *) tlv_next (tlv)) > ((guint8 *) qmi_end (self))) {
g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG,
diff --git a/src/libqmi-glib/test/test-message.c b/src/libqmi-glib/test/test-message.c
index 973b383..4e7c703 100644
--- a/src/libqmi-glib/test/test-message.c
+++ b/src/libqmi-glib/test/test-message.c
@@ -373,8 +373,8 @@
g_assert (init_offset > 0);
ret = qmi_message_tlv_write_complete (self, init_offset, &error);
- g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_EMPTY);
- g_assert (!ret);
+ g_assert_no_error (error);
+ g_assert (ret);
qmi_message_unref (self);
}
diff --git a/src/qmicli/qmicli-helpers.c b/src/qmicli/qmicli-helpers.c
index 7d996d2..3481b36 100644
--- a/src/qmicli/qmicli-helpers.c
+++ b/src/qmicli/qmicli-helpers.c
@@ -676,6 +676,24 @@
}
gboolean
+qmicli_read_pdp_type_from_string (const gchar *str,
+ QmiWdsPdpType *out)
+{
+ if (g_ascii_strcasecmp (str, "IP") == 0 || g_ascii_strcasecmp (str, "IPV4") == 0)
+ *out = QMI_WDS_PDP_TYPE_IPV4;
+ else if (g_ascii_strcasecmp (str, "PPP") == 0)
+ *out = QMI_WDS_PDP_TYPE_PPP;
+ else if (g_ascii_strcasecmp (str, "IPV6") == 0)
+ *out = (QMI_WDS_PDP_TYPE_IPV6);
+ else if (g_ascii_strcasecmp (str, "IPV4V6") == 0)
+ *out = QMI_WDS_PDP_TYPE_IPV4_OR_IPV6;
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
+gboolean
qmicli_read_boot_image_download_mode_from_string (const gchar *str,
QmiDmsBootImageDownloadMode *out)
{
diff --git a/src/qmicli/qmicli-helpers.h b/src/qmicli/qmicli-helpers.h
index 144151e..ed8e61a 100644
--- a/src/qmicli/qmicli-helpers.h
+++ b/src/qmicli/qmicli-helpers.h
@@ -70,6 +70,8 @@
QmiWdsAutoconnectSettingRoaming *out);
gboolean qmicli_read_authentication_from_string (const gchar *str,
QmiWdsAuthentication *out);
+gboolean qmicli_read_pdp_type_from_string (const gchar *str,
+ QmiWdsPdpType *out);
gboolean qmicli_read_boot_image_download_mode_from_string (const gchar *str,
QmiDmsBootImageDownloadMode *out);
gboolean qmicli_read_hp_device_mode_from_string (const gchar *str,
diff --git a/src/qmicli/qmicli-loc.c b/src/qmicli/qmicli-loc.c
index 8c9c169..6fc2845 100644
--- a/src/qmicli/qmicli-loc.c
+++ b/src/qmicli/qmicli-loc.c
@@ -185,7 +185,7 @@
}
if (timeout > 0 && !(get_position_report_flag || get_gnss_sv_info_flag)) {
- g_printerr ("error: `--loc-timeout' is only applicable with `--loc-get-position' or `--loc-get-satellite-info'\n");
+ g_printerr ("error: `--loc-timeout' is only applicable with `--loc-get-position-report' or `--loc-get-gnss-sv-info'\n");
exit (EXIT_FAILURE);
}
diff --git a/src/qmicli/qmicli-wds.c b/src/qmicli/qmicli-wds.c
index 17ce609..02b2471 100644
--- a/src/qmicli/qmicli-wds.c
+++ b/src/qmicli/qmicli-wds.c
@@ -64,6 +64,10 @@
static gboolean go_dormant_flag;
static gboolean go_active_flag;
static gboolean get_dormancy_status_flag;
+static gchar *create_profile_str;
+static gchar *swi_create_profile_indexed_str;
+static gchar *modify_profile_str;
+static gchar *delete_profile_str;
static gchar *get_profile_list_str;
static gchar *get_default_profile_num_str;
static gchar *set_default_profile_num_str;
@@ -122,6 +126,22 @@
"Get the dormancy status of the active data connection",
NULL
},
+ { "wds-create-profile", 0, 0, G_OPTION_ARG_STRING, &create_profile_str,
+ "Create new profile using first available profile index (optional keys: name, apn, pdp-type (IP|PPP|IPV6|IPV4V6), auth (NONE|PAP|CHAP|BOTH), username, password, context-num, no-roaming=yes, disabled=yes)",
+ "[\"(3gpp|3gpp2)[,key=value,...]\"]"
+ },
+ { "wds-swi-create-profile-indexed", 0, 0, G_OPTION_ARG_STRING, &swi_create_profile_indexed_str,
+ "Create new profile at specified profile index [Sierra Wireless specific] (optional keys: name, apn, pdp-type (IP|PPP|IPV6|IPV4V6), auth (NONE|PAP|CHAP|BOTH), username, password, context-num, no-roaming=yes, disabled=yes)",
+ "[\"(3gpp|3gpp2),#[,key=value,...]\"]"
+ },
+ { "wds-modify-profile", 0, 0, G_OPTION_ARG_STRING, &modify_profile_str,
+ "Modify existing profile (optional keys: name, apn, pdp-type (IP|PPP|IPV6|IPV4V6), auth (NONE|PAP|CHAP|BOTH), username, password, context-num, no-roaming=yes, disabled=yes)",
+ "[\"(3gpp|3gpp2),#,key=value,...\"]"
+ },
+ { "wds-delete-profile", 0, 0, G_OPTION_ARG_STRING, &delete_profile_str,
+ "Delete existing profile",
+ "[(3gpp|3gpp2),#]"
+ },
{ "wds-get-profile-list", 0, 0, G_OPTION_ARG_STRING, &get_profile_list_str,
"Get profile list",
"[3gpp|3gpp2]"
@@ -209,6 +229,10 @@
go_dormant_flag +
go_active_flag +
get_dormancy_status_flag +
+ !!create_profile_str +
+ !!swi_create_profile_indexed_str +
+ !!modify_profile_str +
+ !!delete_profile_str +
!!get_profile_list_str +
!!get_default_profile_num_str +
!!set_default_profile_num_str +
@@ -1180,6 +1204,620 @@
operation_shutdown (TRUE);
}
+
+typedef struct {
+ QmiWdsProfileType profile_type;
+ guint profile_index;
+ guint context_number;
+ gchar *name;
+ QmiWdsPdpType pdp_type;
+ gboolean pdp_type_set;
+ gchar *apn;
+ gchar *username;
+ gchar *password;
+ QmiWdsAuthentication auth;
+ gboolean auth_set;
+ gboolean no_roaming;
+ gboolean no_roaming_set;
+ gboolean disabled;
+ gboolean disabled_set;
+} CreateModifyProfileProperties;
+
+static gboolean
+create_modify_profile_properties_handle (const gchar *key,
+ const gchar *value,
+ GError **error,
+ gpointer user_data)
+{
+ CreateModifyProfileProperties *props = user_data;
+
+ /* Allow empty values for string parameters */
+
+ if (g_ascii_strcasecmp (key, "name") == 0 && !props->name) {
+ props->name = g_strdup (value);
+ return TRUE;
+ }
+
+ if (g_ascii_strcasecmp (key, "apn") == 0 && !props->apn) {
+ props->apn = g_strdup (value);
+ return TRUE;
+ }
+
+ if (g_ascii_strcasecmp (key, "username") == 0 && !props->username) {
+ props->username = g_strdup (value);
+ return TRUE;
+ }
+
+ if (g_ascii_strcasecmp (key, "password") == 0 && !props->password) {
+ props->password = g_strdup (value);
+ return TRUE;
+ }
+
+ /* all other TLVs do require a value... */
+ if (!value || !value[0]) {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "key '%s' required a value",
+ key);
+ return FALSE;
+ }
+
+ if (g_ascii_strcasecmp (key, "context-num") == 0 && !props->context_number) {
+ props->context_number = atoi (value);
+ if (props->context_number <= 0 || props->context_number > G_MAXUINT8) {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "invalid or out of range context number [1,%u]: '%s'",
+ G_MAXUINT8,
+ value);
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ if (g_ascii_strcasecmp (key, "auth") == 0 && !props->auth_set) {
+ if (!qmicli_read_authentication_from_string (value, &(props->auth))) {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "unknown auth protocol '%s'",
+ value);
+ return FALSE;
+ }
+ props->auth_set = TRUE;
+ return TRUE;
+ }
+
+ if (g_ascii_strcasecmp (key, "pdp-type") == 0 && !props->pdp_type_set) {
+ if (!qmicli_read_pdp_type_from_string (value, &(props->pdp_type))) {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "unknown pdp type '%s'",
+ value);
+ return FALSE;
+ }
+ props->pdp_type_set = TRUE;
+ return TRUE;
+ }
+
+ if (g_ascii_strcasecmp (key, "no-roaming") == 0 && !props->no_roaming_set) {
+ if (!qmicli_read_yes_no_from_string (value, &(props->no_roaming))) {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "unknown 'no-roaming' value '%s'",
+ value);
+ return FALSE;
+ }
+ props->no_roaming_set = TRUE;
+ return TRUE;
+ }
+
+ if (g_ascii_strcasecmp (key, "disabled") == 0 && !props->disabled_set) {
+ if (!qmicli_read_yes_no_from_string (value, &(props->disabled))) {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "unknown 'disabled' value '%s'",
+ value);
+ return FALSE;
+ }
+ props->disabled_set = TRUE;
+ return TRUE;
+ }
+
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "unrecognized or duplicate option '%s'",
+ key);
+ return FALSE;
+}
+
+static gboolean
+create_profile_input_create (const gchar *str,
+ QmiMessageWdsCreateProfileInput **input,
+ GError **error)
+{
+ GError *parse_error = NULL;
+ CreateModifyProfileProperties props = {};
+ gboolean success = FALSE;
+ gchar **split;
+
+ g_assert (input && !*input);
+
+ split = g_strsplit (str, ",", 2);
+ if (g_strv_length (split) < 1) {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "expected at least 1 arguments for 'wds create profile' command");
+ goto out;
+ }
+
+ g_strstrip (split[0]);
+ if (g_str_equal (split[0], "3gpp"))
+ props.profile_type = QMI_WDS_PROFILE_TYPE_3GPP;
+ else if (g_str_equal (split[0], "3gpp2"))
+ props.profile_type = QMI_WDS_PROFILE_TYPE_3GPP2;
+ else {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "invalid profile type. Expected '3gpp' or '3gpp2'.'");
+ goto out;
+ }
+
+ if (split[1]) {
+ if (!qmicli_parse_key_value_string (split[1],
+ &parse_error,
+ create_modify_profile_properties_handle,
+ &props)) {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "couldn't parse input string: %s",
+ parse_error->message);
+ g_error_free (parse_error);
+ goto out;
+ }
+ }
+
+ /* Create input bundle */
+ *input = qmi_message_wds_create_profile_input_new ();
+
+ /* Profile type is required */
+ qmi_message_wds_create_profile_input_set_profile_type (*input, props.profile_type, NULL);
+
+ if (props.context_number)
+ qmi_message_wds_create_profile_input_set_pdp_context_number (*input, props.context_number, NULL);
+
+ if (props.pdp_type_set)
+ qmi_message_wds_create_profile_input_set_pdp_type (*input, props.pdp_type, NULL);
+
+ if (props.name)
+ qmi_message_wds_create_profile_input_set_profile_name (*input, props.name, NULL);
+
+ if (props.apn)
+ qmi_message_wds_create_profile_input_set_apn_name (*input, props.apn, NULL);
+
+ if (props.auth_set)
+ qmi_message_wds_create_profile_input_set_authentication (*input, props.auth, NULL);
+
+ if (props.username)
+ qmi_message_wds_create_profile_input_set_username (*input, props.username, NULL);
+
+ if (props.password)
+ qmi_message_wds_create_profile_input_set_password (*input, props.password, NULL);
+
+ if (props.no_roaming_set)
+ qmi_message_wds_create_profile_input_set_roaming_disallowed_flag (*input, props.no_roaming, NULL);
+
+ if (props.disabled_set)
+ qmi_message_wds_create_profile_input_set_apn_disabled_flag (*input, props.disabled, NULL);
+
+ success = TRUE;
+
+out:
+ g_strfreev (split);
+ g_free (props.name);
+ g_free (props.apn);
+ g_free (props.username);
+ g_free (props.password);
+
+ return success;
+}
+
+static void
+create_profile_ready (QmiClientWds *client,
+ GAsyncResult *res)
+{
+ QmiMessageWdsCreateProfileOutput *output;
+ GError *error = NULL;
+ QmiWdsProfileType profile_type;
+ guint8 profile_index;
+
+ output = qmi_client_wds_create_profile_finish (client, res, &error);
+ if (!output) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ operation_shutdown (FALSE);
+ return;
+ }
+
+ if (!qmi_message_wds_create_profile_output_get_result (output, &error)) {
+ QmiWdsDsProfileError ds_profile_error;
+
+ if (g_error_matches (error,
+ QMI_PROTOCOL_ERROR,
+ QMI_PROTOCOL_ERROR_EXTENDED_INTERNAL) &&
+ qmi_message_wds_create_profile_output_get_extended_error_code (
+ output,
+ &ds_profile_error,
+ NULL)) {
+ g_printerr ("error: couldn't create profile: ds profile error: %s\n",
+ qmi_wds_ds_profile_error_get_string (ds_profile_error));
+ } else {
+ g_printerr ("error: couldn't create profile: %s\n",
+ error->message);
+ }
+ g_error_free (error);
+ qmi_message_wds_create_profile_output_unref (output);
+ operation_shutdown (FALSE);
+ return;
+ }
+
+ g_print ("New profile created:\n");
+ if (qmi_message_wds_create_profile_output_get_profile_identifier (output,
+ &profile_type,
+ &profile_index,
+ NULL)) {
+ g_print ("\tProfile type: '%s'\n", qmi_wds_profile_type_get_string(profile_type));
+ g_print ("\tProfile index: '%d'\n", profile_index);
+ }
+ qmi_message_wds_create_profile_output_unref (output);
+ operation_shutdown (TRUE);
+}
+
+static gboolean
+swi_create_profile_indexed_input_create (const gchar *str,
+ QmiMessageWdsSwiCreateProfileIndexedInput **input,
+ GError **error)
+{
+ GError *parse_error = NULL;
+ CreateModifyProfileProperties props = {};
+ gchar **split;
+ gboolean success = FALSE;
+
+ g_assert (input && !*input);
+
+ /* Expect max 3 tokens: the first two give us the mandatory parameters of the command,
+ * the 3rd one will contain the key/value pair list */
+ split = g_strsplit (str, ",", 3);
+ if (g_strv_length (split) < 2) {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "expected at least 2 arguments for 'wds swi create profile indexed' command");
+ goto out;
+ }
+
+ g_strstrip (split[0]);
+ if (g_str_equal (split[0], "3gpp"))
+ props.profile_type = QMI_WDS_PROFILE_TYPE_3GPP;
+ else if (g_str_equal (split[0], "3gpp2"))
+ props.profile_type = QMI_WDS_PROFILE_TYPE_3GPP2;
+ else {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "invalid profile type '%s'. Expected '3gpp' or '3gpp2'.'",
+ split[0]);
+ goto out;
+ }
+
+ g_strstrip (split[1]);
+ props.profile_index = atoi (split[1]);
+ if (props.profile_index <= 0 || props.profile_index > G_MAXUINT8) {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "invalid or out of range profile index [1,%u]: '%s'\n",
+ G_MAXUINT8,
+ split[1]);
+ goto out;
+ }
+
+ if (split[2]) {
+ if (!qmicli_parse_key_value_string (split[2],
+ &parse_error,
+ create_modify_profile_properties_handle,
+ &props)) {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "couldn't parse input string: %s",
+ parse_error->message);
+ g_error_free (parse_error);
+ goto out;
+ }
+ }
+
+ /* Create input bundle */
+ *input = qmi_message_wds_swi_create_profile_indexed_input_new ();
+
+ /* Profile identifier is required */
+ qmi_message_wds_swi_create_profile_indexed_input_set_profile_identifier (*input, props.profile_type, props.profile_index, NULL);
+
+ if (props.context_number)
+ qmi_message_wds_swi_create_profile_indexed_input_set_pdp_context_number (*input, props.context_number, NULL);
+
+ if (props.pdp_type_set)
+ qmi_message_wds_swi_create_profile_indexed_input_set_pdp_type (*input, props.pdp_type, NULL);
+
+ if (props.name)
+ qmi_message_wds_swi_create_profile_indexed_input_set_profile_name (*input, props.name, NULL);
+
+ if (props.apn)
+ qmi_message_wds_swi_create_profile_indexed_input_set_apn_name (*input, props.apn, NULL);
+
+ if (props.auth_set)
+ qmi_message_wds_swi_create_profile_indexed_input_set_authentication (*input, props.auth, NULL);
+
+ if (props.username)
+ qmi_message_wds_swi_create_profile_indexed_input_set_username (*input, props.username, NULL);
+
+ if (props.password)
+ qmi_message_wds_swi_create_profile_indexed_input_set_password (*input, props.password, NULL);
+
+ if (props.no_roaming_set)
+ qmi_message_wds_swi_create_profile_indexed_input_set_roaming_disallowed_flag (*input, props.no_roaming, NULL);
+
+ if (props.disabled_set)
+ qmi_message_wds_swi_create_profile_indexed_input_set_apn_disabled_flag (*input, props.disabled, NULL);
+
+ success = TRUE;
+
+out:
+ g_strfreev (split);
+ g_free (props.name);
+ g_free (props.apn);
+ g_free (props.username);
+ g_free (props.password);
+
+ return success;
+}
+
+static void
+swi_create_profile_indexed_ready (QmiClientWds *client,
+ GAsyncResult *res)
+{
+ QmiMessageWdsSwiCreateProfileIndexedOutput *output;
+ GError *error = NULL;
+ QmiWdsProfileType profile_type;
+ guint8 profile_index;
+
+ output = qmi_client_wds_swi_create_profile_indexed_finish (client, res, &error);
+ if (!output) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ operation_shutdown (FALSE);
+ return;
+ }
+
+ if (!qmi_message_wds_swi_create_profile_indexed_output_get_result (output, &error)) {
+ g_printerr ("error: couldn't create indexed profile: %s\n", error->message);
+ g_error_free (error);
+ qmi_message_wds_swi_create_profile_indexed_output_unref (output);
+ operation_shutdown (FALSE);
+ return;
+ }
+
+ g_print ("New profile created:\n");
+ if (qmi_message_wds_swi_create_profile_indexed_output_get_profile_identifier (output,
+ &profile_type,
+ &profile_index,
+ NULL)) {
+ g_print ("\tProfile type: '%s'\n", qmi_wds_profile_type_get_string(profile_type));
+ g_print ("\tProfile index: '%d'\n", profile_index);
+ }
+ qmi_message_wds_swi_create_profile_indexed_output_unref (output);
+ operation_shutdown (TRUE);
+}
+
+static gboolean
+modify_profile_input_create (const gchar *str,
+ QmiMessageWdsModifyProfileInput **input,
+ GError **error)
+{
+ GError *parse_error = NULL;
+ CreateModifyProfileProperties props = {};
+ gchar **split;
+ gboolean success = FALSE;
+
+ g_assert (input && !*input);
+
+ /* Expect max 3 tokens: the first two give us the mandatory parameters of the command,
+ * the 3rd one will contain the key/value pair list */
+ split = g_strsplit (str, ",", 3);
+ if (g_strv_length (split) < 3) {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "expected at least 3 arguments for 'wds modify profile' command");
+ goto out;
+ }
+
+ g_strstrip (split[0]);
+ if (g_str_equal (split[0], "3gpp"))
+ props.profile_type = QMI_WDS_PROFILE_TYPE_3GPP;
+ else if (g_str_equal (split[0], "3gpp2"))
+ props.profile_type = QMI_WDS_PROFILE_TYPE_3GPP2;
+ else {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "invalid profile type '%s'. Expected '3gpp' or '3gpp2'.'",
+ split[0]);
+ goto out;
+ }
+
+ g_strstrip (split[1]);
+ props.profile_index = atoi (split[1]);
+ if (props.profile_index <= 0 || props.profile_index > G_MAXUINT8) {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "invalid or out of range profile index [1,%u]: '%s'\n",
+ G_MAXUINT8,
+ split[1]);
+ goto out;
+ }
+
+ /* advance to third token, that's where key/value pairs start */
+ if (!qmicli_parse_key_value_string (split[2],
+ &parse_error,
+ create_modify_profile_properties_handle,
+ &props)) {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "couldn't parse input string: %s",
+ parse_error->message);
+ g_error_free (parse_error);
+ goto out;
+ }
+
+ /* Create input bundle */
+ *input = qmi_message_wds_modify_profile_input_new ();
+
+ /* Profile identifier is required */
+ qmi_message_wds_modify_profile_input_set_profile_identifier (*input, props.profile_type, props.profile_index, NULL);
+
+ if (props.context_number)
+ qmi_message_wds_modify_profile_input_set_pdp_context_number (*input, props.context_number, NULL);
+
+ if (props.pdp_type_set)
+ qmi_message_wds_modify_profile_input_set_pdp_type (*input, props.pdp_type, NULL);
+
+ if (props.name)
+ qmi_message_wds_modify_profile_input_set_profile_name (*input, props.name, NULL);
+
+ if (props.apn)
+ qmi_message_wds_modify_profile_input_set_apn_name (*input, props.apn, NULL);
+
+ if (props.auth_set)
+ qmi_message_wds_modify_profile_input_set_authentication (*input, props.auth, NULL);
+
+ if (props.username)
+ qmi_message_wds_modify_profile_input_set_username (*input, props.username, NULL);
+
+ if (props.password)
+ qmi_message_wds_modify_profile_input_set_password (*input, props.password, NULL);
+
+ if (props.no_roaming_set)
+ qmi_message_wds_modify_profile_input_set_roaming_disallowed_flag (*input, props.no_roaming, NULL);
+
+ if (props.disabled_set)
+ qmi_message_wds_modify_profile_input_set_apn_disabled_flag (*input, props.disabled, NULL);
+
+ success = TRUE;
+
+out:
+ g_strfreev (split);
+ g_free (props.name);
+ g_free (props.apn);
+ g_free (props.username);
+ g_free (props.password);
+
+ return success;
+}
+
+static void
+modify_profile_ready (QmiClientWds *client,
+ GAsyncResult *res)
+{
+ QmiMessageWdsModifyProfileOutput *output;
+ GError *error = NULL;
+
+ output = qmi_client_wds_modify_profile_finish (client, res, &error);
+ if (!output) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ operation_shutdown (FALSE);
+ return;
+ }
+
+ if (!qmi_message_wds_modify_profile_output_get_result (output, &error)) {
+ QmiWdsDsProfileError ds_profile_error;
+
+ if (g_error_matches (error,
+ QMI_PROTOCOL_ERROR,
+ QMI_PROTOCOL_ERROR_EXTENDED_INTERNAL) &&
+ qmi_message_wds_modify_profile_output_get_extended_error_code (
+ output,
+ &ds_profile_error,
+ NULL)) {
+ g_printerr ("error: couldn't modify profile: ds profile error: %s\n",
+ qmi_wds_ds_profile_error_get_string (ds_profile_error));
+ } else {
+ g_printerr ("error: couldn't modify profile: %s\n",
+ error->message);
+ }
+ g_error_free (error);
+ qmi_message_wds_modify_profile_output_unref (output);
+ operation_shutdown (FALSE);
+ return;
+ }
+ qmi_message_wds_modify_profile_output_unref (output);
+ g_print ("Profile successfully modified.\n");
+ operation_shutdown (TRUE);
+}
+
+static void
+delete_profile_ready (QmiClientWds *client,
+ GAsyncResult *res)
+{
+ QmiMessageWdsDeleteProfileOutput *output;
+ GError *error = NULL;
+
+ output = qmi_client_wds_delete_profile_finish (client, res, &error);
+ if (!output) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ operation_shutdown (FALSE);
+ return;
+ }
+
+ if (!qmi_message_wds_delete_profile_output_get_result (output, &error)) {
+ QmiWdsDsProfileError ds_profile_error;
+
+ if (g_error_matches (error,
+ QMI_PROTOCOL_ERROR,
+ QMI_PROTOCOL_ERROR_EXTENDED_INTERNAL) &&
+ qmi_message_wds_delete_profile_output_get_extended_error_code (
+ output,
+ &ds_profile_error,
+ NULL)) {
+ g_printerr ("error: couldn't delete profile: ds profile error: %s\n",
+ qmi_wds_ds_profile_error_get_string (ds_profile_error));
+ } else {
+ g_printerr ("error: couldn't delete profile: %s\n",
+ error->message);
+ }
+ g_error_free (error);
+ qmi_message_wds_delete_profile_output_unref (output);
+ operation_shutdown (FALSE);
+ return;
+ }
+ qmi_message_wds_delete_profile_output_unref (output);
+ g_print ("Profile successfully deleted.\n");
+ operation_shutdown (TRUE);
+}
+
typedef struct {
guint i;
GArray *profile_list;
@@ -1219,13 +1857,17 @@
qmi_message_wds_get_profile_settings_output_unref (output);
} else {
const gchar *str;
+ guint8 context_number;
QmiWdsPdpType pdp_type;
QmiWdsAuthentication auth;
+ gboolean flag;
if (qmi_message_wds_get_profile_settings_output_get_apn_name (output, &str, NULL))
g_print ("\t\tAPN: '%s'\n", str);
if (qmi_message_wds_get_profile_settings_output_get_pdp_type (output, &pdp_type, NULL))
g_print ("\t\tPDP type: '%s'\n", qmi_wds_pdp_type_get_string (pdp_type));
+ if (qmi_message_wds_get_profile_settings_output_get_pdp_context_number (output, &context_number, NULL))
+ g_print ("\t\tPDP context number: '%d'\n", context_number);
if (qmi_message_wds_get_profile_settings_output_get_username (output, &str, NULL))
g_print ("\t\tUsername: '%s'\n", str);
if (qmi_message_wds_get_profile_settings_output_get_password (output, &str, NULL))
@@ -1237,6 +1879,10 @@
g_print ("\t\tAuth: '%s'\n", aux);
g_free (aux);
}
+ if (qmi_message_wds_get_profile_settings_output_get_roaming_disallowed_flag (output, &flag, NULL))
+ g_print ("\t\tNo roaming: '%s'\n", flag ? "yes" : "no");
+ if (qmi_message_wds_get_profile_settings_output_get_apn_disabled_flag (output, &flag, NULL))
+ g_print ("\t\tAPN disabled: '%s'\n", flag ? "yes" : "no");
qmi_message_wds_get_profile_settings_output_unref (output);
}
@@ -2184,6 +2830,128 @@
return;
}
+ /* Create a new profile using first available profile index */
+ if (create_profile_str) {
+ QmiMessageWdsCreateProfileInput *input = NULL;
+ GError *error = NULL;
+
+ if (!create_profile_input_create (create_profile_str, &input, &error)) {
+ g_printerr ("error: %s\n", error->message);
+ g_error_free (error);
+ operation_shutdown (FALSE);
+ return;
+ }
+
+ g_debug ("Asynchronously creating new profile...");
+ qmi_client_wds_create_profile (ctx->client,
+ input,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)create_profile_ready,
+ NULL);
+ qmi_message_wds_create_profile_input_unref (input);
+ return;
+ }
+
+ /* Create a new profile at spedified profile index (Sierra Wireless only)*/
+ if (swi_create_profile_indexed_str) {
+ QmiMessageWdsSwiCreateProfileIndexedInput *input = NULL;
+ GError *error = NULL;
+
+ if (!swi_create_profile_indexed_input_create (swi_create_profile_indexed_str, &input, &error)) {
+ g_printerr ("error: %s\n", error->message);
+ g_error_free (error);
+ operation_shutdown (FALSE);
+ return;
+ }
+
+ g_debug ("Asynchronously creating new indexed profile...");
+ qmi_client_wds_swi_create_profile_indexed (ctx->client,
+ input,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)swi_create_profile_indexed_ready,
+ NULL);
+ qmi_message_wds_swi_create_profile_indexed_input_unref (input);
+ return;
+ }
+
+ /* Modify an existing profile */
+ if (modify_profile_str) {
+ QmiMessageWdsModifyProfileInput *input = NULL;
+ GError *error = NULL;
+
+ if (!modify_profile_input_create (modify_profile_str, &input, &error)) {
+ g_printerr ("error: %s\n", error->message);
+ g_error_free (error);
+ operation_shutdown (FALSE);
+ return;
+ }
+
+ g_debug ("Asynchronously modifying profile...");
+ qmi_client_wds_modify_profile (ctx->client,
+ input,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)modify_profile_ready,
+ NULL);
+ qmi_message_wds_modify_profile_input_unref (input);
+ return;
+ }
+
+ /* Delete an existing profile */
+ if (delete_profile_str) {
+ QmiMessageWdsDeleteProfileInput *input;
+ gchar **split;
+ QmiWdsProfileType profile_type;
+ guint profile_index;
+
+ split = g_strsplit (delete_profile_str, ",", -1);
+ input = qmi_message_wds_delete_profile_input_new ();
+
+ if (g_strv_length (split) != 2) {
+ g_printerr ("error: expected 2 arguments for delete profile command\n");
+ operation_shutdown (FALSE);
+ return;
+ }
+
+ g_strstrip (split[0]);
+ if (g_str_equal (split[0], "3gpp"))
+ profile_type = QMI_WDS_PROFILE_TYPE_3GPP;
+ else if (g_str_equal (split[0], "3gpp2"))
+ profile_type = QMI_WDS_PROFILE_TYPE_3GPP2;
+ else {
+ g_printerr ("error: invalid profile type '%s'. Expected '3gpp' or '3gpp2'.'\n",
+ split[0]);
+ operation_shutdown (FALSE);
+ return;
+ }
+
+ g_strstrip (split[1]);
+ profile_index = atoi (split[1]);
+ if (profile_index <= 0 || profile_index > G_MAXUINT8) {
+ g_printerr ("error: invalid or out of range profile number [1,%u]: '%s'\n",
+ G_MAXUINT8,
+ split[1]);
+ operation_shutdown (FALSE);
+ return;
+ }
+
+ qmi_message_wds_delete_profile_input_set_profile_identifier (input, profile_type, (guint8)profile_index, NULL);
+
+ g_strfreev (split);
+
+ g_debug ("Asynchronously deleting new profile...");
+ qmi_client_wds_delete_profile (ctx->client,
+ input,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)delete_profile_ready,
+ NULL);
+ qmi_message_wds_delete_profile_input_unref (input);
+ return;
+ }
+
/* Request to list profiles? */
if (get_profile_list_str) {
QmiMessageWdsGetProfileListInput *input;