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/link.h"
18 
19 #include <inttypes.h>
20 #include <stddef.h>
21 #include <stdint.h>
22 #include <string.h>
23 
24 #include "chpp/log.h"
25 #include "chpp/macros.h"
26 #include "chpp/transport.h"
27 
28 // The set of signals to use for the linkSendThread.
29 #define SIGNAL_EXIT UINT32_C(1 << 0)
30 #define SIGNAL_DATA UINT32_C(1 << 1)
31 
32 /**
33  * This thread is used to "send" TX data to the remote endpoint. The remote
34  * endpoint is defined by the ChppTransportState pointer, so a loopback link
35  * with a single CHPP instance can be supported.
36  */
linkSendThread(void * arg)37 static void *linkSendThread(void *arg) {
38   struct ChppPlatformLinkParameters *params =
39       (struct ChppPlatformLinkParameters *)arg;
40   while (true) {
41     uint32_t signal = chppNotifierTimedWait(&params->notifier, CHPP_TIME_MAX);
42 
43     if (signal & SIGNAL_EXIT) {
44       break;
45     }
46     if (signal & SIGNAL_DATA) {
47       enum ChppLinkErrorCode error;
48 
49       chppMutexLock(&params->mutex);
50 
51       if (params->remoteTransportContext == NULL) {
52         CHPP_LOGW("remoteTransportContext is NULL");
53         error = CHPP_LINK_ERROR_NONE_SENT;
54 
55       } else if (!params->linkEstablished) {
56         CHPP_LOGE("No (fake) link");
57         error = CHPP_LINK_ERROR_NO_LINK;
58 
59       } else if (!chppRxDataCb(params->remoteTransportContext, params->buf,
60                                params->bufLen)) {
61         CHPP_LOGW("chppRxDataCb return state!=preamble (packet incomplete)");
62         error = CHPP_LINK_ERROR_NONE_SENT;
63 
64       } else {
65         error = CHPP_LINK_ERROR_NONE_SENT;
66       }
67 
68       params->bufLen = 0;
69       chppLinkSendDoneCb(params, error);
70 
71       chppMutexUnlock(&params->mutex);
72     }
73   }
74 
75   return NULL;
76 }
77 
chppPlatformLinkInit(struct ChppPlatformLinkParameters * params)78 void chppPlatformLinkInit(struct ChppPlatformLinkParameters *params) {
79   params->bufLen = 0;
80   chppMutexInit(&params->mutex);
81   chppNotifierInit(&params->notifier);
82   pthread_create(&params->linkSendThread, NULL /* attr */, linkSendThread,
83                  params);
84   if (params->linkThreadName != NULL) {
85     pthread_setname_np(params->linkSendThread, params->linkThreadName);
86   }
87 }
88 
chppPlatformLinkDeinit(struct ChppPlatformLinkParameters * params)89 void chppPlatformLinkDeinit(struct ChppPlatformLinkParameters *params) {
90   params->bufLen = 0;
91   chppNotifierSignal(&params->notifier, SIGNAL_EXIT);
92   pthread_join(params->linkSendThread, NULL /* retval */);
93   chppNotifierDeinit(&params->notifier);
94   chppMutexDeinit(&params->mutex);
95 }
96 
chppPlatformLinkSend(struct ChppPlatformLinkParameters * params,uint8_t * buf,size_t len)97 enum ChppLinkErrorCode chppPlatformLinkSend(
98     struct ChppPlatformLinkParameters *params, uint8_t *buf, size_t len) {
99   bool success = false;
100   chppMutexLock(&params->mutex);
101   if (params->bufLen != 0) {
102     CHPP_LOGE("Failed to send data - link layer busy");
103   } else {
104     success = true;
105     memcpy(params->buf, buf, len);
106     params->bufLen = len;
107   }
108   chppMutexUnlock(&params->mutex);
109 
110   if (success) {
111     chppNotifierSignal(&params->notifier, SIGNAL_DATA);
112   }
113 
114   return success ? CHPP_LINK_ERROR_NONE_QUEUED : CHPP_LINK_ERROR_BUSY;
115 }
116 
chppPlatformLinkDoWork(struct ChppPlatformLinkParameters * params,uint32_t signal)117 void chppPlatformLinkDoWork(struct ChppPlatformLinkParameters *params,
118                             uint32_t signal) {
119   UNUSED_VAR(params);
120   UNUSED_VAR(signal);
121 }
122 
chppPlatformLinkReset(struct ChppPlatformLinkParameters * params)123 void chppPlatformLinkReset(struct ChppPlatformLinkParameters *params) {
124   chppPlatformLinkDeinit(params);
125   chppPlatformLinkInit(params);
126 }
127