~aleteoryx/muditaos

c19d38e5ba764b05f7f2e2ab5fe7d366c64982a0 — Kuba Kleczkowski 3 years ago 1c96ab6
[MOS-816] Add parse and filter IMSI

Added reading IMSI and parsing US MCC and MNC.
MCC and MNC are filterd if they are TMobile US.
M module-services/service-cellular/CMakeLists.txt => module-services/service-cellular/CMakeLists.txt +7 -1
@@ 15,7 15,13 @@ set(SOURCES
    src/URCCounter.cpp
    src/VolteHandlerImpl.cpp
    src/CSQHandler.cpp
        DTMFCode.cpp

    src/volte/VolteCapabilityHandler.cpp
    src/volte/ImsiParserUS.cpp
    src/volte/VolteAllowedUSList.cpp
    src/volte/VolteCapabilityHandlerCellular.cpp

    DTMFCode.cpp

    CellularServiceAPI.cpp
    CellularUrcHandler.cpp

M module-services/service-cellular/src/ServiceCellularPriv.cpp => module-services/service-cellular/src/ServiceCellularPriv.cpp +12 -3
@@ 8,6 8,10 @@
#include <service-cellular-api>
#include <service-cellular/Constans.hpp>

#include <volte/ImsiParserUS.hpp>
#include <volte/VolteAllowedUSList.hpp>
#include <volte/VolteCapabilityHandlerCellular.hpp>

#include <service-evtmgr/EVMessages.hpp>
#include <service-evtmgr/Constants.hpp>



@@ 38,9 42,14 @@ namespace cellular::internal
          imeiGetHandler{std::make_unique<service::ImeiGetHandler>()},
          tetheringHandler{std::make_unique<TetheringHandler>()},
          volteHandler{std::make_unique<VolteHandler<DLCChannel, ModemResponseParserImpl>>()},
          modemResetHandler{std::make_unique<ModemResetHandler>()}, csqHandler{
                                                                        std::make_unique<CSQHandler>(),
                                                                    }
          modemResetHandler{std::make_unique<ModemResetHandler>()},
          csqHandler{
              std::make_unique<CSQHandler>(),
          },
          volteCapability{
              std::make_unique<VolteCapabilityHandler>(std::make_unique<cellular::service::ImsiParserUS>(),
                                                       std::make_unique<cellular::service::VolteAllowedUSList>(),
                                                       std::make_unique<cellular::service::VolteCapabilityCellular>())}
    {
        initSimCard();
        initSMSSendHandler();

M module-services/service-cellular/src/ServiceCellularPriv.hpp => module-services/service-cellular/src/ServiceCellularPriv.hpp +3 -0
@@ 16,6 16,7 @@
#include "VolteHandlerImpl.hpp"
#include "ModemResetHandler.hpp"
#include "CSQHandler.hpp"
#include "volte/VolteCapabilityHandler.hpp"

namespace cellular::internal
{


@@ 26,6 27,7 @@ namespace cellular::internal
    using service::SimContacts;
    using service::State;
    using service::TetheringHandler;
    using service::VolteCapabilityHandler;
    using service::VolteHandler;

    class ServiceCellularPriv


@@ 42,6 44,7 @@ namespace cellular::internal
        std::unique_ptr<VolteHandler<DLCChannel, ModemResponseParserImpl>> volteHandler;
        std::unique_ptr<ModemResetHandler> modemResetHandler;
        std::unique_ptr<CSQHandler> csqHandler;
        std::unique_ptr<VolteCapabilityHandler> volteCapability;

        State::PowerState nextPowerState = State::PowerState::Off;
        std::uint8_t multiPartSMSUID     = 0;

A module-services/service-cellular/src/volte/ImsiParserInterface.hpp => module-services/service-cellular/src/volte/ImsiParserInterface.hpp +19 -0
@@ 0,0 1,19 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "OperatorInfo.hpp"
#include <string>
#include <optional>

namespace cellular::service
{
    class ImsiParserInteface
    {
      public:
        virtual ~ImsiParserInteface() = default;

        virtual auto parse(const std::string &imsi) -> std::optional<OperatorInfo> = 0;
    };
} // namespace cellular::service

A module-services/service-cellular/src/volte/ImsiParserUS.cpp => module-services/service-cellular/src/volte/ImsiParserUS.cpp +37 -0
@@ 0,0 1,37 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ImsiParserUS.hpp"
#include <log/log.hpp>
#include <array>
#include <algorithm>
#include <stdexcept>

namespace cellular::service
{
    constexpr auto usMccCount = 7;
    const std::array<std::string, usMccCount> usMcc{"310", "311", "312", "313", "314", "315", "316"};

    auto ImsiParserUS::parse(const std::string &imsi) -> std::optional<OperatorInfo>
    {
        constexpr auto mccSize = 3;
        constexpr auto mncSize = 3;

        std::string mcc, mnc;
        try {
            mcc = imsi.substr(0, mccSize);
            mnc = imsi.substr(mccSize, mncSize);
        }
        catch (const std::out_of_range &e) {
            LOG_ERROR("IMSI parsing error: %s", e.what());
            return std::nullopt;
        }

        if (std::find(std::begin(usMcc), std::end(usMcc), mcc) == std::end(usMcc)) {
            LOG_ERROR("Not US MCC.");
            return std::nullopt;
        }

        return OperatorInfo(mcc, mnc);
    }
} // namespace cellular::service

A module-services/service-cellular/src/volte/ImsiParserUS.hpp => module-services/service-cellular/src/volte/ImsiParserUS.hpp +15 -0
@@ 0,0 1,15 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "ImsiParserInterface.hpp"

namespace cellular::service
{
    class ImsiParserUS : public ImsiParserInteface
    {
      public:
        auto parse(const std::string &imsi) -> std::optional<OperatorInfo> final;
    };
} // namespace cellular::service

A module-services/service-cellular/src/volte/OperatorInfo.hpp => module-services/service-cellular/src/volte/OperatorInfo.hpp +22 -0
@@ 0,0 1,22 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <string>

namespace cellular::service
{
    struct OperatorInfo
    {
        OperatorInfo(const std::string &mcc, const std::string &mnc) : MCC(mcc), MNC(mnc)
        {}
        std::string MCC;
        std::string MNC;

        friend bool operator==(const OperatorInfo &lhs, const OperatorInfo &rhs)
        {
            return lhs.MCC == rhs.MCC && lhs.MNC == rhs.MNC;
        }
    };
} // namespace cellular::service

A module-services/service-cellular/src/volte/VolteAllowedListInterface.hpp => module-services/service-cellular/src/volte/VolteAllowedListInterface.hpp +18 -0
@@ 0,0 1,18 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "OperatorInfo.hpp"
#include <string>

namespace cellular::service
{
    class VolteAllowedListInterface
    {
      public:
        virtual ~VolteAllowedListInterface() = default;

        auto virtual isVolteAllowed(const OperatorInfo &operatorInfo) -> bool = 0;
    };
} // namespace cellular::service

A module-services/service-cellular/src/volte/VolteAllowedUSList.cpp => module-services/service-cellular/src/volte/VolteAllowedUSList.cpp +37 -0
@@ 0,0 1,37 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "VolteAllowedUSList.hpp"
#include <log/log.hpp>
#include <array>
#include <algorithm>

namespace cellular::service
{

    constexpr auto allowedOperatorsCount = 12;
    const std::array<OperatorInfo, allowedOperatorsCount> allowedOperators{OperatorInfo{"310", "053"},
                                                                           OperatorInfo{"310", "120"},
                                                                           OperatorInfo{"310", "260"},
                                                                           OperatorInfo{"310", "530"},
                                                                           OperatorInfo{"310", "770"},
                                                                           OperatorInfo{"311", "490"},
                                                                           OperatorInfo{"311", "660"},
                                                                           OperatorInfo{"311", "880"},
                                                                           OperatorInfo{"311", "882"},
                                                                           OperatorInfo{"312", "190"},
                                                                           OperatorInfo{"312", "250"},
                                                                           OperatorInfo{"312", "530"}};

    auto VolteAllowedUSList::isVolteAllowed(const OperatorInfo &operatorInfo) -> bool
    {
        LOG_INFO("Trying to find MCC: %s, MNC: %s", operatorInfo.MCC.c_str(), operatorInfo.MNC.c_str());

        if (std::find(std::begin(allowedOperators), std::end(allowedOperators), operatorInfo) ==
            std::end(allowedOperators)) {
            LOG_ERROR("Unable to find. VoLTE not allowed.");
            return false;
        }
        return true;
    }
} // namespace cellular::service

A module-services/service-cellular/src/volte/VolteAllowedUSList.hpp => module-services/service-cellular/src/volte/VolteAllowedUSList.hpp +16 -0
@@ 0,0 1,16 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "VolteAllowedListInterface.hpp"
#include "OperatorInfo.hpp"

namespace cellular::service
{
    class VolteAllowedUSList : public VolteAllowedListInterface
    {
      public:
        auto isVolteAllowed(const OperatorInfo &operatorInfo) -> bool final;
    };
} // namespace cellular::service

A module-services/service-cellular/src/volte/VolteCapabilityHandler.cpp => module-services/service-cellular/src/volte/VolteCapabilityHandler.cpp +43 -0
@@ 0,0 1,43 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "VolteCapabilityHandler.hpp"
#include <modem/mux/CellularMux.h>
#include <log/log.hpp>
namespace cellular::service
{
    VolteCapabilityHandler::VolteCapabilityHandler(std::unique_ptr<ImsiParserInteface> imsiParser,
                                                   std::unique_ptr<VolteAllowedListInterface> allowedList,
                                                   std::unique_ptr<VolteCapabilityCellularInterface> cellularInterface)
        : imsiParser(std::move(imsiParser)), allowedList(std::move(allowedList)),
          cellularInterface(std::move(cellularInterface))
    {}

    void VolteCapabilityHandler::setChannel(at::BaseChannel *channel)
    {
        if (cellularInterface.get() != nullptr) {
            cellularInterface->setChannel(channel);
        }
    }

    auto VolteCapabilityHandler::isVolteAllowed() -> bool
    {
        const auto imsi = cellularInterface->getImsi();
        if (not imsi.has_value()) {
            LOG_ERROR("Failed to read IMSI, disable VoLTE.");
            return false;
        }

        const auto operatorInfo = imsiParser->parse(imsi.value());
        if (not operatorInfo.has_value()) {
            LOG_ERROR("Failed to parse IMSI, disable VoLTE.");
            return false;
        }
        return allowedList->isVolteAllowed(operatorInfo.value());
    }

    auto VolteCapabilityHandler::isCellularInterfaceReady() -> bool
    {
        return cellularInterface.get() != nullptr;
    }
} // namespace cellular::service

A module-services/service-cellular/src/volte/VolteCapabilityHandler.hpp => module-services/service-cellular/src/volte/VolteCapabilityHandler.hpp +43 -0
@@ 0,0 1,43 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "VolteCapabiltyHandlerCellularInterface.hpp"
#include "ImsiParserInterface.hpp"
#include "VolteAllowedListInterface.hpp"

#include <memory>
#include <vector>

namespace at
{
    class Result;
    class BaseChannel;
} // namespace at

namespace cellular::service
{
    class VolteCapabilityHandler
    {
      public:
        VolteCapabilityHandler(std::unique_ptr<ImsiParserInteface> imsiParser,
                               std::unique_ptr<VolteAllowedListInterface> allowedList,
                               std::unique_ptr<VolteCapabilityCellularInterface> cellularInterface);
        /** Set AT command channel
         * \param channel channel (or nullptr to block communication):
         */
        void setChannel(at::BaseChannel *channel);
        /** Check if it is a possibility to enable VoLTE on current operator
         * @return true when VoLTE is allowed, false when not
         */
        auto isVolteAllowed() -> bool;

      private:
        std::unique_ptr<ImsiParserInteface> imsiParser;
        std::unique_ptr<VolteAllowedListInterface> allowedList;
        std::unique_ptr<VolteCapabilityCellularInterface> cellularInterface;

        auto isCellularInterfaceReady() -> bool;
    };
} // namespace cellular::service

A module-services/service-cellular/src/volte/VolteCapabilityHandlerCellular.cpp => module-services/service-cellular/src/volte/VolteCapabilityHandlerCellular.cpp +29 -0
@@ 0,0 1,29 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "VolteCapabilityHandlerCellular.hpp"
#include <modem/mux/CellularMux.h>

namespace cellular::service
{
    void VolteCapabilityCellular::setChannel(at::BaseChannel *channel)
    {
        this->channel = channel;
    }

    auto VolteCapabilityCellular::getImsi() -> std::optional<std::string>
    {
        if (channel == nullptr) {
            LOG_ERROR("No channel provided. Request ignored");
            return std::nullopt;
        }

        auto result = channel->cmd(at::AT::CIMI);
        if (not result) {
            LOG_ERROR("Failed to read IMSI, disable VoLTE.");
            return std::nullopt;
        }

        return result.response[0];
    }
} // namespace cellular::service

A module-services/service-cellular/src/volte/VolteCapabilityHandlerCellular.hpp => module-services/service-cellular/src/volte/VolteCapabilityHandlerCellular.hpp +29 -0
@@ 0,0 1,29 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "VolteCapabiltyHandlerCellularInterface.hpp"

#include <optional>
#include <string>

namespace at
{
    class Result;
    class BaseChannel;
} // namespace at

namespace cellular::service
{

    class VolteCapabilityCellular : public VolteCapabilityCellularInterface
    {
      public:
        void setChannel(at::BaseChannel *channel) final;
        auto getImsi() -> std::optional<std::string> final;

      private:
        at::BaseChannel *channel = nullptr;
    };
} // namespace cellular::service

A module-services/service-cellular/src/volte/VolteCapabiltyHandlerCellularInterface.hpp => module-services/service-cellular/src/volte/VolteCapabiltyHandlerCellularInterface.hpp +25 -0
@@ 0,0 1,25 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <optional>
#include <string>

namespace at
{
    class Result;
    class BaseChannel;
} // namespace at

namespace cellular::service
{

    class VolteCapabilityCellularInterface
    {
      public:
        virtual ~VolteCapabilityCellularInterface()          = default;
        virtual void setChannel(at::BaseChannel *channel)    = 0;
        virtual auto getImsi() -> std::optional<std::string> = 0;
    };
} // namespace cellular::service

M module-services/service-cellular/tests/CMakeLists.txt => module-services/service-cellular/tests/CMakeLists.txt +9 -0
@@ 113,3 113,12 @@ add_catch2_executable(
        module-cellular
        module-utils
)

add_catch2_executable(
        NAME
        cellular-volte-capability-handler
        SRCS
        unittest_volteCapabilityHandler.cpp
        LIBS
        module-cellular
)

A module-services/service-cellular/tests/unittest_volteCapabilityHandler.cpp => module-services/service-cellular/tests/unittest_volteCapabilityHandler.cpp +146 -0
@@ 0,0 1,146 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <catch2/catch.hpp>

#include <module-services/service-cellular/src/volte/VolteCapabilityHandler.hpp>
#include <module-services/service-cellular/src/volte/ImsiParserUS.hpp>
#include <module-services/service-cellular/src/volte/VolteAllowedUSList.hpp>
#include <module-services/service-cellular/src/volte/VolteCapabiltyHandlerCellularInterface.hpp>

TEST_CASE("VoLTE Capability handler")
{
    SECTION("ImsiParserUS success - US IMSI")
    {
        using namespace cellular::service;

        cellular::service::ImsiParserUS parser;
        std::string imsi("3111231234567890");

        auto result = parser.parse(imsi);

        REQUIRE(result.has_value() == true);
        REQUIRE(result.value().MCC == "311");
        REQUIRE(result.value().MNC == "123");
    }

    SECTION("ImsiParserUS failure - non US IMSI")
    {
        using namespace cellular::service;

        cellular::service::ImsiParserUS parser;
        std::string imsi("2601231234567890");

        auto result = parser.parse(imsi);

        REQUIRE(result.has_value() == false);
    }

    SECTION("ImsiParserUS failure -too short IMSI")
    {
        using namespace cellular::service;

        cellular::service::ImsiParserUS parser;
        std::string imsi("2601");

        auto result = parser.parse(imsi);

        REQUIRE(result.has_value() == false);
    }

    SECTION("VolteAllowedUSList success - TMobileUS IMSI")
    {
        using namespace cellular::service;

        VolteAllowedUSList list;
        OperatorInfo operatorInfo{"310", "120"};

        auto result = list.isVolteAllowed(operatorInfo);

        REQUIRE(result == true);
    }

    SECTION("VolteAllowedUSList failure - non TMobileUS MCC")
    {
        using namespace cellular::service;

        VolteAllowedUSList list;
        OperatorInfo operatorInfo{"210", "120"};

        auto result = list.isVolteAllowed(operatorInfo);

        REQUIRE(result == false);
    }

    SECTION("VolteAllowedUSList failure - non TMobileUS MNC")
    {
        using namespace cellular::service;

        VolteAllowedUSList list;
        OperatorInfo operatorInfo{"310", "999"};

        auto result = list.isVolteAllowed(operatorInfo);

        REQUIRE(result == false);
    }

    class MockTMobileUS : public cellular::service::VolteCapabilityCellularInterface
    {
        void setChannel(at::BaseChannel *channel)
        {}
        auto getImsi() -> std::optional<std::string>
        {
            return "310120123456789";
        }
    };

    SECTION("VolteCapabilityHandler succes = TMobileUS")
    {
        using namespace cellular::service;
        VolteCapabilityHandler handler{std::make_unique<ImsiParserUS>(),
                                       std::make_unique<VolteAllowedUSList>(),
                                       std::make_unique<MockTMobileUS>()};
        auto result = handler.isVolteAllowed();
        REQUIRE(result == true);
    }

    class MockNonTMobileUS : public cellular::service::VolteCapabilityCellularInterface
    {
        void setChannel(at::BaseChannel *channel)
        {}
        auto getImsi() -> std::optional<std::string>
        {
            return "310999123456789";
        }
    };

    SECTION("VolteCapabilityHandler failure = non TMobileUS")
    {
        using namespace cellular::service;
        VolteCapabilityHandler handler{std::make_unique<ImsiParserUS>(),
                                       std::make_unique<VolteAllowedUSList>(),
                                       std::make_unique<MockNonTMobileUS>()};
        auto result = handler.isVolteAllowed();
        REQUIRE(result == false);
    }

    class MockFailedToGetImsi : public cellular::service::VolteCapabilityCellularInterface
    {
        void setChannel(at::BaseChannel *channel)
        {}
        auto getImsi() -> std::optional<std::string>
        {
            return std::nullopt;
        }
    };

    SECTION("VolteCapabilityHandler failure = failed to get imsi")
    {
        using namespace cellular::service;
        VolteCapabilityHandler handler{std::make_unique<ImsiParserUS>(),
                                       std::make_unique<VolteAllowedUSList>(),
                                       std::make_unique<MockFailedToGetImsi>()};
        auto result = handler.isVolteAllowed();
        REQUIRE(result == false);
    }
}