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/sms_service.h"
17 
18 #include "host/commands/modem_simulator/pdu_parser.h"
19 
20 namespace cuttlefish {
21 
SmsService(int32_t service_id,ChannelMonitor * channel_monitor,ThreadLooper * thread_looper)22 SmsService::SmsService(int32_t service_id, ChannelMonitor* channel_monitor,
23                        ThreadLooper* thread_looper)
24     : ModemService(service_id, this->InitializeCommandHandlers(),
25                    channel_monitor, thread_looper) {
26   InitializeServiceState();
27 }
28 
InitializeCommandHandlers()29 std::vector<CommandHandler> SmsService::InitializeCommandHandlers() {
30   std::vector<CommandHandler> command_handlers = {
31       CommandHandler("+CMGS",
32                      [this](const Client& client, std::string& cmd) {
33                        this->HandleSendSMS(client, cmd);
34                      }),
35       CommandHandler("+CNMA",
36                      [this](const Client& client, std::string& cmd) {
37                        this->HandleSMSAcknowledge(client, cmd);
38                      }),
39       CommandHandler("+CMGW",
40                      [this](const Client& client, std::string& cmd) {
41                        this->HandleWriteSMSToSim(client, cmd);
42                      }),
43       CommandHandler("+CMGD",
44                      [this](const Client& client, std::string& cmd) {
45                        this->HandleDeleteSmsOnSim(client, cmd);
46                      }),
47       CommandHandler("+CSCB",
48                      [this](const Client& client, std::string& cmd) {
49                        this->HandleBroadcastConfig(client, cmd);
50                      }),
51       CommandHandler(
52           "+CSCA?",
53           [this](const Client& client) { this->HandleGetSmscAddress(client); }),
54       CommandHandler("+CSCA=",
55                      [this](const Client& client, std::string& cmd) {
56                        this->HandleSetSmscAddress(client, cmd);
57                      }),
58       CommandHandler("+REMOTESMS",
59                      [this](const Client& client, std::string& cmd) {
60                        this->HandleReceiveRemoteSMS(client, cmd);
61                      }),
62   };
63   return (command_handlers);
64 }
65 
InitializeServiceState()66 void SmsService::InitializeServiceState() {
67   is_waiting_sms_pdu_ = false;
68   is_waiting_sms_to_sim_ = false;
69   message_id_ = 1;
70   message_reference_ = 1;
71 
72   broadcast_config_ = {0, "", ""};
73 }
74 
SetupDependency(SimService * sim)75 void SmsService::SetupDependency(SimService* sim) { sim_service_ = sim; }
76 
77 /**
78  * AT+CMGS
79  *   This command sends message from a TE to the network (SMS-SUBMIT).
80  *
81  * Command                            Possible response(s)
82  * +CMGS=<length><CR>                  "> "
83  * PDU is given<ctrl-Z/ESC>            +CMGS: <mr>[,<ackpdu>]<CR>OK
84  *                                     +CMS ERROR: <err>
85  *
86  * <length>:must indicate the number of octets coded in the TP
87  *          layer data unit to be given.
88  *
89  * see RIL_REQUEST_SEND_SMS in RIL
90  */
HandleSendSMS(const Client & client,std::string &)91 void SmsService::HandleSendSMS(const Client& client, std::string& /*command*/) {
92   is_waiting_sms_pdu_ = true;
93 
94   std::vector<std::string> responses;
95   responses.push_back("> ");
96   client.SendCommandResponse(responses);
97 }
98 
99 /**
100  * AT+CNMA
101  *   This command confirms reception of a new message (SMS-DELIVER or
102  * SMS-STATUS-REPORT) which is routed directly to the TE.
103  *
104  * Command                            Possible response(s)
105  * +CNMA [=<n>[, <length> [<CR>        OK
106  * PDU is given<ctrl-Z/ESC>]]]         +CMS ERROR: <err>
107  *
108  * <n>: integer type
109  *   0: command operates similarly as defined for the text mode
110  *   1: send RP-ACK
111  *   2: send RP-ERROR
112  * <length>: ACKPDU length(octet)
113  *
114  * see RIL_REQUEST_SMS_ACKNOWLEDGE in RIL
115  */
HandleSMSAcknowledge(const Client & client,std::string &)116 void SmsService::HandleSMSAcknowledge(const Client& client, std::string& /*command*/) {
117   client.SendCommandResponse("OK");
118 }
119 
120 /*
121  * AT+CMGW
122  *   This command stores message (either SMS-DELIVER or SMS-SUBMIT)
123  * to memory storage <mem2>.
124  *
125  * Command                            Possible response(s)
126  * +CMGW=<length>[,<stat>]<CR>         "> "
127  * PDU is given <ctrl-Z/ESC>           +CMGW: <index>
128  *                                     +CMS ERROR: <err>
129  * <length>: the length of TPDU(bit) with a range of 9-160
130  * < stat >: integer:
131  *        0: Unread Message. (MT)
132  *        1: Read Message. (MT)
133  *        2: Unsent Message. (MO)
134  *        3: Sent Message. (MO)
135  * < index>: index id of <mem2>
136  *
137  * see RIL_REQUEST_WRITE_SMS_TO_SIM in RIL
138  */
HandleWriteSMSToSim(const Client & client,std::string & command)139 void SmsService::HandleWriteSMSToSim(const Client& client, std::string& command) {
140   is_waiting_sms_to_sim_ = true;
141 
142   CommandParser cmd(command);
143   cmd.SkipPrefix();  // skip "AT+CMGW="
144   cmd.SkipComma();
145   sms_status_on_sim_ = (SmsMessage::SmsStatus)cmd.GetNextInt();
146   client.SendCommandResponse("> ");
147 }
148 
149 /**
150  * AT+CMGD
151  *   This command deletes message from preferred message storage <mem1>
152  * location <index>.
153  *
154  * Command                            Possible response(s)
155  * +CMGD=<index>[, <DelFlag>]          OK
156  *                                     +CMS ERROR: <err>
157  * < index>: index id of <mem2>
158  *
159  * see RIL_REQUEST_DELETE_SMS_ON_SIM in RIL
160  */
HandleDeleteSmsOnSim(const Client & client,std::string & command)161 void SmsService::HandleDeleteSmsOnSim(const Client& client, std::string& command) {
162   CommandParser cmd(command);
163   cmd.SkipPrefix();  // skip "AT+CMGD="
164 
165   int index = cmd.GetNextInt();
166   auto iter = messages_on_sim_card_.find(index);
167   if (iter == messages_on_sim_card_.end()) {
168     client.SendCommandResponse(kCmeErrorInvalidIndex);  // No such message
169     return;
170   }
171 
172   messages_on_sim_card_.erase(iter);
173   client.SendCommandResponse("OK");
174 }
175 
176 /**
177  * AT+CSCB
178  *   Set command selects which types of CBMs are to be received by the ME.
179  *
180  * Command                            Possible response(s)
181  * +CSCB=[<mode>[,<mids>[,<dcss>]]]    OK
182  * +CSCB?                              +CSCB: <mode>,<mids>,<dcss>
183  *
184  * <mode>:
185  *      0: message types specified in <mids> and <dcss> are accepted
186  *      1: message types specified in <mids> and <dcss> are not accepted
187  * <mids>: string type; all different possible combinations of CBM message
188  *         identifiers (refer <mid>).
189  * <dcss>: string type; all different possible combinations of CBM data coding
190  *         schemes.
191  *
192  * see RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG &
193  *     RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG in RIL
194  * Notes: This command is allowed in TEXT mode.
195  */
HandleBroadcastConfig(const Client & client,std::string & command)196 void SmsService::HandleBroadcastConfig(const Client& client, std::string& command) {
197   std::vector<std::string> responses;
198 
199   CommandParser cmd(command);
200   cmd.SkipPrefix();
201   if (*cmd == "AT+CSCB?") {  // Query
202     std::stringstream ss;
203     ss << "+CSCB: " << broadcast_config_.mode << ","
204                     << broadcast_config_.mids << ","
205                     << broadcast_config_.dcss;
206     responses.push_back(ss.str());
207   } else {  // Set
208     broadcast_config_.mode = cmd.GetNextInt();
209     broadcast_config_.mids = cmd.GetNextStr();
210     broadcast_config_.dcss = cmd.GetNextStr();
211   }
212   responses.push_back("OK");
213   client.SendCommandResponse(responses);
214 }
215 
216 /**
217  * AT+CSCA
218  *   Set command updates the SMSC address, through which mobile originated
219  * SMs are transmitted.
220  *
221  * Command                            Possible response(s)
222  * +CSCA=<sca>[,<tosca>]               OK
223  * +CSCA?                              +CSCA: <sca>,<tosca>
224  *
225  * <sca>: service center address, its maximum length is 20.
226  * <tosca>: service center address format,protocol uses 8-bit address integer.
227  *
228  * see RIL_REQUEST_SET_SMSC_ADDRESS in RIL
229  */
HandleGetSmscAddress(const Client & client)230 void SmsService::HandleGetSmscAddress(const Client& client) {
231   std::vector<std::string> responses;
232 
233   std::stringstream ss;
234   ss << "+CSCA: " << sms_service_center_address_.sca << ","
235                   << sms_service_center_address_.tosca;
236   responses.push_back(ss.str());
237   responses.push_back("OK");
238   client.SendCommandResponse(responses);
239 }
240 
HandleSetSmscAddress(const Client & client,std::string & command)241 void SmsService::HandleSetSmscAddress(const Client& client, std::string& command) {
242   CommandParser cmd(command);
243   cmd.SkipPrefix();  // skip "AT+CSCA="
244 
245   sms_service_center_address_.sca = cmd.GetNextStr();
246   sms_service_center_address_.tosca = cmd.GetNextInt();
247 
248   client.SendCommandResponse("OK");
249 }
250 
SendSmsToRemote(std::string remote_port,PDUParser & sms_pdu)251 void SmsService::SendSmsToRemote(std::string remote_port, PDUParser& sms_pdu) {
252   auto remote_client = ConnectToRemoteCvd(remote_port);
253   if (!remote_client->IsOpen()) {
254     return;
255   }
256 
257   auto local_host_port = GetHostPort();
258   auto pdu = sms_pdu.CreateRemotePDU(local_host_port);
259 
260   std::string command = "AT+REMOTESMS=" + pdu + "\r";
261   std::string token = "REM0";
262   remote_client->Write(token.data(), token.size());
263   remote_client->Write(command.data(), command.size());
264 }
265 
266 /* process AT+CMGS PDU */
HandleSendSMSPDU(const Client & client,std::string & command)267 void SmsService::HandleSendSMSPDU(const Client& client, std::string& command) {
268   is_waiting_sms_pdu_ = false;
269 
270   std::vector<std::string> responses;
271   PDUParser sms_pdu(command);
272   if (!sms_pdu.IsValidPDU()) {
273     /* Invalid PDU mode parameter */
274     client.SendCommandResponse(kCmsErrorInvalidPDUModeParam);
275     return;
276   }
277 
278   std::string phone_number = sms_pdu.GetPhoneNumberFromAddress();
279 
280   int port = 0;
281   if (phone_number.length() == 11) {
282     port = std::stoi(phone_number.substr(7));
283   } else if (phone_number.length() == 4) {
284     port = std::stoi(phone_number);
285   }
286 
287   if (phone_number == "") {  /* Phone number unknown */
288     LOG(ERROR) << "Failed to get phone number form address";
289     client.SendCommandResponse(kCmsErrorSCAddressUnknown);
290     return;
291   } else if (port >= kRemotePortRange.first &&
292              port <= kRemotePortRange.second) {
293     std::stringstream ss;
294     ss << port;
295     auto remote_host_port = ss.str();
296     if (GetHostPort() == remote_host_port) {  // Send SMS to local host port
297       thread_looper_->PostWithDelay(
298           std::chrono::seconds(1),
299           makeSafeCallback<SmsService>(this, [&sms_pdu](SmsService* me) {
300             me->HandleReceiveSMS(sms_pdu);
301           }));
302     } else {  // Send SMS to remote host port
303       SendSmsToRemote(remote_host_port, sms_pdu);
304     }
305   } else if (sim_service_ && phone_number == sim_service_->GetPhoneNumber()) {
306     /* Local phone number */
307     thread_looper_->PostWithDelay(
308         std::chrono::seconds(1),
309         makeSafeCallback<SmsService>(this, [sms_pdu](SmsService* me) {
310           me->HandleReceiveSMS(sms_pdu);
311         }));
312   } /* else pretend send SMS success */
313 
314   std::stringstream ss;
315   ss << "+CMGS: " << ++message_reference_;
316   responses.push_back(ss.str());
317   responses.push_back("OK");
318   client.SendCommandResponse(responses);
319 
320   if (sms_pdu.IsNeededStatuReport()) {
321     int ref = message_reference_;
322     thread_looper_->PostWithDelay(
323         std::chrono::seconds(1),
324         makeSafeCallback<SmsService>(this, [sms_pdu, ref](SmsService* me) {
325           me->HandleSMSStatuReport(sms_pdu, ref);
326         }));
327   }
328 }
329 
330 /* AT+CMGS callback function */
HandleReceiveSMS(PDUParser sms_pdu)331 void SmsService::HandleReceiveSMS(PDUParser sms_pdu) {
332   std::string pdu = sms_pdu.CreatePDU();
333   if (pdu != "") {
334     SendUnsolicitedCommand("+CMT: 0");
335     SendUnsolicitedCommand(pdu);
336   }
337 }
338 
339 /* Process AT+CMGW PDU */
HandleWriteSMSPduToSim(const Client & client,std::string & command)340 void SmsService::HandleWriteSMSPduToSim(const Client& client, std::string& command) {
341   is_waiting_sms_to_sim_ = false;
342 
343   SmsMessage message;
344   message.status = sms_status_on_sim_;
345   message.message = command;
346   int index = message_id_++;
347   messages_on_sim_card_[index] = message;
348 
349   std::vector<std::string> responses;
350   std::stringstream ss;
351   ss << "+CMGW: " << index;
352   responses.push_back(ss.str());
353   responses.push_back("OK");
354   client.SendCommandResponse(responses);
355 }
356 
357 /* SMS Status Report */
HandleSMSStatuReport(PDUParser sms_pdu,int message_reference)358 void SmsService::HandleSMSStatuReport(PDUParser sms_pdu, int message_reference) {
359   std::string response;
360   std::stringstream ss;
361 
362   auto pdu = sms_pdu.CreateStatuReport(message_reference);
363   auto pdu_length = (pdu.size() - 2) / 2;  // Not Including SMSC Address
364   if (pdu != "" && pdu_length > 0) {
365     ss << "+CDS: " << pdu_length;
366     SendUnsolicitedCommand(ss.str());
367     SendUnsolicitedCommand(pdu);
368   }
369 }
370 
371 /* AT+REMOTESMS=PDU */
HandleReceiveRemoteSMS(const Client &,std::string & command)372 void SmsService::HandleReceiveRemoteSMS(const Client& /*client*/, std::string& command) {
373   CommandParser cmd(command);
374   cmd.SkipPrefix();
375 
376   std::string pdu(*cmd);
377   PDUParser sms_pdu(pdu);
378   if (!sms_pdu.IsValidPDU()) {
379     LOG(ERROR) << "Failed to decode PDU";
380     return;
381   }
382   pdu = sms_pdu.CreatePDU();
383   if (pdu != "") {
384     SendUnsolicitedCommand("+CMT: 0");
385     SendUnsolicitedCommand(pdu);
386   }
387 }
388 }  // namespace cuttlefish
389