* [PATCH v2 01/11] gobi: Limit number of premultiplexed contexts to 4
@ 2024-07-11 16:49 Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 02/11] gobi: Request dedicated WDS services for contexts Denis Kenzior
` (10 more replies)
0 siblings, 11 replies; 12+ messages in thread
From: Denis Kenzior @ 2024-07-11 16:49 UTC (permalink / raw)
To: ofono; +Cc: Denis Kenzior
4 was chosen somewhat arbitrarily, but it is the maximum that the
qmi_wwan_q driver can support out of the box. The only limit is the
number of clients under QMI. Two WDS clients are typically required for
each active context, one for IPv4 and one for IPv6. The total number of
clients cannot exceed 255 (uint8).
---
plugins/gobi.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/plugins/gobi.c b/plugins/gobi.c
index 88e4c7fc4887..b6df849de47e 100644
--- a/plugins/gobi.c
+++ b/plugins/gobi.c
@@ -55,6 +55,8 @@
#define GOBI_VOICE (1 << 6)
#define GOBI_WDA (1 << 7)
+#define MAX_CONTEXTS 4
+
struct service_request {
struct qmi_service **member;
uint32_t service_type;
@@ -75,6 +77,7 @@ struct gobi_data {
int num_service_requests;
unsigned long features;
unsigned int discover_attempts;
+ uint8_t n_premux;
uint8_t oper_mode;
int main_net_ifindex;
char main_net_name[IFNAMSIZ];
@@ -124,6 +127,7 @@ static int gobi_probe(struct ofono_modem *modem)
const char *ifname;
int ifindex;
const char *bus;
+ int n_premux;
DBG("%p", modem);
@@ -132,10 +136,11 @@ static int gobi_probe(struct ofono_modem *modem)
ifname = ofono_modem_get_string(modem, "NetworkInterface");
ifindex = ofono_modem_get_integer(modem, "NetworkInterfaceIndex");
bus = ofono_modem_get_string(modem, "Bus");
+ n_premux = ofono_modem_get_integer(modem, "NumPremuxInterfaces");
DBG("net: %s[%s](%d) %s", ifname, if_driver, ifindex, bus);
- if (!if_driver || !ifname || !ifindex || !bus)
+ if (!if_driver || !ifname || !ifindex || !bus || n_premux < 0)
return -EPROTO;
data = l_new(struct gobi_data, 1);
@@ -145,6 +150,13 @@ static int gobi_probe(struct ofono_modem *modem)
else if (!strcmp(if_driver, "qmi_wwan"))
data->using_qmi_wwan = true;
+ if (n_premux > MAX_CONTEXTS) {
+ l_warn("NumPremuxInterfaces > %d, limiting to %d",
+ MAX_CONTEXTS, MAX_CONTEXTS);
+ n_premux = MAX_CONTEXTS;
+ }
+
+ data->n_premux = n_premux;
data->main_net_ifindex =
ofono_modem_get_integer(modem, "NetworkInterfaceIndex");
l_strlcpy(data->main_net_name,
@@ -753,7 +765,6 @@ static void gobi_pre_sim(struct ofono_modem *modem)
static void gobi_setup_gprs(struct ofono_modem *modem)
{
struct gobi_data *data = ofono_modem_get_data(modem);
- int n_premux = ofono_modem_get_integer(modem, "NumPremuxInterfaces");
struct ofono_gprs *gprs;
struct ofono_gprs_context *gc;
const char *interface;
@@ -770,7 +781,7 @@ static void gobi_setup_gprs(struct ofono_modem *modem)
}
/* Simple case of 802.3 interface, no QMAP */
- if (n_premux == 0) {
+ if (data->n_premux == 0) {
interface = ofono_modem_get_string(modem, "NetworkInterface");
gc = ofono_gprs_context_create(modem, 0, "qmimodem", -1,
@@ -793,7 +804,7 @@ static void gobi_setup_gprs(struct ofono_modem *modem)
ofono_modem_get_integer(modem, "MaxAggregationSize");
DBG("max_aggregation_size: %u", data->max_aggregation_size);
- for (i = 0; i < n_premux; i++) {
+ for (i = 0; i < data->n_premux; i++) {
int mux_id;
sprintf(buf, "PremuxInterface%dMuxId", i + 1);
--
2.45.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 02/11] gobi: Request dedicated WDS services for contexts
2024-07-11 16:49 [PATCH v2 01/11] gobi: Limit number of premultiplexed contexts to 4 Denis Kenzior
@ 2024-07-11 16:49 ` Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 03/11] qmi: Enable _auto_ use for some classes Denis Kenzior
` (9 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Denis Kenzior @ 2024-07-11 16:49 UTC (permalink / raw)
To: ofono; +Cc: Denis Kenzior
Each context the modem supports (up to MAX_CONTEXTS) will require two
dedicated WDS services. One will manage the IPv4 configuration, the
other will manage IPv6 configuration.
---
plugins/gobi.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/plugins/gobi.c b/plugins/gobi.c
index b6df849de47e..76e1e133860d 100644
--- a/plugins/gobi.c
+++ b/plugins/gobi.c
@@ -72,7 +72,11 @@ struct gobi_data {
struct qmi_service *voice;
struct qmi_service *pds;
struct qmi_service *uim;
- struct service_request service_requests[16];
+ struct {
+ struct qmi_service *wds_ipv4;
+ struct qmi_service *wds_ipv6;
+ } context_services[MAX_CONTEXTS];
+ struct service_request service_requests[8 + MAX_CONTEXTS * 2];
int cur_service_request;
int num_service_requests;
unsigned long features;
@@ -170,6 +174,8 @@ static int gobi_probe(struct ofono_modem *modem)
static void cleanup_services(struct gobi_data *data)
{
+ int i;
+
qmi_service_free(data->dms);
data->dms = NULL;
@@ -193,6 +199,13 @@ static void cleanup_services(struct gobi_data *data)
qmi_service_free(data->uim);
data->uim = NULL;
+
+ for (i = 0; i < MAX_CONTEXTS; i++) {
+ qmi_service_free(data->context_services[i].wds_ipv4);
+ qmi_service_free(data->context_services[i].wds_ipv6);
+ }
+
+ memset(&data->context_services, 0, sizeof(data->context_services));
}
static void gobi_remove(struct ofono_modem *modem)
@@ -489,6 +502,7 @@ static void discover_cb(void *user_data)
struct gobi_data *data = ofono_modem_get_data(modem);
uint16_t major;
uint16_t minor;
+ int i;
DBG("");
@@ -538,6 +552,13 @@ static void discover_cb(void *user_data)
if (data->features & GOBI_UIM)
add_service_request(data, &data->uim, QMI_SERVICE_UIM);
+ for (i = 0; i < (data->n_premux ? data->n_premux : 1); i++) {
+ add_service_request(data, &data->context_services[i].wds_ipv4,
+ QMI_SERVICE_WDS);
+ add_service_request(data, &data->context_services[i].wds_ipv6,
+ QMI_SERVICE_WDS);
+ }
+
if (qmi_qmux_device_create_client(data->device, QMI_SERVICE_DMS,
request_service_cb, modem, NULL) > 0)
return;
--
2.45.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 03/11] qmi: Enable _auto_ use for some classes
2024-07-11 16:49 [PATCH v2 01/11] gobi: Limit number of premultiplexed contexts to 4 Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 02/11] gobi: Request dedicated WDS services for contexts Denis Kenzior
@ 2024-07-11 16:49 ` Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 04/11] qmi: gprs-context: Declare qmi_service objects using _auto_ Denis Kenzior
` (8 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Denis Kenzior @ 2024-07-11 16:49 UTC (permalink / raw)
To: ofono; +Cc: Denis Kenzior
This enables ell _auto_ keyword use with qmi_service_free and
qmi_param_free.
---
drivers/qmimodem/qmi.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/qmimodem/qmi.h b/drivers/qmimodem/qmi.h
index 0e48313ebb64..69698ee049c6 100644
--- a/drivers/qmimodem/qmi.h
+++ b/drivers/qmimodem/qmi.h
@@ -5,6 +5,8 @@
* SPDX-License-Identifier: GPL-2.0-only
*/
+#include <ell/cleanup.h>
+
#include <stdbool.h>
#include <stdint.h>
@@ -110,6 +112,8 @@ struct qmi_param;
struct qmi_param *qmi_param_new(void);
void qmi_param_free(struct qmi_param *param);
+DEFINE_CLEANUP_FUNC(qmi_param_free)
+
bool qmi_param_append(struct qmi_param *param, uint8_t type,
uint16_t length, const void *data);
bool qmi_param_append_uint8(struct qmi_param *param, uint8_t type,
@@ -146,6 +150,8 @@ int qmi_error_to_ofono_cme(int qmi_error);
struct qmi_service *qmi_service_clone(struct qmi_service *service);
void qmi_service_free(struct qmi_service *service);
+DEFINE_CLEANUP_FUNC(qmi_service_free)
+
const char *qmi_service_get_identifier(struct qmi_service *service);
bool qmi_service_get_version(struct qmi_service *service, uint8_t *out_version);
--
2.45.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 04/11] qmi: gprs-context: Declare qmi_service objects using _auto_
2024-07-11 16:49 [PATCH v2 01/11] gobi: Limit number of premultiplexed contexts to 4 Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 02/11] gobi: Request dedicated WDS services for contexts Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 03/11] qmi: Enable _auto_ use for some classes Denis Kenzior
@ 2024-07-11 16:49 ` Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 05/11] qmi: Pass two dedicated WDS services to gprs-context Denis Kenzior
` (7 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Denis Kenzior @ 2024-07-11 16:49 UTC (permalink / raw)
To: ofono; +Cc: Denis Kenzior
This simplifies the error paths slightly.
---
drivers/qmimodem/gprs-context.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/qmimodem/gprs-context.c b/drivers/qmimodem/gprs-context.c
index 3c18476142ea..7d13889bf603 100644
--- a/drivers/qmimodem/gprs-context.c
+++ b/drivers/qmimodem/gprs-context.c
@@ -554,7 +554,8 @@ static int qmi_gprs_context_probev(struct ofono_gprs_context *gc,
unsigned int vendor, va_list args)
{
int mux_id = va_arg(args, int);
- struct qmi_service *wds = va_arg(args, struct qmi_service *);
+ _auto_(qmi_service_free) struct qmi_service *wds =
+ va_arg(args, struct qmi_service *);
struct gprs_context_data *data;
DBG("");
@@ -562,14 +563,12 @@ static int qmi_gprs_context_probev(struct ofono_gprs_context *gc,
if (mux_id != -1) {
int r = qmi_gprs_context_bind_mux(gc, wds, mux_id);
- if (r < 0) {
- qmi_service_free(wds);
+ if (r < 0)
return r;
- }
}
data = l_new(struct gprs_context_data, 1);
- data->wds = wds;
+ data->wds = l_steal_ptr(wds);
data->mux_id = mux_id;
qmi_service_register(data->wds, QMI_WDS_PACKET_SERVICE_STATUS,
--
2.45.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 05/11] qmi: Pass two dedicated WDS services to gprs-context
2024-07-11 16:49 [PATCH v2 01/11] gobi: Limit number of premultiplexed contexts to 4 Denis Kenzior
` (2 preceding siblings ...)
2024-07-11 16:49 ` [PATCH v2 04/11] qmi: gprs-context: Declare qmi_service objects using _auto_ Denis Kenzior
@ 2024-07-11 16:49 ` Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 06/11] qmi: gprs-context: Remove parsing of unused TLVs Denis Kenzior
` (6 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Denis Kenzior @ 2024-07-11 16:49 UTC (permalink / raw)
To: ofono; +Cc: Denis Kenzior
gprs-context driver will not take two qmi_service objects, each with a
dedicated WDS service. This will allow gprs-context to support dual
stack (ipv4 + ipv6) contexts (in future commits). For now, the behavior
is left unchanged with the second qmi_service being destroyed.
---
drivers/qmimodem/gprs-context.c | 8 +++++---
plugins/gobi.c | 11 +++++++++--
plugins/qrtrqmi.c | 7 +++++--
3 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/drivers/qmimodem/gprs-context.c b/drivers/qmimodem/gprs-context.c
index 7d13889bf603..5582a8052c0b 100644
--- a/drivers/qmimodem/gprs-context.c
+++ b/drivers/qmimodem/gprs-context.c
@@ -554,21 +554,23 @@ static int qmi_gprs_context_probev(struct ofono_gprs_context *gc,
unsigned int vendor, va_list args)
{
int mux_id = va_arg(args, int);
- _auto_(qmi_service_free) struct qmi_service *wds =
+ _auto_(qmi_service_free) struct qmi_service *ipv4 =
+ va_arg(args, struct qmi_service *);
+ _auto_(qmi_service_free) struct qmi_service *ipv6 =
va_arg(args, struct qmi_service *);
struct gprs_context_data *data;
DBG("");
if (mux_id != -1) {
- int r = qmi_gprs_context_bind_mux(gc, wds, mux_id);
+ int r = qmi_gprs_context_bind_mux(gc, ipv4, mux_id);
if (r < 0)
return r;
}
data = l_new(struct gprs_context_data, 1);
- data->wds = l_steal_ptr(wds);
+ data->wds = l_steal_ptr(ipv4);
data->mux_id = mux_id;
qmi_service_register(data->wds, QMI_WDS_PACKET_SERVICE_STATUS,
diff --git a/plugins/gobi.c b/plugins/gobi.c
index 76e1e133860d..cb20824cc424 100644
--- a/plugins/gobi.c
+++ b/plugins/gobi.c
@@ -803,10 +803,14 @@ static void gobi_setup_gprs(struct ofono_modem *modem)
/* Simple case of 802.3 interface, no QMAP */
if (data->n_premux == 0) {
+ struct qmi_service *ipv4 = data->context_services[0].wds_ipv4;
+ struct qmi_service *ipv6 = data->context_services[0].wds_ipv6;
+
interface = ofono_modem_get_string(modem, "NetworkInterface");
gc = ofono_gprs_context_create(modem, 0, "qmimodem", -1,
- qmi_service_clone(data->wds));
+ qmi_service_clone(ipv4),
+ qmi_service_clone(ipv6));
if (!gc) {
ofono_warn("Unable to create gprs-context for: %s",
ofono_modem_get_path(modem));
@@ -826,13 +830,16 @@ static void gobi_setup_gprs(struct ofono_modem *modem)
DBG("max_aggregation_size: %u", data->max_aggregation_size);
for (i = 0; i < data->n_premux; i++) {
+ struct qmi_service *ipv4 = data->context_services[i].wds_ipv4;
+ struct qmi_service *ipv6 = data->context_services[i].wds_ipv6;
int mux_id;
sprintf(buf, "PremuxInterface%dMuxId", i + 1);
mux_id = ofono_modem_get_integer(modem, buf);
gc = ofono_gprs_context_create(modem, 0, "qmimodem", mux_id,
- qmi_service_clone(data->wds));
+ qmi_service_clone(ipv4),
+ qmi_service_clone(ipv6));
if (!gc) {
ofono_warn("gprs-context creation failed for [%d] %s",
diff --git a/plugins/qrtrqmi.c b/plugins/qrtrqmi.c
index b64ab355a2e8..21103371046a 100644
--- a/plugins/qrtrqmi.c
+++ b/plugins/qrtrqmi.c
@@ -324,10 +324,13 @@ static int setup_gprs_context(uint8_t mux_id, const char *interface,
struct ofono_modem *modem = ofono_gprs_get_modem(gprs);
struct qrtrqmi_data *data = ofono_modem_get_data(modem);
struct qmi_qrtr_node *node = data->node;
+ struct qmi_service *ipv4 = qmi_qrtr_node_get_dedicated_service(node,
+ QMI_SERVICE_WDS);
+ struct qmi_service *ipv6 = qmi_qrtr_node_get_dedicated_service(node,
+ QMI_SERVICE_WDS);
struct ofono_gprs_context *gc;
- gc = ofono_gprs_context_create(modem, 0, "qmimodem", mux_id,
- qmi_qrtr_node_get_service(node, QMI_SERVICE_WDS));
+ gc = ofono_gprs_context_create(modem, 0, "qmimodem", mux_id, ipv4, ipv6);
if (!gc) {
ofono_warn("Unable to create gprs-context for: %s, %s[%u]",
ofono_modem_get_path(modem), interface, mux_id);
--
2.45.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 06/11] qmi: gprs-context: Remove parsing of unused TLVs
2024-07-11 16:49 [PATCH v2 01/11] gobi: Limit number of premultiplexed contexts to 4 Denis Kenzior
` (3 preceding siblings ...)
2024-07-11 16:49 ` [PATCH v2 05/11] qmi: Pass two dedicated WDS services to gprs-context Denis Kenzior
@ 2024-07-11 16:49 ` Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 07/11] qmi: gprs-context: Treat IP family TLV as mandatory Denis Kenzior
` (5 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Denis Kenzior @ 2024-07-11 16:49 UTC (permalink / raw)
To: ofono; +Cc: Denis Kenzior
The information from these TLVs is currently unused and only printed to
debug output. Same can be accomplished using an external sniffer.
Remove this code until the information in these TLVs is needed for
something.
---
drivers/qmimodem/gprs-context.c | 14 +-------------
1 file changed, 1 insertion(+), 13 deletions(-)
diff --git a/drivers/qmimodem/gprs-context.c b/drivers/qmimodem/gprs-context.c
index 5582a8052c0b..f29f10720710 100644
--- a/drivers/qmimodem/gprs-context.c
+++ b/drivers/qmimodem/gprs-context.c
@@ -173,29 +173,17 @@ static void get_settings_ipv4(struct ofono_gprs_context *gc,
static void get_settings_cb(struct qmi_result *result, void *user_data)
{
- static const uint8_t RESULT_PDP_TYPE = 0x11; /* uint8 */
- static const uint8_t RESULT_APN = 0x14; /* string */
static const uint8_t RESULT_IP_FAMILY = 0x2b; /* uint8 */
struct cb_data *cbd = user_data;
ofono_gprs_context_cb_t cb = cbd->cb;
struct ofono_gprs_context *gc = cbd->user;
- uint8_t pdp_type, ip_family;
- char *apn;
+ uint8_t ip_family;
DBG("");
if (qmi_result_set_error(result, NULL))
goto done;
- apn = qmi_result_get_string(result, RESULT_APN);
- if (apn) {
- DBG("APN: %s", apn);
- l_free(apn);
- }
-
- if (qmi_result_get_uint8(result, RESULT_PDP_TYPE, &pdp_type))
- DBG("PDP type %d", pdp_type);
-
if (!qmi_result_get_uint8(result, RESULT_IP_FAMILY, &ip_family)) {
ofono_error("No IP family in results");
goto done;
--
2.45.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 07/11] qmi: gprs-context: Treat IP family TLV as mandatory
2024-07-11 16:49 [PATCH v2 01/11] gobi: Limit number of premultiplexed contexts to 4 Denis Kenzior
` (4 preceding siblings ...)
2024-07-11 16:49 ` [PATCH v2 06/11] qmi: gprs-context: Remove parsing of unused TLVs Denis Kenzior
@ 2024-07-11 16:49 ` Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 08/11] qmi: gprs-context: Set up WDS service for IPv6 Denis Kenzior
` (4 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Denis Kenzior @ 2024-07-11 16:49 UTC (permalink / raw)
To: ofono; +Cc: Denis Kenzior
Also, while here, coalesce two debugging statements into one.
---
drivers/qmimodem/gprs-context.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/qmimodem/gprs-context.c b/drivers/qmimodem/gprs-context.c
index f29f10720710..203a320a42af 100644
--- a/drivers/qmimodem/gprs-context.c
+++ b/drivers/qmimodem/gprs-context.c
@@ -46,10 +46,10 @@ static void pkt_status_notify(struct qmi_result *result, void *user_data)
if (!status)
return;
- DBG("conn status %d", status->status);
+ if (!qmi_result_get_uint8(result, RESULT_IP_FAMILY, &ip_family))
+ return;
- if (qmi_result_get_uint8(result, RESULT_IP_FAMILY, &ip_family))
- DBG("ip family %d", ip_family);
+ DBG("conn status %d ip family %d", status->status, ip_family);
switch (status->status) {
case QMI_WDS_CONNECTION_STATUS_DISCONNECTED:
--
2.45.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 08/11] qmi: gprs-context: Set up WDS service for IPv6
2024-07-11 16:49 [PATCH v2 01/11] gobi: Limit number of premultiplexed contexts to 4 Denis Kenzior
` (5 preceding siblings ...)
2024-07-11 16:49 ` [PATCH v2 07/11] qmi: gprs-context: Treat IP family TLV as mandatory Denis Kenzior
@ 2024-07-11 16:49 ` Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 09/11] qmi: gprs-context: refactor detach_shutdown path Denis Kenzior
` (3 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Denis Kenzior @ 2024-07-11 16:49 UTC (permalink / raw)
To: ofono; +Cc: Denis Kenzior
Track and take ownership of the passed in WDS service meant for IPv6
connectivity. The WDS service should be bound to a particular
endpoint / mux_id and register to the same indication types as the
other WDS service being utilized.
Additionally, WDS services are created with IPv4 as the default family
preference. To support dual-stack bearers, the WDS service managing
IPv6 requires 'Set IP Family Preference' command to be issued with the
IPv6 family preference set.
---
drivers/qmimodem/gprs-context.c | 51 ++++++++++++++++++++++++++++++++-
1 file changed, 50 insertions(+), 1 deletion(-)
diff --git a/drivers/qmimodem/gprs-context.c b/drivers/qmimodem/gprs-context.c
index 203a320a42af..456f46ead6d5 100644
--- a/drivers/qmimodem/gprs-context.c
+++ b/drivers/qmimodem/gprs-context.c
@@ -22,6 +22,7 @@
struct gprs_context_data {
struct qmi_service *wds;
+ struct qmi_service *ipv6;
unsigned int active_context;
uint32_t pkt_handle;
uint8_t mux_id;
@@ -454,6 +455,37 @@ static void qmi_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
qmi_deactivate_primary(gc, cid, NULL, NULL);
}
+static void set_ip_family_preference_cb(struct qmi_result *result,
+ void *user_data)
+{
+ struct ofono_gprs_context *gc = user_data;
+ uint16_t error;
+
+ if (!qmi_result_set_error(result, &error))
+ error = 0;
+
+ DBG("%u", error);
+
+ if (error)
+ ofono_gprs_context_remove(gc);
+}
+
+static int set_ip_family_preference(struct ofono_gprs_context *gc,
+ struct qmi_service *wds,
+ uint8_t family)
+{
+ static const uint8_t PARAM_IP_FAMILY_PREFERENCE = 0x01;
+ struct qmi_param *param =
+ qmi_param_new_uint8(PARAM_IP_FAMILY_PREFERENCE, family);
+
+ if (qmi_service_send(wds, QMI_WDS_SET_IP_FAMILY, param,
+ set_ip_family_preference_cb, gc, NULL) > 0)
+ return 0;
+
+ qmi_param_free(param);
+ return -EIO;
+}
+
static void bind_mux_data_port_cb(struct qmi_result *result, void *user_data)
{
struct ofono_gprs_context *gc = user_data;
@@ -547,22 +579,38 @@ static int qmi_gprs_context_probev(struct ofono_gprs_context *gc,
_auto_(qmi_service_free) struct qmi_service *ipv6 =
va_arg(args, struct qmi_service *);
struct gprs_context_data *data;
+ int r;
DBG("");
if (mux_id != -1) {
- int r = qmi_gprs_context_bind_mux(gc, ipv4, mux_id);
+ r = qmi_gprs_context_bind_mux(gc, ipv4, mux_id);
+ if (r < 0)
+ return r;
+ r = qmi_gprs_context_bind_mux(gc, ipv6, mux_id);
if (r < 0)
return r;
}
+ /*
+ * Default family preference for new WDS services is IPv4. For the
+ * service used for IPv6 contexts, issue a SET_IP_FAMILY_PREFERENCE
+ * command
+ */
+ r = set_ip_family_preference(gc, ipv6, QMI_WDS_IP_FAMILY_IPV6);
+ if (r < 0)
+ return r;
+
data = l_new(struct gprs_context_data, 1);
data->wds = l_steal_ptr(ipv4);
+ data->ipv6 = l_steal_ptr(ipv6);
data->mux_id = mux_id;
qmi_service_register(data->wds, QMI_WDS_PACKET_SERVICE_STATUS,
pkt_status_notify, gc, NULL);
+ qmi_service_register(data->ipv6, QMI_WDS_PACKET_SERVICE_STATUS,
+ pkt_status_notify, gc, NULL);
ofono_gprs_context_set_data(gc, data);
@@ -578,6 +626,7 @@ static void qmi_gprs_context_remove(struct ofono_gprs_context *gc)
ofono_gprs_context_set_data(gc, NULL);
qmi_service_free(data->wds);
+ qmi_service_free(data->ipv6);
l_free(data);
}
--
2.45.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 09/11] qmi: gprs-context: refactor detach_shutdown path
2024-07-11 16:49 [PATCH v2 01/11] gobi: Limit number of premultiplexed contexts to 4 Denis Kenzior
` (6 preceding siblings ...)
2024-07-11 16:49 ` [PATCH v2 08/11] qmi: gprs-context: Set up WDS service for IPv6 Denis Kenzior
@ 2024-07-11 16:49 ` Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 10/11] qmi: gprs-context: refactor deactivate_primary Denis Kenzior
` (2 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Denis Kenzior @ 2024-07-11 16:49 UTC (permalink / raw)
To: ofono; +Cc: Denis Kenzior
Since there will now be up to two WDS clients used (Dual stack
contexts), the detach_shutdown path needs to send a Stop Network
command on any client with an ongoing packet connection.
Implement this by keeping track of WDS clients used for ipv4 and ipv6
families respectively and their respective packet handles. Rename
member 'wds' to 'ipv4', it is used as-is for currently existing code
paths. Similarly, rename pkt_handle to packet_handle_ipv4.
Note that the dedicated WDS client associated with the 'ipv6'
qmi_service handle is effectively not used as of this commit. This is
because packet_handle_ipv6 is never set. IPv6-only context activations
will continue using 'ipv4' and 'packet_handle_ipv4'. This will be
addressed in follow-on commits.
---
drivers/qmimodem/gprs-context.c | 114 ++++++++++++++++++++++++++------
1 file changed, 95 insertions(+), 19 deletions(-)
diff --git a/drivers/qmimodem/gprs-context.c b/drivers/qmimodem/gprs-context.c
index 456f46ead6d5..f4846f0299e7 100644
--- a/drivers/qmimodem/gprs-context.c
+++ b/drivers/qmimodem/gprs-context.c
@@ -21,13 +21,26 @@
#include "util.h"
struct gprs_context_data {
- struct qmi_service *wds;
+ struct qmi_service *ipv4;
struct qmi_service *ipv6;
unsigned int active_context;
- uint32_t pkt_handle;
+ uint32_t packet_handle_ipv4;
+ uint32_t packet_handle_ipv6;
uint8_t mux_id;
};
+static void check_all_deactivated(struct ofono_gprs_context *gc)
+{
+ struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
+
+ if (data->packet_handle_ipv4 || data->packet_handle_ipv6)
+ return;
+
+ /* All families have been disconnected */
+ ofono_gprs_context_deactivated(gc, data->active_context);
+ data->active_context = 0;
+}
+
static void pkt_status_notify(struct qmi_result *result, void *user_data)
{
static const uint8_t RESULT_CONN_STATUS = 0x01;
@@ -54,12 +67,11 @@ static void pkt_status_notify(struct qmi_result *result, void *user_data)
switch (status->status) {
case QMI_WDS_CONNECTION_STATUS_DISCONNECTED:
- if (data->pkt_handle) {
- /* The context has been disconnected by the network */
- ofono_gprs_context_deactivated(gc, data->active_context);
- data->pkt_handle = 0;
- data->active_context = 0;
+ if (data->packet_handle_ipv4) {
+ data->packet_handle_ipv4 = 0;
+ check_all_deactivated(gc);
}
+
break;
}
}
@@ -227,7 +239,7 @@ static void start_net_cb(struct qmi_result *result, void *user_data)
DBG("packet handle %d", handle);
- data->pkt_handle = handle;
+ data->packet_handle_ipv4 = handle;
/*
* Explicitly request certain information to be provided. The requested
@@ -243,7 +255,7 @@ static void start_net_cb(struct qmi_result *result, void *user_data)
param = qmi_param_new_uint32(PARAM_REQUESTED_SETTINGS,
requested_settings);
- if (qmi_service_send(data->wds, QMI_WDS_GET_CURRENT_SETTINGS, param,
+ if (qmi_service_send(data->ipv4, QMI_WDS_GET_CURRENT_SETTINGS, param,
get_settings_cb, cbd, cb_data_unref) > 0) {
cb_data_ref(cbd);
return;
@@ -292,7 +304,7 @@ static void get_lte_attach_param_cb(struct qmi_result *result, void *user_data)
param = qmi_param_new_uint8(QMI_WDS_PARAM_IP_FAMILY, ip_family);
- if (qmi_service_send(data->wds, QMI_WDS_START_NETWORK, param,
+ if (qmi_service_send(data->ipv4, QMI_WDS_START_NETWORK, param,
start_net_cb, cbd, cb_data_unref) > 0) {
cb_data_ref(cbd);
return;
@@ -322,7 +334,7 @@ static void qmi_gprs_read_settings(struct ofono_gprs_context* gc,
DBG("cid %u", cid);
- if (qmi_service_send(data->wds, QMI_WDS_GET_LTE_ATTACH_PARAMETERS,
+ if (qmi_service_send(data->ipv4, QMI_WDS_GET_LTE_ATTACH_PARAMETERS,
NULL, get_lte_attach_param_cb, cbd,
cb_data_unref) > 0) {
data->active_context = cid;
@@ -381,7 +393,7 @@ static void qmi_activate_primary(struct ofono_gprs_context *gc,
qmi_param_append(param, QMI_WDS_PARAM_PASSWORD,
strlen(ctx->password), ctx->password);
- if (qmi_service_send(data->wds, QMI_WDS_START_NETWORK, param,
+ if (qmi_service_send(data->ipv4, QMI_WDS_START_NETWORK, param,
start_net_cb, cbd, cb_data_unref) > 0)
return;
@@ -395,6 +407,24 @@ error:
l_free(cbd);
}
+static uint32_t send_stop_net(struct qmi_service *wds, uint32_t packet_handle,
+ qmi_service_result_func_t func,
+ void *user_data, qmi_destroy_func_t destroy)
+{
+ static const uint8_t PARAM_PACKET_HANDLE = 0x01;
+ struct qmi_param *param = qmi_param_new_uint32(PARAM_PACKET_HANDLE,
+ packet_handle);
+ uint32_t id;
+
+ id = qmi_service_send(wds, QMI_WDS_STOP_NETWORK, param,
+ func, user_data, destroy);
+
+ if (!id)
+ qmi_param_free(param);
+
+ return id;
+}
+
static void stop_net_cb(struct qmi_result *result, void *user_data)
{
struct cb_data *cbd = user_data;
@@ -410,7 +440,7 @@ static void stop_net_cb(struct qmi_result *result, void *user_data)
return;
}
- data->pkt_handle = 0;
+ data->packet_handle_ipv4 = 0;
if (cb)
CALLBACK_WITH_SUCCESS(cb, cbd->data);
@@ -433,9 +463,10 @@ static void qmi_deactivate_primary(struct ofono_gprs_context *gc,
cbd->user = gc;
- param = qmi_param_new_uint32(PARAM_PACKET_HANDLE, data->pkt_handle);
+ param = qmi_param_new_uint32(PARAM_PACKET_HANDLE,
+ data->packet_handle_ipv4);
- if (qmi_service_send(data->wds, QMI_WDS_STOP_NETWORK, param,
+ if (qmi_service_send(data->ipv4, QMI_WDS_STOP_NETWORK, param,
stop_net_cb, cbd, l_free) > 0)
return;
@@ -447,12 +478,57 @@ static void qmi_deactivate_primary(struct ofono_gprs_context *gc,
l_free(cbd);
}
+static void stop_net_detach_ipv4_cb(struct qmi_result *result, void *user_data)
+{
+ struct ofono_gprs_context *gc = user_data;
+ struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
+ uint16_t error;
+
+ if (!qmi_result_set_error(result, &error))
+ error = 0;
+
+ DBG("error: %u", error);
+
+ data->packet_handle_ipv4 = 0;
+ check_all_deactivated(gc);
+}
+
+static void stop_net_detach_ipv6_cb(struct qmi_result *result, void *user_data)
+{
+ struct ofono_gprs_context *gc = user_data;
+ struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
+ uint16_t error;
+
+ if (!qmi_result_set_error(result, &error))
+ error = 0;
+
+ DBG("error: %u", error);
+
+ data->packet_handle_ipv6 = 0;
+ check_all_deactivated(gc);
+}
+
static void qmi_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
unsigned int cid)
{
+ struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
+
DBG("");
- qmi_deactivate_primary(gc, cid, NULL, NULL);
+ if (data->packet_handle_ipv6 &&
+ !send_stop_net(data->ipv6, data->packet_handle_ipv6,
+ stop_net_detach_ipv6_cb, gc, NULL))
+ data->packet_handle_ipv6 = 0;
+
+ if (data->packet_handle_ipv4 &&
+ !send_stop_net(data->ipv4, data->packet_handle_ipv4,
+ stop_net_detach_ipv4_cb, gc, NULL))
+ data->packet_handle_ipv4 = 0;
+
+ if (data->packet_handle_ipv4 || data->packet_handle_ipv6)
+ return;
+
+ data->active_context = 0;
}
static void set_ip_family_preference_cb(struct qmi_result *result,
@@ -603,11 +679,11 @@ static int qmi_gprs_context_probev(struct ofono_gprs_context *gc,
return r;
data = l_new(struct gprs_context_data, 1);
- data->wds = l_steal_ptr(ipv4);
+ data->ipv4 = l_steal_ptr(ipv4);
data->ipv6 = l_steal_ptr(ipv6);
data->mux_id = mux_id;
- qmi_service_register(data->wds, QMI_WDS_PACKET_SERVICE_STATUS,
+ qmi_service_register(data->ipv4, QMI_WDS_PACKET_SERVICE_STATUS,
pkt_status_notify, gc, NULL);
qmi_service_register(data->ipv6, QMI_WDS_PACKET_SERVICE_STATUS,
pkt_status_notify, gc, NULL);
@@ -625,7 +701,7 @@ static void qmi_gprs_context_remove(struct ofono_gprs_context *gc)
ofono_gprs_context_set_data(gc, NULL);
- qmi_service_free(data->wds);
+ qmi_service_free(data->ipv4);
qmi_service_free(data->ipv6);
l_free(data);
}
--
2.45.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 10/11] qmi: gprs-context: refactor deactivate_primary
2024-07-11 16:49 [PATCH v2 01/11] gobi: Limit number of premultiplexed contexts to 4 Denis Kenzior
` (7 preceding siblings ...)
2024-07-11 16:49 ` [PATCH v2 09/11] qmi: gprs-context: refactor detach_shutdown path Denis Kenzior
@ 2024-07-11 16:49 ` Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 11/11] qmi: gprs-context: Dual-Stack context activation support Denis Kenzior
2024-07-11 17:53 ` [PATCH v2 01/11] gobi: Limit number of premultiplexed contexts to 4 patchwork-bot+ofono
10 siblings, 0 replies; 12+ messages in thread
From: Denis Kenzior @ 2024-07-11 16:49 UTC (permalink / raw)
To: ofono; +Cc: Denis Kenzior
When multiple WDS clients are used (Dual stack contexts), the
deactivate_primary path needs to send Stop Network command on any client
with an ongoing packet connection. The following strategy is now used:
1. If no packet connections are ongoing on either IPv4 or IPV6
WDS client, callback with an error
2. If IPv6 WDS client is used, attempt to stop that first,
otherwise, proceed to step 4.
3. If IPv6 WDS client is the only client used, report the
success / failure of this operation. Otherwise, proceed to
step 4.
4. Try to send a Stop Network request to the IPv4 WDS client. If
this step fails, callback with an error.
---
drivers/qmimodem/gprs-context.c | 84 ++++++++++++++++++++++++---------
1 file changed, 62 insertions(+), 22 deletions(-)
diff --git a/drivers/qmimodem/gprs-context.c b/drivers/qmimodem/gprs-context.c
index f4846f0299e7..6061de0a483d 100644
--- a/drivers/qmimodem/gprs-context.c
+++ b/drivers/qmimodem/gprs-context.c
@@ -425,57 +425,97 @@ static uint32_t send_stop_net(struct qmi_service *wds, uint32_t packet_handle,
return id;
}
-static void stop_net_cb(struct qmi_result *result, void *user_data)
+static void stop_net_ipv4_cb(struct qmi_result *result, void *user_data)
{
struct cb_data *cbd = user_data;
ofono_gprs_context_cb_t cb = cbd->cb;
struct ofono_gprs_context *gc = cbd->user;
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
+ uint16_t error;
- DBG("");
+ if (!qmi_result_set_error(result, &error))
+ error = 0;
- if (qmi_result_set_error(result, NULL)) {
- if (cb)
- CALLBACK_WITH_FAILURE(cb, cbd->data);
- return;
- }
+ DBG("error: %u", error);
data->packet_handle_ipv4 = 0;
+ data->active_context = 0;
- if (cb)
- CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ if (error)
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
else
- ofono_gprs_context_deactivated(gc, data->active_context);
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+}
- data->active_context = 0;
+static void stop_net_ipv6_cb(struct qmi_result *result, void *user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_gprs_context_cb_t cb = cbd->cb;
+ struct ofono_gprs_context *gc = cbd->user;
+ struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
+ uint16_t error;
+
+ if (!qmi_result_set_error(result, &error))
+ error = 0;
+
+ DBG("error: %u", error);
+
+ data->packet_handle_ipv6 = 0;
+
+ if (data->packet_handle_ipv4) {
+ if (send_stop_net(data->ipv4, data->packet_handle_ipv4,
+ stop_net_ipv4_cb,
+ cb_data_ref(cbd), cb_data_unref))
+ return;
+
+ cb_data_unref(cbd);
+ data->active_context = 0;
+ data->packet_handle_ipv4 = 0;
+ goto error;
+ } else
+ data->active_context = 0;
+
+ if (!error) {
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ return;
+ }
+error:
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
}
static void qmi_deactivate_primary(struct ofono_gprs_context *gc,
unsigned int cid,
ofono_gprs_context_cb_t cb, void *user_data)
{
- static const uint8_t PARAM_PACKET_HANDLE = 0x01;
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
- struct cb_data *cbd = cb_data_new(cb, user_data);
- struct qmi_param *param;
+ struct cb_data *cbd;
+ uint32_t id;
DBG("cid %u", cid);
+ if (!data->packet_handle_ipv4 && !data->packet_handle_ipv6)
+ goto error;
+
+ cbd = cb_data_new(cb, user_data);
cbd->user = gc;
- param = qmi_param_new_uint32(PARAM_PACKET_HANDLE,
- data->packet_handle_ipv4);
+ if (data->packet_handle_ipv6)
+ id = send_stop_net(data->ipv6, data->packet_handle_ipv6,
+ stop_net_ipv6_cb, cbd, cb_data_unref);
+ else
+ id = send_stop_net(data->ipv4, data->packet_handle_ipv4,
+ stop_net_ipv4_cb, cbd, cb_data_unref);
- if (qmi_service_send(data->ipv4, QMI_WDS_STOP_NETWORK, param,
- stop_net_cb, cbd, l_free) > 0)
+ if (id)
return;
- qmi_param_free(param);
-
- if (cb)
- CALLBACK_WITH_FAILURE(cb, user_data);
+ data->packet_handle_ipv6 = 0;
+ data->packet_handle_ipv4 = 0;
+ data->active_context = 0;
l_free(cbd);
+error:
+ CALLBACK_WITH_FAILURE(cb, user_data);
}
static void stop_net_detach_ipv4_cb(struct qmi_result *result, void *user_data)
--
2.45.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 11/11] qmi: gprs-context: Dual-Stack context activation support
2024-07-11 16:49 [PATCH v2 01/11] gobi: Limit number of premultiplexed contexts to 4 Denis Kenzior
` (8 preceding siblings ...)
2024-07-11 16:49 ` [PATCH v2 10/11] qmi: gprs-context: refactor deactivate_primary Denis Kenzior
@ 2024-07-11 16:49 ` Denis Kenzior
2024-07-11 17:53 ` [PATCH v2 01/11] gobi: Limit number of premultiplexed contexts to 4 patchwork-bot+ofono
10 siblings, 0 replies; 12+ messages in thread
From: Denis Kenzior @ 2024-07-11 16:49 UTC (permalink / raw)
To: ofono; +Cc: Denis Kenzior
Support dual-stack contexts by utilizing two WDS services, one for each
family type. For IPv4 only contexts, the WDS service 'ipv4' is used.
For IPv6 only contexts, the WDS service 'ipv6' is used. For dual stack
contexts, both WDS services are used simultaneously.
When a default bearer (using read_settings) or primary context is
activated (using activate_primary), the Start Network command is issued
on one or both of the WDS services. Once the Start Network command
succeeds, the returned packet handle is stored in 'packet_handle_ipv4'
or 'packet_handle_ipv6', depending on the selected IP family.
Subsequently Get Current Settings command is issued and settings are
read from the QMI response and applied to the context. Success is
signaled to the core if at least one Start Network command succeeded.
Otherwise, an error is signaled.
---
drivers/qmimodem/gprs-context.c | 364 ++++++++++++++++++++------------
1 file changed, 228 insertions(+), 136 deletions(-)
diff --git a/drivers/qmimodem/gprs-context.c b/drivers/qmimodem/gprs-context.c
index 6061de0a483d..89d68d154ed8 100644
--- a/drivers/qmimodem/gprs-context.c
+++ b/drivers/qmimodem/gprs-context.c
@@ -26,6 +26,8 @@ struct gprs_context_data {
unsigned int active_context;
uint32_t packet_handle_ipv4;
uint32_t packet_handle_ipv6;
+ uint32_t start_network_ipv4_id;
+ uint32_t start_network_ipv6_id;
uint8_t mux_id;
};
@@ -67,23 +69,49 @@ static void pkt_status_notify(struct qmi_result *result, void *user_data)
switch (status->status) {
case QMI_WDS_CONNECTION_STATUS_DISCONNECTED:
- if (data->packet_handle_ipv4) {
+ if (ip_family == QMI_WDS_IP_FAMILY_IPV4 &&
+ data->packet_handle_ipv4) {
data->packet_handle_ipv4 = 0;
check_all_deactivated(gc);
}
+ if (ip_family == QMI_WDS_IP_FAMILY_IPV6 &&
+ data->packet_handle_ipv6) {
+ data->packet_handle_ipv6 = 0;
+ check_all_deactivated(gc);
+ }
+
break;
}
}
-static void get_settings_ipv6(struct ofono_gprs_context *gc,
- struct qmi_result *result)
+static void check_all_activated(struct gprs_context_data *data,
+ ofono_gprs_context_cb_t cb,
+ void *user_data)
+{
+ if (data->start_network_ipv4_id || data->start_network_ipv6_id)
+ return;
+
+ if (!data->packet_handle_ipv4 && !data->packet_handle_ipv6) {
+ data->active_context = 0;
+ CALLBACK_WITH_FAILURE(cb, user_data);
+ return;
+ }
+
+ CALLBACK_WITH_SUCCESS(cb, user_data);
+}
+
+static void get_settings_ipv6_cb(struct qmi_result *result, void *user_data)
{
static const uint8_t RESULT_IP_ADDRESS = 0x25;
static const uint8_t RESULT_GATEWAY = 0x26;
static const uint8_t RESULT_PRIMARY_DNS = 0x27;
static const uint8_t RESULT_SECONDARY_DNS = 0x28;
static const uint8_t RESULT_MTU = 0x29;
+ struct cb_data *cbd = user_data;
+ struct ofono_gprs_context *gc = cbd->user;
+ struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
+ uint16_t error;
const char *dns[3] = { NULL, NULL, NULL };
char dns1str[INET6_ADDRSTRLEN];
char dns2str[INET6_ADDRSTRLEN];
@@ -92,6 +120,13 @@ static void get_settings_ipv6(struct ofono_gprs_context *gc,
uint16_t len;
uint32_t mtu;
+ data->start_network_ipv6_id = 0;
+
+ if (qmi_result_set_error(result, &error)) {
+ DBG("error: %u", error);
+ goto done;
+ }
+
tlv = qmi_result_get(result, RESULT_IP_ADDRESS, &len);
if (tlv && len == sizeof(struct in6_addr) + 1) {
const struct in6_addr *ip = tlv;
@@ -131,22 +166,35 @@ static void get_settings_ipv6(struct ofono_gprs_context *gc,
if (qmi_result_get_uint32(result, RESULT_MTU, &mtu))
DBG("MTU: %u", mtu);
+
+done:
+ check_all_activated(data, cbd->cb, cbd->data);
}
-static void get_settings_ipv4(struct ofono_gprs_context *gc,
- struct qmi_result *result)
+static void get_settings_ipv4_cb(struct qmi_result *result, void *user_data)
{
static const uint8_t RESULT_PRIMARY_DNS = 0x15;
static const uint8_t RESULT_SECONDARY_DNS = 0x16;
static const uint8_t RESULT_IP_ADDRESS = 0x1e;
static const uint8_t RESULT_GATEWAY = 0x20;
static const uint8_t RESULT_GATEWAY_NETMASK = 0x21;
+ struct cb_data *cbd = user_data;
+ struct ofono_gprs_context *gc = cbd->user;
+ struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
+ uint16_t error;
uint32_t ip_addr;
struct in_addr addr;
char* straddr;
const char *dns[3] = { NULL, NULL, NULL };
char dns_buf[2][INET_ADDRSTRLEN];
+ data->start_network_ipv4_id = 0;
+
+ if (qmi_result_set_error(result, &error)) {
+ DBG("error: %u", error);
+ goto done;
+ }
+
if (qmi_result_get_uint32(result, RESULT_IP_ADDRESS, &ip_addr)) {
addr.s_addr = htonl(ip_addr);
straddr = inet_ntoa(addr);
@@ -182,65 +230,20 @@ static void get_settings_ipv4(struct ofono_gprs_context *gc,
if (dns[0])
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
-}
-
-static void get_settings_cb(struct qmi_result *result, void *user_data)
-{
- static const uint8_t RESULT_IP_FAMILY = 0x2b; /* uint8 */
- struct cb_data *cbd = user_data;
- ofono_gprs_context_cb_t cb = cbd->cb;
- struct ofono_gprs_context *gc = cbd->user;
- uint8_t ip_family;
-
- DBG("");
-
- if (qmi_result_set_error(result, NULL))
- goto done;
-
- if (!qmi_result_get_uint8(result, RESULT_IP_FAMILY, &ip_family)) {
- ofono_error("No IP family in results");
- goto done;
- }
-
- switch (ip_family) {
- case QMI_WDS_IP_FAMILY_IPV4:
- get_settings_ipv4(gc, result);
- break;
- case QMI_WDS_IP_FAMILY_IPV6:
- get_settings_ipv6(gc, result);
- break;
- default:
- break;
- }
done:
- CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ check_all_activated(data, cbd->cb, cbd->data);
}
-static void start_net_cb(struct qmi_result *result, void *user_data)
+static uint32_t send_get_current_settings(struct qmi_service *wds,
+ qmi_service_result_func_t func,
+ void *user_data,
+ qmi_destroy_func_t destroy)
{
- static const uint8_t RESULT_PACKET_HANDLE = 0x01;
static const uint8_t PARAM_REQUESTED_SETTINGS = 0x10;
- struct cb_data *cbd = user_data;
- ofono_gprs_context_cb_t cb = cbd->cb;
- struct ofono_gprs_context *gc = cbd->user;
- struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
- uint32_t handle;
uint32_t requested_settings = 0;
struct qmi_param *param;
-
- DBG("");
-
- if (qmi_result_set_error(result, NULL))
- goto error;
-
- if (!qmi_result_get_uint32(result, RESULT_PACKET_HANDLE, &handle))
- goto error;
-
- DBG("packet handle %d", handle);
-
- data->packet_handle_ipv4 = handle;
-
+ uint32_t id;
/*
* Explicitly request certain information to be provided. The requested
* settings is a bit field, with each bit representing whether the
@@ -254,18 +257,149 @@ static void start_net_cb(struct qmi_result *result, void *user_data)
L_BITS_SET(&requested_settings, 2, 3, 4, 5, 6, 7, 8, 9, 13, 14, 15, 17);
param = qmi_param_new_uint32(PARAM_REQUESTED_SETTINGS,
requested_settings);
+ id = qmi_service_send(wds, QMI_WDS_GET_CURRENT_SETTINGS, param,
+ func, user_data, destroy);
+
+ if (!id)
+ qmi_param_free(param);
+
+ return id;
+}
+
+static void start_network_common_cb(int family, struct qmi_result *result,
+ struct cb_data *cbd,
+ struct qmi_service *wds,
+ qmi_service_result_func_t func,
+ uint32_t *packet_handle,
+ uint32_t *family_start_id)
+{
+ static const uint8_t RESULT_PACKET_HANDLE = 0x01;
+ struct ofono_gprs_context *gc = cbd->user;
+ struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
+ uint16_t error;
+
+ *family_start_id = 0;
- if (qmi_service_send(data->ipv4, QMI_WDS_GET_CURRENT_SETTINGS, param,
- get_settings_cb, cbd, cb_data_unref) > 0) {
- cb_data_ref(cbd);
+ if (!qmi_result_set_error(result, &error))
+ error = 0;
+
+ DBG("family: %d, error: %u", family, error);
+
+ if (error)
+ goto error;
+
+ if (!qmi_result_get_uint32(result, RESULT_PACKET_HANDLE, packet_handle))
+ goto error;
+
+ *family_start_id =
+ send_get_current_settings(wds, func,
+ cb_data_ref(cbd), cb_data_unref);
+ if (*family_start_id)
return;
+
+ *packet_handle = 0;
+ cb_data_unref(cbd);
+error:
+ check_all_activated(data, cbd->cb, cbd->data);
+}
+
+static void start_network_ipv4_cb(struct qmi_result *result, void *user_data)
+{
+ struct cb_data *cbd = user_data;
+ struct ofono_gprs_context *gc = cbd->user;
+ struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
+
+ start_network_common_cb(4, result, user_data,
+ data->ipv4, get_settings_ipv4_cb,
+ &data->packet_handle_ipv4,
+ &data->start_network_ipv4_id);
+}
+
+static void start_network_ipv6_cb(struct qmi_result *result, void *user_data)
+{
+ struct cb_data *cbd = user_data;
+ struct ofono_gprs_context *gc = cbd->user;
+ struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
+
+ start_network_common_cb(6, result, user_data,
+ data->ipv6, get_settings_ipv6_cb,
+ &data->packet_handle_ipv6,
+ &data->start_network_ipv6_id);
+}
+
+static struct qmi_param *param_from_context(uint8_t ip_family,
+ const struct ofono_gprs_primary_context *ctx)
+{
+ struct qmi_param *param = qmi_param_new();
+ uint8_t auth;
+
+ qmi_param_append_uint8(param, QMI_WDS_PARAM_IP_FAMILY, ip_family);
+
+ if (!ctx)
+ goto done;
+
+ qmi_param_append(param, QMI_WDS_PARAM_APN,
+ strlen(ctx->apn), ctx->apn);
+
+ auth = qmi_wds_auth_from_ofono(ctx->auth_method);
+ qmi_param_append_uint8(param, QMI_WDS_PARAM_AUTHENTICATION_PREFERENCE,
+ auth);
+
+ if (auth && ctx->username[0] != '\0')
+ qmi_param_append(param, QMI_WDS_PARAM_USERNAME,
+ strlen(ctx->username), ctx->username);
+
+ if (auth && ctx->password[0] != '\0')
+ qmi_param_append(param, QMI_WDS_PARAM_PASSWORD,
+ strlen(ctx->password), ctx->password);
+done:
+ return param;
+}
+
+static int start_network(uint8_t iptype, struct gprs_context_data *data,
+ const struct ofono_gprs_primary_context *ctx,
+ struct cb_data *cbd)
+{
+ struct qmi_param *param;
+
+ if (!L_IN_SET(iptype, QMI_WDS_IP_SUPPORT_IPV4, QMI_WDS_IP_SUPPORT_IPV6,
+ QMI_WDS_IP_SUPPORT_IPV4V6))
+ return -EINVAL;
+
+ if (iptype == QMI_WDS_IP_SUPPORT_IPV4 ||
+ iptype == QMI_WDS_IP_SUPPORT_IPV4V6) {
+ param = param_from_context(QMI_WDS_IP_FAMILY_IPV4, ctx);
+
+ data->start_network_ipv4_id =
+ qmi_service_send(data->ipv4, QMI_WDS_START_NETWORK,
+ param, start_network_ipv4_cb,
+ cb_data_ref(cbd), cb_data_unref);
+
+ if (!data->start_network_ipv4_id) {
+ cb_data_unref(cbd);
+ qmi_param_free(param);
+ }
}
- qmi_param_free(param);
+ if (iptype == QMI_WDS_IP_SUPPORT_IPV6 ||
+ iptype == QMI_WDS_IP_SUPPORT_IPV4V6) {
+ param = param_from_context(QMI_WDS_IP_FAMILY_IPV6, ctx);
-error:
- data->active_context = 0;
- CALLBACK_WITH_FAILURE(cb, cbd->data);
+ data->start_network_ipv6_id =
+ qmi_service_send(data->ipv6, QMI_WDS_START_NETWORK,
+ param, start_network_ipv6_cb,
+ cb_data_ref(cbd), cb_data_unref);
+
+ if (!data->start_network_ipv6_id) {
+ cb_data_unref(cbd);
+ qmi_param_free(param);
+ }
+ }
+
+ if (data->start_network_ipv4_id || data->start_network_ipv6_id)
+ return 0;
+
+ return -EIO;
}
static void get_lte_attach_param_cb(struct qmi_result *result, void *user_data)
@@ -277,40 +411,20 @@ static void get_lte_attach_param_cb(struct qmi_result *result, void *user_data)
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
uint16_t error;
uint8_t iptype;
- struct qmi_param *param;
- uint8_t ip_family;
- DBG("");
+ if (!qmi_result_set_error(result, &error))
+ error = 0;
- if (qmi_result_set_error(result, &error))
- goto error;
+ DBG("error: %u", error);
- if (!qmi_result_get_uint8(result, RESULT_IP_SUPPORT_TYPE, &iptype))
+ if (error)
goto error;
- switch (iptype) {
- case QMI_WDS_IP_SUPPORT_IPV4:
- ip_family = QMI_WDS_IP_FAMILY_IPV4;
- break;
- case QMI_WDS_IP_SUPPORT_IPV6:
- ip_family = QMI_WDS_IP_FAMILY_IPV6;
- break;
- case QMI_WDS_IP_SUPPORT_IPV4V6:
- ip_family = QMI_WDS_IP_FAMILY_IPV4;
- break;
- default:
+ if (!qmi_result_get_uint8(result, RESULT_IP_SUPPORT_TYPE, &iptype))
goto error;
- }
-
- param = qmi_param_new_uint8(QMI_WDS_PARAM_IP_FAMILY, ip_family);
- if (qmi_service_send(data->ipv4, QMI_WDS_START_NETWORK, param,
- start_net_cb, cbd, cb_data_unref) > 0) {
- cb_data_ref(cbd);
+ if (!start_network(iptype, data, NULL, cbd))
return;
- }
-
- qmi_param_free(param);
error:
data->active_context = 0;
@@ -320,7 +434,7 @@ error:
/*
* This function gets called for "automatic" contexts, those which are
* not activated via activate_primary. For these, we will still need
- * to call start_net in order to get the packet handle for the context.
+ * to call start_network in order to get the packet handle for the context.
* The process for automatic contexts is essentially identical to that
* for others.
*/
@@ -334,14 +448,15 @@ static void qmi_gprs_read_settings(struct ofono_gprs_context* gc,
DBG("cid %u", cid);
+ data->active_context = cid;
+ cbd->user = gc;
+
if (qmi_service_send(data->ipv4, QMI_WDS_GET_LTE_ATTACH_PARAMETERS,
NULL, get_lte_attach_param_cb, cbd,
- cb_data_unref) > 0) {
- data->active_context = cid;
- cbd->user = gc;
+ cb_data_unref) > 0)
return;
- }
+ data->active_context = 0;
CALLBACK_WITH_FAILURE(cb, cbd->data);
l_free(cbd);
}
@@ -351,60 +466,37 @@ static void qmi_activate_primary(struct ofono_gprs_context *gc,
ofono_gprs_context_cb_t cb, void *user_data)
{
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
- struct cb_data *cbd = cb_data_new(cb, user_data);
- struct qmi_param *param;
- uint8_t ip_family;
- uint8_t auth;
+ enum ofono_gprs_proto proto = ctx->proto;
+ struct cb_data *cbd;
+ int ip_type;
+ int r;
DBG("cid %u", ctx->cid);
- cbd->user = gc;
-
- data->active_context = ctx->cid;
-
- switch (ctx->proto) {
- case OFONO_GPRS_PROTO_IP:
- ip_family = QMI_WDS_IP_FAMILY_IPV4;
- break;
- case OFONO_GPRS_PROTO_IPV6:
- ip_family = QMI_WDS_IP_FAMILY_IPV6;
- break;
- default:
+ if (!L_IN_SET(proto, OFONO_GPRS_PROTO_IP, OFONO_GPRS_PROTO_IPV6,
+ OFONO_GPRS_PROTO_IPV4V6))
goto error;
- }
- param = qmi_param_new();
-
- qmi_param_append(param, QMI_WDS_PARAM_APN,
- strlen(ctx->apn), ctx->apn);
-
- qmi_param_append_uint8(param, QMI_WDS_PARAM_IP_FAMILY, ip_family);
-
- auth = qmi_wds_auth_from_ofono(ctx->auth_method);
+ ip_type = qmi_wds_pdp_type_from_ofono(ctx->proto);
+ if (ip_type < 0)
+ goto error;
- qmi_param_append_uint8(param, QMI_WDS_PARAM_AUTHENTICATION_PREFERENCE,
- auth);
+ if (qmi_wds_auth_from_ofono(ctx->auth_method) < 0)
+ goto error;
- if (auth && ctx->username[0] != '\0')
- qmi_param_append(param, QMI_WDS_PARAM_USERNAME,
- strlen(ctx->username), ctx->username);
+ data->active_context = ctx->cid;
+ cbd = cb_data_new(cb, user_data);
+ cbd->user = gc;
- if (auth && ctx->password[0] != '\0')
- qmi_param_append(param, QMI_WDS_PARAM_PASSWORD,
- strlen(ctx->password), ctx->password);
+ r = start_network(ip_type, data, ctx, cbd);
+ cb_data_unref(cbd);
- if (qmi_service_send(data->ipv4, QMI_WDS_START_NETWORK, param,
- start_net_cb, cbd, cb_data_unref) > 0)
+ if (!r)
return;
- qmi_param_free(param);
-
-error:
data->active_context = 0;
-
- CALLBACK_WITH_FAILURE(cb, cbd->data);
-
- l_free(cbd);
+error:
+ CALLBACK_WITH_FAILURE(cb, user_data);
}
static uint32_t send_stop_net(struct qmi_service *wds, uint32_t packet_handle,
--
2.45.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v2 01/11] gobi: Limit number of premultiplexed contexts to 4
2024-07-11 16:49 [PATCH v2 01/11] gobi: Limit number of premultiplexed contexts to 4 Denis Kenzior
` (9 preceding siblings ...)
2024-07-11 16:49 ` [PATCH v2 11/11] qmi: gprs-context: Dual-Stack context activation support Denis Kenzior
@ 2024-07-11 17:53 ` patchwork-bot+ofono
10 siblings, 0 replies; 12+ messages in thread
From: patchwork-bot+ofono @ 2024-07-11 17:53 UTC (permalink / raw)
To: Denis Kenzior; +Cc: ofono
Hello:
This series was applied to ofono.git (master)
by Denis Kenzior <denkenz@gmail.com>:
On Thu, 11 Jul 2024 11:49:23 -0500 you wrote:
> 4 was chosen somewhat arbitrarily, but it is the maximum that the
> qmi_wwan_q driver can support out of the box. The only limit is the
> number of clients under QMI. Two WDS clients are typically required for
> each active context, one for IPv4 and one for IPv6. The total number of
> clients cannot exceed 255 (uint8).
> ---
> plugins/gobi.c | 19 +++++++++++++++----
> 1 file changed, 15 insertions(+), 4 deletions(-)
Here is the summary with links:
- [v2,01/11] gobi: Limit number of premultiplexed contexts to 4
https://git.kernel.org/pub/scm/network/ofono/ofono.git/?id=3076113d2867
- [v2,02/11] gobi: Request dedicated WDS services for contexts
https://git.kernel.org/pub/scm/network/ofono/ofono.git/?id=a47296c79b10
- [v2,03/11] qmi: Enable _auto_ use for some classes
https://git.kernel.org/pub/scm/network/ofono/ofono.git/?id=b46004b53763
- [v2,04/11] qmi: gprs-context: Declare qmi_service objects using _auto_
https://git.kernel.org/pub/scm/network/ofono/ofono.git/?id=766aa0ac819d
- [v2,05/11] qmi: Pass two dedicated WDS services to gprs-context
https://git.kernel.org/pub/scm/network/ofono/ofono.git/?id=151823bdc330
- [v2,06/11] qmi: gprs-context: Remove parsing of unused TLVs
https://git.kernel.org/pub/scm/network/ofono/ofono.git/?id=4921cfec9723
- [v2,07/11] qmi: gprs-context: Treat IP family TLV as mandatory
https://git.kernel.org/pub/scm/network/ofono/ofono.git/?id=90db5ebd6aef
- [v2,08/11] qmi: gprs-context: Set up WDS service for IPv6
https://git.kernel.org/pub/scm/network/ofono/ofono.git/?id=c09e6bebe703
- [v2,09/11] qmi: gprs-context: refactor detach_shutdown path
https://git.kernel.org/pub/scm/network/ofono/ofono.git/?id=d617baf9e089
- [v2,10/11] qmi: gprs-context: refactor deactivate_primary
https://git.kernel.org/pub/scm/network/ofono/ofono.git/?id=f25f481d45e8
- [v2,11/11] qmi: gprs-context: Dual-Stack context activation support
https://git.kernel.org/pub/scm/network/ofono/ofono.git/?id=3ee784aa9d9c
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2024-07-11 17:53 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-07-11 16:49 [PATCH v2 01/11] gobi: Limit number of premultiplexed contexts to 4 Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 02/11] gobi: Request dedicated WDS services for contexts Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 03/11] qmi: Enable _auto_ use for some classes Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 04/11] qmi: gprs-context: Declare qmi_service objects using _auto_ Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 05/11] qmi: Pass two dedicated WDS services to gprs-context Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 06/11] qmi: gprs-context: Remove parsing of unused TLVs Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 07/11] qmi: gprs-context: Treat IP family TLV as mandatory Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 08/11] qmi: gprs-context: Set up WDS service for IPv6 Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 09/11] qmi: gprs-context: refactor detach_shutdown path Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 10/11] qmi: gprs-context: refactor deactivate_primary Denis Kenzior
2024-07-11 16:49 ` [PATCH v2 11/11] qmi: gprs-context: Dual-Stack context activation support Denis Kenzior
2024-07-11 17:53 ` [PATCH v2 01/11] gobi: Limit number of premultiplexed contexts to 4 patchwork-bot+ofono
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.