Add Foxconn FCC Unlock mechanism to quectel-5G-M (#51)

This commit is contained in:
Julian Braun 2025-06-02 13:00:58 +02:00 committed by GitHub
parent 6fe59c1d2b
commit 393dd33334
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 189 additions and 19 deletions

View File

@ -314,6 +314,11 @@ typedef struct _QMI_TLV
#define QMUX_CTL_FLAG_TYPE_IND 0x04
#define QMUX_CTL_FLAG_MASK_COMPOUND 0x01
#define QMUX_CTL_FLAG_MASK_TYPE 0x06 // 00-cmd, 01-rsp, 10-ind
// Add these definitions to the DMS message types section
#define QMIDMS_FOXCONN_SET_FCC_AUTH_REQ 0x555C
#define QMIDMS_FOXCONN_SET_FCC_AUTH_RESP 0x555C
#define QMIDMS_FOXCONN_SET_FCC_AUTH_V2_REQ 0x555D
#define QMIDMS_FOXCONN_SET_FCC_AUTH_V2_RESP 0x555D
#pragma pack(pop)

View File

@ -399,25 +399,25 @@ typedef struct _QCTLV_PKT_STATISTICS
//#ifdef QC_IP_MODE
/*
â?Bit 0 â?Profile identifier
â?Bit 1 â?Profile name
â?Bit 2 â?PDP type
â?Bit 3 â?APN name
â?Bit 4 â?DNS address
â?Bit 5 â?UMTS/GPRS granted QoS
â?Bit 6 â?Username
â?Bit 7 â?Authentication Protocol
â?Bit 8 â?IP address
â?Bit 9 â?Gateway information (address and subnet mask)
â?Bit 10 â?PCSCF address using a PCO flag
â?Bit 11 â?PCSCF server address list
â?Bit 12 â?PCSCF domain name list
â?Bit 13 â?MTU
â?Bit 14 â?Domain name list
â?Bit 15 â?IP family
â?Bit 16 â?IM_CM flag
â?Bit 17 â?Technology name
â?Bit 18 â?Operator reserved PCO
<EFBFBD>?Bit 0 <EFBFBD>?Profile identifier
<EFBFBD>?Bit 1 <EFBFBD>?Profile name
<EFBFBD>?Bit 2 <EFBFBD>?PDP type
<EFBFBD>?Bit 3 <EFBFBD>?APN name
<EFBFBD>?Bit 4 <EFBFBD>?DNS address
<EFBFBD>?Bit 5 <EFBFBD>?UMTS/GPRS granted QoS
<EFBFBD>?Bit 6 <EFBFBD>?Username
<EFBFBD>?Bit 7 <EFBFBD>?Authentication Protocol
<EFBFBD>?Bit 8 <EFBFBD>?IP address
<EFBFBD>?Bit 9 <EFBFBD>?Gateway information (address and subnet mask)
<EFBFBD>?Bit 10 <EFBFBD>?PCSCF address using a PCO flag
<EFBFBD>?Bit 11 <EFBFBD>?PCSCF server address list
<EFBFBD>?Bit 12 <EFBFBD>?PCSCF domain name list
<EFBFBD>?Bit 13 <EFBFBD>?MTU
<EFBFBD>?Bit 14 <EFBFBD>?Domain name list
<EFBFBD>?Bit 15 <EFBFBD>?IP family
<EFBFBD>?Bit 16 <EFBFBD>?IM_CM flag
<EFBFBD>?Bit 17 <EFBFBD>?Technology name
<EFBFBD>?Bit 18 <EFBFBD>?Operator reserved PCO
*/
#define QMIWDS_GET_RUNTIME_SETTINGS_MASK_IPV4DNS_ADDR (1 << 4)
#define QMIWDS_GET_RUNTIME_SETTINGS_MASK_IPV4_ADDR (1 << 8)
@ -4067,6 +4067,25 @@ typedef struct _QMIUIM_SET_CARD_SLOT_REQ_MSG
#define QMI_COEX_GET_WWAN_STATE_REQ 0x22
#define QMI_COEX_GET_WWAN_STATE_RESP 0x22
// Add these structure definitions after existing message structures
#ifdef CONFIG_FOXCONN_FCC_AUTH
typedef struct _QMIDMS_FOXCONN_SET_FCC_AUTH_REQ_MSG
{
USHORT Type;
USHORT Length;
UCHAR TLVType;
USHORT TLVLength;
UCHAR magic_value;
} __attribute__ ((packed)) QMIDMS_FOXCONN_SET_FCC_AUTH_REQ_MSG, *PQMIDMS_FOXCONN_SET_FCC_AUTH_REQ_MSG;
typedef struct _QMIDMS_FOXCONN_SET_FCC_AUTH_V2_REQ_MSG
{
USHORT Type;
USHORT Length;
} __attribute__ ((packed)) QMIDMS_FOXCONN_SET_FCC_AUTH_V2_REQ_MSG, *PQMIDMS_FOXCONN_SET_FCC_AUTH_V2_REQ_MSG;
#endif
typedef struct {
uint32_t freq;
@ -4293,6 +4312,10 @@ typedef struct _QMUX_MSG
QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG SetDataFormatReq;
QMI_WDA_SET_LOOPBACK_CONFIG_REQ_MSG SetLoopBackReq;
QMI_WDA_SET_LOOPBACK_CONFIG_IND_MSG SetLoopBackInd;
#ifdef CONFIG_FOXCONN_FCC_AUTH
QMIDMS_FOXCONN_SET_FCC_AUTH_REQ_MSG FoxconnSetFccAuthReq;
QMIDMS_FOXCONN_SET_FCC_AUTH_V2_REQ_MSG FoxconnSetFccAuthV2Req;
#endif
};
} __attribute__ ((packed)) QMUX_MSG, *PQMUX_MSG;

View File

@ -1832,6 +1832,88 @@ static int requestQueryDataCall(UCHAR *pConnectionStatus, int curIpFamily) {
return 0;
}
// Add these implementations after existing function implementations
#ifdef CONFIG_FOXCONN_FCC_AUTH
// Make sure these functions are static to avoid symbol conflicts
static USHORT DmsFoxconnSetFccAuthenticationReq(PQMUX_MSG pMUXMsg, void *arg) {
UCHAR magic_value = *((UCHAR *)arg);
pMUXMsg->FoxconnSetFccAuthReq.TLVType = 0x01;
pMUXMsg->FoxconnSetFccAuthReq.TLVLength = cpu_to_le16(1);
pMUXMsg->FoxconnSetFccAuthReq.magic_value = magic_value;
return sizeof(QMIDMS_FOXCONN_SET_FCC_AUTH_REQ_MSG);
}
static USHORT DmsFoxconnSetFccAuthenticationV2Req(PQMUX_MSG pMUXMsg, void *arg) {
FOXCONN_FCC_AUTH_V2_T *fcc_auth = (FOXCONN_FCC_AUTH_V2_T *)arg;
USHORT TLVLength = 0;
UCHAR *pTLV;
pTLV = (UCHAR *)(&pMUXMsg->FoxconnSetFccAuthV2Req + 1);
// Magic string TLV (0x01)
*pTLV++ = 0x01; // TLV Type
*(USHORT *)pTLV = cpu_to_le16(strlen(fcc_auth->magic_string));
pTLV += 2;
memcpy(pTLV, fcc_auth->magic_string, strlen(fcc_auth->magic_string));
pTLV += strlen(fcc_auth->magic_string);
TLVLength += 3 + strlen(fcc_auth->magic_string);
// Magic number TLV (0x02)
*pTLV++ = 0x02; // TLV Type
*(USHORT *)pTLV = cpu_to_le16(1);
pTLV += 2;
*pTLV++ = fcc_auth->magic_number;
TLVLength += 4;
return sizeof(QMIDMS_FOXCONN_SET_FCC_AUTH_V2_REQ_MSG) + TLVLength;
}
// These functions should NOT be static since they're used externally
int requestFoxconnSetFccAuthentication(UCHAR magic_value) {
PQCQMIMSG pRequest;
PQCQMIMSG pResponse;
PQMUX_MSG pMUXMsg;
int err;
dbg_time("%s(magic_value=0x%02x)", __func__, magic_value);
pRequest = ComposeQMUXMsg(QMUX_TYPE_DMS, QMIDMS_FOXCONN_SET_FCC_AUTH_REQ, DmsFoxconnSetFccAuthenticationReq, &magic_value);
err = QmiThreadSendQMI(pRequest, &pResponse);
qmi_rsp_check_and_return();
free(pResponse);
return 0;
}
int requestFoxconnSetFccAuthenticationV2(const char *magic_string, UCHAR magic_number) {
PQCQMIMSG pRequest;
PQCQMIMSG pResponse;
PQMUX_MSG pMUXMsg;
int err;
FOXCONN_FCC_AUTH_V2_T fcc_auth;
dbg_time("%s(magic_string='%s', magic_number=0x%02x)", __func__, magic_string, magic_number);
if (!magic_string || strlen(magic_string) >= sizeof(fcc_auth.magic_string)) {
dbg_time("%s: Invalid magic_string", __func__);
return -1;
}
strcpy(fcc_auth.magic_string, magic_string);
fcc_auth.magic_number = magic_number;
pRequest = ComposeQMUXMsg(QMUX_TYPE_DMS, QMIDMS_FOXCONN_SET_FCC_AUTH_V2_REQ, DmsFoxconnSetFccAuthenticationV2Req, &fcc_auth);
err = QmiThreadSendQMI(pRequest, &pResponse);
qmi_rsp_check_and_return();
free(pResponse);
return 0;
}
#endif
static int requestSetupDataCall(PROFILE_T *profile, int curIpFamily) {
PQCQMIMSG pRequest;
PQCQMIMSG pResponse;
@ -2271,6 +2353,17 @@ static int requestBaseBandVersion(PROFILE_T *profile) {
{
uchar2char(profile->BaseBandVersion, sizeof(profile->BaseBandVersion), &revId->RevisionID, le16_to_cpu(revId->TLVLength));
dbg_time("%s %s", __func__, profile->BaseBandVersion);
#ifdef CONFIG_FOXCONN_FCC_AUTH
// Check if this modem model needs FCC authentication
if (strstr(profile->BaseBandVersion, "T99W175")) {
profile->needs_fcc_auth = 1;
dbg_time("Modem model %s requires FCC authentication", profile->BaseBandVersion);
} else {
profile->needs_fcc_auth = 0;
dbg_time("Modem model %s does not require FCC authentication", profile->BaseBandVersion);
}
#endif
}
free(pResponse);
@ -2555,6 +2648,10 @@ const struct request_ops qmi_request_ops = {
#ifdef CONFIG_COEX_WWAN_STATE
.requestGetCoexWWANState = requestGetCoexWWANState,
#endif
#ifdef CONFIG_FOXCONN_FCC_AUTH
.requestFoxconnSetFccAuthentication = requestFoxconnSetFccAuthentication,
.requestFoxconnSetFccAuthenticationV2 = requestFoxconnSetFccAuthenticationV2,
#endif
};
#ifdef CONFIG_CELLINFO

View File

@ -20,6 +20,7 @@
//#define CONFIG_REG_QOS_IND
//#define CONFIG_GET_QOS_INFO
//#define CONFIG_GET_QOS_DATA_RATE
#define CONFIG_FOXCONN_FCC_AUTH
#if (defined(CONFIG_REG_QOS_IND) || defined(CONFIG_GET_QOS_INFO) || defined(CONFIG_GET_QOS_DATA_RATE))
#ifndef CONFIG_REG_QOS_IND
@ -344,7 +345,20 @@ struct request_ops {
int (*requestRegisterQos)(PROFILE_T *profile);
int (*requestGetQosInfo)(PROFILE_T *profile);
int (*requestGetCoexWWANState)(void);
#ifdef CONFIG_FOXCONN_FCC_AUTH
int (*requestFoxconnSetFccAuthentication)(UCHAR magic_value);
int (*requestFoxconnSetFccAuthenticationV2)(const char *magic_string, UCHAR magic_number);
#endif
};
// Add structure for V2 parameters
#ifdef CONFIG_FOXCONN_FCC_AUTH
typedef struct {
char magic_string[256];
UCHAR magic_number;
} FOXCONN_FCC_AUTH_V2_T;
#endif
extern const struct request_ops qmi_request_ops;
extern const struct request_ops mbim_request_ops;
extern const struct request_ops atc_request_ops;

View File

@ -325,6 +325,37 @@ static int qmi_main(PROFILE_T *profile)
if (request_ops->requestSetEthMode)
request_ops->requestSetEthMode(profile);
#ifdef CONFIG_FOXCONN_FCC_AUTH
// Only execute FCC authentication if the modem model requires it
if (profile->needs_fcc_auth) {
dbg_time("Executing FCC authentication for modem model: %s", profile->BaseBandVersion);
if (request_ops->requestFoxconnSetFccAuthentication) {
// Use magic value 0x01 as seen in libqmi
qmierr = request_ops->requestFoxconnSetFccAuthentication(0x01);
if (qmierr) {
dbg_time("Foxconn FCC Authentication failed with error: %d", qmierr);
} else {
dbg_time("Foxconn FCC Authentication successful");
}
}
if (request_ops->requestFoxconnSetFccAuthenticationV2) {
// Based on libqmi, use "FOXCONN" as magic string for Foxconn modems
const char *magic_string = "FOXCONN"; // Correct magic string for Foxconn
UCHAR magic_number = 0x01; // Standard magic number from libqmi
qmierr = request_ops->requestFoxconnSetFccAuthenticationV2(magic_string, magic_number);
if (qmierr) {
dbg_time("Foxconn FCC Authentication V2 failed with error: %d", qmierr);
} else {
dbg_time("Foxconn FCC Authentication V2 successful");
}
}
} else {
dbg_time("Skipping FCC authentication - not required for this modem model");
}
#endif
if (request_ops->requestSetLoopBackState && profile->loopback_state) {
qmierr = request_ops->requestSetLoopBackState(profile->loopback_state, profile->replication_factor);
if (qmierr != QMI_ERR_INVALID_QMI_CMD) //X20 return this error