1 //
2 // Copyright (C) 2020 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include "host/commands/modem_simulator/sup_service.h"
17 
18 namespace cuttlefish {
19 
SupService(int32_t service_id,ChannelMonitor * channel_monitor,ThreadLooper * thread_looper)20 SupService::SupService(int32_t service_id, ChannelMonitor* channel_monitor,
21                        ThreadLooper* thread_looper)
22     : ModemService(service_id, this->InitializeCommandHandlers(),
23                    channel_monitor, thread_looper) {
24   InitializeServiceState();
25 }
26 
InitializeCommandHandlers()27 std::vector<CommandHandler> SupService::InitializeCommandHandlers() {
28   std::vector<CommandHandler> command_handlers = {
29       CommandHandler("+CUSD",
30                      [this](const Client& client, std::string& cmd) {
31                        this->HandleUSSD(client, cmd);
32                      }),
33       CommandHandler("+CLIR",
34                      [this](const Client& client, std::string& cmd) {
35                        this->HandleCLIR(client, cmd);
36                      }),
37       CommandHandler("+CCWA",
38                      [this](const Client& client, std::string& cmd) {
39                        this->HandleCallWaiting(client, cmd);
40                      }),
41       CommandHandler(
42           "+CLIP?", [this](const Client& client) { this->HandleCLIP(client); }),
43       CommandHandler("+CCFCU",
44                      [this](const Client& client, std::string& cmd) {
45                        this->HandleCallForward(client, cmd);
46                      }),
47       CommandHandler("+CSSN",
48                      [this](const Client& client, std::string& cmd) {
49                        this->HandleSuppServiceNotifications(client, cmd);
50                      }),
51   };
52   return (command_handlers);
53 }
54 
InitializeServiceState()55 void SupService::InitializeServiceState() {
56   call_forward_infos_ = {
57     CallForwardInfo(CallForwardInfo::Reason::CFU),
58     CallForwardInfo(CallForwardInfo::Reason::CFB),
59     CallForwardInfo(CallForwardInfo::Reason::CFNR),
60     CallForwardInfo(CallForwardInfo::Reason::CFNRC)
61   };
62 }
63 
64 /**
65  * AT+CUSD
66  *   This command allows control of the Unstructured Supplementary Service Data (USSD)
67  * according to 3GPP TS 22.090 [23], 3GPP TS 24.090 [148] and 3GPP TS 24.390 [131].
68  * Both network and mobile initiated operations are supported.
69  *
70  * Command                        Possible response(s)
71  * +CUSD=[<n>[,<str>[,<dcs>]]]      +CME ERROR: <err>
72  * +CUSD?                           +CUSD: <n>
73  *
74  * <n>: integer type (sets/shows the result code presentation status to the TE).
75  *   0 disable the result code presentation to the TE
76  *   1 enable the result code presentation to the TE
77  *   2 cancel session (not applicable to read command response)
78  * <str>: string type USSD string
79  *   when <str> parameter is not given, network is not interrogated
80  * <dcs>: integer type (shows Cell Broadcast Data Coding Scheme, see 3GPP TS 23.038 [25]).
81  *   Default value is 0.
82  *
83  * see RIL_REQUEST_SEND_USSD or RIL_REQUEST_CANCEL_USSD in RIL
84  */
HandleUSSD(const Client & client,std::string &)85 void SupService::HandleUSSD(const Client& client, std::string& /*command*/) {
86   client.SendCommandResponse("OK");
87 }
88 
89 /**
90  * AT+CLIR
91  *   This command refers to CLIR‑service according to 3GPP TS 22.081 that allows
92  * a calling subscriber to enable or disable the presentation of the CLI to the
93  * called party when originating a call.
94  *
95  * Command                        Possible response(s)
96  * +CLIR: <n>
97  * +CLIR?                         +CLIR: <n>,<m>
98  *
99  * <n>: integer type (parameter sets the adjustment for outgoing calls).
100  *   0 presentation indicator is used according to the subscription of the CLIR service
101  *   1 CLIR invocation
102  *   2 CLIR suppression
103  * <m>: integer type (parameter shows the subscriber CLIR / OIR service status in the network).
104  *   0 CLIR / OIR not provisioned
105  *   1 CLIR / OIR provisioned in permanent mode
106  *   2 unknown (e.g. no network, etc.)
107  *   3 CLIR / OIR temporary mode presentation restricted
108  *   4 CLIR / OIR temporary mode presentation allowed
109  *
110  * see RIL_REQUEST_SET_CLIR or RIL_REQUEST_GET_CLIR in RIL
111  */
HandleCLIR(const Client & client,std::string & command)112 void SupService::HandleCLIR(const Client& client, std::string& command) {
113   std::vector<std::string> responses;
114   std::stringstream ss;
115 
116   CommandParser cmd(command);
117   cmd.SkipPrefix();
118   if (*cmd == "AT+CLIR?") {
119     ss << "+CLIR:" << clir_status_.type << "," << clir_status_.status;
120     responses.push_back(ss.str());
121   } else {
122     clir_status_.type = (ClirStatusInfo::ClirType)cmd.GetNextInt();
123   }
124   responses.push_back("OK");
125   client.SendCommandResponse(responses);
126 }
127 
128 /**
129  * AT+CLIP
130  *   This command refers to the supplementary service CLIP (Calling Line
131  * Identification Presentation) according to 3GPP TS 22.081 [3] and OIP
132  * (Originating Identification Presentation) according to 3GPP TS 24.607 [119]
133  * that enables a called subscriber to get the calling line identity (CLI) of
134  * the calling party when receiving a mobile terminated call.
135  *
136  * Command                        Possible response(s)
137  * +CLIP?                         +CLIP: <n>,<m>
138  *
139  * <n>: integer type (parameter sets/shows the result code presentation status to the TE).
140  *   0 disable
141  *   1 enable
142  * <m>: integer type (parameter shows the subscriber CLIR / OIR service status in the network).
143  *   0 CLIP / OIP not provisioned
144  *   1 CLIP / OIP provisioned
145  *   2 unknown (e.g. no network, etc.)
146  *
147  * see RIL_REQUEST_QUERY_CLIP in RIL
148  */
HandleCLIP(const Client & client)149 void SupService::HandleCLIP(const Client& client) {
150   std::vector<std::string> responses = {"+CLIP: 0, 0", "OK"};
151   client.SendCommandResponse(responses);
152 }
153 
154 /**
155  * AT+CSSN
156  *   This command refers to supplementary service related network initiated
157  * notifications. The set command enables/disables the presentation of
158  * notification result codes from TA to TE.
159  *
160  * Command                        Possible response(s)
161  * +CSSN: [<n>[,<m>]]
162  *
163  * <n>: integer type (parameter sets/shows the +CSSI intermediate result code
164  *                    presentation status to the TE)
165  *   0   disable
166  *   1   enable
167  * <m>: integer type (parameter sets/shows the +CSSU unsolicited result code
168  *                    presentation status to the TE)
169  *   0   disable
170  *   1   enable
171  *
172  * see RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION in RIL
173  */
HandleSuppServiceNotifications(const Client & client,std::string &)174 void SupService::HandleSuppServiceNotifications(const Client& client, std::string& /*command*/) {
175   client.SendCommandResponse("OK");
176 }
177 
178 /**
179  * AT+CCFCU
180  *   The command allows control of the communication forwarding supplementary service
181  * according to 3GPP TS 22.072 [31], 3GPP TS 22.082 [4] and 3GPP TS 24.604 [132].
182  *
183  * Command                            Possible response(s)
184  * +CCFCU=<reason>,<mode>               +CME ERROR: <err>
185  * [,<numbertype>,<ton>,<number>        when <mode>=2 and command successful:
186  * [,<class>,<ruleset>                  +CCFCU: <status>,<class1>[,<numbertype>,
187  * [,<subaddr>[,<satype>[,<time>]]]]]           <ton>,<number>[,<subaddr>,<satype>[,<time>]]]
188  * [,<class>,<ruleset>
189  *
190  * see SupService::CallForwardInfo
191  *
192  * see RIL_REQUEST_SET_CALL_FORWARD or RIL_REQUEST_QUERY_CALL_FORWARD_STATUS in RIL
193  */
HandleCallForward(const Client & client,std::string & command)194 void SupService::HandleCallForward(const Client& client, std::string& command) {
195   std::vector<std::string> responses;
196   std::stringstream ss;
197 
198   CommandParser cmd(command);
199   cmd.SkipPrefix();
200 
201   int reason = cmd.GetNextInt();
202   int status = cmd.GetNextInt();
203   int number_type = cmd.GetNextInt();
204   int ton = cmd.GetNextInt();
205   std::string_view number = cmd.GetNextStr();
206   int classx = cmd.GetNextInt();
207 
208   switch (reason) {
209     case CallForwardInfo::Reason::ALL_CF: {
210       if (status == CallForwardInfo::CallForwardInfoStatus::INTERROGATE) {
211         auto iter = call_forward_infos_.begin();
212         for (; iter != call_forward_infos_.end(); ++iter) {
213           ss.clear();
214           ss << "+CCFCU: " << iter->status << "," << classx << "," << number_type
215                   << "," << ton << ",\"" << iter->number << "\"";
216           if (iter->reason == CallForwardInfo::Reason::CFNR) {
217             ss << ",,," << iter->timeSeconds;
218           }
219           responses.push_back(ss.str());
220           ss.str("");
221         }
222       }
223       break;
224     }
225     case CallForwardInfo::Reason::CFU:
226     case CallForwardInfo::Reason::CFB:
227     case CallForwardInfo::Reason::CFNR:
228     case CallForwardInfo::Reason::CFNRC: {
229       if (status == CallForwardInfo::CallForwardInfoStatus::INTERROGATE) {
230         ss << "+CCFCU: " << call_forward_infos_[reason].status
231            << "," << classx << "," << number_type << "," << ton << ",\""
232            << call_forward_infos_[reason].number << "\"";
233         if (reason == CallForwardInfo::Reason::CFNR) {
234           ss << ",,," << call_forward_infos_[reason].timeSeconds;
235         }
236         responses.push_back(ss.str());
237       } else {
238         if (status == CallForwardInfo::CallForwardInfoStatus::REGISTRATION) {
239           call_forward_infos_[reason].status
240                 = CallForwardInfo::CallForwardInfoStatus::ENABLE;
241         } else {
242           call_forward_infos_[reason].status =
243                 (CallForwardInfo::CallForwardInfoStatus)status;
244         }
245         call_forward_infos_[reason].number_type = number_type;
246         call_forward_infos_[reason].ton = ton;
247         call_forward_infos_[reason].number = number;
248         if (reason == CallForwardInfo::Reason::CFNR) {
249           cmd.SkipComma();
250           cmd.SkipComma();
251           cmd.SkipComma();
252           call_forward_infos_[reason].timeSeconds = cmd.GetNextInt();
253         }
254       }
255       break;
256     }
257     default:
258       client.SendCommandResponse(kCmeErrorInCorrectParameters);
259       return;
260   }
261 
262   responses.push_back("OK");
263   client.SendCommandResponse(responses);
264 }
265 
266 /**
267  * AT+CCWA
268  *   This command allows control of the supplementary service Call Waiting
269  * according to 3GPP TS 22.083 [5] and Communication Waiting according to
270  * 3GPP TS 24.607 [137]. Activation, deactivation and status query are supported.
271  *
272  * Command                        Possible response(s)
273  * +CCWA=[<n>[,<mode>[,<class>]]] +CME ERROR: <err>
274  *                                when <mode>=2 and command successful
275                                   +CCWA: <status>,<class1>
276                                       [<CR><LF>+CCWA: <status>,<class2>
277  * <n>: integer type (sets/shows the result code presentation status to the TE).
278  *  0   disable
279  *  1   enable
280  * <mode>: integer type (when <mode> parameter is not given, network is not interrogated).
281  *  0   disable
282  *  1   enable
283  *  2   query status
284  * <classx>: a sum of integers each representing a class of information
285  *           (default 7 - voice, data and fax).
286  * <status>: integer type
287  *  0   not active
288  *  1   active
289  *
290  * see RIL_REQUEST_QUERY_CALL_WAITING and RIL_REQUEST_SET_CALL_WAITING in RIL
291  */
HandleCallWaiting(const Client & client,std::string & command)292 void SupService::HandleCallWaiting(const Client& client, std::string& command) {
293   std::vector<std::string> responses;
294   std::stringstream ss;
295 
296   CommandParser cmd(command);
297   cmd.SkipPrefix();
298   cmd.SkipComma();
299   int mode = cmd.GetNextInt();
300   int classx = cmd.GetNextInt();
301 
302   if (mode == 2) {  // Query
303     if (classx == -1) {
304       classx = 7;
305     }
306     ss << "+CCWA: " << call_waiting_info_.mode << "," << classx;
307     responses.push_back(ss.str());
308   } else if (mode == 0 || mode == 1) {  // Enable or disable
309     call_waiting_info_.mode = mode;
310     if (classx != -1) {
311       call_waiting_info_.classx = classx;
312     }
313   }
314 
315   responses.push_back("OK");
316   client.SendCommandResponse(responses);
317 }
318 
319 }  // namespace cuttlefish
320