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/data_service.h"
17 
18 #include <android-base/strings.h>
19 
20 #include "host/commands/modem_simulator/device_config.h"
21 
22 namespace cuttlefish {
23 
DataService(int32_t service_id,ChannelMonitor * channel_monitor,ThreadLooper * thread_looper)24 DataService::DataService(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> DataService::InitializeCommandHandlers() {
32   std::vector<CommandHandler> command_handlers = {
33       CommandHandler("+CGACT=",
34                      [this](const Client& client, std::string& cmd) {
35                        this->HandleActivateDataCall(client, cmd);
36                      }),
37       CommandHandler("+CGACT?",
38                      [this](const Client& client) {
39                        this->HandleQueryDataCallList(client);
40                      }),
41       CommandHandler("+CGDCONT=",
42                      [this](const Client& client, std::string& cmd) {
43                        this->HandlePDPContext(client, cmd);
44                      }),
45       CommandHandler("+CGDCONT?",
46                      [this](const Client& client) {
47                        this->HandleQueryPDPContextList(client);
48                      }),
49       CommandHandler("+CGQREQ=1",
50                      [this](const Client& client) {
51                        this->HandleCommandDefaultSupported(client);
52                      }),
53       CommandHandler("+CGQMIN=1",
54                      [this](const Client& client) {
55                        this->HandleCommandDefaultSupported(client);
56                      }),
57       CommandHandler("+CGEREP=1,0",
58                      [this](const Client& client) {
59                        this->HandleCommandDefaultSupported(client);
60                      }),
61       CommandHandler("+CGDATA",
62                      [this](const Client& client, std::string& cmd) {
63                        this->HandleEnterDataState(client, cmd);
64                      }),
65       CommandHandler("D*99***1#",
66                      [this](const Client& client) {
67                        this->HandleCommandDefaultSupported(client);
68                      }),
69       CommandHandler("+CGCONTRDP",
70                      [this](const Client& client, std::string& cmd) {
71                        this->HandleReadDynamicParam(client, cmd);
72                      }),
73   };
74   return (command_handlers);
75 }
76 
InitializeServiceState()77 void DataService::InitializeServiceState() {
78   // Initialize data connection config
79 }
80 
81 /**
82  * AT+CGACT
83  *   The execution command is used to activate or deactivate the specified PDP
84  * context(s).
85  *
86  * Command                            Possible response(s)
87  * +CGACT=[<state>[,<cid>              OK
88  *        [,<cid>[,...]]]]             +CME ERROR: <err>
89  * +CGACT?                             [+CGACT: <cid>,<state>]
90  *                                     [<CR><LF>+CGACT: <cid>,<state>[...]]
91  * <state>: integer type; indicates the state of PDP context activation.
92  *       0: deactivated
93  *       1: activated
94  * <cid>: (PDP Context Identifier) integer(1~15), specifies the PDP context ID.
95  *
96  * see RIL_REQUEST_SETUP_DATA_CALL in RIL
97  */
HandleActivateDataCall(const Client & client,const std::string &)98 void DataService::HandleActivateDataCall(const Client& client,
99                                          const std::string& /*command*/) {
100   client.SendCommandResponse("OK");
101 }
102 
103 /**
104  * see AT+CGACT
105  */
HandleQueryDataCallList(const Client & client)106 void DataService::HandleQueryDataCallList(const Client& client) {
107   std::vector<std::string> responses;
108 
109   std::stringstream ss;
110   for (auto iter = pdp_context_.begin(); iter != pdp_context_.end(); ++iter) {
111     if (iter->state == PDPContext::ACTIVE) {
112       ss.clear();
113       ss << "+CGACT: " << iter->cid << "," << iter->state;
114       responses.push_back(ss.str());
115       ss.str("");
116     }
117   }
118   responses.push_back("OK");
119   client.SendCommandResponse(responses);
120 }
121 
122 /**
123  * AT+CGDCONT
124  *   The set command specifies PDP context parameter values for a PDP context
125  * identified by the (local) context identification parameter, <cid>.
126  *
127  * Command                            Possible response(s)
128  * +CGDCONT=[<cid>[,<PDP_type>[,<APN>  OK
129  * [,<PDP_addr>[,<d_comp> [,<h_comp>]  +CME ERROR: <err>
130  * ]]]]]
131  * +CGDCONT?                           +CGDCONT: <cid>,<pdp_type>,<APN>,
132  *                                     <pdp_addr>,<d_comp>,<h_comp><CR><LF>
133  *                                     [+CGDCONT: <cid>,<pdp_type>,<APN>,
134  *                                     <pdp_addr>,<d_comp>,<h_comp><CR><LF>[...]]
135  *                                     OK
136  * <cid>: see AT+CGACT
137  * <PDP_type>: string type; specifies the type of packet data protocol.
138  *             Value: X.25, IP, IPV6, IPV4V6, OSPIH, PPP, Non-IP,Ethernet
139  * <APN>: string type; a logical name that is used to select the GGSN or the
140  *        external packet data network.If the value is null or omitted, then
141  *        the subscription value will be requested
142  * <PDP_addr>: string type; identifies the MT in the address space applicable
143  *             to the PDP
144  * <d_comp>: integer type; controls PDP data compression
145  * <h_comp>: integer type; controls PDP header compression
146  *
147  * see RIL_REQUEST_SETUP_DATA_CALL in RIL
148  */
HandlePDPContext(const Client & client,const std::string & command)149 void DataService::HandlePDPContext(const Client& client,
150                                    const std::string& command) {
151   CommandParser cmd(command);
152   cmd.SkipPrefix(); /* skip +CGDCONT= */
153   int cid = cmd.GetNextInt();
154 
155   std::string ip_type(cmd.GetNextStr(','));
156   std::string apn(cmd.GetNextStr(','));
157 
158   auto address = cuttlefish::modem::DeviceConfig::ril_address_and_prefix();
159   auto dnses = cuttlefish::modem::DeviceConfig::ril_dns();
160   auto gateways = cuttlefish::modem::DeviceConfig::ril_gateway();
161 
162   PDPContext pdp_context = {cid,
163                             PDPContext::ACTIVE,
164                             ip_type,  // IPV4 or IPV6 or IPV4V6
165                             apn,
166                             address,
167                             dnses,
168                             gateways};
169 
170   // check cid
171   auto iter = pdp_context_.begin();
172   for (; iter != pdp_context_.end(); ++iter) {
173     if (pdp_context.cid == iter->cid) {
174       *iter = pdp_context;
175       break;
176     }
177   }
178 
179   if (iter == pdp_context_.end()) {
180     pdp_context_.push_back(pdp_context);
181   }
182 
183   client.SendCommandResponse("OK");
184 }
185 
186 /**
187  * see AT+CGDCONT above
188  */
HandleQueryPDPContextList(const Client & client)189 void DataService::HandleQueryPDPContextList(const Client& client) {
190   std::vector<std::string> responses;
191 
192   std::stringstream ss;
193   for (auto it = pdp_context_.begin(); it != pdp_context_.end(); ++it) {
194     std::stringstream ss;
195     ss << "+CGDCONT: " << it->cid << "," << it->conn_types << ","
196        << it->apn << "," << it->addresses << ",0,0";
197     responses.push_back(ss.str());
198   }
199   responses.push_back("OK");
200   client.SendCommandResponse(responses);
201 }
202 
203 /**
204  * AT+CGDATA
205  *   The execution command causes the MT to perform whatever actions are
206  * necessary to establish communication between the TE and the network using
207  * one or more Packet Domain PDP types.
208  *
209  * Command                            Possible response(s)
210  * +CGDATA[=<L2P>[,[,<cid>             CONNECT
211  *          [,...]]]]                  ERROR
212  *                                     +CME ERROR: <err>
213  *
214  * <L2P>: string type; indicates the layer 2 protocol to be used between the
215  *        TE and MT NULL  none, for PDP type OSP:IHOSS (Obsolete)
216  *        value: PPP, PAD, X25, M-xxxx
217  * <cid>: see AT+CGACT
218  *
219  * see RIL_REQUEST_SETUP_DATA_CALL in RIL
220  */
HandleEnterDataState(const Client & client,const std::string & command)221 void DataService::HandleEnterDataState(const Client& client,
222                                        const std::string& command) {
223   std::string response;
224 
225   CommandParser cmd(command);
226   cmd.SkipPrefix();
227   cmd.SkipComma();
228   int cid = cmd.GetNextInt();
229 
230   // Check cid
231   auto iter = pdp_context_.begin();
232   for (; iter != pdp_context_.end(); ++iter) {
233     if (cid == iter->cid && iter->state == PDPContext::ACTIVE) {
234       response = "CONNECT";
235       break;
236     }
237   }
238 
239   if (iter == pdp_context_.end()) {
240     response = "ERROR";
241   }
242 
243   client.SendCommandResponse(response);
244 }
245 
246 /**
247  * AT+CGCONTRDP
248  *   The execution command returns the relevant information for an active non
249  * secondary PDP context with the context identifier <cid>.
250  *
251  * Command                            Possible response(s)
252  * +CGCONTRDP[=<cid>]                 [+CGCONTRDP: <cid>,<bearer_id>,<apn>
253  *                                    [,<local_addr and subnet_mask>[,<gw_addr>
254  *                                    [,<DNS_prim_addr>[<DNS_sec_addr>[...]]]]]]
255  *                                    [<CR><LF>+CGCONTRDP: <cid>,<bearer_id>,<apn>
256  *                                    [,<local_addr and subnet_mask>[,<gw_addr>
257  *                                    [,<DNS_prim_addr>[<DNS_sec_addr>[...]]]]]]
258  *
259  * <cid>: see AT+CGACT
260  * <bearer_id>: integer type; identifies the bearer, i.e. the EPS bearer and
261  *              the NSAPI.
262  * <local_addr and subnet_mask>: string type; shows the IP address and subnet
263  *                               mask of the MT.
264  * <gw_addr>: string type; shows the Gateway Address of the MT. The string is
265  *            given as dot-separated numeric (0-255) parameters.
266  * <DNS_prim_addr>: string type; shows the IP address of the primary DNS server.
267  * <DNS_sec_addr>: string type; shows the IP address of the secondary DNS server.
268  *
269  *
270  * see RIL_REQUEST_SETUP_DATA_CALL in RIL
271  */
HandleReadDynamicParam(const Client & client,const std::string & command)272 void DataService::HandleReadDynamicParam(const Client& client,
273                                          const std::string& command) {
274   std::vector<std::string> responses;
275 
276   CommandParser cmd(command);
277   cmd.SkipPrefix(); /* skip prefix AT+CGCONTRDP= */
278 
279   int cid = cmd.GetNextInt();
280   auto iter = pdp_context_.begin();  // Check cid
281   for (; iter != pdp_context_.end(); ++iter) {
282     if (cid == iter->cid && iter->state == PDPContext::ACTIVE) {
283       break;
284     }
285   }
286 
287   if (iter == pdp_context_.end()) {
288     responses.push_back(kCmeErrorInvalidIndex);  // number
289   } else {
290     std::stringstream ss;
291     ss << "+CGCONTRDP: "
292        << iter->cid << ",5,"
293        << iter->apn << ","
294        << iter->addresses << ","
295        << iter->gateways << ","
296        << iter->dnses;
297     responses.push_back(ss.str());
298     responses.push_back("OK");
299   }
300 
301   client.SendCommandResponse(responses);
302 }
303 
sendOnePhysChanCfgUpdate(int status,int bandwidth,int rat,int freq,int id)304 void DataService::sendOnePhysChanCfgUpdate(int status, int bandwidth, int rat,
305                                            int freq, int id) {
306   std::stringstream ss;
307   ss << "%CGFPCCFG: " << status << "," << bandwidth << "," << rat << "," << freq
308      << "," << id;
309   SendUnsolicitedCommand(ss.str());
310 }
311 
onUpdatePhysicalChannelconfigs(int modem_tech,int freq,int cellBandwidthDownlink)312 void DataService::onUpdatePhysicalChannelconfigs(int modem_tech, int freq,
313                                                  int cellBandwidthDownlink) {
314   updatePhysicalChannelconfigs(modem_tech, freq, cellBandwidthDownlink, 3);
315 }
316 
updatePhysicalChannelconfigs(int modem_tech,int freq,int cellBandwidthDownlink,int count)317 void DataService::updatePhysicalChannelconfigs(int modem_tech, int freq,
318                                                int cellBandwidthDownlink,
319                                                int count) {
320   if (count <= 0) {
321     return;
322   }
323 
324   const int PRIMARY_SERVING = 1;
325   const int SECONDARY_SERVING = 2;
326 
327   for (const auto& iter : pdp_context_) {
328     if (iter.state == PDPContext::ACTIVE) {
329       sendOnePhysChanCfgUpdate(PRIMARY_SERVING, cellBandwidthDownlink,
330                                modem_tech, freq, iter.cid);
331       sendOnePhysChanCfgUpdate(SECONDARY_SERVING, cellBandwidthDownlink,
332                                modem_tech, freq, iter.cid);
333     }
334   }
335 
336   // call again after 1 sec delay
337   count--;
338   thread_looper_->PostWithDelay(
339       std::chrono::seconds(1),
340       makeSafeCallback(this, &DataService::updatePhysicalChannelconfigs,
341                        modem_tech, freq, cellBandwidthDownlink, count));
342 }
343 
344 }  // namespace cuttlefish
345