micropython/drivers/cc3100/src/socket.c

1124 wiersze
33 KiB
C

/*
* socket.c - CC31xx/CC32xx Host Driver Implementation
*
* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*****************************************************************************/
/* Include files */
/*****************************************************************************/
#include "simplelink.h"
#include "protocol.h"
#include "driver.h"
/*******************************************************************************/
/* Functions prototypes */
/*******************************************************************************/
void _sl_BuildAddress(const SlSockAddr_t *addr, _i16 addrlen, _SocketAddrCommand_u *pCmd);
void _sl_ParseAddress(_SocketAddrResponse_u *pRsp, SlSockAddr_t *addr, SlSocklen_t *addrlen);
void _sl_HandleAsync_Connect(void *pVoidBuf);
void _sl_HandleAsync_Accept(void *pVoidBuf);
void _sl_HandleAsync_Select(void *pVoidBuf);
_u16 _sl_TruncatePayloadByProtocol(const _i16 pSd,const _u16 length);
/*******************************************************************************/
/* Functions */
/*******************************************************************************/
/* ******************************************************************************/
/* _sl_BuildAddress */
/* ******************************************************************************/
void _sl_BuildAddress(const SlSockAddr_t *addr, _i16 addrlen, _SocketAddrCommand_u *pCmd)
{
/* Note: parsing of family and port in the generic way for all IPV4, IPV6 and EUI48 */
/* is possible as _i32 as these parameters are in the same offset and size for these */
/* three families. */
pCmd->IpV4.FamilyAndFlags = (addr->sa_family << 4) & 0xF0;
pCmd->IpV4.port = ((SlSockAddrIn_t *)addr)->sin_port;
if(SL_AF_INET == addr->sa_family)
{
pCmd->IpV4.address = ((SlSockAddrIn_t *)addr)->sin_addr.s_addr;
}
else if (SL_AF_INET6_EUI_48 == addr->sa_family )
{
sl_Memcpy( pCmd->IpV6EUI48.address,((SlSockAddrIn6_t *)addr)->sin6_addr._S6_un._S6_u8, 6);
}
#ifdef SL_SUPPORT_IPV6
else
{
sl_Memcpy(pCmd->IpV6.address, ((sockaddr_in6 *)addr)->sin6_addr._S6_un._S6_u32, 16 );
}
#endif
}
/* ******************************************************************************/
/* _sl_TruncatePayloadByProtocol */
/* ******************************************************************************/
_u16 _sl_TruncatePayloadByProtocol(const _i16 sd,const _u16 length)
{
_u16 maxLength;
switch(sd & SL_SOCKET_PAYLOAD_TYPE_MASK)
{
case SL_SOCKET_PAYLOAD_TYPE_UDP_IPV4:
maxLength = 1472;
break;
case SL_SOCKET_PAYLOAD_TYPE_TCP_IPV4:
maxLength = 1460;
break;
case SL_SOCKET_PAYLOAD_TYPE_UDP_IPV6:
maxLength = 1452;
break;
case SL_SOCKET_PAYLOAD_TYPE_TCP_IPV6:
maxLength = 1440;
break;
case SL_SOCKET_PAYLOAD_TYPE_TCP_IPV4_SECURE:
case SL_SOCKET_PAYLOAD_TYPE_UDP_IPV4_SECURE:
maxLength = 1402;
break;
case SL_SOCKET_PAYLOAD_TYPE_UDP_IPV6_SECURE:
case SL_SOCKET_PAYLOAD_TYPE_TCP_IPV6_SECURE:
maxLength = 1396;
break;
case SL_SOCKET_PAYLOAD_TYPE_RAW_TRANCEIVER:
maxLength = 1476;
break;
case SL_SOCKET_PAYLOAD_TYPE_RAW_PACKET:
maxLength = 1514;
break;
case SL_SOCKET_PAYLOAD_TYPE_RAW_IP4:
maxLength = 1480;
break;
default:
maxLength = 1440;
break;
}
if( length > maxLength )
{
return maxLength;
}
else
{
return length;
}
}
/*******************************************************************************/
/* _sl_ParseAddress */
/*******************************************************************************/
void _sl_ParseAddress(_SocketAddrResponse_u *pRsp, SlSockAddr_t *addr, SlSocklen_t *addrlen)
{
/* Note: parsing of family and port in the generic way for all IPV4, IPV6 and EUI48 */
/* is possible as long as these parameters are in the same offset and size for these */
/* three families. */
addr->sa_family = pRsp->IpV4.family;
((SlSockAddrIn_t *)addr)->sin_port = pRsp->IpV4.port;
*addrlen = (SL_AF_INET == addr->sa_family) ? sizeof(SlSockAddrIn_t) : sizeof(SlSockAddrIn6_t);
if(SL_AF_INET == addr->sa_family)
{
((SlSockAddrIn_t *)addr)->sin_addr.s_addr = pRsp->IpV4.address;
}
else if (SL_AF_INET6_EUI_48 == addr->sa_family )
{
sl_Memcpy(((SlSockAddrIn6_t *)addr)->sin6_addr._S6_un._S6_u8, pRsp->IpV6EUI48.address, 6);
}
#ifdef SL_SUPPORT_IPV6
else
{
sl_Memcpy(((sockaddr_in6 *)addr)->sin6_addr._S6_un._S6_u32, pRsp->IpV6.address, 16);
}
#endif
}
/*******************************************************************************/
/* sl_Socket */
/*******************************************************************************/
typedef union
{
_u32 Dummy;
_SocketCommand_t Cmd;
_SocketResponse_t Rsp;
}_SlSockSocketMsg_u;
const _SlCmdCtrl_t _SlSockSocketCmdCtrl =
{
SL_OPCODE_SOCKET_SOCKET,
sizeof(_SocketCommand_t),
sizeof(_SocketResponse_t)
};
#if _SL_INCLUDE_FUNC(sl_Socket)
_i16 sl_Socket(_i16 Domain, _i16 Type, _i16 Protocol)
{
_SlSockSocketMsg_u Msg;
Msg.Cmd.Domain = (_u8)Domain;
Msg.Cmd.Type = (_u8)Type;
Msg.Cmd.Protocol = (_u8)Protocol;
VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlSockSocketCmdCtrl, &Msg, NULL));
if( Msg.Rsp.statusOrLen < 0 )
{
return( Msg.Rsp.statusOrLen );
}
else
{
return (_i16)((_u8)Msg.Rsp.sd);
}
}
#endif
/*******************************************************************************/
/* sl_Close */
/*******************************************************************************/
typedef union
{
_CloseCommand_t Cmd;
_SocketResponse_t Rsp;
}_SlSockCloseMsg_u;
const _SlCmdCtrl_t _SlSockCloseCmdCtrl =
{
SL_OPCODE_SOCKET_CLOSE,
sizeof(_CloseCommand_t),
sizeof(_SocketResponse_t)
};
#if _SL_INCLUDE_FUNC(sl_Close)
_i16 sl_Close(_i16 sd)
{
_SlSockCloseMsg_u Msg;
Msg.Cmd.sd = (_u8)sd;
VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlSockCloseCmdCtrl, &Msg, NULL));
return Msg.Rsp.statusOrLen;
}
#endif
/*******************************************************************************/
/* sl_Bind */
/*******************************************************************************/
typedef union
{
_SocketAddrCommand_u Cmd;
_SocketResponse_t Rsp;
}_SlSockBindMsg_u;
#if _SL_INCLUDE_FUNC(sl_Bind)
_i16 sl_Bind(_i16 sd, const SlSockAddr_t *addr, _i16 addrlen)
{
_SlSockBindMsg_u Msg;
_SlCmdCtrl_t CmdCtrl = {0, 0, sizeof(_SocketResponse_t)};
switch(addr->sa_family)
{
case SL_AF_INET :
CmdCtrl.Opcode = SL_OPCODE_SOCKET_BIND;
CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv4Command_t);
break;
case SL_AF_INET6_EUI_48:
CmdCtrl.Opcode = SL_OPCODE_SOCKET_BIND_V6;
CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6EUI48Command_t);
break;
#ifdef SL_SUPPORT_IPV6
case AF_INET6:
CmdCtrl.Opcode = SL_OPCODE_SOCKET_BIND_V6;
CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6Command_t);
break;
#endif
case SL_AF_RF :
default:
return SL_RET_CODE_INVALID_INPUT;
}
Msg.Cmd.IpV4.lenOrPadding = 0;
Msg.Cmd.IpV4.sd = (_u8)sd;
_sl_BuildAddress(addr, addrlen, &Msg.Cmd);
VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&CmdCtrl, &Msg, NULL));
return Msg.Rsp.statusOrLen;
}
#endif
/*******************************************************************************/
/* sl_Sendto */
/*******************************************************************************/
typedef union
{
_SocketAddrCommand_u Cmd;
/* no response for 'sendto' commands*/
}_SlSendtoMsg_u;
#if _SL_INCLUDE_FUNC(sl_SendTo)
_i16 sl_SendTo(_i16 sd, const void *pBuf, _i16 Len, _i16 flags, const SlSockAddr_t *to, SlSocklen_t tolen)
{
_SlSendtoMsg_u Msg;
_SlCmdCtrl_t CmdCtrl = {0, 0, 0};
_SlCmdExt_t CmdExt;
_u16 ChunkLen;
_i16 RetVal;
CmdExt.TxPayloadLen = (_u16)Len;
CmdExt.RxPayloadLen = 0;
CmdExt.pTxPayload = (_u8 *)pBuf;
CmdExt.pRxPayload = NULL;
switch(to->sa_family)
{
case SL_AF_INET:
CmdCtrl.Opcode = SL_OPCODE_SOCKET_SENDTO;
CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv4Command_t);
break;
case SL_AF_INET6_EUI_48:
CmdCtrl.Opcode = SL_OPCODE_SOCKET_BIND_V6;
CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6EUI48Command_t);
break;
#ifdef SL_SUPPORT_IPV6
case AF_INET6:
CmdCtrl.Opcode = SL_OPCODE_SOCKET_SENDTO_V6;
CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6Command_t);
break;
#endif
case SL_AF_RF:
default:
return SL_RET_CODE_INVALID_INPUT;
}
ChunkLen = _sl_TruncatePayloadByProtocol(sd,Len);
Msg.Cmd.IpV4.lenOrPadding = ChunkLen;
CmdExt.TxPayloadLen = ChunkLen;
Msg.Cmd.IpV4.sd = (_u8)sd;
_sl_BuildAddress(to, tolen, &Msg.Cmd);
Msg.Cmd.IpV4.FamilyAndFlags |= flags & 0x0F;
do
{
RetVal = _SlDrvDataWriteOp((_SlSd_t)sd, &CmdCtrl, &Msg, &CmdExt);
if(SL_OS_RET_CODE_OK == RetVal)
{
CmdExt.pTxPayload += ChunkLen;
ChunkLen = (_u16)((_u8 *)pBuf + Len - CmdExt.pTxPayload);
ChunkLen = _sl_TruncatePayloadByProtocol(sd,ChunkLen);
CmdExt.TxPayloadLen = ChunkLen;
Msg.Cmd.IpV4.lenOrPadding = ChunkLen;
}
else
{
return RetVal;
}
}while(ChunkLen > 0);
return (_i16)Len;
}
#endif
/*******************************************************************************/
/* sl_Recvfrom */
/*******************************************************************************/
typedef union
{
_sendRecvCommand_t Cmd;
_SocketAddrResponse_u Rsp;
}_SlRecvfromMsg_u;
const _SlCmdCtrl_t _SlRecvfomCmdCtrl =
{
SL_OPCODE_SOCKET_RECVFROM,
sizeof(_sendRecvCommand_t),
sizeof(_SocketAddrResponse_u)
};
#if _SL_INCLUDE_FUNC(sl_RecvFrom)
_i16 sl_RecvFrom(_i16 sd, void *buf, _i16 Len, _i16 flags, SlSockAddr_t *from, SlSocklen_t *fromlen)
{
_SlRecvfromMsg_u Msg;
_SlCmdExt_t CmdExt;
_i16 RetVal;
CmdExt.TxPayloadLen = 0;
CmdExt.RxPayloadLen = Len;
CmdExt.pTxPayload = NULL;
CmdExt.pRxPayload = (_u8 *)buf;
Msg.Cmd.sd = (_u8)sd;
Msg.Cmd.StatusOrLen = Len;
/* no size truncation in recv path */
CmdExt.RxPayloadLen = Msg.Cmd.StatusOrLen;
if(sizeof(SlSockAddrIn_t) == *fromlen)
{
Msg.Cmd.FamilyAndFlags = SL_AF_INET;
}
else if (sizeof(SlSockAddrIn6_t) == *fromlen)
{
Msg.Cmd.FamilyAndFlags = SL_AF_INET6;
}
else
{
return SL_RET_CODE_INVALID_INPUT;
}
Msg.Cmd.FamilyAndFlags = (Msg.Cmd.FamilyAndFlags << 4) & 0xF0;
Msg.Cmd.FamilyAndFlags |= flags & 0x0F;
RetVal = _SlDrvDataReadOp((_SlSd_t)sd, (_SlCmdCtrl_t *)&_SlRecvfomCmdCtrl, &Msg, &CmdExt);
if( RetVal != SL_OS_RET_CODE_OK )
{
return RetVal;
}
RetVal = Msg.Rsp.IpV4.statusOrLen;
if(RetVal >= 0)
{
VERIFY_PROTOCOL(sd == Msg.Rsp.IpV4.sd);
#if 0
_sl_ParseAddress(&Msg.Rsp, from, fromlen);
#else
from->sa_family = Msg.Rsp.IpV4.family;
if(SL_AF_INET == from->sa_family)
{
((SlSockAddrIn_t *)from)->sin_port = Msg.Rsp.IpV4.port;
((SlSockAddrIn_t *)from)->sin_addr.s_addr = Msg.Rsp.IpV4.address;
*fromlen = sizeof(SlSockAddrIn_t);
}
else if (SL_AF_INET6_EUI_48 == from->sa_family )
{
((SlSockAddrIn6_t *)from)->sin6_port = Msg.Rsp.IpV6EUI48.port;
sl_Memcpy(((SlSockAddrIn6_t *)from)->sin6_addr._S6_un._S6_u8, Msg.Rsp.IpV6EUI48.address, 6);
}
#ifdef SL_SUPPORT_IPV6
else if(AF_INET6 == from->sa_family)
{
VERIFY_PROTOCOL(*fromlen >= sizeof(sockaddr_in6));
((sockaddr_in6 *)from)->sin6_port = Msg.Rsp.IpV6.port;
sl_Memcpy(((sockaddr_in6 *)from)->sin6_addr._S6_un._S6_u32, Msg.Rsp.IpV6.address, 16);
*fromlen = sizeof(sockaddr_in6);
}
#endif
#endif
}
return (_i16)RetVal;
}
#endif
/*******************************************************************************/
/* sl_Connect */
/*******************************************************************************/
typedef union
{
_SocketAddrCommand_u Cmd;
_SocketResponse_t Rsp;
}_SlSockConnectMsg_u;
#if _SL_INCLUDE_FUNC(sl_Connect)
_i16 sl_Connect(_i16 sd, const SlSockAddr_t *addr, _i16 addrlen)
{
_SlSockConnectMsg_u Msg;
_SlReturnVal_t RetVal;
_SlCmdCtrl_t CmdCtrl = {0, 0, sizeof(_SocketResponse_t)};
_SocketResponse_t AsyncRsp;
_u8 ObjIdx = MAX_CONCURRENT_ACTIONS;
switch(addr->sa_family)
{
case SL_AF_INET :
CmdCtrl.Opcode = SL_OPCODE_SOCKET_CONNECT;
CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv4Command_t);
break;
case SL_AF_INET6_EUI_48:
CmdCtrl.Opcode = SL_OPCODE_SOCKET_CONNECT_V6;
CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6EUI48Command_t);
break;
#ifdef SL_SUPPORT_IPV6
case AF_INET6:
CmdCtrl.Opcode = SL_OPCODE_SOCKET_CONNECT_V6;
CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6Command_t);
break;
#endif
case SL_AF_RF :
default:
return SL_RET_CODE_INVALID_INPUT;
}
Msg.Cmd.IpV4.lenOrPadding = 0;
Msg.Cmd.IpV4.sd = (_u8)sd;
_sl_BuildAddress(addr, addrlen, &Msg.Cmd);
/* Use Obj to issue the command, if not available try later */
ObjIdx = (_u8)_SlDrvWaitForPoolObj(CONNECT_ID, (_u8)(sd & BSD_SOCKET_ID_MASK));
if (MAX_CONCURRENT_ACTIONS == ObjIdx)
{
return SL_POOL_IS_EMPTY;
}
OSI_RET_OK_CHECK(sl_LockObjLock(&g_pCB->ProtectionLockObj, SL_OS_WAIT_FOREVER));
g_pCB->ObjPool[ObjIdx].pRespArgs = (_u8 *)&AsyncRsp;
OSI_RET_OK_CHECK(sl_LockObjUnlock(&g_pCB->ProtectionLockObj));
/* send the command */
VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&CmdCtrl, &Msg, NULL));
VERIFY_PROTOCOL(Msg.Rsp.sd == sd)
RetVal = Msg.Rsp.statusOrLen;
if(SL_RET_CODE_OK == RetVal)
{
/* wait for async and get Data Read parameters */
OSI_RET_OK_CHECK(sl_SyncObjWait(&g_pCB->ObjPool[ObjIdx].SyncObj, SL_OS_WAIT_FOREVER));
VERIFY_PROTOCOL(AsyncRsp.sd == sd);
RetVal = AsyncRsp.statusOrLen;
}
_SlDrvReleasePoolObj(ObjIdx);
return RetVal;
}
#endif
/*******************************************************************************/
/* _sl_HandleAsync_Connect */
/*******************************************************************************/
void _sl_HandleAsync_Connect(void *pVoidBuf)
{
_SocketResponse_t *pMsgArgs = (_SocketResponse_t *)_SL_RESP_ARGS_START(pVoidBuf);
OSI_RET_OK_CHECK(sl_LockObjLock(&g_pCB->ProtectionLockObj, SL_OS_WAIT_FOREVER));
VERIFY_PROTOCOL((pMsgArgs->sd & BSD_SOCKET_ID_MASK) <= SL_MAX_SOCKETS);
VERIFY_SOCKET_CB(NULL != g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs);
((_SocketResponse_t *)(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs))->sd = pMsgArgs->sd;
((_SocketResponse_t *)(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs))->statusOrLen = pMsgArgs->statusOrLen;
OSI_RET_OK_CHECK(sl_SyncObjSignal(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].SyncObj));
OSI_RET_OK_CHECK(sl_LockObjUnlock(&g_pCB->ProtectionLockObj));
return;
}
/*******************************************************************************/
/* sl_Send */
/*******************************************************************************/
typedef union
{
_sendRecvCommand_t Cmd;
/* no response for 'sendto' commands*/
}_SlSendMsg_u;
const _SlCmdCtrl_t _SlSendCmdCtrl =
{
SL_OPCODE_SOCKET_SEND,
sizeof(_sendRecvCommand_t),
0
};
#if _SL_INCLUDE_FUNC(sl_Send)
_i16 sl_Send(_i16 sd, const void *pBuf, _i16 Len, _i16 flags)
{
_SlSendMsg_u Msg;
_SlCmdExt_t CmdExt;
_u16 ChunkLen;
_i16 RetVal;
_u32 tempVal;
_u8 runSingleChunk = FALSE;
CmdExt.TxPayloadLen = Len;
CmdExt.RxPayloadLen = 0;
CmdExt.pTxPayload = (_u8 *)pBuf;
/* Only for RAW transceiver type socket, relay the flags parameter in the 2 bytes (4 byte aligned) before the actual payload */
if ((sd & SL_SOCKET_PAYLOAD_TYPE_MASK) == SL_SOCKET_PAYLOAD_TYPE_RAW_TRANCEIVER)
{
tempVal = flags;
CmdExt.pRxPayload = (_u8 *)&tempVal;
CmdExt.RxPayloadLen = 4;
g_pCB->RelayFlagsViaRxPayload = TRUE;
runSingleChunk = TRUE;
}
else
{
CmdExt.pRxPayload = NULL;
}
ChunkLen = _sl_TruncatePayloadByProtocol(sd,Len);
CmdExt.TxPayloadLen = ChunkLen;
Msg.Cmd.StatusOrLen = ChunkLen;
Msg.Cmd.sd = (_u8)sd;
Msg.Cmd.FamilyAndFlags |= flags & 0x0F;
do
{
RetVal = _SlDrvDataWriteOp((_u8)sd, (_SlCmdCtrl_t *)&_SlSendCmdCtrl, &Msg, &CmdExt);
if(SL_OS_RET_CODE_OK == RetVal)
{
CmdExt.pTxPayload += ChunkLen;
ChunkLen = (_u8 *)pBuf + Len - CmdExt.pTxPayload;
ChunkLen = _sl_TruncatePayloadByProtocol(sd,ChunkLen);
CmdExt.TxPayloadLen = ChunkLen;
Msg.Cmd.StatusOrLen = ChunkLen;
}
else
{
return RetVal;
}
}while((ChunkLen > 0) && (runSingleChunk==FALSE));
return (_i16)Len;
}
#endif
/*******************************************************************************/
/* sl_Listen */
/*******************************************************************************/
typedef union
{
_ListenCommand_t Cmd;
_BasicResponse_t Rsp;
}_SlListenMsg_u;
const _SlCmdCtrl_t _SlListenCmdCtrl =
{
SL_OPCODE_SOCKET_LISTEN,
sizeof(_ListenCommand_t),
sizeof(_BasicResponse_t),
};
#if _SL_INCLUDE_FUNC(sl_Listen)
_i16 sl_Listen(_i16 sd, _i16 backlog)
{
_SlListenMsg_u Msg;
Msg.Cmd.sd = (_u8)sd;
Msg.Cmd.backlog = (_u8)backlog;
VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlListenCmdCtrl, &Msg, NULL));
return (_i16)Msg.Rsp.status;
}
#endif
/*******************************************************************************/
/* sl_Accept */
/*******************************************************************************/
typedef union
{
_AcceptCommand_t Cmd;
_SocketResponse_t Rsp;
}_SlSockAcceptMsg_u;
const _SlCmdCtrl_t _SlAcceptCmdCtrl =
{
SL_OPCODE_SOCKET_ACCEPT,
sizeof(_AcceptCommand_t),
sizeof(_BasicResponse_t),
};
#if _SL_INCLUDE_FUNC(sl_Accept)
_i16 sl_Accept(_i16 sd, SlSockAddr_t *addr, SlSocklen_t *addrlen)
{
_SlSockAcceptMsg_u Msg;
_SlReturnVal_t RetVal;
_SocketAddrResponse_u AsyncRsp;
_u8 ObjIdx = MAX_CONCURRENT_ACTIONS;
Msg.Cmd.sd = (_u8)sd;
Msg.Cmd.family = (sizeof(SlSockAddrIn_t) == *addrlen) ? SL_AF_INET : SL_AF_INET6;
/* Use Obj to issue the command, if not available try later */
ObjIdx = (_u8)_SlDrvWaitForPoolObj(ACCEPT_ID, (_u8)(sd & BSD_SOCKET_ID_MASK));
if (MAX_CONCURRENT_ACTIONS == ObjIdx)
{
return SL_POOL_IS_EMPTY;
}
OSI_RET_OK_CHECK(sl_LockObjLock(&g_pCB->ProtectionLockObj, SL_OS_WAIT_FOREVER));
g_pCB->ObjPool[ObjIdx].pRespArgs = (_u8 *)&AsyncRsp;
OSI_RET_OK_CHECK(sl_LockObjUnlock(&g_pCB->ProtectionLockObj));
/* send the command */
VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlAcceptCmdCtrl, &Msg, NULL));
VERIFY_PROTOCOL(Msg.Rsp.sd == sd);
RetVal = Msg.Rsp.statusOrLen;
if(SL_OS_RET_CODE_OK == RetVal)
{
/* wait for async and get Data Read parameters */
OSI_RET_OK_CHECK(sl_SyncObjWait(&g_pCB->ObjPool[ObjIdx].SyncObj, SL_OS_WAIT_FOREVER));
VERIFY_PROTOCOL(AsyncRsp.IpV4.sd == sd);
RetVal = AsyncRsp.IpV4.statusOrLen;
if( (NULL != addr) && (NULL != addrlen) )
{
#if 0 /* Kept for backup */
_sl_ParseAddress(&AsyncRsp, addr, addrlen);
#else
addr->sa_family = AsyncRsp.IpV4.family;
if(SL_AF_INET == addr->sa_family)
{
if( *addrlen == sizeof( SlSockAddrIn_t ) )
{
((SlSockAddrIn_t *)addr)->sin_port = AsyncRsp.IpV4.port;
((SlSockAddrIn_t *)addr)->sin_addr.s_addr = AsyncRsp.IpV4.address;
}
else
{
*addrlen = 0;
}
}
else if (SL_AF_INET6_EUI_48 == addr->sa_family )
{
if( *addrlen == sizeof( SlSockAddrIn6_t ) )
{
((SlSockAddrIn6_t *)addr)->sin6_port = AsyncRsp.IpV6EUI48.port ;
/* will be called from here and from _sl_BuildAddress*/
sl_Memcpy(((SlSockAddrIn6_t *)addr)->sin6_addr._S6_un._S6_u8, AsyncRsp.IpV6EUI48.address, 6);
}
else
{
*addrlen = 0;
}
}
#ifdef SL_SUPPORT_IPV6
else
{
if( *addrlen == sizeof( sockaddr_in6 ) )
{
((sockaddr_in6 *)addr)->sin6_port = AsyncRsp.IpV6.port ;
sl_Memcpy(((sockaddr_in6 *)addr)->sin6_addr._S6_un._S6_u32, AsyncRsp.IpV6.address, 16);
}
else
{
*addrlen = 0;
}
}
#endif
#endif
}
}
_SlDrvReleasePoolObj(ObjIdx);
return (_i16)RetVal;
}
#endif
/*******************************************************************************/
/* sl_Htonl */
/*******************************************************************************/
_u32 sl_Htonl( _u32 val )
{
_u32 i = 1;
_i8 *p = (_i8 *)&i;
if (p[0] == 1) /* little endian */
{
p[0] = ((_i8* )&val)[3];
p[1] = ((_i8* )&val)[2];
p[2] = ((_i8* )&val)[1];
p[3] = ((_i8* )&val)[0];
return i;
}
else /* big endian */
{
return val;
}
}
/*******************************************************************************/
/* sl_Htonl */
/*******************************************************************************/
_u16 sl_Htons( _u16 val )
{
_i16 i = 1;
_i8 *p = (_i8 *)&i;
if (p[0] == 1) /* little endian */
{
p[0] = ((_i8* )&val)[1];
p[1] = ((_i8* )&val)[0];
return i;
}
else /* big endian */
{
return val;
}
}
/*******************************************************************************/
/* _sl_HandleAsync_Accept */
/*******************************************************************************/
void _sl_HandleAsync_Accept(void *pVoidBuf)
{
_SocketAddrResponse_u *pMsgArgs = (_SocketAddrResponse_u *)_SL_RESP_ARGS_START(pVoidBuf);
OSI_RET_OK_CHECK(sl_LockObjLock(&g_pCB->ProtectionLockObj, SL_OS_WAIT_FOREVER));
VERIFY_PROTOCOL(( pMsgArgs->IpV4.sd & BSD_SOCKET_ID_MASK) <= SL_MAX_SOCKETS);
VERIFY_SOCKET_CB(NULL != g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs);
sl_Memcpy(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs, pMsgArgs,sizeof(_SocketAddrResponse_u));
OSI_RET_OK_CHECK(sl_SyncObjSignal(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].SyncObj));
OSI_RET_OK_CHECK(sl_LockObjUnlock(&g_pCB->ProtectionLockObj));
return;
}
/*******************************************************************************/
/* sl_Recv */
/*******************************************************************************/
typedef union
{
_sendRecvCommand_t Cmd;
_SocketResponse_t Rsp;
}_SlRecvMsg_u;
const _SlCmdCtrl_t _SlRecvCmdCtrl =
{
SL_OPCODE_SOCKET_RECV,
sizeof(_sendRecvCommand_t),
sizeof(_SocketResponse_t)
};
#if _SL_INCLUDE_FUNC(sl_Recv)
_i16 sl_Recv(_i16 sd, void *pBuf, _i16 Len, _i16 flags)
{
_SlRecvMsg_u Msg;
_SlCmdExt_t CmdExt;
_SlReturnVal_t status;
CmdExt.TxPayloadLen = 0;
CmdExt.RxPayloadLen = Len;
CmdExt.pTxPayload = NULL;
CmdExt.pRxPayload = (_u8 *)pBuf;
Msg.Cmd.sd = (_u8)sd;
Msg.Cmd.StatusOrLen = Len;
/* no size truncation in recv path */
CmdExt.RxPayloadLen = Msg.Cmd.StatusOrLen;
Msg.Cmd.FamilyAndFlags = flags & 0x0F;
status = _SlDrvDataReadOp((_SlSd_t)sd, (_SlCmdCtrl_t *)&_SlRecvCmdCtrl, &Msg, &CmdExt);
if( status != SL_OS_RET_CODE_OK )
{
return status;
}
/* if the Device side sends less than expected it is not the Driver's role */
/* the returned value could be smaller than the requested size */
return (_i16)Msg.Rsp.statusOrLen;
}
#endif
/*******************************************************************************/
/* sl_SetSockOpt */
/*******************************************************************************/
typedef union
{
_setSockOptCommand_t Cmd;
_SocketResponse_t Rsp;
}_SlSetSockOptMsg_u;
const _SlCmdCtrl_t _SlSetSockOptCmdCtrl =
{
SL_OPCODE_SOCKET_SETSOCKOPT,
sizeof(_setSockOptCommand_t),
sizeof(_SocketResponse_t)
};
#if _SL_INCLUDE_FUNC(sl_SetSockOpt)
_i16 sl_SetSockOpt(_i16 sd, _i16 level, _i16 optname, const void *optval, SlSocklen_t optlen)
{
_SlSetSockOptMsg_u Msg;
_SlCmdExt_t CmdExt;
CmdExt.TxPayloadLen = optlen;
CmdExt.RxPayloadLen = 0;
CmdExt.pTxPayload = (_u8 *)optval;
CmdExt.pRxPayload = NULL;
Msg.Cmd.sd = (_u8)sd;
Msg.Cmd.level = (_u8)level;
Msg.Cmd.optionLen = (_u8)optlen;
Msg.Cmd.optionName = (_u8)optname;
VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlSetSockOptCmdCtrl, &Msg, &CmdExt));
return (_i16)Msg.Rsp.statusOrLen;
}
#endif
/*******************************************************************************/
/* sl_GetSockOpt */
/*******************************************************************************/
typedef union
{
_getSockOptCommand_t Cmd;
_getSockOptResponse_t Rsp;
}_SlGetSockOptMsg_u;
const _SlCmdCtrl_t _SlGetSockOptCmdCtrl =
{
SL_OPCODE_SOCKET_GETSOCKOPT,
sizeof(_getSockOptCommand_t),
sizeof(_getSockOptResponse_t)
};
#if _SL_INCLUDE_FUNC(sl_GetSockOpt)
_i16 sl_GetSockOpt(_i16 sd, _i16 level, _i16 optname, void *optval, SlSocklen_t *optlen)
{
_SlGetSockOptMsg_u Msg;
_SlCmdExt_t CmdExt;
if (*optlen == 0)
{
return SL_EZEROLEN;
}
CmdExt.TxPayloadLen = 0;
CmdExt.RxPayloadLen = *optlen;
CmdExt.pTxPayload = NULL;
CmdExt.pRxPayload = optval;
CmdExt.ActualRxPayloadLen = 0;
Msg.Cmd.sd = (_u8)sd;
Msg.Cmd.level = (_u8)level;
Msg.Cmd.optionLen = (_u8)(*optlen);
Msg.Cmd.optionName = (_u8)optname;
VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlGetSockOptCmdCtrl, &Msg, &CmdExt));
if (CmdExt.RxPayloadLen < CmdExt.ActualRxPayloadLen)
{
*optlen = Msg.Rsp.optionLen;
return SL_ESMALLBUF;
}
else
{
*optlen = (_u8)CmdExt.ActualRxPayloadLen;
}
return (_i16)Msg.Rsp.status;
}
#endif
/*******************************************************************************/
/* sl_Select */
/* ******************************************************************************/
typedef union
{
_SelectCommand_t Cmd;
_BasicResponse_t Rsp;
}_SlSelectMsg_u;
const _SlCmdCtrl_t _SlSelectCmdCtrl =
{
SL_OPCODE_SOCKET_SELECT,
sizeof(_SelectCommand_t),
sizeof(_BasicResponse_t)
};
#if _SL_INCLUDE_FUNC(sl_Select)
_i16 sl_Select(_i16 nfds, SlFdSet_t *readsds, SlFdSet_t *writesds, SlFdSet_t *exceptsds, struct SlTimeval_t *timeout)
{
_SlSelectMsg_u Msg;
_SelectAsyncResponse_t AsyncRsp;
_u8 ObjIdx = MAX_CONCURRENT_ACTIONS;
Msg.Cmd.nfds = (_u8)nfds;
Msg.Cmd.readFdsCount = 0;
Msg.Cmd.writeFdsCount = 0;
Msg.Cmd.readFds = 0;
Msg.Cmd.writeFds = 0;
if( readsds )
{
Msg.Cmd.readFds = (_u16)readsds->fd_array[0];
}
if( writesds )
{
Msg.Cmd.writeFds = (_u16)writesds->fd_array[0];
}
if( NULL == timeout )
{
Msg.Cmd.tv_sec = 0xffff;
Msg.Cmd.tv_usec = 0xffff;
}
else
{
if( 0xffff <= timeout->tv_sec )
{
Msg.Cmd.tv_sec = 0xffff;
}
else
{
Msg.Cmd.tv_sec = (_u16)timeout->tv_sec;
}
timeout->tv_usec = timeout->tv_usec >> 10; /* convert to milliseconds */
if( 0xffff <= timeout->tv_usec )
{
Msg.Cmd.tv_usec = 0xffff;
}
else
{
Msg.Cmd.tv_usec = (_u16)timeout->tv_usec;
}
}
/* Use Obj to issue the command, if not available try later */
ObjIdx = (_u8)_SlDrvWaitForPoolObj(SELECT_ID, SL_MAX_SOCKETS);
if (MAX_CONCURRENT_ACTIONS == ObjIdx)
{
return SL_POOL_IS_EMPTY;
}
OSI_RET_OK_CHECK(sl_LockObjLock(&g_pCB->ProtectionLockObj, SL_OS_WAIT_FOREVER));
g_pCB->ObjPool[ObjIdx].pRespArgs = (_u8 *)&AsyncRsp;
OSI_RET_OK_CHECK(sl_LockObjUnlock(&g_pCB->ProtectionLockObj));
/* send the command */
VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlSelectCmdCtrl, &Msg, NULL));
if(SL_OS_RET_CODE_OK == (_i16)Msg.Rsp.status)
{
OSI_RET_OK_CHECK(sl_SyncObjWait(&g_pCB->ObjPool[ObjIdx].SyncObj, SL_OS_WAIT_FOREVER));
Msg.Rsp.status = AsyncRsp.status;
if( ((_i16)Msg.Rsp.status) >= 0 )
{
if( readsds )
{
readsds->fd_array[0] = AsyncRsp.readFds;
}
if( writesds )
{
writesds->fd_array[0] = AsyncRsp.writeFds;
}
}
}
_SlDrvReleasePoolObj(ObjIdx);
return (_i16)Msg.Rsp.status;
}
/* Select helper functions */
/*******************************************************************************/
/* SL_FD_SET */
/* ******************************************************************************/
void SL_FD_SET(_i16 fd, SlFdSet_t *fdset)
{
fdset->fd_array[0] |= (1<< (fd & BSD_SOCKET_ID_MASK));
}
/*******************************************************************************/
/* SL_FD_CLR */
/*******************************************************************************/
void SL_FD_CLR(_i16 fd, SlFdSet_t *fdset)
{
fdset->fd_array[0] &= ~(1<< (fd & BSD_SOCKET_ID_MASK));
}
/*******************************************************************************/
/* SL_FD_ISSET */
/*******************************************************************************/
_i16 SL_FD_ISSET(_i16 fd, SlFdSet_t *fdset)
{
if( fdset->fd_array[0] & (1<< (fd & BSD_SOCKET_ID_MASK)) )
{
return 1;
}
return 0;
}
/*******************************************************************************/
/* SL_FD_ZERO */
/*******************************************************************************/
void SL_FD_ZERO(SlFdSet_t *fdset)
{
fdset->fd_array[0] = 0;
}
#endif
/*******************************************************************************/
/* _sl_HandleAsync_Select */
/*******************************************************************************/
void _sl_HandleAsync_Select(void *pVoidBuf)
{
_SelectAsyncResponse_t *pMsgArgs = (_SelectAsyncResponse_t *)_SL_RESP_ARGS_START(pVoidBuf);
OSI_RET_OK_CHECK(sl_LockObjLock(&g_pCB->ProtectionLockObj, SL_OS_WAIT_FOREVER));
VERIFY_SOCKET_CB(NULL != g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs);
sl_Memcpy(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs, pMsgArgs, sizeof(_SelectAsyncResponse_t));
OSI_RET_OK_CHECK(sl_SyncObjSignal(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].SyncObj));
OSI_RET_OK_CHECK(sl_LockObjUnlock(&g_pCB->ProtectionLockObj));
return;
}