| /** |
| * @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; |
| } |