• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 #include "chpp/services/wwan.h"
18 
19 #include <inttypes.h>
20 #include <stdbool.h>
21 #include <stddef.h>
22 #include <stdint.h>
23 
24 #include "chpp/common/standard_uuids.h"
25 #include "chpp/common/wwan.h"
26 #include "chpp/common/wwan_types.h"
27 #include "chpp/log.h"
28 #include "chpp/macros.h"
29 #include "chpp/memory.h"
30 #include "chpp/services.h"
31 #include "chre/pal/wwan.h"
32 
33 /************************************************
34  *  Prototypes
35  ***********************************************/
36 
37 static enum ChppAppErrorCode chppDispatchWwanRequest(void *serviceContext,
38                                                      uint8_t *buf, size_t len);
39 static void chppWwanServiceNotifyReset(void *serviceContext);
40 
41 /************************************************
42  *  Private Definitions
43  ***********************************************/
44 
45 /**
46  * Configuration parameters for this service
47  */
48 static const struct ChppService kWwanServiceConfig = {
49     .descriptor.uuid = CHPP_UUID_WWAN_STANDARD,
50 
51     // Human-readable name
52     .descriptor.name = "WWAN",
53 
54     // Version
55     .descriptor.version.major = 1,
56     .descriptor.version.minor = 0,
57     .descriptor.version.patch = 0,
58 
59     // Notifies service if CHPP is reset
60     .resetNotifierFunctionPtr = &chppWwanServiceNotifyReset,
61 
62     // Client request dispatch function pointer
63     .requestDispatchFunctionPtr = &chppDispatchWwanRequest,
64 
65     // Client notification dispatch function pointer
66     .notificationDispatchFunctionPtr = NULL,  // Not supported
67 
68     // Min length is the entire header
69     .minLength = sizeof(struct ChppAppHeader),
70 };
71 
72 /**
73  * Structure to maintain state for the WWAN service and its Request/Response
74  * (RR) functionality.
75  */
76 struct ChppWwanServiceState {
77   struct ChppServiceState service;   // WWAN service state
78   const struct chrePalWwanApi *api;  // WWAN PAL API
79 
80   struct ChppRequestResponseState open;              // Service init state
81   struct ChppRequestResponseState close;             // Service deinit state
82   struct ChppRequestResponseState getCapabilities;   // Get Capabilities state
83   struct ChppRequestResponseState getCellInfoAsync;  // Get CellInfo Async state
84 };
85 
86 // Note: This global definition of gWwanServiceContext supports only one
87 // instance of the CHPP WWAN service at a time. This limitation is primarily due
88 // to the PAL API.
89 // It would be possible to generate different API and callback pointers to
90 // support multiple instances of the service or modify the PAL API to pass a
91 // void* for context, but this is not necessary in the current version of CHPP.
92 // In such case, wwanServiceContext would be allocated dynamically as part of
93 // chppRegisterWwanService(), e.g.
94 //   struct ChppWwanServiceState *wwanServiceContext = chppMalloc(...);
95 // instead of globally here.
96 struct ChppWwanServiceState gWwanServiceContext;
97 
98 /************************************************
99  *  Prototypes
100  ***********************************************/
101 
102 static enum ChppAppErrorCode chppWwanServiceOpen(
103     struct ChppWwanServiceState *wwanServiceContext,
104     struct ChppAppHeader *requestHeader);
105 static enum ChppAppErrorCode chppWwanServiceClose(
106     struct ChppWwanServiceState *wwanServiceContext,
107     struct ChppAppHeader *requestHeader);
108 static enum ChppAppErrorCode chppWwanServiceGetCapabilities(
109     struct ChppWwanServiceState *wwanServiceContext,
110     struct ChppAppHeader *requestHeader);
111 static enum ChppAppErrorCode chppWwanServiceGetCellInfoAsync(
112     struct ChppWwanServiceState *wwanServiceContext,
113     struct ChppAppHeader *requestHeader);
114 
115 static void chppWwanServiceCellInfoResultCallback(
116     struct chreWwanCellInfoResult *result);
117 
118 /************************************************
119  *  Private Functions
120  ***********************************************/
121 
122 /**
123  * Dispatches a client request from the transport layer that is determined to be
124  * for the WWAN service. If the result of the dispatch is an error, this
125  * function responds to the client with the same error.
126  *
127  * This function is called from the app layer using its function pointer given
128  * during service registration.
129  *
130  * @param serviceContext Maintains status for each service instance.
131  * @param buf Input data. Cannot be null.
132  * @param len Length of input data in bytes.
133  *
134  * @return Indicates the result of this function call.
135  */
chppDispatchWwanRequest(void * serviceContext,uint8_t * buf,size_t len)136 static enum ChppAppErrorCode chppDispatchWwanRequest(void *serviceContext,
137                                                      uint8_t *buf, size_t len) {
138   struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
139   struct ChppWwanServiceState *wwanServiceContext =
140       (struct ChppWwanServiceState *)serviceContext;
141   struct ChppRequestResponseState *rRState = NULL;
142   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
143   bool dispatched = true;
144 
145   UNUSED_VAR(len);
146 
147   switch (rxHeader->command) {
148     case CHPP_WWAN_OPEN: {
149       rRState = &wwanServiceContext->open;
150       chppServiceTimestampRequest(rRState, rxHeader);
151       error = chppWwanServiceOpen(wwanServiceContext, rxHeader);
152       break;
153     }
154 
155     case CHPP_WWAN_CLOSE: {
156       rRState = &wwanServiceContext->close;
157       chppServiceTimestampRequest(rRState, rxHeader);
158       error = chppWwanServiceClose(wwanServiceContext, rxHeader);
159       break;
160     }
161 
162     case CHPP_WWAN_GET_CAPABILITIES: {
163       rRState = &wwanServiceContext->getCapabilities;
164       chppServiceTimestampRequest(rRState, rxHeader);
165       error = chppWwanServiceGetCapabilities(wwanServiceContext, rxHeader);
166       break;
167     }
168 
169     case CHPP_WWAN_GET_CELLINFO_ASYNC: {
170       rRState = &wwanServiceContext->getCellInfoAsync;
171       chppServiceTimestampRequest(rRState, rxHeader);
172       error = chppWwanServiceGetCellInfoAsync(wwanServiceContext, rxHeader);
173       break;
174     }
175 
176     default: {
177       dispatched = false;
178       error = CHPP_APP_ERROR_INVALID_COMMAND;
179       break;
180     }
181   }
182 
183   if (dispatched == true && error != CHPP_APP_ERROR_NONE) {
184     // Request was dispatched but an error was returned. Close out
185     // chppServiceTimestampRequest()
186     chppServiceTimestampResponse(rRState);
187   }
188 
189   return error;
190 }
191 
192 /**
193  * Initializes the WWAN service upon an open request from the client and
194  * responds to the client with the result.
195  *
196  * @param serviceContext Maintains status for each service instance.
197  * @param requestHeader App layer header of the request.
198  *
199  * @return Indicates the result of this function call.
200  */
chppWwanServiceOpen(struct ChppWwanServiceState * wwanServiceContext,struct ChppAppHeader * requestHeader)201 static enum ChppAppErrorCode chppWwanServiceOpen(
202     struct ChppWwanServiceState *wwanServiceContext,
203     struct ChppAppHeader *requestHeader) {
204   static const struct chrePalWwanCallbacks palCallbacks = {
205       .cellInfoResultCallback = chppWwanServiceCellInfoResultCallback,
206   };
207 
208   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
209 
210   if (wwanServiceContext->service.openState == CHPP_OPEN_STATE_OPENED) {
211     CHPP_DEBUG_ASSERT_LOG(false, "WWAN service already open");
212     error = CHPP_APP_ERROR_INVALID_COMMAND;
213 
214   } else if (!wwanServiceContext->api->open(
215                  wwanServiceContext->service.appContext->systemApi,
216                  &palCallbacks)) {
217     CHPP_DEBUG_ASSERT_LOG(false, "WWAN PAL open failed");
218     error = CHPP_APP_ERROR_BEYOND_CHPP;
219 
220   } else {
221     CHPP_LOGD("WWAN service opened");
222     wwanServiceContext->service.openState = CHPP_OPEN_STATE_OPENED;
223 
224     struct ChppAppHeader *response =
225         chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader);
226     size_t responseLen = sizeof(*response);
227 
228     if (response == NULL) {
229       CHPP_LOG_OOM();
230       error = CHPP_APP_ERROR_OOM;
231     } else {
232       chppSendTimestampedResponseOrFail(&wwanServiceContext->service,
233                                         &wwanServiceContext->open, response,
234                                         responseLen);
235     }
236   }
237 
238   return error;
239 }
240 
241 /**
242  * Deinitializes the WWAN service.
243  *
244  * @param serviceContext Maintains status for each service instance.
245  * @param requestHeader App layer header of the request.
246  *
247  * @return Indicates the result of this function call.
248  */
chppWwanServiceClose(struct ChppWwanServiceState * wwanServiceContext,struct ChppAppHeader * requestHeader)249 static enum ChppAppErrorCode chppWwanServiceClose(
250     struct ChppWwanServiceState *wwanServiceContext,
251     struct ChppAppHeader *requestHeader) {
252   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
253 
254   wwanServiceContext->api->close();
255   wwanServiceContext->service.openState = CHPP_OPEN_STATE_CLOSED;
256 
257   CHPP_LOGD("WWAN service closed");
258 
259   struct ChppAppHeader *response =
260       chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader);
261   size_t responseLen = sizeof(*response);
262 
263   if (response == NULL) {
264     CHPP_LOG_OOM();
265     error = CHPP_APP_ERROR_OOM;
266   } else {
267     chppSendTimestampedResponseOrFail(&wwanServiceContext->service,
268                                       &wwanServiceContext->close, response,
269                                       responseLen);
270   }
271 
272   return error;
273 }
274 
275 /**
276  * Notifies the service of an incoming reset.
277  *
278  * @param serviceContext Maintains status for each service instance.
279  */
chppWwanServiceNotifyReset(void * serviceContext)280 static void chppWwanServiceNotifyReset(void *serviceContext) {
281   struct ChppWwanServiceState *wwanServiceContext =
282       (struct ChppWwanServiceState *)serviceContext;
283 
284   if (wwanServiceContext->service.openState != CHPP_OPEN_STATE_OPENED) {
285     CHPP_LOGW("WWAN service reset but wasn't open");
286   } else {
287     CHPP_LOGD("WWAN service reset. Closing");
288     wwanServiceContext->service.openState = CHPP_OPEN_STATE_CLOSED;
289     wwanServiceContext->api->close();
290   }
291 }
292 
293 /**
294  * Retrieves a set of flags indicating the WWAN features supported by the
295  * current implementation.
296  *
297  * @param serviceContext Maintains status for each service instance.
298  * @param requestHeader App layer header of the request.
299  *
300  * @return Indicates the result of this function call.
301  */
chppWwanServiceGetCapabilities(struct ChppWwanServiceState * wwanServiceContext,struct ChppAppHeader * requestHeader)302 static enum ChppAppErrorCode chppWwanServiceGetCapabilities(
303     struct ChppWwanServiceState *wwanServiceContext,
304     struct ChppAppHeader *requestHeader) {
305   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
306 
307   struct ChppWwanGetCapabilitiesResponse *response =
308       chppAllocServiceResponseFixed(requestHeader,
309                                     struct ChppWwanGetCapabilitiesResponse);
310   size_t responseLen = sizeof(*response);
311 
312   if (response == NULL) {
313     CHPP_LOG_OOM();
314     error = CHPP_APP_ERROR_OOM;
315   } else {
316     response->params.capabilities = wwanServiceContext->api->getCapabilities();
317 
318     CHPP_LOGD("chppWwanServiceGetCapabilities returning 0x%" PRIx32
319               ", %" PRIuSIZE " bytes",
320               response->params.capabilities, responseLen);
321     chppSendTimestampedResponseOrFail(&wwanServiceContext->service,
322                                       &wwanServiceContext->getCapabilities,
323                                       response, responseLen);
324   }
325 
326   return error;
327 }
328 
329 /**
330  * Query information about the current serving cell and its neighbors in
331  * response to a client request. This does not perform a network scan, but
332  * should return state from the current network registration data stored in the
333  * cellular modem.
334  *
335  * This function returns an error code synchronously. The requested cellular
336  * information shall be returned asynchronously to the client via the
337  * chppPlatformWwanCellInfoResultEvent() service response.
338  *
339  * @param serviceContext Maintains status for each service instance.
340  * @param requestHeader App layer header of the request.
341  *
342  * @return Indicates the result of this function call.
343  */
chppWwanServiceGetCellInfoAsync(struct ChppWwanServiceState * wwanServiceContext,struct ChppAppHeader * requestHeader)344 static enum ChppAppErrorCode chppWwanServiceGetCellInfoAsync(
345     struct ChppWwanServiceState *wwanServiceContext,
346     struct ChppAppHeader *requestHeader) {
347   UNUSED_VAR(requestHeader);
348 
349   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
350 
351   if (!wwanServiceContext->api->requestCellInfo()) {
352     CHPP_LOGE(
353         "WWAN requestCellInfo PAL API failed. Unable to register for callback");
354     error = CHPP_APP_ERROR_UNSPECIFIED;
355   }
356 
357   return error;
358 }
359 
360 /**
361  * PAL callback to provide the result of a prior Request Cell Info
362  * (cellInfoResultCallback).
363  *
364  * @param result Scan results.
365  */
chppWwanServiceCellInfoResultCallback(struct chreWwanCellInfoResult * result)366 static void chppWwanServiceCellInfoResultCallback(
367     struct chreWwanCellInfoResult *result) {
368   // Recover state
369   struct ChppRequestResponseState *rRState =
370       &gWwanServiceContext.getCellInfoAsync;
371   struct ChppWwanServiceState *wwanServiceContext =
372       container_of(rRState, struct ChppWwanServiceState, getCellInfoAsync);
373 
374   // Craft response per parser script
375   struct ChppWwanCellInfoResultWithHeader *response = NULL;
376   size_t responseLen = 0;
377   if (!chppWwanCellInfoResultFromChre(result, &response, &responseLen)) {
378     CHPP_LOGE("CellInfo conversion failed (OOM?) ID=%" PRIu8,
379               rRState->transaction);
380 
381     response = chppMalloc(sizeof(struct ChppAppHeader));
382     if (response == NULL) {
383       CHPP_LOG_OOM();
384     } else {
385       responseLen = sizeof(struct ChppAppHeader);
386     }
387   }
388 
389   if (response != NULL) {
390     response->header.handle = wwanServiceContext->service.handle;
391     response->header.type = CHPP_MESSAGE_TYPE_SERVICE_RESPONSE;
392     response->header.transaction = rRState->transaction;
393     response->header.error = (responseLen > sizeof(struct ChppAppHeader))
394                                  ? CHPP_APP_ERROR_NONE
395                                  : CHPP_APP_ERROR_CONVERSION_FAILED;
396     response->header.command = CHPP_WWAN_GET_CELLINFO_ASYNC;
397 
398     chppSendTimestampedResponseOrFail(&wwanServiceContext->service, rRState,
399                                       response, responseLen);
400   }
401 
402   gWwanServiceContext.api->releaseCellInfoResult(result);
403 }
404 
405 /************************************************
406  *  Public Functions
407  ***********************************************/
408 
chppRegisterWwanService(struct ChppAppState * appContext)409 void chppRegisterWwanService(struct ChppAppState *appContext) {
410   gWwanServiceContext.api = chrePalWwanGetApi(CHPP_PAL_WWAN_API_VERSION);
411 
412   if (gWwanServiceContext.api == NULL) {
413     CHPP_DEBUG_ASSERT_LOG(false,
414                           "WWAN PAL API incompatible. Cannot register service");
415 
416   } else {
417     chppRegisterService(appContext, (void *)&gWwanServiceContext,
418                         &gWwanServiceContext.service, &kWwanServiceConfig);
419     CHPP_DEBUG_ASSERT(gWwanServiceContext.service.handle);
420   }
421 }
422 
chppDeregisterWwanService(struct ChppAppState * appContext)423 void chppDeregisterWwanService(struct ChppAppState *appContext) {
424   // TODO
425 
426   UNUSED_VAR(appContext);
427 }
428