1*84e33947SAndroid Build Coastguard Worker /*
2*84e33947SAndroid Build Coastguard Worker * Copyright (C) 2020 The Android Open Source Project
3*84e33947SAndroid Build Coastguard Worker *
4*84e33947SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*84e33947SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*84e33947SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*84e33947SAndroid Build Coastguard Worker *
8*84e33947SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*84e33947SAndroid Build Coastguard Worker *
10*84e33947SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*84e33947SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*84e33947SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*84e33947SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*84e33947SAndroid Build Coastguard Worker * limitations under the License.
15*84e33947SAndroid Build Coastguard Worker */
16*84e33947SAndroid Build Coastguard Worker
17*84e33947SAndroid Build Coastguard Worker #include "chpp/link.h"
18*84e33947SAndroid Build Coastguard Worker
19*84e33947SAndroid Build Coastguard Worker #include <inttypes.h>
20*84e33947SAndroid Build Coastguard Worker #include <stddef.h>
21*84e33947SAndroid Build Coastguard Worker #include <stdint.h>
22*84e33947SAndroid Build Coastguard Worker #include <string.h>
23*84e33947SAndroid Build Coastguard Worker
24*84e33947SAndroid Build Coastguard Worker #include "chpp/log.h"
25*84e33947SAndroid Build Coastguard Worker #include "chpp/macros.h"
26*84e33947SAndroid Build Coastguard Worker #include "chpp/notifier.h"
27*84e33947SAndroid Build Coastguard Worker #include "chpp/platform/platform_link.h"
28*84e33947SAndroid Build Coastguard Worker #include "chpp/transport.h"
29*84e33947SAndroid Build Coastguard Worker
30*84e33947SAndroid Build Coastguard Worker // The set of signals to use for the linkSendThread.
31*84e33947SAndroid Build Coastguard Worker #define SIGNAL_EXIT UINT32_C(1 << 0)
32*84e33947SAndroid Build Coastguard Worker #define SIGNAL_DATA UINT32_C(1 << 1)
33*84e33947SAndroid Build Coastguard Worker #define SIGNAL_DATA_RX UINT32_C(1 << 2)
34*84e33947SAndroid Build Coastguard Worker
35*84e33947SAndroid Build Coastguard Worker struct ChppNotifier gCycleSendThreadNotifier;
36*84e33947SAndroid Build Coastguard Worker
cycleSendThread(void)37*84e33947SAndroid Build Coastguard Worker void cycleSendThread(void) {
38*84e33947SAndroid Build Coastguard Worker chppNotifierSignal(&gCycleSendThreadNotifier, 1);
39*84e33947SAndroid Build Coastguard Worker }
40*84e33947SAndroid Build Coastguard Worker
41*84e33947SAndroid Build Coastguard Worker /**
42*84e33947SAndroid Build Coastguard Worker * This thread is used to "send" TX data to the remote endpoint. The remote
43*84e33947SAndroid Build Coastguard Worker * endpoint is defined by the ChppTransportState pointer, so a loopback link
44*84e33947SAndroid Build Coastguard Worker * with a single CHPP instance can be supported.
45*84e33947SAndroid Build Coastguard Worker */
linkSendThread(void * linkContext)46*84e33947SAndroid Build Coastguard Worker static void *linkSendThread(void *linkContext) {
47*84e33947SAndroid Build Coastguard Worker struct ChppLinuxLinkState *context =
48*84e33947SAndroid Build Coastguard Worker (struct ChppLinuxLinkState *)(linkContext);
49*84e33947SAndroid Build Coastguard Worker while (true) {
50*84e33947SAndroid Build Coastguard Worker if (context->manualSendCycle) {
51*84e33947SAndroid Build Coastguard Worker chppNotifierWait(&gCycleSendThreadNotifier);
52*84e33947SAndroid Build Coastguard Worker }
53*84e33947SAndroid Build Coastguard Worker uint32_t signal = chppNotifierTimedWait(&context->notifier, CHPP_TIME_MAX);
54*84e33947SAndroid Build Coastguard Worker
55*84e33947SAndroid Build Coastguard Worker if (signal & SIGNAL_EXIT) {
56*84e33947SAndroid Build Coastguard Worker break;
57*84e33947SAndroid Build Coastguard Worker }
58*84e33947SAndroid Build Coastguard Worker
59*84e33947SAndroid Build Coastguard Worker if (signal & SIGNAL_DATA) {
60*84e33947SAndroid Build Coastguard Worker enum ChppLinkErrorCode error;
61*84e33947SAndroid Build Coastguard Worker
62*84e33947SAndroid Build Coastguard Worker chppMutexLock(&context->mutex);
63*84e33947SAndroid Build Coastguard Worker
64*84e33947SAndroid Build Coastguard Worker if (context->remoteLinkState == NULL) {
65*84e33947SAndroid Build Coastguard Worker CHPP_LOGW("remoteLinkState is NULL");
66*84e33947SAndroid Build Coastguard Worker error = CHPP_LINK_ERROR_NONE_SENT;
67*84e33947SAndroid Build Coastguard Worker
68*84e33947SAndroid Build Coastguard Worker } else if (!context->linkEstablished) {
69*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("No (fake) link");
70*84e33947SAndroid Build Coastguard Worker error = CHPP_LINK_ERROR_NO_LINK;
71*84e33947SAndroid Build Coastguard Worker
72*84e33947SAndroid Build Coastguard Worker } else {
73*84e33947SAndroid Build Coastguard Worker // Use notifiers only when there are 2 different link layers (i.e. no
74*84e33947SAndroid Build Coastguard Worker // loopback). Otherwise call chppRxDataCb directly.
75*84e33947SAndroid Build Coastguard Worker if (context->rxInRemoteEndpointWorker &&
76*84e33947SAndroid Build Coastguard Worker context->remoteLinkState != context) {
77*84e33947SAndroid Build Coastguard Worker chppNotifierSignal(&context->remoteLinkState->notifier,
78*84e33947SAndroid Build Coastguard Worker SIGNAL_DATA_RX);
79*84e33947SAndroid Build Coastguard Worker
80*84e33947SAndroid Build Coastguard Worker // Wait for the RX thread to consume the buffer before we can modify
81*84e33947SAndroid Build Coastguard Worker // it.
82*84e33947SAndroid Build Coastguard Worker chppNotifierTimedWait(&context->rxNotifier, CHPP_TIME_MAX);
83*84e33947SAndroid Build Coastguard Worker } else if (!chppRxDataCb(context->remoteLinkState->transportContext,
84*84e33947SAndroid Build Coastguard Worker context->buf, context->bufLen)) {
85*84e33947SAndroid Build Coastguard Worker CHPP_LOGW("chppRxDataCb return state!=preamble (packet incomplete)");
86*84e33947SAndroid Build Coastguard Worker }
87*84e33947SAndroid Build Coastguard Worker error = CHPP_LINK_ERROR_NONE_SENT;
88*84e33947SAndroid Build Coastguard Worker }
89*84e33947SAndroid Build Coastguard Worker
90*84e33947SAndroid Build Coastguard Worker context->bufLen = 0;
91*84e33947SAndroid Build Coastguard Worker chppLinkSendDoneCb(context->transportContext, error);
92*84e33947SAndroid Build Coastguard Worker
93*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&context->mutex);
94*84e33947SAndroid Build Coastguard Worker }
95*84e33947SAndroid Build Coastguard Worker
96*84e33947SAndroid Build Coastguard Worker if (signal & SIGNAL_DATA_RX) {
97*84e33947SAndroid Build Coastguard Worker CHPP_NOT_NULL(context->transportContext);
98*84e33947SAndroid Build Coastguard Worker CHPP_NOT_NULL(context->remoteLinkState);
99*84e33947SAndroid Build Coastguard Worker // Process RX data which are the TX data from the remote link.
100*84e33947SAndroid Build Coastguard Worker chppRxDataCb(context->transportContext, context->remoteLinkState->buf,
101*84e33947SAndroid Build Coastguard Worker context->remoteLinkState->bufLen);
102*84e33947SAndroid Build Coastguard Worker // Unblock the TX thread when the buffer has been consumed.
103*84e33947SAndroid Build Coastguard Worker chppNotifierSignal(&context->remoteLinkState->rxNotifier, 0x01);
104*84e33947SAndroid Build Coastguard Worker }
105*84e33947SAndroid Build Coastguard Worker }
106*84e33947SAndroid Build Coastguard Worker
107*84e33947SAndroid Build Coastguard Worker return NULL;
108*84e33947SAndroid Build Coastguard Worker }
109*84e33947SAndroid Build Coastguard Worker
init(void * linkContext,struct ChppTransportState * transportContext)110*84e33947SAndroid Build Coastguard Worker static void init(void *linkContext,
111*84e33947SAndroid Build Coastguard Worker struct ChppTransportState *transportContext) {
112*84e33947SAndroid Build Coastguard Worker struct ChppLinuxLinkState *context =
113*84e33947SAndroid Build Coastguard Worker (struct ChppLinuxLinkState *)(linkContext);
114*84e33947SAndroid Build Coastguard Worker context->bufLen = 0;
115*84e33947SAndroid Build Coastguard Worker context->transportContext = transportContext;
116*84e33947SAndroid Build Coastguard Worker chppMutexInit(&context->mutex);
117*84e33947SAndroid Build Coastguard Worker chppNotifierInit(&context->notifier);
118*84e33947SAndroid Build Coastguard Worker chppNotifierInit(&context->rxNotifier);
119*84e33947SAndroid Build Coastguard Worker chppNotifierInit(&gCycleSendThreadNotifier);
120*84e33947SAndroid Build Coastguard Worker pthread_create(&context->linkSendThread, NULL /* attr */, linkSendThread,
121*84e33947SAndroid Build Coastguard Worker context);
122*84e33947SAndroid Build Coastguard Worker if (context->linkThreadName != NULL) {
123*84e33947SAndroid Build Coastguard Worker pthread_setname_np(context->linkSendThread, context->linkThreadName);
124*84e33947SAndroid Build Coastguard Worker }
125*84e33947SAndroid Build Coastguard Worker }
126*84e33947SAndroid Build Coastguard Worker
deinit(void * linkContext)127*84e33947SAndroid Build Coastguard Worker static void deinit(void *linkContext) {
128*84e33947SAndroid Build Coastguard Worker struct ChppLinuxLinkState *context =
129*84e33947SAndroid Build Coastguard Worker (struct ChppLinuxLinkState *)(linkContext);
130*84e33947SAndroid Build Coastguard Worker context->bufLen = 0;
131*84e33947SAndroid Build Coastguard Worker chppNotifierSignal(&context->notifier, SIGNAL_EXIT);
132*84e33947SAndroid Build Coastguard Worker if (context->manualSendCycle) {
133*84e33947SAndroid Build Coastguard Worker // Unblock the send thread so it exits.
134*84e33947SAndroid Build Coastguard Worker cycleSendThread();
135*84e33947SAndroid Build Coastguard Worker }
136*84e33947SAndroid Build Coastguard Worker pthread_join(context->linkSendThread, NULL /* retval */);
137*84e33947SAndroid Build Coastguard Worker chppNotifierDeinit(&context->notifier);
138*84e33947SAndroid Build Coastguard Worker chppNotifierDeinit(&context->rxNotifier);
139*84e33947SAndroid Build Coastguard Worker chppNotifierDeinit(&gCycleSendThreadNotifier);
140*84e33947SAndroid Build Coastguard Worker chppMutexDeinit(&context->mutex);
141*84e33947SAndroid Build Coastguard Worker }
142*84e33947SAndroid Build Coastguard Worker
send(void * linkContext,size_t len)143*84e33947SAndroid Build Coastguard Worker static enum ChppLinkErrorCode send(void *linkContext, size_t len) {
144*84e33947SAndroid Build Coastguard Worker struct ChppLinuxLinkState *context =
145*84e33947SAndroid Build Coastguard Worker (struct ChppLinuxLinkState *)(linkContext);
146*84e33947SAndroid Build Coastguard Worker bool success = false;
147*84e33947SAndroid Build Coastguard Worker chppMutexLock(&context->mutex);
148*84e33947SAndroid Build Coastguard Worker if (context->bufLen != 0) {
149*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Failed to send data - link layer busy");
150*84e33947SAndroid Build Coastguard Worker } else if (!context->isLinkActive) {
151*84e33947SAndroid Build Coastguard Worker success = false;
152*84e33947SAndroid Build Coastguard Worker } else {
153*84e33947SAndroid Build Coastguard Worker success = true;
154*84e33947SAndroid Build Coastguard Worker context->bufLen = len;
155*84e33947SAndroid Build Coastguard Worker }
156*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&context->mutex);
157*84e33947SAndroid Build Coastguard Worker
158*84e33947SAndroid Build Coastguard Worker if (success) {
159*84e33947SAndroid Build Coastguard Worker chppNotifierSignal(&context->notifier, SIGNAL_DATA);
160*84e33947SAndroid Build Coastguard Worker }
161*84e33947SAndroid Build Coastguard Worker
162*84e33947SAndroid Build Coastguard Worker return success ? CHPP_LINK_ERROR_NONE_QUEUED : CHPP_LINK_ERROR_BUSY;
163*84e33947SAndroid Build Coastguard Worker }
164*84e33947SAndroid Build Coastguard Worker
doWork(void * linkContext,uint32_t signal)165*84e33947SAndroid Build Coastguard Worker static void doWork(void *linkContext, uint32_t signal) {
166*84e33947SAndroid Build Coastguard Worker UNUSED_VAR(linkContext);
167*84e33947SAndroid Build Coastguard Worker UNUSED_VAR(signal);
168*84e33947SAndroid Build Coastguard Worker }
169*84e33947SAndroid Build Coastguard Worker
reset(void * linkContext)170*84e33947SAndroid Build Coastguard Worker static void reset(void *linkContext) {
171*84e33947SAndroid Build Coastguard Worker struct ChppLinuxLinkState *context =
172*84e33947SAndroid Build Coastguard Worker (struct ChppLinuxLinkState *)(linkContext);
173*84e33947SAndroid Build Coastguard Worker deinit(context);
174*84e33947SAndroid Build Coastguard Worker init(context, context->transportContext);
175*84e33947SAndroid Build Coastguard Worker }
176*84e33947SAndroid Build Coastguard Worker
getConfig(void * linkContext)177*84e33947SAndroid Build Coastguard Worker static struct ChppLinkConfiguration getConfig(void *linkContext) {
178*84e33947SAndroid Build Coastguard Worker UNUSED_VAR(linkContext);
179*84e33947SAndroid Build Coastguard Worker const struct ChppLinkConfiguration config = {
180*84e33947SAndroid Build Coastguard Worker .txBufferLen = CHPP_LINUX_LINK_TX_MTU_BYTES,
181*84e33947SAndroid Build Coastguard Worker .rxBufferLen = CHPP_LINUX_LINK_RX_MTU_BYTES,
182*84e33947SAndroid Build Coastguard Worker };
183*84e33947SAndroid Build Coastguard Worker return config;
184*84e33947SAndroid Build Coastguard Worker }
185*84e33947SAndroid Build Coastguard Worker
getTxBuffer(void * linkContext)186*84e33947SAndroid Build Coastguard Worker static uint8_t *getTxBuffer(void *linkContext) {
187*84e33947SAndroid Build Coastguard Worker struct ChppLinuxLinkState *context =
188*84e33947SAndroid Build Coastguard Worker (struct ChppLinuxLinkState *)(linkContext);
189*84e33947SAndroid Build Coastguard Worker return &context->buf[0];
190*84e33947SAndroid Build Coastguard Worker }
191*84e33947SAndroid Build Coastguard Worker
192*84e33947SAndroid Build Coastguard Worker const struct ChppLinkApi gLinuxLinkApi = {
193*84e33947SAndroid Build Coastguard Worker .init = &init,
194*84e33947SAndroid Build Coastguard Worker .deinit = &deinit,
195*84e33947SAndroid Build Coastguard Worker .send = &send,
196*84e33947SAndroid Build Coastguard Worker .doWork = &doWork,
197*84e33947SAndroid Build Coastguard Worker .reset = &reset,
198*84e33947SAndroid Build Coastguard Worker .getConfig = &getConfig,
199*84e33947SAndroid Build Coastguard Worker .getTxBuffer = &getTxBuffer,
200*84e33947SAndroid Build Coastguard Worker };
201*84e33947SAndroid Build Coastguard Worker
getLinuxLinkApi(void)202*84e33947SAndroid Build Coastguard Worker const struct ChppLinkApi *getLinuxLinkApi(void) {
203*84e33947SAndroid Build Coastguard Worker return &gLinuxLinkApi;
204*84e33947SAndroid Build Coastguard Worker }
205