/** * @file mainRjct.c * @author NXP Semiconductors * @version 1.0 * @par License * * Copyright 2017,2020 NXP * SPDX-License-Identifier: Apache-2.0 * * @par Description * Connection Oriented TCP/IP Server implementing Remote JCTerminal Protocol. * The server can connect to the secure element via the * - SCI2C protocol * - T1oI2C protocol * @par History * *****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include "rjct.h" #if defined(SCI2C) #include "apduComm.h" #include "sci2c.h" #endif #define PORT "8050" // the port users will be connecting to #define BACKLOG 1 // how many pending connections queue will hold #define APP_BUFFER 2048 #if defined(SCI2C) #define MAX_READ_SOCKET 2000 #elif defined(TDA8029_UART) #define MAX_READ_SOCKET 500 #elif defined(PCSC) #define MAX_READ_SOCKET 1024 #elif defined(SMCOM_JRCP_V2) // TODO: Check value #define MAX_READ_SOCKET 2000 #elif defined(T1oI2C) // TODO: Check value #define MAX_READ_SOCKET 2000 #else #error "No communication channel defined" #endif #define ERROR_VERBOSE #ifndef FLOW_VERBOSE #define FLOW_VERBOSE #endif // #define DBG_VERBOSE #ifdef ERROR_VERBOSE #define EPRINTF(...) printf (__VA_ARGS__) #else #define EPRINTF(...) #endif #ifdef FLOW_VERBOSE #define FPRINTF(...) printf (__VA_ARGS__) #else #define FPRINTF(...) #endif #ifdef DBG_VERBOSE #define DPRINTF(...) printf (__VA_ARGS__) #else #define DPRINTF(...) #endif void sigchld_handler(int s) { while (waitpid(-1, NULL, WNOHANG) > 0); } // get sockaddr, IPv4 or IPv6: void *get_in_addr(struct sockaddr *sa) { if (sa->sa_family == AF_INET) { return &(((struct sockaddr_in*)sa)->sin_addr); } return &(((struct sockaddr_in6*)sa)->sin6_addr); } int main(void) { int sockfd, new_fd; // listen on sock_fd, new connection on new_fd struct addrinfo hints, *servinfo, *p; struct sockaddr_storage their_addr; // connector's address information socklen_t sin_size; struct sigaction sa; int yes=1; char s[INET6_ADDRSTRLEN]; int rv; U8 targetBuffer[APP_BUFFER]; U16 targetBufferLen = sizeof(targetBuffer); U16 statusValue = 0; U8 respBuf[APP_BUFFER]; U16 respBufLen = sizeof(respBuf); static bool sessionOpen = FALSE; // U8 result = 1; U16 connectStatus = 0; #if defined(TDA8029_UART) || defined(SCI2C) || defined(PCSC) || defined(SMCOM_JRCP_V2) || defined(T1oI2C) U8 Atr[64]; U16 AtrLen = sizeof(Atr); SmCommStateRjct_t commState; // Scp03SessionState_t sessionState; #endif memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; // use my IP if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) { EPRINTF("getaddrinfo: %s\n", gai_strerror(rv)); return 1; } // loop through all the results and bind to the first we can for (p = servinfo; p != NULL; p = p->ai_next) { if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { perror("server: socket"); continue; } if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt"); exit(1); } if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { close(sockfd); perror("server: bind"); continue; } break; } if (p == NULL) { EPRINTF("server: failed to bind\n"); return 2; } freeaddrinfo(servinfo); // all done with this structure if (listen(sockfd, BACKLOG) == -1) { perror("listen"); exit(1); } sa.sa_handler = sigchld_handler; // reap all dead processes sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) == -1) { perror("sigaction"); exit(1); } #if defined(TDA8029_UART) printf("RemoteJCShell Terminal Server (supporting TDA-8029-UART to smartcard) Rev 0.91\n"); #elif defined(SCI2C) printf("RemoteJCShell Terminal Server (supporting SCI2C) Rev 0.92\n"); #if defined(TGT_A71CH) || defined(TGT_A71CL) printf("A71 (I2C_CLK_MAX = 400 kHz) - Effective Master Clock depends on Host Platform.\n"); #else printf("A70 (I2C_CLK_MAX = 100 kHz) - Effective Master Clock depends on Host Platform.\n"); #endif #elif defined (PCSC) printf("RemoteJCShell Terminal Server (supporting PCSC) Rev 0.92\n"); #elif defined(SMCOM_JRCP_V2) printf("RemoteJCShell Terminal Server (supporting JRCPv2 Client Side)\n"); #elif defined(T1oI2C) printf("RemoteJCShell Terminal Server (supporting T1oI2C Client Side)\n"); #else #error "No interconnect defined: supported are TDA8029_UART, SCI2C and PCSC" #endif printf("******************************************************************************\n"); printf("Establish a connection via JCShell:\n"); printf("\t/term Remote|:\n"); printf("\t e.g.\n"); printf("\t /term Remote|192.168.1.27:8050\n"); printf("\n"); printf("Server: waiting for connections...\n"); while (1) // main accept() loop { sin_size = sizeof their_addr; new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); if (new_fd == -1) { perror("accept"); continue; } inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s); FPRINTF("Server: got connection from %s\n", s); if (!fork()) { // this is the child process int nExpectedPayload = 0; close(sockfd); // child doesn't need the listener while(1) { U8 rcvBuf[APP_BUFFER]; int nRcv; int nRcvAcc; int i; U8 emptyDbgInfo[] = {DEBUG_INFORMATION, 0x00, 0x00, 0x00}; U8 emptyTerminalInfo[] = {TERMINAL_INFO, 0x00, 0x00, 0x00}; nRcv = recv(new_fd, rcvBuf, 4, MSG_WAITALL); nRcvAcc = nRcv; switch (nRcv) { case -1: perror("recv"); FPRINTF("recv() failed: %d\n", nRcv); exit(0); break; case 0: FPRINTF("Connection closed by client (%d)\n", nRcv); #if defined(SCI2C) sci2c_TerminateI2C(1); #endif exit(0); break; default: DPRINTF("Received: \n"); for (i=0; i MAX_READ_SOCKET) { EPRINTF("nExpectPayload too big %d (limit=%d).\n", nExpectedPayload, MAX_READ_SOCKET); exit(0); } nRcv = recv(new_fd, rcvBuf+4, nExpectedPayload, 0); if (nRcv == -1) { perror("Error on additional read"); exit(0); } else if (nRcv == 0) { EPRINTF("Connection was closed by client on additional read.\n"); exit(0); } else if (nRcv < 0) { EPRINTF("recv returns error on additional read. nRcv = %d (nRcv = 0x%08X).\n", nRcv, nRcv); exit(0); } else { DPRINTF("Received: \n"); for (i=0; i