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/pdu_parser.h"
17 
18 #include <unistd.h>
19 
20 #include <algorithm>
21 #include <ctime>
22 #include <iomanip>
23 #include <sstream>
24 #include <string>
25 
26 namespace cuttlefish {
27 
28 static const std::string kWithoutServiceCenterAddress     = "00";
29 static const std::string kStatusReportIndicator           = "06";
30 static const std::string kSRIAndMMSIndicator              = "24";  /* SRI is 1 && MMS is 1*/
31 static const std::string kUDHIAndSRIAndMMSIndicator       = "64";  /* UDHI is 1 && SRI is 1 && MMS is 1*/
32 
PDUParser(std::string & pdu)33 PDUParser::PDUParser(std::string &pdu) {
34   is_valid_pdu_ = DecodePDU(pdu);
35 }
36 
IsValidPDU()37 bool PDUParser::IsValidPDU() {
38   return is_valid_pdu_;
39 }
40 
41 /**
42  * PDU format:
43  *         SCA    PDU-Type   MR         OA            PID    DCS   VP    UDL    UD
44  * bytes: 1-12      1        1         2-12            1      1     0     1    0-140
45  * eg.     00       21       00   0B 91 5155255155F4   00     00          0C  AB58AD56ABC962B55A8D06
46  */
47 //    00 01 00 05 81 0180F6 00 00 0D 61B2996C0691CD6433190402
DecodePDU(std::string & pdu)48 bool PDUParser::DecodePDU(std::string& pdu) {
49   // At least: SCA(1) + PDU-Type(1) + MR(1) + OA(2) + PID(1) + DSC(1) + UDL(1)
50   auto pdu_total_length = pdu.size();
51   if (pdu_total_length < 8) {
52     return false;
53   }
54 
55   std::string_view pdu_view = pdu;
56   size_t pos = 0;
57 
58   /* 1. SMSC Address Length: 1 byte */
59   std::string temp = pdu.substr(0, 2);
60   pos += 2;
61   if (temp != kWithoutServiceCenterAddress) {
62     auto smsc_length = Hex2ToByte(temp);
63     pos += smsc_length * 2;  // Skip SMSC Address
64   }
65 
66   /* 2. PDU-Type: 1 byte */
67   pdu_type_ = pdu_view.substr(std::min(pos, pdu_total_length), 2);
68   pos += 2;
69 
70   /* 3. MR: 1 byte */
71   message_reference_ = pdu_view.substr(std::min(pos, pdu_total_length), 2);
72   pos += 2;
73 
74   /* 4. Originator Address Length: 1 byte */
75   temp = pdu_view.substr(std::min(pos, pdu_total_length), 2);
76   auto oa_length = Hex2ToByte(temp);
77   if (oa_length & 0x01) oa_length += 1;
78 
79   /* 5. Originator Address including OA length */
80   originator_address_ = pdu_view.substr(std::min(pos, pdu_total_length), (oa_length + 4));
81   pos += (oa_length + 4);
82 
83   /* 6. Protocol ID: 1 byte */
84   protocol_id_ = pdu_view.substr(std::min(pos, pdu_total_length), 2);
85   pos += 2;
86 
87   /* 7. Data Code Scheme: 1 byte */
88   data_code_scheme_ = pdu_view.substr(std::min(pos, pdu_total_length), 2);
89   pos += 2;
90 
91   /* 8. User Data Length: 1 byte */
92   temp = pdu_view.substr(std::min(pos, pdu_total_length), 2);
93   auto ud_length = Hex2ToByte(temp);
94 
95   /* 9. User Data including UDL */
96   user_data_ = pdu_view.substr(std::min(pos, pdu_total_length));
97 
98   if (data_code_scheme_ == "00") {  // GSM_7BIT
99     pos += ud_length * 2 + 2;
100     int offset = ud_length / 8;
101     pos -= offset * 2;
102   } else if (data_code_scheme_ == "08") {  // GSM_UCS2
103     pos += ud_length;
104   } else {
105     pos += ud_length * 2 + 2;
106   }
107   if (pos == pdu_total_length) {
108     return true;
109   }
110 
111   return false;
112 }
113 
114 /**
115  * The PDU-Type of receiver
116  * BIT      7    6    5    4    3    2    1    0
117  * Param   RP  UDHI  SRI  -    -   MMS  MTI MTI
118  * When SRR bit is 1, it represents that SMS status report should be reported.
119  */
CreatePDU()120 std::string PDUParser::CreatePDU() {
121   if (!is_valid_pdu_) return "";
122 
123   // Ignore SMSC address, default to be '00'
124   std::string pdu = kWithoutServiceCenterAddress;
125   int pdu_type = Hex2ToByte(pdu_type_);
126 
127   if (pdu_type & 0x40) {
128     pdu += kUDHIAndSRIAndMMSIndicator;
129   } else {
130     pdu += kSRIAndMMSIndicator;
131   }
132 
133   pdu += originator_address_ + protocol_id_ + data_code_scheme_;
134   pdu += GetCurrentTimeStamp();
135   pdu += user_data_;
136 
137   return pdu;
138 }
139 
140 /**
141  * the PDU-Type of sender
142  * BIT     7    6    5    4    3    2    1    0
143  * Param   RP  UDHI  SRR  VPF  VPF  RD    MTI MTI
144  * When SRR bit is 1, it represents that SMS status report should be reported.
145  */
IsNeededStatuReport()146 bool PDUParser::IsNeededStatuReport() {
147   if (!is_valid_pdu_) return false;
148 
149   int pdu_type = Hex2ToByte(pdu_type_);
150   if (pdu_type & 0x20) {
151     return true;
152   }
153 
154   return false;
155 }
156 
CreateStatuReport(int message_reference)157 std::string PDUParser::CreateStatuReport(int message_reference) {
158   if (!is_valid_pdu_) return "";
159 
160   std::string pdu = kWithoutServiceCenterAddress;
161   pdu += kStatusReportIndicator;
162 
163   std::stringstream ss;
164   ss << std::setfill('0') << std::setw(2) << std::hex << message_reference;
165   pdu += ss.str();
166 
167   pdu += originator_address_;
168   pdu += GetCurrentTimeStamp();
169   sleep(1);
170   pdu += GetCurrentTimeStamp();
171   pdu += "00"; /* "00" means that SMS have been sent successfully */
172 
173   return pdu;
174 }
175 
CreateRemotePDU(std::string & host_port)176 std::string PDUParser::CreateRemotePDU(std::string& host_port) {
177   if (host_port.size() != 4 || !is_valid_pdu_) {
178     return "";
179   }
180 
181   std::string pdu = kWithoutServiceCenterAddress + pdu_type_ + message_reference_;
182 
183   // Remove the remote port
184   std::string number = GetPhoneNumberFromAddress();
185   auto new_phone_number = number.substr(0, number.size() - 4);;
186   new_phone_number.append(host_port);
187   if (new_phone_number.size() & 1) {
188     new_phone_number.append("F");
189   }
190 
191   // Add OA length and type
192   pdu += originator_address_.substr(0,
193       originator_address_.size() - new_phone_number .size());
194   pdu += BCDToString(new_phone_number);   // Add local host port
195   pdu += protocol_id_;
196   pdu += data_code_scheme_;
197   pdu += user_data_;
198 
199   return pdu;
200 }
201 
GetPhoneNumberFromAddress()202 std::string PDUParser::GetPhoneNumberFromAddress() {
203   if (!is_valid_pdu_) return "";
204 
205   // Skip OA length and type
206   std::string address;
207   if (originator_address_.size() == 18) {
208     address = originator_address_.substr(6);
209   } else {
210     address = originator_address_.substr(4);
211   }
212 
213   return BCDToString(address);
214 }
215 
HexCharToInt(char c)216 int PDUParser::HexCharToInt(char c) {
217   if (c >= '0' && c <= '9') return (c - '0');
218   if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
219   if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
220 
221   return -1;  // Invalid hex char
222 }
223 
Hex2ToByte(const std::string & hex)224 int PDUParser::Hex2ToByte(const std::string& hex) {
225   int  hi = HexCharToInt(hex[0]);
226   int  lo = HexCharToInt(hex[1]);
227 
228   if (hi < 0 || lo < 0) {
229     return -1;
230   }
231 
232   return ( (hi << 4) | lo );
233 }
234 
IntToHexString(int value)235 std::string PDUParser::IntToHexString(int value) {
236   int  hi = value / 10;
237   int  lo = value % 10;
238   return std::to_string(lo) + std::to_string(hi);
239 }
240 
BCDToString(std::string & data)241 std::string PDUParser::BCDToString(std::string& data) {
242   std::string dst;
243   if (data.empty()) {
244     return "";
245   }
246   int length = data.size();
247   if (length & 0x01) {  /* Must be even */
248     return "";
249   }
250   for (int i = 0; i < length; i += 2) {
251     dst += data[i + 1];
252     dst += data[i];
253   }
254 
255   if (dst[length -1] == 'F') {
256     dst.replace(length -1, length, "\0");
257   }
258   return dst;
259 }
260 
GetCurrentTimeStamp()261 std::string PDUParser::GetCurrentTimeStamp() {
262   std::string time_stamp;
263   auto now = std::time(0);
264 
265   auto local_time = *std::localtime(&now);
266   auto gm_time = *std::gmtime(&now);
267 
268   auto t_local_time = std::mktime(&local_time);
269   auto t_gm_time = std::mktime(&gm_time);
270 
271   auto tzdiff = (int)std::difftime(t_local_time, t_gm_time) / (60 * 60);
272 
273   time_stamp += IntToHexString(local_time.tm_year % 100);
274   time_stamp += IntToHexString(local_time.tm_mon + 1);
275   time_stamp += IntToHexString(local_time.tm_mday);
276   time_stamp += IntToHexString(local_time.tm_hour);
277   time_stamp += IntToHexString(local_time.tm_min);
278   time_stamp += IntToHexString(local_time.tm_sec);
279   time_stamp += IntToHexString(tzdiff);
280 
281   return time_stamp;
282 }
283 
284 } // namespace cuttlefish
285