blob: 3ef1bca1cfee258b560638bdac945fa1fe766c77 [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef HERMES_MODEM_MBIM_H_
#define HERMES_MODEM_MBIM_H_
#include <deque>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <base/strings/string_number_conversions.h>
#include <glib-bridge/glib_bridge.h>
#include <glib-bridge/glib_logger.h>
#include <glib-bridge/glib_scopers.h>
#include <google-lpa/lpa/card/euicc_card.h>
#include <libmbim-glib/libmbim-glib.h>
#include <libmbim-glib/mbim-enums.h>
#include "hermes/euicc_interface.h"
#include "hermes/executor.h"
#include "hermes/logger.h"
#include "hermes/mbim_cmd.h"
#include "hermes/modem.h"
#include "hermes/modem_control_interface.h"
#include "hermes/modem_manager_proxy.h"
#include "hermes/socket_interface.h"
namespace hermes {
// Implementation of EuiccCard using MBIM
// messages.
class ModemMbim : public Modem<MbimCmd> {
public:
static std::unique_ptr<ModemMbim> Create(
Logger* logger,
Executor* executor,
std::unique_ptr<ModemManagerProxy> modem_manager_proxy);
virtual ~ModemMbim();
// EuiccInterface overrides
void Initialize(EuiccManagerInterface* euicc_manager,
ResultCallback cb) override;
void ProcessEuiccEvent(EuiccEvent event, ResultCallback cb) override;
void RestoreActiveSlot(ResultCallback cb) override;
bool IsSimValidAfterEnable() override;
bool IsSimValidAfterDisable() override;
void OpenConnection(
const std::vector<uint8_t>& aid,
base::OnceCallback<void(std::vector<uint8_t>)> cb) override;
void TransmitApdu(const std::vector<uint8_t>& apduCommand,
base::OnceCallback<void(std::vector<uint8_t>)> cb) override;
static bool ParseEidApduResponseForTesting(const MbimMessage* response,
std::string* eid);
private:
struct SwitchSlotTxInfo : public TxInfo {
explicit SwitchSlotTxInfo(const uint32_t physical_slot)
: physical_slot_(physical_slot) {}
const uint32_t physical_slot_;
};
ModemMbim(Logger* logger,
Executor* executor,
std::unique_ptr<ModemManagerProxy> modem_manager_proxy);
void Shutdown() override;
void TransmitFromQueue() override;
std::unique_ptr<MbimCmd> GetTagForSendApdu() override;
void ProcessMbimResult(int err);
static void MbimCreateNewDeviceCb(GObject* source,
GAsyncResult* res,
ModemMbim* modem_mbim);
static void MbimDeviceOpenReadyCb(MbimDevice* dev,
GAsyncResult* res,
ModemMbim* modem_mbim);
void TransmitSubscriberStatusReady();
void TransmitDeviceCaps();
void TransmitCloseChannel();
void TransmitDeviceSlotMapping();
void TransmitSlotInfoStatus();
void TransmitOpenChannel();
void TransmitSendEidApdu();
void TransmitSysCapsQuery();
void TransmitSetDeviceSlotMapping();
void TransmitMbimSendApdu(TxElement* tx_element);
template <typename Func, typename... Args>
void SendMessage(MbimCmd::MbimType type,
std::unique_ptr<TxInfo> tx_info,
ResultCallback cb,
Func&& next_step,
Args&&... args);
static void SubscriberReadyStatusRspCb(MbimDevice* device,
GAsyncResult* res,
ModemMbim* modem_mbim);
static void QuerySysCapsReady(MbimDevice* device,
GAsyncResult* res,
ModemMbim* modem_mbim);
static void DeviceSlotStatusMappingRspCb(MbimDevice* device,
GAsyncResult* res,
ModemMbim* modem_mbim);
static void DeviceCapsQueryReady(MbimDevice* device,
GAsyncResult* res,
ModemMbim* modem_mbim);
static void DeviceSlotStatusInfoRspCb(MbimDevice* device,
GAsyncResult* res,
ModemMbim* modem_mbim);
static void UiccLowLevelAccessCloseChannelSetCb(MbimDevice* device,
GAsyncResult* res,
ModemMbim* modem_mbim);
static void UiccLowLevelAccessOpenChannelSetCb(MbimDevice* device,
GAsyncResult* res,
ModemMbim* modem_mbim);
static void UiccLowLevelAccessApduEidParse(MbimDevice* device,
GAsyncResult* res,
ModemMbim* modem_mbim);
static bool ParseEidApduResponse(const MbimMessage* response,
std::string* eid);
static void UiccLowLevelAccessApduResponseParse(MbimDevice* device,
GAsyncResult* res,
ModemMbim* modem_mbim);
static void SetDeviceSlotMappingsRspCb(MbimDevice* device,
GAsyncResult* res,
ModemMbim* modem_mbim);
static void ClientIndicationCb(MbimDevice* device,
MbimMessage* notification,
ModemMbim* modem_mbim);
void CloseDevice();
void CloseDeviceAndUninhibit(ResultCallback cb);
enum class EuiccEventStep {
GET_MBIM_DEVICE,
GET_SLOT_MAPPING,
GET_SLOT_INFO,
SET_SLOT_MAPPING,
CLOSE_CHANNEL,
OPEN_CHANNEL,
GET_EID,
EUICC_EVENT_STEP_LAST,
};
void ReacquireChannel(EuiccEventStep step,
std::vector<uint8_t> aid,
ResultCallback cb);
void OnEuiccEventStart(uint32_t physical_slot,
bool switch_slot_only,
EuiccEventStep step,
ResultCallback cb);
void AcquireChannelAfterCardReady(EuiccEvent event, ResultCallback cb);
class State {
public:
enum Value : uint8_t {
kMbimUninitialized,
kMbimInitializeStarted,
kReadImei,
kGetSubscriberReadyState,
kCheckSingleSim,
kSysQuery, // for num slots
kDeviceSlotMapping,
kSlotInfo,
kCloseChannel,
kOpenChannel,
kReadEid,
kEidReadComplete,
kMbimStarted,
};
State() : value_(kMbimUninitialized) {}
// Transitions to the indicated state. Returns whether or not the
// transition was successful.
bool Transition(Value value);
bool operator==(Value value) const { return value_ == value; }
bool operator!=(Value value) const { return value_ != value; }
friend std::ostream& operator<<(std::ostream& os, State state);
private:
explicit State(Value value) : value_(value) {}
Value value_;
};
friend std::ostream& operator<<(std::ostream& os, State state);
void InitializationStep(ModemMbim::State::Value next_state,
ResultCallback cb);
void ReadSlotsInfo(uint32_t slot_num,
uint32_t retry_count,
ResultCallback cb);
void OnEuiccUpdated();
State current_state_;
ResultCallback init_done_cb_;
guint32 channel_;
glib_bridge::ScopedGObject<MbimDevice> device_;
uint8_t indication_id_;
bool is_ready_state_valid;
MbimSubscriberReadyState ready_state_;
GFile* file_ = NULL;
struct SlotInfo {
guint32 map_count_; // number of executors/ radio. 1 for DSSA
guint32 slot_count_;
int cached_active_slot_;
// cached_active_slot is updated when Hermes reads the slot mapping or when
// Hermes switches slots. It may be outdated if another daemon switches
// slots when Hermes is idle.
std::optional<int> get_slot_mapping_result_;
// get_slot_mapping_result_ may be used to restore the active slot to that
// before a Hermes operation
std::vector<MbimUiccSlotState> slot_state_;
std::vector<std::string> eid_;
bool IsEuicc(int slot) const;
bool IsEuiccPresentOnAnySlot() const;
bool IsEsimActive() const { return IsEuicc(cached_active_slot_); }
void Clear() { InitSlotInfo(0, 0); }
void InitSlotInfo(guint32 slot_count, guint32 map_count);
void SetEidActiveSlot(std::string eid);
void SetSlotStateActiveSlot(MbimUiccSlotState state);
};
friend std::ostream& operator<<(std::ostream& os, const SlotInfo& info);
SlotInfo slot_info_;
base::WeakPtrFactory<ModemMbim> weak_factory_;
};
} // namespace hermes
#endif // HERMES_MODEM_MBIM_H_