blob: f1fb86fb565389e0b22c80ac3f6bc178421d4e19 [file] [log] [blame]
// Copyright (c) 2010 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.
#include "gobi_cdma_modem.h"
#include "gobi_modem_handler.h"
extern "C" {
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
};
#include <base/files/file_path.h>
#include <base/file_util.h>
#include <base/strings/stringprintf.h>
#include <cromo/carrier.h>
#include <mm/mm-modem.h>
using base::FilePath;
using base::StringPrintf;
using std::string;
using utilities::DBusPropertyMap;
// static
static const char kExecPostActivationStepsCookieCrumbFormat[] =
"/tmp/cromo-modem-exec-post-activation-steps-%s";
//======================================================================
// Construct and destruct
GobiCdmaModem::GobiCdmaModem(DBus::Connection& connection,
const DBus::Path& path,
const gobi::DeviceElement& device,
gobi::Sdk* sdk,
GobiModemHelper *modem_helper)
: GobiModem(connection, path, device, sdk, modem_helper),
activation_time_(METRIC_BASE_NAME "Activation", 0, 150000, 20),
activation_in_progress_(false),
force_activated_status_(false) {
}
GobiCdmaModem::~GobiCdmaModem() {
}
void GobiCdmaModem::Init() {
GobiModem::Init();
DBus::Error error;
ScopedApiConnection connection(*this);
connection.ApiConnect(error);
if (error.is_set()) {
LOG(ERROR) << "Failed to connect to Gobi modem, "
<< "skipping post activation steps";
return;
}
int activation_state = GobiCdmaModem::GetMmActivationState();
if (activation_state == MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED &&
ShouldExecPostActivationSteps()) {
LOG(INFO) << "Executing post activation steps";
PerformPostActivationSteps();
}
}
void GobiCdmaModem::GetCdmaRegistrationState(ULONG* cdma_1x_state,
ULONG* cdma_evdo_state,
ULONG* roaming_state,
DBus::Error& error) {
ULONG reg_state;
ULONG l1;
WORD w1, w2;
BYTE radio_interfaces[10];
BYTE num_radio_interfaces = sizeof(radio_interfaces)/sizeof(BYTE);
CHAR netname[32];
ULONG rc = sdk_->GetServingNetwork(&reg_state, &l1, &num_radio_interfaces,
radio_interfaces, roaming_state,
&w1, &w2, sizeof(netname), netname);
if (rc != 0) {
// All errors are treated as if the modem is not yet registered.
*cdma_1x_state = gobi::kUnregistered;
*cdma_evdo_state = gobi::kUnregistered;
*roaming_state = gobi::kRoaming; // Should not matter
return;
}
// There is no guarantee that both interfaces will be included in
// the array, so assume not registered.
*cdma_1x_state = gobi::kUnregistered;
*cdma_evdo_state = gobi::kUnregistered;
for (int i = 0; i < num_radio_interfaces; i++) {
if (radio_interfaces[i] == gobi::kRfiCdma1xRtt)
*cdma_1x_state = reg_state;
else if (radio_interfaces[i] == gobi::kRfiCdmaEvdo)
*cdma_evdo_state = reg_state;
}
}
int GobiCdmaModem::GetMmActivationState() {
ULONG device_activation_state;
ULONG rc;
rc = sdk_->GetActivationState(&device_activation_state);
if (rc != 0) {
LOG(ERROR) << "GetActivationState: " << rc;
return -1;
}
LOG(INFO) << "Device activation state: " << device_activation_state;
if (activation_in_progress_ && !force_activated_status_) {
LOG(INFO) << "Device activation still in progress";
return MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING;
}
if (device_activation_state == 1) {
return MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED;
}
if (force_activated_status_) {
// |force_activated_status_| is set to true for testing purposes via
// org.chromium.ModemManager.Modem.Gobi.ForceModemActivatedStatus.
LOG(INFO) << __func__ << "Forcing modem activation status to activated";
return MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED;
}
ULONG firmware_id;
ULONG technology_id;
ULONG carrier_id;
ULONG region;
ULONG gps_capability;
const Carrier *carrier = NULL;
rc = sdk_->GetFirmwareInfo(&firmware_id,
&technology_id,
&carrier_id,
&region,
&gps_capability);
if (rc == 0) {
carrier = handler_->server().FindCarrierByCarrierId(carrier_id);
if (carrier == NULL)
LOG(WARNING) << "Carrier lookup failed for ID " << carrier_id;
} else {
LOG(WARNING) << "GetFirmwareInfo failed: " << rc;
}
if (carrier == NULL)
return MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED;
// Is the modem de-activated, or is there an activation in flight?
switch (carrier->activation_method()) {
case Carrier::kOmadm: {
ULONG session_state;
ULONG session_type;
ULONG failure_reason;
BYTE retry_count;
WORD session_pause;
WORD time_remaining; // For session pause
rc = sdk_->OMADMGetSessionInfo(
&session_state, &session_type, &failure_reason, &retry_count,
&session_pause, & time_remaining);
if (rc != 0) {
// kNoTrackingSessionHasBeenStarted -> modem has never tried
// to run OMADM; this is not an error condition.
if (rc != gobi::kNoTrackingSessionHasBeenStarted) {
LOG(ERROR) << "Could not get omadm state: " << rc;
}
return MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED;
}
return (session_state <= gobi::kOmadmMaxFinal) ?
MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED :
MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING;
}
break;
case Carrier::kOtasp:
return (device_activation_state == gobi::kNotActivated) ?
MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED :
MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING;
break;
default: // This is a UMTS carrier; we count it as activated
return MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED;
}
}
//======================================================================
// Callbacks and callback utilities
static GobiCdmaModem* LookupCdmaModem(GobiModemHandler *handler,
const DBus::Path &path) {
return static_cast<GobiCdmaModem *>(handler->LookupByDbusPath(path));
}
static BYTE* GetFileContents(const char* filename, ULONG* num_bytes) {
int bytes_read;
int fd;
struct stat st;
fd = open(filename, O_RDONLY);
if (fd == -1) {
LOG(WARNING) << "Can't open '" << filename << "': " << strerror(errno);
return NULL;
}
if (fstat(fd, &st) == -1) {
LOG(WARNING) << "Can't fstat '" << filename << "': " << strerror(errno);
close(fd);
return NULL;
}
*num_bytes = st.st_size;
BYTE* buffer = new BYTE[*num_bytes];
bytes_read = read(fd, reinterpret_cast<char*>(buffer), *num_bytes);
if (bytes_read < 0) {
LOG(WARNING) << "Cannot read contents of PRL file \"" << filename
<< "\": " << strerror(errno);
delete [] buffer;
close(fd);
return NULL;
}
LOG(INFO) << "Read " << bytes_read << " bytes from file \""
<< filename << "\"";
*num_bytes = bytes_read;
close(fd);
return buffer;
}
gboolean GobiCdmaModem::ActivationStatusCallback(gpointer data) {
ActivationStatusArgs* args = static_cast<ActivationStatusArgs*>(data);
LOG(INFO) << "OTASP status callback: " << args->device_activation_state;
GobiCdmaModem* modem = LookupCdmaModem(handler_, *args->path);
if (modem != NULL) {
if (args->device_activation_state == gobi::kActivated ||
args->device_activation_state == gobi::kNotActivated) {
modem->ActivationFinished();
}
if (args->device_activation_state == gobi::kActivated) {
DBus::Error error;
// Reset modem as per SDK documentation. This has the side-effect of
// causing the modem to disappear from the DBus bus, which will cause the
// connection manager to lose track of its state, but when we come back,
// we'll be in the right state.
// Do not send the ActivationStateChanged signal here as it will
// only serve to encourage flimflam to start issuing new
// commands and the modem is about to disappear anyway.
modem->ResetModem(error);
} else if (args->device_activation_state == gobi::kNotActivated) {
modem->SendActivationStateChanged(
MM_MODEM_CDMA_ACTIVATION_ERROR_PROVISIONING_FAILED);
}
}
return FALSE;
}
static void OMADMAlertCallback(ULONG type, USHORT id) {
LOG(INFO) << "OMDADMAlertCallback type " << type << " id " << id;
}
gboolean GobiCdmaModem::OmadmStateDeviceConfigureCallback(gpointer data) {
OmadmStateArgs* args = static_cast<OmadmStateArgs*>(data);
LOG(INFO) << "OMA-DM State Device Configure Callback: "
<< args->session_state;
GobiCdmaModem* modem = LookupCdmaModem(handler_, *args->path);
bool activation_done = true;
if (modem != NULL) {
switch (args->session_state) {
case gobi::kOmadmComplete:
modem->SendActivationStateChanged(
MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR);
// Activation completed successfully, the modem will reset. Mark the
// modem to execute post activation steps when it's next seen.
modem->MarkForExecPostActivationStepsAfterReset();
break;
case gobi::kOmadmFailed:
LOG(INFO) << "OMA-DM device configuration failure reason: "
<< args->failure_reason;
// fall through
case gobi::kOmadmUpdateInformationUnavailable:
modem->SendActivationStateChanged(
MM_MODEM_CDMA_ACTIVATION_ERROR_PROVISIONING_FAILED);
break;
default:
activation_done = false;
}
}
if (activation_done) {
modem->sdk_->SetOMADMStateCallback(NULL);
modem->ActivationFinished();
}
return FALSE;
}
gboolean GobiCdmaModem::OmadmStateClientPrlUpdateCallback(gpointer data) {
OmadmStateArgs* args = static_cast<OmadmStateArgs*>(data);
LOG(INFO) << "OMA-DM State Client PRL Update Callback: "
<< args->session_state;
GobiCdmaModem* modem = LookupCdmaModem(handler_, *args->path);
bool done = true;
switch (args->session_state) {
case gobi::kOmadmComplete:
LOG(INFO) << "OMA-DM client initiated PRL completed, "
<< "information updated.";
break;
case gobi::kOmadmUpdateInformationUnavailable:
LOG(INFO) << "OMA-DM client initiated PRL completed, "
<< "update information unavailable (PRL up-to-date).";
break;
case gobi::kOmadmFailed:
LOG(INFO) << "OMA-DM client initiated PRL update failure reason: "
<< args->failure_reason;
break;
case gobi::kOmadmPrlDownloaded:
LOG(INFO) << "OMA-DM client initiated PRL completed, PRL downloaded.";
break;
default:
done = false;
break;
}
if (done) {
modem->sdk_->SetOMADMStateCallback(NULL);
modem->activation_in_progress_ = false;
}
return FALSE;
}
void GobiCdmaModem::SignalStrengthHandler(INT8 signal_strength,
ULONG radio_interface) {
unsigned long ss_percent = MapDbmToPercent(signal_strength);
ULONG cdma_evdo_state;
ULONG cdma_1x_state;
ULONG roaming_state;
DBus::Error error;
GetCdmaRegistrationState(&cdma_1x_state, &cdma_evdo_state,
&roaming_state, error);
if ((radio_interface == gobi::kRfiCdma1xRtt &&
cdma_1x_state == gobi::kRegistered) ||
(radio_interface == gobi::kRfiCdmaEvdo &&
cdma_evdo_state == gobi::kRegistered)) {
SignalQuality(ss_percent); // NB: org.freedesktop...Modem.Cdma
}
}
void GobiCdmaModem::RegisterCallbacks() {
GobiModem::RegisterCallbacks();
sdk_->SetOMADMAlertCallback(OMADMAlertCallback);
sdk_->SetActivationStatusCallback(ActivationStatusCallbackTrampoline);
sdk_->SetOMADMStateCallback(NULL);
}
//======================================================================
// DBUS Methods: overridden Modem.Simple
void GobiCdmaModem::Connect(const DBusPropertyMap& properties,
DBus::Error& error) {
if (activation_in_progress_) {
LOG(WARNING) << "Connect while modem is activating";
error.set(kConnectError, "Modem is activating");
return;
}
GobiModem::Connect(properties, error);
}
void GobiCdmaModem::GetTechnologySpecificStatus(DBusPropertyMap* properties) {
WORD prl_version;
ULONG rc = sdk_->GetPRLVersion(&prl_version);
if (rc == 0) {
(*properties)["prl_version"].writer().append_uint16(prl_version);
}
int activation_state = GetMmActivationState();
if (activation_state >= 0) {
(*properties)["activation_state"].writer().append_uint32(activation_state);
}
}
//======================================================================
// DBUS Methods: ModemGobi
void GobiCdmaModem::ForceModemActivatedStatus(DBus::Error& error) {
force_activated_status_ = true;
}
//======================================================================
// DBUS Methods: ModemCDMA
// NB: This function only uses the DBus::Error field to return
// kOperationInitiatedError. Other errors are returned as uint32_t
// values from MM_MODEM_CDMA_ACTIVATION_ERROR
uint32_t GobiCdmaModem::Activate(const std::string& carrier_name,
DBus::Error& activation_started_error) {
LOG(INFO) << "Activate(" << carrier_name << ")";
// Check current firmware to see whether it's for the requested carrier
ULONG firmware_id;
ULONG technology;
ULONG carrier_id;
ULONG region;
ULONG gps_capability;
ULONG rc = sdk_->GetFirmwareInfo(&firmware_id,
&technology,
&carrier_id,
&region,
&gps_capability);
if (0 != rc) {
LOG(ERROR) << "GetFirmwareInfo: " << rc;
return MM_MODEM_CDMA_ACTIVATION_ERROR_UNKNOWN;
}
const Carrier *carrier;
if (carrier_name.empty()) {
carrier = handler_->server().FindCarrierByCarrierId(carrier_id);
if (carrier == NULL) {
LOG(ERROR) << "Unknown carrier id: " << carrier_id;
return MM_MODEM_CDMA_ACTIVATION_ERROR_UNKNOWN;
}
} else {
carrier = handler_->server().FindCarrierByName(carrier_name);
if (carrier == NULL) {
LOG(WARNING) << "Unknown carrier: " << carrier_name;
return MM_MODEM_CDMA_ACTIVATION_ERROR_UNKNOWN;
}
if (carrier_id != carrier->carrier_id()) {
LOG(WARNING) << "Current device firmware does not match the requested"
"carrier.";
LOG(WARNING) << "SetCarrier operation must be done before activating.";
return MM_MODEM_CDMA_ACTIVATION_ERROR_UNKNOWN;
}
}
DBus::Error internal_error;
DBusPropertyMap status = GetStatus(internal_error);
if (internal_error.is_set()) {
LOG(ERROR) << internal_error;
return MM_MODEM_CDMA_ACTIVATION_ERROR_UNKNOWN;
}
DBusPropertyMap::const_iterator p;
p = status.find("no_signal");
if (p != status.end()) {
LOG(ERROR) << "no_signal";
return MM_MODEM_CDMA_ACTIVATION_ERROR_NO_SIGNAL;
}
p = status.find("activation_state");
if (p != status.end()) {
try { // Style guide violation forced by dbus-c++
LOG(INFO) << "Current activation state: "
<< p->second.reader().get_uint32();
} catch (const DBus::Error &e) {
LOG(ERROR) << e;
return MM_MODEM_CDMA_ACTIVATION_ERROR_UNKNOWN;
}
}
uint32_t ret;
activation_time_.Start();
switch (carrier->activation_method()) {
case Carrier::kOmadm:
ret = ActivateOmadm();
break;
case Carrier::kOtasp:
if (carrier->CdmaCarrierSpecificActivate(status, this, &ret)) {
// ret is set in call above
break;
}
if (carrier->activation_code() == NULL) {
LOG(ERROR) << "Number was not supplied for OTASP activation";
ret = MM_MODEM_CDMA_ACTIVATION_ERROR_UNKNOWN;
break;
}
ret = ActivateOtasp(carrier->activation_code());
break;
default:
LOG(ERROR) << "Unknown activation method: "
<< carrier->activation_method();
ret = MM_MODEM_CDMA_ACTIVATION_ERROR_UNKNOWN;
break;
}
if (ret == MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR)
// Record that activation is in progress
activation_in_progress_ = true;
return ret;
}
void GobiCdmaModem::ActivateManual(const DBusPropertyMap& const_properties,
DBus::Error &error) {
using utilities::ExtractString;
DBusPropertyMap properties(const_properties);
// TODO(rochberg): Does it make sense to set defaults from the
// modem's current state?
const char* spc = NULL;
const char* prl_file = NULL;
uint16_t system_id = 65535;
const char* mdn = NULL;
const char* min = NULL;
const char* mnha = NULL;
const char* mnaaa = NULL;
DBusPropertyMap::const_iterator p;
// try/catch required to cope with dbus-c++'s handling of type
// mismatches
try { // Style guide violation forced by dbus-c++
spc = ExtractString(properties, "spc", "000000", error);
prl_file = ExtractString(properties, "prlfile", NULL, error);
p = properties.find("system_id");
if (p != properties.end()) {
system_id = p->second.reader().get_uint16();
}
mdn = ExtractString(properties, "mdn", "", error);
min = ExtractString(properties, "min", "", error);
mnha = ExtractString(properties, "mnha", NULL, error);
mnaaa = ExtractString(properties, "mnaaa", NULL, error);
} catch (DBus::Error e) {
error = e;
return;
}
BYTE* prl = NULL;
ULONG prl_size = 0;
if (prl_file != NULL) {
prl = GetFileContents(prl_file, &prl_size);
if (prl == NULL) {
error.set(kActivationError, "PRL file cannot be read");
return;
}
}
ULONG rc = sdk_->ActivateManual(spc,
system_id,
mdn,
min,
prl_size,
prl,
mnha,
mnaaa);
delete [] prl;
ENSURE_SDK_SUCCESS(ActivateManual, rc, kActivationError);
}
void GobiCdmaModem::ActivateManualDebug(
const std::map<std::string, std::string>& properties,
DBus::Error &error) {
DBusPropertyMap output;
for (std::map<std::string, std::string>::const_iterator i =
properties.begin();
i != properties.end();
++i) {
if (i->first != "system_id") {
output[i->first].writer().append_string(i->second.c_str());
} else {
const std::string& value = i->second;
char *end;
errno = 0;
uint16_t system_id = static_cast<uint16_t>(
strtoul(value.c_str(), &end, 10));
if (errno != 0 || *end != '\0') {
LOG(ERROR) << "Bad system_id: " << value;
error.set(kSdkError, "Bad system_id");
return;
}
output[i->first].writer().append_uint16(system_id);
}
}
ActivateManual(output, error);
}
uint32_t GobiCdmaModem::ActivateOmadm() {
ULONG rc;
LOG(INFO) << "Activating OMA-DM device configure";
rc = sdk_->OMADMSetPRLUpdateFeature(TRUE);
if (rc != 0) {
LOG(ERROR) << "OMA-DM device configure activation failed to enable PRL "
<< "update: " << rc;
return MM_MODEM_CDMA_ACTIVATION_ERROR_START_FAILED;
}
sdk_->SetOMADMStateCallback(OmadmStateDeviceConfigureCallbackTrampoline);
rc = sdk_->OMADMStartSession(gobi::kConfigure);
if (rc != 0) {
LOG(ERROR) << "OMA-DM device configure activation failed: " << rc;
return MM_MODEM_CDMA_ACTIVATION_ERROR_START_FAILED;
}
return MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR;
}
uint32_t GobiCdmaModem::ActivateOtasp(const std::string& number) {
ULONG rc;
LOG(INFO) << "Activating OTASP";
rc = sdk_->ActivateAutomatic(number.c_str());
if (rc != 0) {
LOG(ERROR) << "OTASP activation failed: " << rc;
return MM_MODEM_CDMA_ACTIVATION_ERROR_START_FAILED;
}
return MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR;
}
void GobiCdmaModem::ActivationFinished(void) {
activation_time_.StopIfStarted();
activation_in_progress_ = false;
}
void GobiCdmaModem::PerformPostActivationSteps() {
activation_in_progress_ = true;
StartClientInitiatedPrlUpdate();
}
void GobiCdmaModem::StartClientInitiatedPrlUpdate() {
LOG(INFO) << "Activating OMA-DM client initiated PRL update";
sdk_->SetOMADMStateCallback(OmadmStateClientPrlUpdateCallbackTrampoline);
ULONG rc = sdk_->OMADMSetPRLUpdateFeature(TRUE);
if (rc != 0) {
LOG(ERROR) << "OMA-DM client initiated PRL update failed to enable PRL "
<< "update: " << rc;
sdk_->SetOMADMStateCallback(NULL);
return;
}
rc = sdk_->OMADMStartSession(gobi::kPrlUpdate);
if (rc != 0) {
LOG(ERROR) << "OMA-DM client initiated PRL update failed to start: "
<< rc;
sdk_->SetOMADMStateCallback(NULL);
}
}
std::string GobiCdmaModem::GetEsn(DBus::Error& error) {
LOG(INFO) << "GetEsn";
SerialNumbers serials;
GetSerialNumbers(&serials, error);
return serials.esn;
}
void GobiCdmaModem::GetRegistrationState(uint32_t& cdma_1x_state,
uint32_t& cdma_evdo_state,
DBus::Error& error) {
ULONG reg_state_evdo;
ULONG reg_state_1x;
ULONG roaming_state;
cdma_1x_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
cdma_evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
GetCdmaRegistrationState(&reg_state_1x, &reg_state_evdo,
&roaming_state, error);
if (error.is_set())
return;
uint32_t mm_reg_state;
if (roaming_state == gobi::kHome)
mm_reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_HOME;
else
mm_reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING;
if (reg_state_1x == gobi::kRegistered)
cdma_1x_state = mm_reg_state;
if (reg_state_evdo == gobi::kRegistered)
cdma_evdo_state = mm_reg_state;
}
// returns <band class, band, system id>
DBus::Struct<uint32_t, std::string, uint32_t> GobiCdmaModem::GetServingSystem(
DBus::Error& error) {
DBus::Struct<uint32_t, std::string, uint32_t> result;
WORD mcc, mnc, sid, nid;
CHAR netname[32];
ULONG reg_state;
ULONG roaming_state;
ULONG l1;
BYTE radio_interfaces[10];
BYTE num_radio_interfaces = sizeof(radio_interfaces)/sizeof(BYTE);
LOG(INFO) << "GetServingSystem";
ULONG rc = sdk_->GetServingNetwork(&reg_state, &l1, &num_radio_interfaces,
radio_interfaces, &roaming_state,
&mcc, &mnc, sizeof(netname), netname);
ENSURE_SDK_SUCCESS_WITH_RESULT(GetServingNetwork, rc, kSdkError, result);
LOG(INFO) << "Serving MCC/MNC: " << mcc << "/" << mnc;
if (reg_state != gobi::kRegistered) {
error.set(kErrorNoNetwork, "No network service is available");
return result;
}
rc = sdk_->GetHomeNetwork(&mcc, &mnc,
sizeof(netname), netname, &sid, &nid);
ENSURE_SDK_SUCCESS_WITH_RESULT(GetHomeNetwork, rc, kSdkError, result);
LOG(INFO) << "Home MCC/MNC: " << mcc << "/" << mnc << " SID/NID: " << sid
<< "/" << nid << " name: " << netname;
gobi::RfInfoInstance rf_info[10];
BYTE rf_info_size = sizeof(rf_info) / sizeof(rf_info[0]);
rc = sdk_->GetRFInfo(&rf_info_size, static_cast<BYTE*>((void *)&rf_info[0]));
if (rc == gobi::kInformationElementUnavailable) {
error.set(kErrorNoNetwork, "No network service is available");
return result;
} else if (rc != 0) {
error.set(kSdkError, "GetRFInfo");
return result;
}
if (rf_info_size != 0) {
LOG(INFO) << "RF info for " << rf_info[0].radioInterface
<< " band class " << rf_info[0].activeBandClass
<< " channel " << rf_info[0].activeChannel;
switch (rf_info[0].activeBandClass) {
case 0:
case 85: // WCDMA 800
result._1 = 1; // 800 Mhz band class
break;
case 1:
case 81: // WCDMA PCS 1900
result._1 = 2; // 1900 Mhz band class
break;
default:
result._1 = 0; // unknown band class
break;
}
result._2 = "F"; // XXX bogus
}
result._3 = sid;
return result;
}
uint32_t GobiCdmaModem::GetSignalQuality(DBus::Error& error) {
return GobiModem::CommonGetSignalQuality(error);
}
void GobiCdmaModem::RegistrationStateHandler() {
uint32_t cdma_1x_state;
uint32_t evdo_state;
DBus::Error error;
bool registered = false;
GetRegistrationState(cdma_1x_state, evdo_state, error);
if (error.is_set())
return;
if (cdma_1x_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN ||
evdo_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) {
registered = true;
registration_time_.StopIfStarted();
}
RegistrationStateChanged(cdma_1x_state, evdo_state);
if (registered && mm_state() <= MM_MODEM_STATE_SEARCHING)
SetMmState(MM_MODEM_STATE_REGISTERED,
MM_MODEM_STATE_CHANGED_REASON_UNKNOWN);
// TODO(ers) check data bearer technology and notify if appropriate.
LOG(INFO) << " => 1xRTT: " << cdma_1x_state << " EVDO: " << evdo_state;
}
void GobiCdmaModem::DataCapabilitiesHandler(BYTE num_data_caps,
ULONG* data_caps) {
// TODO(ers) explore whether we should be doing anything
// with this event.
}
void GobiCdmaModem::SetTechnologySpecificProperties() {
SerialNumbers serials;
DBus::Error error;
GetSerialNumbers(&serials, error);
if (!error.is_set())
Meid = serials.meid;
}
bool GobiCdmaModem::CheckEnableOk(DBus::Error &error) {
return !activation_in_progress_;
}
void GobiCdmaModem::SendActivationStateFailed() {
DBusPropertyMap empty;
ActivationStateChanged(MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED,
MM_MODEM_CDMA_ACTIVATION_ERROR_UNKNOWN,
empty);
}
void GobiCdmaModem::SendActivationStateChanged(uint32_t mm_activation_error) {
DBusPropertyMap status;
DBusPropertyMap to_send;
DBus::Error internal_error;
status = GetStatus(internal_error);
if (internal_error.is_set()) {
// GetStatus should never fail; we are punting here.
SendActivationStateFailed();
return;
}
DBusPropertyMap::const_iterator p;
uint32_t mm_activation_state;
if ((p = status.find("activation_state")) == status.end()) {
LOG(ERROR);
SendActivationStateFailed();
return;
}
try { // Style guide violation forced by dbus-c++
mm_activation_state = p->second.reader().get_uint32();
} catch (const DBus::Error &e) {
LOG(ERROR);
SendActivationStateFailed();
return;
}
if (mm_activation_error == MM_MODEM_CDMA_ACTIVATION_ERROR_TIMED_OUT &&
mm_activation_state == MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED) {
mm_activation_error = MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR;
}
// TODO(rochberg): Table drive
if ((p = status.find("mdn")) != status.end()) {
to_send["mdn"] = p->second;
}
if ((p = status.find("min")) != status.end()) {
to_send["min"] = p->second;
}
if ((p = status.find("payment_url")) != status.end()) {
to_send["payment_url"] = p->second;
}
if ((p = status.find("payment_url_method")) != status.end()) {
to_send["payment_url_method"] = p->second;
}
if ((p = status.find("payment_url_postdata")) != status.end()) {
to_send["payment_url_postdata"] = p->second;
}
ActivationStateChanged(mm_activation_state,
mm_activation_error,
to_send);
}
FilePath GobiCdmaModem::GetExecPostActivationStepsCookieCrumbPath() const {
string path =
StringPrintf(kExecPostActivationStepsCookieCrumbFormat,
device_.deviceKey);
return FilePath::FromUTF8Unsafe(path);
}
void GobiCdmaModem::MarkForExecPostActivationStepsAfterReset() {
// This is a best effort attempt to write out the cookie crumb so don't
// need to check for write failures.
file_util::WriteFile(GetExecPostActivationStepsCookieCrumbPath(), "", 0);
}
bool GobiCdmaModem::ShouldExecPostActivationSteps() const {
FilePath cookie_crumb_path = GetExecPostActivationStepsCookieCrumbPath();
if (base::PathExists(cookie_crumb_path)) {
base::DeleteFile(cookie_crumb_path, false);
return true;
}
return false;
}