blob: eb5de18f2a48b13f57d2e707f2420a6658b1dbaf [file] [log] [blame]
//
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "host/commands/modem_simulator/sup_service.h"
namespace cuttlefish {
SupService::SupService(int32_t service_id, ChannelMonitor* channel_monitor,
ThreadLooper* thread_looper)
: ModemService(service_id, this->InitializeCommandHandlers(),
channel_monitor, thread_looper) {
InitializeServiceState();
}
std::vector<CommandHandler> SupService::InitializeCommandHandlers() {
std::vector<CommandHandler> command_handlers = {
CommandHandler("+CUSD",
[this](const Client& client, std::string& cmd) {
this->HandleUSSD(client, cmd);
}),
CommandHandler("+CLIR",
[this](const Client& client, std::string& cmd) {
this->HandleCLIR(client, cmd);
}),
CommandHandler("+CCWA",
[this](const Client& client, std::string& cmd) {
this->HandleCallWaiting(client, cmd);
}),
CommandHandler(
"+CLIP?", [this](const Client& client) { this->HandleCLIP(client); }),
CommandHandler("+CCFCU",
[this](const Client& client, std::string& cmd) {
this->HandleCallForward(client, cmd);
}),
CommandHandler("+CSSN",
[this](const Client& client, std::string& cmd) {
this->HandleSuppServiceNotifications(client, cmd);
}),
};
return (command_handlers);
}
void SupService::InitializeServiceState() {
call_forward_infos_ = {
CallForwardInfo(CallForwardInfo::Reason::CFU),
CallForwardInfo(CallForwardInfo::Reason::CFB),
CallForwardInfo(CallForwardInfo::Reason::CFNR),
CallForwardInfo(CallForwardInfo::Reason::CFNRC)
};
}
/**
* AT+CUSD
* This command allows control of the Unstructured Supplementary Service Data (USSD)
* according to 3GPP TS 22.090 [23], 3GPP TS 24.090 [148] and 3GPP TS 24.390 [131].
* Both network and mobile initiated operations are supported.
*
* Command Possible response(s)
* +CUSD=[<n>[,<str>[,<dcs>]]] +CME ERROR: <err>
* +CUSD? +CUSD: <n>
*
* <n>: integer type (sets/shows the result code presentation status to the TE).
* 0 disable the result code presentation to the TE
* 1 enable the result code presentation to the TE
* 2 cancel session (not applicable to read command response)
* <str>: string type USSD string
* when <str> parameter is not given, network is not interrogated
* <dcs>: integer type (shows Cell Broadcast Data Coding Scheme, see 3GPP TS 23.038 [25]).
* Default value is 0.
*
* see RIL_REQUEST_SEND_USSD or RIL_REQUEST_CANCEL_USSD in RIL
*/
void SupService::HandleUSSD(const Client& client, std::string& /*command*/) {
client.SendCommandResponse("OK");
}
/**
* AT+CLIR
* This command refers to CLIR‑service according to 3GPP TS 22.081 that allows
* a calling subscriber to enable or disable the presentation of the CLI to the
* called party when originating a call.
*
* Command Possible response(s)
* +CLIR: <n>
* +CLIR? +CLIR: <n>,<m>
*
* <n>: integer type (parameter sets the adjustment for outgoing calls).
* 0 presentation indicator is used according to the subscription of the CLIR service
* 1 CLIR invocation
* 2 CLIR suppression
* <m>: integer type (parameter shows the subscriber CLIR / OIR service status in the network).
* 0 CLIR / OIR not provisioned
* 1 CLIR / OIR provisioned in permanent mode
* 2 unknown (e.g. no network, etc.)
* 3 CLIR / OIR temporary mode presentation restricted
* 4 CLIR / OIR temporary mode presentation allowed
*
* see RIL_REQUEST_SET_CLIR or RIL_REQUEST_GET_CLIR in RIL
*/
void SupService::HandleCLIR(const Client& client, std::string& command) {
std::vector<std::string> responses;
std::stringstream ss;
CommandParser cmd(command);
cmd.SkipPrefix();
if (*cmd == "AT+CLIR?") {
ss << "+CLIR:" << clir_status_.type << "," << clir_status_.status;
responses.push_back(ss.str());
} else {
clir_status_.type = (ClirStatusInfo::ClirType)cmd.GetNextInt();
}
responses.push_back("OK");
client.SendCommandResponse(responses);
}
/**
* AT+CLIP
* This command refers to the supplementary service CLIP (Calling Line
* Identification Presentation) according to 3GPP TS 22.081 [3] and OIP
* (Originating Identification Presentation) according to 3GPP TS 24.607 [119]
* that enables a called subscriber to get the calling line identity (CLI) of
* the calling party when receiving a mobile terminated call.
*
* Command Possible response(s)
* +CLIP? +CLIP: <n>,<m>
*
* <n>: integer type (parameter sets/shows the result code presentation status to the TE).
* 0 disable
* 1 enable
* <m>: integer type (parameter shows the subscriber CLIR / OIR service status in the network).
* 0 CLIP / OIP not provisioned
* 1 CLIP / OIP provisioned
* 2 unknown (e.g. no network, etc.)
*
* see RIL_REQUEST_QUERY_CLIP in RIL
*/
void SupService::HandleCLIP(const Client& client) {
std::vector<std::string> responses = {"+CLIP: 0, 0", "OK"};
client.SendCommandResponse(responses);
}
/**
* AT+CSSN
* This command refers to supplementary service related network initiated
* notifications. The set command enables/disables the presentation of
* notification result codes from TA to TE.
*
* Command Possible response(s)
* +CSSN: [<n>[,<m>]]
*
* <n>: integer type (parameter sets/shows the +CSSI intermediate result code
* presentation status to the TE)
* 0 disable
* 1 enable
* <m>: integer type (parameter sets/shows the +CSSU unsolicited result code
* presentation status to the TE)
* 0 disable
* 1 enable
*
* see RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION in RIL
*/
void SupService::HandleSuppServiceNotifications(const Client& client, std::string& /*command*/) {
client.SendCommandResponse("OK");
}
/**
* AT+CCFCU
* The command allows control of the communication forwarding supplementary service
* according to 3GPP TS 22.072 [31], 3GPP TS 22.082 [4] and 3GPP TS 24.604 [132].
*
* Command Possible response(s)
* +CCFCU=<reason>,<mode> +CME ERROR: <err>
* [,<numbertype>,<ton>,<number> when <mode>=2 and command successful:
* [,<class>,<ruleset> +CCFCU: <status>,<class1>[,<numbertype>,
* [,<subaddr>[,<satype>[,<time>]]]]] <ton>,<number>[,<subaddr>,<satype>[,<time>]]]
* [,<class>,<ruleset>
*
* see SupService::CallForwardInfo
*
* see RIL_REQUEST_SET_CALL_FORWARD or RIL_REQUEST_QUERY_CALL_FORWARD_STATUS in RIL
*/
void SupService::HandleCallForward(const Client& client, std::string& command) {
std::vector<std::string> responses;
std::stringstream ss;
CommandParser cmd(command);
cmd.SkipPrefix();
int reason = cmd.GetNextInt();
int status = cmd.GetNextInt();
int number_type = cmd.GetNextInt();
int ton = cmd.GetNextInt();
std::string_view number = cmd.GetNextStr();
int classx = cmd.GetNextInt();
switch (reason) {
case CallForwardInfo::Reason::ALL_CF: {
if (status == CallForwardInfo::CallForwardInfoStatus::INTERROGATE) {
auto iter = call_forward_infos_.begin();
for (; iter != call_forward_infos_.end(); ++iter) {
ss.clear();
ss << "+CCFCU: " << iter->status << "," << classx << "," << number_type
<< "," << ton << ",\"" << iter->number << "\"";
if (iter->reason == CallForwardInfo::Reason::CFNR) {
ss << ",,," << iter->timeSeconds;
}
responses.push_back(ss.str());
ss.str("");
}
}
break;
}
case CallForwardInfo::Reason::CFU:
case CallForwardInfo::Reason::CFB:
case CallForwardInfo::Reason::CFNR:
case CallForwardInfo::Reason::CFNRC: {
if (status == CallForwardInfo::CallForwardInfoStatus::INTERROGATE) {
ss << "+CCFCU: " << call_forward_infos_[reason].status
<< "," << classx << "," << number_type << "," << ton << ",\""
<< call_forward_infos_[reason].number << "\"";
if (reason == CallForwardInfo::Reason::CFNR) {
ss << ",,," << call_forward_infos_[reason].timeSeconds;
}
responses.push_back(ss.str());
} else {
if (status == CallForwardInfo::CallForwardInfoStatus::REGISTRATION) {
call_forward_infos_[reason].status
= CallForwardInfo::CallForwardInfoStatus::ENABLE;
} else {
call_forward_infos_[reason].status =
(CallForwardInfo::CallForwardInfoStatus)status;
}
call_forward_infos_[reason].number_type = number_type;
call_forward_infos_[reason].ton = ton;
call_forward_infos_[reason].number = number;
if (reason == CallForwardInfo::Reason::CFNR) {
cmd.SkipComma();
cmd.SkipComma();
cmd.SkipComma();
int timeSeconds = cmd.GetNextInt();
call_forward_infos_[reason].timeSeconds = timeSeconds >= 0 ? timeSeconds : 0;
}
}
break;
}
default:
client.SendCommandResponse(kCmeErrorInCorrectParameters);
return;
}
responses.push_back("OK");
client.SendCommandResponse(responses);
}
/**
* AT+CCWA
* This command allows control of the supplementary service Call Waiting
* according to 3GPP TS 22.083 [5] and Communication Waiting according to
* 3GPP TS 24.607 [137]. Activation, deactivation and status query are supported.
*
* Command Possible response(s)
* +CCWA=[<n>[,<mode>[,<class>]]] +CME ERROR: <err>
* when <mode>=2 and command successful
+CCWA: <status>,<class1>
[<CR><LF>+CCWA: <status>,<class2>
* <n>: integer type (sets/shows the result code presentation status to the TE).
* 0 disable
* 1 enable
* <mode>: integer type (when <mode> parameter is not given, network is not interrogated).
* 0 disable
* 1 enable
* 2 query status
* <classx>: a sum of integers each representing a class of information
* (default 7 - voice, data and fax).
* <status>: integer type
* 0 not active
* 1 active
*
* see RIL_REQUEST_QUERY_CALL_WAITING and RIL_REQUEST_SET_CALL_WAITING in RIL
*/
void SupService::HandleCallWaiting(const Client& client, std::string& command) {
std::vector<std::string> responses;
std::stringstream ss;
CommandParser cmd(command);
cmd.SkipPrefix();
cmd.SkipComma();
int mode = cmd.GetNextInt();
int classx = cmd.GetNextInt();
if (mode == 2) { // Query
if (classx == -1) {
classx = 7;
}
ss << "+CCWA: " << call_waiting_info_.mode << "," << classx;
responses.push_back(ss.str());
} else if (mode == 0 || mode == 1) { // Enable or disable
call_waiting_info_.mode = mode;
if (classx != -1) {
call_waiting_info_.classx = classx;
}
}
responses.push_back("OK");
client.SendCommandResponse(responses);
}
} // namespace cuttlefish