1262 lines
44 KiB
C
1262 lines
44 KiB
C
/*******************************************************************************
|
|
File Name:
|
|
socket.c
|
|
|
|
Summary:
|
|
WINC3400 BSD Compatible Socket Interface
|
|
|
|
Description:
|
|
WINC3400 BSD Compatible Socket Interface
|
|
*******************************************************************************/
|
|
|
|
//DOM-IGNORE-BEGIN
|
|
/*******************************************************************************
|
|
* Copyright (C) 2021 Microchip Technology Inc. and its subsidiaries.
|
|
*
|
|
* Subject to your compliance with these terms, you may use Microchip software
|
|
* and any derivatives exclusively with Microchip products. It is your
|
|
* responsibility to comply with third party license terms applicable to your
|
|
* use of third party software (including open source software) that may
|
|
* accompany Microchip software.
|
|
*
|
|
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
|
|
* EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
|
|
* WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
|
|
* PARTICULAR PURPOSE.
|
|
*
|
|
* IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
|
|
* INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
|
|
* WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
|
|
* BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
|
|
* FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
|
|
* ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
|
|
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
|
|
*******************************************************************************/
|
|
|
|
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
|
|
INCLUDES
|
|
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
|
|
|
|
#include "nm_bsp.h"
|
|
#include "socket.h"
|
|
#include "m2m_hif.h"
|
|
#include "m2m_socket_host_if.h"
|
|
|
|
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
|
|
MACROS
|
|
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
|
|
|
|
#define TLS_RECORD_HEADER_LENGTH (5)
|
|
#define ETHERNET_HEADER_OFFSET (34)
|
|
#define ETHERNET_HEADER_LENGTH (14)
|
|
#define TCP_IP_HEADER_LENGTH (40)
|
|
#define UDP_IP_HEADER_LENGTH (28)
|
|
|
|
#define IP_PACKET_OFFSET (ETHERNET_HEADER_LENGTH + ETHERNET_HEADER_OFFSET - M2M_HIF_HDR_OFFSET)
|
|
|
|
#define TCP_TX_PACKET_OFFSET (IP_PACKET_OFFSET + TCP_IP_HEADER_LENGTH)
|
|
#define UDP_TX_PACKET_OFFSET (IP_PACKET_OFFSET + UDP_IP_HEADER_LENGTH)
|
|
#define SSL_TX_PACKET_OFFSET (TCP_TX_PACKET_OFFSET + TLS_RECORD_HEADER_LENGTH)
|
|
|
|
#define SOCKET_REQUEST(reqID, reqArgs, reqSize, reqPayload, reqPayloadSize, reqPayloadOffset) \
|
|
hif_send(M2M_REQ_GROUP_IP, reqID, reqArgs, reqSize, reqPayload, reqPayloadSize, reqPayloadOffset)
|
|
|
|
|
|
#define SSL_FLAGS_ACTIVE NBIT0
|
|
#define SSL_FLAGS_BYPASS_X509 NBIT1
|
|
#define SSL_FLAGS_CACHE_SESSION NBIT4
|
|
#define SSL_FLAGS_CHECK_CERTNAME NBIT6
|
|
#define SSL_FLAGS_DELAY NBIT7
|
|
|
|
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
|
|
PRIVATE DATA TYPES
|
|
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
|
|
|
|
|
|
/*!
|
|
* @brief
|
|
*/
|
|
typedef struct {
|
|
SOCKET sock;
|
|
uint8_t u8Dummy;
|
|
uint16_t u16SessionID;
|
|
} tstrCloseCmd;
|
|
|
|
|
|
/*!
|
|
* @brief
|
|
*/
|
|
typedef struct {
|
|
uint8_t *pu8UserBuffer;
|
|
uint16_t u16UserBufferSize;
|
|
uint16_t u16SessionID;
|
|
uint16_t u16DataOffset;
|
|
uint8_t bIsUsed;
|
|
uint8_t u8SSLFlags;
|
|
uint8_t bIsRecvPending;
|
|
uint8_t u8AlpnStatus;
|
|
uint8_t u8ErrSource;
|
|
uint8_t u8ErrCode;
|
|
} tstrSocket;
|
|
|
|
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
|
|
GLOBALS
|
|
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
|
|
|
|
volatile tstrSocket gastrSockets[MAX_SOCKET];
|
|
volatile uint16_t gu16SessionID = 0;
|
|
|
|
volatile tpfAppSocketCb gpfAppSocketCb;
|
|
volatile tpfAppResolveCb gpfAppResolveCb;
|
|
volatile uint8_t gbSocketInit = 0;
|
|
|
|
static tpfPingCb gfpPingCb = NULL;
|
|
static uint32_t gu32PingId = 0;
|
|
|
|
/*********************************************************************
|
|
Function
|
|
Socket_ReadSocketData
|
|
|
|
Description
|
|
Callback function used by the WINC3400 driver to deliver messages
|
|
for socket layer.
|
|
|
|
Return
|
|
None.
|
|
*********************************************************************/
|
|
static void Socket_ReadSocketData(SOCKET sock, tstrSocketRecvMsg *pstrRecv, uint8_t u8SocketMsg,
|
|
uint32_t u32StartAddress, uint16_t u16ReadCount)
|
|
{
|
|
uint32_t u32Address = u32StartAddress;
|
|
uint16_t u16Read;
|
|
int16_t s16Diff;
|
|
|
|
pstrRecv->u16RemainingSize = u16ReadCount;
|
|
if((u16ReadCount > 0) && (gastrSockets[sock].pu8UserBuffer != NULL) && (gastrSockets[sock].u16UserBufferSize > 0) && (gastrSockets[sock].bIsUsed == 1))
|
|
{
|
|
u16Read = u16ReadCount;
|
|
s16Diff = u16Read - gastrSockets[sock].u16UserBufferSize;
|
|
if(s16Diff > 0)
|
|
{
|
|
/* We don't expect to be here. Firmware only sends data to the driver according to the application's buffer size.
|
|
* But it is worth keeping this check, eg in case the application calls recv again with a smaller buffer size, or in case of HIF hacking. */
|
|
u16Read = gastrSockets[sock].u16UserBufferSize;
|
|
}
|
|
|
|
if(hif_receive(u32Address, gastrSockets[sock].pu8UserBuffer, u16Read, 1) == M2M_SUCCESS)
|
|
{
|
|
pstrRecv->pu8Buffer = gastrSockets[sock].pu8UserBuffer;
|
|
pstrRecv->s16BufferSize = u16Read;
|
|
pstrRecv->u16RemainingSize -= u16Read;
|
|
|
|
gastrSockets[sock].u16UserBufferSize = 0;
|
|
gastrSockets[sock].pu8UserBuffer = NULL;
|
|
|
|
if(gpfAppSocketCb)
|
|
gpfAppSocketCb(sock, u8SocketMsg, pstrRecv);
|
|
}
|
|
else
|
|
{
|
|
M2M_ERR("Current <%d>\r\n", u16ReadCount);
|
|
}
|
|
}
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
m2m_ip_cb
|
|
|
|
Description
|
|
Callback function used by the NMC1000 driver to deliver messages
|
|
for socket layer.
|
|
|
|
Return
|
|
None.
|
|
*********************************************************************/
|
|
static void m2m_ip_cb(uint8_t u8OpCode, uint16_t u16BufferSize, uint32_t u32Address)
|
|
{
|
|
if(u8OpCode == SOCKET_CMD_BIND)
|
|
{
|
|
tstrBindReply strBindReply;
|
|
tstrSocketBindMsg strBind;
|
|
|
|
if(hif_receive(u32Address, (uint8_t*)&strBindReply, sizeof(tstrBindReply), 0) == M2M_SUCCESS)
|
|
{
|
|
strBind.status = strBindReply.s8Status;
|
|
if(gpfAppSocketCb)
|
|
gpfAppSocketCb(strBindReply.sock, SOCKET_MSG_BIND, &strBind);
|
|
}
|
|
}
|
|
else if(u8OpCode == SOCKET_CMD_LISTEN)
|
|
{
|
|
tstrListenReply strListenReply;
|
|
tstrSocketListenMsg strListen;
|
|
if(hif_receive(u32Address, (uint8_t*)&strListenReply, sizeof(tstrListenReply), 0) == M2M_SUCCESS)
|
|
{
|
|
strListen.status = strListenReply.s8Status;
|
|
if(gpfAppSocketCb)
|
|
gpfAppSocketCb(strListenReply.sock, SOCKET_MSG_LISTEN, &strListen);
|
|
}
|
|
}
|
|
else if(u8OpCode == SOCKET_CMD_ACCEPT)
|
|
{
|
|
tstrAcceptReply strAcceptReply;
|
|
tstrSocketAcceptMsg strAccept;
|
|
if(hif_receive(u32Address, (uint8_t*)&strAcceptReply, sizeof(tstrAcceptReply), 0) == M2M_SUCCESS)
|
|
{
|
|
if((strAcceptReply.sConnectedSock >= 0) && (strAcceptReply.sConnectedSock < MAX_SOCKET))
|
|
{
|
|
gastrSockets[strAcceptReply.sConnectedSock].u8SSLFlags = 0;
|
|
gastrSockets[strAcceptReply.sConnectedSock].bIsUsed = 1;
|
|
|
|
/* The session ID is used to distinguish different socket connections
|
|
by comparing the assigned session ID to the one reported by the firmware*/
|
|
++gu16SessionID;
|
|
if(gu16SessionID == 0)
|
|
++gu16SessionID;
|
|
|
|
gastrSockets[strAcceptReply.sConnectedSock].u16SessionID = gu16SessionID;
|
|
M2M_DBG("Socket %d session ID = %d\r\n", strAcceptReply.sConnectedSock, gu16SessionID);
|
|
}
|
|
strAccept.sock = strAcceptReply.sConnectedSock;
|
|
strAccept.strAddr.sin_family = AF_INET;
|
|
strAccept.strAddr.sin_port = strAcceptReply.strAddr.u16Port;
|
|
strAccept.strAddr.sin_addr.s_addr = strAcceptReply.strAddr.u32IPAddr;
|
|
if(gpfAppSocketCb)
|
|
gpfAppSocketCb(strAcceptReply.sListenSock, SOCKET_MSG_ACCEPT, &strAccept);
|
|
}
|
|
}
|
|
else if((u8OpCode == SOCKET_CMD_CONNECT) || (u8OpCode == SOCKET_CMD_SSL_CONNECT) || (u8OpCode == SOCKET_CMD_SSL_CONNECT_ALPN))
|
|
{
|
|
/* Note that for successful connections the fw always sends SOCKET_CMD_CONNECT, even for SSL connections. */
|
|
tstrConnectAlpnReply strConnectAlpnReply = {{0}};
|
|
tstrSocketConnectMsg strConnMsg;
|
|
uint16_t u16HifSz = sizeof(tstrConnectAlpnReply);
|
|
if(u8OpCode != SOCKET_CMD_SSL_CONNECT_ALPN)
|
|
u16HifSz = sizeof(tstrConnectReply);
|
|
if(hif_receive(u32Address, (uint8_t*)&strConnectAlpnReply, u16HifSz, 0) == M2M_SUCCESS)
|
|
{
|
|
if((strConnectAlpnReply.strConnReply.sock >= 0) && (strConnectAlpnReply.strConnReply.sock < MAX_SOCKET))
|
|
{
|
|
uint8_t u8Msg = SOCKET_MSG_CONNECT;
|
|
|
|
strConnMsg.sock = strConnectAlpnReply.strConnReply.sock;
|
|
strConnMsg.s8Error = strConnectAlpnReply.strConnReply.s8Error;
|
|
|
|
/* If the SOCKET_CMD_SSL_CONNECT op code is received and the socket was already connected, then the
|
|
callback corresponds to an attempt to make the socket secure. */
|
|
if(0 != gastrSockets[strConnMsg.sock].u16DataOffset)
|
|
{
|
|
u8Msg = SOCKET_MSG_SECURE;
|
|
}
|
|
if(strConnectAlpnReply.strConnReply.s8Error == SOCK_ERR_NO_ERROR)
|
|
{
|
|
gastrSockets[strConnMsg.sock].u16DataOffset = strConnectAlpnReply.strConnReply.u16AppDataOffset - M2M_HIF_HDR_OFFSET;
|
|
gastrSockets[strConnMsg.sock].u8AlpnStatus = strConnectAlpnReply.u8AppProtocolIdx;
|
|
}
|
|
else
|
|
{
|
|
gastrSockets[strConnMsg.sock].u8ErrSource = strConnectAlpnReply.strConnReply.u8ErrSource;
|
|
gastrSockets[strConnMsg.sock].u8ErrCode = strConnectAlpnReply.strConnReply.u8ErrCode;
|
|
}
|
|
if(gpfAppSocketCb)
|
|
gpfAppSocketCb(strConnMsg.sock, u8Msg, &strConnMsg);
|
|
}
|
|
}
|
|
}
|
|
else if(u8OpCode == SOCKET_CMD_DNS_RESOLVE)
|
|
{
|
|
tstrDnsReply strDnsReply;
|
|
if(hif_receive(u32Address, (uint8_t*)&strDnsReply, sizeof(tstrDnsReply), 0) == M2M_SUCCESS)
|
|
{
|
|
strDnsReply.u32HostIP = strDnsReply.u32HostIP;
|
|
if(gpfAppResolveCb)
|
|
gpfAppResolveCb((uint8_t*)strDnsReply.acHostName, strDnsReply.u32HostIP);
|
|
}
|
|
}
|
|
else if((u8OpCode == SOCKET_CMD_RECV) || (u8OpCode == SOCKET_CMD_RECVFROM) || (u8OpCode == SOCKET_CMD_SSL_RECV))
|
|
{
|
|
SOCKET sock;
|
|
int16_t s16RecvStatus;
|
|
tstrRecvReply strRecvReply;
|
|
uint16_t u16ReadSize;
|
|
tstrSocketRecvMsg strRecvMsg;
|
|
uint8_t u8CallbackMsgID = SOCKET_MSG_RECV;
|
|
uint16_t u16DataOffset;
|
|
|
|
if(u8OpCode == SOCKET_CMD_RECVFROM)
|
|
u8CallbackMsgID = SOCKET_MSG_RECVFROM;
|
|
|
|
/* Read RECV REPLY data structure.
|
|
*/
|
|
u16ReadSize = sizeof(tstrRecvReply);
|
|
if(hif_receive(u32Address, (uint8_t*)&strRecvReply, u16ReadSize, 0) == M2M_SUCCESS)
|
|
{
|
|
if((strRecvReply.sock >= 0) && (strRecvReply.sock < MAX_SOCKET))
|
|
{
|
|
uint16_t u16SessionID = 0;
|
|
|
|
sock = strRecvReply.sock;
|
|
u16SessionID = strRecvReply.u16SessionID;
|
|
M2M_DBG("recv callback session ID = %d\r\n", u16SessionID);
|
|
|
|
/* Reset the Socket RX Pending Flag.
|
|
*/
|
|
gastrSockets[sock].bIsRecvPending = 0;
|
|
|
|
s16RecvStatus = NM_BSP_B_L_16(strRecvReply.s16RecvStatus);
|
|
u16DataOffset = NM_BSP_B_L_16(strRecvReply.u16DataOffset);
|
|
strRecvMsg.strRemoteAddr.sin_port = strRecvReply.strRemoteAddr.u16Port;
|
|
strRecvMsg.strRemoteAddr.sin_addr.s_addr = strRecvReply.strRemoteAddr.u32IPAddr;
|
|
|
|
if(u16SessionID == gastrSockets[sock].u16SessionID)
|
|
{
|
|
if((s16RecvStatus > 0) && (s16RecvStatus < u16BufferSize))
|
|
{
|
|
/* Skip incoming bytes until reaching the Start of Application Data.
|
|
*/
|
|
u32Address += u16DataOffset;
|
|
|
|
/* Read the Application data and deliver it to the application callback in
|
|
the given application buffer. Firmware only sends data up to
|
|
the size of the application buffer. For TCP, a new call to recv is needed
|
|
in order to retrieve any outstanding data from firmware.
|
|
*/
|
|
u16ReadSize = (uint16_t)s16RecvStatus;
|
|
Socket_ReadSocketData(sock, &strRecvMsg, u8CallbackMsgID, u32Address, u16ReadSize);
|
|
}
|
|
else
|
|
{
|
|
/* Don't tidy up here. Application must call shutdown().
|
|
*/
|
|
strRecvMsg.s16BufferSize = s16RecvStatus;
|
|
strRecvMsg.pu8Buffer = NULL;
|
|
if(gpfAppSocketCb)
|
|
gpfAppSocketCb(sock, u8CallbackMsgID, &strRecvMsg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
M2M_DBG("Discard recv callback %d %d\r\n", u16SessionID, gastrSockets[sock].u16SessionID);
|
|
if(u16ReadSize < u16BufferSize)
|
|
hif_receive(0, NULL, 0, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if((u8OpCode == SOCKET_CMD_SEND) || (u8OpCode == SOCKET_CMD_SENDTO) || (u8OpCode == SOCKET_CMD_SSL_SEND))
|
|
{
|
|
SOCKET sock;
|
|
int16_t s16Rcvd;
|
|
tstrSendReply strReply;
|
|
uint8_t u8CallbackMsgID = SOCKET_MSG_SEND;
|
|
|
|
if(u8OpCode == SOCKET_CMD_SENDTO)
|
|
u8CallbackMsgID = SOCKET_MSG_SENDTO;
|
|
|
|
if(hif_receive(u32Address, (uint8_t*)&strReply, sizeof(tstrSendReply), 0) == M2M_SUCCESS)
|
|
{
|
|
if((strReply.sock >=0) && (strReply.sock < MAX_SOCKET))
|
|
{
|
|
uint16_t u16SessionID = 0;
|
|
|
|
sock = strReply.sock;
|
|
u16SessionID = strReply.u16SessionID;
|
|
M2M_DBG("send callback session ID = %d\r\n", u16SessionID);
|
|
|
|
s16Rcvd = NM_BSP_B_L_16(strReply.s16SentBytes);
|
|
|
|
if(u16SessionID == gastrSockets[sock].u16SessionID)
|
|
{
|
|
if(gpfAppSocketCb)
|
|
gpfAppSocketCb(sock, u8CallbackMsgID, &s16Rcvd);
|
|
}
|
|
else
|
|
{
|
|
M2M_DBG("Discard send callback %d %d\r\n", u16SessionID, gastrSockets[sock].u16SessionID);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(u8OpCode == SOCKET_CMD_PING)
|
|
{
|
|
tstrPingReply strPingReply;
|
|
if(hif_receive(u32Address, (uint8_t*)&strPingReply, sizeof(tstrPingReply), 1) == M2M_SUCCESS)
|
|
{
|
|
if((gu32PingId == strPingReply.u32CmdPrivate) && (gfpPingCb != NULL))
|
|
{
|
|
gfpPingCb(strPingReply.u32IPAddr, strPingReply.u32RTT, strPingReply.u8ErrorCode);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
socketInit
|
|
|
|
Description
|
|
|
|
Return
|
|
None.
|
|
*********************************************************************/
|
|
void socketInit(void)
|
|
{
|
|
if(gbSocketInit==0)
|
|
{
|
|
memset((uint8_t*)gastrSockets, 0, MAX_SOCKET * sizeof(tstrSocket));
|
|
hif_register_cb(M2M_REQ_GROUP_IP, m2m_ip_cb);
|
|
gbSocketInit=1;
|
|
gu16SessionID = 0;
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
Function
|
|
socketDeinit
|
|
|
|
Description
|
|
|
|
Return
|
|
None.
|
|
*********************************************************************/
|
|
void socketDeinit(void)
|
|
{
|
|
memset((uint8_t*)gastrSockets, 0, MAX_SOCKET * sizeof(tstrSocket));
|
|
hif_register_cb(M2M_REQ_GROUP_IP, NULL);
|
|
gpfAppSocketCb = NULL;
|
|
gpfAppResolveCb = NULL;
|
|
gbSocketInit = 0;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
Function
|
|
registerSocketCallback
|
|
|
|
Description
|
|
|
|
Return
|
|
None.
|
|
*********************************************************************/
|
|
void registerSocketCallback(tpfAppSocketCb pfAppSocketCb, tpfAppResolveCb pfAppResolveCb)
|
|
{
|
|
gpfAppSocketCb = pfAppSocketCb;
|
|
gpfAppResolveCb = pfAppResolveCb;
|
|
}
|
|
void registerSocketEventCallback(tpfAppSocketCb pfAppSocketCb)
|
|
{
|
|
gpfAppSocketCb = pfAppSocketCb;
|
|
}
|
|
void registerSocketResolveCallback(tpfAppResolveCb pfAppResolveCb)
|
|
{
|
|
gpfAppResolveCb = pfAppResolveCb;
|
|
}
|
|
|
|
/*********************************************************************
|
|
Function
|
|
socket
|
|
|
|
Description
|
|
Creates a socket.
|
|
|
|
Return
|
|
- Negative value for error.
|
|
- ZERO or positive value as a socket ID if successful.
|
|
*********************************************************************/
|
|
SOCKET socket(uint16_t u16Domain, uint8_t u8Type, uint8_t u8Config)
|
|
{
|
|
SOCKET sock = -1;
|
|
uint8_t u8SockID;
|
|
uint8_t u8Count;
|
|
volatile tstrSocket *pstrSock = NULL;
|
|
static volatile uint8_t u8NextTcpSock = 0;
|
|
static volatile uint8_t u8NextUdpSock = 0;
|
|
|
|
/* The only supported family is the AF_INET for UDP and TCP transport layer protocols. */
|
|
if(u16Domain == AF_INET)
|
|
{
|
|
if(u8Type == SOCK_STREAM)
|
|
{
|
|
for(u8Count = 0; u8Count < TCP_SOCK_MAX; u8Count ++)
|
|
{
|
|
u8SockID = u8NextTcpSock;
|
|
pstrSock = &gastrSockets[u8NextTcpSock];
|
|
u8NextTcpSock = (u8NextTcpSock + 1) % TCP_SOCK_MAX;
|
|
if(!pstrSock->bIsUsed)
|
|
{
|
|
sock = (SOCKET)u8SockID;
|
|
memset((uint8_t*)pstrSock, 0, sizeof(tstrSocket));
|
|
/* In the current implementation, SSL flags only have meaning for the TCP socket case. */
|
|
if(u8Config != SOCKET_CONFIG_SSL_OFF)
|
|
{
|
|
tstrSSLSocketCreateCmd strSSLCreate;
|
|
|
|
strSSLCreate.sslSock = sock;
|
|
SOCKET_REQUEST(SOCKET_CMD_SSL_CREATE, (uint8_t*)&strSSLCreate, sizeof(tstrSSLSocketCreateCmd), 0, 0, 0);
|
|
|
|
pstrSock->u8SSLFlags = SSL_FLAGS_ACTIVE;
|
|
if(u8Config == SOCKET_CONFIG_SSL_DELAY)
|
|
pstrSock->u8SSLFlags |= SSL_FLAGS_DELAY;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if(u8Type == SOCK_DGRAM)
|
|
{
|
|
volatile tstrSocket *pastrUDPSockets = &gastrSockets[TCP_SOCK_MAX];
|
|
for(u8Count = 0; u8Count < UDP_SOCK_MAX; u8Count ++)
|
|
{
|
|
u8SockID = u8NextUdpSock;
|
|
pstrSock = &pastrUDPSockets[u8NextUdpSock];
|
|
u8NextUdpSock = (u8NextUdpSock + 1) % UDP_SOCK_MAX;
|
|
if(!pstrSock->bIsUsed)
|
|
{
|
|
sock = (SOCKET)(u8SockID + TCP_SOCK_MAX);
|
|
memset((uint8_t*)pstrSock, 0, sizeof(tstrSocket));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if(u8Type == SOCK_RAW)
|
|
{
|
|
/* Only raw IP packets are supported */
|
|
if(u8Config == SOCKET_CONFIG_IPPROTO_RAW)
|
|
{
|
|
pstrSock = &gastrSockets[RAW_SOCK_ID];
|
|
if(!pstrSock->bIsUsed)
|
|
{
|
|
/* Socket identified by RAW_SOCK_ID is reserved */
|
|
sock = (SOCKET)RAW_SOCK_ID;
|
|
memset((uint8_t*)pstrSock, 0, sizeof(tstrSocket));
|
|
}
|
|
}
|
|
}
|
|
|
|
if(sock >= 0)
|
|
{
|
|
pstrSock->bIsUsed = 1;
|
|
|
|
/* The session ID is used to distinguish different socket connections
|
|
by comparing the assigned session ID to the one reported by the firmware*/
|
|
++gu16SessionID;
|
|
if(gu16SessionID == 0)
|
|
++gu16SessionID;
|
|
|
|
pstrSock->u16SessionID = gu16SessionID;
|
|
M2M_INFO("Socket %d session ID = %d\r\n", sock, gu16SessionID);
|
|
}
|
|
}
|
|
return sock;
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
bind
|
|
|
|
Description
|
|
Request to bind a socket on a local address.
|
|
|
|
Return
|
|
*********************************************************************/
|
|
int8_t bind(SOCKET sock, struct sockaddr *pstrAddr, uint8_t u8AddrLen)
|
|
{
|
|
int8_t s8Ret = SOCK_ERR_INVALID_ARG;
|
|
if((pstrAddr != NULL) && (sock >= 0) && (sock < MAX_SOCKET) && (gastrSockets[sock].bIsUsed == 1) && (u8AddrLen != 0))
|
|
{
|
|
tstrBindCmd strBind;
|
|
|
|
/* Build the bind request. */
|
|
strBind.sock = sock;
|
|
memcpy((uint8_t *)&strBind.strAddr, (uint8_t *)pstrAddr, sizeof(tstrSockAddr));
|
|
|
|
strBind.strAddr.u16Family = strBind.strAddr.u16Family;
|
|
strBind.strAddr.u16Port = strBind.strAddr.u16Port;
|
|
strBind.strAddr.u32IPAddr = strBind.strAddr.u32IPAddr;
|
|
strBind.u16SessionID = gastrSockets[sock].u16SessionID;
|
|
|
|
/* Send the request. */
|
|
s8Ret = SOCKET_REQUEST(SOCKET_CMD_BIND, (uint8_t*)&strBind, sizeof(tstrBindCmd), NULL, 0, 0);
|
|
if(s8Ret != SOCK_ERR_NO_ERROR)
|
|
{
|
|
s8Ret = SOCK_ERR_INVALID;
|
|
}
|
|
}
|
|
return s8Ret;
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
listen
|
|
|
|
Description
|
|
|
|
|
|
Return
|
|
*********************************************************************/
|
|
int8_t listen(SOCKET sock, uint8_t backlog)
|
|
{
|
|
int8_t s8Ret = SOCK_ERR_INVALID_ARG;
|
|
|
|
if((sock >= 0) && (sock < MAX_SOCKET) && (gastrSockets[sock].bIsUsed == 1))
|
|
{
|
|
tstrListenCmd strListen;
|
|
|
|
strListen.sock = sock;
|
|
strListen.u8BackLog = backlog;
|
|
strListen.u16SessionID = gastrSockets[sock].u16SessionID;
|
|
|
|
s8Ret = SOCKET_REQUEST(SOCKET_CMD_LISTEN, (uint8_t*)&strListen, sizeof(tstrListenCmd), NULL, 0, 0);
|
|
if(s8Ret != SOCK_ERR_NO_ERROR)
|
|
{
|
|
s8Ret = SOCK_ERR_INVALID;
|
|
}
|
|
}
|
|
return s8Ret;
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
accept
|
|
|
|
Description
|
|
|
|
Return
|
|
*********************************************************************/
|
|
int8_t accept(SOCKET sock, struct sockaddr *addr, uint8_t *addrlen)
|
|
{
|
|
int8_t s8Ret = SOCK_ERR_INVALID_ARG;
|
|
|
|
if((sock >= 0) && (sock < MAX_SOCKET) && (gastrSockets[sock].bIsUsed == 1))
|
|
{
|
|
s8Ret = SOCK_ERR_NO_ERROR;
|
|
}
|
|
return s8Ret;
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
connect
|
|
|
|
Description
|
|
Connect to a remote TCP Server.
|
|
|
|
Return
|
|
*********************************************************************/
|
|
int8_t connect(SOCKET sock, struct sockaddr *pstrAddr, uint8_t u8AddrLen)
|
|
{
|
|
int8_t s8Ret = SOCK_ERR_INVALID_ARG;
|
|
if((sock >= 0) && (sock < MAX_SOCKET) && (pstrAddr != NULL) && (gastrSockets[sock].bIsUsed == 1) && (u8AddrLen != 0))
|
|
{
|
|
tstrConnectCmd strConnect;
|
|
uint8_t u8Cmd = SOCKET_CMD_CONNECT;
|
|
if((gastrSockets[sock].u8SSLFlags) & SSL_FLAGS_ACTIVE)
|
|
{
|
|
u8Cmd = SOCKET_CMD_SSL_CONNECT;
|
|
strConnect.u8SslFlags = gastrSockets[sock].u8SSLFlags;
|
|
}
|
|
strConnect.sock = sock;
|
|
memcpy((uint8_t *)&strConnect.strAddr, (uint8_t *)pstrAddr, sizeof(tstrSockAddr));
|
|
|
|
strConnect.u16SessionID = gastrSockets[sock].u16SessionID;
|
|
s8Ret = SOCKET_REQUEST(u8Cmd, (uint8_t*)&strConnect, sizeof(tstrConnectCmd), NULL, 0, 0);
|
|
if(s8Ret != SOCK_ERR_NO_ERROR)
|
|
{
|
|
s8Ret = SOCK_ERR_INVALID;
|
|
}
|
|
}
|
|
return s8Ret;
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
secure
|
|
|
|
Description
|
|
Make secure (TLS) an open TCP client connection.
|
|
|
|
Return
|
|
*********************************************************************/
|
|
int8_t secure(SOCKET sock)
|
|
{
|
|
int8_t s8Ret = SOCK_ERR_INVALID_ARG;
|
|
if((sock >= 0) && (sock < MAX_SOCKET) && (gastrSockets[sock].bIsUsed == 1))
|
|
{
|
|
if(
|
|
(gastrSockets[sock].u8SSLFlags & SSL_FLAGS_ACTIVE)
|
|
&& (gastrSockets[sock].u8SSLFlags & SSL_FLAGS_DELAY)
|
|
&& (gastrSockets[sock].u16DataOffset != 0)
|
|
)
|
|
{
|
|
tstrConnectCmd strConnect = {0};
|
|
|
|
gastrSockets[sock].u8SSLFlags &= ~SSL_FLAGS_DELAY;
|
|
strConnect.u8SslFlags = gastrSockets[sock].u8SSLFlags;
|
|
strConnect.sock = sock;
|
|
strConnect.u16SessionID = gastrSockets[sock].u16SessionID;
|
|
|
|
s8Ret = SOCKET_REQUEST(SOCKET_CMD_SECURE, (uint8_t*)&strConnect, sizeof(tstrConnectCmd), NULL, 0, 0);
|
|
if(s8Ret != SOCK_ERR_NO_ERROR)
|
|
{
|
|
s8Ret = SOCK_ERR_INVALID;
|
|
}
|
|
}
|
|
}
|
|
return s8Ret;
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
send
|
|
|
|
Description
|
|
|
|
Return
|
|
*********************************************************************/
|
|
int16_t send(SOCKET sock, void *pvSendBuffer, uint16_t u16SendLength, uint16_t flags)
|
|
{
|
|
int16_t s16Ret = SOCK_ERR_INVALID_ARG;
|
|
|
|
if((sock >= 0) && (sock < MAX_SOCKET) && (pvSendBuffer != NULL) && (u16SendLength <= SOCKET_BUFFER_MAX_LENGTH) && (gastrSockets[sock].bIsUsed == 1))
|
|
{
|
|
uint16_t u16DataOffset;
|
|
tstrSendCmd strSend;
|
|
uint8_t u8Cmd;
|
|
|
|
u8Cmd = SOCKET_CMD_SEND;
|
|
u16DataOffset = TCP_TX_PACKET_OFFSET;
|
|
|
|
strSend.sock = sock;
|
|
strSend.u16DataSize = NM_BSP_B_L_16(u16SendLength);
|
|
strSend.u16SessionID = gastrSockets[sock].u16SessionID;
|
|
|
|
if(sock >= TCP_SOCK_MAX)
|
|
{
|
|
u16DataOffset = UDP_TX_PACKET_OFFSET;
|
|
}
|
|
if(
|
|
(gastrSockets[sock].u8SSLFlags & SSL_FLAGS_ACTIVE)
|
|
&& (!(gastrSockets[sock].u8SSLFlags & SSL_FLAGS_DELAY))
|
|
)
|
|
{
|
|
u8Cmd = SOCKET_CMD_SSL_SEND;
|
|
u16DataOffset = gastrSockets[sock].u16DataOffset;
|
|
}
|
|
|
|
s16Ret = SOCKET_REQUEST(u8Cmd|M2M_REQ_DATA_PKT, (uint8_t*)&strSend, sizeof(tstrSendCmd), pvSendBuffer, u16SendLength, u16DataOffset);
|
|
if(s16Ret != SOCK_ERR_NO_ERROR)
|
|
{
|
|
s16Ret = SOCK_ERR_BUFFER_FULL;
|
|
}
|
|
}
|
|
return s16Ret;
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
sendto
|
|
|
|
Description
|
|
|
|
Return
|
|
*********************************************************************/
|
|
int16_t sendto(SOCKET sock, void *pvSendBuffer, uint16_t u16SendLength, uint16_t flags, struct sockaddr *pstrDestAddr, uint8_t u8AddrLen)
|
|
{
|
|
int16_t s16Ret = SOCK_ERR_INVALID_ARG;
|
|
uint16_t u16MaxLength = (sock == RAW_SOCK_ID) ? (M2M_HIF_MAX_PACKET_SIZE - M2M_HIF_HDR_OFFSET - sizeof(tstrSendCmd)) : SOCKET_BUFFER_MAX_LENGTH;
|
|
|
|
if((sock >= 0) && (sock < MAX_SOCKET) && (pvSendBuffer != NULL) && (u16SendLength <= u16MaxLength) && (gastrSockets[sock].bIsUsed == 1))
|
|
{
|
|
tstrSendCmd strSendTo;
|
|
|
|
memset((uint8_t*)&strSendTo, 0, sizeof(tstrSendCmd));
|
|
|
|
strSendTo.sock = sock;
|
|
strSendTo.u16DataSize = NM_BSP_B_L_16(u16SendLength);
|
|
strSendTo.u16SessionID = gastrSockets[sock].u16SessionID;
|
|
|
|
if(pstrDestAddr != NULL)
|
|
{
|
|
struct sockaddr_in *pstrAddr;
|
|
pstrAddr = (void*)pstrDestAddr;
|
|
|
|
strSendTo.strAddr.u16Family = pstrAddr->sin_family;
|
|
strSendTo.strAddr.u16Port = pstrAddr->sin_port;
|
|
strSendTo.strAddr.u32IPAddr = pstrAddr->sin_addr.s_addr;
|
|
}
|
|
s16Ret = SOCKET_REQUEST(SOCKET_CMD_SENDTO|M2M_REQ_DATA_PKT, (uint8_t*)&strSendTo, sizeof(tstrSendCmd),
|
|
pvSendBuffer, u16SendLength, (sock == RAW_SOCK_ID) ? IP_PACKET_OFFSET: UDP_TX_PACKET_OFFSET);
|
|
|
|
if(s16Ret != SOCK_ERR_NO_ERROR)
|
|
{
|
|
s16Ret = SOCK_ERR_BUFFER_FULL;
|
|
}
|
|
}
|
|
return s16Ret;
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
recv
|
|
|
|
Description
|
|
|
|
Return
|
|
|
|
*********************************************************************/
|
|
int16_t recv(SOCKET sock, void *pvRecvBuf, uint16_t u16BufLen, uint32_t u32Timeoutmsec)
|
|
{
|
|
int16_t s16Ret = SOCK_ERR_INVALID_ARG;
|
|
|
|
if((sock >= 0) && (sock < MAX_SOCKET) && (pvRecvBuf != NULL) && (u16BufLen != 0) && (gastrSockets[sock].bIsUsed == 1))
|
|
{
|
|
s16Ret = SOCK_ERR_NO_ERROR;
|
|
gastrSockets[sock].pu8UserBuffer = (uint8_t*)pvRecvBuf;
|
|
gastrSockets[sock].u16UserBufferSize = u16BufLen;
|
|
|
|
if(!gastrSockets[sock].bIsRecvPending)
|
|
{
|
|
tstrRecvCmd strRecv;
|
|
uint8_t u8Cmd = SOCKET_CMD_RECV;
|
|
|
|
gastrSockets[sock].bIsRecvPending = 1;
|
|
if(
|
|
(gastrSockets[sock].u8SSLFlags & SSL_FLAGS_ACTIVE)
|
|
&& (!(gastrSockets[sock].u8SSLFlags & SSL_FLAGS_DELAY))
|
|
)
|
|
{
|
|
u8Cmd = SOCKET_CMD_SSL_RECV;
|
|
}
|
|
|
|
/* Check the timeout value. */
|
|
if(u32Timeoutmsec == 0)
|
|
strRecv.u32Timeoutmsec = 0xFFFFFFFF;
|
|
else
|
|
strRecv.u32Timeoutmsec = NM_BSP_B_L_32(u32Timeoutmsec);
|
|
strRecv.sock = sock;
|
|
strRecv.u16SessionID = gastrSockets[sock].u16SessionID;
|
|
strRecv.u16BufLen = u16BufLen;
|
|
|
|
s16Ret = SOCKET_REQUEST(u8Cmd, (uint8_t*)&strRecv, sizeof(tstrRecvCmd), NULL, 0, 0);
|
|
if(s16Ret != SOCK_ERR_NO_ERROR)
|
|
{
|
|
s16Ret = SOCK_ERR_BUFFER_FULL;
|
|
}
|
|
}
|
|
}
|
|
return s16Ret;
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
shutdown
|
|
|
|
Description
|
|
|
|
Return
|
|
None.
|
|
*********************************************************************/
|
|
int8_t shutdown(SOCKET sock)
|
|
{
|
|
int8_t s8Ret = SOCK_ERR_INVALID_ARG;
|
|
|
|
M2M_INFO("Sock to delete <%d> (used %u)\r\n", sock, gastrSockets[sock].bIsUsed);
|
|
|
|
if((sock >= 0) && (sock < MAX_SOCKET) && (gastrSockets[sock].bIsUsed == 1))
|
|
{
|
|
uint8_t u8Cmd = SOCKET_CMD_CLOSE;
|
|
tstrCloseCmd strclose;
|
|
strclose.sock = sock;
|
|
strclose.u16SessionID = gastrSockets[sock].u16SessionID;
|
|
|
|
if(gastrSockets[sock].u8SSLFlags & SSL_FLAGS_ACTIVE)
|
|
{
|
|
u8Cmd = SOCKET_CMD_SSL_CLOSE;
|
|
}
|
|
s8Ret = SOCKET_REQUEST(u8Cmd, (uint8_t*)&strclose, sizeof(tstrCloseCmd), NULL, 0, 0);
|
|
if(s8Ret != SOCK_ERR_NO_ERROR)
|
|
{
|
|
s8Ret = SOCK_ERR_INVALID;
|
|
}
|
|
memset((uint8_t*)&gastrSockets[sock], 0, sizeof(tstrSocket));
|
|
}
|
|
return s8Ret;
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
recvfrom
|
|
|
|
Description
|
|
|
|
Return
|
|
|
|
*********************************************************************/
|
|
int16_t recvfrom(SOCKET sock, void *pvRecvBuf, uint16_t u16BufLen, uint32_t u32Timeoutmsec)
|
|
{
|
|
int16_t s16Ret = SOCK_ERR_NO_ERROR;
|
|
if((sock >= 0) && (sock < MAX_SOCKET) && (pvRecvBuf != NULL) && (u16BufLen != 0) && (gastrSockets[sock].bIsUsed == 1))
|
|
{
|
|
if(gastrSockets[sock].bIsUsed)
|
|
{
|
|
s16Ret = SOCK_ERR_NO_ERROR;
|
|
gastrSockets[sock].pu8UserBuffer = (uint8_t*)pvRecvBuf;
|
|
gastrSockets[sock].u16UserBufferSize = u16BufLen;
|
|
|
|
if(!gastrSockets[sock].bIsRecvPending)
|
|
{
|
|
tstrRecvCmd strRecv;
|
|
|
|
gastrSockets[sock].bIsRecvPending = 1;
|
|
|
|
/* Check the timeout value. */
|
|
if(u32Timeoutmsec == 0)
|
|
strRecv.u32Timeoutmsec = 0xFFFFFFFF;
|
|
else
|
|
strRecv.u32Timeoutmsec = NM_BSP_B_L_32(u32Timeoutmsec);
|
|
strRecv.sock = sock;
|
|
strRecv.u16SessionID = gastrSockets[sock].u16SessionID;
|
|
strRecv.u16BufLen = u16BufLen;
|
|
|
|
s16Ret = SOCKET_REQUEST(SOCKET_CMD_RECVFROM, (uint8_t*)&strRecv, sizeof(tstrRecvCmd), NULL, 0, 0);
|
|
if(s16Ret != SOCK_ERR_NO_ERROR)
|
|
{
|
|
s16Ret = SOCK_ERR_BUFFER_FULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
s16Ret = SOCK_ERR_INVALID_ARG;
|
|
}
|
|
return s16Ret;
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
gethostbyname
|
|
|
|
Description
|
|
|
|
Return
|
|
None.
|
|
*********************************************************************/
|
|
int8_t gethostbyname(const char *pcHostName)
|
|
{
|
|
int8_t s8Err = SOCK_ERR_INVALID_ARG;
|
|
uint8_t u8HostNameSize = (uint8_t)strlen(pcHostName);
|
|
if(u8HostNameSize <= HOSTNAME_MAX_SIZE)
|
|
{
|
|
s8Err = SOCKET_REQUEST(SOCKET_CMD_DNS_RESOLVE|M2M_REQ_DATA_PKT, (uint8_t*)pcHostName, u8HostNameSize + 1, NULL, 0, 0);
|
|
if(s8Err != SOCK_ERR_NO_ERROR)
|
|
{
|
|
s8Err = SOCK_ERR_INVALID;
|
|
}
|
|
}
|
|
return s8Err;
|
|
}
|
|
|
|
/*********************************************************************
|
|
Function
|
|
rawSetSockOpt
|
|
|
|
Description
|
|
|
|
Return
|
|
None.
|
|
*********************************************************************/
|
|
static int8_t rawSetSockOpt(SOCKET sock, uint8_t u8Opt, const void *pvOptVal, uint16_t u16OptLen)
|
|
{
|
|
int8_t s8Ret = SOCK_ERR_INVALID_ARG;
|
|
if(RAW_SOCK_ID == sock)
|
|
{
|
|
if(u16OptLen == sizeof(uint32_t))
|
|
{
|
|
uint8_t u8Cmd = SOCKET_CMD_RAW_SET_SOCK_OPT;
|
|
tstrSetSocketOptCmd strSetSockOpt;
|
|
strSetSockOpt.u8Option = u8Opt;
|
|
strSetSockOpt.sock = sock;
|
|
strSetSockOpt.u32OptionValue = *(uint32_t*)pvOptVal;
|
|
strSetSockOpt.u16SessionID = gastrSockets[sock].u16SessionID;
|
|
|
|
s8Ret = SOCKET_REQUEST(u8Cmd, (uint8_t*)&strSetSockOpt, sizeof(tstrSetSocketOptCmd), NULL, 0, 0);
|
|
if(s8Ret != SOCK_ERR_NO_ERROR)
|
|
{
|
|
s8Ret = SOCK_ERR_INVALID;
|
|
}
|
|
}
|
|
}
|
|
|
|
return s8Ret;
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
sslSetSockOpt
|
|
|
|
Description
|
|
|
|
Return
|
|
None.
|
|
*********************************************************************/
|
|
static int8_t sslSetSockOpt(SOCKET sock, uint8_t u8Opt, const void *pvOptVal, uint16_t u16OptLen)
|
|
{
|
|
int8_t s8Ret = SOCK_ERR_INVALID_ARG;
|
|
if(sock < TCP_SOCK_MAX)
|
|
{
|
|
if(gastrSockets[sock].u8SSLFlags & SSL_FLAGS_ACTIVE)
|
|
{
|
|
uint8_t sslFlag = 0;
|
|
|
|
s8Ret = SOCK_ERR_NO_ERROR;
|
|
if(u16OptLen == sizeof(int))
|
|
{
|
|
if(u8Opt == SO_SSL_BYPASS_X509_VERIF)
|
|
{
|
|
sslFlag = SSL_FLAGS_BYPASS_X509;
|
|
}
|
|
else if(u8Opt == SO_SSL_ENABLE_SESSION_CACHING)
|
|
{
|
|
sslFlag = SSL_FLAGS_CACHE_SESSION;
|
|
}
|
|
else if(u8Opt == SO_SSL_ENABLE_CERTNAME_VALIDATION)
|
|
{
|
|
sslFlag = SSL_FLAGS_CHECK_CERTNAME;
|
|
}
|
|
}
|
|
if(sslFlag)
|
|
{
|
|
int optVal = *((int*)pvOptVal);
|
|
if(optVal)
|
|
{
|
|
gastrSockets[sock].u8SSLFlags |= sslFlag;
|
|
}
|
|
else
|
|
{
|
|
gastrSockets[sock].u8SSLFlags &= ~sslFlag;
|
|
}
|
|
}
|
|
else if(
|
|
((u8Opt == SO_SSL_SNI) && (u16OptLen < HOSTNAME_MAX_SIZE))
|
|
|| ((u8Opt == SO_SSL_ALPN) && (u16OptLen <= ALPN_LIST_MAX_SIZE))
|
|
)
|
|
{
|
|
tstrSSLSetSockOptCmd strCmd = {0};
|
|
|
|
strCmd.sock = sock;
|
|
strCmd.u16SessionID = gastrSockets[sock].u16SessionID;
|
|
strCmd.u8Option = u8Opt;
|
|
strCmd.u32OptLen = u16OptLen;
|
|
memcpy(strCmd.au8OptVal, (uint8_t*)pvOptVal, u16OptLen);
|
|
|
|
s8Ret = SOCKET_REQUEST(SOCKET_CMD_SSL_SET_SOCK_OPT, (uint8_t*)&strCmd, sizeof(tstrSSLSetSockOptCmd), 0, 0, 0);
|
|
if(s8Ret == M2M_ERR_MEM_ALLOC)
|
|
{
|
|
s8Ret = SOCKET_REQUEST(SOCKET_CMD_SSL_SET_SOCK_OPT | M2M_REQ_DATA_PKT,
|
|
(uint8_t*)&strCmd, sizeof(tstrSSLSetSockOptCmd), 0, 0, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
M2M_ERR("Unknown SSL Socket Option %d\r\n",u8Opt);
|
|
s8Ret = SOCK_ERR_INVALID_ARG;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
M2M_ERR("Not SSL Socket\r\n");
|
|
}
|
|
}
|
|
return s8Ret;
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
setsockopt
|
|
|
|
Description
|
|
|
|
Return
|
|
None.
|
|
*********************************************************************/
|
|
int8_t setsockopt(SOCKET sock, uint8_t u8Level, uint8_t option_name,
|
|
const void *option_value, uint16_t u16OptionLen)
|
|
{
|
|
int8_t s8Ret = SOCK_ERR_INVALID_ARG;
|
|
if((sock >= 0) && (sock < MAX_SOCKET) && (option_value != NULL) && (gastrSockets[sock].bIsUsed == 1))
|
|
{
|
|
if(u8Level == SOL_RAW)
|
|
{
|
|
s8Ret = rawSetSockOpt(sock, option_name, option_value, u16OptionLen);
|
|
}
|
|
else if(u8Level == SOL_SSL_SOCKET)
|
|
{
|
|
s8Ret = sslSetSockOpt(sock, option_name, option_value, u16OptionLen);
|
|
}
|
|
else if(u8Level == SOL_SOCKET)
|
|
{
|
|
if(u16OptionLen == sizeof(uint32_t))
|
|
{
|
|
uint8_t u8Cmd = SOCKET_CMD_SET_SOCKET_OPTION;
|
|
tstrSetSocketOptCmd strSetSockOpt;
|
|
strSetSockOpt.u8Option=option_name;
|
|
strSetSockOpt.sock = sock;
|
|
strSetSockOpt.u32OptionValue = *(uint32_t*)option_value;
|
|
strSetSockOpt.u16SessionID = gastrSockets[sock].u16SessionID;
|
|
|
|
s8Ret = SOCKET_REQUEST(u8Cmd, (uint8_t*)&strSetSockOpt, sizeof(tstrSetSocketOptCmd), NULL, 0, 0);
|
|
if(s8Ret != SOCK_ERR_NO_ERROR)
|
|
{
|
|
s8Ret = SOCK_ERR_INVALID;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return s8Ret;
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
getsockopt
|
|
|
|
Description
|
|
|
|
Return
|
|
None.
|
|
*********************************************************************/
|
|
int8_t getsockopt(SOCKET sock, uint8_t u8Level, uint8_t u8OptName, const void *pvOptValue, uint8_t* pu8OptLen)
|
|
{
|
|
// This is not implemented so return a value that will cause failure should this be used.
|
|
return SOCK_ERR_INVALID_ARG;
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
m2m_ping_req
|
|
|
|
Description
|
|
Send Ping request.
|
|
|
|
Return
|
|
*********************************************************************/
|
|
int8_t m2m_ping_req(uint32_t u32DstIP, uint8_t u8TTL, tpfPingCb fpPingCb)
|
|
{
|
|
int8_t s8Ret = M2M_ERR_INVALID_ARG;
|
|
|
|
if((u32DstIP != 0) && (fpPingCb != NULL))
|
|
{
|
|
tstrPingCmd strPingCmd;
|
|
|
|
strPingCmd.u16PingCount = 1;
|
|
strPingCmd.u32DestIPAddr = u32DstIP;
|
|
strPingCmd.u32CmdPrivate = ++gu32PingId;
|
|
strPingCmd.u8TTL = u8TTL;
|
|
|
|
gfpPingCb = fpPingCb;
|
|
s8Ret = SOCKET_REQUEST(SOCKET_CMD_PING, (uint8_t*)&strPingCmd, sizeof(tstrPingCmd), NULL, 0, 0);
|
|
}
|
|
return s8Ret;
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
set_alpn_protocol_list
|
|
|
|
Description
|
|
This function sets the protocol list used for application-layer protocol negotiation (ALPN).
|
|
If used, it must be called after creating a SSL socket (using @ref socket) and before
|
|
connecting/binding (using @ref connect or @ref bind).
|
|
|
|
Return
|
|
The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise.
|
|
*********************************************************************/
|
|
int8_t set_alpn_list(SOCKET sock, const char *pcProtocolList)
|
|
{
|
|
int8_t s8Ret = SOCK_ERR_INVALID_ARG;
|
|
|
|
if ((sock >= 0) && (sock < TCP_SOCK_MAX) && (pcProtocolList != NULL))
|
|
{
|
|
uint8_t u8Length = strlen(pcProtocolList);
|
|
if ((u8Length > 0) && (u8Length < ALPN_LIST_MAX_APP_LENGTH))
|
|
{
|
|
/*
|
|
ALPN socket option requires Alpn list in this format:
|
|
0 1 2 3 ... (bytes)
|
|
+-------+-------+-------+ ... +-------+ ... +-------+ ...
|
|
| Length L (BE) | len1 | name1... | len2 | name2... | len3 | name3...
|
|
+-------+-------+-------+ ... +-------+ ... +-------+ ...
|
|
Length fields do not include themselves.
|
|
*/
|
|
uint8_t au8AlpnList[ALPN_LIST_MAX_SIZE] = {0};
|
|
uint8_t *pu8Ptr = &au8AlpnList[3] + u8Length;
|
|
uint8_t u8Len = 0;
|
|
|
|
memcpy(&au8AlpnList[3], pcProtocolList, u8Length);
|
|
u8Length++;
|
|
au8AlpnList[1] = u8Length;
|
|
au8AlpnList[2] = ' ';
|
|
|
|
/* Convert space characters into length fields. */
|
|
while (u8Length--)
|
|
{
|
|
if (*--pu8Ptr == ' ')
|
|
{
|
|
if (u8Len == 0) goto ERR;
|
|
*pu8Ptr = u8Len;
|
|
u8Len = 0;
|
|
}
|
|
else u8Len++;
|
|
}
|
|
s8Ret = setsockopt(sock, SOL_SSL_SOCKET, SO_SSL_ALPN, au8AlpnList, sizeof(au8AlpnList));
|
|
}
|
|
}
|
|
ERR:
|
|
return s8Ret;
|
|
}
|
|
/*********************************************************************
|
|
Function
|
|
get_alpn_protocol_index
|
|
|
|
Description
|
|
This function gets the protocol list used for application-layer protocol negotiation (ALPN).
|
|
If used, it must be called after creating a SSL socket (using @ref socket) and before
|
|
connecting/binding (using @ref connect or @ref bind).
|
|
|
|
Return
|
|
The function returns the index of the selected application-layer protocol.
|
|
Special values:
|
|
0: no negotiation has occurred.
|
|
<0: error.
|
|
*********************************************************************/
|
|
int8_t get_alpn_index(SOCKET sock)
|
|
{
|
|
if (sock >= TCP_SOCK_MAX || sock < 0)
|
|
return SOCK_ERR_INVALID_ARG;
|
|
if (!(gastrSockets[sock].u8SSLFlags & SSL_FLAGS_ACTIVE) || !gastrSockets[sock].bIsUsed)
|
|
return SOCK_ERR_INVALID_ARG;
|
|
return gastrSockets[sock].u8AlpnStatus;
|
|
}
|
|
|
|
/*********************************************************************
|
|
Function
|
|
IsSocketReady
|
|
|
|
Description
|
|
|
|
Return
|
|
None.
|
|
*********************************************************************/
|
|
uint8_t IsSocketReady(void)
|
|
{
|
|
return gbSocketInit;
|
|
}
|
|
|
|
/*********************************************************************
|
|
Function
|
|
get_error_detail
|
|
|
|
Description
|
|
This function gets detail about a socket failure.
|
|
The application can call this when notified of a socket failure via
|
|
@ref SOCKET_MSG_CONNECT or @ref SOCKET_MSG_RECV.
|
|
If used, it must be called before @ref shutdown.
|
|
|
|
Return
|
|
The function returns @ref SOCK_ERR_NO_ERROR if the request is successful
|
|
and a negative value otherwise.
|
|
*********************************************************************/
|
|
int8_t get_error_detail(SOCKET sock, tstrSockErr *pstrErr)
|
|
{
|
|
if ((sock >= TCP_SOCK_MAX) || (sock < 0) || (pstrErr == NULL))
|
|
return SOCK_ERR_INVALID_ARG;
|
|
if (!gastrSockets[sock].bIsUsed)
|
|
return SOCK_ERR_INVALID_ARG;
|
|
pstrErr->enuErrSource = gastrSockets[sock].u8ErrSource;
|
|
pstrErr->u8ErrCode = gastrSockets[sock].u8ErrCode;
|
|
return SOCK_ERR_NO_ERROR;
|
|
}
|