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.h"
18 
19 #include <inttypes.h>
20 #include <stdbool.h>
21 #include <stddef.h>
22 #include <stdint.h>
23 
24 #include "chpp/app.h"
25 #include "chpp/log.h"
26 #include "chpp/memory.h"
27 #ifdef CHPP_SERVICE_ENABLED_GNSS
28 #include "chpp/services/gnss.h"
29 #endif
30 #ifdef CHPP_SERVICE_ENABLED_WIFI
31 #include "chpp/services/wifi.h"
32 #endif
33 #ifdef CHPP_SERVICE_ENABLED_WWAN
34 #include "chpp/services/wwan.h"
35 #endif
36 #include "chpp/time.h"
37 #include "chpp/transport.h"
38 
39 /************************************************
40  *  Public Functions
41  ***********************************************/
42 
chppRegisterCommonServices(struct ChppAppState * context)43 void chppRegisterCommonServices(struct ChppAppState *context) {
44   UNUSED_VAR(context);
45 
46 #ifdef CHPP_SERVICE_ENABLED_WWAN
47   if (context->clientServiceSet.wwanService) {
48     chppRegisterWwanService(context);
49   }
50 #endif
51 
52 #ifdef CHPP_SERVICE_ENABLED_WIFI
53   if (context->clientServiceSet.wifiService) {
54     chppRegisterWifiService(context);
55   }
56 #endif
57 
58 #ifdef CHPP_SERVICE_ENABLED_GNSS
59   if (context->clientServiceSet.gnssService) {
60     chppRegisterGnssService(context);
61   }
62 #endif
63 }
64 
chppDeregisterCommonServices(struct ChppAppState * context)65 void chppDeregisterCommonServices(struct ChppAppState *context) {
66   UNUSED_VAR(context);
67 
68 #ifdef CHPP_SERVICE_ENABLED_WWAN
69   if (context->clientServiceSet.wwanService) {
70     chppDeregisterWwanService(context);
71   }
72 #endif
73 
74 #ifdef CHPP_SERVICE_ENABLED_WIFI
75   if (context->clientServiceSet.wifiService) {
76     chppDeregisterWifiService(context);
77   }
78 #endif
79 
80 #ifdef CHPP_SERVICE_ENABLED_GNSS
81   if (context->clientServiceSet.gnssService) {
82     chppDeregisterGnssService(context);
83   }
84 #endif
85 }
86 
chppRegisterService(struct ChppAppState * appContext,void * serviceContext,const struct ChppService * newService)87 uint8_t chppRegisterService(struct ChppAppState *appContext,
88                             void *serviceContext,
89                             const struct ChppService *newService) {
90   CHPP_NOT_NULL(newService);
91 
92   if (appContext->registeredServiceCount >= CHPP_MAX_REGISTERED_SERVICES) {
93     CHPP_LOGE("Max services registered: # %" PRIu8,
94               appContext->registeredServiceCount);
95     return CHPP_HANDLE_NONE;
96 
97   } else {
98     appContext->registeredServices[appContext->registeredServiceCount] =
99         newService;
100     appContext->registeredServiceContexts[appContext->registeredServiceCount] =
101         serviceContext;
102 
103     char uuidText[CHPP_SERVICE_UUID_STRING_LEN];
104     chppUuidToStr(newService->descriptor.uuid, uuidText);
105     CHPP_LOGD("Registered service # %" PRIu8
106               " on handle %d"
107               " with name=%s, UUID=%s, version=%" PRIu8 ".%" PRIu8 ".%" PRIu16
108               ", min_len=%" PRIuSIZE " ",
109               appContext->registeredServiceCount,
110               CHPP_SERVICE_HANDLE_OF_INDEX(appContext->registeredServiceCount),
111               newService->descriptor.name, uuidText,
112               newService->descriptor.version.major,
113               newService->descriptor.version.minor,
114               newService->descriptor.version.patch, newService->minLength);
115 
116     return CHPP_SERVICE_HANDLE_OF_INDEX(appContext->registeredServiceCount++);
117   }
118 }
119 
chppAllocServiceNotification(size_t len)120 struct ChppAppHeader *chppAllocServiceNotification(size_t len) {
121   CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
122 
123   struct ChppAppHeader *result = chppMalloc(len);
124   if (result) {
125     result->handle = CHPP_HANDLE_NONE;
126     result->type = CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION;
127     result->transaction = 0;
128     result->error = CHPP_APP_ERROR_NONE;
129     result->command = CHPP_APP_COMMAND_NONE;
130   }
131   return result;
132 }
133 
chppAllocServiceResponse(const struct ChppAppHeader * requestHeader,size_t len)134 struct ChppAppHeader *chppAllocServiceResponse(
135     const struct ChppAppHeader *requestHeader, size_t len) {
136   CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
137 
138   struct ChppAppHeader *result = chppMalloc(len);
139   if (result) {
140     *result = *requestHeader;
141     result->type = CHPP_MESSAGE_TYPE_SERVICE_RESPONSE;
142     result->error = CHPP_APP_ERROR_NONE;
143   }
144   return result;
145 }
146 
chppServiceTimestampRequest(struct ChppRequestResponseState * rRState,struct ChppAppHeader * requestHeader)147 void chppServiceTimestampRequest(struct ChppRequestResponseState *rRState,
148                                  struct ChppAppHeader *requestHeader) {
149   if (rRState->responseTimeNs == CHPP_TIME_NONE &&
150       rRState->requestTimeNs != CHPP_TIME_NONE) {
151     CHPP_LOGE("Duplicate request rx at t=%" PRIu64,
152               rRState->requestTimeNs / CHPP_NSEC_PER_MSEC);
153   }
154   rRState->requestTimeNs = chppGetCurrentTimeNs();
155   rRState->responseTimeNs = CHPP_TIME_NONE;
156   rRState->transaction = requestHeader->transaction;
157 }
158 
chppServiceTimestampResponse(struct ChppRequestResponseState * rRState)159 void chppServiceTimestampResponse(struct ChppRequestResponseState *rRState) {
160   uint64_t previousResponseTime = rRState->responseTimeNs;
161   rRState->responseTimeNs = chppGetCurrentTimeNs();
162 
163   if (rRState->requestTimeNs == CHPP_TIME_NONE) {
164     CHPP_LOGE("Tx response w/ no req t=%" PRIu64,
165               rRState->responseTimeNs / CHPP_NSEC_PER_MSEC);
166 
167   } else if (previousResponseTime != CHPP_TIME_NONE) {
168     CHPP_LOGW("Resend response t=%" PRIu64 " for request at t=%" PRIu64,
169               rRState->responseTimeNs / CHPP_NSEC_PER_MSEC,
170               rRState->responseTimeNs / CHPP_NSEC_PER_MSEC);
171 
172   } else {
173     CHPP_LOGD("Sending initial response at t=%" PRIu64
174               " for request at t=%" PRIu64 " (RTT=%" PRIu64 ")",
175               rRState->responseTimeNs / CHPP_NSEC_PER_MSEC,
176               rRState->responseTimeNs / CHPP_NSEC_PER_MSEC,
177               (rRState->responseTimeNs - rRState->requestTimeNs) /
178                   CHPP_NSEC_PER_MSEC);
179   }
180 }
181 
chppSendTimestampedResponseOrFail(struct ChppServiceState * serviceState,struct ChppRequestResponseState * rRState,void * buf,size_t len)182 bool chppSendTimestampedResponseOrFail(struct ChppServiceState *serviceState,
183                                        struct ChppRequestResponseState *rRState,
184                                        void *buf, size_t len) {
185   chppServiceTimestampResponse(rRState);
186   return chppEnqueueTxDatagramOrFail(serviceState->appContext->transportContext,
187                                      buf, len);
188 }
189