micropython/drivers/cc3100/src/socket.c

1151 wiersze
32 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"
void _sl_BuildAddress(const SlSockAddr_t *addr, _SocketAddrCommand_u *pCmd);
void _sl_HandleAsync_Connect(void *pVoidBuf);
#ifndef SL_TINY_EXT
void _sl_ParseAddress(_SocketAddrResponse_u *pRsp, SlSockAddr_t *addr, SlSocklen_t *addrlen);
void _sl_HandleAsync_Accept(void *pVoidBuf);
void _sl_HandleAsync_Select(void *pVoidBuf);
#endif
_u16 _sl_TruncatePayloadByProtocol(const _i16 pSd, const _u16 length);
/*******************************************************************************/
/* Functions */
/*******************************************************************************/
/* 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. */
#define SL_SOCKET_PAYLOAD_BASE (1350)
const _u8 _SlPayloadByProtocolLUT[16] =
{
(1472 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_UDP_IPV4 */
(1460 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_TCP_IPV4 */
(1452 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_UDP_IPV6 */
(1440 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_TCP_IPV6 */
(1386 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_TCP_IPV4_SECURE */
(1386 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_UDP_IPV4_SECURE */
(1396 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_UDP_IPV6_SECURE */
(1396 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_TCP_IPV6_SECURE */
(1476 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_RAW_TRANCEIVER */
(1514 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_RAW_PACKET */
(1480 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_RAW_IP4 */
(1480 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_RAW_IP6 */
(1440 - SL_SOCKET_PAYLOAD_BASE), /* Default */
(1440 - SL_SOCKET_PAYLOAD_BASE), /* Default */
(1440 - SL_SOCKET_PAYLOAD_BASE), /* Default */
(1440 - SL_SOCKET_PAYLOAD_BASE) /* Default */
};
/* ******************************************************************************/
/* _sl_BuildAddress */
/* ******************************************************************************/
void _sl_BuildAddress(const SlSockAddr_t *addr, _SocketAddrCommand_u *pCmd)
{
/* 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. */
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)
{
unsigned int maxLength;
maxLength = SL_SOCKET_PAYLOAD_BASE + _SlPayloadByProtocolLUT[((sd & SL_SOCKET_PAYLOAD_TYPE_MASK) >> 4)];
if( length > maxLength )
{
return maxLength;
}
else
{
return length;
}
}
/*******************************************************************************/
/* _sl_ParseAddress */
/*******************************************************************************/
#ifndef SL_TINY_EXT
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
}
#endif
/*******************************************************************************/
/* sl_Socket */
/*******************************************************************************/
typedef union
{
_u32 Dummy;
_SocketCommand_t Cmd;
_SocketResponse_t Rsp;
}_SlSockSocketMsg_u;
#if _SL_INCLUDE_FUNC(sl_Socket)
const _SlCmdCtrl_t _SlSockSocketCmdCtrl =
{
SL_OPCODE_SOCKET_SOCKET,
sizeof(_SocketCommand_t),
sizeof(_SocketResponse_t)
};
_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;
#if _SL_INCLUDE_FUNC(sl_Close)
const _SlCmdCtrl_t _SlSockCloseCmdCtrl =
{
SL_OPCODE_SOCKET_CLOSE,
sizeof(_CloseCommand_t),
sizeof(_SocketResponse_t)
};
_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;
#ifndef SL_TINY_EXT
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
#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, &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;
_SlDrvResetCmdExt(&CmdExt);
CmdExt.TxPayloadLen = (_u16)Len;
CmdExt.pTxPayload = (_u8 *)pBuf;
switch(to->sa_family)
{
case SL_AF_INET:
CmdCtrl.Opcode = SL_OPCODE_SOCKET_SENDTO;
CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv4Command_t);
break;
#ifndef SL_TINY_EXT
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
#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, &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;
_SlDrvResetCmdExt(&CmdExt);
CmdExt.RxPayloadLen = Len;
CmdExt.pRxPayload = (_u8 *)buf;
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;
if(sizeof(SlSockAddrIn_t) == *fromlen)
{
Msg.Cmd.FamilyAndFlags |= (SL_AF_INET << 4);
}
else if (sizeof(SlSockAddrIn6_t) == *fromlen)
{
Msg.Cmd.FamilyAndFlags |= (SL_AF_INET6 << 4);
}
else
{
return SL_RET_CODE_INVALID_INPUT;
}
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);
/* Do nothing - cmd already initialized to this type */
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, &Msg.Cmd);
ObjIdx = _SlDrvProtectAsyncRespSetting((_u8*)&AsyncRsp, CONNECT_ID, sd & BSD_SOCKET_ID_MASK);
if (MAX_CONCURRENT_ACTIONS == ObjIdx)
{
return SL_POOL_IS_EMPTY;
}
/* 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 */
_SlDrvSyncObjWaitForever(&g_pCB->ObjPool[ObjIdx].SyncObj);
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);
_SlDrvProtectionObjLockWaitForever();
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;
_SlDrvSyncObjSignal(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].SyncObj);
_SlDrvProtectionObjUnLock();
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;
_SlDrvResetCmdExt(&CmdExt);
CmdExt.TxPayloadLen = Len;
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; /* mark as Rx data to send */
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;
#if _SL_INCLUDE_FUNC(sl_Listen)
const _SlCmdCtrl_t _SlListenCmdCtrl =
{
SL_OPCODE_SOCKET_LISTEN,
sizeof(_ListenCommand_t),
sizeof(_BasicResponse_t),
};
_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;
#if _SL_INCLUDE_FUNC(sl_Accept)
const _SlCmdCtrl_t _SlAcceptCmdCtrl =
{
SL_OPCODE_SOCKET_ACCEPT,
sizeof(_AcceptCommand_t),
sizeof(_BasicResponse_t),
};
_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;
ObjIdx = _SlDrvProtectAsyncRespSetting((_u8*)&AsyncRsp, ACCEPT_ID, sd & BSD_SOCKET_ID_MASK );
if (MAX_CONCURRENT_ACTIONS == ObjIdx)
{
return SL_POOL_IS_EMPTY;
}
/* 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 */
_SlDrvSyncObjWaitForever(&g_pCB->ObjPool[ObjIdx].SyncObj);
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 */
/*******************************************************************************/
#ifndef SL_TINY_EXT
void _sl_HandleAsync_Accept(void *pVoidBuf)
{
_SocketAddrResponse_u *pMsgArgs = (_SocketAddrResponse_u *)_SL_RESP_ARGS_START(pVoidBuf);
_SlDrvProtectionObjLockWaitForever();
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));
_SlDrvSyncObjSignal(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].SyncObj);
_SlDrvProtectionObjUnLock();
return;
}
/*******************************************************************************/
/* _sl_HandleAsync_Select */
/*******************************************************************************/
void _sl_HandleAsync_Select(void *pVoidBuf)
{
_SelectAsyncResponse_t *pMsgArgs = (_SelectAsyncResponse_t *)_SL_RESP_ARGS_START(pVoidBuf);
_SlDrvProtectionObjLockWaitForever();
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));
_SlDrvSyncObjSignal(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].SyncObj);
_SlDrvProtectionObjUnLock();
return;
}
#endif
/*******************************************************************************/
/* sl_Recv */
/*******************************************************************************/
typedef union
{
_sendRecvCommand_t Cmd;
_SocketResponse_t Rsp;
}_SlRecvMsg_u;
#if _SL_INCLUDE_FUNC(sl_Recv)
const _SlCmdCtrl_t _SlRecvCmdCtrl =
{
SL_OPCODE_SOCKET_RECV,
sizeof(_sendRecvCommand_t),
sizeof(_SocketResponse_t)
};
_i16 sl_Recv(_i16 sd, void *pBuf, _i16 Len, _i16 flags)
{
_SlRecvMsg_u Msg;
_SlCmdExt_t CmdExt;
_SlReturnVal_t status;
_SlDrvResetCmdExt(&CmdExt);
CmdExt.RxPayloadLen = Len;
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;
_SlDrvResetCmdExt(&CmdExt);
CmdExt.TxPayloadLen = optlen;
CmdExt.pTxPayload = (_u8 *)optval;
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;
#if _SL_INCLUDE_FUNC(sl_GetSockOpt)
const _SlCmdCtrl_t _SlGetSockOptCmdCtrl =
{
SL_OPCODE_SOCKET_GETSOCKOPT,
sizeof(_getSockOptCommand_t),
sizeof(_getSockOptResponse_t)
};
_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;
}
_SlDrvResetCmdExt(&CmdExt);
CmdExt.RxPayloadLen = *optlen;
CmdExt.pRxPayload = optval;
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;
#ifndef SL_TINY_EXT
#if _SL_INCLUDE_FUNC(sl_Select)
const _SlCmdCtrl_t _SlSelectCmdCtrl =
{
SL_OPCODE_SOCKET_SELECT,
sizeof(_SelectCommand_t),
sizeof(_BasicResponse_t)
};
_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 = _SlDrvProtectAsyncRespSetting((_u8*)&AsyncRsp, SELECT_ID, SL_MAX_SOCKETS);
if (MAX_CONCURRENT_ACTIONS == ObjIdx)
{
return SL_POOL_IS_EMPTY;
}
/* send the command */
VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlSelectCmdCtrl, &Msg, NULL));
if(SL_OS_RET_CODE_OK == (_i16)Msg.Rsp.status)
{
_SlDrvSyncObjWaitForever(&g_pCB->ObjPool[ObjIdx].SyncObj);
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
#endif