| // |
| // 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 |