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