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