diff mbox series

[uqmi,3/3] wds: allow profile reconfiguration

Message ID 20231010135845.183016-3-mail@david-bauer.net
State Superseded
Delegated to: David Bauer
Headers show
Series [uqmi,1/3] uim: add application state to SIM status | expand

Commit Message

David Bauer Oct. 10, 2023, 1:58 p.m. UTC
Extend uqmi so it can modify connection profiles stored on the modem.

This is required in case the operator disallows connections using the
dual-stacked PDP type. In case of either the home or visited network
disallowing dual-stacked connections, the PDP context establishment
fails with the default settings.

This can be worked around by configuring the APN and PDP type to profile
slot 1 and subsequently enabling the data connection.

Signed-off-by: David Bauer <mail@david-bauer.net>
---
 commands-wds.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++
 commands-wds.h |  9 +++++
 2 files changed, 105 insertions(+)

Comments

Henrik Ginstmark Oct. 11, 2023, 7:52 a.m. UTC | #1
Hi

I have a similar patch for APN profile commands,
https://patchwork.ozlabs.org/project/openwrt/patch/20220905200751.998416-1-henrik@ginstmark.se/

I included commands for
--get-default-profile-number
--get-profile-settings
--create-profile
--modify-profile

/Henrik


Den tis 10 okt. 2023 kl 16:07 skrev David Bauer <mail@david-bauer.net>:
>
> Extend uqmi so it can modify connection profiles stored on the modem.
>
> This is required in case the operator disallows connections using the
> dual-stacked PDP type. In case of either the home or visited network
> disallowing dual-stacked connections, the PDP context establishment
> fails with the default settings.
>
> This can be worked around by configuring the APN and PDP type to profile
> slot 1 and subsequently enabling the data connection.
>
> Signed-off-by: David Bauer <mail@david-bauer.net>
> ---
>  commands-wds.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  commands-wds.h |  9 +++++
>  2 files changed, 105 insertions(+)
>
> diff --git a/commands-wds.c b/commands-wds.c
> index 3aecefd..b72dcc7 100644
> --- a/commands-wds.c
> +++ b/commands-wds.c
> @@ -30,11 +30,30 @@ static struct qmi_wds_start_network_request wds_sn_req = {
>  };
>  static struct qmi_wds_stop_network_request wds_stn_req;
>
> +struct uqmi_profile_modify_req {
> +       int idx;
> +
> +       char *apn_name;
> +       char *username;
> +       char *password;
> +
> +       struct {
> +               QmiWdsPdpType val;
> +               bool set;
> +       } pdp_type;
> +
> +       struct {
> +               QmiWdsAuthentication val;
> +               bool set;
> +       } auth;
> +} prf_mdf_req;
> +
>  #define cmd_wds_set_apn_cb no_cb
>  static enum qmi_cmd_result
>  cmd_wds_set_apn_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
>  {
>         qmi_set_ptr(&wds_sn_req, apn, arg);
> +       prf_mdf_req.apn_name = arg;
>         return QMI_CMD_DONE;
>  }
>
> @@ -58,6 +77,9 @@ cmd_wds_set_auth_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qm
>                         continue;
>
>                 qmi_set(&wds_sn_req, authentication_preference, modes[i].auth);
> +
> +               prf_mdf_req.auth.set = true;
> +               prf_mdf_req.auth.val = modes[i].auth;
>                 return QMI_CMD_DONE;
>         }
>
> @@ -70,6 +92,7 @@ static enum qmi_cmd_result
>  cmd_wds_set_username_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
>  {
>         qmi_set_ptr(&wds_sn_req, username, arg);
> +       prf_mdf_req.username = arg;
>         return QMI_CMD_DONE;
>  }
>
> @@ -78,9 +101,37 @@ static enum qmi_cmd_result
>  cmd_wds_set_password_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
>  {
>         qmi_set_ptr(&wds_sn_req, password, arg);
> +       prf_mdf_req.password = arg;
>         return QMI_CMD_DONE;
>  }
>
> +#define cmd_wds_set_pdp_type_cb no_cb
> +static enum qmi_cmd_result
> +cmd_wds_set_pdp_type_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
> +{
> +       static const struct {
> +               const char *name;
> +               const QmiWdsPdpType mode;
> +       } modes[] = {
> +               { "ipv4", QMI_WDS_PDP_TYPE_IPV4 },
> +               { "ipv6", QMI_WDS_PDP_TYPE_IPV6 },
> +               { "ipv4v6", QMI_WDS_PDP_TYPE_IPV4_OR_IPV6 },
> +       };
> +       int i;
> +
> +       for (i = 0; i < ARRAY_SIZE(modes); i++) {
> +               if (strcasecmp(modes[i].name, arg) != 0)
> +                       continue;
> +
> +               prf_mdf_req.pdp_type.val = modes[i].mode;
> +               prf_mdf_req.pdp_type.set = true;
> +               return QMI_CMD_DONE;
> +       }
> +
> +       uqmi_add_error("Invalid value (valid: ipv4, ipv6, ipv4v6)");
> +       return QMI_CMD_EXIT;
> +}
> +
>  #define cmd_wds_set_autoconnect_cb no_cb
>  static enum qmi_cmd_result
>  cmd_wds_set_autoconnect_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
> @@ -123,9 +174,54 @@ cmd_wds_set_profile_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct
>         uint32_t idx = strtoul(arg, NULL, 10);
>
>         qmi_set(&wds_sn_req, profile_index_3gpp, idx);
> +       prf_mdf_req.idx = idx;
>         return QMI_CMD_DONE;
>  }
>
> +static void
> +cmd_wds_modify_profile_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
> +{
> +       struct qmi_wds_modify_profile_response res;
> +
> +       qmi_parse_wds_modify_profile_response(msg, &res);
> +       if (res.set.extended_error_code)
> +               blobmsg_add_u32(&status, NULL, res.data.extended_error_code);
> +}
> +
> +static enum qmi_cmd_result
> +cmd_wds_modify_profile_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
> +{
> +       struct qmi_wds_modify_profile_request wds_mdf_prf_req = {
> +               QMI_INIT_SEQUENCE(profile_identifier,
> +                       .profile_type = QMI_WDS_PROFILE_TYPE_3GPP,
> +                       .profile_index = prf_mdf_req.idx,
> +               ),
> +       };
> +
> +       if (!prf_mdf_req.idx) {
> +               uqmi_add_error("Profile needs to be specified");
> +               return QMI_CMD_EXIT;
> +       }
> +
> +       if (prf_mdf_req.apn_name)
> +               qmi_set_ptr(&wds_mdf_prf_req, apn_name, prf_mdf_req.apn_name);
> +
> +       if (prf_mdf_req.username)
> +               qmi_set_ptr(&wds_mdf_prf_req, username, prf_mdf_req.username);
> +
> +       if (prf_mdf_req.password)
> +               qmi_set_ptr(&wds_mdf_prf_req, password, prf_mdf_req.password);
> +
> +       if (prf_mdf_req.pdp_type.set)
> +               qmi_set(&wds_mdf_prf_req, pdp_type, prf_mdf_req.pdp_type.val);
> +
> +       if (prf_mdf_req.auth.set)
> +               qmi_set(&wds_mdf_prf_req, authentication, prf_mdf_req.auth.val);
> +
> +       qmi_set_wds_modify_profile_request(msg, &wds_mdf_prf_req);
> +       return QMI_CMD_REQUEST;
> +}
> +
>  static void
>  cmd_wds_start_network_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
>  {
> diff --git a/commands-wds.h b/commands-wds.h
> index 5aa7ea8..e9c2638 100644
> --- a/commands-wds.h
> +++ b/commands-wds.h
> @@ -29,6 +29,8 @@
>         __uqmi_command(wds_set_autoconnect, autoconnect, no, CMD_TYPE_OPTION), \
>         __uqmi_command(wds_set_profile, profile, required, CMD_TYPE_OPTION), \
>         __uqmi_command(wds_stop_network, stop-network, required, QMI_SERVICE_WDS), \
> +       __uqmi_command(wds_modify_profile, modify-profile, no, QMI_SERVICE_WDS), \
> +       __uqmi_command(wds_set_pdp_type, pdp-type, required, CMD_TYPE_OPTION), \
>         __uqmi_command(wds_get_packet_service_status, get-data-status, no, QMI_SERVICE_WDS), \
>         __uqmi_command(wds_set_ip_family, set-ip-family, required, QMI_SERVICE_WDS), \
>         __uqmi_command(wds_set_autoconnect_settings, set-autoconnect, required, QMI_SERVICE_WDS), \
> @@ -47,6 +49,13 @@
>                 "    --profile <index>:              Use connection profile\n" \
>                 "  --stop-network <pdh>:             Stop network connection (use with option below)\n" \
>                 "    --autoconnect:                  Disable automatic connect/reconnect\n" \
> +               "  --modify-profile:                 Modify a profile (use with options below)\n" \
> +               "    --profile <index>:              Profile to modify\n" \
> +               "    --apn <apn>:                    Use APN\n" \
> +               "    --auth-type pap|chap|both|none: Use network authentication type\n" \
> +               "    --username <name>:              Use network username\n" \
> +               "    --password <password>:          Use network password\n" \
> +               "    --pdp-type <family>:            Use PDP type (ipv4, ipv6, ipv4v6)\n" \
>                 "  --get-data-status:                Get current data access status\n" \
>                 "  --set-ip-family <val>:            Set ip-family (ipv4, ipv6, unspecified)\n" \
>                 "  --set-autoconnect <val>:          Set automatic connect/reconnect (disabled, enabled, paused)\n" \
> --
> 2.42.0
>
>
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel@lists.openwrt.org
> https://lists.openwrt.org/mailman/listinfo/openwrt-devel
David Bauer Oct. 11, 2023, 9:14 a.m. UTC | #2
Hi Henrik,

On 10/11/23 09:52, Henrik Ginstmark wrote:
> Hi
> 
> I have a similar patch for APN profile commands,
> https://patchwork.ozlabs.org/project/openwrt/patch/20220905200751.998416-1-henrik@ginstmark.se/
> 
> I included commands for
> --get-default-profile-number
> --get-profile-settings
> --create-profile
> --modify-profile

Your patch looks better, I'll strip patch 3 from my series and instead
apply yours.

Best
David

> 
> /Henrik
> 
> 
> Den tis 10 okt. 2023 kl 16:07 skrev David Bauer <mail@david-bauer.net>:
>>
>> Extend uqmi so it can modify connection profiles stored on the modem.
>>
>> This is required in case the operator disallows connections using the
>> dual-stacked PDP type. In case of either the home or visited network
>> disallowing dual-stacked connections, the PDP context establishment
>> fails with the default settings.
>>
>> This can be worked around by configuring the APN and PDP type to profile
>> slot 1 and subsequently enabling the data connection.
>>
>> Signed-off-by: David Bauer <mail@david-bauer.net>
>> ---
>>   commands-wds.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++
>>   commands-wds.h |  9 +++++
>>   2 files changed, 105 insertions(+)
>>
>> diff --git a/commands-wds.c b/commands-wds.c
>> index 3aecefd..b72dcc7 100644
>> --- a/commands-wds.c
>> +++ b/commands-wds.c
>> @@ -30,11 +30,30 @@ static struct qmi_wds_start_network_request wds_sn_req = {
>>   };
>>   static struct qmi_wds_stop_network_request wds_stn_req;
>>
>> +struct uqmi_profile_modify_req {
>> +       int idx;
>> +
>> +       char *apn_name;
>> +       char *username;
>> +       char *password;
>> +
>> +       struct {
>> +               QmiWdsPdpType val;
>> +               bool set;
>> +       } pdp_type;
>> +
>> +       struct {
>> +               QmiWdsAuthentication val;
>> +               bool set;
>> +       } auth;
>> +} prf_mdf_req;
>> +
>>   #define cmd_wds_set_apn_cb no_cb
>>   static enum qmi_cmd_result
>>   cmd_wds_set_apn_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
>>   {
>>          qmi_set_ptr(&wds_sn_req, apn, arg);
>> +       prf_mdf_req.apn_name = arg;
>>          return QMI_CMD_DONE;
>>   }
>>
>> @@ -58,6 +77,9 @@ cmd_wds_set_auth_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qm
>>                          continue;
>>
>>                  qmi_set(&wds_sn_req, authentication_preference, modes[i].auth);
>> +
>> +               prf_mdf_req.auth.set = true;
>> +               prf_mdf_req.auth.val = modes[i].auth;
>>                  return QMI_CMD_DONE;
>>          }
>>
>> @@ -70,6 +92,7 @@ static enum qmi_cmd_result
>>   cmd_wds_set_username_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
>>   {
>>          qmi_set_ptr(&wds_sn_req, username, arg);
>> +       prf_mdf_req.username = arg;
>>          return QMI_CMD_DONE;
>>   }
>>
>> @@ -78,9 +101,37 @@ static enum qmi_cmd_result
>>   cmd_wds_set_password_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
>>   {
>>          qmi_set_ptr(&wds_sn_req, password, arg);
>> +       prf_mdf_req.password = arg;
>>          return QMI_CMD_DONE;
>>   }
>>
>> +#define cmd_wds_set_pdp_type_cb no_cb
>> +static enum qmi_cmd_result
>> +cmd_wds_set_pdp_type_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
>> +{
>> +       static const struct {
>> +               const char *name;
>> +               const QmiWdsPdpType mode;
>> +       } modes[] = {
>> +               { "ipv4", QMI_WDS_PDP_TYPE_IPV4 },
>> +               { "ipv6", QMI_WDS_PDP_TYPE_IPV6 },
>> +               { "ipv4v6", QMI_WDS_PDP_TYPE_IPV4_OR_IPV6 },
>> +       };
>> +       int i;
>> +
>> +       for (i = 0; i < ARRAY_SIZE(modes); i++) {
>> +               if (strcasecmp(modes[i].name, arg) != 0)
>> +                       continue;
>> +
>> +               prf_mdf_req.pdp_type.val = modes[i].mode;
>> +               prf_mdf_req.pdp_type.set = true;
>> +               return QMI_CMD_DONE;
>> +       }
>> +
>> +       uqmi_add_error("Invalid value (valid: ipv4, ipv6, ipv4v6)");
>> +       return QMI_CMD_EXIT;
>> +}
>> +
>>   #define cmd_wds_set_autoconnect_cb no_cb
>>   static enum qmi_cmd_result
>>   cmd_wds_set_autoconnect_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
>> @@ -123,9 +174,54 @@ cmd_wds_set_profile_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct
>>          uint32_t idx = strtoul(arg, NULL, 10);
>>
>>          qmi_set(&wds_sn_req, profile_index_3gpp, idx);
>> +       prf_mdf_req.idx = idx;
>>          return QMI_CMD_DONE;
>>   }
>>
>> +static void
>> +cmd_wds_modify_profile_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
>> +{
>> +       struct qmi_wds_modify_profile_response res;
>> +
>> +       qmi_parse_wds_modify_profile_response(msg, &res);
>> +       if (res.set.extended_error_code)
>> +               blobmsg_add_u32(&status, NULL, res.data.extended_error_code);
>> +}
>> +
>> +static enum qmi_cmd_result
>> +cmd_wds_modify_profile_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
>> +{
>> +       struct qmi_wds_modify_profile_request wds_mdf_prf_req = {
>> +               QMI_INIT_SEQUENCE(profile_identifier,
>> +                       .profile_type = QMI_WDS_PROFILE_TYPE_3GPP,
>> +                       .profile_index = prf_mdf_req.idx,
>> +               ),
>> +       };
>> +
>> +       if (!prf_mdf_req.idx) {
>> +               uqmi_add_error("Profile needs to be specified");
>> +               return QMI_CMD_EXIT;
>> +       }
>> +
>> +       if (prf_mdf_req.apn_name)
>> +               qmi_set_ptr(&wds_mdf_prf_req, apn_name, prf_mdf_req.apn_name);
>> +
>> +       if (prf_mdf_req.username)
>> +               qmi_set_ptr(&wds_mdf_prf_req, username, prf_mdf_req.username);
>> +
>> +       if (prf_mdf_req.password)
>> +               qmi_set_ptr(&wds_mdf_prf_req, password, prf_mdf_req.password);
>> +
>> +       if (prf_mdf_req.pdp_type.set)
>> +               qmi_set(&wds_mdf_prf_req, pdp_type, prf_mdf_req.pdp_type.val);
>> +
>> +       if (prf_mdf_req.auth.set)
>> +               qmi_set(&wds_mdf_prf_req, authentication, prf_mdf_req.auth.val);
>> +
>> +       qmi_set_wds_modify_profile_request(msg, &wds_mdf_prf_req);
>> +       return QMI_CMD_REQUEST;
>> +}
>> +
>>   static void
>>   cmd_wds_start_network_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
>>   {
>> diff --git a/commands-wds.h b/commands-wds.h
>> index 5aa7ea8..e9c2638 100644
>> --- a/commands-wds.h
>> +++ b/commands-wds.h
>> @@ -29,6 +29,8 @@
>>          __uqmi_command(wds_set_autoconnect, autoconnect, no, CMD_TYPE_OPTION), \
>>          __uqmi_command(wds_set_profile, profile, required, CMD_TYPE_OPTION), \
>>          __uqmi_command(wds_stop_network, stop-network, required, QMI_SERVICE_WDS), \
>> +       __uqmi_command(wds_modify_profile, modify-profile, no, QMI_SERVICE_WDS), \
>> +       __uqmi_command(wds_set_pdp_type, pdp-type, required, CMD_TYPE_OPTION), \
>>          __uqmi_command(wds_get_packet_service_status, get-data-status, no, QMI_SERVICE_WDS), \
>>          __uqmi_command(wds_set_ip_family, set-ip-family, required, QMI_SERVICE_WDS), \
>>          __uqmi_command(wds_set_autoconnect_settings, set-autoconnect, required, QMI_SERVICE_WDS), \
>> @@ -47,6 +49,13 @@
>>                  "    --profile <index>:              Use connection profile\n" \
>>                  "  --stop-network <pdh>:             Stop network connection (use with option below)\n" \
>>                  "    --autoconnect:                  Disable automatic connect/reconnect\n" \
>> +               "  --modify-profile:                 Modify a profile (use with options below)\n" \
>> +               "    --profile <index>:              Profile to modify\n" \
>> +               "    --apn <apn>:                    Use APN\n" \
>> +               "    --auth-type pap|chap|both|none: Use network authentication type\n" \
>> +               "    --username <name>:              Use network username\n" \
>> +               "    --password <password>:          Use network password\n" \
>> +               "    --pdp-type <family>:            Use PDP type (ipv4, ipv6, ipv4v6)\n" \
>>                  "  --get-data-status:                Get current data access status\n" \
>>                  "  --set-ip-family <val>:            Set ip-family (ipv4, ipv6, unspecified)\n" \
>>                  "  --set-autoconnect <val>:          Set automatic connect/reconnect (disabled, enabled, paused)\n" \
>> --
>> 2.42.0
>>
>>
>> _______________________________________________
>> openwrt-devel mailing list
>> openwrt-devel@lists.openwrt.org
>> https://lists.openwrt.org/mailman/listinfo/openwrt-devel
> 
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel@lists.openwrt.org
> https://lists.openwrt.org/mailman/listinfo/openwrt-devel
diff mbox series

Patch

diff --git a/commands-wds.c b/commands-wds.c
index 3aecefd..b72dcc7 100644
--- a/commands-wds.c
+++ b/commands-wds.c
@@ -30,11 +30,30 @@  static struct qmi_wds_start_network_request wds_sn_req = {
 };
 static struct qmi_wds_stop_network_request wds_stn_req;
 
+struct uqmi_profile_modify_req {
+	int idx;
+
+	char *apn_name;
+	char *username;
+	char *password;
+
+	struct {
+		QmiWdsPdpType val;
+		bool set;
+	} pdp_type;
+
+	struct {
+		QmiWdsAuthentication val;
+		bool set;
+	} auth;
+} prf_mdf_req;
+
 #define cmd_wds_set_apn_cb no_cb
 static enum qmi_cmd_result
 cmd_wds_set_apn_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
 {
 	qmi_set_ptr(&wds_sn_req, apn, arg);
+	prf_mdf_req.apn_name = arg;
 	return QMI_CMD_DONE;
 }
 
@@ -58,6 +77,9 @@  cmd_wds_set_auth_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qm
 			continue;
 
 		qmi_set(&wds_sn_req, authentication_preference, modes[i].auth);
+
+		prf_mdf_req.auth.set = true;
+		prf_mdf_req.auth.val = modes[i].auth;
 		return QMI_CMD_DONE;
 	}
 
@@ -70,6 +92,7 @@  static enum qmi_cmd_result
 cmd_wds_set_username_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
 {
 	qmi_set_ptr(&wds_sn_req, username, arg);
+	prf_mdf_req.username = arg;
 	return QMI_CMD_DONE;
 }
 
@@ -78,9 +101,37 @@  static enum qmi_cmd_result
 cmd_wds_set_password_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
 {
 	qmi_set_ptr(&wds_sn_req, password, arg);
+	prf_mdf_req.password = arg;
 	return QMI_CMD_DONE;
 }
 
+#define cmd_wds_set_pdp_type_cb no_cb
+static enum qmi_cmd_result
+cmd_wds_set_pdp_type_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
+{
+	static const struct {
+		const char *name;
+		const QmiWdsPdpType mode;
+	} modes[] = {
+		{ "ipv4", QMI_WDS_PDP_TYPE_IPV4 },
+		{ "ipv6", QMI_WDS_PDP_TYPE_IPV6 },
+		{ "ipv4v6", QMI_WDS_PDP_TYPE_IPV4_OR_IPV6 },
+	};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(modes); i++) {
+		if (strcasecmp(modes[i].name, arg) != 0)
+			continue;
+
+		prf_mdf_req.pdp_type.val = modes[i].mode;
+		prf_mdf_req.pdp_type.set = true;
+		return QMI_CMD_DONE;
+	}
+
+	uqmi_add_error("Invalid value (valid: ipv4, ipv6, ipv4v6)");
+	return QMI_CMD_EXIT;
+}
+
 #define cmd_wds_set_autoconnect_cb no_cb
 static enum qmi_cmd_result
 cmd_wds_set_autoconnect_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
@@ -123,9 +174,54 @@  cmd_wds_set_profile_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct
 	uint32_t idx = strtoul(arg, NULL, 10);
 
 	qmi_set(&wds_sn_req, profile_index_3gpp, idx);
+	prf_mdf_req.idx = idx;
 	return QMI_CMD_DONE;
 }
 
+static void
+cmd_wds_modify_profile_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
+{
+	struct qmi_wds_modify_profile_response res;
+
+	qmi_parse_wds_modify_profile_response(msg, &res);
+	if (res.set.extended_error_code)
+		blobmsg_add_u32(&status, NULL, res.data.extended_error_code);
+}
+
+static enum qmi_cmd_result
+cmd_wds_modify_profile_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
+{
+	struct qmi_wds_modify_profile_request wds_mdf_prf_req = {
+		QMI_INIT_SEQUENCE(profile_identifier,
+			.profile_type = QMI_WDS_PROFILE_TYPE_3GPP,
+			.profile_index = prf_mdf_req.idx,
+		),
+	};
+
+	if (!prf_mdf_req.idx) {
+		uqmi_add_error("Profile needs to be specified");
+		return QMI_CMD_EXIT;
+	}
+
+	if (prf_mdf_req.apn_name)
+		qmi_set_ptr(&wds_mdf_prf_req, apn_name, prf_mdf_req.apn_name);
+
+	if (prf_mdf_req.username)
+		qmi_set_ptr(&wds_mdf_prf_req, username, prf_mdf_req.username);
+
+	if (prf_mdf_req.password)
+		qmi_set_ptr(&wds_mdf_prf_req, password, prf_mdf_req.password);
+	
+	if (prf_mdf_req.pdp_type.set)
+		qmi_set(&wds_mdf_prf_req, pdp_type, prf_mdf_req.pdp_type.val);
+
+	if (prf_mdf_req.auth.set)
+		qmi_set(&wds_mdf_prf_req, authentication, prf_mdf_req.auth.val);
+
+	qmi_set_wds_modify_profile_request(msg, &wds_mdf_prf_req);
+	return QMI_CMD_REQUEST;
+}
+
 static void
 cmd_wds_start_network_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
 {
diff --git a/commands-wds.h b/commands-wds.h
index 5aa7ea8..e9c2638 100644
--- a/commands-wds.h
+++ b/commands-wds.h
@@ -29,6 +29,8 @@ 
 	__uqmi_command(wds_set_autoconnect, autoconnect, no, CMD_TYPE_OPTION), \
 	__uqmi_command(wds_set_profile, profile, required, CMD_TYPE_OPTION), \
 	__uqmi_command(wds_stop_network, stop-network, required, QMI_SERVICE_WDS), \
+	__uqmi_command(wds_modify_profile, modify-profile, no, QMI_SERVICE_WDS), \
+	__uqmi_command(wds_set_pdp_type, pdp-type, required, CMD_TYPE_OPTION), \
 	__uqmi_command(wds_get_packet_service_status, get-data-status, no, QMI_SERVICE_WDS), \
 	__uqmi_command(wds_set_ip_family, set-ip-family, required, QMI_SERVICE_WDS), \
 	__uqmi_command(wds_set_autoconnect_settings, set-autoconnect, required, QMI_SERVICE_WDS), \
@@ -47,6 +49,13 @@ 
 		"    --profile <index>:              Use connection profile\n" \
 		"  --stop-network <pdh>:             Stop network connection (use with option below)\n" \
 		"    --autoconnect:                  Disable automatic connect/reconnect\n" \
+		"  --modify-profile:                 Modify a profile (use with options below)\n" \
+		"    --profile <index>:              Profile to modify\n" \
+		"    --apn <apn>:                    Use APN\n" \
+		"    --auth-type pap|chap|both|none: Use network authentication type\n" \
+		"    --username <name>:              Use network username\n" \
+		"    --password <password>:          Use network password\n" \
+		"    --pdp-type <family>:            Use PDP type (ipv4, ipv6, ipv4v6)\n" \
 		"  --get-data-status:                Get current data access status\n" \
 		"  --set-ip-family <val>:            Set ip-family (ipv4, ipv6, unspecified)\n" \
 		"  --set-autoconnect <val>:          Set automatic connect/reconnect (disabled, enabled, paused)\n" \