blob: 5088fbd2f4fd4a3fcbbc77a06dd90683c9bf8124 [file] [log] [blame]
/**
* @file smComSocket_linux.c
* @author NXP Semiconductors
* @version 1.0
* @par License
*
* Copyright 2016 NXP
* SPDX-License-Identifier: Apache-2.0
*
* @par Description
*
*/
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <time.h>
#include <netdb.h>
#include "smCom.h"
#include "smComSocket.h"
#include "sm_printf.h"
#include "sm_types.h"
#include "nxEnsure.h"
#include "sm_timer.h"
#ifdef FLOW_VERBOSE
#define NX_LOG_ENABLE_SMCOM_DEBUG 1
#define LOG_SOCK 1
// #define LOG_FULL_CMD_RSP
#endif
#include "nxLog_smCom.h"
// Enable define of LOG_SOCK to echo APDU cmd/rsp
// #define LOG_SOCK
// Enable define of CHECK_ON_ATR to enable check on returned ATR (don't enable this when using the Smart Card Server ...)
#define CHECK_ON_ATR
#define REMOTE_JC_SHELL_HEADER_LEN (4)
#define REMOTE_JC_SHELL_MSG_TYPE_APDU_DATA (0x01)
#include "sm_apdu.h"
#define MAX_BUF_SIZE (MAX_APDU_BUF_LENGTH)
#define MTY_ATR 0x00
#define MTY_CLOSE 0x03
#define NAD 0x00
static U8 Header[2] = {0x01, 0x00};
static U8 sockapdu[MAX_BUF_SIZE];
static U8 response[MAX_BUF_SIZE];
static U8 *pCmd = (U8 *)&sockapdu;
static U8 *pRsp = (U8 *)&response;
#if defined(__OSX_AVAILABLE) || defined(RJCT_VCOM)
#define READ_RECV( FD, PTR, BUFLEN) \
read((FD), (PTR), (BUFLEN))
#define READ_RECV_STR "read"
#define WRITE_SEND( FD, PTR, BUFLEN) \
write((FD), (PTR), (BUFLEN))
#define WRITE_SEND_STR "write"
#else
#define READ_RECV( FD, PTR, BUFLEN) \
recv((FD), (PTR), (BUFLEN), 0)
#define READ_RECV_STR "recv"
#define WRITE_SEND( FD, PTR, BUFLEN) \
send((FD), (PTR), (BUFLEN), 0)
#define WRITE_SEND_STR "send"
#endif
U32 smComSocket_CloseFD(int fd)
{
int retval;
U8 Cmd[4] = {MTY_CLOSE, NAD, 0, 0};
U32 totalReceived = 0;
U8 lengthReceived = 0;
U32 expectedLength = 0;
LOG_D("Closing()");
retval = WRITE_SEND( fd, Cmd, sizeof(Cmd));
if (retval < 0) {
LOG_W("Client: " WRITE_SEND_STR "() failed: error %i", retval);
return SMCOM_SND_FAILED;
}
expectedLength = REMOTE_JC_SHELL_HEADER_LEN; // remote JC shell header length
while (totalReceived < expectedLength) {
U32 maxCommLength;
if (lengthReceived == 0) {
maxCommLength = REMOTE_JC_SHELL_HEADER_LEN - totalReceived;
}
else {
maxCommLength = expectedLength - totalReceived;
}
retval = READ_RECV(fd, (char *)&pRsp[totalReceived], maxCommLength);
if (retval < 0) {
LOG_W("Client: " READ_RECV_STR "() failed: error %i", retval);
close(fd);
return SMCOM_RCV_FAILED;
}
else {
totalReceived += retval;
}
if ((totalReceived >= REMOTE_JC_SHELL_HEADER_LEN) && (lengthReceived == 0)) {
expectedLength += ((pRsp[2] << 8) | (pRsp[3]));
lengthReceived = 1;
}
}
retval = totalReceived;
close(fd);
return 0;
}
U32 smComSocket_GetATRFD(int fd, U8 *pAtr, U16 *atrLen)
{
#define MTY 0
// #define NAD 0x21
#define NAD 0x00
int retval = 0;
int read_write_len;
U32 expectedLength = 0;
U32 totalReceived = 0;
U8 lengthReceived = 0;
// wait 256 ms
U8 ATRCmd[8] = {MTY, NAD, 0, 4, 0, 0, 1, 0};
ENSURE_OR_GO_EXIT(pAtr != NULL);
ENSURE_OR_GO_EXIT(atrLen != NULL);
LOG_MAU8_D("ATRCmd", ATRCmd, sizeof(ATRCmd));
read_write_len = WRITE_SEND( fd, (const char *)ATRCmd, sizeof(ATRCmd));
if (read_write_len < 0) {
LOG_W("Client: " WRITE_SEND_STR "() failed: error %i", read_write_len);
return -1;
}
expectedLength = REMOTE_JC_SHELL_HEADER_LEN; // remote JC shell header length
while (totalReceived < expectedLength) {
U32 maxCommLength;
if (lengthReceived == 0) {
maxCommLength = REMOTE_JC_SHELL_HEADER_LEN - totalReceived;
}
else {
maxCommLength = expectedLength - totalReceived;
}
LOG_D("Enter: " READ_RECV_STR "() ");
read_write_len = READ_RECV(fd, (char *)&pRsp[totalReceived], expectedLength);
LOG_D("Exit: " READ_RECV_STR "(). read_write_len=%d", read_write_len);
if (read_write_len < 0) {
LOG_W("Client: " READ_RECV_STR "() failed: error %i", retval);
close(fd);
retval = 0;
ENSURE_OR_GO_EXIT(0);
}
else {
totalReceived += read_write_len;
}
if ((totalReceived >= REMOTE_JC_SHELL_HEADER_LEN) && (lengthReceived == 0)) {
expectedLength += ((pRsp[2] << 8) | (pRsp[3]));
lengthReceived = 1;
}
}
read_write_len = totalReceived;
#ifdef LOG_FULL_CMD_RSP
LOG_MAU8_D("Rsp:Hdr", pRsp, 4);
#endif
read_write_len -= 4; // Remove the 4 bytes of the Remote JC Terminal protocol
memcpy(pAtr, pRsp + 4, read_write_len);
LOG_MAU8_D("Atr", pAtr, read_write_len);
*atrLen = (U16)read_write_len;
exit:
return retval;
}
U32 smComSocket_TransceiveFD(int fd, apdu_t *pApdu)
{
int retval;
U32 txLen = 0;
U32 expectedLength = 0;
U32 totalReceived = 0;
U8 lengthReceived = 0;
U32 rv = SMCOM_SND_FAILED;
ENSURE_OR_GO_EXIT(pApdu != NULL);
pApdu->rxlen = 0;
// TODO (?): adjustments on Le and Lc for SCP still to be done
memset(sockapdu, 0x00, MAX_BUF_SIZE);
memset(response, 0x00, MAX_BUF_SIZE);
// remote JC Terminal header construction
txLen = pApdu->buflen;
memcpy(pCmd, Header, sizeof(Header));
pCmd[2] = (txLen & 0xFF00) >> 8;
pCmd[3] = txLen & 0xFF;
memcpy(&pCmd[4], pApdu->pBuf, pApdu->buflen);
pApdu->buflen += 4; /* header & length */
#ifdef LOG_FULL_CMD_RSP
LOG_MAU8_D("Cmd:Hdr", pCmd, 4);
#endif
LOG_MAU8_D("Cmd", pCmd + 4, pApdu->buflen - 4);
retval = WRITE_SEND( fd, (const char *)pCmd, pApdu->buflen);
if (retval < 0) {
LOG_W("Client: " WRITE_SEND_STR "() failed: error %i", retval);
return SMCOM_SND_FAILED;
}
expectedLength = REMOTE_JC_SHELL_HEADER_LEN; // remote JC shell header length
while (totalReceived < expectedLength) {
retval = READ_RECV(fd, (char *)&pRsp[totalReceived], MAX_BUF_SIZE);
if (retval < 0) {
LOG_W("Client: " READ_RECV_STR "() failed: error %i", retval);
close(fd);
rv = SMCOM_RCV_FAILED;
ENSURE_OR_GO_EXIT(0);
}
else {
totalReceived += retval;
}
if ((totalReceived >= REMOTE_JC_SHELL_HEADER_LEN) && (lengthReceived == 0)) {
expectedLength += ((pRsp[2] << 8) | (pRsp[3]));
lengthReceived = 1;
}
}
retval = totalReceived;
retval -= 4; // Remove the 4 bytes of the Remote JC Terminal protocol
memcpy(pApdu->pBuf, &pRsp[4], retval);
#ifdef LOG_FULL_CMD_RSP
LOG_MAU8_D("Rsp:Hdr", pRsp, 4);
#endif
LOG_MAU8_D("Rsp", pApdu->pBuf, retval);
pApdu->rxlen = (U16)retval;
// reset offset for subsequent response parsing
pApdu->offset = 0;
rv = SMCOM_OK;
exit:
return rv;
}
U32 smComSocket_TransceiveRawFD(int fd, U8 *pTx, U16 txLen, U8 *pRx, U32 *pRxLen)
{
int read_write_len;
U32 expectedLength = 0;
int lengthReceived = 0;
U32 totalReceived = 0;
U32 rv = SMCOM_COM_FAILED;
ENSURE_OR_GO_EXIT(pTx != NULL);
ENSURE_OR_GO_EXIT(pRx != NULL);
ENSURE_OR_GO_EXIT(pRxLen != NULL);
memset(sockapdu, 0x00, MAX_BUF_SIZE);
memset(response, 0x00, MAX_BUF_SIZE);
memcpy(pCmd, Header, 2);
pCmd[2] = (txLen & 0xFF00) >> 8;
pCmd[3] = (txLen & 0x00FF);
memcpy(&pCmd[4], pTx, txLen);
txLen += 4; /* header + len */
#ifdef LOG_FULL_CMD_RSP
LOG_MAU8_D("Cmd:Hdr", pCmd, REMOTE_JC_SHELL_HEADER_LEN);
#endif
LOG_MAU8_D("Cmd", pCmd + REMOTE_JC_SHELL_HEADER_LEN, txLen - REMOTE_JC_SHELL_HEADER_LEN);
read_write_len = WRITE_SEND( fd, (const char *)pCmd, txLen);
if (read_write_len < 0) {
LOG_W("Client: " WRITE_SEND_STR "() failed: error %i", read_write_len);
return SMCOM_SND_FAILED;
}
else {
#ifdef DBG_LOG_SOCK
LOG_D("Client: " WRITE_SEND_STR "() is OK.\r\n");
#endif
}
expectedLength = REMOTE_JC_SHELL_HEADER_LEN; // remote JC shell header length
while (totalReceived < expectedLength) {
read_write_len = READ_RECV(fd, (char *)&pRsp[totalReceived], MAX_BUF_SIZE);
if (read_write_len < 0) {
LOG_W("Client: " READ_RECV_STR "() failed: error %i", read_write_len);
close(fd);
rv = SMCOM_RCV_FAILED;
ENSURE_OR_GO_EXIT(0);
}
else {
totalReceived += read_write_len;
}
if ((totalReceived >= REMOTE_JC_SHELL_HEADER_LEN) && (lengthReceived == 0)) {
expectedLength += ((pRsp[2] << 8) | (pRsp[3]));
lengthReceived = 1;
}
}
#ifdef LOG_FULL_CMD_RSP
LOG_MAU8_D("Rsp:Hdr", pRsp, REMOTE_JC_SHELL_HEADER_LEN);
#endif
memcpy(pRx, &pRsp[REMOTE_JC_SHELL_HEADER_LEN], totalReceived - REMOTE_JC_SHELL_HEADER_LEN);
*pRxLen = totalReceived - REMOTE_JC_SHELL_HEADER_LEN;
LOG_MAU8_D("Rsp", pRx, *pRxLen);
rv = SMCOM_OK;
exit:
return rv;
}