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 */ 37 static void *linkSendThread(void *arg) { 38 struct ChppPlatformLinkParameters *params = 39 (struct ChppPlatformLinkParameters *)arg; 40 while (true) { 41 uint32_t signal = chppNotifierTimedWait(¶ms->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(¶ms->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(¶ms->mutex); 72 } 73 } 74 75 return NULL; 76 } 77 78 void chppPlatformLinkInit(struct ChppPlatformLinkParameters *params) { 79 params->bufLen = 0; 80 chppMutexInit(¶ms->mutex); 81 chppNotifierInit(¶ms->notifier); 82 pthread_create(¶ms->linkSendThread, NULL /* attr */, linkSendThread, 83 params); 84 if (params->linkThreadName != NULL) { 85 pthread_setname_np(params->linkSendThread, params->linkThreadName); 86 } 87 } 88 89 void chppPlatformLinkDeinit(struct ChppPlatformLinkParameters *params) { 90 params->bufLen = 0; 91 chppNotifierSignal(¶ms->notifier, SIGNAL_EXIT); 92 pthread_join(params->linkSendThread, NULL /* retval */); 93 chppNotifierDeinit(¶ms->notifier); 94 chppMutexDeinit(¶ms->mutex); 95 } 96 97 enum ChppLinkErrorCode chppPlatformLinkSend( 98 struct ChppPlatformLinkParameters *params, uint8_t *buf, size_t len) { 99 bool success = false; 100 chppMutexLock(¶ms->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(¶ms->mutex); 109 110 if (success) { 111 chppNotifierSignal(¶ms->notifier, SIGNAL_DATA); 112 } 113 114 return success ? CHPP_LINK_ERROR_NONE_QUEUED : CHPP_LINK_ERROR_BUSY; 115 } 116 117 void chppPlatformLinkDoWork(struct ChppPlatformLinkParameters *params, 118 uint32_t signal) { 119 UNUSED_VAR(params); 120 UNUSED_VAR(signal); 121 } 122 123 void chppPlatformLinkReset(struct ChppPlatformLinkParameters *params) { 124 chppPlatformLinkDeinit(params); 125 chppPlatformLinkInit(params); 126 } 127