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