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