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