From 33ed089d4b59bd79ae35f626ea6fc3da20c2edb9 Mon Sep 17 00:00:00 2001 From: Yevhen Mykhno Date: Thu, 9 Feb 2023 20:25:11 +0200 Subject: [GP-1597] mPower R.6.3.X: Cellular Provider Profiles - LTE Authentication --- src/MTS_IO_CellularRadio.cpp | 299 ++++++++++++++++++++++++++++++++++-------- src/MTS_IO_ICellularRadio.cpp | 11 ++ src/MTS_IO_QuectelRadio.cpp | 108 +++++++++++++++ src/MTS_IO_SequansRadio.cpp | 21 +++ src/MTS_IO_TelitRadio.cpp | 103 +++++++++++++++ 5 files changed, 489 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/MTS_IO_CellularRadio.cpp b/src/MTS_IO_CellularRadio.cpp index 3ce97ec..7200658 100644 --- a/src/MTS_IO_CellularRadio.cpp +++ b/src/MTS_IO_CellularRadio.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -1760,27 +1761,81 @@ ICellularRadio::CODE CellularRadio::sendBasicQuery(const std::string& sCmd, cons return SUCCESS; } +ICellularRadio::CODE CellularRadio::isCommandSupported(const std::string& sCmd, bool& bIsSupported) { + CODE rc; + bIsSupported = false; + + rc = sendBasicCommand(sCmd); + + if (SUCCESS == rc) { + bIsSupported = true; + } else if (ERROR == rc) { + // if not applicable + rc = SUCCESS; + } + + return rc; +} + ICellularRadio::CODE CellularRadio::getSelectedBandsRaw(std::string& sRawBands) { printTrace("%s| Acquiring selected bands: not applicable", m_sName.c_str()); return NOT_APPLICABLE; } -ICellularRadio::CODE CellularRadio::getPdpContexts(Json::Value& jData) { - printTrace("%s| Fetching the list of PDP contexts from the radio", getName().c_str()); +ICellularRadio::CODE CellularRadio::convertPdpContextAuthTypeToString(PDP_CONTEXT_AUTH_TYPE eAuthType, std::string& sAuthType) { + CODE rc = FAILURE; + + switch (eAuthType) { + case NONE: sAuthType = VALUE_PDP_CONTEXT_AUTH_TYPE_NONE; rc = SUCCESS; break; + case PAP: sAuthType = VALUE_PDP_CONTEXT_AUTH_TYPE_PAP; rc = SUCCESS; break; + case CHAP: sAuthType = VALUE_PDP_CONTEXT_AUTH_TYPE_CHAP; rc = SUCCESS; break; + case PAP_CHAP: sAuthType = VALUE_PDP_CONTEXT_AUTH_TYPE_PAP_CHAP; rc = SUCCESS; break; + default: sAuthType = ICellularRadio::VALUE_UNKNOWN; break; + } + return rc; +} + +ICellularRadio::CODE MTS::IO::CellularRadio::convertStringToPdpContextAuthType(const std::string& sAuthType, PDP_CONTEXT_AUTH_TYPE& eAuthType) { + CODE rc = FAILURE; + if (VALUE_PDP_CONTEXT_AUTH_TYPE_NONE == sAuthType) { + eAuthType = PDP_CONTEXT_AUTH_TYPE::NONE; + rc = SUCCESS; + } else if (VALUE_PDP_CONTEXT_AUTH_TYPE_PAP == sAuthType) { + eAuthType = PDP_CONTEXT_AUTH_TYPE::PAP; + rc = SUCCESS; + } else if (VALUE_PDP_CONTEXT_AUTH_TYPE_CHAP == sAuthType) { + eAuthType = PDP_CONTEXT_AUTH_TYPE::CHAP; + rc = SUCCESS; + } else if (VALUE_PDP_CONTEXT_AUTH_TYPE_PAP_CHAP == sAuthType) { + eAuthType = PDP_CONTEXT_AUTH_TYPE::PAP_CHAP; + rc = SUCCESS; + } + return rc; +} + +// When there are no defined contexts +// Telit returns: +// OK +// Quectel returns: +// +CGDCONT: +// +// OK +ICellularRadio::CODE CellularRadio::getPdpContextsBase(Json::Value& jData) { CODE rc; const std::string sCommand = "AT+CGDCONT?"; const int dTimeout = 1000; std::string sResult; + jData = Json::objectValue; + rc = sendBasicQuery(sCommand, "", sResult, dTimeout); if (rc != SUCCESS) { return rc; } - std::vector vContexts = MTS::Text::split(sResult, "+CGDCONT: "); - std::vector vContextParams; + std::vector vContexts = MTS::Text::split(sResult, "+CGDCONT:"); for (size_t i = 0; i < vContexts.size(); i++) { vContexts[i] = MTS::Text::trim(vContexts[i]); @@ -1789,7 +1844,7 @@ ICellularRadio::CODE CellularRadio::getPdpContexts(Json::Value& jData) { continue; } - vContextParams = MTS::Text::split(vContexts[i], ",", 4); + std::vector vContextParams = MTS::Text::split(vContexts[i], ",", 4); if (vContextParams.size() < 3) { return FAILURE; @@ -1806,78 +1861,216 @@ ICellularRadio::CODE CellularRadio::getPdpContexts(Json::Value& jData) { return SUCCESS; } -ICellularRadio::CODE CellularRadio::setPdpContext(const std::string& sId, const Json::Value& jConfig) { - printTrace("%s| Setting context to the radio", getName().c_str()); +ICellularRadio::CODE CellularRadio::getPdpContexts(Json::Value& jData) { + printTrace("%s| Fetching the list of PDP contexts from the radio", getName().c_str()); CODE rc; + bool bPdpAuthSupported; - if (sId.empty()) { - printError("%s| PDP Context ID is not specified", getName().c_str()); - return FAILURE; + // check if pdp context authentication is applicable + rc = isPdpContextAuthSupported(bPdpAuthSupported); + if (SUCCESS != rc) { + return rc; } - std::string sCommand = "AT+CGDCONT=" + sId; - const int dTimeout = 1000; - - Json::Value jAllContexts; + rc = getPdpContextsBase(jData); - rc = getPdpContexts(jAllContexts); - if (rc != SUCCESS) { - printError("%s| Failed to retrieve the current PDP context configuration: [%d]", getName().c_str(), rc); + if (SUCCESS != rc) { + printError("%s| Failed to fetch the list of the defined PDP contexts from the radio", getName().c_str()); return rc; } - // Remove the context if no parameters defined - if (!jConfig.isMember(ICellularRadio::KEY_PDP_CONTEXT_IPMODE) && !jConfig.isMember(ICellularRadio::KEY_PDP_CONTEXT_APN)) { - if (jAllContexts.isMember(sId)) { - rc = sendBasicCommand(sCommand, dTimeout); + if (bPdpAuthSupported) { + rc = fillPdpContextAuthFields(jData); + + if (SUCCESS != rc) { + printError("%s| Failed to fetch the authentication parameters for PDP contexts", getName().c_str()); return rc; - } else { - printError("%s| PDP Context [%s] does not exist", getName().c_str(), sId.c_str()); - return FAILURE; } } - std::string sIpMode; + return SUCCESS; +} - if (jConfig.isMember(ICellularRadio::KEY_PDP_CONTEXT_IPMODE)) { - if (jConfig[ICellularRadio::KEY_PDP_CONTEXT_IPMODE] == "IP" || jConfig[ICellularRadio::KEY_PDP_CONTEXT_IPMODE] == "PPP" || - jConfig[ICellularRadio::KEY_PDP_CONTEXT_IPMODE] == "IPV6" || jConfig[ICellularRadio::KEY_PDP_CONTEXT_IPMODE] == "IPV4V6") { - sIpMode = jConfig[ICellularRadio::KEY_PDP_CONTEXT_IPMODE].asString(); - } else { - printError("%s| Invalid IP Mode defined: [%s]", getName().c_str(), jConfig[ICellularRadio::KEY_PDP_CONTEXT_IPMODE].asString().c_str()); - return FAILURE; +ICellularRadio::CODE CellularRadio::mergePdpContexts(const std::string& sId, const Json::Value& jCurrentContext, const Json::Value& jChanges, Json::Value& jResult) { + jResult[KEY_PDP_CONTEXT_ID] = sId; + + if (jChanges.isMember(KEY_PDP_CONTEXT_IPMODE)) { + jResult[KEY_PDP_CONTEXT_IPMODE] = jChanges[KEY_PDP_CONTEXT_IPMODE].asString(); + } else if (jCurrentContext.isMember(KEY_PDP_CONTEXT_IPMODE)) { + printInfo("%s| Re-using IP Mode [%s] for PDP context [%s]", getName().c_str(), jCurrentContext[KEY_PDP_CONTEXT_IPMODE].asString().c_str(), sId.c_str()); + jResult[KEY_PDP_CONTEXT_IPMODE] = jCurrentContext[KEY_PDP_CONTEXT_IPMODE].asString(); + } + + if (jChanges.isMember(KEY_PDP_CONTEXT_APN)) { + jResult[KEY_PDP_CONTEXT_APN] = jChanges[KEY_PDP_CONTEXT_APN].asString(); + } else if (jCurrentContext.isMember(KEY_PDP_CONTEXT_APN)) { + printInfo("%s| Re-using APN [%s] for PDP context [%s]", getName().c_str(), jCurrentContext[KEY_PDP_CONTEXT_APN].asString().c_str(), sId.c_str()); + jResult[KEY_PDP_CONTEXT_APN] = jCurrentContext[KEY_PDP_CONTEXT_APN].asString(); + } + + if (jChanges.isMember(KEY_PDP_CONTEXT_AUTH_TYPE)) { + jResult[KEY_PDP_CONTEXT_AUTH_TYPE] = jChanges[KEY_PDP_CONTEXT_AUTH_TYPE].asString(); + } + + if (jChanges.isMember(KEY_PDP_CONTEXT_AUTH_USERNAME)) { + jResult[KEY_PDP_CONTEXT_AUTH_USERNAME] = jChanges[KEY_PDP_CONTEXT_AUTH_USERNAME].asString(); + } + + if (jChanges.isMember(KEY_PDP_CONTEXT_AUTH_PASSWORD)) { + jResult[KEY_PDP_CONTEXT_AUTH_PASSWORD] = jChanges[KEY_PDP_CONTEXT_AUTH_PASSWORD].asString(); + } + + return SUCCESS; +} + +ICellularRadio::CODE CellularRadio::initPdpContextInfo(const Json::Value& jConfig, PdpContextInfo& pdpContextResult) { + // validate IP mode + if (jConfig[KEY_PDP_CONTEXT_IPMODE].asString() != VALUE_PDP_CONTEXT_IP_MODE_IP && + jConfig[KEY_PDP_CONTEXT_IPMODE].asString() != VALUE_PDP_CONTEXT_IP_MODE_IPV6 && + jConfig[KEY_PDP_CONTEXT_IPMODE].asString() != VALUE_PDP_CONTEXT_IP_MODE_IPV4V6) { + printError("%s| The PDP context IP mode value is invalid [%s]", getName().c_str(), jConfig[KEY_PDP_CONTEXT_IPMODE].asString().c_str()); + return INVALID_ARGS; + } + + // validate authentication fields only if it is present + if (jConfig.isMember(KEY_PDP_CONTEXT_AUTH_TYPE)) { + + // check if the PDP context authentication is supported by the radio + const auto& sRequested = jConfig[KEY_PDP_CONTEXT_AUTH_TYPE].asString(); + const auto& vSupported = getSupportedPdpContextAuthTypes(); + + auto supportCheck = [sRequested](const std::string& sElement) { + return sRequested == sElement; + }; + + if (std::none_of(vSupported.begin(), vSupported.end(), supportCheck)) { + printError("%s| PDP context parameters: authentication type [%s] is not supported", getName().c_str(), jConfig[KEY_PDP_CONTEXT_AUTH_TYPE].asString().c_str()); + return INVALID_ARGS; } - } else if (jAllContexts.isMember(sId)) { - printInfo("%s| Re-using IP Mode [%s] for PDP context [%s]", getName().c_str(), jAllContexts[sId][ICellularRadio::KEY_PDP_CONTEXT_IPMODE].asString().c_str(), sId.c_str()); - sIpMode = jAllContexts[sId][ICellularRadio::KEY_PDP_CONTEXT_IPMODE].asString(); - } else { - printError("%s| Failed to edit PDP context [%s] - no such context defined", getName().c_str(), sId.c_str()); - return FAILURE; } - sCommand += ",\""; - sCommand += sIpMode; - sCommand += "\""; + if (! jConfig.isMember(KEY_PDP_CONTEXT_AUTH_TYPE) && (jConfig.isMember(KEY_PDP_CONTEXT_AUTH_USERNAME) || jConfig.isMember(KEY_PDP_CONTEXT_AUTH_PASSWORD))) { + printError("%s| PDP context authentication type is not provided, but username or password are given", getName().c_str()); + return INVALID_ARGS; + } - std::string sApn; + if (jConfig.isMember(KEY_PDP_CONTEXT_AUTH_TYPE) && jConfig[KEY_PDP_CONTEXT_AUTH_TYPE].asString() != VALUE_PDP_CONTEXT_AUTH_TYPE_NONE && + ! (jConfig.isMember(KEY_PDP_CONTEXT_AUTH_USERNAME) && jConfig.isMember(KEY_PDP_CONTEXT_AUTH_PASSWORD))) { + printError("%s| PDP context authentication type [%s]. The username or password are not provided", getName().c_str(), jConfig[KEY_PDP_CONTEXT_AUTH_TYPE].asString().c_str()); + return INVALID_ARGS; + } - if (jConfig.isMember(ICellularRadio::KEY_PDP_CONTEXT_APN)) { - sApn = jConfig[ICellularRadio::KEY_PDP_CONTEXT_APN].asString(); - } else if (jAllContexts.isMember(sId)) { - printInfo("%s| Re-using APN [%s] for PDP context [%s]", getName().c_str(), jAllContexts[sId][ICellularRadio::KEY_PDP_CONTEXT_APN].asString().c_str(), sId.c_str()); - sApn = jAllContexts[sId][ICellularRadio::KEY_PDP_CONTEXT_APN].asString(); - } else { - printError("%s| Failed to edit PDP context [%s] - no such context defined", getName().c_str(), sId.c_str()); - return FAILURE; + // fills with empty string if there are no such fields + pdpContextResult.sId = jConfig[KEY_PDP_CONTEXT_ID].asString(); + pdpContextResult.sIpMode = jConfig[KEY_PDP_CONTEXT_IPMODE].asString(); + pdpContextResult.sApn = jConfig[KEY_PDP_CONTEXT_APN].asString(); + pdpContextResult.sAuthType = jConfig[KEY_PDP_CONTEXT_AUTH_TYPE].asString(); + pdpContextResult.sUsername = jConfig[KEY_PDP_CONTEXT_AUTH_USERNAME].asString(); + pdpContextResult.sPassword = jConfig[KEY_PDP_CONTEXT_AUTH_PASSWORD].asString(); + + return SUCCESS; +} + +ICellularRadio::CODE CellularRadio::isPdpContextAuthEditRequired(const Json::Value& jConfig, bool& bIsAuthEditRequired) { + bIsAuthEditRequired = false; + + if (jConfig.isMember(KEY_PDP_CONTEXT_AUTH_TYPE) || + jConfig.isMember(KEY_PDP_CONTEXT_AUTH_PASSWORD) || + jConfig.isMember(KEY_PDP_CONTEXT_AUTH_USERNAME)) { + bIsAuthEditRequired = true; } + return SUCCESS; +} + +ICellularRadio::CODE CellularRadio::setPdpContextBase(const PdpContextInfo& pdpContext) { + std::string sCommand = "AT+CGDCONT="; + const int dTimeout = 1000; + + sCommand += pdpContext.sId; sCommand += ",\""; - sCommand += sApn; + sCommand += pdpContext.sIpMode; + sCommand += "\",\""; + sCommand += pdpContext.sApn; sCommand += "\""; - rc = sendBasicCommand(sCommand, dTimeout); + return sendBasicCommand(sCommand, dTimeout); +} + +ICellularRadio::CODE CellularRadio::deletePdpContext(const std::string& sId) { + std::string sCommand = "AT+CGDCONT=" + sId; + const int dTimeout = 1000; - return rc; + return sendBasicCommand(sCommand, dTimeout); +} + +ICellularRadio::CODE CellularRadio::setPdpContext(const std::string& sId, const Json::Value& jConfig) { + printTrace("%s| Setting PDP context [%s] to the radio", getName().c_str(), sId.c_str()); + + CODE rc; + Json::Value jCurrentContexts; + bool bPdpAuthSupported; + bool bPdpAuthEditRequired; + PdpContextInfo pdpContext; + + if (sId.empty()) { + printError("%s| PDP Context ID is not specified", getName().c_str()); + return INVALID_ARGS; + } + + rc = getPdpContexts(jCurrentContexts); + if (SUCCESS != rc) { + return rc; + } + + // DELETE context + + if (jConfig.empty()) { + rc = deletePdpContext(sId); + if (SUCCESS != rc) { + printError("%s| Failed to delete PDP context [%s]", getName().c_str(), sId.c_str()); + } + return rc; + } + + // ADD or EDIT context + + // check if PDP context authentication is applicable + + (void) isPdpContextAuthEditRequired(jConfig, bPdpAuthEditRequired); + + rc = isPdpContextAuthSupported(bPdpAuthSupported); + if (SUCCESS != rc) { + return rc; + } + + if (! bPdpAuthSupported && bPdpAuthEditRequired) { + printError("%s| PDP context authentication is not supported by this radio, but arguments are provided", getName().c_str()); + return INVALID_ARGS; + } + + Json::Value jResult; + + // Edit - fetch missing arguments from the current state. + (void) mergePdpContexts(sId, jCurrentContexts[sId], jConfig, jResult); + + // validate fields and create a PDP context structure to use in the commands + rc = initPdpContextInfo(jResult, pdpContext); + if (SUCCESS != rc) { + return rc; + } + + // setting context + rc = setPdpContextBase(pdpContext); + if (SUCCESS != rc) { + return rc; + } + + if (bPdpAuthSupported && bPdpAuthEditRequired) { + return setPdpContextAuth(pdpContext); + } + + return SUCCESS; } ICellularRadio::CODE CellularRadio::getDiagnostics(std::string& sReport) { diff --git a/src/MTS_IO_ICellularRadio.cpp b/src/MTS_IO_ICellularRadio.cpp index e42713d..f93cb21 100644 --- a/src/MTS_IO_ICellularRadio.cpp +++ b/src/MTS_IO_ICellularRadio.cpp @@ -97,8 +97,19 @@ const char *MTS::IO::ICellularRadio::KEY_MIP_REVTUN = "revTun"; const char *MTS::IO::ICellularRadio::KEY_MIP_MNAAASS = "mnAaaSs"; //!< Mobile Node Authentication, Authorization, and Accounting Server Shared Secret const char *MTS::IO::ICellularRadio::KEY_MIP_MNHASS = "mnHaSs"; //!< Mobile Node Home Agent Shared Secret +const char *MTS::IO::ICellularRadio::KEY_PDP_CONTEXT_ID = "id"; const char *MTS::IO::ICellularRadio::KEY_PDP_CONTEXT_APN = "apn"; const char *MTS::IO::ICellularRadio::KEY_PDP_CONTEXT_IPMODE = "ipMode"; +const char *MTS::IO::ICellularRadio::KEY_PDP_CONTEXT_AUTH_TYPE = "authType"; +const char *MTS::IO::ICellularRadio::KEY_PDP_CONTEXT_AUTH_USERNAME = "username"; +const char *MTS::IO::ICellularRadio::KEY_PDP_CONTEXT_AUTH_PASSWORD = "password"; +const char *MTS::IO::ICellularRadio::VALUE_PDP_CONTEXT_IP_MODE_IP = "IP"; +const char *MTS::IO::ICellularRadio::VALUE_PDP_CONTEXT_IP_MODE_IPV6 = "IPV6"; +const char *MTS::IO::ICellularRadio::VALUE_PDP_CONTEXT_IP_MODE_IPV4V6 = "IPV4V6"; +const char *MTS::IO::ICellularRadio::VALUE_PDP_CONTEXT_AUTH_TYPE_NONE = "NONE"; +const char *MTS::IO::ICellularRadio::VALUE_PDP_CONTEXT_AUTH_TYPE_PAP = "PAP"; +const char *MTS::IO::ICellularRadio::VALUE_PDP_CONTEXT_AUTH_TYPE_CHAP = "CHAP"; +const char *MTS::IO::ICellularRadio::VALUE_PDP_CONTEXT_AUTH_TYPE_PAP_CHAP = "PAP-CHAP"; const char *MTS::IO::ICellularRadio::VALUE_TYPE_GSM = "GSM"; const char *MTS::IO::ICellularRadio::VALUE_TYPE_LTE = "LTE"; diff --git a/src/MTS_IO_QuectelRadio.cpp b/src/MTS_IO_QuectelRadio.cpp index 0c0c8ab..b01bbb1 100644 --- a/src/MTS_IO_QuectelRadio.cpp +++ b/src/MTS_IO_QuectelRadio.cpp @@ -1629,6 +1629,114 @@ ICellularRadio::CODE QuectelRadio::setRxDiversity(const Json::Value& jArgs) { return SUCCESS; } +ICellularRadio::CODE QuectelRadio::convertStringToPdpContextType(const std::string& sStringType, std::string& sIntType) { + CODE rc = FAILURE; + + if ("IP" == sStringType) { + sIntType = "1"; + rc = SUCCESS; + } else if ("IPV6" == sStringType) { + sIntType = "2"; + rc = SUCCESS; + } else if ("IPV4V6" == sStringType) { + sIntType = "3"; + rc = SUCCESS; + } + + return rc; +} + +std::vector QuectelRadio::getSupportedPdpContextAuthTypes() const { + return { + VALUE_PDP_CONTEXT_AUTH_TYPE_NONE, + VALUE_PDP_CONTEXT_AUTH_TYPE_PAP, + VALUE_PDP_CONTEXT_AUTH_TYPE_CHAP, + VALUE_PDP_CONTEXT_AUTH_TYPE_PAP_CHAP + }; +} + +ICellularRadio::CODE QuectelRadio::isPdpContextAuthSupported(bool& isSupported) { + std::string sCmd("AT+QICSGP=?"); + return isCommandSupported(sCmd, isSupported); +} + +ICellularRadio::CODE QuectelRadio::fillPdpContextAuthFields(Json::Value& jData) { + CODE rc; + std::string sCmd("AT+QICSGP="); + std::string sResult; + uint8_t iValue; + + // iterate over PDP contex IDs to get context settings + for (std::string & sContextId : jData.getMemberNames()) { + // +QICSGP: ,,,, + // +QICSGP: 0,"","","",0 -- if the context does not exist + + rc = sendBasicQuery(sCmd+sContextId, "+QICSGP:", sResult, 300); + + if (SUCCESS != rc) { + return rc; + } + + // 1,"test","login","password",1 + // [0] [1] [2] [3] [4] + auto vAuthParams = MTS::Text::split(sResult, ","); + + if (vAuthParams.size() < 5) { + printError("%s| Failed to parse PDP context authentication string [%s]", getName().c_str(), sResult.c_str()); + return FAILURE; + } + + if (! MTS::Text::parse(iValue, vAuthParams[4])) { + printError("%s| Failed to parse PDP context authentication type [%s]", getName().c_str(), vAuthParams[4].c_str()); + return FAILURE; + } + + rc = convertPdpContextAuthTypeToString(static_cast(iValue), sResult); + if (SUCCESS != rc) { + return rc; + } + + jData[sContextId][KEY_PDP_CONTEXT_AUTH_TYPE] = sResult; + + if (iValue != PDP_CONTEXT_AUTH_TYPE::NONE) { + jData[sContextId][KEY_PDP_CONTEXT_AUTH_USERNAME] = MTS::Text::trim(vAuthParams[2], '"'); + jData[sContextId][KEY_PDP_CONTEXT_AUTH_PASSWORD] = MTS::Text::trim(vAuthParams[3], '"'); + } + } + + return SUCCESS; +} + +// AT+QICSGP=[,,[,,)[,[,]]]] +ICellularRadio::CODE QuectelRadio::setPdpContextAuth(const PdpContextInfo& pdpContext) { + printTrace("%s| Setting PDP context authentication to the radio", getName().c_str()); + + CODE rc; + std::string sContextType; + std::string sCmd = "AT+QICSGP="; + PDP_CONTEXT_AUTH_TYPE eAuthType; + + rc = convertStringToPdpContextType(pdpContext.sIpMode, sContextType); + if (SUCCESS != rc) { + return rc; + } + + rc = convertStringToPdpContextAuthType(pdpContext.sAuthType, eAuthType); + if (SUCCESS != rc) { + return rc; + } + + sCmd += pdpContext.sId + "," + sContextType + ",\"" + pdpContext.sApn + "\""; + + if (PDP_CONTEXT_AUTH_TYPE::NONE == eAuthType) { + sCmd += ",\"\",\"\"," + std::to_string(eAuthType); + } else { + sCmd += ",\"" + pdpContext.sUsername + "\",\"" + pdpContext.sPassword +"\"," + std::to_string(eAuthType); + } + + return sendBasicCommand(sCmd); +} + const std::vector& QuectelRadio::getDiagCommands(bool) { // Declare as static to initialize only when used, but cache the results. const static std::vector vCommands { diff --git a/src/MTS_IO_SequansRadio.cpp b/src/MTS_IO_SequansRadio.cpp index a48a309..8133bbf 100644 --- a/src/MTS_IO_SequansRadio.cpp +++ b/src/MTS_IO_SequansRadio.cpp @@ -534,6 +534,27 @@ ICellularRadio::CODE SequansRadio::getSimLockAttemptsByType(const std::string& s return SUCCESS; } +std::vector SequansRadio::getSupportedPdpContextAuthTypes() const { + return { + VALUE_PDP_CONTEXT_AUTH_TYPE_NONE, + VALUE_PDP_CONTEXT_AUTH_TYPE_PAP, + VALUE_PDP_CONTEXT_AUTH_TYPE_CHAP + }; +} + +ICellularRadio::CODE SequansRadio::isPdpContextAuthSupported(bool& isSupported) { + isSupported = false; + return SUCCESS; +} + +ICellularRadio::CODE SequansRadio::fillPdpContextAuthFields(Json::Value& jData) { + return NOT_APPLICABLE; +} + +ICellularRadio::CODE SequansRadio::setPdpContextAuth(const PdpContextInfo& pdpContext) { + return NOT_APPLICABLE; +} + const std::vector& SequansRadio::getDiagCommands(bool) { // Declare as static to initialize only when used, but cache the results. const static std::vector vCommands { diff --git a/src/MTS_IO_TelitRadio.cpp b/src/MTS_IO_TelitRadio.cpp index 21af65d..00c1686 100644 --- a/src/MTS_IO_TelitRadio.cpp +++ b/src/MTS_IO_TelitRadio.cpp @@ -1178,6 +1178,109 @@ bool MTS::IO::TelitRadio::isContainsSignChar(const std::string& str) { return true; } +std::vector TelitRadio::getSupportedPdpContextAuthTypes() const { + return { + VALUE_PDP_CONTEXT_AUTH_TYPE_NONE, + VALUE_PDP_CONTEXT_AUTH_TYPE_PAP, + VALUE_PDP_CONTEXT_AUTH_TYPE_CHAP + }; +} + +ICellularRadio::CODE TelitRadio::isPdpContextAuthSupported(bool& isSupported) { + std::string sCmd("AT#PDPAUTH=?"); + return isCommandSupported(sCmd, isSupported); +} + +ICellularRadio::CODE TelitRadio::fillPdpContextAuthFields(Json::Value& jData) { + CODE rc; + std::string sCmd("AT#PDPAUTH?"); + std::string sResult; + + // #PDPAUTH: 1,0 + // #PDPAUTH: 2,0 + // #PDPAUTH: 3,0 + // #PDPAUTH: 4,1,"admin" + rc = sendBasicQuery(sCmd, "", sResult, 300); + + if (SUCCESS != rc) { + return rc; + } + + std::vector vContexts = MTS::Text::split(sResult, "#PDPAUTH:"); + std::string sContextId; + + for (std::string& sLine : vContexts) { + sLine = MTS::Text::trim(sLine); + + if (sLine.empty()) { + continue; + } + + // 4,1,"admin" + // [0][1] [2] + auto vAuthParams = MTS::Text::split(sLine, ","); + + // Contains 2 elements when the authentication type is NONE, contains 3 elements in other cases + if (vAuthParams.size() < 2) { + printError("%s| Failed to parse PDP context authentication string [%s]", getName().c_str(), sLine.c_str()); + return FAILURE; + } + + sContextId = vAuthParams[0]; + + uint8_t iValue; + if (! MTS::Text::parse(iValue, vAuthParams[1])) { + printError("%s| Failed to parse PDP context authentication type [%s]", getName().c_str(), vAuthParams[1].c_str()); + return FAILURE; + } + + rc = convertPdpContextAuthTypeToString(static_cast(iValue), sResult); + if (SUCCESS != rc) { + printError("%s| Failed to convert PDP context authentication type to string [%d]", getName().c_str(), iValue); + return rc; + } + + jData[sContextId][KEY_PDP_CONTEXT_AUTH_TYPE] = sResult; + + if (iValue == PDP_CONTEXT_AUTH_TYPE::NONE) { + continue; + } + + if (vAuthParams.size() < 3) { + printError("%s| Failed to parse PDP context authentication string [%s]", getName().c_str(), sLine.c_str()); + return FAILURE; + } + + jData[sContextId][KEY_PDP_CONTEXT_AUTH_USERNAME] = MTS::Text::trim(vAuthParams[2], '"'); + } + + return SUCCESS; +} + +ICellularRadio::CODE TelitRadio::setPdpContextAuth(const PdpContextInfo& pdpContext) { + printTrace("%s| Setting PDP context authentication to the radio", getName().c_str()); + + CODE rc; + std::string sCmd = "AT#PDPAUTH="; + PDP_CONTEXT_AUTH_TYPE eAuthType; + + sCmd += pdpContext.sId + ","; + + rc = convertStringToPdpContextAuthType(pdpContext.sAuthType, eAuthType); + + if (SUCCESS != rc) { + return rc; + } + + sCmd += std::to_string(eAuthType); + + if (PDP_CONTEXT_AUTH_TYPE::NONE != eAuthType) { + sCmd += "," + pdpContext.sUsername + "," + pdpContext.sPassword; + } + + return sendBasicCommand(sCmd); +} + const std::vector& TelitRadio::getDiagCommands(bool) { // Declare as static to initialize only when used, but cache the results. const static std::vector vCommands { -- cgit v1.2.3