[PATCH v4 2/6] mbimmodem: add support for MBIM extensions * With MBIMEx 3.0, arguments for activating GPRS changed. Update as needed.

Muhammad Asif <[email protected]> Mon, 5 May 2025 00:19:27 +0500
Newsgroups dev.linux.lists.ofono
Message-ID <[email protected]>
---
 drivers/mbimmodem/gprs-context.c | 59 ++++++++++++++++++++++++--------
 drivers/mbimmodem/mbim.c         | 55 +++++++++++++++++++++++++++++
 drivers/mbimmodem/mbim.h         |  7 ++++
 3 files changed, 107 insertions(+), 14 deletions(-)

diff --git a/drivers/mbimmodem/gprs-context.c b/drivers/mbimmodem/gprs-context.c
index c420e300..e912b6a5 100644
--- a/drivers/mbimmodem/gprs-context.c
+++ b/drivers/mbimmodem/gprs-context.c
@@ -102,9 +102,16 @@ static void mbim_gprs_deactivate_primary(struct ofono_gprs_context *gc,
 	message = mbim_message_new(mbim_uuid_basic_connect,
 					MBIM_CID_CONNECT,
 					MBIM_COMMAND_TYPE_SET);
-	mbim_message_set_arguments(message, "uusssuuu16y",
-					cid, 0, NULL, NULL, NULL, 0, 0, 0,
-					mbim_context_type_internet);
+
+	if (mbim_device_check_mbimex_version(gcd->device, 3, 0)) {
+		mbim_message_set_arguments(message, "uuuuu16yussss",
+						cid, 0, 0, 0, 0, mbim_context_type_internet,
+						0, NULL, NULL, NULL, NULL);
+	} else {
+		mbim_message_set_arguments(message, "uusssuuu16y",
+						cid, 0, NULL, NULL, NULL, 0, 0, 0,
+						mbim_context_type_internet);
+	}
 
 	if (mbim_device_send(gcd->device, GPRS_CONTEXT_GROUP, message,
 				mbim_deactivate_cb, gc, NULL) > 0)
@@ -288,10 +295,18 @@ error:
 	message = mbim_message_new(mbim_uuid_basic_connect,
 					MBIM_CID_CONNECT,
 					MBIM_COMMAND_TYPE_SET);
-	mbim_message_set_arguments(message, "uusssuuu16y",
+
+	if (mbim_device_check_mbimex_version(gcd->device, 3, 0)) {
+		mbim_message_set_arguments(message, "uuuuu16yussss",
+					gcd->active_context, 0, 0, 0, 0,
+					mbim_context_type_internet, 0, NULL,
+					NULL, NULL, NULL);
+	} else {
+		mbim_message_set_arguments(message, "uusssuuu16y",
 					gcd->active_context, 0,
 					NULL, NULL, NULL, 0, 0, 0,
 					mbim_context_type_internet);
+	}
 
 	if (!mbim_device_send(gcd->device, GPRS_CONTEXT_GROUP, message,
 				NULL, NULL, NULL))
@@ -352,16 +367,32 @@ static void mbim_gprs_activate_primary(struct ofono_gprs_context *gc,
 	message = mbim_message_new(mbim_uuid_basic_connect,
 					MBIM_CID_CONNECT,
 					MBIM_COMMAND_TYPE_SET);
-	mbim_message_set_arguments(message, "uusssuuu16y",
-				ctx->cid,
-				1, /* MBIMActivationCommandActivate */
-				ctx->apn,
-				username,
-				password,
-				0, /*MBIMCompressionNone */
-				auth_method_to_auth_protocol(ctx->auth_method),
-				proto_to_context_ip_type(ctx->proto),
-				mbim_context_type_internet);
+
+	if (mbim_device_check_mbimex_version(gcd->device, 3, 0)) {
+		mbim_message_set_arguments(message, "uuuuu16yussss",
+			ctx->cid,
+			1, // Activate
+			0, // Compression
+			auth_method_to_auth_protocol(ctx->auth_method),
+			proto_to_context_ip_type(ctx->proto),
+			mbim_context_type_internet,
+			0, // MbimMediaTypeNone
+			ctx->apn,
+			username,
+			password,
+			NULL);
+	} else {
+		mbim_message_set_arguments(message, "uusssuuu16y",
+			ctx->cid,
+			1, // Activate
+			ctx->apn,
+			username,
+			password,
+			0, // compression
+			auth_method_to_auth_protocol(ctx->auth_method),
+			proto_to_context_ip_type(ctx->proto),
+			mbim_context_type_internet);
+	}
 
 	if (mbim_device_send(gcd->device, GPRS_CONTEXT_GROUP, message,
 				mbim_activate_cb, gc, NULL) > 0)
diff --git a/drivers/mbimmodem/mbim.c b/drivers/mbimmodem/mbim.c
index 43ff9704..be4df986 100644
--- a/drivers/mbimmodem/mbim.c
+++ b/drivers/mbimmodem/mbim.c
@@ -107,6 +107,11 @@ const uint8_t mbim_context_type_local[] = {
 	0x03, 0x3C, 0x39, 0xF6, 0x0D, 0xB9,
 };
 
+const uint8_t mbim_ms_basic_connect_extensions[] = {
+	0x3D, 0x01, 0xDC, 0xC5, 0xFE, 0xF5, 0x4D, 0x05, 0x0D, 0x3A,
+	0xBE, 0xF7, 0x05, 0x8E, 0x9A, 0xAF,
+};
+
 struct message_assembly_node {
 	struct mbim_message_header msg_hdr;
 	struct mbim_fragment_header frag_hdr;
@@ -253,6 +258,11 @@ struct mbim_device {
 	struct message_assembly *assembly;
 	struct l_idle *close_io;
 
+	uint8_t mbim_version_major;
+	uint8_t mbim_version_minor;
+	uint8_t mbimex_version_major;
+	uint8_t mbimex_version_minor;
+
 	bool is_ready : 1;
 	bool in_notify : 1;
 };
@@ -875,6 +885,22 @@ static bool close_read_handler(struct l_io *io, void *user_data)
 	return true;
 }
 
+static void parse_mbim_version(struct mbim_message *message, void *user_data)
+{
+	struct mbim_device *device = user_data;
+	uint16_t mbim_version = 0, mbimex_version = 0;
+
+	if (mbim_message_get_error(message) != 0)
+		return;
+
+	mbim_message_get_arguments(message, "qq", &mbim_version, &mbimex_version);
+
+	device->mbim_version_major = mbim_version >> 8;
+	device->mbim_version_minor = mbim_version & 0xFF;
+	device->mbimex_version_major = mbimex_version >> 8;
+	device->mbimex_version_minor = mbimex_version & 0xFF;
+}
+
 struct mbim_device *mbim_device_new(int fd, uint32_t max_segment_size)
 {
 	struct mbim_device *device;
@@ -1035,6 +1061,35 @@ bool mbim_device_set_ready_handler(struct mbim_device *device,
 	return true;
 }
 
+void mbim_device_get_version(struct mbim_device *device)
+{
+	// Version is formatted as (major version) << 8 | (minor version)
+	const int mbim_version = 1 << 8 | 0;
+
+	// Always open with MBIMEx 3, devices not supporting it will fallback to MBIMEx 2
+	const int mbimex_version = 3 << 8 | 0;
+
+	struct mbim_message *message = mbim_message_new(mbim_ms_basic_connect_extensions,
+					MBIM_CID_MS_BASIC_CONNECT_EXTENSIONS_VERSION,
+					MBIM_COMMAND_TYPE_QUERY);
+
+	mbim_message_set_arguments(message, "qq",
+								mbim_version,
+								mbimex_version);
+
+	// For some reason, sending a message will return an error code, even if valid
+	mbim_device_send(device, 0, message,
+						parse_mbim_version, device, NULL);
+}
+
+bool mbim_device_check_mbimex_version(struct mbim_device *device,
+					int version_major, int version_minor)
+{
+	return (device->mbimex_version_major > version_major) ||
+			((device->mbimex_version_major == version_major) &&
+			(device->mbimex_version_minor >= version_minor));
+}
+
 uint32_t mbim_device_send(struct mbim_device *device, uint32_t gid,
 				struct mbim_message *message,
 				mbim_device_reply_func_t function,
diff --git a/drivers/mbimmodem/mbim.h b/drivers/mbimmodem/mbim.h
index 5f15d0a2..4a6c8f47 100644
--- a/drivers/mbimmodem/mbim.h
+++ b/drivers/mbimmodem/mbim.h
@@ -31,6 +31,8 @@ struct mbim_message;
 #define MBIM_CID_IP_PACKET_FILTERS		23
 #define MBIM_CID_MULTICARRIER_PROVIDERS		24
 
+#define MBIM_CID_MS_BASIC_CONNECT_EXTENSIONS_VERSION	15
+
 #define MBIM_CID_SMS_CONFIGURATION		1
 #define MBIM_CID_SMS_READ			2
 #define MBIM_CID_SMS_SEND			3
@@ -87,6 +89,7 @@ extern const uint8_t mbim_uuid_phonebook[];
 extern const uint8_t mbim_uuid_stk[];
 extern const uint8_t mbim_uuid_auth[];
 extern const uint8_t mbim_uuid_dss[];
+extern const uint8_t mbim_ms_basic_connect_extensions[];
 
 extern const uint8_t mbim_context_type_none[];
 extern const uint8_t mbim_context_type_internet[];
@@ -118,6 +121,10 @@ bool mbim_device_set_ready_handler(struct mbim_device *device,
 					void *user_data,
 					mbim_device_destroy_func_t destroy);
 
+void mbim_device_get_version(struct mbim_device *device);
+bool mbim_device_check_mbimex_version(struct mbim_device *device,
+					int version_major, int version_minor);
+
 uint32_t mbim_device_send(struct mbim_device *device, uint32_t gid,
 				struct mbim_message *message,
 				mbim_device_reply_func_t function,
-- 
2.49.0