Files
rpc/MicroLMS/heci/LMEConnection.c
2020-09-08 13:40:45 -07:00

554 lines
18 KiB
C

/*********************************************************************
* Copyright (c) Intel Corporation 2011 - 2020
* SPDX-License-Identifier: Apache-2.0
**********************************************************************/
#ifndef _MINCORE
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "LMEConnection.h"
#include "LMS_if.h"
#include "../microstack/ILibParsers.h"
#ifdef _POSIX
#define UNREFERENCED_PARAMETER(P) (P)
#endif
#define MEI_IO_TIMEOUT 1000
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
const unsigned int LME_RX_WINDOW_SIZE = 4096;
int LME_sendMessage(struct LMEConnection* module, unsigned char *buffer, int len);
void LME_doRX(struct LMEConnection* module, unsigned char *rxBuffer, unsigned int bytesRead);
void LME_apfGlobalRequest(struct LMEConnection* module, unsigned char *rxBuffer, unsigned int bytesRead, int *status);
void LME_Deinit(struct LMEConnection* module);
bool LME_IsInitialized(struct LMEConnection* module)
{
// Lock il(_initLock);
bool ret = (bool)(module->initState == INIT_STATE_CONNECTED);
return ret;
}
#ifdef WIN32
DWORD WINAPI LME_Thread(void* obj)
#else
void LME_Thread(void* obj)
#endif
{
#ifdef WIN32
HECI_VERSION version;
#endif
int len = 0;
int bufsize = 0;
unsigned char* data = NULL;
struct LMEConnection* module = (struct LMEConnection*)obj;
//printf("LMS THREAD START\r\n");
do {
bufsize = heci_GetBufferSize(&(module->mei));
if ((data = (unsigned char*)malloc(bufsize)) == NULL) ILIBCRITICALEXIT(254);
do {
len = heci_ReceiveMessage(&(module->mei), data, bufsize, 0xFFFFFFFF);
//printf("LMS THREAD READ LEN=%d\r\n", len);
if (len > 0 && data != NULL) LME_doRX(module, data, len);
} while (len >= 0);
module->cb(module, module->cbParam, NULL, 0);
module->initState = INIT_STATE_DISCONNECTED;
free(data);
// printf("LMS TRYING RECONNECT\r\n");
while (module->exit == 0 && module->initState == INIT_STATE_DISCONNECTED)
{
// Setup the MEI interface with the LME GUID
#ifdef WIN32
if (heci_Init(&(module->mei), LMS_CLIENT) == TRUE && heci_GetHeciVersion(&(module->mei), &version) == TRUE && version.major >= LMS_PROTOCOL_VERSION) { module->initState = INIT_STATE_CONNECTED; }
#else
if (heci_Init(&(module->mei), 1) == TRUE && heci_GetProtocolVersion(&(module->mei)) >= LMS_PROTOCOL_VERSION) { module->initState = INIT_STATE_CONNECTED; }
#endif
if (module->exit == 0 && module->initState == INIT_STATE_DISCONNECTED)
{
// printf("LMS THREAD SLEEP\r\n");
#ifdef WIN32
Sleep(2000);
#else
sleep(2);
#endif
}
//if (module->initState == INIT_STATE_CONNECTED) printf("LMS THREAD RECONNECT\r\n");
}
}
while (module->exit == 0);
// printf("LMS THREAD QUIT\r\n");
module->exit = 2;
#ifdef WIN32
return 0;
#endif
}
// Setup the LME connection
bool LME_Init(struct LMEConnection* module, MEICallback cb, void *param)
{
#ifdef WIN32
HECI_VERSION version;
#endif
// Setup the state object
memset(module, 0, sizeof(struct LMEConnection));
module->initState = INIT_STATE_DISCONNECTED;
module->cb = cb;
module->cbParam = param;
// Setup the MEI interface with the LME GUID
#ifdef WIN32
if (heci_Init(&(module->mei), LMS_CLIENT) == FALSE || heci_GetHeciVersion(&(module->mei), &version) == FALSE || version.major < LMS_PROTOCOL_VERSION) { module->initState = INIT_STATE_DISCONNECTED; return FALSE; }
#else
if (heci_Init(&(module->mei), 1) == FALSE || heci_GetProtocolVersion(&(module->mei)) < LMS_PROTOCOL_VERSION) { module->initState = INIT_STATE_DISCONNECTED; return FALSE; }
#endif
module->initState = INIT_STATE_CONNECTED;
if ((module->txBuffer = (unsigned char*)malloc(LME_GetMeiBufferSize(module))) == NULL) ILIBCRITICALEXIT(254);
// Create the thread that will read the MEI/LME stream
ILibSpawnNormalThread((voidfp)(&LME_Thread), module);
return TRUE;
}
// Disconnect the LME connection
void LME_Deinit(struct LMEConnection* module)
{
//printf("LME_Deinit()\r\n");
if (module == NULL) return;
if (module->initState == INIT_STATE_CONNECTED) { heci_Deinit(&(module->mei)); }
module->initState = INIT_STATE_DISCONNECTED;
}
// Exit LME
void LME_Exit(struct LMEConnection* module)
{
int l = 0;
//printf("LME_Exit()\r\n");
if (module == NULL) return;
if (module->exit == 0) module->exit = 1;
LME_Deinit(module);
#ifdef WIN32
while (module->exit != 2 && l < 40) { Sleep(100); l++; }
#else
/*
while (module->exit != 2 && l < 4)
{
printf("LME_Holding %d\r\n", l);
Sleep(1);
l++;
}
*/
#endif
if (module->txBuffer != NULL && l < 40) { free(module->txBuffer); module->txBuffer = NULL; }
}
// Send the APF disconnect message to the MEI
bool LME_Disconnect(struct LMEConnection* module, APF_DISCONNECT_REASON_CODE reasonCode)
{
unsigned char buf[sizeof(APF_DISCONNECT_MESSAGE)];
APF_DISCONNECT_MESSAGE *disconnectMessage = (APF_DISCONNECT_MESSAGE *)buf;
memset(disconnectMessage, 0, sizeof(buf));
disconnectMessage->MessageType = APF_DISCONNECT;
disconnectMessage->ReasonCode = htonl(reasonCode);
return (LME_sendMessage(module, buf, sizeof(buf)) == sizeof(buf));
}
// Send the AFP service accept message to the MEI
bool LME_ServiceAccept(struct LMEConnection* module, char* serviceName)
{
int len;
int res;
int servicenamelen = (int)strnlen_s(serviceName, _MAX_PATH);
unsigned char *buf;
unsigned char *pCurrent;
if (!LME_IsInitialized(module)) return FALSE;
if ((buf = (unsigned char*)malloc(sizeof(APF_SERVICE_ACCEPT_MESSAGE) + servicenamelen)) == NULL) ILIBCRITICALEXIT(254);
pCurrent = buf;
*pCurrent = APF_SERVICE_ACCEPT;
++pCurrent;
*((unsigned int *)pCurrent) = htonl(servicenamelen);
pCurrent += 4;
memcpy_s(pCurrent, sizeof(APF_SERVICE_ACCEPT_MESSAGE) + servicenamelen, serviceName, servicenamelen);
pCurrent += servicenamelen;
len = (int)(pCurrent - buf);
res = LME_sendMessage(module, buf, len);
free(buf);
return (res == len);
}
bool LME_ProtocolVersion(struct LMEConnection* module, unsigned int majorversion, unsigned int minorversion, unsigned int triggerreason)
{
APF_PROTOCOL_VERSION_MESSAGE protVersion;
memset(&protVersion, 0, sizeof(protVersion));
protVersion.MessageType = APF_PROTOCOLVERSION;
protVersion.MajorVersion = htonl(majorversion);
protVersion.MinorVersion = htonl(minorversion);
protVersion.TriggerReason = htonl(triggerreason);
return (LME_sendMessage(module, (unsigned char *)&protVersion, sizeof(protVersion)) == sizeof(protVersion));
}
bool LME_TcpForwardReplySuccess(struct LMEConnection* module, unsigned int port)
{
APF_TCP_FORWARD_REPLY_MESSAGE message;
memset(&message, 0, sizeof(message));
message.MessageType = APF_REQUEST_SUCCESS;
message.PortBound = htonl(port);
return (LME_sendMessage(module, (unsigned char *)&message, sizeof(message)) == sizeof(message));
}
bool LME_SendShortMessage(struct LMEConnection* module, unsigned char buf)
{
return (LME_sendMessage(module, &buf, sizeof(buf)) == sizeof(buf));
}
#define pCurrentOffset ((int)(pCurrent - buf))
bool LME_ChannelOpenForwardedRequest(struct LMEConnection* module, unsigned int senderChannel, char* connectedIP, unsigned int connectedPort, char* originatorIP, unsigned int originatorPort)
{
int res;
int connectedIPlen = (int)strnlen_s(connectedIP, _MAX_PATH);
int originatorIPlen = (int)strnlen_s(originatorIP, _MAX_PATH);
unsigned char *buf;
unsigned char *pCurrent;
int mallocSize = 5 + APF_STR_SIZE_OF(APF_OPEN_CHANNEL_REQUEST_FORWARDED) + 16 + connectedIPlen + 8 + originatorIPlen + 4;
if (!LME_IsInitialized(module)) return FALSE;
if ((buf = (unsigned char*)malloc(mallocSize)) == NULL) ILIBCRITICALEXIT(254);
pCurrent = buf;
if (strnlen_s(originatorIP, _MAX_PATH) > 63) { free(buf); return FALSE; }
*pCurrent = APF_CHANNEL_OPEN;
++pCurrent;
*((unsigned int *)pCurrent) = htonl(APF_STR_SIZE_OF(APF_OPEN_CHANNEL_REQUEST_FORWARDED));
pCurrent += sizeof(unsigned int);
memcpy_s(pCurrent, mallocSize - pCurrentOffset, APF_OPEN_CHANNEL_REQUEST_FORWARDED, APF_STR_SIZE_OF(APF_OPEN_CHANNEL_REQUEST_FORWARDED));
pCurrent += APF_STR_SIZE_OF(APF_OPEN_CHANNEL_REQUEST_FORWARDED);
*((unsigned int *)pCurrent) = htonl(senderChannel);
pCurrent += sizeof(unsigned int);
*((unsigned int *)pCurrent) = htonl(LME_RX_WINDOW_SIZE);
pCurrent += sizeof(unsigned int);
*((unsigned int *)pCurrent) = 0xFFFFFFFF;
pCurrent += sizeof(unsigned int);
*((unsigned int *)pCurrent) = htonl(connectedIPlen);
pCurrent += sizeof(unsigned int);
memcpy_s(pCurrent, mallocSize - pCurrentOffset, connectedIP, connectedIPlen);
pCurrent += connectedIPlen;
*((unsigned int *)pCurrent) = htonl(connectedPort);
pCurrent += sizeof(unsigned int);
*((unsigned int *)pCurrent) = htonl((unsigned int)originatorIPlen);
pCurrent += sizeof(unsigned int);
memcpy_s(pCurrent, mallocSize - pCurrentOffset, originatorIP, originatorIPlen);
pCurrent += originatorIPlen;
*((unsigned int *)pCurrent) = htonl(originatorPort);
pCurrent += sizeof(unsigned int);
res = LME_sendMessage(module, buf, (int)(pCurrent - buf));
free(buf);
return (res == pCurrent - buf);
}
bool LME_ChannelOpenReplySuccess(struct LMEConnection* module, unsigned int recipientChannel, unsigned int senderChannel)
{
APF_CHANNEL_OPEN_CONFIRMATION_MESSAGE message;
message.MessageType = APF_CHANNEL_OPEN_CONFIRMATION;
message.RecipientChannel = htonl(recipientChannel);
message.SenderChannel = htonl(senderChannel);
message.InitialWindowSize = htonl(LME_RX_WINDOW_SIZE);
message.Reserved = 0xFFFFFFFF;
return (LME_sendMessage(module, (unsigned char*)&message, sizeof(message)) == sizeof(message));
}
bool LME_ChannelOpenReplyFailure(struct LMEConnection* module, unsigned int recipientChannel, unsigned int reason)
{
APF_CHANNEL_OPEN_FAILURE_MESSAGE message;
message.MessageType = APF_CHANNEL_OPEN_FAILURE;
message.RecipientChannel = htonl(recipientChannel);
message.ReasonCode = htonl(reason);
message.Reserved = 0x00000000;
message.Reserved2 = 0x00000000;
return (LME_sendMessage(module, (unsigned char*)&message, sizeof(message)) == sizeof(message));
}
bool LME_ChannelClose(struct LMEConnection* module, unsigned int recipientChannel, unsigned int senderChannel )
{
APF_CHANNEL_CLOSE_MESSAGE message;
UNREFERENCED_PARAMETER( senderChannel );
message.MessageType = APF_CHANNEL_CLOSE;
message.RecipientChannel = htonl(recipientChannel);
return (LME_sendMessage(module, (unsigned char*)&message, sizeof(message)) == sizeof(message));
}
int LME_ChannelData(struct LMEConnection* module, unsigned int recipientChannel, unsigned int len, unsigned char *buffer)
{
APF_CHANNEL_DATA_MESSAGE *message;
if (len > (LME_GetMeiBufferSize(module) - sizeof(APF_CHANNEL_DATA_MESSAGE)) || module->txBuffer == NULL) return -1;
message = (APF_CHANNEL_DATA_MESSAGE*)module->txBuffer;
message->MessageType = APF_CHANNEL_DATA;
message->RecipientChannel = htonl(recipientChannel);
message->DataLength = htonl(len);
memcpy_s(module->txBuffer + sizeof(APF_CHANNEL_DATA_MESSAGE), LME_GetMeiBufferSize(module) - sizeof(APF_CHANNEL_DATA_MESSAGE), buffer, len);
return LME_sendMessage(module, (unsigned char *)message, sizeof(APF_CHANNEL_DATA_MESSAGE) + len) - sizeof(APF_CHANNEL_DATA_MESSAGE);
}
bool LME_ChannelWindowAdjust(struct LMEConnection* module, unsigned int recipientChannel, unsigned int len)
{
APF_WINDOW_ADJUST_MESSAGE message;
message.MessageType = APF_CHANNEL_WINDOW_ADJUST;
message.RecipientChannel = htonl(recipientChannel);
message.BytesToAdd = htonl(len);
return (LME_sendMessage(module, (unsigned char *)&message, sizeof(message)) == sizeof(message));
}
int LME_sendMessage(struct LMEConnection* module, unsigned char *buffer, int len)
{
int result;
if (!LME_IsInitialized(module)) { return -1; }
result = heci_SendMessage(&(module->mei), buffer, len, MEI_IO_TIMEOUT);
if (result < 0) LME_Deinit(module);
return result;
}
bool LME_checkMinMsgSize(unsigned char *buf, unsigned int bytesRead)
{
switch (buf[0]) {
case APF_DISCONNECT:
if (bytesRead < sizeof(APF_DISCONNECT_MESSAGE)) { return FALSE; }
break;
case APF_SERVICE_REQUEST:
if (bytesRead < sizeof(APF_SERVICE_REQUEST_MESSAGE)) { return FALSE; }
if (bytesRead < (sizeof(APF_SERVICE_REQUEST_MESSAGE) + ntohl(((APF_SERVICE_REQUEST_MESSAGE *)buf)->ServiceNameLength))) { return FALSE; }
break;
case APF_USERAUTH_REQUEST:
if (bytesRead < (3 * sizeof(unsigned int))) { return FALSE; }
break;
case APF_GLOBAL_REQUEST:
if (bytesRead < (sizeof(APF_GENERIC_HEADER) + sizeof(UINT8))) { return FALSE; }
if (bytesRead < (sizeof(APF_GENERIC_HEADER) + sizeof(UINT8) + ntohl(((APF_GENERIC_HEADER *)buf)->StringLength))) { return FALSE; }
break;
case APF_CHANNEL_OPEN:
if (bytesRead < sizeof(APF_GENERIC_HEADER)) { return FALSE; }
if (bytesRead < (sizeof(APF_GENERIC_HEADER) + ntohl(((APF_GENERIC_HEADER *)buf)->StringLength))) { return FALSE; }
break;
case APF_CHANNEL_OPEN_CONFIRMATION:
if (bytesRead < sizeof(APF_CHANNEL_OPEN_CONFIRMATION_MESSAGE)) { return FALSE; }
break;
case APF_CHANNEL_OPEN_FAILURE:
if (bytesRead < sizeof(APF_CHANNEL_OPEN_FAILURE_MESSAGE)) { return FALSE; }
break;
case APF_CHANNEL_CLOSE:
if (bytesRead < sizeof(APF_CHANNEL_CLOSE_MESSAGE)) { return FALSE; }
break;
case APF_CHANNEL_DATA:
if (bytesRead < sizeof(APF_CHANNEL_DATA_MESSAGE)) { return FALSE; }
if (bytesRead < (sizeof(APF_CHANNEL_DATA_MESSAGE) + ntohl(((APF_CHANNEL_DATA_MESSAGE *)buf)->DataLength))) { return FALSE; }
break;
case APF_CHANNEL_WINDOW_ADJUST:
if (bytesRead < sizeof(APF_WINDOW_ADJUST_MESSAGE)) { return FALSE; }
break;
case APF_PROTOCOLVERSION:
if (bytesRead < sizeof(APF_PROTOCOL_VERSION_MESSAGE)) { return FALSE; }
break;
default:
return FALSE;
}
return TRUE;
}
void LME_doRX(struct LMEConnection* module, unsigned char *rxBuffer, unsigned int bytesRead)
{
if (bytesRead == 0) return;
if (!LME_checkMinMsgSize(rxBuffer, bytesRead)) { LME_Deinit(module); return; }
module->cb(module, module->cbParam, rxBuffer, bytesRead);
}
/*
void LME_apfChannelOpen(struct LMEConnection* module, unsigned char *rxBuffer, unsigned int bytesRead, int *status)
{
APF_GENERIC_HEADER *pHeader = (APF_GENERIC_HEADER *)rxBuffer;
if (_strnicmp((char *)pHeader->String, APF_OPEN_CHANNEL_REQUEST_DIRECT, APF_STR_SIZE_OF(APF_OPEN_CHANNEL_REQUEST_DIRECT)) == 0)
{
unsigned int senderChannel = 0;
LME_apfChannelOpenDirect(module, rxBuffer, bytesRead, &senderChannel, status);
if (LME_IsInitialized(module) && (*status == 1)) {
if (plugin.retry(rxBuffer, bytesRead) != LMS_DROPPED) { LME_apfChannelOpenDirect(module, rxBuffer, bytesRead, NULL, status); }
}
if (LME_IsInitialized(module) && (*status == 1)) {
LME_ChannelOpenReplyFailure(module, senderChannel, OPEN_FAILURE_REASON_CONNECT_FAILED);
}
}
}
void LME_apfChannelOpenDirect(struct LMEConnection* module, unsigned char *rxBuffer, unsigned int bytesRead, unsigned int *senderChannel, int *status)
{
unsigned char *pCurrent;
APF_GENERIC_HEADER *pHeader = (APF_GENERIC_HEADER *)rxBuffer;
if (bytesRead < sizeof(APF_GENERIC_HEADER) +
ntohl(pHeader->StringLength) +
7 + (5 * sizeof(unsigned int))) {
ILIBMESSAGE("apfChannelOpenDirect: Error receiving data from MEI\n");
LME_Deinit(module);
return;
}
pCurrent = rxBuffer + sizeof(APF_GENERIC_HEADER) +
APF_STR_SIZE_OF(APF_OPEN_CHANNEL_REQUEST_DIRECT);
LMEChannelOpenRequestMessage channelOpenRequest;
channelOpenRequest.ChannelType = APF_CHANNEL_DIRECT;
channelOpenRequest.SenderChannel = ntohl(*((unsigned int *)pCurrent));
if (senderChannel) {
*senderChannel = channelOpenRequest.SenderChannel;
}
pCurrent += sizeof(unsigned int);
channelOpenRequest.InitialWindow = ntohl(*((unsigned int *)pCurrent));
pCurrent += 2 * sizeof(unsigned int);
unsigned int len = ntohl(*((unsigned int *)pCurrent));
pCurrent += sizeof(unsigned int);
channelOpenRequest.Address.append((char *)pCurrent, len);
pCurrent += len;
channelOpenRequest.Port = ntohl(*((unsigned int *)pCurrent));
pCurrent += sizeof(unsigned int);
module->_cb(module, module->_cbParam, &channelOpenRequest, sizeof(channelOpenRequest), status);
}
*/
/*
void LME_apfUserAuthRequest(struct LMEConnection* module, unsigned char *rxBuffer, unsigned int bytesRead, int *status)
{
unsigned char *pCurrent = rxBuffer;
++pCurrent;
LMEUserAuthRequestMessage userAuthRequest;
unsigned int len = ntohl(*((unsigned int *)pCurrent));
pCurrent += sizeof(unsigned int);
if ((bytesRead - (pCurrent - rxBuffer)) < len) {
ILIBMESSAGE("_apfUserAuthRequest1: Error receiving data from MEI\n");
LME_Deinit(module);
return;
}
userAuthRequest.Username.append((char *)pCurrent, len);
pCurrent += len;
if ((unsigned int)(bytesRead - (pCurrent - rxBuffer)) < sizeof(unsigned int)) {
ILIBMESSAGE("_apfUserAuthRequest2: Error receiving data from MEI\n");
LME_Deinit(module);
return;
}
len = ntohl(*((unsigned int *)pCurrent));
pCurrent += sizeof(unsigned int);
if ((bytesRead - (pCurrent - rxBuffer)) < len) {
ILIBMESSAGE("_apfUserAuthRequest3: Error receiving data from MEI\n");
LME_Deinit(module);
return;
}
userAuthRequest.ServiceName.append((char *)pCurrent, len);
pCurrent += len;
if ((unsigned int)(bytesRead - (pCurrent - rxBuffer)) < sizeof(unsigned int)) {
ILIBMESSAGE("_apfUserAuthRequest4: Error receiving data from MEI\n");
LME_Deinit(module);
return;
}
len = ntohl(*((unsigned int *)pCurrent));
pCurrent += sizeof(unsigned int);
if ((bytesRead - (pCurrent - rxBuffer)) < len) {
ILIBMESSAGE("_apfUserAuthRequest5: Error receiving data from MEI\n");
LME_Deinit(module);
return;
}
userAuthRequest.MethodName.append((char *)pCurrent, len);
pCurrent += len;
if (_strnicmp(userAuthRequest.MethodName.c_str(), APF_AUTH_PASSWORD,
userAuthRequest.MethodName.size()) == 0) {
if ((unsigned int)(bytesRead - (pCurrent - rxBuffer)) < sizeof(unsigned int) + 1) {
ILIBMESSAGE("_apfUserAuthRequest6: Error receiving data from MEI\n");
LME_Deinit(module);
return;
}
++pCurrent;
len = ntohl(*((unsigned int *)pCurrent));
pCurrent += sizeof(unsigned int);
if ((bytesRead - (pCurrent - rxBuffer)) < len) {
ILIBMESSAGE("_apfUserAuthRequest7: Error receiving data from MEI\n");
LME_Deinit(module);
return;
}
AuthPasswordData authData;
authData.Password.append((char *)pCurrent, len);
pCurrent += len;
userAuthRequest.MethodData = &authData;
}
module->_cb(module, module->_cbParam, &userAuthRequest, sizeof(userAuthRequest), status);
}
*/
unsigned int LME_GetMeiBufferSize(struct LMEConnection* module)
{
return heci_GetBufferSize(&(module->mei));
}
#endif